Refactor AbsDownloader

This commit is contained in:
Nicholas Wallace
2025-02-28 22:07:24 -07:00
parent ee0ab43fc5
commit 4a09238a8e
@@ -160,190 +160,22 @@ class AbsDownloader : Plugin() {
val tempFolderPath = val tempFolderPath =
if (isInternal) "${mainActivity.filesDir}/downloads/${libraryItem.id}" if (isInternal) "${mainActivity.filesDir}/downloads/${libraryItem.id}"
else mainActivity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) else "${mainActivity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)}"
Log.d(tag, "downloadCacheDirectory=$tempFolderPath") Log.d(tag, "downloadCacheDirectory=$tempFolderPath")
if (libraryItem.mediaType == "book") {
val bookTitle = cleanStringForFileSystem(libraryItem.media.metadata.title)
val bookAuthor = cleanStringForFileSystem(libraryItem.media.metadata.getAuthorDisplayName())
val tracks = libraryItem.media.getAudioTracks()
Log.d(tag, "Starting library item download with ${tracks.size} tracks")
val itemSubfolder = "$bookAuthor/$bookTitle"
val itemFolderPath = val itemFolderPath =
if (isInternal) "$tempFolderPath" else "${localFolder.absolutePath}/$itemSubfolder" if (isInternal) "$tempFolderPath"
val downloadItem = else
DownloadItem( "${localFolder.absolutePath}/${cleanStringForFileSystem(libraryItem.media.metadata.title)}"
libraryItem.id,
libraryItem.id,
null,
libraryItem.userMediaProgress,
DeviceManager.serverConnectionConfig?.id ?: "",
DeviceManager.serverAddress,
DeviceManager.serverUserId,
libraryItem.mediaType,
itemFolderPath,
localFolder,
bookTitle,
itemSubfolder,
libraryItem.media,
mutableListOf()
)
val book = libraryItem.media as Book val downloadItemId = if (episode != null) "${libraryItem.id}-${episode.id}" else libraryItem.id
book.ebookFile?.let { ebookFile -> val titleCleaned = cleanStringForFileSystem(libraryItem.media.metadata.title)
val fileSize = ebookFile.metadata?.size ?: 0 val author =
val serverPath = "/api/items/${libraryItem.id}/file/${ebookFile.ino}/download" if (episode == null)
val destinationFilename = getFilenameFromRelPath(ebookFile.metadata?.relPath ?: "") cleanStringForFileSystem(libraryItem.media.metadata.getAuthorDisplayName())
val finalDestinationFile = File("$itemFolderPath/$destinationFilename") else titleCleaned
val destinationFile = File("$tempFolderPath/$destinationFilename") val itemSubfolder = if (episode == null) "$author/$titleCleaned" else "$titleCleaned"
if (destinationFile.exists()) {
Log.d(
tag,
"TEMP ebook file already exists, removing it from ${destinationFile.absolutePath}"
)
destinationFile.delete()
}
if (finalDestinationFile.exists()) {
Log.d(
tag,
"ebook file already exists, removing it from ${finalDestinationFile.absolutePath}"
)
finalDestinationFile.delete()
}
val downloadItemPart =
DownloadItemPart.make(
downloadItem.id,
destinationFilename,
fileSize,
destinationFile,
finalDestinationFile,
itemSubfolder,
serverPath,
localFolder,
ebookFile,
null,
null
)
downloadItem.downloadItemParts.add(downloadItemPart)
}
// Create download item part for each audio track
val audioFiles = (libraryItem.media as Book).audioFiles ?: mutableListOf()
tracks.forEach { audioTrack ->
val fileSize = audioTrack.metadata?.size ?: 0
// TODO: Currently file ino is only stored on AudioFile. This should be updated server side
// to be in FileMetadata or on the AudioTrack
val audioFileIno = audioFiles.find { it.metadata.path == audioTrack.metadata?.path }?.ino
val serverPath = "/api/items/${libraryItem.id}/file/${audioFileIno}/download"
val destinationFilename = getFilenameFromRelPath(audioTrack.relPath)
Log.d(
tag,
"Audio File Server Path $serverPath | AF RelPath ${audioTrack.relPath} | LocalFolder Path ${localFolder.absolutePath} | DestName $destinationFilename"
)
val finalDestinationFile = File("$itemFolderPath/$destinationFilename")
val destinationFile = File("$tempFolderPath/$destinationFilename")
if (destinationFile.exists()) {
Log.d(
tag,
"TEMP Audio file already exists, removing it from ${destinationFile.absolutePath}"
)
destinationFile.delete()
}
if (finalDestinationFile.exists()) {
Log.d(
tag,
"Audio file already exists, removing it from ${finalDestinationFile.absolutePath}"
)
finalDestinationFile.delete()
}
val downloadItemPart =
DownloadItemPart.make(
downloadItem.id,
destinationFilename,
fileSize,
destinationFile,
finalDestinationFile,
itemSubfolder,
serverPath,
localFolder,
null,
audioTrack,
null
)
downloadItem.downloadItemParts.add(downloadItemPart)
}
if (downloadItem.downloadItemParts.isNotEmpty()) {
// Add cover download item
if (libraryItem.media.coverPath != null && libraryItem.media.coverPath?.isNotEmpty() == true
) {
val coverLibraryFile =
libraryItem.libraryFiles?.find { it.metadata.path == libraryItem.media.coverPath }
val coverFileSize = coverLibraryFile?.metadata?.size ?: 0
val serverPath = "/api/items/${libraryItem.id}/cover"
val destinationFilename = "cover-${libraryItem.id}.jpg"
val destinationFile = File("$tempFolderPath/$destinationFilename")
val finalDestinationFile = File("$itemFolderPath/$destinationFilename")
if (destinationFile.exists()) {
Log.d(
tag,
"TEMP Audio file already exists, removing it from ${destinationFile.absolutePath}"
)
destinationFile.delete()
}
if (finalDestinationFile.exists()) {
Log.d(
tag,
"Cover already exists, removing it from ${finalDestinationFile.absolutePath}"
)
finalDestinationFile.delete()
}
val downloadItemPart =
DownloadItemPart.make(
downloadItem.id,
destinationFilename,
coverFileSize,
destinationFile,
finalDestinationFile,
itemSubfolder,
serverPath,
localFolder,
null,
null,
null
)
downloadItem.downloadItemParts.add(downloadItemPart)
}
downloadItemManager.addDownloadItem(downloadItem)
}
} else {
// Podcast episode download
val podcastTitle = cleanStringForFileSystem(libraryItem.media.metadata.title)
val audioTrack = episode?.audioTrack
val audioFileIno = episode?.audioFile?.ino
val fileSize = audioTrack?.metadata?.size ?: 0
Log.d(tag, "Starting podcast episode download")
val itemFolderPath =
if (isInternal) "$tempFolderPath" else "${localFolder.absolutePath}/$podcastTitle"
val downloadItemId = "${libraryItem.id}-${episode?.id}"
val downloadItem = val downloadItem =
DownloadItem( DownloadItem(
downloadItemId, downloadItemId,
@@ -356,37 +188,78 @@ class AbsDownloader : Plugin() {
libraryItem.mediaType, libraryItem.mediaType,
itemFolderPath, itemFolderPath,
localFolder, localFolder,
podcastTitle, titleCleaned,
podcastTitle, itemSubfolder,
libraryItem.media, libraryItem.media,
mutableListOf() mutableListOf()
) )
var serverPath = "/api/items/${libraryItem.id}/file/${audioFileIno}/download" if (libraryItem.mediaType == "book") {
var destinationFilename = getFilenameFromRelPath(audioTrack?.relPath ?: "") val book = libraryItem.media as Book
Log.d( book.ebookFile?.let { ebookFile ->
tag, val serverPath = "/api/items/${libraryItem.id}/file/${ebookFile.ino}/download"
"Audio File Server Path $serverPath | AF RelPath ${audioTrack?.relPath} | LocalFolder Path ${localFolder.absolutePath} | DestName $destinationFilename" val destinationFilename = getFilenameFromRelPath(ebookFile.metadata?.relPath ?: "")
) val destinationFile = File("$tempFolderPath/$destinationFilename")
val finalDestinationFile = File("$itemFolderPath/$destinationFilename")
var destinationFile = File("$tempFolderPath/$destinationFilename") checkAndDeleteFile(destinationFile, finalDestinationFile)
var finalDestinationFile = File("$itemFolderPath/$destinationFilename") val downloadItemPart =
if (finalDestinationFile.exists()) {
Log.d(
tag,
"Audio file already exists, removing it from ${finalDestinationFile.absolutePath}"
)
finalDestinationFile.delete()
}
var downloadItemPart =
DownloadItemPart.make( DownloadItemPart.make(
downloadItem.id, downloadItem.id,
destinationFilename, destinationFilename,
fileSize, ebookFile.metadata?.size ?: 0,
destinationFile, destinationFile,
finalDestinationFile, finalDestinationFile,
podcastTitle, itemSubfolder,
serverPath,
localFolder,
ebookFile,
null,
null
)
downloadItem.downloadItemParts.add(downloadItemPart)
}
val audioFiles = book.audioFiles ?: mutableListOf()
libraryItem.media.getAudioTracks().forEach { audioTrack ->
val audioFileIno = audioFiles.find { it.metadata.path == audioTrack.metadata?.path }?.ino
val serverPath = "/api/items/${libraryItem.id}/file/${audioFileIno}/download"
val destinationFilename = getFilenameFromRelPath(audioTrack.relPath)
val destinationFile = File("$tempFolderPath/$destinationFilename")
val finalDestinationFile = File("$itemFolderPath/$destinationFilename")
checkAndDeleteFile(destinationFile, finalDestinationFile)
val downloadItemPart =
DownloadItemPart.make(
downloadItem.id,
destinationFilename,
audioTrack.metadata?.size ?: 0,
destinationFile,
finalDestinationFile,
itemSubfolder,
serverPath,
localFolder,
null,
audioTrack,
null
)
downloadItem.downloadItemParts.add(downloadItemPart)
}
} else {
val audioTrack = episode?.audioTrack
val audioFileIno = episode?.audioFile?.ino
val serverPath = "/api/items/${libraryItem.id}/file/${audioFileIno}/download"
val destinationFilename = getFilenameFromRelPath(audioTrack?.relPath ?: "")
val destinationFile = File("$tempFolderPath/$destinationFilename")
val finalDestinationFile = File("$itemFolderPath/$destinationFilename")
checkAndDeleteFile(destinationFile, finalDestinationFile)
val downloadItemPart =
DownloadItemPart.make(
downloadItem.id,
destinationFilename,
audioTrack?.metadata?.size ?: 0,
destinationFile,
finalDestinationFile,
titleCleaned,
serverPath, serverPath,
localFolder, localFolder,
null, null,
@@ -394,30 +267,24 @@ class AbsDownloader : Plugin() {
episode episode
) )
downloadItem.downloadItemParts.add(downloadItemPart) downloadItem.downloadItemParts.add(downloadItemPart)
}
if (libraryItem.media.coverPath != null && libraryItem.media.coverPath?.isNotEmpty() == true if (libraryItem.media.coverPath != null && libraryItem.media.coverPath?.isNotEmpty() == true) {
) {
val coverLibraryFile = val coverLibraryFile =
libraryItem.libraryFiles?.find { it.metadata.path == libraryItem.media.coverPath } libraryItem.libraryFiles?.find { it.metadata.path == libraryItem.media.coverPath }
val coverFileSize = coverLibraryFile?.metadata?.size ?: 0 val serverPath = "/api/items/${libraryItem.id}/cover"
val destinationFilename = if (episode == null) "cover-${libraryItem.id}.jpg" else "cover.jpg"
serverPath = "/api/items/${libraryItem.id}/cover" val destinationFile = File("$tempFolderPath/$destinationFilename")
destinationFilename = "cover.jpg" val finalDestinationFile = File("$itemFolderPath/$destinationFilename")
checkAndDeleteFile(destinationFile, finalDestinationFile)
destinationFile = File("$tempFolderPath/$destinationFilename") val downloadItemPart =
finalDestinationFile = File("$itemFolderPath/$destinationFilename")
if (finalDestinationFile.exists()) {
Log.d(tag, "Podcast cover already exists - not downloading cover again")
} else {
downloadItemPart =
DownloadItemPart.make( DownloadItemPart.make(
downloadItem.id, downloadItem.id,
destinationFilename, destinationFilename,
coverFileSize, coverLibraryFile?.metadata?.size ?: 0,
destinationFile, destinationFile,
finalDestinationFile, finalDestinationFile,
podcastTitle, titleCleaned,
serverPath, serverPath,
localFolder, localFolder,
null, null,
@@ -426,9 +293,23 @@ class AbsDownloader : Plugin() {
) )
downloadItem.downloadItemParts.add(downloadItemPart) downloadItem.downloadItemParts.add(downloadItemPart)
} }
}
if (downloadItem.downloadItemParts.isNotEmpty()) {
downloadItemManager.addDownloadItem(downloadItem) downloadItemManager.addDownloadItem(downloadItem)
} }
} }
/* Delete files if they already exist */
private fun checkAndDeleteFile(destinationFile: File, finalDestinationFile: File) {
if (destinationFile.exists()) {
Log.d(tag, "TEMP file already exists, removing it from ${destinationFile.absolutePath}")
destinationFile.delete()
}
if (finalDestinationFile.exists()) {
Log.d(tag, "File already exists, removing it from ${finalDestinationFile.absolutePath}")
finalDestinationFile.delete()
}
}
} }