@@ -29,6 +29,7 @@ import project.pipepipe.app.platform.getPlaybackStartPosition
2929import project.pipepipe.app.platform.toMedia3MediaItem
3030import project.pipepipe.app.platform.toPlatformMediaItem
3131import project.pipepipe.app.platform.uuid
32+ import project.pipepipe.app.uistate.VideoDetailPageState
3233import project.pipepipe.shared.infoitem.StreamInfo
3334import project.pipepipe.shared.job.SupportedJobType
3435import java.util.concurrent.ExecutorService
@@ -589,6 +590,11 @@ class PlaybackService : MediaLibraryService() {
589590
590591 private fun applyPlaybackMode (mode : PlaybackMode ) {
591592 val disableVideo = (mode == PlaybackMode .AUDIO_ONLY )
593+ if (disableVideo && SharedContext .sharedVideoDetailViewModel.uiState.value.pageState == VideoDetailPageState .FULLSCREEN_PLAYER ) {
594+ // for unknown reason, sometimes switching from detail page -> fullscreen will cause video track disabled but playback mode still video_audio
595+ // hopefully this check should prevent it.
596+ return
597+ }
592598 val params = player.trackSelectionParameters
593599 .buildUpon()
594600 .setTrackTypeDisabled(C .TRACK_TYPE_VIDEO , disableVideo)
@@ -611,43 +617,6 @@ class PlaybackService : MediaLibraryService() {
611617 )
612618 }
613619
614- private fun refreshStreamAndRetry () {
615- val currentIndex = player.currentMediaItemIndex
616- val savedPosition = player.currentPosition
617- serviceScope.launch {
618- try {
619- // Get service ID from current media item
620- val currentItem = player.currentMediaItem ? : return @launch
621- val serviceId = currentItem.mediaMetadata.extras?.getInt(" KEY_SERVICE_ID" )
622- val uuid = currentItem.mediaMetadata.extras?.getString(" KEY_UUID" )
623-
624- // Fetch fresh stream info
625- val streamInfo = withContext(Dispatchers .IO ) {
626- executeJobFlow(
627- SupportedJobType .FETCH_INFO ,
628- currentItem.mediaId,
629- serviceId
630- ).info as StreamInfo
631- }
632-
633- // Create new media item with fresh stream URLs
634- val newMediaItem = streamInfo.toMedia3MediaItem(uuid)
635-
636- // Replace the media item at the current position
637- withContext(Dispatchers .Main ) {
638- player.removeMediaItem(currentIndex)
639- player.addMediaItem(currentIndex, newMediaItem)
640-
641- // Seek to the saved position and try to play
642- player.seekTo(currentIndex, savedPosition)
643- player.prepare()
644- player.play()
645- }
646- } catch (e: Exception ) {
647- e.printStackTrace()
648- }
649- }
650- }
651620 private fun createPlayerListener (): Player .Listener {
652621 return object : Player .Listener {
653622 override fun onMediaItemTransition (mediaItem : MediaItem ? , reason : Int ) {
@@ -695,54 +664,6 @@ class PlaybackService : MediaLibraryService() {
695664 )
696665 }
697666
698-
699- if (error.cause?.message?.contains(" 403" ) == true
700- || error.cause?.message?.contains(" maybeThrowPlaylistRefreshError" ) == true ) {
701- val retryState = retryStates.getOrPut(mediaId) { RetryState () }
702-
703- // First phase: retry up to MAX_RETRIES_BEFORE_REFRESH times before refreshing
704- if (! retryState.hasRefreshedStream && retryState.retryCount < MAX_RETRIES_BEFORE_REFRESH ) {
705- retryState.retryCount++
706- ToastManager .show(" 403 error, retrying (${retryState.retryCount} /$MAX_RETRIES_BEFORE_REFRESH )..." )
707-
708- // Simple retry - just prepare and play again
709- player.prepare()
710- player.play()
711- return
712- }
713-
714- // Second phase: refresh stream if we haven't done so yet
715- if (! retryState.hasRefreshedStream) {
716- retryState.hasRefreshedStream = true
717- retryState.retryCount = 0
718- ToastManager .show(" Refreshing stream after $MAX_RETRIES_BEFORE_REFRESH retries..." )
719-
720- refreshStreamAndRetry()
721- return
722- }
723-
724- // Third phase: retry up to MAX_RETRIES_AFTER_REFRESH more times after refresh
725- if (retryState.retryCount < MAX_RETRIES_AFTER_REFRESH ) {
726- retryState.retryCount++
727- ToastManager .show(" 403 error after refresh, retrying (${retryState.retryCount} /$MAX_RETRIES_AFTER_REFRESH )..." )
728-
729- // Simple retry - just prepare and play again
730- player.prepare()
731- player.play()
732- return
733- }
734-
735- // Final phase: all retries exhausted, give up and skip to next
736- ToastManager .show(" Failed after all retries, skipping to next..." )
737- retryStates.remove(mediaId)
738- SharedContext .queueManager.removeItemByUuid(player.currentMediaItem!! .uuid)
739- if (player.mediaItemCount > 0 ) {
740- player.prepare()
741- player.play()
742- }
743- return
744- }
745-
746667 // Handle network-related errors: just pause, don't evict
747668 when (error.errorCode) {
748669 PlaybackException .ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE ,
0 commit comments