Compare commits

...

3 Commits

Author SHA1 Message Date
Hailey cdbec848b7 add a little tester 2024-07-29 16:01:38 -07:00
Hailey f68114bd47 add cb function 2024-07-29 15:55:31 -07:00
Hailey 8d03297de6 a little something here... 2024-07-29 15:54:50 -07:00
8 changed files with 185 additions and 2 deletions
@@ -1,7 +1,7 @@
{
"platforms": ["ios", "tvos", "android", "web"],
"ios": {
"modules": ["ExpoBlueskySharedPrefsModule", "ExpoBlueskyReferrerModule"]
"modules": ["ExpoBlueskySharedPrefsModule", "ExpoBlueskyReferrerModule", "ExpoHLSDownloadModule"]
},
"android": {
"modules": [
+2 -1
View File
@@ -1,4 +1,5 @@
import * as HLSDownload from './src/HLSDownload'
import * as Referrer from './src/Referrer'
import * as SharedPrefs from './src/SharedPrefs'
export {Referrer, SharedPrefs}
export {HLSDownload, Referrer, SharedPrefs}
@@ -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("ExpoHLSDownload")
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,14 @@
import {requireNativeModule} from 'expo'
const NativeModule = requireNativeModule('ExpoHLSDownload')
export async function downloadAsync(
sourceUrl: string,
progressCb: (progress: number) => void,
): Promise<string> {
return NativeModule.downloadAsync(sourceUrl, progressCb)
}
export async function cancelAsync(sourceUrl: string): Promise<void> {
return NativeModule.cancelAsync(sourceUrl)
}
@@ -0,0 +1,12 @@
import {NotImplementedError} from '../NotImplemented'
export async function downloadAsync(
sourceUrl: string,
progressCb: (progress: number) => void,
): Promise<string> {
throw new NotImplementedError({sourceUrl, progressCb})
}
export async function cancelAsync(sourceUrl: string): Promise<void> {
throw new NotImplementedError({sourceUrl})
}
+14
View File
@@ -7,6 +7,7 @@ import {CenteredView} from '#/view/com/util/Views'
import {ListContained} from 'view/screens/Storybook/ListContained'
import {atoms as a, ThemeProvider, useTheme} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import {HLSDownload} from '../../../../modules/expo-bluesky-swiss-army'
import {Breakpoints} from './Breakpoints'
import {Buttons} from './Buttons'
import {Dialogs} from './Dialogs'
@@ -37,6 +38,19 @@ function StorybookInner() {
return (
<CenteredView style={[t.atoms.bg]}>
<View style={[a.p_xl, a.gap_5xl, {paddingBottom: 200}]}>
<Button
variant="solid"
color="primary"
size="small"
onPress={async () => {
const res = await HLSDownload.downloadAsync('', progress => {
console.log(`Download progress: ${progress}`)
})
console.log(`Download UR: ${res}`)
}}
label="idk">
<ButtonText>TEST THE DOWNLOAD PLZ</ButtonText>
</Button>
{!showContainedList ? (
<>
<View style={[a.flex_row, a.align_start, a.gap_md]}>