Support downloading covers and podcast episodes

This commit is contained in:
ronaldheft 2022-08-07 11:23:50 -04:00
parent b549528e23
commit 5b7fcca800
2 changed files with 71 additions and 15 deletions

View file

@ -123,39 +123,79 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate {
@objc func downloadLibraryItem(_ call: CAPPluginCall) {
let libraryItemId = call.getString("libraryItemId")
let episodeId = call.getString("episodeId")
var episodeId = call.getString("episodeId")
if ( episodeId == "null" ) { episodeId = nil }
NSLog("Download library item \(libraryItemId ?? "N/A") / episode \(episodeId ?? "")")
guard let libraryItemId = libraryItemId else { call.resolve(); return; }
NSLog("Download library item \(libraryItemId ?? "N/A") / episode \(episodeId ?? "N/A")")
guard let libraryItemId = libraryItemId else { return call.resolve(["error": "libraryItemId not specified"]) }
// Verify the file isn't already downloading
let downloadItemId = episodeId != nil ? "\(libraryItemId)-\(episodeId!)" : libraryItemId
let downloadItem = Database.shared.getDownloadItem(downloadItemId: downloadItemId)
if ( downloadItem != nil ) {
return call.resolve(["error": "Download already started for this media entity"])
}
ApiClient.getLibraryItemWithProgress(libraryItemId: libraryItemId, episodeId: episodeId) { libraryItem in
if (libraryItem == nil) {
NSLog("Library item not found")
call.resolve(["error": "Library item not found"])
} else {
NSLog("Got library item from server \(libraryItem!.id)")
if let libraryItem = libraryItem {
NSLog("Got library item from server \(libraryItem.id)")
do {
try self.startLibraryItemDownload(libraryItem!)
if let episodeId = episodeId {
// Download a podcast episode
guard libraryItem.mediaType == "podcast" else { throw LibraryItemDownloadError.libraryItemNotPodcast }
let episode = libraryItem.media.episodes?.first(where: { $0.id == episodeId })
guard let episode = episode else { throw LibraryItemDownloadError.podcastEpisodeNotFound }
try self.startLibraryItemDownload(libraryItem, episode: episode)
} else {
// Download a book
try self.startLibraryItemDownload(libraryItem)
}
call.resolve()
} catch {
NSLog("Failed to download \(error)")
debugPrint(error)
call.resolve(["error": "Failed to download"])
}
} else {
call.resolve(["error": "Server request failed"])
}
}
}
private func startLibraryItemDownload(_ item: LibraryItem) throws {
guard let tracks = item.media.tracks else {
throw LibraryItemDownloadError.noTracks
try startLibraryItemDownload(item, episode: nil)
}
private func startLibraryItemDownload(_ item: LibraryItem, episode: PodcastEpisode?) throws {
var tracks: [AudioTrack]
var episodeId: String?
// Handle the different media type downloads
switch item.mediaType {
case "book":
guard let bookTracks = item.media.tracks else { throw LibraryItemDownloadError.noTracks }
tracks = bookTracks
case "podcast":
guard let episode = episode else { throw LibraryItemDownloadError.podcastEpisodeNotFound }
guard let podcastTrack = episode.audioTrack else { throw LibraryItemDownloadError.noTracks }
episodeId = episode.id
tracks = [podcastTrack]
default:
throw LibraryItemDownloadError.unknownMediaType
}
// Queue up everything for downloading
var downloadItem = DownloadItem(libraryItem: item, server: Store.serverConfig!)
var downloadItem = DownloadItem(libraryItem: item, episodeId: episodeId, server: Store.serverConfig!)
downloadItem.downloadItemParts = try tracks.enumerated().map({ i, track in
try startLibraryItemTrackDownload(item: item, position: i, track: track)
})
// Also download the cover
if item.media.coverPath != nil && !item.media.coverPath!.isEmpty {
if let coverDownload = try? startLibraryItemCoverDownload(item: item) {
downloadItem.downloadItemParts.append(coverDownload)
}
}
// Persist in the database before status start coming in
Database.shared.saveDownloadItem(downloadItem)
@ -187,6 +227,15 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate {
return downloadItemPart
}
private func startLibraryItemCoverDownload(item: LibraryItem) throws -> DownloadItemPart {
let filename = "cover.jpg"
let serverPath = "/api/items/\(item.id)/cover"
let itemDirectory = try createLibraryItemFileDirectory(item: item)
let localUrl = itemDirectory.appendingPathComponent("\(filename)")
return DownloadItemPart(filename: filename, destination: localUrl, itemTitle: "cover", serverPath: serverPath, audioTrack: nil, episode: nil)
}
private func urlForTrack(item: LibraryItem, track: AudioTrack) -> URL {
// filename needs to be encoded otherwise would just use contentUrl
let filenameEncoded = track.metadata?.filename.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
@ -213,6 +262,9 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate {
enum LibraryItemDownloadError: String, Error {
case noTracks = "No tracks on library item"
case noMetadata = "No metadata for track, unable to download"
case libraryItemNotPodcast = "Library item is not a podcast but episode was requested"
case podcastEpisodeNotFound = "Invalid podcast episode not found"
case unknownMediaType = "Unknown media type"
case failedDirectory = "Failed to create directory"
case failedDownload = "Failed to download item"
case noTaskDescription = "No task description"

View file

@ -35,10 +35,9 @@ struct DownloadItem: Realmable, Codable {
}
extension DownloadItem {
init(libraryItem: LibraryItem, server: ServerConnectionConfig) {
init(libraryItem: LibraryItem, episodeId: String?, server: ServerConnectionConfig) {
self.id = libraryItem.id
self.libraryItemId = libraryItem.id
//self.episodeId // TODO
self.userMediaProgress = libraryItem.userMediaProgress
self.serverConnectionConfigId = server.id
self.serverAddress = server.address
@ -46,6 +45,11 @@ extension DownloadItem {
self.mediaType = libraryItem.mediaType
self.itemTitle = libraryItem.media.metadata.title
self.media = libraryItem.media
if let episodeId = episodeId {
self.id! += "-\(episodeId)"
self.episodeId = episodeId
}
}
func isDoneDownloading() -> Bool {