diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/Database.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/Database.kt index 2b6c2ce..c10ace9 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/Database.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/Database.kt @@ -284,7 +284,7 @@ interface Database { fun artistSongs(artistId: String): Flow> @Query("SELECT * FROM Format WHERE songId = :songId") - fun format(songId: String): Flow + fun format(songId: String): Flow @Transaction @Query("SELECT * FROM Song JOIN Format ON id = songId WHERE contentLength IS NOT NULL AND totalPlayTimeMs > 0 ORDER BY Song.ROWID DESC") diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt index 2e45781..3153f98 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt @@ -666,9 +666,7 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene } when (val status = body.playabilityStatus?.status) { - "OK" -> body.streamingData?.adaptiveFormats?.findLast { format -> - format.itag == 251 || format.itag == 140 - }?.let { format -> + "OK" -> body.streamingData?.highestQualityFormat?.let { format -> val mediaItem = runBlocking(Dispatchers.Main) { player.findNextMediaItemById(videoId) } @@ -694,8 +692,7 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene itag = format.itag, mimeType = format.mimeType, bitrate = format.bitrate, - loudnessDb = body.playerConfig?.audioConfig?.loudnessDb?.toFloat() - ?.plus(7), + loudnessDb = body.playerConfig?.audioConfig?.normalizedLoudnessDb, contentLength = format.contentLength, lastModified = format.lastModified ) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/StatsForNerds.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/StatsForNerds.kt index fb1ca11..3f62d48 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/StatsForNerds.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/StatsForNerds.kt @@ -5,7 +5,6 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -16,7 +15,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.BasicText import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -35,7 +34,6 @@ import it.vfsfitvnm.innertube.requests.player import it.vfsfitvnm.vimusic.Database import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder import it.vfsfitvnm.vimusic.models.Format -import it.vfsfitvnm.vimusic.query import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.onOverlay import it.vfsfitvnm.vimusic.ui.styling.overlay @@ -44,8 +42,10 @@ import it.vfsfitvnm.vimusic.utils.color import it.vfsfitvnm.vimusic.utils.medium import kotlin.math.roundToInt import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext @Composable fun StatsForNerds( @@ -67,9 +67,36 @@ fun StatsForNerds( mutableStateOf(binder.cache.getCachedBytes(mediaId, 0, -1)) } - val format by remember(mediaId) { - Database.format(mediaId).distinctUntilChanged() - }.collectAsState(initial = null, context = Dispatchers.IO) + var format by remember { + mutableStateOf(null) + } + + LaunchedEffect(mediaId) { + Database.format(mediaId).distinctUntilChanged().collectLatest { + if (it?.itag == null) { + withContext(Dispatchers.IO) { + delay(3000) + Innertube.player(PlayerBody(videoId = mediaId))?.onSuccess { response -> + response.streamingData?.highestQualityFormat?.let { format -> + Database.insert( + Format( + songId = mediaId, + itag = format.itag, + mimeType = format.mimeType, + bitrate = format.bitrate, + loudnessDb = response.playerConfig?.audioConfig?.normalizedLoudnessDb, + contentLength = format.contentLength, + lastModified = format.lastModified + ) + ) + } + } + } + } else { + format = it + } + } + } var volume by remember { mutableStateOf(binder.player.volume) @@ -194,47 +221,6 @@ fun StatsForNerds( ) } } - - if (format != null && format?.itag == null) { - BasicText( - text = "FETCH MISSING DATA", - style = typography.xxs.medium.color(colorPalette.onOverlay), - modifier = Modifier - .clickable( - onClick = { - query { - runBlocking(Dispatchers.IO) { - Innertube - .player(PlayerBody(videoId = mediaId)) - ?.map { response -> - response.streamingData?.adaptiveFormats - ?.findLast { format -> - format.itag == 251 || format.itag == 140 - } - ?.let { format -> - Format( - songId = mediaId, - itag = format.itag, - mimeType = format.mimeType, - bitrate = format.bitrate, - loudnessDb = response.playerConfig?.audioConfig?.loudnessDb - ?.toFloat() - ?.plus(7), - contentLength = format.contentLength, - lastModified = format.lastModified - ) - } - } - } - ?.getOrNull() - ?.let(Database::insert) - } - } - ) - .padding(horizontal = 16.dp, vertical = 8.dp) - .align(Alignment.BottomEnd) - ) - } } } } diff --git a/innertube/src/main/kotlin/it/vfsfitvnm/innertube/models/PlayerResponse.kt b/innertube/src/main/kotlin/it/vfsfitvnm/innertube/models/PlayerResponse.kt index e768cdc..d913698 100644 --- a/innertube/src/main/kotlin/it/vfsfitvnm/innertube/models/PlayerResponse.kt +++ b/innertube/src/main/kotlin/it/vfsfitvnm/innertube/models/PlayerResponse.kt @@ -20,14 +20,21 @@ data class PlayerResponse( ) { @Serializable data class AudioConfig( - val loudnessDb: Double? - ) + private val loudnessDb: Double? + ) { + // For music clients only + val normalizedLoudnessDb: Float? + get() = loudnessDb?.plus(7)?.toFloat() + } } @Serializable data class StreamingData( val adaptiveFormats: List? ) { + val highestQualityFormat: AdaptiveFormat? + get() = adaptiveFormats?.findLast { it.itag == 251 || it.itag == 140 } + @Serializable data class AdaptiveFormat( val itag: Int,