Rework YouTube Radio

This commit is contained in:
vfsfitvnm
2022-06-11 23:01:06 +02:00
parent f39276875d
commit a0e42473e6
10 changed files with 222 additions and 219 deletions

View File

@@ -32,29 +32,33 @@ import androidx.media3.exoplayer.analytics.AnalyticsListener
import androidx.media3.exoplayer.analytics.PlaybackStats
import androidx.media3.exoplayer.analytics.PlaybackStatsListener
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
import androidx.media3.session.MediaController
import androidx.media3.session.MediaNotification
import androidx.media3.session.*
import androidx.media3.session.MediaNotification.ActionFactory
import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService
import coil.ImageLoader
import coil.request.ImageRequest
import com.google.common.util.concurrent.ListenableFuture
import it.vfsfitvnm.vimusic.Database
import it.vfsfitvnm.vimusic.MainActivity
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.utils.RingBuffer
import it.vfsfitvnm.vimusic.utils.YoutubePlayer
import it.vfsfitvnm.vimusic.utils.forcePlayFromBeginning
import it.vfsfitvnm.vimusic.utils.insert
import it.vfsfitvnm.youtubemusic.Outcome
import kotlinx.coroutines.*
import kotlin.math.roundToInt
val StartRadioCommand = SessionCommand("StartRadioCommand", Bundle.EMPTY)
val StartArtistRadioCommand = SessionCommand("StartArtistRadioCommand", Bundle.EMPTY)
val StopRadioCommand = SessionCommand("StopRadioCommand", Bundle.EMPTY)
@ExperimentalAnimationApi
@ExperimentalFoundationApi
class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
MediaNotification.Provider,
PlaybackStatsListener.Callback, Player.Listener,YoutubePlayer.Radio.Listener {
MediaSession.SessionCallback,
PlaybackStatsListener.Callback, Player.Listener {
companion object {
private const val NotificationId = 1001
@@ -74,6 +78,8 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
private var lastArtworkUri: Uri? = null
private var lastBitmap: Bitmap? = null
private var radio: YoutubePlayer.Radio? = null
private val coroutineScope = CoroutineScope(Dispatchers.IO) + Job()
override fun onCreate() {
@@ -101,11 +107,11 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
mediaSession = MediaSession.Builder(this, player)
.withSessionActivity()
.setSessionCallback(this)
.setMediaItemFiller(this)
.build()
player.addListener(this)
YoutubePlayer.Radio.listener = this
}
override fun onDestroy() {
@@ -119,6 +125,49 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
return mediaSession
}
override fun onConnect(
session: MediaSession,
controller: MediaSession.ControllerInfo
): MediaSession.ConnectionResult {
val sessionCommands = SessionCommands.Builder()
.add(StartRadioCommand)
.add(StartArtistRadioCommand)
.add(StopRadioCommand)
.build()
val playerCommands = Player.Commands.Builder().addAllCommands().build()
return MediaSession.ConnectionResult.accept(sessionCommands,playerCommands)
}
override fun onCustomCommand(
session: MediaSession,
controller: MediaSession.ControllerInfo,
customCommand: SessionCommand,
args: Bundle
): ListenableFuture<SessionResult> {
when (customCommand) {
StartRadioCommand, StartArtistRadioCommand -> {
radio = null
YoutubePlayer.Radio(
videoId = args.getString("videoId"),
playlistId = args.getString("playlistId"),
playlistSetVideoId = args.getString("playlistSetVideoId"),
parameters = args.getString("params"),
).let {
coroutineScope.launch(Dispatchers.Main) {
when (customCommand) {
StartRadioCommand -> mediaSession.player.addMediaItems(it.process().drop(1))
StartArtistRadioCommand -> mediaSession.player.forcePlayFromBeginning(it.process())
}
radio = it
}
}
}
StopRadioCommand -> radio = null
}
return super.onCustomCommand(session, controller, customCommand, args)
}
override fun onPlaybackStatsReady(
eventTime: AnalyticsListener.EventTime,
playbackStats: PlaybackStats
@@ -132,18 +181,12 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
}
}
override fun process(play: Boolean) {
if (YoutubePlayer.Radio.isActive) {
coroutineScope.launch {
YoutubePlayer.Radio.process(mediaSession.player, play = play)
}
}
}
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
if (YoutubePlayer.Radio.isActive) {
coroutineScope.launch {
YoutubePlayer.Radio.process(mediaSession.player)
radio?.let { radio ->
if (mediaSession.player.mediaItemCount - mediaSession.player.currentMediaItemIndex <= 3) {
coroutineScope.launch(Dispatchers.Main) {
mediaSession.player.addMediaItems(radio.process())
}
}
}
}