refactor: encode player metadata as JSON string instead of parcelable

This commit is contained in:
Bnyro 2025-02-03 18:33:53 +01:00
parent a1cb16b07a
commit 33c386e4ce
4 changed files with 33 additions and 13 deletions

View File

@ -7,10 +7,12 @@ import androidx.core.os.bundleOf
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata import androidx.media3.common.MediaMetadata
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import com.github.libretube.api.JsonHelper
import com.github.libretube.api.obj.Streams import com.github.libretube.api.obj.Streams
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
import com.github.libretube.db.obj.DownloadChapter import com.github.libretube.db.obj.DownloadChapter
import com.github.libretube.db.obj.DownloadWithItems import com.github.libretube.db.obj.DownloadWithItems
import kotlinx.serialization.encodeToString
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
fun MediaItem.Builder.setMetadata(streams: Streams, videoId: String) = apply { fun MediaItem.Builder.setMetadata(streams: Streams, videoId: String) = apply {
@ -18,8 +20,9 @@ fun MediaItem.Builder.setMetadata(streams: Streams, videoId: String) = apply {
MediaMetadataCompat.METADATA_KEY_TITLE to streams.title, MediaMetadataCompat.METADATA_KEY_TITLE to streams.title,
MediaMetadataCompat.METADATA_KEY_ARTIST to streams.uploader, MediaMetadataCompat.METADATA_KEY_ARTIST to streams.uploader,
IntentData.videoId to videoId, IntentData.videoId to videoId,
IntentData.streams to streams, // JSON-encode as work-around for https://github.com/androidx/media/issues/564
IntentData.chapters to streams.chapters IntentData.streams to JsonHelper.json.encodeToString(streams),
IntentData.chapters to JsonHelper.json.encodeToString(streams.chapters)
) )
setMediaMetadata( setMediaMetadata(
MediaMetadata.Builder() MediaMetadata.Builder()
@ -37,13 +40,14 @@ fun MediaItem.Builder.setMetadata(streams: Streams, videoId: String) = apply {
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
fun MediaItem.Builder.setMetadata(downloadWithItems: DownloadWithItems) = apply { fun MediaItem.Builder.setMetadata(downloadWithItems: DownloadWithItems) = apply {
val (download, _, chapters) = downloadWithItems val (download, _, downloadChapters) = downloadWithItems
val chapters = downloadChapters.map(DownloadChapter::toChapterSegment)
val extras = bundleOf( val extras = bundleOf(
MediaMetadataCompat.METADATA_KEY_TITLE to download.title, MediaMetadataCompat.METADATA_KEY_TITLE to download.title,
MediaMetadataCompat.METADATA_KEY_ARTIST to download.uploader, MediaMetadataCompat.METADATA_KEY_ARTIST to download.uploader,
IntentData.videoId to download.videoId, IntentData.videoId to download.videoId,
IntentData.chapters to chapters.map(DownloadChapter::toChapterSegment) IntentData.chapters to JsonHelper.json.encodeToString(chapters)
) )
setMediaMetadata( setMediaMetadata(
MediaMetadata.Builder() MediaMetadata.Builder()

View File

@ -207,7 +207,9 @@ open class OnlinePlayerService : AbstractPlayerService() {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
updatePlaylistMetadata { updatePlaylistMetadata {
setExtras(bundleOf(IntentData.segments to ArrayList(sponsorBlockSegments))) // JSON-encode as work-around for https://github.com/androidx/media/issues/564
val segments = JsonHelper.json.encodeToString(sponsorBlockSegments)
setExtras(bundleOf(IntentData.segments to segments))
} }
checkForSegments() checkForSegments()

View File

@ -25,14 +25,13 @@ import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.session.MediaController import androidx.media3.session.MediaController
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.api.JsonHelper
import com.github.libretube.api.obj.ChapterSegment import com.github.libretube.api.obj.ChapterSegment
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
import com.github.libretube.databinding.FragmentAudioPlayerBinding import com.github.libretube.databinding.FragmentAudioPlayerBinding
import com.github.libretube.extensions.navigateVideo import com.github.libretube.extensions.navigateVideo
import com.github.libretube.extensions.normalize import com.github.libretube.extensions.normalize
import com.github.libretube.extensions.parcelableList
import com.github.libretube.extensions.seekBy import com.github.libretube.extensions.seekBy
import com.github.libretube.extensions.serializable
import com.github.libretube.extensions.togglePlayPauseState import com.github.libretube.extensions.togglePlayPauseState
import com.github.libretube.extensions.updateIfChanged import com.github.libretube.extensions.updateIfChanged
import com.github.libretube.helpers.AudioHelper import com.github.libretube.helpers.AudioHelper
@ -194,8 +193,11 @@ class AudioPlayerFragment : Fragment(R.layout.fragment_audio_player), AudioPlaye
} }
binding.openChapters.setOnClickListener { binding.openChapters.setOnClickListener {
// JSON-encode as work-around for https://github.com/androidx/media/issues/564
chaptersModel.chaptersLiveData.value = chaptersModel.chaptersLiveData.value =
playerController?.mediaMetadata?.extras?.serializable(IntentData.chapters) playerController?.mediaMetadata?.extras?.getString(IntentData.chapters)?.let {
JsonHelper.json.decodeFromString(it)
}
ChaptersBottomSheet() ChaptersBottomSheet()
.apply { .apply {
@ -430,7 +432,10 @@ class AudioPlayerFragment : Fragment(R.layout.fragment_audio_player), AudioPlaye
super.onMediaMetadataChanged(mediaMetadata) super.onMediaMetadataChanged(mediaMetadata)
updateStreamInfo(mediaMetadata) updateStreamInfo(mediaMetadata)
val chapters: List<ChapterSegment>? = mediaMetadata.extras?.parcelableList(IntentData.chapters) // JSON-encode as work-around for https://github.com/androidx/media/issues/564
val chapters: List<ChapterSegment>? = mediaMetadata.extras?.getString(IntentData.chapters)?.let {
JsonHelper.json.decodeFromString(it)
}
_binding?.openChapters?.isVisible = !chapters.isNullOrEmpty() _binding?.openChapters?.isVisible = !chapters.isNullOrEmpty()
} }
}) })

View File

@ -51,6 +51,7 @@ import androidx.media3.common.Player
import androidx.media3.session.MediaController import androidx.media3.session.MediaController
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.api.JsonHelper
import com.github.libretube.api.obj.ChapterSegment import com.github.libretube.api.obj.ChapterSegment
import com.github.libretube.api.obj.Segment import com.github.libretube.api.obj.Segment
import com.github.libretube.api.obj.Streams import com.github.libretube.api.obj.Streams
@ -66,7 +67,6 @@ import com.github.libretube.enums.PlayerEvent
import com.github.libretube.enums.ShareObjectType import com.github.libretube.enums.ShareObjectType
import com.github.libretube.extensions.formatShort import com.github.libretube.extensions.formatShort
import com.github.libretube.extensions.parcelable import com.github.libretube.extensions.parcelable
import com.github.libretube.extensions.parcelableList
import com.github.libretube.extensions.serializableExtra import com.github.libretube.extensions.serializableExtra
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
import com.github.libretube.extensions.togglePlayPauseState import com.github.libretube.extensions.togglePlayPauseState
@ -308,7 +308,10 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
override fun onMediaMetadataChanged(mediaMetadata: MediaMetadata) { override fun onMediaMetadataChanged(mediaMetadata: MediaMetadata) {
super.onMediaMetadataChanged(mediaMetadata) super.onMediaMetadataChanged(mediaMetadata)
val maybeStreams: Streams? = mediaMetadata.extras?.parcelable(IntentData.streams) // JSON-encode as work-around for https://github.com/androidx/media/issues/564
val maybeStreams: Streams? = mediaMetadata.extras?.getString(IntentData.streams)?.let {
JsonHelper.json.decodeFromString(it)
}
maybeStreams?.let { streams -> maybeStreams?.let { streams ->
this@PlayerFragment.streams = streams this@PlayerFragment.streams = streams
viewModel.segments.postValue(emptyList()) viewModel.segments.postValue(emptyList())
@ -332,7 +335,10 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
} }
} }
val segments: List<Segment>? = mediaMetadata.extras?.parcelableList(IntentData.segments) // JSON-encode as work-around for https://github.com/androidx/media/issues/564
val segments: List<Segment>? = mediaMetadata.extras?.getString(IntentData.segments)?.let {
JsonHelper.json.decodeFromString(it)
}
viewModel.segments.postValue(segments.orEmpty()) viewModel.segments.postValue(segments.orEmpty())
} }
@ -514,8 +520,11 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
updatePlayPauseButton() updatePlayPauseButton()
if (!startNewSession) { if (!startNewSession) {
// JSON-encode as work-around for https://github.com/androidx/media/issues/564
val streams: Streams? = val streams: Streams? =
playerController.mediaMetadata.extras?.parcelable(IntentData.streams) playerController.mediaMetadata.extras?.getString(IntentData.streams)?.let { json ->
JsonHelper.json.decodeFromString(json)
}
// reload the streams data and playback, metadata apparently no longer exists // reload the streams data and playback, metadata apparently no longer exists
if (streams == null) { if (streams == null) {