a little something here...

This commit is contained in:
Hailey
2024-07-29 15:54:50 -07:00
parent 43ba0f21f6
commit 8d03297de6
6 changed files with 163 additions and 1 deletions
@@ -1,7 +1,7 @@
{
"platforms": ["ios", "tvos", "android", "web"],
"ios": {
"modules": ["ExpoBlueskySharedPrefsModule", "ExpoBlueskyReferrerModule"]
"modules": ["ExpoBlueskySharedPrefsModule", "ExpoBlueskyReferrerModule", "ExpoHLSDownloadModule"]
},
"android": {
"modules": [
@@ -0,0 +1,50 @@
//
// DownloadManager.swift
// ExpoBlueskySwissArmy
//
// Created by Hailey on 7/29/24.
//
class DownloadManager {
static let shared = DownloadManager()
private let downloads: NSMapTable<NSString, HLSDownload> = NSMapTable(keyOptions: .weakMemory, valueOptions: .weakMemory)
func add(_ hlsDownload: HLSDownload) {
let key = hlsDownload.sourceUrl.absoluteString as NSString
downloads.setObject(hlsDownload, forKey: key)
}
func remove(string: String) {
let key = string as NSString
downloads.removeObject(forKey: key)
}
func remove(hlsDownload: HLSDownload) {
let key = hlsDownload.sourceUrl.absoluteString as NSString
downloads.setObject(hlsDownload, forKey: key)
}
func getForSource(url: URL) -> HLSDownload? {
let key = url.absoluteString as NSString
return downloads.object(forKey: key)
}
func getForSource(string: String) -> HLSDownload? {
let key = string as NSString
return downloads.object(forKey: key)
}
func cancel(url: URL) {
let download = self.getForSource(url: url)
download?.cancel()
}
func cancelAll() {
let downloadsEnumerator = downloads.objectEnumerator()
while let download = downloadsEnumerator?.nextObject() {
let download = download as? HLSDownload
download?.cancel()
}
}
}
@@ -0,0 +1,28 @@
//
// ExpoHLSDownloadModule.swift
// DoubleConversion
//
// Created by Hailey on 7/29/24.
//
import ExpoModulesCore
class ExpoHLSDownloadModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoHLSDownloadModule")
AsyncFunction("downloadAsync") { (sourceUrl: URL, progressCb: JavaScriptFunction<Void>, promise: Promise) in
let hlsDownload = HLSDownload(sourceUrl: sourceUrl)
let downloadTask = Task {
let outUrl = await hlsDownload.download { (progress: Float) in
try? progressCb.call(progress)
}
promise.resolve(outUrl)
}
}
AsyncFunction("cancelDownloadAsync") { (sourceUrl: URL) in
DownloadManager.shared.cancel(url: sourceUrl)
}
}
}
@@ -0,0 +1,64 @@
//
// HLSDownload.swift
// ExpoBlueskySwissArmy
//
// Created by Hailey on 7/29/24.
//
import Foundation
import AVKit
class HLSDownload {
private let avAsset: AVAsset
private var exportSession: AVAssetExportSession?
let sourceUrl: URL
init (sourceUrl: URL) {
self.sourceUrl = sourceUrl
self.avAsset = AVAsset(url: sourceUrl)
}
func download(progress: @escaping(Float) -> Void) async -> URL? {
guard let exportSession = AVAssetExportSession(asset: self.avAsset, presetName: AVAssetExportPresetHighestQuality) else {
// @TODO return an error for the user here
print("Export session error")
return nil
}
let outDir = FileManager().urls(for: .cachesDirectory, in: .userDomainMask)[0]
guard let outUrl = URL(string: "\(outDir.absoluteString)\(ProcessInfo.processInfo.globallyUniqueString).mp4") else {
print("oops failed to make a url")
return nil
}
print(outUrl.absoluteString)
exportSession.outputFileType = AVFileType.mp4
exportSession.outputURL = outUrl
let timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (_: Timer) in
// Do something here
}
self.exportSession = exportSession
await exportSession.export()
// Update with final progress
progress(1)
// Stop calling the callback
timer.invalidate()
return outUrl
}
func progress() -> Float {
guard let exportSession = self.exportSession else {
return 0
}
return exportSession.progress
}
func cancel() {
// Cancel the download
}
}
@@ -0,0 +1,11 @@
import {requireNativeModule} from 'expo'
const NativeModule = requireNativeModule('ExpoHLSDownload')
export async function downloadAsync(sourceUrl: string): Promise<string> {
return NativeModule.downloadAsync(sourceUrl)
}
export async function cancelAsync(sourceUrl: string): Promise<void> {
return NativeModule.cancelAsync(sourceUrl)
}
@@ -0,0 +1,9 @@
import {NotImplementedError} from '../NotImplemented'
export function downloadAsync(sourceUrl: string): Promise<string> {
throw new NotImplementedError({sourceUrl})
}
export function cancelAsync(sourceUrl: string): Promise<void> {
throw new NotImplementedError({sourceUrl})
}