From 12de187b7af818835eafbec499ad94c7ebfadf41 Mon Sep 17 00:00:00 2001 From: advplyr Date: Tue, 5 Apr 2022 19:44:14 -0500 Subject: [PATCH] Update folder scanner and db to store LocalLibraryItem objects instead of LocalMediaItem objects, some ui fixes and audio player service binding fix --- android/app/src/main/AndroidManifest.xml | 2 +- .../com/audiobookshelf/app/MainActivity.kt | 10 +-- .../audiobookshelf/app/data/DataClasses.kt | 75 +++++++++++++---- .../com/audiobookshelf/app/data/DbManager.kt | 40 +++++----- .../audiobookshelf/app/data/DeviceClasses.kt | 64 ++++++++++----- .../app/data/FolderScanResult.kt | 2 +- .../app/data/PlaybackSession.kt | 4 +- .../app/device/FolderScanner.kt | 80 +++++++++++-------- .../app/player/PlayerNotificationService.kt | 2 +- .../app/plugins/AbsAudioPlayer.kt | 12 ++- .../audiobookshelf/app/plugins/AbsDatabase.kt | 35 ++++---- .../app/plugins/AbsDownloader.kt | 10 +-- components/app/AudioPlayer.vue | 14 ++-- components/app/AudioPlayerContainer.vue | 4 +- components/ui/Dropdown.vue | 2 +- pages/bookshelf/index.vue | 2 +- pages/item/_id.vue | 2 +- pages/localMedia/folders/_id.vue | 29 +++---- pages/localMedia/folders/index.vue | 1 + plugins/capacitor/AbsFileSystem.js | 2 + plugins/db.js | 12 +-- store/index.js | 2 +- 22 files changed, 248 insertions(+), 158 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 424b4a6a..f3adddf9 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -71,7 +71,7 @@ + android:name=".player.PlayerNotificationService"> diff --git a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt index 9d331833..654f77f1 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt @@ -10,7 +10,6 @@ import androidx.core.app.ActivityCompat import com.anggrayudi.storage.SimpleStorage import com.anggrayudi.storage.SimpleStorageHelper import com.audiobookshelf.app.data.AbsDatabase -import com.audiobookshelf.app.data.DbManager import com.audiobookshelf.app.player.PlayerNotificationService import com.audiobookshelf.app.plugins.AbsDownloader import com.audiobookshelf.app.plugins.AbsAudioPlayer @@ -18,7 +17,6 @@ import com.audiobookshelf.app.plugins.AbsFileSystem import com.getcapacitor.BridgeActivity import io.paperdb.Paper - class MainActivity : BridgeActivity() { private val tag = "MainActivity" @@ -87,6 +85,7 @@ class MainActivity : BridgeActivity() { override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) + Log.d(tag, "onPostCreate MainActivity") mConnection = object : ServiceConnection { override fun onServiceDisconnected(name: ComponentName) { @@ -97,7 +96,6 @@ class MainActivity : BridgeActivity() { override fun onServiceConnected(name: ComponentName, service: IBinder) { Log.d(tag, "Service Connected $name") - mBounded = true val mLocalBinder = service as PlayerNotificationService.LocalBinder foregroundService = mLocalBinder.getService() @@ -109,8 +107,10 @@ class MainActivity : BridgeActivity() { } } - val startIntent = Intent(this, PlayerNotificationService::class.java) - bindService(startIntent, mConnection as ServiceConnection, Context.BIND_AUTO_CREATE); + Intent(this, PlayerNotificationService::class.java).also { intent -> + Log.d(tag, "Binding PlayerNotificationService") + bindService(intent, mConnection, Context.BIND_AUTO_CREATE) + } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt b/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt index ab016e25..859001e7 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt @@ -30,28 +30,68 @@ data class LibraryItem( JsonSubTypes.Type(Book::class), JsonSubTypes.Type(Podcast::class) ) -open class MediaType {} +open class MediaType(var metadata:MediaTypeMetadata, var coverPath:String?) { + @JsonIgnore + open fun getAudioTracks():List { return mutableListOf() } + @JsonIgnore + open fun setAudioTracks(audioTracks:List) { } +} @JsonIgnoreProperties(ignoreUnknown = true) -data class Podcast( - var metadata:PodcastMetadata, - var coverPath:String?, +class Podcast( + metadata:PodcastMetadata, + coverPath:String?, var tags:MutableList, var episodes:MutableList, var autoDownloadEpisodes:Boolean -) : MediaType() +) : MediaType(metadata, coverPath) { + @JsonIgnore + override fun getAudioTracks():List { + var tracks = episodes.map { it.audioTrack } + return tracks.filterNotNull() + } + @JsonIgnore + override fun setAudioTracks(audioTracks:List) { + // Remove episodes no longer there in tracks + episodes = episodes.filter { ep -> + audioTracks.find { it.localFileId == ep.audioTrack?.localFileId } != null + } as MutableList + // Add new episodes + audioTracks.forEach { at -> + if (episodes.find{ it.audioTrack?.localFileId == at.localFileId } == null) { + var newEpisode = PodcastEpisode("local_" + at.localFileId,episodes.size + 1,null,null,at.title,null,null,null,at) + episodes.add(newEpisode) + } + } + } +} @JsonIgnoreProperties(ignoreUnknown = true) -data class Book( - var metadata:BookMetadata, - var coverPath:String?, +class Book( + metadata:BookMetadata, + coverPath:String?, var tags:List, var audioFiles:List, var chapters:List, var tracks:List?, var size:Long?, var duration:Double? -) : MediaType() +) : MediaType(metadata, coverPath) { + @JsonIgnore + override fun getAudioTracks():List { + return tracks ?: mutableListOf() + } + @JsonIgnore + override fun setAudioTracks(audioTracks:List) { + tracks = audioTracks + + var totalDuration = 0.0 + tracks?.forEach { + totalDuration += it.duration + } + duration = totalDuration + } +} // This auto-detects whether it is a Book or Podcast @JsonTypeInfo(use=JsonTypeInfo.Id.DEDUCTION) @@ -59,11 +99,11 @@ data class Book( JsonSubTypes.Type(BookMetadata::class), JsonSubTypes.Type(PodcastMetadata::class) ) -open class MediaTypeMetadata {} +open class MediaTypeMetadata(var title:String) {} @JsonIgnoreProperties(ignoreUnknown = true) -data class BookMetadata( - var title:String, +class BookMetadata( + title:String, var subtitle:String?, var authors:MutableList, var narrators:MutableList, @@ -81,15 +121,15 @@ data class BookMetadata( var authorNameLF:String?, var narratorName:String?, var seriesName:String? -) : MediaTypeMetadata() +) : MediaTypeMetadata(title) @JsonIgnoreProperties(ignoreUnknown = true) -data class PodcastMetadata( - var title:String, +class PodcastMetadata( + title:String, var author:String?, var feedUrl:String?, var genres:MutableList -) : MediaTypeMetadata() +) : MediaTypeMetadata(title) @JsonIgnoreProperties(ignoreUnknown = true) data class Author( @@ -107,7 +147,8 @@ data class PodcastEpisode( var title:String?, var subtitle:String?, var description:String?, - var audioFile:AudioFile + var audioFile:AudioFile?, + var audioTrack:AudioTrack? ) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt b/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt index 264aee1d..b6356d4a 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt @@ -14,11 +14,11 @@ class DbManager { Paper.book("device").write("data", deviceData) } - fun getLocalMediaItems():MutableList { - var localMediaItems:MutableList = mutableListOf() - Paper.book("localMediaItems").allKeys.forEach { - var localMediaItem:LocalMediaItem? = Paper.book("localMediaItems").read(it) - if (localMediaItem != null) { + fun getLocalLibraryItems():MutableList { + var localLibraryItems:MutableList = mutableListOf() + Paper.book("localLibraryItems").allKeys.forEach { + var localLibraryItem:LocalLibraryItem? = Paper.book("localLibraryItems").read(it) + if (localLibraryItem != null) { // TODO: Check to make sure all file paths exist // if (localMediaItem.coverContentUrl != null) { // var file = DocumentFile.fromSingleUri(ctx) @@ -29,31 +29,31 @@ class DbManager { // localMediaItems.add(localMediaItem) // } // } else { - localMediaItems.add(localMediaItem) + localLibraryItems.add(localLibraryItem) // } } } - return localMediaItems + return localLibraryItems } - fun getLocalMediaItemsInFolder(folderId:String):List { - var localMediaItems = getLocalMediaItems() - return localMediaItems.filter { + fun getLocalLibraryItemsInFolder(folderId:String):List { + var localLibraryItems = getLocalLibraryItems() + return localLibraryItems.filter { it.folderId == folderId } } - fun getLocalMediaItem(localMediaItemId:String):LocalMediaItem? { - return Paper.book("localMediaItems").read(localMediaItemId) + fun getLocalLibraryItem(localLibraryItemId:String):LocalLibraryItem? { + return Paper.book("localLibraryItems").read(localLibraryItemId) } - fun removeLocalMediaItem(localMediaItemId:String) { - Paper.book("localMediaItems").delete(localMediaItemId) + fun removeLocalLibraryItem(localLibraryItemId:String) { + Paper.book("localLibraryItems").delete(localLibraryItemId) } - fun saveLocalMediaItems(localMediaItems:List) { - localMediaItems.map { - Paper.book("localMediaItems").write(it.id, it) + fun saveLocalLibraryItems(localLibraryItems:List) { + localLibraryItems.map { + Paper.book("localLibraryItems").write(it.id, it) } } @@ -77,9 +77,9 @@ class DbManager { } fun removeLocalFolder(folderId:String) { - var localMediaItems = getLocalMediaItemsInFolder(folderId) - localMediaItems.forEach { - Paper.book("localMediaItems").delete(it.id) + var localLibraryItems = getLocalLibraryItemsInFolder(folderId) + localLibraryItems.forEach { + Paper.book("localLibraryItems").delete(it.id) } Paper.book("localFolders").delete(folderId) } diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt b/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt index d24d7ab3..a03d924c 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt @@ -22,14 +22,54 @@ data class DeviceData( @JsonIgnoreProperties(ignoreUnknown = true) data class LocalLibraryItem( var id:String, + var libraryItemId:String?, var folderId:String, var absolutePath:String, var isInvalid:Boolean, var mediaType:String, var media:MediaType, var localFiles:MutableList, + var coverContentUrl:String?, + var coverAbsolutePath:String?, var isLocal:Boolean -) +) { + @JsonIgnore + fun getDuration():Double { + var total = 0.0 + var audioTracks = media.getAudioTracks() + audioTracks.forEach{ total += it.duration } + return total + } + + @JsonIgnore + fun updateFromScan(audioTracks:List, _localFiles:MutableList) { + media.setAudioTracks(audioTracks) + localFiles = _localFiles + + if (coverContentUrl != null) { + if (localFiles.find { it.contentUrl == coverContentUrl } == null) { + // Cover was removed + coverContentUrl = null + coverAbsolutePath = null + media.coverPath = null + } + } + } + + @JsonIgnore + fun getPlaybackSession():PlaybackSession { + var sessionId = "play-${UUID.randomUUID()}" + + var mediaMetadata = media.metadata + var chapters = if (mediaType == "book") (media as Book).chapters else mutableListOf() + var authorName = "Unknown" + if (mediaType == "book") { + var bookMetadata = mediaMetadata as BookMetadata + authorName = bookMetadata?.authorName ?: "Unknown" + } + return PlaybackSession(sessionId,null,null,null, mediaType, mediaMetadata, chapters, mediaMetadata.title, authorName,null,getDuration(),PLAYMETHOD_LOCAL, media.getAudioTracks() as MutableList,0.0,null,this,null,null) + } +} @JsonIgnoreProperties(ignoreUnknown = true) data class LocalMediaItem( @@ -69,20 +109,6 @@ data class LocalMediaItem( } } - @JsonIgnore - fun getPlaybackSession():PlaybackSession { - var sessionId = "play-${UUID.randomUUID()}" - - var mediaMetadata = getMediaMetadata() - var chapters = getAudiobookChapters() - var authorName = "Unknown" - if (mediaType == "book") { - var bookMetadata = mediaMetadata as BookMetadata - authorName = bookMetadata?.authorName ?: "Unknown" - } - return PlaybackSession(sessionId,null,null,null, mediaType, mediaMetadata, chapters, name, authorName,null,getDuration(),PLAYMETHOD_LOCAL,audioTracks,0.0,null,this,null,null) - } - @JsonIgnore fun getAudiobookChapters():List { if (mediaType != "book" || audioTracks.isEmpty()) return mutableListOf() @@ -98,11 +124,11 @@ data class LocalMediaItem( var mediaMetadata = getMediaMetadata() if (mediaType == "book") { var chapters = getAudiobookChapters() - var book = Book(mediaMetadata as BookMetadata, coverContentUrl, mutableListOf(), mutableListOf(), chapters,audioTracks,getTotalSize(),getDuration()) - return LocalLibraryItem(id, folderId, absolutePath, false,mediaType, book, localFiles, true) + var book = Book(mediaMetadata as BookMetadata, coverAbsolutePath, mutableListOf(), mutableListOf(), chapters,audioTracks,getTotalSize(),getDuration()) + return LocalLibraryItem(id, null, folderId, absolutePath, false,mediaType, book, localFiles, coverContentUrl, coverAbsolutePath,true) } else { - var podcast = Podcast(mediaMetadata as PodcastMetadata, coverContentUrl, mutableListOf(), mutableListOf(), false) - return LocalLibraryItem(id, folderId, absolutePath, false, mediaType, podcast,localFiles,true) + var podcast = Podcast(mediaMetadata as PodcastMetadata, coverAbsolutePath, mutableListOf(), mutableListOf(), false) + return LocalLibraryItem(id, null, folderId, absolutePath, false, mediaType, podcast,localFiles,coverContentUrl, coverAbsolutePath, true) } } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/FolderScanResult.kt b/android/app/src/main/java/com/audiobookshelf/app/data/FolderScanResult.kt index 94f9e0a2..11449234 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/FolderScanResult.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/FolderScanResult.kt @@ -6,5 +6,5 @@ data class FolderScanResult( var itemsRemoved:Int, var itemsUpToDate:Int, val localFolder:LocalFolder, - val localMediaItems:List, + val localLibraryItems:List, ) diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/PlaybackSession.kt b/android/app/src/main/java/com/audiobookshelf/app/data/PlaybackSession.kt index 2dc02cdc..c3116867 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/PlaybackSession.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/PlaybackSession.kt @@ -32,7 +32,7 @@ class PlaybackSession( var audioTracks:MutableList, var currentTime:Double, var libraryItem:LibraryItem?, - var localMediaItem:LocalMediaItem?, + var localLibraryItem:LocalLibraryItem?, var serverUrl:String?, var token:String? ) { @@ -74,7 +74,7 @@ class PlaybackSession( @JsonIgnore fun getCoverUri(): Uri { - if (localMediaItem?.coverContentUrl != null) return Uri.parse(localMediaItem?.coverContentUrl) ?: Uri.parse("android.resource://com.audiobookshelf.app/" + R.drawable.icon) + if (localLibraryItem?.coverContentUrl != null) return Uri.parse(localLibraryItem?.coverContentUrl) ?: Uri.parse("android.resource://com.audiobookshelf.app/" + R.drawable.icon) if (coverPath == null) return Uri.parse("android.resource://com.audiobookshelf.app/" + R.drawable.icon) return Uri.parse("$serverUrl/api/items/$libraryItemId/cover?token=$token") diff --git a/android/app/src/main/java/com/audiobookshelf/app/device/FolderScanner.kt b/android/app/src/main/java/com/audiobookshelf/app/device/FolderScanner.kt index 187327ba..5579f3e4 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/device/FolderScanner.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/device/FolderScanner.kt @@ -15,6 +15,10 @@ import com.fasterxml.jackson.module.kotlin.readValue class FolderScanner(var ctx: Context) { private val tag = "FolderScanner" + private fun getLocalLibraryItemId(mediaItemId:String):String { + return "local_" + DeviceManager.getBase64Id(mediaItemId) + } + // TODO: CLEAN this monster! Divide into bite-size methods fun scanForMediaItems(localFolder:LocalFolder, forceAudioProbe:Boolean):FolderScanResult? { FFmpegKitConfig.enableLogCallback { log -> @@ -38,32 +42,32 @@ class FolderScanner(var ctx: Context) { // Search for files in media item folder var foldersFound = df.search(false, DocumentFileType.FOLDER) - // Match folders found with media items already saved in db - var existingMediaItems = DeviceManager.dbManager.getLocalMediaItemsInFolder(localFolder.id) + // Match folders found with local library items already saved in db + var existingLocalLibraryItems = DeviceManager.dbManager.getLocalLibraryItemsInFolder(localFolder.id) // Remove existing items no longer there - existingMediaItems = existingMediaItems.filter { lmi -> - var fileFound = foldersFound.find { f -> lmi.id == DeviceManager.getBase64Id(f.id) } + existingLocalLibraryItems = existingLocalLibraryItems.filter { lli -> + var fileFound = foldersFound.find { f -> lli.id == getLocalLibraryItemId(f.id) } if (fileFound == null) { - Log.d(tag, "Existing media item is no longer in file system ${lmi.name}") - DeviceManager.dbManager.removeLocalMediaItem(lmi.id) + Log.d(tag, "Existing local library item is no longer in file system ${lli.media.metadata.title}") + DeviceManager.dbManager.removeLocalLibraryItem(lli.id) mediaItemsRemoved++ } fileFound != null } - var mediaItems = mutableListOf() + var localLibraryItems = mutableListOf() - foldersFound.forEach { - Log.d(tag, "Iterating over Folder Found ${it.name} | ${it.getSimplePath(ctx)} | URI: ${it.uri}") + foldersFound.forEach { itemFolder -> + Log.d(tag, "Iterating over Folder Found ${itemFolder.name} | ${itemFolder.getSimplePath(ctx)} | URI: ${itemFolder.uri}") - var itemFolderName = it.name ?: "" - var itemId = "local_" + DeviceManager.getBase64Id(it.id) + var itemFolderName = itemFolder.name ?: "" + var itemId = getLocalLibraryItemId(itemFolder.id) - var existingMediaItem = existingMediaItems.find { emi -> emi.id == itemId } - var existingLocalFiles = existingMediaItem?.localFiles ?: mutableListOf() - var existingAudioTracks = existingMediaItem?.audioTracks ?: mutableListOf() - var isNewOrUpdated = existingMediaItem == null + var existingItem = existingLocalLibraryItems.find { emi -> emi.id == itemId } + var existingLocalFiles = existingItem?.localFiles ?: mutableListOf() + var existingAudioTracks = existingItem?.media?.getAudioTracks() ?: mutableListOf() + var isNewOrUpdated = existingItem == null var audioTracks = mutableListOf() var localFiles = mutableListOf() @@ -72,13 +76,14 @@ class FolderScanner(var ctx: Context) { var coverContentUrl:String? = null var coverAbsolutePath:String? = null - var filesInFolder = it.search(false, DocumentFileType.FILE, arrayOf("audio/*", "image/*")) + var filesInFolder = itemFolder.search(false, DocumentFileType.FILE, arrayOf("audio/*", "image/*")) + var existingLocalFilesRemoved = existingLocalFiles.filter { elf -> filesInFolder.find { fif -> DeviceManager.getBase64Id(fif.id) == elf.id } == null // File was not found in media item folder } if (existingLocalFilesRemoved.isNotEmpty()) { - Log.d(tag, "${existingLocalFilesRemoved.size} Local files were removed from local media item ${existingMediaItem?.name}") + Log.d(tag, "${existingLocalFilesRemoved.size} Local files were removed from local media item ${existingItem?.media?.metadata?.title}") isNewOrUpdated = true } @@ -147,9 +152,12 @@ class FolderScanner(var ctx: Context) { if (existingLocalFile == null) { isNewOrUpdated = true } - if (existingMediaItem != null && existingMediaItem.coverContentUrl == null) { + if (existingItem != null && existingItem.coverContentUrl == null) { // Existing media item did not have a cover - cover found on scan isNewOrUpdated = true + existingItem.coverAbsolutePath = localFile.absolutePath + existingItem.coverContentUrl = localFile.contentUrl + existingItem.media.coverPath = localFile.absolutePath } // First image file use as cover path @@ -160,30 +168,36 @@ class FolderScanner(var ctx: Context) { } } - if (existingMediaItem != null && audioTracks.isEmpty()) { - Log.d(tag, "Local media item ${existingMediaItem.name} no longer has audio tracks - removing item") - DeviceManager.dbManager.removeLocalMediaItem(existingMediaItem.id) + if (existingItem != null && audioTracks.isEmpty()) { + Log.d(tag, "Local library item ${existingItem.media.metadata.title} no longer has audio tracks - removing item") + DeviceManager.dbManager.removeLocalLibraryItem(existingItem.id) mediaItemsRemoved++ - } else if (existingMediaItem != null && !isNewOrUpdated) { - Log.d(tag, "Local media item ${existingMediaItem.name} has no updates") + } else if (existingItem != null && !isNewOrUpdated) { + Log.d(tag, "Local library item ${existingItem.media.metadata.title} has no updates") mediaItemsUpToDate++ - } else if (audioTracks.isNotEmpty()) { - if (existingMediaItem != null) mediaItemsUpdated++ - else mediaItemsAdded++ + } else if (existingItem != null) { + Log.d(tag, "Updating local library item ${existingItem.media.metadata.title}") + mediaItemsUpdated++ - Log.d(tag, "Found local media item named $itemFolderName with ${audioTracks.size} tracks and ${localFiles.size} local files") - var localMediaItem = LocalMediaItem(itemId, itemFolderName, localFolder.mediaType, localFolder.id, it.uri.toString(), it.getSimplePath(ctx), it.getAbsolutePath(ctx),audioTracks,localFiles,coverContentUrl,coverAbsolutePath) - mediaItems.add(localMediaItem) + existingItem.updateFromScan(audioTracks,localFiles) + localLibraryItems.add(existingItem) + } else if (audioTracks.isNotEmpty()) { + Log.d(tag, "Found local media item named $itemFolderName with ${audioTracks.size} tracks and ${localFiles.size} local files") + mediaItemsAdded++ + + var localMediaItem = LocalMediaItem(itemId, itemFolderName, localFolder.mediaType, localFolder.id, itemFolder.uri.toString(), itemFolder.getSimplePath(ctx), itemFolder.getAbsolutePath(ctx),audioTracks,localFiles,coverContentUrl,coverAbsolutePath) + var localLibraryItem = localMediaItem.getLocalLibraryItem() + localLibraryItems.add(localLibraryItem) } } Log.d(tag, "Folder $${localFolder.name} scan Results: $mediaItemsAdded Added | $mediaItemsUpdated Updated | $mediaItemsRemoved Removed | $mediaItemsUpToDate Up-to-date") - return if (mediaItems.isNotEmpty()) { - DeviceManager.dbManager.saveLocalMediaItems(mediaItems) + return if (localLibraryItems.isNotEmpty()) { + DeviceManager.dbManager.saveLocalLibraryItems(localLibraryItems) - var folderMediaItems = DeviceManager.dbManager.getLocalMediaItemsInFolder(localFolder.id) // Get all local media items - FolderScanResult(mediaItemsAdded, mediaItemsUpdated, mediaItemsRemoved, mediaItemsUpToDate, localFolder, folderMediaItems) + var folderLibraryItems = DeviceManager.dbManager.getLocalLibraryItemsInFolder(localFolder.id) // Get all local media items + FolderScanResult(mediaItemsAdded, mediaItemsUpdated, mediaItemsRemoved, mediaItemsUpToDate, localFolder, folderLibraryItems) } else { Log.d(tag, "No Media Items to save") FolderScanResult(mediaItemsAdded, mediaItemsUpdated, mediaItemsRemoved, mediaItemsUpToDate, localFolder, mutableListOf()) diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt index 643e19ba..6be2a841 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt @@ -133,8 +133,8 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - Log.d(tag, "onStartCommand $startId") isStarted = true + Log.d(tag, "onStartCommand $startId") return START_STICKY } diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt index 639bfe98..d79daaba 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt @@ -1,8 +1,10 @@ package com.audiobookshelf.app.plugins +import android.content.Intent import android.os.Handler import android.os.Looper import android.util.Log +import androidx.core.content.ContextCompat import com.audiobookshelf.app.MainActivity import com.audiobookshelf.app.data.PlaybackSession import com.audiobookshelf.app.device.DeviceManager @@ -75,11 +77,19 @@ class AbsAudioPlayer : Plugin() { @PluginMethod fun prepareLibraryItem(call: PluginCall) { + // Need to make sure the player service has been started + if (!PlayerNotificationService.isStarted) { + Log.w(tag, "prepareLibraryItem: PlayerService not started - Starting foreground service --") + Intent(mainActivity, PlayerNotificationService::class.java).also { intent -> + ContextCompat.startForegroundService(mainActivity, intent) + } + } + var libraryItemId = call.getString("libraryItemId", "").toString() var playWhenReady = call.getBoolean("playWhenReady") == true if (libraryItemId.startsWith("local")) { // Play local media item - DeviceManager.dbManager.getLocalMediaItem(libraryItemId)?.let { + DeviceManager.dbManager.getLocalLibraryItem(libraryItemId)?.let { Handler(Looper.getMainLooper()).post() { Log.d(tag, "Preparing Local Media item ${jacksonObjectMapper().writeValueAsString(it)}") var playbackSession = it.getPlaybackSession() diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt index b41638e2..afa75558 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt @@ -48,23 +48,22 @@ class AbsDatabase : Plugin() { } @PluginMethod - fun getLocalMediaItemsInFolder(call:PluginCall) { - var folderId = call.getString("folderId", "").toString() + fun getLocalLibraryItem(call:PluginCall) { + var id = call.getString("id", "").toString() GlobalScope.launch(Dispatchers.IO) { - var localMediaItems = DeviceManager.dbManager.getLocalMediaItemsInFolder(folderId) - var mediaItemsArray = jacksonObjectMapper().writeValueAsString(localMediaItems) - var jsobj = JSObject() - jsobj.put("localMediaItems", mediaItemsArray) - call.resolve(jsobj) + var localLibraryItem = DeviceManager.dbManager.getLocalLibraryItem(id) + if (localLibraryItem == null) { + call.resolve() + } else { + call.resolve(JSObject(jacksonObjectMapper().writeValueAsString(localLibraryItem))) + } } } @PluginMethod fun getLocalLibraryItems(call:PluginCall) { GlobalScope.launch(Dispatchers.IO) { - var localLibraryItems = DeviceManager.dbManager.getLocalMediaItems().map { - it.getLocalLibraryItem() - } + var localLibraryItems = DeviceManager.dbManager.getLocalLibraryItems() var jsobj = JSObject() jsobj.put("localLibraryItems", jacksonObjectMapper().writeValueAsString(localLibraryItems)) call.resolve(jsobj) @@ -72,16 +71,14 @@ class AbsDatabase : Plugin() { } @PluginMethod - fun getLocalLibraryItem(call:PluginCall) { - var id = call.getString("id", "").toString() + fun getLocalLibraryItemsInFolder(call:PluginCall) { + var folderId = call.getString("folderId", "").toString() GlobalScope.launch(Dispatchers.IO) { - var mediaItem = DeviceManager.dbManager.getLocalMediaItem(id) - var localLibraryItem = mediaItem?.getLocalLibraryItem() - if (localLibraryItem == null) { - call.resolve() - } else { - call.resolve(JSObject(jacksonObjectMapper().writeValueAsString(localLibraryItem))) - } + var localMediaItems = DeviceManager.dbManager.getLocalLibraryItemsInFolder(folderId) + var mediaItemsArray = jacksonObjectMapper().writeValueAsString(localMediaItems) + var jsobj = JSObject() + jsobj.put("localLibraryItems", mediaItemsArray) + call.resolve(jsobj) } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDownloader.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDownloader.kt index 38e322ef..8d45f57e 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDownloader.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDownloader.kt @@ -118,11 +118,11 @@ class AbsDownloader : Plugin() { fun getAbMetadataText(libraryItem:LibraryItem):String { var bookMedia = libraryItem.media as com.audiobookshelf.app.data.Book var fileString = ";ABMETADATA1\n" - fileString += "#libraryItemId=${libraryItem.id}\n" - fileString += "title=${bookMedia.metadata.title}\n" - fileString += "author=${bookMedia.metadata.authorName}\n" - fileString += "narrator=${bookMedia.metadata.narratorName}\n" - fileString += "series=${bookMedia.metadata.seriesName}\n" +// fileString += "#libraryItemId=${libraryItem.id}\n" +// fileString += "title=${bookMedia.metadata.title}\n" +// fileString += "author=${bookMedia.metadata.authorName}\n" +// fileString += "narrator=${bookMedia.metadata.narratorName}\n" +// fileString += "series=${bookMedia.metadata.seriesName}\n" return fileString } diff --git a/components/app/AudioPlayer.vue b/components/app/AudioPlayer.vue index 07cc66bb..896031d9 100644 --- a/components/app/AudioPlayer.vue +++ b/components/app/AudioPlayer.vue @@ -1,5 +1,5 @@