Initial commit

This commit is contained in:
vfsfitvnm
2022-06-02 18:59:18 +02:00
commit 1e673ad582
160 changed files with 10800 additions and 0 deletions

View File

@@ -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
)
}
}
}

View File

@@ -0,0 +1,9 @@
package it.vfsfitvnm.youtubemusic.models
import kotlinx.serialization.Serializable
@Serializable
data class ButtonRenderer(
val navigationEndpoint: NavigationEndpoint
)

View File

@@ -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
)
}

View File

@@ -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>
// )
}
}

View File

@@ -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?
)
}

View File

@@ -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,
)
}
}
}
}

View File

@@ -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
)
}
}
}

View File

@@ -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
)
}

View File

@@ -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?
)
}
}

View File

@@ -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()
}
}

View File

@@ -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,
)

View File

@@ -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()
// }
// }
//}

View File

@@ -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
)
}
}
}
}
}
}
}

View File

@@ -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
)
}

View File

@@ -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?,
)
}

View File

@@ -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
)
}

View File

@@ -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,
)
}
}

View File

@@ -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
}
}
}
}
}
}