Skip to content

Commit

Permalink
Fix artist items continuation (#1689)
Browse files Browse the repository at this point in the history
* add `gridContinuation` support to show all albums on `ArtistItemsScreen`

* fix artist songs continuation

* removed duplicate and unused code from `ArtistItemsContinuationPage`
  • Loading branch information
gechoto authored Dec 17, 2024
1 parent c5b2856 commit bb11093
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Checkbox
Expand Down Expand Up @@ -56,6 +57,7 @@ import com.zionhuang.music.ui.component.IconButton
import com.zionhuang.music.ui.component.LocalMenuState
import com.zionhuang.music.ui.component.YouTubeGridItem
import com.zionhuang.music.ui.component.YouTubeListItem
import com.zionhuang.music.ui.component.shimmer.GridItemPlaceHolder
import com.zionhuang.music.ui.component.shimmer.ListItemPlaceHolder
import com.zionhuang.music.ui.component.shimmer.ShimmerHost
import com.zionhuang.music.ui.menu.YouTubeAlbumMenu
Expand All @@ -80,6 +82,7 @@ fun ArtistItemsScreen(
val mediaMetadata by playerConnection.mediaMetadata.collectAsState()

val lazyListState = rememberLazyListState()
val lazyGridState = rememberLazyGridState()
val coroutineScope = rememberCoroutineScope()

val title by viewModel.title.collectAsState()
Expand Down Expand Up @@ -117,6 +120,15 @@ fun ArtistItemsScreen(
}
}

LaunchedEffect(lazyGridState) {
snapshotFlow {
lazyGridState.layoutInfo.visibleItemsInfo.any { it.key == "loading" }
}.collect { shouldLoadMore ->
if (!shouldLoadMore) return@collect
viewModel.loadMore()
}
}

if (itemsPage == null) {
ShimmerHost(
modifier = Modifier.windowInsetsPadding(LocalPlayerAwareWindowInsets.current)
Expand Down Expand Up @@ -208,6 +220,7 @@ fun ArtistItemsScreen(
}
} else {
LazyVerticalGrid(
state = lazyGridState,
columns = GridCells.Adaptive(minSize = GridThumbnailHeight + 24.dp),
contentPadding = LocalPlayerAwareWindowInsets.current.asPaddingValues()
) {
Expand Down Expand Up @@ -268,6 +281,14 @@ fun ArtistItemsScreen(
.animateItem()
)
}

if (itemsPage?.continuation != null) {
item(key = "loading") {
ShimmerHost(Modifier.animateItem()) {
GridItemPlaceHolder(fillMaxWidth = true)
}
}
}
}
}

Expand Down
26 changes: 19 additions & 7 deletions innertube/src/main/java/com/zionhuang/innertube/YouTube.kt
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ object YouTube {
ArtistItemsPage.fromMusicTwoRowItemRenderer(renderer)
}
},
continuation = null
continuation = gridRenderer.continuations?.getContinuation()
)
} else {
ArtistItemsPage(
Expand All @@ -260,12 +260,24 @@ object YouTube {

suspend fun artistItemsContinuation(continuation: String): Result<ArtistItemsContinuationPage> = runCatching {
val response = innerTube.browse(WEB_REMIX, continuation = continuation).body<BrowseResponse>()
ArtistItemsContinuationPage(
items = response.continuationContents?.musicPlaylistShelfContinuation?.contents?.mapNotNull {
ArtistItemsContinuationPage.fromMusicResponsiveListItemRenderer(it.musicResponsiveListItemRenderer)
}!!,
continuation = response.continuationContents.musicPlaylistShelfContinuation.continuations?.getContinuation()
)
val gridContinuation = response.continuationContents?.gridContinuation
if (gridContinuation != null) {
ArtistItemsContinuationPage(
items = gridContinuation.items.mapNotNull {
it.musicTwoRowItemRenderer?.let { renderer ->
ArtistItemsPage.fromMusicTwoRowItemRenderer(renderer)
}
},
continuation = gridContinuation.continuations?.getContinuation()
)
} else {
ArtistItemsContinuationPage(
items = response.continuationContents?.musicPlaylistShelfContinuation?.contents?.mapNotNull {
ArtistItemsPage.fromMusicResponsiveListItemRenderer(it.musicResponsiveListItemRenderer)
}!!,
continuation = response.continuationContents.musicPlaylistShelfContinuation.continuations?.getContinuation()
)
}
}

suspend fun playlist(playlistId: String): Result<PlaylistPage> = runCatching {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import kotlinx.serialization.Serializable
data class GridRenderer(
val header: Header?,
val items: List<Item>,
val continuations: List<Continuation>?,
) {
@Serializable
data class Header(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.zionhuang.innertube.models.response

import com.zionhuang.innertube.models.Button
import com.zionhuang.innertube.models.Continuation
import com.zionhuang.innertube.models.GridRenderer
import com.zionhuang.innertube.models.Menu
import com.zionhuang.innertube.models.MusicShelfRenderer
import com.zionhuang.innertube.models.ResponseContext
Expand Down Expand Up @@ -49,6 +50,7 @@ data class BrowseResponse(
data class ContinuationContents(
val sectionListContinuation: SectionListContinuation?,
val musicPlaylistShelfContinuation: MusicPlaylistShelfContinuation?,
val gridContinuation: GridContinuation?,
) {
@Serializable
data class SectionListContinuation(
Expand All @@ -61,6 +63,12 @@ data class BrowseResponse(
val contents: List<MusicShelfRenderer.Content>,
val continuations: List<Continuation>?,
)

@Serializable
data class GridContinuation(
val items: List<GridRenderer.Item>,
val continuations: List<Continuation>?,
)
}

@Serializable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,8 @@
package com.zionhuang.innertube.pages

import com.zionhuang.innertube.models.Album
import com.zionhuang.innertube.models.Artist
import com.zionhuang.innertube.models.MusicResponsiveListItemRenderer
import com.zionhuang.innertube.models.SongItem
import com.zionhuang.innertube.models.YTItem
import com.zionhuang.innertube.models.oddElements
import com.zionhuang.innertube.utils.parseTime

data class ArtistItemsContinuationPage(
val items: List<YTItem>,
val continuation: String?,
) {
companion object {
fun fromMusicResponsiveListItemRenderer(renderer: MusicResponsiveListItemRenderer): SongItem? {
return SongItem(
id = renderer.playlistItemData?.videoId ?: return null,
title = renderer.flexColumns.firstOrNull()
?.musicResponsiveListItemFlexColumnRenderer?.text
?.runs?.firstOrNull()?.text ?: return null,
artists = renderer.flexColumns.getOrNull(1)?.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.oddElements()?.map {
Artist(
name = it.text,
id = it.navigationEndpoint?.browseEndpoint?.browseId
)
} ?: return null,
album = renderer.flexColumns.getOrNull(2)?.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.firstOrNull()?.let {
Album(
name = it.text,
id = it.navigationEndpoint?.browseEndpoint?.browseId ?: return null
)
},
duration = renderer.fixedColumns?.firstOrNull()
?.musicResponsiveListItemFlexColumnRenderer?.text
?.runs?.firstOrNull()
?.text?.parseTime() ?: return null,
thumbnail = renderer.thumbnail?.musicThumbnailRenderer?.getThumbnailUrl() ?: return null,
explicit = renderer.badges?.find {
it.musicInlineBadgeRenderer?.icon?.iconType == "MUSIC_EXPLICIT_BADGE"
} != null,
endpoint = renderer.overlay?.musicItemThumbnailOverlayRenderer?.content?.musicPlayButtonRenderer?.playNavigationEndpoint?.watchEndpoint
)
}
}
}
)

0 comments on commit bb11093

Please sign in to comment.