Fix incorrect thumbnail url and song metadata inference
This commit is contained in:
@@ -367,7 +367,7 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
lastBitmap = Coil.imageLoader(applicationContext).execute(
|
||||
ImageRequest.Builder(applicationContext)
|
||||
.data("${mediaMetadata.artworkUri}-w${notificationThumbnailSize}-h${notificationThumbnailSize}")
|
||||
.data(mediaMetadata.artworkUri.thumbnail(notificationThumbnailSize))
|
||||
.build()
|
||||
).drawable?.let {
|
||||
lastArtworkUri = mediaMetadata.artworkUri
|
||||
|
||||
@@ -13,7 +13,6 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
@@ -102,7 +101,7 @@ fun PlayerView(
|
||||
}
|
||||
) {
|
||||
AsyncImage(
|
||||
model = "${player.mediaMetadata.artworkUri}-w$smallThumbnailSize-h$smallThumbnailSize",
|
||||
model = player.mediaMetadata.artworkUri.thumbnail(smallThumbnailSize),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
@@ -220,11 +219,11 @@ fun PlayerView(
|
||||
.align(Alignment.CenterHorizontally)
|
||||
) {
|
||||
val artworkUri = remember(it) {
|
||||
player.mediaController.getMediaItemAt(it).mediaMetadata.artworkUri
|
||||
player.mediaController.getMediaItemAt(it).mediaMetadata.artworkUri.thumbnail(thumbnailSizePx)
|
||||
}
|
||||
|
||||
AsyncImage(
|
||||
model = "$artworkUri-w$thumbnailSizePx-h$thumbnailSizePx",
|
||||
model = artworkUri,
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
|
||||
@@ -26,6 +26,7 @@ import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
||||
import it.vfsfitvnm.vimusic.utils.color
|
||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
|
||||
@@ -54,7 +55,7 @@ fun PlaylistPreviewItem(
|
||||
) {
|
||||
if (thumbnails.toSet().size == 1) {
|
||||
AsyncImage(
|
||||
model = "${thumbnails.first()}-w${thumbnailSizePx * 2}-h${thumbnailSizePx * 2}",
|
||||
model = thumbnails.first().thumbnail(thumbnailSizePx * 2),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
@@ -68,7 +69,7 @@ fun PlaylistPreviewItem(
|
||||
Alignment.BottomEnd
|
||||
).forEachIndexed { index, alignment ->
|
||||
AsyncImage(
|
||||
model = "${thumbnails.getOrNull(index)}-w$thumbnailSizePx-h$thumbnailSizePx",
|
||||
model = thumbnails.getOrNull(index).thumbnail(thumbnailSizePx),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
|
||||
@@ -32,6 +32,7 @@ import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
||||
import it.vfsfitvnm.vimusic.utils.secondary
|
||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
||||
|
||||
|
||||
@ExperimentalAnimationApi
|
||||
@@ -49,7 +50,7 @@ fun SongItem(
|
||||
SongItem(
|
||||
thumbnailModel = ImageRequest.Builder(LocalContext.current)
|
||||
.diskCacheKey(mediaItem.mediaId)
|
||||
.data("${mediaItem.mediaMetadata.artworkUri}-w$thumbnailSize-h$thumbnailSize")
|
||||
.data(mediaItem.mediaMetadata.artworkUri.thumbnail(thumbnailSize))
|
||||
.build(),
|
||||
title = mediaItem.mediaMetadata.title!!.toString(),
|
||||
authors = mediaItem.mediaMetadata.artist.toString(),
|
||||
@@ -75,7 +76,7 @@ fun SongItem(
|
||||
onThumbnailContent: (@Composable BoxScope.() -> Unit)? = null,
|
||||
) {
|
||||
SongItem(
|
||||
thumbnailModel = "${song.song.thumbnailUrl}-w$thumbnailSize-h$thumbnailSize",
|
||||
thumbnailModel = song.song.thumbnailUrl?.thumbnail(thumbnailSize),
|
||||
title = song.song.title,
|
||||
authors = song.authors?.joinToString("") { it.text } ?: "",
|
||||
durationText = song.song.durationText,
|
||||
|
||||
@@ -2,6 +2,7 @@ package it.vfsfitvnm.vimusic.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.media3.common.MediaItem
|
||||
@@ -171,4 +172,16 @@ fun YouTube.PlaylistOrAlbum.Item.toMediaItem(
|
||||
)
|
||||
.setMediaId(info.endpoint?.videoId ?: return null)
|
||||
.build()
|
||||
}
|
||||
|
||||
fun String?.thumbnail(size: Int): String? {
|
||||
return when {
|
||||
this?.startsWith("https://lh3.googleusercontent.com") == true -> "$this-w$size-h$size"
|
||||
this?.startsWith("https://yt3.ggpht.com") == true -> "$this-s$size"
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
fun Uri?.thumbnail(size: Int): Uri? {
|
||||
return toString().thumbnail(size)?.toUri()
|
||||
}
|
||||
@@ -159,18 +159,32 @@ object YouTube {
|
||||
override fun from(content: MusicShelfRenderer.Content): Song {
|
||||
val (mainRuns, otherRuns) = content.runs
|
||||
|
||||
// Possible configurations:
|
||||
// "song" • author(s) • album • duration
|
||||
// "song" • author(s) • duration
|
||||
// author(s) • album • duration
|
||||
// author(s) • duration
|
||||
|
||||
val album: Info<NavigationEndpoint.Endpoint.Browse>? = otherRuns
|
||||
.getOrNull(otherRuns.lastIndex - 1)
|
||||
?.firstOrNull()
|
||||
?.takeIf { run ->
|
||||
run
|
||||
.navigationEndpoint
|
||||
?.browseEndpoint
|
||||
?.type == "MUSIC_PAGE_TYPE_ALBUM"
|
||||
}
|
||||
?.let(Info.Companion::from)
|
||||
|
||||
return Song(
|
||||
info = Info.from(mainRuns.first()),
|
||||
authors = otherRuns
|
||||
.getOrNull(otherRuns.lastIndex - 2)
|
||||
.getOrNull(otherRuns.lastIndex - if (album == null) 1 else 2)
|
||||
?.map(Info.Companion::from)
|
||||
?: emptyList(),
|
||||
album = otherRuns
|
||||
.getOrNull(otherRuns.lastIndex - 1)
|
||||
?.firstOrNull()
|
||||
?.let(Info.Companion::from),
|
||||
album = album,
|
||||
durationText = otherRuns
|
||||
.getOrNull(otherRuns.lastIndex)
|
||||
.lastOrNull()
|
||||
?.firstOrNull()?.text,
|
||||
thumbnail = content
|
||||
.thumbnail
|
||||
@@ -603,8 +617,13 @@ object YouTube {
|
||||
thumbnail = renderer
|
||||
.thumbnail
|
||||
.thumbnails
|
||||
.getOrNull(0),
|
||||
durationText = renderer.lengthText.text
|
||||
.also {
|
||||
println(it)
|
||||
}
|
||||
.firstOrNull(),
|
||||
durationText = renderer
|
||||
.lengthText
|
||||
.text
|
||||
)
|
||||
},
|
||||
lyrics = NextResult.Lyrics(
|
||||
|
||||
@@ -56,10 +56,8 @@ data class NavigationEndpoint(
|
||||
val endpoint: Endpoint?
|
||||
get() = watchEndpoint ?: browseEndpoint ?: watchPlaylistEndpoint ?: searchEndpoint
|
||||
|
||||
|
||||
@Serializable
|
||||
sealed class Endpoint {
|
||||
|
||||
@Serializable
|
||||
data class Watch(
|
||||
val params: String? = null,
|
||||
@@ -69,6 +67,10 @@ data class NavigationEndpoint(
|
||||
val playlistSetVideoId: String? = null,
|
||||
val watchEndpointMusicSupportedConfigs: WatchEndpointMusicSupportedConfigs? = null,
|
||||
) : Endpoint() {
|
||||
val type: String?
|
||||
get() = watchEndpointMusicSupportedConfigs
|
||||
?.watchEndpointMusicConfig
|
||||
?.musicVideoType
|
||||
|
||||
@Serializable
|
||||
data class WatchEndpointMusicSupportedConfigs(
|
||||
@@ -82,7 +84,6 @@ data class NavigationEndpoint(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Serializable
|
||||
data class WatchPlaylist(
|
||||
val params: String?,
|
||||
@@ -96,6 +97,10 @@ data class NavigationEndpoint(
|
||||
val browseId: String,
|
||||
val browseEndpointContextSupportedConfigs: BrowseEndpointContextSupportedConfigs?,
|
||||
) : Endpoint() {
|
||||
val type: String?
|
||||
get() = browseEndpointContextSupportedConfigs
|
||||
?.browseEndpointContextMusicConfig
|
||||
?.pageType
|
||||
|
||||
@Serializable
|
||||
data class BrowseEndpointContextSupportedConfigs(
|
||||
|
||||
@@ -16,7 +16,11 @@ data class Runs(
|
||||
run.text == " • " -> listOf(index - 1, index + 1)
|
||||
else -> emptyList()
|
||||
}
|
||||
}.windowed(size = 2, step = 2) { (from, to) -> runs.slice(from..to) }
|
||||
}.windowed(size = 2, step = 2) { (from, to) -> runs.slice(from..to) }.let {
|
||||
it.ifEmpty {
|
||||
listOf(runs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
||||
@@ -45,3 +45,4 @@ data class ThumbnailRenderer(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user