Fix crash when server requests fail

This commit is contained in:
advplyr
2022-06-19 11:57:19 -05:00
parent 6805d7eb96
commit a69054fefa
8 changed files with 134 additions and 66 deletions
@@ -270,17 +270,21 @@ class MediaManager(var apiHandler: ApiHandler, var ctx: Context) {
} }
} }
fun play(libraryItemWrapper:LibraryItemWrapper, episode:PodcastEpisode?, playItemRequestPayload:PlayItemRequestPayload, cb: (PlaybackSession) -> Unit) { fun play(libraryItemWrapper:LibraryItemWrapper, episode:PodcastEpisode?, playItemRequestPayload:PlayItemRequestPayload, cb: (PlaybackSession?) -> Unit) {
if (libraryItemWrapper is LocalLibraryItem) { if (libraryItemWrapper is LocalLibraryItem) {
val localLibraryItem = libraryItemWrapper as LocalLibraryItem val localLibraryItem = libraryItemWrapper as LocalLibraryItem
cb(localLibraryItem.getPlaybackSession(episode)) cb(localLibraryItem.getPlaybackSession(episode))
} else { } else {
val libraryItem = libraryItemWrapper as LibraryItem val libraryItem = libraryItemWrapper as LibraryItem
apiHandler.playLibraryItem(libraryItem.id,episode?.id ?: "",playItemRequestPayload) { apiHandler.playLibraryItem(libraryItem.id,episode?.id ?: "",playItemRequestPayload) {
if (it == null) {
cb(null)
} else {
cb(it) cb(it)
} }
} }
} }
}
private fun levenshtein(lhs : CharSequence, rhs : CharSequence) : Int { private fun levenshtein(lhs : CharSequence, rhs : CharSequence) : Int {
val lhsLength = lhs.length + 1 val lhsLength = lhs.length + 1
@@ -25,13 +25,16 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
Log.d(tag, "ON PREPARE MEDIA SESSION COMPAT") Log.d(tag, "ON PREPARE MEDIA SESSION COMPAT")
playerNotificationService.mediaManager.getFirstItem()?.let { li -> playerNotificationService.mediaManager.getFirstItem()?.let { li ->
playerNotificationService.mediaManager.play(li, null, playerNotificationService.getPlayItemRequestPayload(false)) { playerNotificationService.mediaManager.play(li, null, playerNotificationService.getPlayItemRequestPayload(false)) {
Log.d(tag, "About to prepare player with ${it.displayTitle}") if (it == null) {
Log.e(tag, "Failed to play library item")
} else {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,true,null) playerNotificationService.preparePlayer(it,true,null)
} }
} }
} }
} }
}
override fun onPlay() { override fun onPlay() {
Log.d(tag, "ON PLAY MEDIA SESSION COMPAT") Log.d(tag, "ON PLAY MEDIA SESSION COMPAT")
@@ -47,9 +50,12 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
Log.d(tag, "ON PLAY FROM SEARCH $query") Log.d(tag, "ON PLAY FROM SEARCH $query")
playerNotificationService.mediaManager.getFromSearch(query)?.let { li -> playerNotificationService.mediaManager.getFromSearch(query)?.let { li ->
playerNotificationService.mediaManager.play(li, null, playerNotificationService.getPlayItemRequestPayload(false)) { playerNotificationService.mediaManager.play(li, null, playerNotificationService.getPlayItemRequestPayload(false)) {
Log.d(tag, "About to prepare player with ${it.displayTitle}") if (it == null) {
Log.e(tag, "Failed to play library item")
} else {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,true,null) playerNotificationService.preparePlayer(it, true, null)
}
} }
} }
} }
@@ -105,9 +111,12 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
libraryItemWrapper?.let { li -> libraryItemWrapper?.let { li ->
playerNotificationService.mediaManager.play(li, podcastEpisode, playerNotificationService.getPlayItemRequestPayload(false)) { playerNotificationService.mediaManager.play(li, podcastEpisode, playerNotificationService.getPlayItemRequestPayload(false)) {
Log.d(tag, "About to prepare player with ${it.displayTitle}") if (it == null) {
Log.e(tag, "Failed to play library item")
} else {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,true,null) playerNotificationService.preparePlayer(it, true, null)
}
} }
} }
} }
@@ -31,8 +31,12 @@ class MediaSessionPlaybackPreparer(var playerNotificationService:PlayerNotificat
Log.d(tag, "ON PREPARE $playWhenReady") Log.d(tag, "ON PREPARE $playWhenReady")
playerNotificationService.mediaManager.getFirstItem()?.let { li -> playerNotificationService.mediaManager.getFirstItem()?.let { li ->
playerNotificationService.mediaManager.play(li, null, playerNotificationService.getPlayItemRequestPayload(false)) { playerNotificationService.mediaManager.play(li, null, playerNotificationService.getPlayItemRequestPayload(false)) {
if (it == null) {
Log.e(tag, "Failed to play library item")
} else {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,playWhenReady,null) playerNotificationService.preparePlayer(it, playWhenReady, null)
}
} }
} }
} }
@@ -54,9 +58,12 @@ class MediaSessionPlaybackPreparer(var playerNotificationService:PlayerNotificat
libraryItemWrapper?.let { li -> libraryItemWrapper?.let { li ->
playerNotificationService.mediaManager.play(li, podcastEpisode, playerNotificationService.getPlayItemRequestPayload(false)) { playerNotificationService.mediaManager.play(li, podcastEpisode, playerNotificationService.getPlayItemRequestPayload(false)) {
Log.d(tag, "About to prepare player with ${it.displayTitle}") if (it == null) {
Log.e(tag, "Failed to play library item")
} else {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,playWhenReady,null) playerNotificationService.preparePlayer(it, playWhenReady, null)
}
} }
} }
} }
@@ -66,9 +73,12 @@ class MediaSessionPlaybackPreparer(var playerNotificationService:PlayerNotificat
Log.d(tag, "ON PREPARE FROM SEARCH $query") Log.d(tag, "ON PREPARE FROM SEARCH $query")
playerNotificationService.mediaManager.getFromSearch(query)?.let { li -> playerNotificationService.mediaManager.getFromSearch(query)?.let { li ->
playerNotificationService.mediaManager.play(li, null, playerNotificationService.getPlayItemRequestPayload(false)) { playerNotificationService.mediaManager.play(li, null, playerNotificationService.getPlayItemRequestPayload(false)) {
Log.d(tag, "About to prepare player with ${it.displayTitle}") if (it == null) {
Log.e(tag, "Failed to play library item")
} else {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,playWhenReady,null) playerNotificationService.preparePlayer(it, playWhenReady, null)
}
} }
} }
} }
@@ -381,10 +381,15 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
val libraryItemId = playbackSession.libraryItemId ?: "" // Must be true since direct play val libraryItemId = playbackSession.libraryItemId ?: "" // Must be true since direct play
val episodeId = playbackSession.episodeId val episodeId = playbackSession.episodeId
apiHandler.playLibraryItem(libraryItemId, episodeId, playItemRequestPayload) { apiHandler.playLibraryItem(libraryItemId, episodeId, playItemRequestPayload) {
if (it == null) { // Play request failed
clientEventEmitter?.onPlaybackFailed(errorMessage)
closePlayback()
} else {
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
preparePlayer(it, true, null) preparePlayer(it, true, null)
} }
} }
}
} else { } else {
clientEventEmitter?.onPlaybackFailed(errorMessage) clientEventEmitter?.onPlaybackFailed(errorMessage)
closePlayback() closePlayback()
@@ -400,12 +405,16 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
val libraryItemId = playbackSession.libraryItemId ?: "" // Must be true since direct play val libraryItemId = playbackSession.libraryItemId ?: "" // Must be true since direct play
val episodeId = playbackSession.episodeId val episodeId = playbackSession.episodeId
apiHandler.playLibraryItem(libraryItemId, episodeId, playItemRequestPayload) { apiHandler.playLibraryItem(libraryItemId, episodeId, playItemRequestPayload) {
if (it == null) {
Log.e(tag, "Failed to start new playback session")
} else {
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
preparePlayer(it, true, null) preparePlayer(it, true, null)
} }
} }
} }
} }
}
fun switchToPlayer(useCastPlayer: Boolean) { fun switchToPlayer(useCastPlayer: Boolean) {
val wasPlaying = currentPlayer.isPlaying val wasPlaying = currentPlayer.isPlaying
@@ -165,7 +165,7 @@ class AbsAudioPlayer : Plugin() {
if (libraryItemId.isEmpty()) { if (libraryItemId.isEmpty()) {
Log.e(tag, "Invalid call to play library item no library item id") Log.e(tag, "Invalid call to play library item no library item id")
return call.resolve() return call.resolve(JSObject("{\"error\":\"Invalid request\"}"))
} }
if (libraryItemId.startsWith("local")) { // Play local media item if (libraryItemId.startsWith("local")) { // Play local media item
@@ -176,7 +176,7 @@ class AbsAudioPlayer : Plugin() {
episode = podcastMedia.episodes?.find { ep -> ep.id == episodeId } episode = podcastMedia.episodes?.find { ep -> ep.id == episodeId }
if (episode == null) { if (episode == null) {
Log.e(tag, "prepareLibraryItem: Podcast episode not found $episodeId") Log.e(tag, "prepareLibraryItem: Podcast episode not found $episodeId")
return call.resolve(JSObject()) return call.resolve(JSObject("{\"error\":\"Podcast episode not found\"}"))
} }
} }
@@ -191,7 +191,9 @@ class AbsAudioPlayer : Plugin() {
val playItemRequestPayload = playerNotificationService.getPlayItemRequestPayload(false) val playItemRequestPayload = playerNotificationService.getPlayItemRequestPayload(false)
apiHandler.playLibraryItem(libraryItemId, episodeId, playItemRequestPayload) { apiHandler.playLibraryItem(libraryItemId, episodeId, playItemRequestPayload) {
if (it == null) {
call.resolve(JSObject("{\"error\":\"Server play request failed\"}"))
} else {
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
Log.d(tag, "Preparing Player TEST ${jacksonMapper.writeValueAsString(it)}") Log.d(tag, "Preparing Player TEST ${jacksonMapper.writeValueAsString(it)}")
playerNotificationService.preparePlayer(it, playWhenReady, playbackRate) playerNotificationService.preparePlayer(it, playWhenReady, playbackRate)
@@ -201,6 +203,7 @@ class AbsAudioPlayer : Plugin() {
} }
} }
} }
}
@PluginMethod @PluginMethod
fun getCurrentTime(call: PluginCall) { fun getCurrentTime(call: PluginCall) {
@@ -143,6 +143,9 @@ class AbsDownloader : Plugin() {
} }
apiHandler.getLibraryItemWithProgress(libraryItemId, episodeId) { libraryItem -> apiHandler.getLibraryItemWithProgress(libraryItemId, episodeId) { libraryItem ->
if (libraryItem == null) {
call.resolve(JSObject("{\"error\":\"Server request failed\"}"))
} else {
Log.d(tag, "Got library item from server ${libraryItem.id}") Log.d(tag, "Got library item from server ${libraryItem.id}")
val localFolder = DeviceManager.dbManager.getLocalFolder(localFolderId) val localFolder = DeviceManager.dbManager.getLocalFolder(localFolderId)
@@ -171,6 +174,7 @@ class AbsDownloader : Plugin() {
} }
} }
} }
}
// Clean folder path so it can be used in URL // Clean folder path so it can be used in URL
private fun cleanRelPath(relPath: String): String { private fun cleanRelPath(relPath: String): String {
@@ -135,21 +135,31 @@ class ApiHandler(var ctx:Context) {
} }
} }
fun getLibraryItem(libraryItemId:String, cb: (LibraryItem) -> Unit) { fun getLibraryItem(libraryItemId:String, cb: (LibraryItem?) -> Unit) {
getRequest("/api/items/$libraryItemId?expanded=1", null, null) { getRequest("/api/items/$libraryItemId?expanded=1", null, null) {
if (it.has("error")) {
Log.e(tag, it.getString("error") ?: "getLibraryItem Failed")
cb(null)
} else {
val libraryItem = jacksonMapper.readValue<LibraryItem>(it.toString()) val libraryItem = jacksonMapper.readValue<LibraryItem>(it.toString())
cb(libraryItem) cb(libraryItem)
} }
} }
}
fun getLibraryItemWithProgress(libraryItemId:String, episodeId:String?, cb: (LibraryItem) -> Unit) { fun getLibraryItemWithProgress(libraryItemId:String, episodeId:String?, cb: (LibraryItem?) -> Unit) {
var requestUrl = "/api/items/$libraryItemId?expanded=1&include=progress" var requestUrl = "/api/items/$libraryItemId?expanded=1&include=progress"
if (!episodeId.isNullOrEmpty()) requestUrl += "&episode=$episodeId" if (!episodeId.isNullOrEmpty()) requestUrl += "&episode=$episodeId"
getRequest(requestUrl, null, null) { getRequest(requestUrl, null, null) {
if (it.has("error")) {
Log.e(tag, it.getString("error") ?: "getLibraryItemWithProgress Failed")
cb(null)
} else {
val libraryItem = jacksonMapper.readValue<LibraryItem>(it.toString()) val libraryItem = jacksonMapper.readValue<LibraryItem>(it.toString())
cb(libraryItem) cb(libraryItem)
} }
} }
}
fun getLibraryItems(libraryId:String, cb: (List<LibraryItem>) -> Unit) { fun getLibraryItems(libraryId:String, cb: (List<LibraryItem>) -> Unit) {
getRequest("/api/libraries/$libraryId/items?limit=100&minified=1", null, null) { getRequest("/api/libraries/$libraryId/items?limit=100&minified=1", null, null) {
@@ -186,17 +196,22 @@ class ApiHandler(var ctx:Context) {
} }
} }
fun playLibraryItem(libraryItemId:String, episodeId:String?, playItemRequestPayload:PlayItemRequestPayload, cb: (PlaybackSession) -> Unit) { fun playLibraryItem(libraryItemId:String, episodeId:String?, playItemRequestPayload:PlayItemRequestPayload, cb: (PlaybackSession?) -> Unit) {
val payload = JSObject(jacksonMapper.writeValueAsString(playItemRequestPayload)) val payload = JSObject(jacksonMapper.writeValueAsString(playItemRequestPayload))
val endpoint = if (episodeId.isNullOrEmpty()) "/api/items/$libraryItemId/play" else "/api/items/$libraryItemId/play/$episodeId" val endpoint = if (episodeId.isNullOrEmpty()) "/api/items/$libraryItemId/play" else "/api/items/$libraryItemId/play/$episodeId"
postRequest(endpoint, payload) { postRequest(endpoint, payload) {
if (it.has("error")) {
Log.e(tag, it.getString("error") ?: "Play Library Item Failed")
cb(null)
} else {
it.put("serverConnectionConfigId", DeviceManager.serverConnectionConfig?.id) it.put("serverConnectionConfigId", DeviceManager.serverConnectionConfig?.id)
it.put("serverAddress", DeviceManager.serverAddress) it.put("serverAddress", DeviceManager.serverAddress)
val playbackSession = jacksonMapper.readValue<PlaybackSession>(it.toString()) val playbackSession = jacksonMapper.readValue<PlaybackSession>(it.toString())
cb(playbackSession) cb(playbackSession)
} }
} }
}
fun sendProgressSync(sessionId:String, syncData: MediaProgressSyncData, cb: (Boolean) -> Unit) { fun sendProgressSync(sessionId:String, syncData: MediaProgressSyncData, cb: (Boolean) -> Unit) {
val payload = JSObject(jacksonMapper.writeValueAsString(syncData)) val payload = JSObject(jacksonMapper.writeValueAsString(syncData))
@@ -236,10 +251,12 @@ class ApiHandler(var ctx:Context) {
Log.d(tag, "Sending sync local progress request with ${localMediaProgress.size} progress items") Log.d(tag, "Sending sync local progress request with ${localMediaProgress.size} progress items")
val payload = JSObject(jacksonMapper.writeValueAsString(LocalMediaProgressSyncPayload(localMediaProgress))) val payload = JSObject(jacksonMapper.writeValueAsString(LocalMediaProgressSyncPayload(localMediaProgress)))
postRequest("/api/me/sync-local-progress", payload) { postRequest("/api/me/sync-local-progress", payload) {
Log.d(tag, "Media Progress Sync payload $payload - response ${it.toString()}") Log.d(tag, "Media Progress Sync payload $payload - response ${it}")
if (it.toString() == "{}") { if (it.toString() == "{}") {
Log.e(tag, "Progress sync received empty object") Log.e(tag, "Progress sync received empty object")
} else if (it.has("error")) {
Log.e(tag, it.getString("error") ?: "Progress sync error")
} else { } else {
val progressSyncResponsePayload = jacksonMapper.readValue<MediaProgressSyncResponsePayload>(it.toString()) val progressSyncResponsePayload = jacksonMapper.readValue<MediaProgressSyncResponsePayload>(it.toString())
+12
View File
@@ -185,11 +185,17 @@ export default {
} }
AbsAudioPlayer.prepareLibraryItem({ libraryItemId, episodeId: null, playWhenReady: false, playbackRate }) AbsAudioPlayer.prepareLibraryItem({ libraryItemId, episodeId: null, playWhenReady: false, playbackRate })
.then((data) => { .then((data) => {
if (data.error) {
const errorMsg = data.error || 'Failed to play'
this.$toast.error(errorMsg)
} else {
console.log('Library item play response', JSON.stringify(data)) console.log('Library item play response', JSON.stringify(data))
AbsAudioPlayer.requestSession() AbsAudioPlayer.requestSession()
}
}) })
.catch((error) => { .catch((error) => {
console.error('Failed', error) console.error('Failed', error)
this.$toast.error('Failed to play')
}) })
}, },
async playLibraryItem(payload) { async playLibraryItem(payload) {
@@ -220,15 +226,21 @@ export default {
console.log('Called playLibraryItem', libraryItemId) console.log('Called playLibraryItem', libraryItemId)
AbsAudioPlayer.prepareLibraryItem({ libraryItemId, episodeId, playWhenReady: true, playbackRate }) AbsAudioPlayer.prepareLibraryItem({ libraryItemId, episodeId, playWhenReady: true, playbackRate })
.then((data) => { .then((data) => {
if (data.error) {
const errorMsg = data.error || 'Failed to play'
this.$toast.error(errorMsg)
} else {
console.log('Library item play response', JSON.stringify(data)) console.log('Library item play response', JSON.stringify(data))
if (!libraryItemId.startsWith('local')) { if (!libraryItemId.startsWith('local')) {
this.serverLibraryItemId = libraryItemId this.serverLibraryItemId = libraryItemId
} else { } else {
this.serverLibraryItemId = serverLibraryItemId this.serverLibraryItemId = serverLibraryItemId
} }
}
}) })
.catch((error) => { .catch((error) => {
console.error('Failed', error) console.error('Failed', error)
this.$toast.error('Failed to play')
}) })
}, },
pauseItem() { pauseItem() {