From 88a5df88bf92c3a6aa5bb960e30f10dcdaab8afa Mon Sep 17 00:00:00 2001 From: Francesco <100066266+cranci1@users.noreply.github.com> Date: Sat, 31 May 2025 22:16:41 +0200 Subject: [PATCH] =?UTF-8?q?yeah=20idk=20tf=20is=20this=20=F0=9F=98=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sora/Utils/DownloadUtils/DownloadModels.swift | 61 +++++++++++++++ .../Downloads/JSController+MP4Download.swift | 74 ++++++++++++------- Sora/Views/DownloadView.swift | 22 ++++-- 3 files changed, 126 insertions(+), 31 deletions(-) diff --git a/Sora/Utils/DownloadUtils/DownloadModels.swift b/Sora/Utils/DownloadUtils/DownloadModels.swift index 1278542..2e33337 100644 --- a/Sora/Utils/DownloadUtils/DownloadModels.swift +++ b/Sora/Utils/DownloadUtils/DownloadModels.swift @@ -399,6 +399,67 @@ struct ActiveDownload: Identifiable, Equatable { } } +// MARK: - JS Active Download Model +struct JSActiveDownload: Identifiable, Equatable { + let id: UUID + let originalURL: URL + var progress: Double + let task: AVAssetDownloadTask? // For HLS downloads + let mp4Task: URLSessionDownloadTask? // For MP4 downloads + let type: DownloadType + var metadata: AssetMetadata? + var title: String? + var imageURL: URL? + var subtitleURL: URL? + var queueStatus: DownloadQueueStatus + var asset: AVURLAsset? + var headers: [String: String] + var module: ScrapingModule? + + static func == (lhs: JSActiveDownload, rhs: JSActiveDownload) -> Bool { + return lhs.id == rhs.id && + lhs.originalURL == rhs.originalURL && + lhs.progress == rhs.progress && + lhs.type == rhs.type && + lhs.title == rhs.title && + lhs.imageURL == rhs.imageURL && + lhs.subtitleURL == rhs.subtitleURL && + lhs.queueStatus == rhs.queueStatus + } + + init( + id: UUID = UUID(), + originalURL: URL, + progress: Double = 0, + task: AVAssetDownloadTask? = nil, + mp4Task: URLSessionDownloadTask? = nil, + queueStatus: DownloadQueueStatus = .queued, + type: DownloadType = .movie, + metadata: AssetMetadata? = nil, + title: String? = nil, + imageURL: URL? = nil, + subtitleURL: URL? = nil, + asset: AVURLAsset? = nil, + headers: [String: String] = [:], + module: ScrapingModule? = nil + ) { + self.id = id + self.originalURL = originalURL + self.progress = progress + self.task = task + self.mp4Task = mp4Task + self.type = type + self.metadata = metadata + self.title = title + self.imageURL = imageURL + self.subtitleURL = subtitleURL + self.queueStatus = queueStatus + self.asset = asset + self.headers = headers + self.module = module + } +} + // MARK: - Asset Metadata struct AssetMetadata: Codable { let title: String diff --git a/Sora/Utils/JSLoader/Downloads/JSController+MP4Download.swift b/Sora/Utils/JSLoader/Downloads/JSController+MP4Download.swift index dacd549..9eaf4fa 100644 --- a/Sora/Utils/JSLoader/Downloads/JSController+MP4Download.swift +++ b/Sora/Utils/JSLoader/Downloads/JSController+MP4Download.swift @@ -75,23 +75,6 @@ extension JSController { let filename = "\(sanitizedTitle)_\(downloadID.uuidString.prefix(8)).mp4" let destinationURL = downloadDirectory.appendingPathComponent(filename) - // Create an active download object - let activeDownload = JSActiveDownload( - id: downloadID, - originalURL: url, - task: nil, - queueStatus: .downloading, - type: downloadType, - metadata: metadata, - title: title, - imageURL: imageURL, - subtitleURL: subtitleURL, - headers: headers - ) - - // Add to active downloads - activeDownloads.append(activeDownload) - // Create request with headers var request = URLRequest(url: url) request.timeoutInterval = 30.0 @@ -204,16 +187,32 @@ extension JSController { } } - // Set up progress observation - setupProgressObservation(for: downloadTask, downloadID: downloadID) + // Create an active download object with the mp4Task + let activeDownload = JSActiveDownload( + id: downloadID, + originalURL: url, + task: nil, + mp4Task: downloadTask, // Add the MP4 download task + queueStatus: .downloading, + type: downloadType, + metadata: metadata, + title: title, + imageURL: imageURL, + subtitleURL: subtitleURL, + headers: headers + ) + // Add to active downloads and map + activeDownloads.append(activeDownload) + activeDownloadMap[downloadTask] = downloadID + // Store session reference storeSessionReference(session: customSession, for: downloadID) - // Start download + // Set initial task state to running downloadTask.resume() print("MP4 Download: Task started for \(filename)") - + // Initial success callback completionHandler?(true, "Download started") } @@ -230,14 +229,39 @@ extension JSController { } private func setupProgressObservation(for task: URLSessionDownloadTask, downloadID: UUID) { + // Create a dispatch queue for progress updates + let progressQueue = DispatchQueue(label: "com.sora.download.progress") + let observation = task.progress.observe(\.fractionCompleted) { [weak self] progress, _ in - DispatchQueue.main.async { + progressQueue.async { guard let self = self else { return } - self.updateDownloadProgress(downloadID: downloadID, progress: progress.fractionCompleted) - NotificationCenter.default.post(name: NSNotification.Name("downloadProgressUpdated"), object: nil) + + // Only update if enough time has passed since last update + let currentTime = Date() + let lastUpdate = JSController.lastProgressUpdateTime[downloadID] ?? .distantPast + + if currentTime.timeIntervalSince(lastUpdate) >= JSController.progressUpdateInterval { + DispatchQueue.main.async { + self.updateDownloadProgress(downloadID: downloadID, progress: progress.fractionCompleted) + JSController.lastProgressUpdateTime[downloadID] = currentTime + + // Find and update the download object + if let index = self.activeDownloads.firstIndex(where: { $0.id == downloadID }) { + let download = self.activeDownloads[index] + // Post progress notification with episode info if available + if let episodeNumber = download.metadata?.episode { + self.postDownloadNotification(.progress, userInfo: [ + "episodeNumber": episodeNumber, + "progress": progress.fractionCompleted, + "status": "downloading" + ]) + } + } + } + } } } - + if mp4ProgressObservations == nil { mp4ProgressObservations = [:] } diff --git a/Sora/Views/DownloadView.swift b/Sora/Views/DownloadView.swift index aa38615..8726b5c 100644 --- a/Sora/Views/DownloadView.swift +++ b/Sora/Views/DownloadView.swift @@ -555,7 +555,7 @@ struct DownloadSectionView: View { struct DownloadSummaryCard: View { let totalShows: Int - let totalEpisodes: Int + let totalEpisodes: Int64 let totalSize: Int64 var body: some View { @@ -733,7 +733,7 @@ struct EnhancedActiveDownloadCard: View { init(download: JSActiveDownload) { self.download = download _currentProgress = State(initialValue: download.progress) - _taskState = State(initialValue: download.task?.state ?? .suspended) + _taskState = State(initialValue: download.mp4Task?.state ?? download.task?.state ?? .suspended) } var body: some View { @@ -877,11 +877,21 @@ struct EnhancedActiveDownloadCard: View { private func toggleDownload() { if taskState == .running { - download.task?.suspend() - taskState = .suspended + if let hlsTask = download.task { + hlsTask.suspend() + taskState = .suspended + } else if let mp4Task = download.mp4Task { + mp4Task.suspend() + taskState = .suspended + } } else if taskState == .suspended { - download.task?.resume() - taskState = .running + if let hlsTask = download.task { + hlsTask.resume() + taskState = .running + } else if let mp4Task = download.mp4Task { + mp4Task.resume() + taskState = .running + } } }