Add:Android auto show currently reading

This commit is contained in:
advplyr
2021-12-11 19:49:22 -06:00
parent 6faa9b6324
commit a295889a52
4 changed files with 127 additions and 58 deletions
@@ -84,6 +84,7 @@ class Audiobook {
putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getCover().toString()) putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getCover().toString())
putString(MediaMetadataCompat.METADATA_KEY_ART_URI, getCover().toString()) putString(MediaMetadataCompat.METADATA_KEY_ART_URI, getCover().toString())
putString(MediaMetadataCompat.METADATA_KEY_AUTHOR, book.authorFL) putString(MediaMetadataCompat.METADATA_KEY_AUTHOR, book.authorFL)
// val extras = Bundle() // val extras = Bundle()
// if (isDownloaded) { // if (isDownloaded) {
// extras.putLong( // extras.putLong(
@@ -10,6 +10,7 @@ import com.getcapacitor.JSArray
import com.getcapacitor.JSObject import com.getcapacitor.JSObject
import com.jeep.plugin.capacitor.capacitordatastoragesqlite.CapacitorDataStorageSqlite import com.jeep.plugin.capacitor.capacitordatastoragesqlite.CapacitorDataStorageSqlite
import okhttp3.* import okhttp3.*
import org.json.JSONArray
import java.io.IOException import java.io.IOException
class AudiobookManager { class AudiobookManager {
@@ -29,6 +30,7 @@ class AudiobookManager {
lateinit var localMediaManager:LocalMediaManager lateinit var localMediaManager:LocalMediaManager
var audiobooks:MutableList<Audiobook> = mutableListOf() var audiobooks:MutableList<Audiobook> = mutableListOf()
var audiobooksInProgress:MutableList<Audiobook> = mutableListOf()
constructor(_ctx:Context, _client:OkHttpClient) { constructor(_ctx:Context, _client:OkHttpClient) {
ctx = _ctx ctx = _ctx
@@ -45,19 +47,9 @@ class AudiobookManager {
Log.d(tag, "SHARED PREF TOKEN $token") Log.d(tag, "SHARED PREF TOKEN $token")
} }
fun loadAudiobooks(cb: (() -> Unit)) { fun loadCategories(cb: (() -> Unit)) {
Log.d(tag, "LOAD AUDIBOOOSK $serverUrl | $token") Log.d(tag, "LOAD Categories $serverUrl | $token")
if (serverUrl == "" || token == "") { var url = "$serverUrl/api/libraries/main/categories"
Log.d(tag, "No Server or Token set")
cb()
return
} else if (!serverUrl.startsWith("http")) {
Log.e(tag, "Invalid server url $serverUrl")
cb()
return
}
var url = "$serverUrl/api/libraries/main/books/all"
val request = Request.Builder() val request = Request.Builder()
.url(url).addHeader("Authorization", "Bearer $token") .url(url).addHeader("Authorization", "Bearer $token")
.build() .build()
@@ -74,37 +66,108 @@ class AudiobookManager {
if (!response.isSuccessful) throw IOException("Unexpected code $response") if (!response.isSuccessful) throw IOException("Unexpected code $response")
var bodyString = response.body!!.string() var bodyString = response.body!!.string()
var resJson = JSObject(bodyString) var results = JSONArray(bodyString)
var results = resJson.getJSONArray("results") // var results = resJson.getJSONArray("results")
var totalBooks = results.length() - 1 var totalShelves = results.length() - 1
for (i in 0..totalBooks) { Log.d(tag, "Got categories $totalShelves")
var abobj = results.get(i) for (i in 0..totalShelves) {
var jsobj = JSObject(abobj.toString()) var shelfobj = results.get(i)
var jsobj = JSObject(shelfobj.toString())
jsobj.put("isDownloaded", false) var shelfId = jsobj.getString("id", "")
var audiobook = Audiobook(jsobj, serverUrl, token) Log.d(tag, "Category shelf id $shelfId")
if (shelfId == "continue-reading") {
if (audiobook.isMissing || audiobook.isInvalid) { var entities = jsobj.getJSONArray("entities")
Log.d(tag, "Audiobook ${audiobook.book.title} is missing or invalid") var totalEntities = entities.length() - 1
} else if (audiobook.numTracks <= 0) { Log.d(tag, "Shelf total entities $totalEntities")
Log.d(tag, "Audiobook ${audiobook.book.title} has audio tracks") for (y in 0..totalEntities) {
} else { var abobj = entities.get(y)
var audiobookExists = audiobooks.find { it.id == audiobook.id } Log.d(tag, "Shelf category ab id $y = ${abobj.toString()}")
if (audiobookExists == null) { var abjsobj = JSObject(abobj.toString())
audiobooks.add(audiobook) abjsobj.put("isDownloaded", false)
} else { var audiobook = Audiobook(abjsobj, serverUrl, token)
Log.d(tag, "Audiobook already there from downloaded") if (audiobook.isMissing || audiobook.isInvalid || audiobook.numTracks <= 0) {
Log.d(tag, "Not an audiobook or invalid/missing")
} else {
var audiobookExists = audiobooksInProgress.find { it.id == audiobook.id }
if (audiobookExists == null) {
audiobooksInProgress.add(audiobook)
}
}
} }
} }
} }
Log.d(tag, "${audiobooks.size} Audiobooks Loaded") Log.d(tag, "${audiobooksInProgress.size} Audiobooks In Progress Loaded")
cb() cb()
} }
} }
}) })
} }
fun loadAudiobooks(cb: (() -> Unit)) {
Log.d(tag, "LOAD AUDIBOOOSK $serverUrl | $token")
if (serverUrl == "" || token == "") {
Log.d(tag, "No Server or Token set")
cb()
return
} else if (!serverUrl.startsWith("http")) {
Log.e(tag, "Invalid server url $serverUrl")
cb()
return
}
// First load currently reading
loadCategories() {
// Then load all
var url = "$serverUrl/api/libraries/main/books/all"
val request = Request.Builder()
.url(url).addHeader("Authorization", "Bearer $token")
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.d(tag, "FAILURE TO CONNECT")
e.printStackTrace()
cb()
}
override fun onResponse(call: Call, response: Response) {
response.use {
if (!response.isSuccessful) throw IOException("Unexpected code $response")
var bodyString = response.body!!.string()
var resJson = JSObject(bodyString)
var results = resJson.getJSONArray("results")
var totalBooks = results.length() - 1
for (i in 0..totalBooks) {
var abobj = results.get(i)
var jsobj = JSObject(abobj.toString())
jsobj.put("isDownloaded", false)
var audiobook = Audiobook(jsobj, serverUrl, token)
if (audiobook.isMissing || audiobook.isInvalid) {
Log.d(tag, "Audiobook ${audiobook.book.title} is missing or invalid")
} else if (audiobook.numTracks <= 0) {
Log.d(tag, "Audiobook ${audiobook.book.title} has audio tracks")
} else {
var audiobookExists = audiobooks.find { it.id == audiobook.id }
if (audiobookExists == null) {
audiobooks.add(audiobook)
} else {
Log.d(tag, "Audiobook already there from downloaded")
}
}
}
Log.d(tag, "${audiobooks.size} Audiobooks Loaded")
cb()
}
}
})
}
}
fun load() { fun load() {
isLoading = true isLoading = true
hasLoaded = true hasLoaded = true
@@ -10,6 +10,7 @@ import androidx.annotation.AnyRes
class BrowseTree( class BrowseTree(
val context: Context, val context: Context,
val audiobooksInProgress: List<Audiobook>,
val audiobooks: List<Audiobook>, val audiobooks: List<Audiobook>,
val localAudio: List<LocalMediaManager.LocalAudio>, val localAudio: List<LocalMediaManager.LocalAudio>,
val recentMediaId: String? = null val recentMediaId: String? = null
@@ -33,6 +34,13 @@ class BrowseTree(
init { init {
val rootList = mediaIdToChildren[AUTO_BROWSE_ROOT] ?: mutableListOf() val rootList = mediaIdToChildren[AUTO_BROWSE_ROOT] ?: mutableListOf()
val continueReadingMetadata = MediaMetadataCompat.Builder().apply {
putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, CONTINUE_ROOT)
putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Reading")
putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToDrawable(context, R.drawable.exo_icon_localaudio).toString())
}.build()
val allMetadata = MediaMetadataCompat.Builder().apply { val allMetadata = MediaMetadataCompat.Builder().apply {
putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, ALL_ROOT) putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, ALL_ROOT)
putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Audiobooks") putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Audiobooks")
@@ -42,6 +50,7 @@ class BrowseTree(
putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, resource) putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, resource)
}.build() }.build()
val downloadsMetadata = MediaMetadataCompat.Builder().apply { val downloadsMetadata = MediaMetadataCompat.Builder().apply {
putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, DOWNLOADS_ROOT) putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, DOWNLOADS_ROOT)
putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Downloads") putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Downloads")
@@ -54,11 +63,20 @@ class BrowseTree(
putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToDrawable(context, R.drawable.exo_icon_localaudio).toString()) putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToDrawable(context, R.drawable.exo_icon_localaudio).toString())
}.build() }.build()
if (audiobooksInProgress.isNotEmpty()) {
rootList += continueReadingMetadata
}
rootList += allMetadata rootList += allMetadata
rootList += downloadsMetadata rootList += downloadsMetadata
rootList += localsMetadata rootList += localsMetadata
mediaIdToChildren[AUTO_BROWSE_ROOT] = rootList mediaIdToChildren[AUTO_BROWSE_ROOT] = rootList
audiobooksInProgress.forEach { audiobook ->
val children = mediaIdToChildren[CONTINUE_ROOT] ?: mutableListOf()
children += audiobook.toMediaMetadata()
mediaIdToChildren[CONTINUE_ROOT] = children
}
audiobooks.forEach { audiobook -> audiobooks.forEach { audiobook ->
if (audiobook.isDownloaded) { if (audiobook.isDownloaded) {
val downloadsChildren = mediaIdToChildren[DOWNLOADS_ROOT] ?: mutableListOf() val downloadsChildren = mediaIdToChildren[DOWNLOADS_ROOT] ?: mutableListOf()
@@ -83,5 +101,6 @@ class BrowseTree(
const val AUTO_BROWSE_ROOT = "/" const val AUTO_BROWSE_ROOT = "/"
const val ALL_ROOT = "__ALL__" const val ALL_ROOT = "__ALL__"
const val CONTINUE_ROOT = "__CONTINUE__"
const val DOWNLOADS_ROOT = "__DOWNLOADS__" const val DOWNLOADS_ROOT = "__DOWNLOADS__"
const val LOCAL_ROOT = "__LOCAL__" const val LOCAL_ROOT = "__LOCAL__"
@@ -31,6 +31,7 @@ import com.bumptech.glide.request.RequestOptions
import com.getcapacitor.JSObject import com.getcapacitor.JSObject
import com.getcapacitor.PluginCall import com.getcapacitor.PluginCall
import com.google.android.exoplayer2.* import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.MediaMetadata
import com.google.android.exoplayer2.audio.AudioAttributes import com.google.android.exoplayer2.audio.AudioAttributes
import com.google.android.exoplayer2.ext.cast.CastPlayer import com.google.android.exoplayer2.ext.cast.CastPlayer
import com.google.android.exoplayer2.ext.cast.SessionAvailabilityListener import com.google.android.exoplayer2.ext.cast.SessionAvailabilityListener
@@ -42,10 +43,10 @@ import com.google.android.exoplayer2.source.hls.HlsMediaSource
import com.google.android.exoplayer2.ui.PlayerNotificationManager import com.google.android.exoplayer2.ui.PlayerNotificationManager
import com.google.android.exoplayer2.upstream.* import com.google.android.exoplayer2.upstream.*
import com.google.android.exoplayer2.util.MimeTypes import com.google.android.exoplayer2.util.MimeTypes
import com.google.android.gms.cast.*
import com.google.android.gms.cast.Cast.MessageReceivedCallback import com.google.android.gms.cast.Cast.MessageReceivedCallback
import com.google.android.gms.cast.CastDevice
import com.google.android.gms.cast.CastMediaControlIntent
import com.google.android.gms.cast.framework.* import com.google.android.gms.cast.framework.*
import com.google.android.gms.cast.framework.media.MediaQueue
import kotlinx.coroutines.* import kotlinx.coroutines.*
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.json.JSONObject import org.json.JSONObject
@@ -69,7 +70,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
fun onMetadata(metadata: JSObject) fun onMetadata(metadata: JSObject)
fun onPrepare(audiobookId: String, playWhenReady: Boolean) fun onPrepare(audiobookId: String, playWhenReady: Boolean)
fun onSleepTimerEnded(currentPosition: Long) fun onSleepTimerEnded(currentPosition: Long)
fun onSleepTimerSet(sleepTimerEndTime:Long) fun onSleepTimerSet(sleepTimerEndTime: Long)
} }
private val tag = "PlayerService" private val tag = "PlayerService"
@@ -303,7 +304,6 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
} }
Log.d(tag, "Media Session Set") Log.d(tag, "Media Session Set")
val mediaController = MediaControllerCompat(ctx, mediaSession.sessionToken) val mediaController = MediaControllerCompat(ctx, mediaSession.sessionToken)
@@ -916,10 +916,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
MediaConstants.BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED, true) MediaConstants.BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED, true)
extras.putInt( extras.putInt(
MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE, MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE,
MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM) MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM)
extras.putInt( extras.putInt(
MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE, MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE,
MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM) MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM)
BrowserRoot(AUTO_MEDIA_ROOT, extras) BrowserRoot(AUTO_MEDIA_ROOT, extras)
} }
@@ -937,7 +937,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
audiobookManager.isLoading = false audiobookManager.isLoading = false
Log.d(tag, "LOADED AUDIOBOOKS") Log.d(tag, "LOADED AUDIOBOOKS")
browseTree = BrowseTree(this, audiobookManager.audiobooks, audiobookManager.localMediaManager.localAudioFiles, null) browseTree = BrowseTree(this, audiobookManager.audiobooksInProgress, audiobookManager.audiobooks, audiobookManager.localMediaManager.localAudioFiles, null)
val children = browseTree[parentMediaId]?.map { item -> val children = browseTree[parentMediaId]?.map { item ->
MediaBrowserCompat.MediaItem(item.description, flag) MediaBrowserCompat.MediaItem(item.description, flag)
} }
@@ -990,7 +990,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
audiobookManager.isLoading = false audiobookManager.isLoading = false
Log.d(tag, "LOADED AUDIOBOOKS") Log.d(tag, "LOADED AUDIOBOOKS")
browseTree = BrowseTree(this, audiobookManager.audiobooks, audiobookManager.localMediaManager.localAudioFiles, null) browseTree = BrowseTree(this, audiobookManager.audiobooksInProgress, audiobookManager.audiobooks, audiobookManager.localMediaManager.localAudioFiles, null)
val children = browseTree[ALL_ROOT]?.map { item -> val children = browseTree[ALL_ROOT]?.map { item ->
MediaBrowserCompat.MediaItem(item.description, MediaBrowserCompat.MediaItem.FLAG_PLAYABLE) MediaBrowserCompat.MediaItem(item.description, MediaBrowserCompat.MediaItem.FLAG_PLAYABLE)
} }
@@ -1149,7 +1149,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
if (sleepTimerRunning || sleepTimerFinishedAt > 0L) checkShouldExtendSleepTimer() if (sleepTimerRunning || sleepTimerFinishedAt > 0L) checkShouldExtendSleepTimer()
} }
fun increaseSleepTime(time:Long) { fun increaseSleepTime(time: Long) {
Log.d(tag, "Increase Sleep time $time") Log.d(tag, "Increase Sleep time $time")
if (!sleepTimerRunning) return if (!sleepTimerRunning) return
var newSleepEndTime = sleepTimerEndTime + time var newSleepEndTime = sleepTimerEndTime + time
@@ -1162,7 +1162,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
listener?.onSleepTimerSet(sleepTimerEndTime) listener?.onSleepTimerSet(sleepTimerEndTime)
} }
fun decreaseSleepTime(time:Long) { fun decreaseSleepTime(time: Long) {
Log.d(tag, "Decrease Sleep time $time") Log.d(tag, "Decrease Sleep time $time")
if (!sleepTimerRunning) return if (!sleepTimerRunning) return
var newSleepEndTime = sleepTimerEndTime - time var newSleepEndTime = sleepTimerEndTime - time
@@ -1488,20 +1488,6 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
setSessionAvailabilityListener(CastSessionAvailabilityListener()) setSessionAvailabilityListener(CastSessionAvailabilityListener())
addListener(getPlayerListener()) addListener(getPlayerListener())
} }
currentPlayer = castPlayer as CastPlayer
if (currentAudiobookStreamData != null) {
var mimeType = MimeTypes.AUDIO_AAC
val mediaItem: MediaItem = MediaItem.Builder()
.setUri(currentAudiobookStreamData!!.contentUri)
.setMediaId(currentAudiobookStreamData!!.id).setMimeType(mimeType)
// .setTag(metadata)
.build()
castPlayer?.setMediaItem(mediaItem, currentAudiobookStreamData!!.startTime)
}
Log.d(tag, "CAST Cast Player Applied") Log.d(tag, "CAST Cast Player Applied")
} catch (e: Exception) { } catch (e: Exception) {
// We wouldn't normally catch the generic `Exception` however // We wouldn't normally catch the generic `Exception` however