mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-01-17 08:38:04 +00:00
wip
This commit is contained in:
@@ -3,6 +3,7 @@ import { type EventSubscription } from "expo-modules-core";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import type {
|
||||
DownloadInfo,
|
||||
DownloadMetadata,
|
||||
OnCompleteEventPayload,
|
||||
OnErrorEventPayload,
|
||||
@@ -14,16 +15,14 @@ import HlsDownloaderModule from "./src/HlsDownloaderModule";
|
||||
* Initiates an HLS download.
|
||||
* @param id - A unique identifier for the download.
|
||||
* @param url - The HLS stream URL.
|
||||
* @param assetTitle - A title for the asset.
|
||||
* @param destination - The destination path for the downloaded asset.
|
||||
* @param metadata - Additional metadata for the download.
|
||||
*/
|
||||
function downloadHLSAsset(
|
||||
id: string,
|
||||
url: string,
|
||||
assetTitle: string,
|
||||
metadata: DownloadMetadata
|
||||
): void {
|
||||
HlsDownloaderModule.downloadHLSAsset(id, url, assetTitle, metadata);
|
||||
HlsDownloaderModule.downloadHLSAsset(id, url, metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,15 +30,7 @@ function downloadHLSAsset(
|
||||
* Returns an array of downloads with additional fields:
|
||||
* id, progress, bytesDownloaded, bytesTotal, and state.
|
||||
*/
|
||||
async function checkForExistingDownloads(): Promise<
|
||||
Array<{
|
||||
id: string;
|
||||
progress: number;
|
||||
bytesDownloaded: number;
|
||||
bytesTotal: number;
|
||||
state: "PENDING" | "DOWNLOADING" | "PAUSED" | "DONE" | "FAILED" | "STOPPED";
|
||||
}>
|
||||
> {
|
||||
async function checkForExistingDownloads(): Promise<DownloadInfo[]> {
|
||||
return HlsDownloaderModule.checkForExistingDownloads();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@ import ExpoModulesCore
|
||||
|
||||
public class HlsDownloaderModule: Module {
|
||||
var activeDownloads:
|
||||
[Int: (task: AVAssetDownloadTask, delegate: HLSDownloadDelegate, metadata: [String: Any])] = [:]
|
||||
[Int: (
|
||||
task: AVAssetDownloadTask, delegate: HLSDownloadDelegate, metadata: [String: Any],
|
||||
startTime: Date
|
||||
)] = [:]
|
||||
|
||||
public func definition() -> ModuleDefinition {
|
||||
Name("HlsDownloader")
|
||||
@@ -11,9 +14,9 @@ public class HlsDownloaderModule: Module {
|
||||
Events("onProgress", "onError", "onComplete")
|
||||
|
||||
Function("downloadHLSAsset") {
|
||||
(providedId: String, url: String, assetTitle: String, metadata: [String: Any]?) -> Void in
|
||||
(providedId: String, url: String, metadata: [String: Any]?) -> Void in
|
||||
print(
|
||||
"Starting download - ID: \(providedId), URL: \(url), Title: \(assetTitle), Metadata: \(String(describing: metadata))"
|
||||
"Starting download - ID: \(providedId), URL: \(url), Metadata: \(String(describing: metadata))"
|
||||
)
|
||||
|
||||
guard let assetURL = URL(string: url) else {
|
||||
@@ -42,7 +45,7 @@ public class HlsDownloaderModule: Module {
|
||||
guard
|
||||
let task = downloadSession.makeAssetDownloadTask(
|
||||
asset: asset,
|
||||
assetTitle: assetTitle,
|
||||
assetTitle: providedId,
|
||||
assetArtworkData: nil,
|
||||
options: nil
|
||||
)
|
||||
@@ -59,7 +62,7 @@ public class HlsDownloaderModule: Module {
|
||||
}
|
||||
|
||||
delegate.taskIdentifier = task.taskIdentifier
|
||||
self.activeDownloads[task.taskIdentifier] = (task, delegate, metadata ?? [:])
|
||||
self.activeDownloads[task.taskIdentifier] = (task, delegate, metadata ?? [:], Date())
|
||||
self.sendEvent(
|
||||
"onProgress",
|
||||
[
|
||||
@@ -67,6 +70,7 @@ public class HlsDownloaderModule: Module {
|
||||
"progress": 0.0,
|
||||
"state": "PENDING",
|
||||
"metadata": metadata ?? [:],
|
||||
"startTime": Date().timeIntervalSince1970,
|
||||
])
|
||||
|
||||
task.resume()
|
||||
@@ -80,6 +84,7 @@ public class HlsDownloaderModule: Module {
|
||||
let task = pair.task
|
||||
let delegate = pair.delegate
|
||||
let metadata = pair.metadata
|
||||
let startTime = pair.startTime
|
||||
let downloaded = delegate.downloadedSeconds
|
||||
let total = delegate.totalSeconds
|
||||
let progress = total > 0 ? downloaded / total : 0
|
||||
@@ -90,6 +95,7 @@ public class HlsDownloaderModule: Module {
|
||||
"bytesTotal": total,
|
||||
"state": self.mappedState(for: task),
|
||||
"metadata": metadata,
|
||||
"startTime": startTime.timeIntervalSince1970,
|
||||
])
|
||||
}
|
||||
return downloads
|
||||
@@ -136,6 +142,7 @@ class HLSDownloadDelegate: NSObject, AVAssetDownloadDelegate {
|
||||
var providedId: String = ""
|
||||
var downloadedSeconds: Double = 0
|
||||
var totalSeconds: Double = 0
|
||||
|
||||
init(module: HlsDownloaderModule) {
|
||||
self.module = module
|
||||
}
|
||||
@@ -150,7 +157,9 @@ class HLSDownloadDelegate: NSObject, AVAssetDownloadDelegate {
|
||||
}
|
||||
|
||||
let total = CMTimeGetSeconds(timeRangeExpectedToLoad.duration)
|
||||
let metadata = module?.activeDownloads[assetDownloadTask.taskIdentifier]?.metadata ?? [:]
|
||||
let downloadInfo = module?.activeDownloads[assetDownloadTask.taskIdentifier]
|
||||
let metadata = downloadInfo?.metadata ?? [:]
|
||||
let startTime = downloadInfo?.startTime.timeIntervalSince1970 ?? Date().timeIntervalSince1970
|
||||
|
||||
self.downloadedSeconds = downloaded
|
||||
self.totalSeconds = total
|
||||
@@ -166,6 +175,7 @@ class HLSDownloadDelegate: NSObject, AVAssetDownloadDelegate {
|
||||
"bytesTotal": total,
|
||||
"state": progress >= 1.0 ? "DONE" : "DOWNLOADING",
|
||||
"metadata": metadata,
|
||||
"startTime": startTime,
|
||||
])
|
||||
}
|
||||
|
||||
@@ -173,13 +183,22 @@ class HLSDownloadDelegate: NSObject, AVAssetDownloadDelegate {
|
||||
_ session: URLSession, assetDownloadTask: AVAssetDownloadTask,
|
||||
didFinishDownloadingTo location: URL
|
||||
) {
|
||||
let metadata = module?.activeDownloads[assetDownloadTask.taskIdentifier]?.metadata ?? [:]
|
||||
let folderName = providedId // using providedId as the folder name
|
||||
let downloadInfo = module?.activeDownloads[assetDownloadTask.taskIdentifier]
|
||||
let metadata = downloadInfo?.metadata ?? [:]
|
||||
let startTime = downloadInfo?.startTime.timeIntervalSince1970 ?? Date().timeIntervalSince1970
|
||||
let folderName = providedId
|
||||
do {
|
||||
guard let module = module else { return }
|
||||
let newLocation = try module.persistDownloadedFolder(
|
||||
originalLocation: location, folderName: folderName)
|
||||
|
||||
if !metadata.isEmpty {
|
||||
let metadataLocation = newLocation.deletingLastPathComponent().appendingPathComponent(
|
||||
"\(providedId).json")
|
||||
let jsonData = try JSONSerialization.data(withJSONObject: metadata, options: .prettyPrinted)
|
||||
try jsonData.write(to: metadataLocation)
|
||||
}
|
||||
|
||||
module.sendEvent(
|
||||
"onComplete",
|
||||
[
|
||||
@@ -187,6 +206,7 @@ class HLSDownloadDelegate: NSObject, AVAssetDownloadDelegate {
|
||||
"location": newLocation.absoluteString,
|
||||
"state": "DONE",
|
||||
"metadata": metadata,
|
||||
"startTime": startTime,
|
||||
])
|
||||
} catch {
|
||||
module?.sendEvent(
|
||||
@@ -196,6 +216,7 @@ class HLSDownloadDelegate: NSObject, AVAssetDownloadDelegate {
|
||||
"error": error.localizedDescription,
|
||||
"state": "FAILED",
|
||||
"metadata": metadata,
|
||||
"startTime": startTime,
|
||||
])
|
||||
}
|
||||
module?.removeDownload(with: assetDownloadTask.taskIdentifier)
|
||||
@@ -203,7 +224,10 @@ class HLSDownloadDelegate: NSObject, AVAssetDownloadDelegate {
|
||||
|
||||
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
|
||||
if let error = error {
|
||||
let metadata = module?.activeDownloads[task.taskIdentifier]?.metadata ?? [:]
|
||||
let downloadInfo = module?.activeDownloads[task.taskIdentifier]
|
||||
let metadata = downloadInfo?.metadata ?? [:]
|
||||
let startTime = downloadInfo?.startTime.timeIntervalSince1970 ?? Date().timeIntervalSince1970
|
||||
|
||||
module?.sendEvent(
|
||||
"onError",
|
||||
[
|
||||
@@ -211,6 +235,7 @@ class HLSDownloadDelegate: NSObject, AVAssetDownloadDelegate {
|
||||
"error": error.localizedDescription,
|
||||
"state": "FAILED",
|
||||
"metadata": metadata,
|
||||
"startTime": startTime,
|
||||
])
|
||||
module?.removeDownload(with: taskIdentifier)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
import {
|
||||
BaseItemDto,
|
||||
MediaSourceInfo,
|
||||
} from "@jellyfin/sdk/lib/generated-client";
|
||||
|
||||
export type DownloadState =
|
||||
| "PENDING"
|
||||
| "DOWNLOADING"
|
||||
@@ -7,7 +12,8 @@ export type DownloadState =
|
||||
| "STOPPED";
|
||||
|
||||
export interface DownloadMetadata {
|
||||
Name: string;
|
||||
item: BaseItemDto;
|
||||
mediaSource: MediaSourceInfo;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
@@ -42,6 +48,7 @@ export type HlsDownloaderModuleEvents = {
|
||||
// Export a common interface that can be used by both HLS and regular downloads
|
||||
export interface DownloadInfo {
|
||||
id: string;
|
||||
startTime?: number;
|
||||
progress: number;
|
||||
state: DownloadState;
|
||||
bytesDownloaded?: number;
|
||||
|
||||
Reference in New Issue
Block a user