Cleanup progress handling

This commit is contained in:
ronaldheft 2022-08-06 21:12:21 -04:00
parent dc8bc2fccd
commit 7fded5e105
2 changed files with 75 additions and 30 deletions

View file

@ -11,36 +11,53 @@ import Capacitor
@objc(AbsDownloader) @objc(AbsDownloader)
public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate { public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate {
typealias DownloadProgressHandler = (_ downloadItem: DownloadItem, _ downloadItemPart: inout DownloadItemPart) throws -> Void
private let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] private let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
private lazy var session = URLSession(configuration: .default, delegate: self, delegateQueue: .current) private lazy var session = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue.main)
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
NSLog("Finished downloading \(downloadTask.taskDescription ?? "Unknown Task")") handleDownloadTaskUpdate(downloadTask: downloadTask) { downloadItem, downloadItemPart in
downloadItemPart.progress = 1
guard let downloadItemPartId = downloadTask.taskDescription else { return } downloadItemPart.completed = true
let downloadItem = Database.shared.getDownloadItem(downloadItemPartId: downloadItemPartId) do {
guard let downloadItem = downloadItem else { // Move the downloaded file into place
NSLog("Download item part (%@) not found! Unable to move file!", downloadItemPartId) guard let destinationUrl = downloadItemPart.destinationURL() else {
return throw LibraryItemDownloadError.downloadItemPartDestinationUrlNotDefined
}
try? FileManager.default.removeItem(at: destinationUrl)
try FileManager.default.moveItem(at: location, to: destinationUrl)
downloadItemPart.moved = true
} catch {
downloadItemPart.failed = true
throw error
}
} }
NSLog("Found downloadItem(%@)", downloadItem.id)
self.moveLibraryItemToFileDirectory(tempUrl: location)
} }
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
NSLog("Error downloading \(task.taskDescription ?? "Unknown Task"): \(error ?? "Unknown Error")") handleDownloadTaskUpdate(downloadTask: task) { downloadItem, downloadItemPart in
if let error = error {
downloadItemPart.failed = true
throw error
}
}
} }
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
do { handleDownloadTaskUpdate(downloadTask: downloadTask) { downloadItem, downloadItemPart in
guard let downloadItemPartId = downloadTask.taskDescription else { throw LibraryItemDownloadError.noTaskDescription }
// Calculate the download percentage // Calculate the download percentage
let percentDownloaded = (Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)) * 100 let percentDownloaded = (Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)) * 100
NSLog("Received download status \(downloadItemPartId): \(percentDownloaded)") downloadItemPart.progress = percentDownloaded
}
}
private func handleDownloadTaskUpdate(downloadTask: URLSessionTask, progressHandler: DownloadProgressHandler) {
do {
guard let downloadItemPartId = downloadTask.taskDescription else { throw LibraryItemDownloadError.noTaskDescription }
NSLog("Received download update for \(downloadItemPartId)")
// Find the download item // Find the download item
let downloadItem = Database.shared.getDownloadItem(downloadItemPartId: downloadItemPartId) let downloadItem = Database.shared.getDownloadItem(downloadItemPartId: downloadItemPartId)
guard let downloadItem = downloadItem else { throw LibraryItemDownloadError.downloadItemNotFound } guard let downloadItem = downloadItem else { throw LibraryItemDownloadError.downloadItemNotFound }
@ -49,14 +66,22 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate {
let downloadItemPart = downloadItem.downloadItemParts.filter { $0.id == downloadItemPartId }.first let downloadItemPart = downloadItem.downloadItemParts.filter { $0.id == downloadItemPartId }.first
guard var downloadItemPart = downloadItemPart else { throw LibraryItemDownloadError.downloadItemPartNotFound } guard var downloadItemPart = downloadItemPart else { throw LibraryItemDownloadError.downloadItemPartNotFound }
// Call the progress handler
do {
try progressHandler(downloadItem, &downloadItemPart)
} catch {
NSLog("Error while processing progress")
debugPrint(error)
}
// Update the progress // Update the progress
downloadItemPart.progress = percentDownloaded
Database.shared.updateDownloadItemPart(downloadItemPart) Database.shared.updateDownloadItemPart(downloadItemPart)
// Notify the UI // Notify the UI
try! notifyListeners("onItemDownloadUpdate", data: downloadItem.asDictionary()) try! notifyListeners("onItemDownloadUpdate", data: downloadItem.asDictionary())
} catch { } catch {
NSLog("DownloadItemError: \(error)") NSLog("DownloadItemError")
debugPrint(error)
} }
} }
@ -147,10 +172,6 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate {
return itemDirectory return itemDirectory
} }
private func moveLibraryItemToFileDirectory(tempUrl: URL) {
//try FileManager.default.moveItem(at: tempUrl, to: localUrl)
}
} }
enum LibraryItemDownloadError: String, Error { enum LibraryItemDownloadError: String, Error {
@ -161,4 +182,5 @@ enum LibraryItemDownloadError: String, Error {
case noTaskDescription = "No task description" case noTaskDescription = "No task description"
case downloadItemNotFound = "DownloadItem not found" case downloadItemNotFound = "DownloadItem not found"
case downloadItemPartNotFound = "DownloadItemPart not found" case downloadItemPartNotFound = "DownloadItemPart not found"
case downloadItemPartDestinationUrlNotDefined = "DownloadItemPart destination URL not defined"
} }

View file

@ -51,7 +51,6 @@ extension DownloadItem {
struct DownloadItemPart: Realmable, Codable { struct DownloadItemPart: Realmable, Codable {
var id: String = UUID().uuidString var id: String = UUID().uuidString
var filename: String? var filename: String?
var finalDestinationPath: String?
var itemTitle: String? var itemTitle: String?
var serverPath: String? var serverPath: String?
var audioTrack: AudioTrack? var audioTrack: AudioTrack?
@ -61,7 +60,6 @@ struct DownloadItemPart: Realmable, Codable {
var failed: Bool = false var failed: Bool = false
var uri: String? var uri: String?
var destinationUri: String? var destinationUri: String?
var finalDestinationUri: String?
var progress: Double = 0 var progress: Double = 0
var task: URLSessionDownloadTask! var task: URLSessionDownloadTask!
@ -74,15 +72,40 @@ struct DownloadItemPart: Realmable, Codable {
} }
private enum CodingKeys : String, CodingKey { private enum CodingKeys : String, CodingKey {
case id, filename, completed, moved, failed, progress case id, filename, itemTitle, completed, moved, failed, progress
} }
} }
extension DownloadItemPart { extension DownloadItemPart {
init(filename: String, destination: URL, itemTitle: String, serverPath: String, audioTrack:AudioTrack?, episode: PodcastEpisode?) { init(filename: String, destination: URL, itemTitle: String, serverPath: String, audioTrack: AudioTrack?, episode: PodcastEpisode?) {
var downloadUrl = "" // TODO: Set this self.filename = filename
self.itemTitle = itemTitle
self.serverPath = serverPath
self.audioTrack = audioTrack
self.episode = episode
let config = Store.serverConfig!
var downloadUrl = "\(config.address)\(serverPath)?token=\(config.token)"
if (serverPath.hasSuffix("/cover")) { if (serverPath.hasSuffix("/cover")) {
downloadUrl += "&format=jpeg" // For cover images force to jpeg downloadUrl += "&format=jpeg" // For cover images force to jpeg
} }
self.uri = downloadUrl
self.destinationUri = destination.path
}
func downloadURL() -> URL? {
if let uri = self.uri {
return URL(string: uri)
} else {
return nil
}
}
func destinationURL() -> URL? {
if let destinationUri = self.destinationUri {
return URL(fileURLWithPath: destinationUri)
} else {
return nil
}
} }
} }