a little something here...
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"platforms": ["ios", "tvos", "android", "web"],
|
"platforms": ["ios", "tvos", "android", "web"],
|
||||||
"ios": {
|
"ios": {
|
||||||
"modules": ["ExpoBlueskySharedPrefsModule", "ExpoBlueskyReferrerModule"]
|
"modules": ["ExpoBlueskySharedPrefsModule", "ExpoBlueskyReferrerModule", "ExpoHLSDownloadModule"]
|
||||||
},
|
},
|
||||||
"android": {
|
"android": {
|
||||||
"modules": [
|
"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})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user