mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2026-08-08 04:48:36 +02:00
Auto formatting AbsDownloader.kt
This commit is contained in:
@@ -8,10 +8,10 @@ import com.audiobookshelf.app.MainActivity
|
||||
import com.audiobookshelf.app.data.*
|
||||
import com.audiobookshelf.app.device.DeviceManager
|
||||
import com.audiobookshelf.app.device.FolderScanner
|
||||
import com.audiobookshelf.app.managers.DownloadItemManager
|
||||
import com.audiobookshelf.app.models.DownloadItem
|
||||
import com.audiobookshelf.app.models.DownloadItemPart
|
||||
import com.audiobookshelf.app.server.ApiHandler
|
||||
import com.audiobookshelf.app.managers.DownloadItemManager
|
||||
import com.fasterxml.jackson.core.json.JsonReadFeature
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.getcapacitor.JSObject
|
||||
@@ -24,7 +24,9 @@ import java.io.File
|
||||
@CapacitorPlugin(name = "AbsDownloader")
|
||||
class AbsDownloader : Plugin() {
|
||||
private val tag = "AbsDownloader"
|
||||
private var jacksonMapper = jacksonObjectMapper().enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature())
|
||||
private var jacksonMapper =
|
||||
jacksonObjectMapper()
|
||||
.enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature())
|
||||
|
||||
lateinit var mainActivity: MainActivity
|
||||
lateinit var downloadManager: DownloadManager
|
||||
@@ -32,24 +34,32 @@ class AbsDownloader : Plugin() {
|
||||
lateinit var folderScanner: FolderScanner
|
||||
lateinit var downloadItemManager: DownloadItemManager
|
||||
|
||||
private val clientEventEmitter = (object : DownloadItemManager.DownloadEventEmitter {
|
||||
override fun onDownloadItem(downloadItem:DownloadItem) {
|
||||
notifyListeners("onDownloadItem", JSObject(jacksonMapper.writeValueAsString(downloadItem)))
|
||||
}
|
||||
override fun onDownloadItemPartUpdate(downloadItemPart:DownloadItemPart) {
|
||||
notifyListeners("onDownloadItemPartUpdate", JSObject(jacksonMapper.writeValueAsString(downloadItemPart)))
|
||||
}
|
||||
override fun onDownloadItemComplete(jsobj:JSObject) {
|
||||
notifyListeners("onItemDownloadComplete", jsobj)
|
||||
}
|
||||
})
|
||||
private val clientEventEmitter =
|
||||
(object : DownloadItemManager.DownloadEventEmitter {
|
||||
override fun onDownloadItem(downloadItem: DownloadItem) {
|
||||
notifyListeners(
|
||||
"onDownloadItem",
|
||||
JSObject(jacksonMapper.writeValueAsString(downloadItem))
|
||||
)
|
||||
}
|
||||
override fun onDownloadItemPartUpdate(downloadItemPart: DownloadItemPart) {
|
||||
notifyListeners(
|
||||
"onDownloadItemPartUpdate",
|
||||
JSObject(jacksonMapper.writeValueAsString(downloadItemPart))
|
||||
)
|
||||
}
|
||||
override fun onDownloadItemComplete(jsobj: JSObject) {
|
||||
notifyListeners("onItemDownloadComplete", jsobj)
|
||||
}
|
||||
})
|
||||
|
||||
override fun load() {
|
||||
mainActivity = (activity as MainActivity)
|
||||
downloadManager = activity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||
folderScanner = FolderScanner(mainActivity)
|
||||
apiHandler = ApiHandler(mainActivity)
|
||||
downloadItemManager = DownloadItemManager(downloadManager, folderScanner, mainActivity, clientEventEmitter)
|
||||
downloadItemManager =
|
||||
DownloadItemManager(downloadManager, folderScanner, mainActivity, clientEventEmitter)
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
@@ -58,12 +68,17 @@ class AbsDownloader : Plugin() {
|
||||
var episodeId = call.data.getString("episodeId").toString()
|
||||
if (episodeId == "null") episodeId = ""
|
||||
var localFolderId = call.data.getString("localFolderId", "").toString()
|
||||
Log.d(tag, "Download library item $libraryItemId to folder $localFolderId / episode: $episodeId")
|
||||
Log.d(
|
||||
tag,
|
||||
"Download library item $libraryItemId to folder $localFolderId / episode: $episodeId"
|
||||
)
|
||||
|
||||
val downloadId = if (episodeId.isEmpty()) libraryItemId else "$libraryItemId-$episodeId"
|
||||
if (downloadItemManager.downloadItemQueue.find { it.id == downloadId } != null) {
|
||||
Log.d(tag, "Download already started for this media entity $downloadId")
|
||||
return call.resolve(JSObject("{\"error\":\"Download already started for this media entity\"}"))
|
||||
return call.resolve(
|
||||
JSObject("{\"error\":\"Download already started for this media entity\"}")
|
||||
)
|
||||
}
|
||||
|
||||
apiHandler.getLibraryItemWithProgress(libraryItemId, episodeId) { libraryItem ->
|
||||
@@ -79,7 +94,17 @@ class AbsDownloader : Plugin() {
|
||||
|
||||
if (localFolder == null && localFolderId.startsWith("internal-")) {
|
||||
Log.d(tag, "Creating new App Storage internal LocalFolder $localFolderId")
|
||||
localFolder = LocalFolder(localFolderId, "Internal App Storage", "", "", "", "", "internal", libraryItem.mediaType)
|
||||
localFolder =
|
||||
LocalFolder(
|
||||
localFolderId,
|
||||
"Internal App Storage",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"internal",
|
||||
libraryItem.mediaType
|
||||
)
|
||||
DeviceManager.dbManager.saveLocalFolder(localFolder)
|
||||
}
|
||||
|
||||
@@ -89,9 +114,8 @@ class AbsDownloader : Plugin() {
|
||||
call.resolve(JSObject("{\"error\":\"Invalid library item not a podcast\"}"))
|
||||
} else if (episodeId.isNotEmpty()) {
|
||||
val podcast = libraryItem.media as Podcast
|
||||
val episode = podcast.episodes?.find { podcastEpisode ->
|
||||
podcastEpisode.id == episodeId
|
||||
}
|
||||
val episode =
|
||||
podcast.episodes?.find { podcastEpisode -> podcastEpisode.id == episodeId }
|
||||
if (episode == null) {
|
||||
call.resolve(JSObject("{\"error\":\"Invalid podcast episode not found\"}"))
|
||||
} else {
|
||||
@@ -118,21 +142,25 @@ class AbsDownloader : Plugin() {
|
||||
|
||||
// Replace characters that cant be used in the file system
|
||||
// Reserved characters: ?:\"*|/\\<>
|
||||
private fun cleanStringForFileSystem(str:String):String {
|
||||
private fun cleanStringForFileSystem(str: String): String {
|
||||
val reservedCharacters = listOf("?", "\"", "*", "|", "/", "\\", "<", ">")
|
||||
var newTitle = str
|
||||
newTitle = newTitle.replace(":", " -") // Special case replace : with -
|
||||
|
||||
reservedCharacters.forEach {
|
||||
newTitle = newTitle.replace(it, "")
|
||||
}
|
||||
reservedCharacters.forEach { newTitle = newTitle.replace(it, "") }
|
||||
return newTitle
|
||||
}
|
||||
|
||||
private fun startLibraryItemDownload(libraryItem: LibraryItem, localFolder: LocalFolder, episode:PodcastEpisode?) {
|
||||
private fun startLibraryItemDownload(
|
||||
libraryItem: LibraryItem,
|
||||
localFolder: LocalFolder,
|
||||
episode: PodcastEpisode?
|
||||
) {
|
||||
val isInternal = localFolder.id.startsWith("internal-")
|
||||
|
||||
val tempFolderPath = if (isInternal) "${mainActivity.filesDir}/downloads/${libraryItem.id}" else mainActivity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
|
||||
val tempFolderPath =
|
||||
if (isInternal) "${mainActivity.filesDir}/downloads/${libraryItem.id}"
|
||||
else mainActivity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
|
||||
|
||||
Log.d(tag, "downloadCacheDirectory=$tempFolderPath")
|
||||
|
||||
@@ -143,8 +171,25 @@ class AbsDownloader : Plugin() {
|
||||
val tracks = libraryItem.media.getAudioTracks()
|
||||
Log.d(tag, "Starting library item download with ${tracks.size} tracks")
|
||||
val itemSubfolder = "$bookAuthor/$bookTitle"
|
||||
val itemFolderPath = if (isInternal) "$tempFolderPath" else "${localFolder.absolutePath}/$itemSubfolder"
|
||||
val downloadItem = DownloadItem(libraryItem.id, libraryItem.id, null, libraryItem.userMediaProgress,DeviceManager.serverConnectionConfig?.id ?: "", DeviceManager.serverAddress, DeviceManager.serverUserId, libraryItem.mediaType, itemFolderPath, localFolder, bookTitle, itemSubfolder, libraryItem.media, mutableListOf())
|
||||
val itemFolderPath =
|
||||
if (isInternal) "$tempFolderPath" else "${localFolder.absolutePath}/$itemSubfolder"
|
||||
val downloadItem =
|
||||
DownloadItem(
|
||||
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
|
||||
book.ebookFile?.let { ebookFile ->
|
||||
@@ -155,16 +200,35 @@ class AbsDownloader : Plugin() {
|
||||
val destinationFile = File("$tempFolderPath/$destinationFilename")
|
||||
|
||||
if (destinationFile.exists()) {
|
||||
Log.d(tag, "TEMP ebook file already exists, removing it from ${destinationFile.absolutePath}")
|
||||
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}")
|
||||
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)
|
||||
val downloadItemPart =
|
||||
DownloadItemPart.make(
|
||||
downloadItem.id,
|
||||
destinationFilename,
|
||||
fileSize,
|
||||
destinationFile,
|
||||
finalDestinationFile,
|
||||
itemSubfolder,
|
||||
serverPath,
|
||||
localFolder,
|
||||
ebookFile,
|
||||
null,
|
||||
null
|
||||
)
|
||||
downloadItem.downloadItemParts.add(downloadItemPart)
|
||||
}
|
||||
|
||||
@@ -173,34 +237,59 @@ class AbsDownloader : Plugin() {
|
||||
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
|
||||
// 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")
|
||||
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}")
|
||||
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}")
|
||||
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)
|
||||
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 }
|
||||
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"
|
||||
@@ -209,16 +298,35 @@ class AbsDownloader : Plugin() {
|
||||
val finalDestinationFile = File("$itemFolderPath/$destinationFilename")
|
||||
|
||||
if (destinationFile.exists()) {
|
||||
Log.d(tag, "TEMP Audio file already exists, removing it from ${destinationFile.absolutePath}")
|
||||
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}")
|
||||
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)
|
||||
val downloadItemPart =
|
||||
DownloadItemPart.make(
|
||||
downloadItem.id,
|
||||
destinationFilename,
|
||||
coverFileSize,
|
||||
destinationFile,
|
||||
finalDestinationFile,
|
||||
itemSubfolder,
|
||||
serverPath,
|
||||
localFolder,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
downloadItem.downloadItemParts.add(downloadItemPart)
|
||||
}
|
||||
|
||||
@@ -233,26 +341,64 @@ class AbsDownloader : Plugin() {
|
||||
val fileSize = audioTrack?.metadata?.size ?: 0
|
||||
|
||||
Log.d(tag, "Starting podcast episode download")
|
||||
val itemFolderPath = if (isInternal) "$tempFolderPath" else "${localFolder.absolutePath}/$podcastTitle"
|
||||
val itemFolderPath =
|
||||
if (isInternal) "$tempFolderPath" else "${localFolder.absolutePath}/$podcastTitle"
|
||||
val downloadItemId = "${libraryItem.id}-${episode?.id}"
|
||||
val downloadItem = DownloadItem(downloadItemId, libraryItem.id, episode?.id, libraryItem.userMediaProgress, DeviceManager.serverConnectionConfig?.id ?: "", DeviceManager.serverAddress, DeviceManager.serverUserId, libraryItem.mediaType, itemFolderPath, localFolder, podcastTitle, podcastTitle, libraryItem.media, mutableListOf())
|
||||
val downloadItem =
|
||||
DownloadItem(
|
||||
downloadItemId,
|
||||
libraryItem.id,
|
||||
episode?.id,
|
||||
libraryItem.userMediaProgress,
|
||||
DeviceManager.serverConnectionConfig?.id ?: "",
|
||||
DeviceManager.serverAddress,
|
||||
DeviceManager.serverUserId,
|
||||
libraryItem.mediaType,
|
||||
itemFolderPath,
|
||||
localFolder,
|
||||
podcastTitle,
|
||||
podcastTitle,
|
||||
libraryItem.media,
|
||||
mutableListOf()
|
||||
)
|
||||
|
||||
var serverPath = "/api/items/${libraryItem.id}/file/${audioFileIno}/download"
|
||||
var destinationFilename = getFilenameFromRelPath(audioTrack?.relPath ?: "")
|
||||
Log.d(tag, "Audio File Server Path $serverPath | AF RelPath ${audioTrack?.relPath} | LocalFolder Path ${localFolder.absolutePath} | DestName $destinationFilename")
|
||||
Log.d(
|
||||
tag,
|
||||
"Audio File Server Path $serverPath | AF RelPath ${audioTrack?.relPath} | LocalFolder Path ${localFolder.absolutePath} | DestName $destinationFilename"
|
||||
)
|
||||
|
||||
var destinationFile = File("$tempFolderPath/$destinationFilename")
|
||||
var finalDestinationFile = File("$itemFolderPath/$destinationFilename")
|
||||
if (finalDestinationFile.exists()) {
|
||||
Log.d(tag, "Audio file already exists, removing it from ${finalDestinationFile.absolutePath}")
|
||||
Log.d(
|
||||
tag,
|
||||
"Audio file already exists, removing it from ${finalDestinationFile.absolutePath}"
|
||||
)
|
||||
finalDestinationFile.delete()
|
||||
}
|
||||
|
||||
var downloadItemPart = DownloadItemPart.make(downloadItem.id, destinationFilename,fileSize, destinationFile,finalDestinationFile,podcastTitle,serverPath,localFolder,null,audioTrack,episode)
|
||||
var downloadItemPart =
|
||||
DownloadItemPart.make(
|
||||
downloadItem.id,
|
||||
destinationFilename,
|
||||
fileSize,
|
||||
destinationFile,
|
||||
finalDestinationFile,
|
||||
podcastTitle,
|
||||
serverPath,
|
||||
localFolder,
|
||||
null,
|
||||
audioTrack,
|
||||
episode
|
||||
)
|
||||
downloadItem.downloadItemParts.add(downloadItemPart)
|
||||
|
||||
if (libraryItem.media.coverPath != null && libraryItem.media.coverPath?.isNotEmpty() == true) {
|
||||
val coverLibraryFile = libraryItem.libraryFiles?.find { it.metadata.path == libraryItem.media.coverPath }
|
||||
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
|
||||
|
||||
serverPath = "/api/items/${libraryItem.id}/cover"
|
||||
@@ -264,7 +410,20 @@ class AbsDownloader : Plugin() {
|
||||
if (finalDestinationFile.exists()) {
|
||||
Log.d(tag, "Podcast cover already exists - not downloading cover again")
|
||||
} else {
|
||||
downloadItemPart = DownloadItemPart.make(downloadItem.id, destinationFilename,coverFileSize,destinationFile,finalDestinationFile,podcastTitle,serverPath,localFolder,null,null,null)
|
||||
downloadItemPart =
|
||||
DownloadItemPart.make(
|
||||
downloadItem.id,
|
||||
destinationFilename,
|
||||
coverFileSize,
|
||||
destinationFile,
|
||||
finalDestinationFile,
|
||||
podcastTitle,
|
||||
serverPath,
|
||||
localFolder,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
downloadItem.downloadItemParts.add(downloadItemPart)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user