Initial commit
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class BrowseResponse(
|
||||
val contents: Contents,
|
||||
val header: Header?
|
||||
) {
|
||||
@Serializable
|
||||
data class Contents(
|
||||
val singleColumnBrowseResultsRenderer: Tabs?,
|
||||
val sectionListRenderer: SectionListRenderer?,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Header(
|
||||
val musicImmersiveHeaderRenderer: MusicImmersiveHeaderRenderer?,
|
||||
val musicDetailHeaderRenderer: MusicDetailHeaderRenderer?,
|
||||
) {
|
||||
@Serializable
|
||||
data class MusicDetailHeaderRenderer(
|
||||
val title: Runs,
|
||||
val subtitle: Runs,
|
||||
val secondSubtitle: Runs,
|
||||
val thumbnail: ThumbnailRenderer,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class MusicImmersiveHeaderRenderer(
|
||||
val description: Runs?,
|
||||
val playButton: PlayButton?,
|
||||
val startRadioButton: StartRadioButton?,
|
||||
val thumbnail: ThumbnailRenderer?,
|
||||
val title: Runs
|
||||
) {
|
||||
@Serializable
|
||||
data class PlayButton(
|
||||
val buttonRenderer: ButtonRenderer
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StartRadioButton(
|
||||
val buttonRenderer: ButtonRenderer
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
||||
@Serializable
|
||||
data class ButtonRenderer(
|
||||
val navigationEndpoint: NavigationEndpoint
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonNames
|
||||
|
||||
@Serializable
|
||||
data class Continuation(
|
||||
@JsonNames("nextContinuationData", "nextRadioContinuationData")
|
||||
val nextRadioContinuationData: Data
|
||||
) {
|
||||
@Serializable
|
||||
data class Data(
|
||||
val continuation: String
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ContinuationResponse(
|
||||
val continuationContents: ContinuationContents,
|
||||
) {
|
||||
@Serializable
|
||||
data class ContinuationContents(
|
||||
val musicShelfContinuation: MusicShelfRenderer
|
||||
) {
|
||||
// @Serializable
|
||||
// data class MusicShelfContinuation(
|
||||
// val continuations: List<Continuation>?,
|
||||
// val contents: List<MusicShelfRenderer.Content>
|
||||
// )
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GetQueueResponse(
|
||||
val queueDatas: List<QueueData>?,
|
||||
) {
|
||||
@Serializable
|
||||
data class QueueData(
|
||||
val content: NextResponse.MusicQueueRenderer.Content.PlaylistPanelRenderer.Content?
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GetSearchSuggestionsResponse(
|
||||
val contents: List<Content>?
|
||||
) {
|
||||
@Serializable
|
||||
data class Content(
|
||||
val searchSuggestionsSectionRenderer: SearchSuggestionsSectionRenderer
|
||||
) {
|
||||
@Serializable
|
||||
data class SearchSuggestionsSectionRenderer(
|
||||
val contents: List<Content>
|
||||
) {
|
||||
@Serializable
|
||||
data class Content(
|
||||
val searchSuggestionRenderer: SearchSuggestionRenderer
|
||||
) {
|
||||
@Serializable
|
||||
data class SearchSuggestionRenderer(
|
||||
val navigationEndpoint: NavigationEndpoint,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class MusicCarouselShelfRenderer(
|
||||
val header: Header,
|
||||
val contents: List<Content>,
|
||||
) {
|
||||
@Serializable
|
||||
data class Content(
|
||||
val musicTwoRowItemRenderer: MusicTwoRowItemRenderer?,
|
||||
val musicNavigationButtonRenderer: MusicNavigationButtonRenderer?
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Header(
|
||||
val musicTwoRowItemRenderer: MusicTwoRowItemRenderer?,
|
||||
val musicResponsiveListItemRenderer: MusicResponsiveListItemRenderer?,
|
||||
val musicCarouselShelfBasicHeaderRenderer: MusicCarouselShelfBasicHeaderRenderer?
|
||||
) {
|
||||
@Serializable
|
||||
data class MusicCarouselShelfBasicHeaderRenderer(
|
||||
val moreContentButton: MoreContentButton?,
|
||||
val title: Runs,
|
||||
) {
|
||||
@Serializable
|
||||
data class MoreContentButton(
|
||||
val buttonRenderer: ButtonRenderer
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class MusicNavigationButtonRenderer(
|
||||
val buttonText: Runs,
|
||||
val solid: Solid?,
|
||||
val clickCommand: ClickCommand,
|
||||
) {
|
||||
@Serializable
|
||||
data class Solid(
|
||||
val leftStripeColor: Long
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ClickCommand(
|
||||
val clickTrackingParams: String,
|
||||
val browseEndpoint: NavigationEndpoint.Endpoint.Browse
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonNames
|
||||
|
||||
@Serializable
|
||||
data class MusicResponsiveListItemRenderer(
|
||||
val fixedColumns: List<FlexColumn>?,
|
||||
val flexColumns: List<FlexColumn>,
|
||||
val thumbnail: ThumbnailRenderer?,
|
||||
val navigationEndpoint: NavigationEndpoint?,
|
||||
) {
|
||||
@Serializable
|
||||
data class FlexColumn(
|
||||
@JsonNames("musicResponsiveListItemFixedColumnRenderer")
|
||||
val musicResponsiveListItemFlexColumnRenderer: MusicResponsiveListItemFlexColumnRenderer
|
||||
) {
|
||||
@Serializable
|
||||
data class MusicResponsiveListItemFlexColumnRenderer(
|
||||
val text: Runs?
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class MusicShelfRenderer(
|
||||
val bottomEndpoint: NavigationEndpoint?,
|
||||
val contents: List<Content>,
|
||||
val continuations: List<Continuation>?,
|
||||
val title: Runs?
|
||||
) {
|
||||
@Serializable
|
||||
data class Content(
|
||||
val musicResponsiveListItemRenderer: MusicResponsiveListItemRenderer,
|
||||
) {
|
||||
val runs: Pair<List<Runs.Run>, List<List<Runs.Run>>>
|
||||
get() = (musicResponsiveListItemRenderer.flexColumns.first().musicResponsiveListItemFlexColumnRenderer.text?.runs ?: emptyList()) to
|
||||
(musicResponsiveListItemRenderer.flexColumns.last().musicResponsiveListItemFlexColumnRenderer.text?.splitBySeparator() ?: emptyList())
|
||||
|
||||
val thumbnail: ThumbnailRenderer.MusicThumbnailRenderer.Thumbnail.Thumbnail
|
||||
get() = musicResponsiveListItemRenderer.thumbnail!!.musicThumbnailRenderer.thumbnail.thumbnails.first()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class MusicTwoRowItemRenderer(
|
||||
val navigationEndpoint: NavigationEndpoint,
|
||||
val thumbnailRenderer: ThumbnailRenderer,
|
||||
val title: Runs,
|
||||
val subtitle: Runs,
|
||||
)
|
||||
@@ -0,0 +1,200 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* watchPlaylistEndpoint: params, playlistId
|
||||
* watchEndpoint: params, playlistId, videoId, index
|
||||
* browseEndpoint: params, browseId
|
||||
* searchEndpoint: params, query
|
||||
*/
|
||||
//@Serializable
|
||||
//data class NavigationEndpoint(
|
||||
// @JsonNames("watchEndpoint", "watchPlaylistEndpoint", "navigationEndpoint", "browseEndpoint", "searchEndpoint")
|
||||
// val endpoint: Endpoint
|
||||
//) {
|
||||
// @Serializable
|
||||
// data class Endpoint(
|
||||
// val params: String?,
|
||||
// val playlistId: String?,
|
||||
// val videoId: String?,
|
||||
// val index: Int?,
|
||||
// val browseId: String?,
|
||||
// val query: String?,
|
||||
// val watchEndpointMusicSupportedConfigs: WatchEndpointMusicSupportedConfigs?,
|
||||
// val browseEndpointContextSupportedConfigs: BrowseEndpointContextSupportedConfigs?,
|
||||
// ) {
|
||||
// @Serializable
|
||||
// data class WatchEndpointMusicSupportedConfigs(
|
||||
// val watchEndpointMusicConfig: WatchEndpointMusicConfig
|
||||
// ) {
|
||||
// @Serializable
|
||||
// data class WatchEndpointMusicConfig(
|
||||
// val musicVideoType: String
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// @Serializable
|
||||
// data class BrowseEndpointContextSupportedConfigs(
|
||||
// val browseEndpointContextMusicConfig: BrowseEndpointContextMusicConfig
|
||||
// ) {
|
||||
// @Serializable
|
||||
// data class BrowseEndpointContextMusicConfig(
|
||||
// val pageType: String
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@Serializable
|
||||
data class NavigationEndpoint(
|
||||
val watchEndpoint: Endpoint.Watch?,
|
||||
val watchPlaylistEndpoint: Endpoint.WatchPlaylist?,
|
||||
val browseEndpoint: Endpoint.Browse?,
|
||||
val searchEndpoint: Endpoint.Search?,
|
||||
) {
|
||||
val endpoint: Endpoint?
|
||||
get() = watchEndpoint ?: browseEndpoint ?: watchPlaylistEndpoint ?: searchEndpoint
|
||||
|
||||
|
||||
@Serializable
|
||||
sealed class Endpoint {
|
||||
|
||||
@Serializable
|
||||
data class Watch(
|
||||
val params: String? = null,
|
||||
val playlistId: String? = null,
|
||||
val videoId: String,
|
||||
val index: Int? = null,
|
||||
val playlistSetVideoId: String? = null,
|
||||
val watchEndpointMusicSupportedConfigs: WatchEndpointMusicSupportedConfigs? = null,
|
||||
) : Endpoint() {
|
||||
|
||||
@Serializable
|
||||
data class WatchEndpointMusicSupportedConfigs(
|
||||
val watchEndpointMusicConfig: WatchEndpointMusicConfig
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class WatchEndpointMusicConfig(
|
||||
val musicVideoType: String
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Serializable
|
||||
data class WatchPlaylist(
|
||||
val params: String?,
|
||||
val playlistId: String,
|
||||
) : Endpoint()
|
||||
|
||||
|
||||
@Serializable
|
||||
data class Browse(
|
||||
val params: String?,
|
||||
val browseId: String,
|
||||
val browseEndpointContextSupportedConfigs: BrowseEndpointContextSupportedConfigs?,
|
||||
) : Endpoint() {
|
||||
|
||||
@Serializable
|
||||
data class BrowseEndpointContextSupportedConfigs(
|
||||
val browseEndpointContextMusicConfig: BrowseEndpointContextMusicConfig
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class BrowseEndpointContextMusicConfig(
|
||||
val pageType: String
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Serializable
|
||||
data class Search(
|
||||
val params: String?,
|
||||
val query: String,
|
||||
) : Endpoint()
|
||||
}
|
||||
}
|
||||
|
||||
//@Serializable(with = NavigationEndpoint.Serializer::class)
|
||||
//sealed class NavigationEndpoint {
|
||||
// @Serializable
|
||||
// data class Watch(
|
||||
// val watchEndpoint: Data
|
||||
// ) : NavigationEndpoint() {
|
||||
// @Serializable
|
||||
// data class Data(
|
||||
// val params: String?,
|
||||
// val playlistId: String,
|
||||
// val videoId: String,
|
||||
//// val index: Int?
|
||||
// val watchEndpointMusicSupportedConfigs: WatchEndpointMusicSupportedConfigs,
|
||||
// )
|
||||
//
|
||||
// @Serializable
|
||||
// data class WatchEndpointMusicSupportedConfigs(
|
||||
// val watchEndpointMusicConfig: WatchEndpointMusicConfig
|
||||
// ) {
|
||||
// @Serializable
|
||||
// data class WatchEndpointMusicConfig(
|
||||
// val musicVideoType: String
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Serializable
|
||||
// data class WatchPlaylist(
|
||||
// val watchPlaylistEndpoint: Data
|
||||
// ) : NavigationEndpoint() {
|
||||
// @Serializable
|
||||
// data class Data(
|
||||
// val params: String?,
|
||||
// val playlistId: String,
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// @Serializable
|
||||
// data class Browse(
|
||||
// val browseEndpoint: Data
|
||||
// ) : NavigationEndpoint() {
|
||||
// @Serializable
|
||||
// data class Data(
|
||||
// val params: String?,
|
||||
// val browseId: String,
|
||||
// val browseEndpointContextSupportedConfigs: BrowseEndpointContextSupportedConfigs,
|
||||
// )
|
||||
//
|
||||
// @Serializable
|
||||
// data class BrowseEndpointContextSupportedConfigs(
|
||||
// val browseEndpointContextMusicConfig: BrowseEndpointContextMusicConfig
|
||||
// ) {
|
||||
// @Serializable
|
||||
// data class BrowseEndpointContextMusicConfig(
|
||||
// val pageType: String
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Serializable
|
||||
// data class Search(
|
||||
// val searchEndpoint: Data
|
||||
// ) : NavigationEndpoint() {
|
||||
// @Serializable
|
||||
// data class Data(
|
||||
// val params: String?,
|
||||
// val query: String,
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// object Serializer : JsonContentPolymorphicSerializer<NavigationEndpoint>(NavigationEndpoint::class) {
|
||||
// override fun selectDeserializer(element: JsonElement) = when {
|
||||
// "watchEndpoint" in element.jsonObject -> Watch.serializer()
|
||||
// "watchPlaylistEndpoint" in element.jsonObject -> WatchPlaylist.serializer()
|
||||
// "browseEndpoint" in element.jsonObject -> Browse.serializer()
|
||||
// "searchEndpoint" in element.jsonObject -> Search.serializer()
|
||||
// else -> TODO()
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,83 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonNames
|
||||
|
||||
@Serializable
|
||||
data class NextResponse(
|
||||
val contents: Contents,
|
||||
val continuationContents: MusicQueueRenderer.Content?
|
||||
) {
|
||||
@Serializable
|
||||
data class MusicQueueRenderer(
|
||||
val content: Content?
|
||||
) {
|
||||
@Serializable
|
||||
data class Content(
|
||||
@JsonNames("playlistPanelContinuation")
|
||||
val playlistPanelRenderer: PlaylistPanelRenderer
|
||||
) {
|
||||
@Serializable
|
||||
data class PlaylistPanelRenderer(
|
||||
val contents: List<Content>?,
|
||||
val continuations: List<Continuation>?,
|
||||
val playlistId: String?
|
||||
) {
|
||||
@Serializable
|
||||
data class Content(
|
||||
val playlistPanelVideoRenderer: PlaylistPanelVideoRenderer?
|
||||
) {
|
||||
@Serializable
|
||||
data class PlaylistPanelVideoRenderer(
|
||||
val title: Runs,
|
||||
val longBylineText: Runs?,
|
||||
val shortBylineText: Runs,
|
||||
val lengthText: Runs,
|
||||
val navigationEndpoint: NavigationEndpoint,
|
||||
val thumbnail: ThumbnailRenderer.MusicThumbnailRenderer.Thumbnail,
|
||||
val videoId: String,
|
||||
val playlistSetVideoId: String?,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Contents(
|
||||
val singleColumnMusicWatchNextResultsRenderer: SingleColumnMusicWatchNextResultsRenderer
|
||||
) {
|
||||
@Serializable
|
||||
data class SingleColumnMusicWatchNextResultsRenderer(
|
||||
val tabbedRenderer: TabbedRenderer
|
||||
) {
|
||||
@Serializable
|
||||
data class TabbedRenderer(
|
||||
val watchNextTabbedResultsRenderer: WatchNextTabbedResultsRenderer
|
||||
) {
|
||||
@Serializable
|
||||
data class WatchNextTabbedResultsRenderer(
|
||||
val tabs: List<Tab>
|
||||
) {
|
||||
@Serializable
|
||||
data class Tab(
|
||||
val tabRenderer: TabRenderer
|
||||
) {
|
||||
@Serializable
|
||||
data class TabRenderer(
|
||||
val content: Content?,
|
||||
val endpoint: NavigationEndpoint?,
|
||||
val title: String
|
||||
) {
|
||||
@Serializable
|
||||
data class Content(
|
||||
val musicQueueRenderer: MusicQueueRenderer
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
||||
@Serializable
|
||||
data class PlayerResponse(
|
||||
val playabilityStatus: PlayabilityStatus,
|
||||
val playerConfig: PlayerConfig?,
|
||||
val streamingData: StreamingData?,
|
||||
val videoDetails: VideoDetails,
|
||||
) {
|
||||
@Serializable
|
||||
data class PlayabilityStatus(
|
||||
val status: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PlayerConfig(
|
||||
val audioConfig: AudioConfig?
|
||||
) {
|
||||
@Serializable
|
||||
data class AudioConfig(
|
||||
val loudnessDb: Double?,
|
||||
val perceptualLoudnessDb: Double?
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class StreamingData(
|
||||
val adaptiveFormats: List<AdaptiveFormat>,
|
||||
val expiresInSeconds: String
|
||||
) {
|
||||
@Serializable
|
||||
data class AdaptiveFormat(
|
||||
val itag: Int,
|
||||
val mimeType: String,
|
||||
val averageBitrate: Int?,
|
||||
val contentLength: Long?,
|
||||
val audioQuality: String?,
|
||||
val approxDurationMs: Long?,
|
||||
val loudnessDb: Double?,
|
||||
val audioSampleRate: Int?,
|
||||
val url: String,
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class VideoDetails(
|
||||
val author: String,
|
||||
val channelId: String,
|
||||
val lengthSeconds: String,
|
||||
val thumbnail: ThumbnailRenderer.MusicThumbnailRenderer.Thumbnail,
|
||||
val title: String,
|
||||
val videoId: String
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Runs(
|
||||
val runs: List<Run> = listOf()
|
||||
) {
|
||||
val text: String
|
||||
get() = runs.joinToString("") { it.text }
|
||||
|
||||
fun splitBySeparator(): List<List<Run>> {
|
||||
return runs.flatMapIndexed { index, run ->
|
||||
when {
|
||||
index == 0 || index == runs.lastIndex -> listOf(index)
|
||||
run.text == " • " -> listOf(index - 1, index + 1)
|
||||
else -> emptyList()
|
||||
}
|
||||
}.windowed(size = 2, step = 2) { (from, to) -> runs.slice(from..to) }
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Run(
|
||||
val text: String,
|
||||
val navigationEndpoint: NavigationEndpoint?,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class SearchResponse(
|
||||
val contents: Contents,
|
||||
) {
|
||||
@Serializable
|
||||
data class Contents(
|
||||
val tabbedSearchResultsRenderer: Tabs
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonNames
|
||||
|
||||
@Serializable
|
||||
data class Tabs(
|
||||
val tabs: List<Tab>
|
||||
) {
|
||||
@Serializable
|
||||
data class Tab(
|
||||
val tabRenderer: TabRenderer
|
||||
) {
|
||||
@Serializable
|
||||
data class TabRenderer(
|
||||
val content: Content?,
|
||||
val title: String?,
|
||||
val tabIdentifier: String?,
|
||||
) {
|
||||
@Serializable
|
||||
data class Content(
|
||||
val sectionListRenderer: SectionListRenderer,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class SectionListRenderer(
|
||||
val contents: List<Content>,
|
||||
val continuations: List<Continuation>?
|
||||
) {
|
||||
@Serializable
|
||||
data class Content(
|
||||
@JsonNames("musicImmersiveCarouselShelfRenderer")
|
||||
val musicCarouselShelfRenderer: MusicCarouselShelfRenderer?,
|
||||
val musicShelfRenderer: MusicShelfRenderer?,
|
||||
val gridRenderer: GridRenderer?,
|
||||
val musicDescriptionShelfRenderer: MusicDescriptionShelfRenderer?,
|
||||
) {
|
||||
@Serializable
|
||||
data class GridRenderer(
|
||||
val items: List<Item>,
|
||||
) {
|
||||
@Serializable
|
||||
data class Item(
|
||||
val musicNavigationButtonRenderer: MusicNavigationButtonRenderer
|
||||
)
|
||||
}
|
||||
@Serializable
|
||||
data class MusicDescriptionShelfRenderer(
|
||||
val description: Runs,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package it.vfsfitvnm.youtubemusic.models
|
||||
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonNames
|
||||
|
||||
@Serializable
|
||||
data class ThumbnailRenderer(
|
||||
@JsonNames("croppedSquareThumbnailRenderer")
|
||||
val musicThumbnailRenderer: MusicThumbnailRenderer
|
||||
) {
|
||||
@Serializable
|
||||
data class MusicThumbnailRenderer(
|
||||
val thumbnail: Thumbnail
|
||||
) {
|
||||
@Serializable
|
||||
data class Thumbnail(
|
||||
val thumbnails: List<Thumbnail>
|
||||
) {
|
||||
@Serializable
|
||||
data class Thumbnail(
|
||||
val url: String,
|
||||
val height: Int,
|
||||
val width: Int
|
||||
) {
|
||||
val isResizable: Boolean
|
||||
get() = !url.startsWith("https://i.ytimg.com")
|
||||
|
||||
fun width(width: Int): String {
|
||||
return when {
|
||||
url.startsWith("https://lh3.googleusercontent.com") -> "$url-w$width-h${width * height / this.width}"
|
||||
url.startsWith("https://yt3.ggpht.com") -> "$url-s$width"
|
||||
else -> url
|
||||
}
|
||||
}
|
||||
|
||||
fun size(size: Int): String {
|
||||
return when {
|
||||
url.startsWith("https://lh3.googleusercontent.com") -> "$url-w$size-h$size"
|
||||
url.startsWith("https://yt3.ggpht.com") -> "$url-s$size"
|
||||
else -> url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user