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 7a290211..f6e8800a 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 @@ -28,7 +28,8 @@ open class MediaType(var metadata:MediaTypeMetadata, var coverPath:String?) { open fun removeAudioTrack(localFileId:String) { } @JsonIgnore open fun getLocalCopy():MediaType { return MediaType(MediaTypeMetadata("", false),null) } - + @JsonIgnore + open fun checkHasTracks():Boolean { return false } } @JsonIgnoreProperties(ignoreUnknown = true) @@ -96,6 +97,11 @@ class Podcast( return Podcast(metadata as PodcastMetadata,coverPath,tags, mutableListOf(),autoDownloadEpisodes, 0) } + @JsonIgnore + override fun checkHasTracks():Boolean { + return (episodes?.size ?: numEpisodes ?: 0) > 0 + } + @JsonIgnore fun addEpisode(audioTrack:AudioTrack, episode:PodcastEpisode):PodcastEpisode { val localEpisodeId = "local_ep_" + episode.id @@ -185,6 +191,11 @@ class Book( override fun getLocalCopy(): Book { return Book(metadata as BookMetadata,coverPath,tags, mutableListOf(),chapters,mutableListOf(), ebookFile, null,null, 0) } + + @JsonIgnore + override fun checkHasTracks():Boolean { + return (tracks?.size ?: numTracks ?: 0) > 0 + } } // This auto-detects whether it is a BookMetadata or PodcastMetadata @@ -375,8 +386,9 @@ data class Library( @JsonIgnoreProperties(ignoreUnknown = true) data class LibraryStats( var totalItems: Int, - var totalAuthors: Int, - var numAudioTracks: Int + var totalSize: Long, + var totalDuration: Double, + var numAudioFiles: Int ) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/LibraryItem.kt b/android/app/src/main/java/com/audiobookshelf/app/data/LibraryItem.kt index 965ca35d..7b2dcf70 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/LibraryItem.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/LibraryItem.kt @@ -58,11 +58,7 @@ class LibraryItem( @JsonIgnore fun checkHasTracks():Boolean { - return if (mediaType == "podcast") { - ((media as Podcast).numEpisodes ?: 0) > 0 - } else { - ((media as Book).numTracks ?: 0) > 0 - } + return media.checkHasTracks() } @get:JsonIgnore diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/LibrarySeriesItem.kt b/android/app/src/main/java/com/audiobookshelf/app/data/LibrarySeriesItem.kt index 921a909a..47ff50c2 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/LibrarySeriesItem.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/LibrarySeriesItem.kt @@ -25,7 +25,7 @@ class LibrarySeriesItem( val audiobookCount: Int get() { if (books == null) return 0 - val booksWithAudio = books?.filter { b -> (b.media as Book).numTracks != 0 } + val booksWithAudio = books?.filter { b -> b.media.checkHasTracks() } return booksWithAudio?.size ?: 0 } diff --git a/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt b/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt index 2adcc7c6..be91e516 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt @@ -182,7 +182,10 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { libraryPersonalizationsDone-- } } + while (libraryPersonalizationsDone > 0) { } + + Log.d(tag, "Finished loading all library personalization data") allLibraryPersonalizationsDone = true cb() } @@ -239,8 +242,12 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { cachedLibraryRecentShelves[libraryId]!!.add(shelf) } + val podcastLibraryItemIds = mutableListOf() (shelf as LibraryShelfEpisodeEntity).entities?.forEach { libraryItem -> - loadPodcastItem(libraryItem.libraryId, libraryItem.id) {} + if (!podcastLibraryItemIds.contains(libraryItem.id)) { + podcastLibraryItemIds.add(libraryItem.id) + loadPodcastItem(libraryItem.libraryId, libraryItem.id) {} + } } } } else if (shelf.type == "podcast") { @@ -596,13 +603,13 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { cachedLibraryPodcasts[libraryId] = mutableMapOf() } if (cachedLibraryPodcasts[libraryId]!!.containsKey(libraryItemId)) { - Log.d(tag, "Podcast found from cache | Library $libraryItemId ") + Log.d(tag, "loadPodcastItem: Podcast found from cache | Library $libraryItemId ") cb(cachedLibraryPodcasts[libraryId]?.get(libraryItemId)) } else { - Log.d(tag, "loadPodcastItem: $libraryItemId") + Log.d(tag, "loadPodcastItem: Calling getLibraryItem $libraryItemId") apiHandler.getLibraryItem(libraryItemId) { libraryItem -> if (libraryItem !== null) { - Log.d(tag, "loadPodcastItem: Got library item $libraryItem") + Log.d(tag, "loadPodcastItem: Got library item ${libraryItem.id} ${libraryItem.media.metadata.title}") val podcast = libraryItem.media as Podcast podcast.episodes?.forEach { podcastEpisode -> podcastEpisodeLibraryItemMap[podcastEpisode.id] = LibraryItemWithEpisode(libraryItem, podcastEpisode) @@ -682,21 +689,14 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { } /** - * Loads libraries for selected server. - * After loading libraries fetches stats for each library. + * Loads libraries for selected server with stats */ private fun loadLibraries(cb: (List) -> Unit) { if (serverLibraries.isNotEmpty()) { cb(serverLibraries) } else { apiHandler.getLibraries { loadedLibraries -> - serverLibraries = loadedLibraries.map { library -> - apiHandler.getLibraryStats(library.id) { libraryStats -> - Log.d(tag, "Library stats for library ${library.id} | $libraryStats") - library.stats = libraryStats - } - library - } + serverLibraries = loadedLibraries cb(serverLibraries) } } @@ -875,8 +875,9 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { // Books if (searchResult.book !== null && searchResult.book!!.isNotEmpty()) { Log.d(tag, "searchLocalCache: found ${searchResult.book!!.size} books") - val children = searchResult.book!!.map { bookResult -> + val children = searchResult.book!!.filter { it.libraryItem.checkHasTracks() }.map { bookResult -> val libraryItem = bookResult.libraryItem + if (serverLibraryItems.find { li -> li.id == libraryItem.id } == null) { serverLibraryItems.add(libraryItem) } diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/BrowseTree.kt b/android/app/src/main/java/com/audiobookshelf/app/player/BrowseTree.kt index 126ed588..8dd5cd19 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/BrowseTree.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/BrowseTree.kt @@ -54,7 +54,7 @@ class BrowseTree( libraries.forEach { library -> // Skip libraries without audio content - if (library.stats?.numAudioTracks == 0) return@forEach + if (library.stats?.numAudioFiles == 0) return@forEach Log.d("BrowseTree", "Library $library | ${library.icon}") // Generate library list items for Libraries menu val libraryMediaMetadata = library.getMediaMetadata(context) 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 7781dfc2..9bc1340c 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 @@ -1224,7 +1224,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { return } Log.d(tag, "Mediaparts: ${mediaIdParts.size} | $mediaIdParts") - if(mediaIdParts.size == 3) { + if (mediaIdParts.size == 3) { mediaManager.getLibraryRecentShelfs(mediaIdParts[2]) { availableShelfs -> Log.d(tag, "Found ${availableShelfs.size} shelfs") val children : MutableList = mutableListOf() @@ -1302,7 +1302,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_PLAYABLE) } result.sendResult(children as MutableList?) - }else if (shelf.type == "episode") { + } else if (shelf.type == "episode") { val episodesWithRecentEpisode = (shelf as LibraryShelfEpisodeEntity).entities?.filter { libraryItem -> libraryItem.recentEpisode !== null } val children = episodesWithRecentEpisode?.map { libraryItem -> val podcast = libraryItem.media as Podcast @@ -1319,7 +1319,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_PLAYABLE) } result.sendResult(children as MutableList?) - }else if (shelf.type == "podcast") { + } else if (shelf.type == "podcast") { val children = (shelf as LibraryShelfPodcastEntity).entities?.map { libraryItem -> val mediaDescription = libraryItem.getMediaDescription(null, ctx) MediaBrowserCompat.MediaItem( @@ -1328,22 +1328,19 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { ) } result.sendResult(children as MutableList?) - } - else if (shelf.type == "series") { + } else if (shelf.type == "series") { val children = (shelf as LibraryShelfSeriesEntity).entities?.map { librarySeriesItem -> val description = librarySeriesItem.getMediaDescription(null, ctx) MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE) } result.sendResult(children as MutableList?) - } - else if (shelf.type == "authors") { + } else if (shelf.type == "authors") { val children = (shelf as LibraryShelfAuthorEntity).entities?.map { authorItem -> val description = authorItem.getMediaDescription(null, ctx) MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE) } result.sendResult(children as MutableList?) - } - else { + } else { result.sendResult(mutableListOf()) } @@ -1396,7 +1393,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { result.sendResult(children as MutableList?) } } - }else if (mediaIdParts[3] == "SERIES_LIST") { + } else if (mediaIdParts[3] == "SERIES_LIST") { Log.d(tag, "Loading series from library ${mediaIdParts[2]}") mediaManager.loadLibrarySeriesWithAudio(mediaIdParts[2]) { seriesItems -> Log.d(tag, "Received ${seriesItems.size} series") @@ -1563,7 +1560,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { } result.sendResult(children as MutableList?) } - }else { + } else { result.sendResult(null) } } else { @@ -1586,7 +1583,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { mediaManager.serverLibraries.forEach { serverLibrary -> runBlocking { // Skip searching library if it doesn't have any audio files - if (serverLibrary.stats?.numAudioTracks == 0) return@runBlocking + if (serverLibrary.stats?.numAudioFiles == 0) return@runBlocking val searchResult = mediaManager.doSearch(serverLibrary.id, query) for (resultData in searchResult.entries.iterator()) { when (resultData.key) { diff --git a/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt b/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt index 63ad5b3c..dfd97064 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt @@ -155,7 +155,7 @@ class ApiHandler(var ctx:Context) { fun getLibraries(cb: (List) -> Unit) { val mapper = jacksonMapper - getRequest("/api/libraries", null,null) { + getRequest("/api/libraries?include=stats", null,null) { val libraries = mutableListOf() var array = JSONArray() @@ -172,18 +172,6 @@ class ApiHandler(var ctx:Context) { } } - fun getLibraryStats(libraryItemId:String, cb: (LibraryStats?) -> Unit) { - getRequest("/api/libraries/$libraryItemId/stats", null, null) { - if (it.has("error")) { - Log.e(tag, it.getString("error") ?: "getLibraryStats Failed") - cb(null) - } else { - val libraryStats = jacksonMapper.readValue(it.toString()) - cb(libraryStats) - } - } - } - fun getLibraryPersonalized(libraryItemId:String, cb: (List?) -> Unit) { getRequest("/api/libraries/$libraryItemId/personalized", null, null) { if (it.has("error")) {