mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-08-31 15:19:34 +02:00
Support downloading covers and podcast episodes
This commit is contained in:
parent
b549528e23
commit
5b7fcca800
2 changed files with 71 additions and 15 deletions
|
@ -123,39 +123,79 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate {
|
||||||
|
|
||||||
@objc func downloadLibraryItem(_ call: CAPPluginCall) {
|
@objc func downloadLibraryItem(_ call: CAPPluginCall) {
|
||||||
let libraryItemId = call.getString("libraryItemId")
|
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 ?? "")")
|
NSLog("Download library item \(libraryItemId ?? "N/A") / episode \(episodeId ?? "N/A")")
|
||||||
guard let libraryItemId = libraryItemId else { call.resolve(); return; }
|
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
|
ApiClient.getLibraryItemWithProgress(libraryItemId: libraryItemId, episodeId: episodeId) { libraryItem in
|
||||||
if (libraryItem == nil) {
|
if let libraryItem = libraryItem {
|
||||||
NSLog("Library item not found")
|
NSLog("Got library item from server \(libraryItem.id)")
|
||||||
call.resolve(["error": "Library item not found"])
|
|
||||||
} else {
|
|
||||||
NSLog("Got library item from server \(libraryItem!.id)")
|
|
||||||
do {
|
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()
|
call.resolve()
|
||||||
} catch {
|
} catch {
|
||||||
NSLog("Failed to download \(error)")
|
debugPrint(error)
|
||||||
call.resolve(["error": "Failed to download"])
|
call.resolve(["error": "Failed to download"])
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
call.resolve(["error": "Server request failed"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func startLibraryItemDownload(_ item: LibraryItem) throws {
|
private func startLibraryItemDownload(_ item: LibraryItem) throws {
|
||||||
guard let tracks = item.media.tracks else {
|
try startLibraryItemDownload(item, episode: nil)
|
||||||
throw LibraryItemDownloadError.noTracks
|
}
|
||||||
|
|
||||||
|
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
|
// 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
|
downloadItem.downloadItemParts = try tracks.enumerated().map({ i, track in
|
||||||
try startLibraryItemTrackDownload(item: item, position: i, track: track)
|
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
|
// Persist in the database before status start coming in
|
||||||
Database.shared.saveDownloadItem(downloadItem)
|
Database.shared.saveDownloadItem(downloadItem)
|
||||||
|
|
||||||
|
@ -187,6 +227,15 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate {
|
||||||
return downloadItemPart
|
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 {
|
private func urlForTrack(item: LibraryItem, track: AudioTrack) -> URL {
|
||||||
// filename needs to be encoded otherwise would just use contentUrl
|
// filename needs to be encoded otherwise would just use contentUrl
|
||||||
let filenameEncoded = track.metadata?.filename.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
|
let filenameEncoded = track.metadata?.filename.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
|
||||||
|
@ -213,6 +262,9 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate {
|
||||||
enum LibraryItemDownloadError: String, Error {
|
enum LibraryItemDownloadError: String, Error {
|
||||||
case noTracks = "No tracks on library item"
|
case noTracks = "No tracks on library item"
|
||||||
case noMetadata = "No metadata for track, unable to download"
|
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 failedDirectory = "Failed to create directory"
|
||||||
case failedDownload = "Failed to download item"
|
case failedDownload = "Failed to download item"
|
||||||
case noTaskDescription = "No task description"
|
case noTaskDescription = "No task description"
|
||||||
|
|
|
@ -35,10 +35,9 @@ struct DownloadItem: Realmable, Codable {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension DownloadItem {
|
extension DownloadItem {
|
||||||
init(libraryItem: LibraryItem, server: ServerConnectionConfig) {
|
init(libraryItem: LibraryItem, episodeId: String?, server: ServerConnectionConfig) {
|
||||||
self.id = libraryItem.id
|
self.id = libraryItem.id
|
||||||
self.libraryItemId = libraryItem.id
|
self.libraryItemId = libraryItem.id
|
||||||
//self.episodeId // TODO
|
|
||||||
self.userMediaProgress = libraryItem.userMediaProgress
|
self.userMediaProgress = libraryItem.userMediaProgress
|
||||||
self.serverConnectionConfigId = server.id
|
self.serverConnectionConfigId = server.id
|
||||||
self.serverAddress = server.address
|
self.serverAddress = server.address
|
||||||
|
@ -46,6 +45,11 @@ extension DownloadItem {
|
||||||
self.mediaType = libraryItem.mediaType
|
self.mediaType = libraryItem.mediaType
|
||||||
self.itemTitle = libraryItem.media.metadata.title
|
self.itemTitle = libraryItem.media.metadata.title
|
||||||
self.media = libraryItem.media
|
self.media = libraryItem.media
|
||||||
|
|
||||||
|
if let episodeId = episodeId {
|
||||||
|
self.id! += "-\(episodeId)"
|
||||||
|
self.episodeId = episodeId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isDoneDownloading() -> Bool {
|
func isDoneDownloading() -> Bool {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue