playback: improve queue item setup
- Use same media description code - Make queue removal more reliable
This commit is contained in:
parent
130d30c70d
commit
889713d5e0
3 changed files with 59 additions and 59 deletions
|
@ -105,11 +105,8 @@ fun Category.toMediaItem(context: Context): MediaItem {
|
|||
return MediaItem(description.build(), MediaItem.FLAG_BROWSABLE)
|
||||
}
|
||||
|
||||
fun Song.toMediaItem(
|
||||
context: Context,
|
||||
parent: MusicParent? = null,
|
||||
vararg sugar: Sugar
|
||||
): MediaItem {
|
||||
fun Song.toMediaDescription(context: Context, parent: MusicParent? = null,
|
||||
vararg sugar: Sugar): MediaDescriptionCompat {
|
||||
val mediaSessionUID =
|
||||
if (parent == null) {
|
||||
MediaSessionUID.SingleItem(uid)
|
||||
|
@ -117,17 +114,23 @@ fun Song.toMediaItem(
|
|||
MediaSessionUID.ChildItem(parent.uid, uid)
|
||||
}
|
||||
val extras = Bundle().apply { sugar.forEach { this.it(context) } }
|
||||
val description =
|
||||
MediaDescriptionCompat.Builder()
|
||||
.setMediaId(mediaSessionUID.toString())
|
||||
.setTitle(name.resolve(context))
|
||||
.setSubtitle(artists.resolveNames(context))
|
||||
.setDescription(album.name.resolve(context))
|
||||
.setIconUri(album.cover.single.mediaStoreCoverUri)
|
||||
.setMediaUri(uri)
|
||||
.setExtras(extras)
|
||||
.build()
|
||||
return MediaItem(description, MediaItem.FLAG_PLAYABLE)
|
||||
return MediaDescriptionCompat.Builder()
|
||||
.setMediaId(mediaSessionUID.toString())
|
||||
.setTitle(name.resolve(context))
|
||||
.setSubtitle(artists.resolveNames(context))
|
||||
.setDescription(album.name.resolve(context))
|
||||
.setIconUri(cover.mediaStoreCoverUri)
|
||||
.setMediaUri(uri)
|
||||
.setExtras(extras)
|
||||
.build()
|
||||
}
|
||||
|
||||
fun Song.toMediaItem(
|
||||
context: Context,
|
||||
parent: MusicParent? = null,
|
||||
vararg sugar: Sugar
|
||||
): MediaItem {
|
||||
return MediaItem(toMediaDescription(context, parent, *sugar), MediaItem.FLAG_PLAYABLE)
|
||||
}
|
||||
|
||||
fun Album.toMediaItem(
|
||||
|
|
|
@ -42,6 +42,8 @@ import org.oxycblt.auxio.music.MusicParent
|
|||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.resolveNames
|
||||
import org.oxycblt.auxio.music.service.MediaSessionUID
|
||||
import org.oxycblt.auxio.music.service.toMediaDescription
|
||||
import org.oxycblt.auxio.music.service.toMediaItem
|
||||
import org.oxycblt.auxio.playback.ActionMode
|
||||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import org.oxycblt.auxio.playback.service.MediaSessionInterface
|
||||
|
@ -304,20 +306,7 @@ private constructor(
|
|||
private fun updateQueue(queue: List<Song>) {
|
||||
val queueItems =
|
||||
queue.mapIndexed { i, song ->
|
||||
val description =
|
||||
MediaDescriptionCompat.Builder()
|
||||
// Media ID should not be the item index but rather the UID,
|
||||
// as it's used to request a song to be played from the queue.
|
||||
.setMediaId(song.uid.toString())
|
||||
.setTitle(song.name.resolve(context))
|
||||
.setSubtitle(song.artists.resolveNames(context))
|
||||
// Since we usually have to load many songs into the queue, use the
|
||||
// MediaStore URI instead of loading a bitmap.
|
||||
.setIconUri(song.album.cover.single.mediaStoreCoverUri)
|
||||
.setMediaUri(song.uri)
|
||||
.setExtras(
|
||||
Bundle().apply { putInt(MediaSessionInterface.KEY_QUEUE_POS, i) })
|
||||
.build()
|
||||
val description = song.toMediaDescription(context, null, { putInt(MediaSessionInterface.KEY_QUEUE_POS, i) })
|
||||
// Store the item index so we can then use the analogous index in the
|
||||
// playback state.
|
||||
MediaSessionCompat.QueueItem(description, i.toLong())
|
||||
|
|
|
@ -93,22 +93,11 @@ constructor(
|
|||
super.onPlayFromSearch(query, extras)
|
||||
val deviceLibrary = musicRepository.deviceLibrary ?: return
|
||||
val userLibrary = musicRepository.userLibrary ?: return
|
||||
val command = expandSearchInfoCommand(
|
||||
query.ifBlank { null },
|
||||
extras,
|
||||
deviceLibrary,
|
||||
userLibrary)
|
||||
val command =
|
||||
expandSearchInfoCommand(query.ifBlank { null }, extras, deviceLibrary, userLibrary)
|
||||
playbackManager.play(requireNotNull(command) { "Invalid playback configuration" })
|
||||
}
|
||||
|
||||
data class QueryBundle(
|
||||
val title: String?,
|
||||
val album: String?,
|
||||
val artist: String?,
|
||||
val genre: String?,
|
||||
val playlist: String?
|
||||
)
|
||||
|
||||
override fun onAddQueueItem(description: MediaDescriptionCompat) {
|
||||
super.onAddQueueItem(description)
|
||||
val deviceLibrary = musicRepository.deviceLibrary ?: return
|
||||
|
@ -125,8 +114,22 @@ constructor(
|
|||
|
||||
override fun onRemoveQueueItem(description: MediaDescriptionCompat) {
|
||||
super.onRemoveQueueItem(description)
|
||||
val at = description.extras?.getInt(KEY_QUEUE_POS) ?: return
|
||||
playbackManager.removeQueueItem(at)
|
||||
val at = description.extras?.getInt(KEY_QUEUE_POS)
|
||||
if (at != null) {
|
||||
// Direct queue item removal w/preserved extras, we can explicitly remove
|
||||
// the correct item rather than a duplicate elsewhere.
|
||||
playbackManager.removeQueueItem(at)
|
||||
return
|
||||
}
|
||||
// Non-queue item or queue item lost it's extras in transit, remove the first item
|
||||
val uid = MediaSessionUID.fromString(description.mediaId ?: return) ?: return
|
||||
val songUid = when (uid) {
|
||||
is MediaSessionUID.SingleItem -> uid.uid
|
||||
is MediaSessionUID.ChildItem -> uid.childUid
|
||||
else -> return
|
||||
}
|
||||
val firstAt = playbackManager.queue.indexOfFirst { it.uid == songUid }
|
||||
playbackManager.removeQueueItem(firstAt)
|
||||
}
|
||||
|
||||
override fun onPlay() {
|
||||
|
@ -224,26 +227,28 @@ constructor(
|
|||
val songQuery = extras.getString(MediaStore.EXTRA_MEDIA_TITLE)
|
||||
val albumQuery = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM)
|
||||
val artistQuery = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST)
|
||||
val best = deviceLibrary.songs.maxByOrNull {
|
||||
fuzzy(it.name, songQuery) + fuzzy(it.album.name, albumQuery) +
|
||||
val best =
|
||||
deviceLibrary.songs.maxByOrNull {
|
||||
fuzzy(it.name, songQuery) +
|
||||
fuzzy(it.album.name, albumQuery) +
|
||||
it.artists.maxOf { artist -> fuzzy(artist.name, artistQuery) }
|
||||
}
|
||||
}
|
||||
if (best != null) {
|
||||
return expandSongIntoCommand(best, null)
|
||||
}
|
||||
}
|
||||
|
||||
MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE -> {
|
||||
val albumQuery = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM)
|
||||
val artistQuery = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST)
|
||||
val best = deviceLibrary.albums.maxByOrNull {
|
||||
fuzzy(it.name, albumQuery) + it.artists.maxOf { artist -> fuzzy(artist.name, artistQuery) }
|
||||
}
|
||||
val best =
|
||||
deviceLibrary.albums.maxByOrNull {
|
||||
fuzzy(it.name, albumQuery) +
|
||||
it.artists.maxOf { artist -> fuzzy(artist.name, artistQuery) }
|
||||
}
|
||||
if (best != null) {
|
||||
return commandFactory.album(best, ShuffleMode.OFF)
|
||||
}
|
||||
}
|
||||
|
||||
MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE -> {
|
||||
val artistQuery = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST)
|
||||
val best = deviceLibrary.artists.maxByOrNull { fuzzy(it.name, artistQuery) }
|
||||
|
@ -251,7 +256,6 @@ constructor(
|
|||
return commandFactory.artist(best, ShuffleMode.OFF)
|
||||
}
|
||||
}
|
||||
|
||||
MediaStore.Audio.Genres.ENTRY_CONTENT_TYPE -> {
|
||||
val genreQuery = extras.getString(MediaStore.EXTRA_MEDIA_GENRE)
|
||||
val best = deviceLibrary.genres.maxByOrNull { fuzzy(it.name, genreQuery) }
|
||||
|
@ -259,7 +263,6 @@ constructor(
|
|||
return commandFactory.genre(best, ShuffleMode.OFF)
|
||||
}
|
||||
}
|
||||
|
||||
MediaStore.Audio.Playlists.ENTRY_CONTENT_TYPE -> {
|
||||
val playlistQuery = extras.getString(MediaStore.EXTRA_MEDIA_PLAYLIST)
|
||||
val best = userLibrary.playlists.maxByOrNull { fuzzy(it.name, playlistQuery) }
|
||||
|
@ -267,14 +270,19 @@ constructor(
|
|||
return commandFactory.playlist(best, ShuffleMode.OFF)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
|
||||
val bestMusic = (deviceLibrary.songs + deviceLibrary.albums + deviceLibrary.artists + deviceLibrary.genres + userLibrary.playlists)
|
||||
.maxByOrNull { fuzzy(it.name, query) }
|
||||
val bestMusic =
|
||||
(deviceLibrary.songs +
|
||||
deviceLibrary.albums +
|
||||
deviceLibrary.artists +
|
||||
deviceLibrary.genres +
|
||||
userLibrary.playlists)
|
||||
.maxByOrNull { fuzzy(it.name, query) }
|
||||
// TODO: Error out when we can't correctly resolve the query
|
||||
return bestMusic?.let { expandMusicIntoCommand(it, null) } ?: commandFactory.all(ShuffleMode.ON)
|
||||
return bestMusic?.let { expandMusicIntoCommand(it, null) }
|
||||
?: commandFactory.all(ShuffleMode.ON)
|
||||
}
|
||||
|
||||
private fun fuzzy(name: Name, query: String?): Double =
|
||||
|
|
Loading…
Reference in a new issue