Skip to content

Commit

Permalink
feat(playlist-parser): Enhance playlist data handling and add setVide…
Browse files Browse the repository at this point in the history
…oId support
  • Loading branch information
maxrave-dev committed Feb 8, 2025
1 parent 000c080 commit cdea1ab
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 206 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -428,11 +428,12 @@ fun parsePodcastData(
?: "",
durationString =
content.musicMultiRowListItemRenderer
?.subtitle
?.playbackProgress
?.musicPlaybackProgressRenderer
?.durationText
?.runs
?.getOrNull(
1,
)?.text ?: "",
?.lastOrNull()
?.text ?: "",
videoId =
content.musicMultiRowListItemRenderer
?.onTap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.maxrave.kotlinytmusicscraper.pages.BrowseResult
import com.maxrave.kotlinytmusicscraper.pages.NextPage
import com.maxrave.kotlinytmusicscraper.pages.PlaylistPage
import com.maxrave.kotlinytmusicscraper.pages.SearchPage
import com.maxrave.kotlinytmusicscraper.parser.getPlaylistContinuation
import com.maxrave.lyricsproviders.LyricsClient
import com.maxrave.lyricsproviders.models.response.MusixmatchCredential
import com.maxrave.lyricsproviders.models.response.MusixmatchTranslationLyricsResponse
Expand Down Expand Up @@ -1468,69 +1469,13 @@ class MainRepository(
?.header
?.musicResponsiveHeaderRenderer
Log.d("Header", "header: $header")
var continueParam =
result.contents
?.singleColumnBrowseResultsRenderer
?.tabs
?.get(
0,
)?.tabRenderer
?.content
?.sectionListRenderer
?.contents
?.get(
0,
)?.musicPlaylistShelfRenderer
?.continuations
?.get(
0,
)?.nextContinuationData
?.continuation
?: result.contents
?.twoColumnBrowseResultsRenderer
?.secondaryContents
?.sectionListRenderer
?.contents
?.firstOrNull()
?.musicPlaylistShelfRenderer
?.continuations
?.firstOrNull()
?.nextContinuationData
?.continuation
var count = 0
val finalContinueParam =
result.getPlaylistContinuation()
Log.d("Repository", "playlist data: ${listContent.size}")
Log.d("Repository", "continueParam: $continueParam")
Log.d("Repository", "continueParam: $finalContinueParam")
// else {
// var listTrack = playlistBrowse.tracks.toMutableList()
while (count < 1 && continueParam != null) {
youTube
.customQuery(
browseId = "",
continuation = continueParam,
setLogin = true,
).onSuccess { values ->
Log.d("Continue", "continue: $continueParam")
val dataMore: List<MusicShelfRenderer.Content>? =
values.continuationContents?.musicPlaylistShelfContinuation?.contents
if (dataMore != null) {
listContent.addAll(dataMore)
}
continueParam =
values.continuationContents
?.musicPlaylistShelfContinuation
?.continuations
?.get(
0,
)?.nextContinuationData
?.continuation
count++
}.onFailure {
Log.e("Continue", "Error: ${it.message}")
count = 3
}
}
Log.d("Repository", "playlist final data: ${listContent.size}")
val finalContinueParam = continueParam
if (finalContinueParam != null) {
parsePlaylistData(header, listContent, radioId, context)?.let { playlist ->
emit(
Expand Down Expand Up @@ -1622,47 +1567,7 @@ class MainRepository(
?.musicResponsiveHeaderRenderer
Log.d("getPlaylistData", "header: $header")
var continueParam =
result.contents
?.singleColumnBrowseResultsRenderer
?.tabs
?.get(
0,
)?.tabRenderer
?.content
?.sectionListRenderer
?.contents
?.get(
0,
)?.musicPlaylistShelfRenderer
?.continuations
?.get(
0,
)?.nextContinuationData
?.continuation
?: result.contents
?.twoColumnBrowseResultsRenderer
?.secondaryContents
?.sectionListRenderer
?.contents
?.firstOrNull()
?.musicPlaylistShelfRenderer
?.continuations
?.firstOrNull()
?.nextContinuationData
?.continuation
?: result.contents
?.twoColumnBrowseResultsRenderer
?.secondaryContents
?.sectionListRenderer
?.contents
?.firstOrNull()
?.musicPlaylistShelfRenderer
?.contents
?.lastOrNull()
?.continuationItemRenderer
?.continuationEndpoint
?.continuationCommand
?.token
result.getPlaylistContinuation()
var count = 0
Log.d("getPlaylistData", "playlist data: ${listContent.size}")
Log.d("getPlaylistData", "continueParam: $continueParam")
Expand Down Expand Up @@ -1694,15 +1599,7 @@ class MainRepository(
} ?: emptyList()
listContent.addAll(dataMore.map { it.toTrack() })
continueParam =
values.onResponseReceivedActions
?.firstOrNull()
?.appendContinuationItemsAction
?.continuationItems
?.lastOrNull()
?.continuationItemRenderer
?.continuationEndpoint
?.continuationCommand
?.token
values.getPlaylistContinuation()
count++
}.onFailure {
Log.e("getPlaylistData", "Error: ${it.message}")
Expand Down Expand Up @@ -2948,7 +2845,7 @@ class MainRepository(
youTube
.customQuery(browseId = id, setLogin = true)
.onSuccess { result ->
val listContent: ArrayList<MusicShelfRenderer.Content> = arrayListOf()
val listContent: ArrayList<SongItem> = arrayListOf()
val data: List<MusicShelfRenderer.Content>? =
result.contents
?.singleColumnBrowseResultsRenderer
Expand All @@ -2963,29 +2860,8 @@ class MainRepository(
0,
)?.musicPlaylistShelfRenderer
?.contents
if (data != null) {
Log.d("Data", "data: $data")
Log.d("Data", "data size: ${data.size}")
listContent.addAll(data)
}
var continueParam =
result.contents
?.singleColumnBrowseResultsRenderer
?.tabs
?.get(
0,
)?.tabRenderer
?.content
?.sectionListRenderer
?.contents
?.get(
0,
)?.musicPlaylistShelfRenderer
?.continuations
?.get(
0,
)?.nextContinuationData
?.continuation
result.getPlaylistContinuation()
var count = 0
Log.d("Repository", "playlist data: ${listContent.size}")
Log.d("Repository", "continueParam: $continueParam")
Expand All @@ -2996,20 +2872,26 @@ class MainRepository(
continuation = continueParam,
setLogin = true,
).onSuccess { values ->
Log.d("Continue", "continue: $continueParam")
val dataMore: List<MusicShelfRenderer.Content>? =
values.continuationContents?.musicPlaylistShelfContinuation?.contents
if (dataMore != null) {
listContent.addAll(dataMore)
}
Log.d("getPlaylistData", "continue: $continueParam")
Log.d(
"getPlaylistData",
"values: ${values.onResponseReceivedActions}",
)
val dataMore: List<SongItem> =
values.onResponseReceivedActions
?.firstOrNull()
?.appendContinuationItemsAction
?.continuationItems
?.apply {
Log.w("getPlaylistData", "dataMore: ${this.size}")
}?.mapNotNull {
NextPage.fromMusicResponsiveListItemRenderer(
it.musicResponsiveListItemRenderer ?: return@mapNotNull null,
)
} ?: emptyList()
listContent.addAll(dataMore)
continueParam =
values.continuationContents
?.musicPlaylistShelfContinuation
?.continuations
?.get(
0,
)?.nextContinuationData
?.continuation
values.getPlaylistContinuation()
count++
}.onFailure {
Log.e("Continue", "Error: ${it.message}")
Expand All @@ -3018,11 +2900,19 @@ class MainRepository(
}
}
Log.d("Repository", "playlist final data: ${listContent.size}")
parseSetVideoId(youtubePlaylistId, listContent).let { playlist ->
Log.d("Repository", "playlist final data setVideoId: $playlist")
parseSetVideoId(youtubePlaylistId, data ?: emptyList()).let { playlist ->
playlist.forEach { item ->
insertSetVideoId(item)
}
listContent.forEach { item ->
insertSetVideoId(
SetVideoIdEntity(
videoId = item.id,
setVideoId = item.setVideoId,
youtubePlaylistId = youtubePlaylistId,
),
)
}
emit(playlist)
}
}.onFailure { e ->
Expand All @@ -3032,61 +2922,6 @@ class MainRepository(
}
}.flowOn(Dispatchers.IO)

suspend fun createYouTubePlaylist(playlist: LocalPlaylistEntity): Flow<String?> =
flow {
runCatching {
youTube
.createPlaylist(playlist.title, playlist.tracks)
.onSuccess {
emit(it.playlistId)
}.onFailure {
it.printStackTrace()
emit(null)
}
}
}

suspend fun editYouTubePlaylist(
title: String,
youtubePlaylistId: String,
): Flow<Int> =
flow {
runCatching {
youTube
.editPlaylist(youtubePlaylistId, title)
.onSuccess { response ->
emit(response)
}.onFailure {
it.printStackTrace()
emit(0)
}
}
}

suspend fun removeYouTubePlaylistItem(
youtubePlaylistId: String,
videoId: String,
) = flow {
runCatching {
getSetVideoId(videoId).collect { setVideoId ->
if (setVideoId?.setVideoId != null) {
youTube
.removeItemYouTubePlaylist(
youtubePlaylistId,
videoId,
setVideoId.setVideoId,
).onSuccess {
emit(it)
}.onFailure {
emit(0)
}
} else {
emit(0)
}
}
}
}

suspend fun addYouTubePlaylistItem(
youtubePlaylistId: String,
videoId: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,26 @@ data class MusicShelfRenderer(
data class MusicMultiRowListItemRenderer(
val description: Description?,
val subtitle: Subtitle?,
val playbackProgress: PlaybackProgress?,
val title: Title?,
val thumbnail: Thumbnail?,
val onTap: OnTap?,
) {
@Serializable
data class PlaybackProgress(
val musicPlaybackProgressRenderer: MusicPlaybackProgressRenderer?,
) {
@Serializable
data class MusicPlaybackProgressRenderer(
val durationText: DurationText?,
) {
@Serializable
data class DurationText(
val runs: List<Run>?,
)
}
}

@Serializable
data class Description(
val runs: List<Run>?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ data class SongItem(
val thumbnails: Thumbnails? = null,
val badges: List<SongBadges>? = null,
val likeStatus: LikeStatus = LikeStatus.INDIFFERENT,
val setVideoId: String? = null,
) : YTItem() {
override val shareLink: String
get() = "https://music.youtube.com/watch?v=$id"
Expand All @@ -58,6 +59,7 @@ data class VideoItem(
val duration: Int? = null,
val view: String? = null,
val likeStatus: LikeStatus = LikeStatus.INDIFFERENT,
val setVideoId: String? = null,
) : YTItem() {
override val shareLink: String
get() = "https://music.youtube.com/watch?v=$id"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,20 @@ object NextPage {
?.text
?.runs
?.firstOrNull()
val setVideoId =
renderer.menu
?.menuRenderer
?.items
?.find { it.menuServiceItemRenderer?.icon?.iconType == "REMOVE_FROM_PLAYLIST" }
?.menuServiceItemRenderer
?.serviceEndpoint
?.playlistEditEndpoint
?.actions
?.firstOrNull()
?.setVideoId
return SongItem(
id = videoId,
setVideoId = setVideoId,
title =
renderer.flexColumns
.firstOrNull()
Expand Down
Loading

0 comments on commit cdea1ab

Please sign in to comment.