From b549528e23eacfec556fd0ab57d960af17e0aa02 Mon Sep 17 00:00:00 2001 From: ronaldheft Date: Sun, 7 Aug 2022 10:27:08 -0400 Subject: [PATCH] Handle download complete lifecycle --- ios/App/App/plugins/AbsDownloader.swift | 29 +++++++++++++++---- ios/App/Shared/models/DownloadItem.swift | 9 ++++-- ios/App/Shared/models/LocalLibrary.swift | 2 +- .../models/LocalLibraryExtensions.swift | 25 ++++++++++++++++ ios/App/Shared/util/Database.swift | 6 ++++ 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/ios/App/App/plugins/AbsDownloader.swift b/ios/App/App/plugins/AbsDownloader.swift index 198e913d..5cf3552f 100644 --- a/ios/App/App/plugins/AbsDownloader.swift +++ b/ios/App/App/plugins/AbsDownloader.swift @@ -83,6 +83,8 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate { // Handle a completed download if ( downloadItem.isDoneDownloading() ) { + // Delete the download item on exit even if handling complete errors + defer { Database.shared.removeDownloadItem(downloadItem) } handleDownloadTaskCompleteFromDownloadItem(downloadItem) } } catch { @@ -92,17 +94,31 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate { } private func handleDownloadTaskCompleteFromDownloadItem(_ downloadItem: DownloadItem) { - var statusNotification = [String: String]() - if ( downloadItem.didDownloadSuccessfully() ) { + ApiClient.getLibraryItemWithProgress(libraryItemId: downloadItem.libraryItemId!, episodeId: downloadItem.episodeId) { libraryItem in - //let localDirectory = documentsDirectory.appendingPathComponent("\(libraryItem.id)") - //let localLibraryItem = LocalLibraryItem(libraryItem, localUrl: localDirectory, server: Store.serverConfig!, files: <#T##[LocalFile]#>) + var statusNotification = [String: Any]() + statusNotification["libraryItemId"] = libraryItem?.id + + guard let libraryItem = libraryItem else { NSLog("LibraryItem not found"); return } + let localDirectory = self.documentsDirectory.appendingPathComponent("\(libraryItem.id)") + let files = downloadItem.downloadItemParts.map { part in LocalFile(libraryItem.id, part.filename!, part.mimeType()!, part.destinationURL()!) } + let localLibraryItem = LocalLibraryItem(libraryItem, localUrl: localDirectory, server: Store.serverConfig!, files: files) + + Database.shared.saveLocalLibraryItem(localLibraryItem: localLibraryItem) + statusNotification["localLibraryItem"] = try? localLibraryItem.asDictionary() + + if let progress = libraryItem.userMediaProgress { + // TODO: Handle podcast + let localMediaProgress = LocalMediaProgress(localLibraryItem: localLibraryItem, episode: nil, progress: progress) + Database.shared.saveLocalMediaProgress(localMediaProgress) + statusNotification["localMediaProgress"] = try? localMediaProgress.asDictionary() + } + + self.notifyListeners("onItemDownloadComplete", data: statusNotification) } } - - notifyListeners("onItemDownloadComplete", data: statusNotification) } @objc func downloadLibraryItem(_ call: CAPPluginCall) { @@ -203,4 +219,5 @@ enum LibraryItemDownloadError: String, Error { case downloadItemNotFound = "DownloadItem not found" case downloadItemPartNotFound = "DownloadItemPart not found" case downloadItemPartDestinationUrlNotDefined = "DownloadItemPart destination URL not defined" + case libraryItemNotFound = "LibraryItem not found for id" } diff --git a/ios/App/Shared/models/DownloadItem.swift b/ios/App/Shared/models/DownloadItem.swift index e521c647..56e8ca4f 100644 --- a/ios/App/Shared/models/DownloadItem.swift +++ b/ios/App/Shared/models/DownloadItem.swift @@ -9,7 +9,7 @@ import Foundation import Unrealm struct DownloadItem: Realmable, Codable { - var id: String = UUID().uuidString + var id: String? var libraryItemId: String? var episodeId: String? var userMediaProgress: MediaProgress? @@ -36,6 +36,7 @@ struct DownloadItem: Realmable, Codable { extension DownloadItem { init(libraryItem: LibraryItem, server: ServerConnectionConfig) { + self.id = libraryItem.id self.libraryItemId = libraryItem.id //self.episodeId // TODO self.userMediaProgress = libraryItem.userMediaProgress @@ -52,7 +53,7 @@ extension DownloadItem { } func didDownloadSuccessfully() -> Bool { - self.downloadItemParts.allSatisfy({ $0.failed = false }) + self.downloadItemParts.allSatisfy({ $0.failed == false }) } } @@ -101,6 +102,10 @@ extension DownloadItemPart { self.destinationUri = destination.path } + func mimeType() -> String? { + audioTrack?.mimeType ?? episode?.audioTrack?.mimeType + } + func downloadURL() -> URL? { if let uri = self.uri { return URL(string: uri) diff --git a/ios/App/Shared/models/LocalLibrary.swift b/ios/App/Shared/models/LocalLibrary.swift index f0e49887..5f36ff99 100644 --- a/ios/App/Shared/models/LocalLibrary.swift +++ b/ios/App/Shared/models/LocalLibrary.swift @@ -63,7 +63,7 @@ struct LocalFile: Realmable, Codable { } struct LocalMediaProgress: Realmable, Codable { - var id: String = UUID().uuidString + var id: String = "" var localLibraryItemId: String = "" var localEpisodeId: String? var duration: Double = 0 diff --git a/ios/App/Shared/models/LocalLibraryExtensions.swift b/ios/App/Shared/models/LocalLibraryExtensions.swift index e05c6be0..93ca000b 100644 --- a/ios/App/Shared/models/LocalLibraryExtensions.swift +++ b/ios/App/Shared/models/LocalLibraryExtensions.swift @@ -75,6 +75,7 @@ extension LocalFile { self.init() self.id = "\(libraryItemId)_\(filename.toBase64())" self.filename = filename + self.mimeType = mimeType self.contentUrl = localUrl.absoluteString self.absolutePath = localUrl.path self.size = Int(localUrl.fileSize) @@ -90,3 +91,27 @@ extension LocalFile { } } } + +extension LocalMediaProgress { + init(localLibraryItem: LocalLibraryItem, episode: LocalPodcastEpisode?, progress: MediaProgress) { + self.id = localLibraryItem.id + self.localLibraryItemId = localLibraryItem.id + self.libraryItemId = localLibraryItem.libraryItemId + + if let episode = episode { + self.id += "-\(episode.id)" + self.episodeId = episode.id + } + + self.serverAddress = localLibraryItem.serverAddress + self.serverUserId = localLibraryItem.serverUserId + self.serverConnectionConfigId = localLibraryItem.serverConnectionConfigId + + self.duration = progress.duration + self.currentTime = progress.currentTime + self.isFinished = false + self.lastUpdate = progress.lastUpdate + self.startedAt = progress.startedAt + self.finishedAt = progress.finishedAt + } +} diff --git a/ios/App/Shared/util/Database.swift b/ios/App/Shared/util/Database.swift index 4e1bd1b1..542af63a 100644 --- a/ios/App/Shared/util/Database.swift +++ b/ios/App/Shared/util/Database.swift @@ -177,6 +177,12 @@ class Database { } } + public func removeDownloadItem(_ downloadItem: DownloadItem) { + Database.realmQueue.sync { + try! instance.write { instance.delete(downloadItem) } + } + } + public func getDeviceSettings() -> DeviceSettings { return Database.realmQueue.sync { return instance.objects(DeviceSettings.self).first ?? getDefaultDeviceSettings()