mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2026-08-07 04:18:48 +02:00
Android playback session for local media items
This commit is contained in:
@@ -85,11 +85,13 @@ class MyNativeAudio : Plugin() {
|
||||
fun playLocalLibraryItem(call:PluginCall) {
|
||||
var localMediaItemId = call.getString("localMediaItemId", "").toString()
|
||||
var playWhenReady = call.getBoolean("playWhenReady") == true
|
||||
Log.d(tag, "playLocalLibraryItem $playWhenReady")
|
||||
|
||||
DeviceManager.dbManager.loadLocalMediaItem(localMediaItemId)?.let {
|
||||
Handler(Looper.getMainLooper()).post() {
|
||||
Log.d(tag, "Preparing Local Media item ${jacksonObjectMapper().writeValueAsString(it)}")
|
||||
playerNotificationService.playLocalMediaItem(it, playWhenReady)
|
||||
var playbackSession = it.getPlaybackSession()
|
||||
playerNotificationService.preparePlayer(playbackSession, playWhenReady)
|
||||
}
|
||||
return call.resolve(JSObject())
|
||||
}
|
||||
|
||||
@@ -603,7 +603,6 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||
if (currentPlayer.playbackState == Player.STATE_READY) {
|
||||
Log.d(tag, "STATE_READY : " + mPlayer.duration.toString())
|
||||
|
||||
// currentAudiobookStreamData!!.hasPlayerLoaded = true
|
||||
if (lastPauseTime == 0L) {
|
||||
sendClientMetadata("ready_no_sync")
|
||||
lastPauseTime = -1;
|
||||
@@ -673,42 +672,35 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||
mediaSession.setMetadata(metadata)
|
||||
var mediaMetadata = playbackSession.getExoMediaMetadata()
|
||||
|
||||
var mediaUri = playbackSession.getContentUri()
|
||||
var mimeType = playbackSession.getMimeType()
|
||||
var mediaItem = MediaItem.Builder().setUri(mediaUri).setMediaMetadata(mediaMetadata).setMimeType(mimeType).build()
|
||||
|
||||
// var mediaUri = playbackSession.getContentUri()
|
||||
// var mimeType = playbackSession.getMimeType()
|
||||
// var mediaItem = MediaItem.Builder().setUri(mediaUri).setMediaMetadata(mediaMetadata).setMimeType(mimeType).build()
|
||||
// var dataSourceFactory = DefaultDataSourceFactory(ctx, channelId)
|
||||
// var mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItem)
|
||||
// mPlayer.setMediaSource(mediaSource, 0L)
|
||||
if (mPlayer == currentPlayer) {
|
||||
var mediaSource:MediaSource
|
||||
|
||||
// if (mPlayer == currentPlayer) {
|
||||
// var mediaSource:MediaSource
|
||||
//
|
||||
// if (currentAudiobookStreamData!!.isLocal) {
|
||||
// Log.d(tag, "Playing Local File")
|
||||
// var dataSourceFactory = DefaultDataSourceFactory(ctx, channelId)
|
||||
// mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItem)
|
||||
// } else {
|
||||
// Log.d(tag, "Playing HLS File")
|
||||
// var dataSourceFactory = DefaultHttpDataSource.Factory()
|
||||
// dataSourceFactory.setUserAgent(channelId)
|
||||
// dataSourceFactory.setDefaultRequestProperties(hashMapOf("Authorization" to "Bearer ${currentAudiobookStreamData!!.token}"))
|
||||
// mediaSource = HlsMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItem)
|
||||
// }
|
||||
// mPlayer.setMediaSource(mediaSource, currentAudiobookStreamData!!.startTime)
|
||||
// } else if (castPlayer != null) {
|
||||
if (currentPlaybackSession?.isLocal == true) {
|
||||
Log.d(tag, "Playing Local File")
|
||||
var dataSourceFactory = DefaultDataSourceFactory(ctx, channelId)
|
||||
mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItem)
|
||||
} else {
|
||||
Log.d(tag, "Playing HLS File")
|
||||
var dataSourceFactory = DefaultHttpDataSource.Factory()
|
||||
dataSourceFactory.setUserAgent(channelId)
|
||||
dataSourceFactory.setDefaultRequestProperties(hashMapOf("Authorization" to "Bearer ${playbackSession.token}"))
|
||||
mediaSource = HlsMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItem)
|
||||
}
|
||||
Log.d(tag, "Playback Session CURRENT TIME ${playbackSession.currentTime} | ${playbackSession.currentTimeMs}")
|
||||
mPlayer.setMediaSource(mediaSource, playbackSession.currentTimeMs)
|
||||
} else if (castPlayer != null) {
|
||||
//// var mediaQueue = currentAudiobookStreamData!!.getCastQueue()
|
||||
// // TODO: Start position will need to be adjusted if using multi-track queue
|
||||
//// castPlayer?.setMediaItems(mediaQueue, 0, 0)
|
||||
// }
|
||||
}
|
||||
|
||||
currentPlayer.prepare()
|
||||
currentPlayer.playWhenReady = playWhenReady
|
||||
currentPlayer.setPlaybackSpeed(1f) // TODO: Playback speed should come from settings
|
||||
}
|
||||
|
||||
fun playLocalMediaItem(localMediaItem: LocalMediaItem, playWhenReady:Boolean) {
|
||||
Log.d(tag, "playLocalMediaItem ${localMediaItem}")
|
||||
currentPlayer.prepare()
|
||||
}
|
||||
|
||||
fun initPlayer(audiobookStreamData: AudiobookStreamData) {
|
||||
@@ -727,10 +719,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||
var deviceMan = Build.MANUFACTURER
|
||||
var deviceModel = Build.MODEL
|
||||
Log.d(tag, "Checking device $deviceName | Model $deviceModel | Manufacturer $deviceMan")
|
||||
if (deviceMan.toLowerCase().contains("oneplus") || deviceName.toLowerCase().contains("oneplus")) {
|
||||
if (deviceMan.lowercase(Locale.getDefault()).contains("oneplus") || deviceName.lowercase(Locale.getDefault()).contains("oneplus")) {
|
||||
Log.d(tag, "Detected OnePlus device - removing local cover")
|
||||
currentAudiobookStreamData?.clearCover()
|
||||
} else if (deviceName.toLowerCase().contains("xperia") || deviceModel.toLowerCase().contains("xperia")) {
|
||||
} else if (deviceName.lowercase(Locale.getDefault()).contains("xperia") || deviceModel.lowercase(Locale.getDefault()).contains("xperia")) {
|
||||
Log.d(tag, "Detected Sony Xperia device - removing local cover")
|
||||
currentAudiobookStreamData?.clearCover()
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ data class BookMetadata(
|
||||
data class PodcastMetadata(
|
||||
var title:String,
|
||||
var author:String?,
|
||||
var feedUrl:String,
|
||||
var feedUrl:String?,
|
||||
var genres:MutableList<String>
|
||||
) : MediaTypeMetadata()
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.audiobookshelf.app.data
|
||||
|
||||
import android.net.Uri
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import com.getcapacitor.JSObject
|
||||
import java.util.*
|
||||
|
||||
data class ServerConfig(
|
||||
var id:String,
|
||||
@@ -30,7 +30,32 @@ data class LocalMediaItem(
|
||||
var audioTracks:MutableList<AudioTrack>,
|
||||
var localFiles:MutableList<LocalFile>,
|
||||
var coverPath:String?
|
||||
)
|
||||
) {
|
||||
|
||||
@JsonIgnore
|
||||
fun getDuration():Double {
|
||||
var total = 0.0
|
||||
audioTracks.forEach{ total += it.duration }
|
||||
return total
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
fun getMediaMetadata():MediaTypeMetadata {
|
||||
return if (mediaType == "book") {
|
||||
BookMetadata(name,null, mutableListOf(), mutableListOf(), mutableListOf(),null,null,null,null,null,null,null,false,null,null,null,null)
|
||||
} else {
|
||||
PodcastMetadata(name,null,null, mutableListOf())
|
||||
}
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
fun getPlaybackSession():PlaybackSession {
|
||||
var sessionId = "play-${UUID.randomUUID()}"
|
||||
|
||||
var mediaMetadata = getMediaMetadata()
|
||||
return PlaybackSession(sessionId,null,null,null,null,mediaType,mediaMetadata,null,getDuration(),PLAYMETHOD_LOCAL,audioTracks,0.0,null,this,null,null)
|
||||
}
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class LocalFile(
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import com.google.android.exoplayer2.MediaMetadata
|
||||
|
||||
// TODO: enum or something in kotlin?
|
||||
val PLAYMETHOD_DIRECTPLAY = 0
|
||||
val PLAYMETHOD_DIRECTSTREAM = 1
|
||||
val PLAYMETHOD_TRANSCODE = 2
|
||||
@@ -15,10 +16,10 @@ val PLAYMETHOD_LOCAL = 3
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
class PlaybackSession(
|
||||
var id:String,
|
||||
var userId:String,
|
||||
var libraryItemId:String,
|
||||
var episodeId:String,
|
||||
var mediaEntityId:String,
|
||||
var userId:String?,
|
||||
var libraryItemId:String?,
|
||||
var episodeId:String?,
|
||||
var mediaEntityId:String?,
|
||||
var mediaType:String,
|
||||
var mediaMetadata:MediaTypeMetadata,
|
||||
var coverPath:String?,
|
||||
@@ -26,15 +27,15 @@ class PlaybackSession(
|
||||
var playMethod:Int,
|
||||
var audioTracks:MutableList<AudioTrack>,
|
||||
var currentTime:Double,
|
||||
var libraryItem:LibraryItem,
|
||||
var serverUrl:String,
|
||||
var token:String
|
||||
var libraryItem:LibraryItem?,
|
||||
var localMediaItem:LocalMediaItem?,
|
||||
var serverUrl:String?,
|
||||
var token:String?
|
||||
) {
|
||||
|
||||
@JsonIgnore
|
||||
fun getIsHls():Boolean {
|
||||
return playMethod == PLAYMETHOD_TRANSCODE
|
||||
}
|
||||
val isHLS get() = playMethod == PLAYMETHOD_TRANSCODE
|
||||
val isLocal get() = playMethod == PLAYMETHOD_LOCAL
|
||||
val currentTimeMs get() = (currentTime * 1000L).toLong()
|
||||
|
||||
@JsonIgnore
|
||||
fun getTitle():String {
|
||||
@@ -47,11 +48,13 @@ class PlaybackSession(
|
||||
fun getAuthor():String {
|
||||
if (mediaMetadata == null) return "Unset"
|
||||
var metadata = mediaMetadata as BookMetadata
|
||||
return metadata.authors.joinToString(",") { it.name }
|
||||
return metadata.authorName ?: "Unset"
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
fun getCoverUri(): Uri {
|
||||
if (localMediaItem?.coverPath != null) return Uri.parse(localMediaItem?.coverPath) ?: 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")
|
||||
}
|
||||
@@ -59,6 +62,7 @@ class PlaybackSession(
|
||||
@JsonIgnore
|
||||
fun getContentUri(): Uri {
|
||||
var audioTrack = audioTracks[0]
|
||||
if (isLocal) return Uri.parse(audioTrack.contentUrl) // Local content url
|
||||
return Uri.parse("$serverUrl${audioTrack.contentUrl}?token=$token")
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ class FolderScanner(var ctx: Context) {
|
||||
|
||||
// First image file use as cover path
|
||||
if (coverPath == null) {
|
||||
coverPath = localFile.absolutePath
|
||||
coverPath = localFile.contentUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user