Began cleaning up the ytmusic parsers
This commit is contained in:
@@ -142,10 +142,9 @@ export class YouTubeMusic implements Connection {
|
|||||||
const headerTitle = section.musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer.title.runs[0].text
|
const headerTitle = section.musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer.title.runs[0].text
|
||||||
const rawContents = section.musicCarouselShelfRenderer.contents
|
const rawContents = section.musicCarouselShelfRenderer.contents
|
||||||
|
|
||||||
const parsedContent: (Song | Album | Playlist)[] =
|
const parsedContent = rawContents.map((content) =>
|
||||||
'musicTwoRowItemRenderer' in rawContents[0]
|
'musicTwoRowItemRenderer' in content ? this.parseTwoRowItemRenderer(content.musicTwoRowItemRenderer) : this.parseResponsiveListItemRenderer(content.musicResponsiveListItemRenderer),
|
||||||
? this.parseTwoRowItemRenderer((rawContents as { musicTwoRowItemRenderer: InnerTube.musicTwoRowItemRenderer }[]).map((item) => item.musicTwoRowItemRenderer))
|
)
|
||||||
: this.parseResponsiveListItemRenderer((rawContents as { musicResponsiveListItemRenderer: InnerTube.musicResponsiveListItemRenderer }[]).map((item) => item.musicResponsiveListItemRenderer))
|
|
||||||
|
|
||||||
if (headerTitle === 'Listen again') {
|
if (headerTitle === 'Listen again') {
|
||||||
homeItems.listenAgain = parsedContent
|
homeItems.listenAgain = parsedContent
|
||||||
@@ -159,158 +158,109 @@ export class YouTubeMusic implements Connection {
|
|||||||
return homeItems
|
return homeItems
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseTwoRowItemRenderer = (rowContent: InnerTube.musicTwoRowItemRenderer[]): (Song | Album | Playlist)[] => {
|
private parseTwoRowItemRenderer = (rowContent: InnerTube.musicTwoRowItemRenderer): Song | Album | Artist | Playlist => {
|
||||||
const parsedContent: (Song | Album | Playlist)[] = []
|
const connection = { id: this.id, type: 'youtube-music' } satisfies (Song | Album | Artist | Playlist)['connection']
|
||||||
for (const data of rowContent) {
|
const name = rowContent.title.runs[0].text
|
||||||
const title = data.title.runs[0].text
|
|
||||||
const subtitles = data.subtitle.runs
|
|
||||||
const artists: Song['artists'] | Album['artists'] = []
|
|
||||||
for (const subtitle of subtitles) {
|
|
||||||
if (subtitle.navigationEndpoint && 'browseEndpoint' in subtitle.navigationEndpoint) {
|
|
||||||
artists.push({ id: subtitle.navigationEndpoint.browseEndpoint.browseId, name: subtitle.text })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('browseEndpoint' in data.navigationEndpoint && data.navigationEndpoint.browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType === 'MUSIC_PAGE_TYPE_ALBUM') {
|
function getArtists() {
|
||||||
const album: Album = {
|
const artists: (Song | Album)['artists'] = []
|
||||||
connection: {
|
for (const run of rowContent.subtitle.runs) {
|
||||||
id: this.id,
|
if (run.navigationEndpoint && 'browseEndpoint' in run.navigationEndpoint) {
|
||||||
type: 'youtube-music',
|
|
||||||
},
|
|
||||||
type: 'album',
|
|
||||||
id: data.navigationEndpoint.browseEndpoint.browseId,
|
|
||||||
name: title,
|
|
||||||
thumbnail: refineThumbnailUrl(data.thumbnailRenderer.musicThumbnailRenderer.thumbnail.thumbnails[0].url),
|
|
||||||
}
|
|
||||||
if (artists.length > 0) album.artists = artists
|
|
||||||
parsedContent.push(album)
|
|
||||||
} else if ('watchEndpoint' in data.navigationEndpoint) {
|
|
||||||
const song: Song = {
|
|
||||||
connection: {
|
|
||||||
id: this.id,
|
|
||||||
type: 'youtube-music',
|
|
||||||
},
|
|
||||||
type: 'song',
|
|
||||||
id: data.navigationEndpoint.watchEndpoint.videoId,
|
|
||||||
name: title,
|
|
||||||
thumbnail: refineThumbnailUrl(data.thumbnailRenderer.musicThumbnailRenderer.thumbnail.thumbnails[0].url),
|
|
||||||
}
|
|
||||||
if (artists.length > 0) song.artists = artists
|
|
||||||
parsedContent.push(song)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsedContent
|
|
||||||
}
|
|
||||||
|
|
||||||
private parseResponsiveListItemRenderer = (listContent: InnerTube.musicResponsiveListItemRenderer[]): Song[] => {
|
|
||||||
const parsedContent: Song[] = []
|
|
||||||
for (const data of listContent) {
|
|
||||||
const title = data.flexColumns[0].musicResponsiveListItemFlexColumnRenderer.text.runs[0].text,
|
|
||||||
id = (data.flexColumns[0].musicResponsiveListItemFlexColumnRenderer.text.runs[0].navigationEndpoint! as { watchEndpoint: InnerTube.watchEndpoint }).watchEndpoint.videoId
|
|
||||||
|
|
||||||
const artists: Song['artists'] = []
|
|
||||||
for (const run of data.flexColumns[1].musicResponsiveListItemFlexColumnRenderer.text.runs) {
|
|
||||||
if ('navigationEndpoint' in run && 'browseEndpoint' in run.navigationEndpoint!) {
|
|
||||||
artists.push({ id: run.navigationEndpoint.browseEndpoint.browseId, name: run.text })
|
artists.push({ id: run.navigationEndpoint.browseEndpoint.browseId, name: run.text })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (artists.length > 0) return artists
|
||||||
const thumbnail = refineThumbnailUrl(data.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails[0].url)
|
return undefined
|
||||||
|
|
||||||
const song: Song = {
|
|
||||||
connection: {
|
|
||||||
id: this.id,
|
|
||||||
type: 'youtube-music',
|
|
||||||
},
|
|
||||||
type: 'song',
|
|
||||||
id,
|
|
||||||
name: title,
|
|
||||||
thumbnail,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (artists.length > 0) song.artists = artists
|
const thumbnail = refineThumbnailUrl(rowContent.thumbnailRenderer.musicThumbnailRenderer.thumbnail.thumbnails[0].url)
|
||||||
|
|
||||||
|
if ('watchEndpoint' in rowContent.navigationEndpoint) {
|
||||||
|
const id = rowContent.navigationEndpoint.watchEndpoint.videoId
|
||||||
|
return { connection, id, name, type: 'song', artists: getArtists(), thumbnail } satisfies Song
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('watchPlaylistEndpoint' in rowContent.navigationEndpoint) {
|
||||||
|
const id = rowContent.navigationEndpoint.watchPlaylistEndpoint.playlistId
|
||||||
|
return { connection, id, name, type: 'playlist', thumbnail } satisfies Playlist
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageType = rowContent.navigationEndpoint.browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType
|
||||||
|
const id = rowContent.navigationEndpoint.browseEndpoint.browseId
|
||||||
|
switch (pageType) {
|
||||||
|
case 'MUSIC_PAGE_TYPE_ALBUM':
|
||||||
|
return { connection, id, name, type: 'album', artists: getArtists(), thumbnail } satisfies Album
|
||||||
|
case 'MUSIC_PAGE_TYPE_ARTIST':
|
||||||
|
return { connection, id, name, type: 'artist', thumbnail } satisfies Artist
|
||||||
|
case 'MUSIC_PAGE_TYPE_PLAYLIST':
|
||||||
|
return { connection, id, name, type: 'playlist', thumbnail } satisfies Playlist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseResponsiveListItemRenderer = (listContent: InnerTube.musicResponsiveListItemRenderer): Song => {
|
||||||
|
const connection = { id: this.id, type: 'youtube-music' } satisfies Song['connection']
|
||||||
|
const name = listContent.flexColumns[0].musicResponsiveListItemFlexColumnRenderer.text.runs[0].text
|
||||||
|
const id = (listContent.flexColumns[0].musicResponsiveListItemFlexColumnRenderer.text.runs[0].navigationEndpoint! as { watchEndpoint: InnerTube.watchEndpoint }).watchEndpoint.videoId
|
||||||
|
|
||||||
|
const mappedArtists: Song['artists'] = []
|
||||||
|
for (const run of listContent.flexColumns[1].musicResponsiveListItemFlexColumnRenderer.text.runs) {
|
||||||
|
if ('navigationEndpoint' in run && 'browseEndpoint' in run.navigationEndpoint!) {
|
||||||
|
mappedArtists.push({ id: run.navigationEndpoint.browseEndpoint.browseId, name: run.text })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const artists = mappedArtists.length > 0 ? mappedArtists : undefined
|
||||||
|
|
||||||
|
function getAlbum() {
|
||||||
// This is like the ONE situation where `text` might not have a run
|
// This is like the ONE situation where `text` might not have a run
|
||||||
if (data.flexColumns[2].musicResponsiveListItemFlexColumnRenderer.text?.runs) {
|
if (listContent.flexColumns[2].musicResponsiveListItemFlexColumnRenderer.text?.runs) {
|
||||||
song.album = {
|
return {
|
||||||
id: (data.flexColumns[2].musicResponsiveListItemFlexColumnRenderer.text.runs[0].navigationEndpoint! as { browseEndpoint: InnerTube.browseEndpoint }).browseEndpoint.browseId,
|
id: (listContent.flexColumns[2].musicResponsiveListItemFlexColumnRenderer.text.runs[0].navigationEndpoint! as { browseEndpoint: InnerTube.browseEndpoint }).browseEndpoint.browseId,
|
||||||
name: data.flexColumns[2].musicResponsiveListItemFlexColumnRenderer.text.runs[0].text,
|
name: listContent.flexColumns[2].musicResponsiveListItemFlexColumnRenderer.text.runs[0].text,
|
||||||
|
} satisfies Song['album']
|
||||||
}
|
}
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedContent.push(song)
|
const thumbnail = refineThumbnailUrl(listContent.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails[0].url)
|
||||||
}
|
|
||||||
|
|
||||||
return parsedContent
|
return { connection, id, name, type: 'song', artists, album: getAlbum(), thumbnail } satisfies Song
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseMusicCardShelfRenderer = (cardContent: InnerTube.musicCardShelfRenderer): Song | Album | Artist | Playlist => {
|
private parseMusicCardShelfRenderer = (cardContent: InnerTube.musicCardShelfRenderer): Song | Album | Artist | Playlist => {
|
||||||
const navigationEndpoint = cardContent.title.runs[0].navigationEndpoint
|
const connection = { id: this.id, type: 'youtube-music' } satisfies (Song | Album | Artist | Playlist)['connection']
|
||||||
const artists: Song['artists'] | Album['artists'] = []
|
const name = cardContent.title.runs[0].text
|
||||||
cardContent.subtitle.runs.forEach((run) => {
|
|
||||||
if (run.navigationEndpoint?.browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType === 'MUSIC_PAGE_TYPE_ARTIST') {
|
const artistsSubtitleRuns = cardContent.subtitle.runs.filter(
|
||||||
artists.push({ id: run.navigationEndpoint.browseEndpoint.browseId, name: run.text })
|
(run) => run.navigationEndpoint?.browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType === 'MUSIC_PAGE_TYPE_ARTIST',
|
||||||
}
|
)
|
||||||
|
const artists: (Song | Album)['artists'] =
|
||||||
|
artistsSubtitleRuns.length > 0
|
||||||
|
? artistsSubtitleRuns.map((run) => {
|
||||||
|
return { id: run.navigationEndpoint!.browseEndpoint.browseId, name: run.text }
|
||||||
})
|
})
|
||||||
|
: undefined
|
||||||
|
|
||||||
const thumbnail = refineThumbnailUrl(cardContent.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails[0].url)
|
const thumbnail = refineThumbnailUrl(cardContent.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails[0].url)
|
||||||
|
|
||||||
|
const navigationEndpoint = cardContent.title.runs[0].navigationEndpoint
|
||||||
if ('watchEndpoint' in navigationEndpoint) {
|
if ('watchEndpoint' in navigationEndpoint) {
|
||||||
|
const id = navigationEndpoint.watchEndpoint.videoId
|
||||||
const albumSubtitleRun = cardContent.subtitle.runs.find(
|
const albumSubtitleRun = cardContent.subtitle.runs.find(
|
||||||
(run) => run.navigationEndpoint?.browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType === 'MUSIC_PAGE_TYPE_ALBUM',
|
(run) => run.navigationEndpoint?.browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType === 'MUSIC_PAGE_TYPE_ALBUM',
|
||||||
)
|
)
|
||||||
const song: Song = {
|
const album = albumSubtitleRun ? { id: albumSubtitleRun.navigationEndpoint!.browseEndpoint.browseId, name: albumSubtitleRun.text } : undefined
|
||||||
connection: {
|
return { connection, id, name, type: 'song', artists, album, thumbnail } satisfies Song
|
||||||
id: this.id,
|
|
||||||
type: 'youtube-music',
|
|
||||||
},
|
|
||||||
id: navigationEndpoint.watchEndpoint.videoId,
|
|
||||||
name: cardContent.title.runs[0].text,
|
|
||||||
type: 'song',
|
|
||||||
thumbnail,
|
|
||||||
}
|
}
|
||||||
if (artists.length > 0) song.artists = artists
|
|
||||||
if (albumSubtitleRun) song.album = { id: albumSubtitleRun.navigationEndpoint!.browseEndpoint.browseId, name: albumSubtitleRun.text }
|
|
||||||
return song
|
|
||||||
} else {
|
|
||||||
const pageType = navigationEndpoint.browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType
|
const pageType = navigationEndpoint.browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType
|
||||||
if (pageType === 'MUSIC_PAGE_TYPE_ALBUM') {
|
const id = navigationEndpoint.browseEndpoint.browseId
|
||||||
const album: Album = {
|
switch (pageType) {
|
||||||
connection: {
|
case 'MUSIC_PAGE_TYPE_ALBUM':
|
||||||
id: this.id,
|
return { connection, id, name, type: 'album', artists, thumbnail } satisfies Album
|
||||||
type: 'youtube-music',
|
case 'MUSIC_PAGE_TYPE_ARTIST':
|
||||||
},
|
return { connection, id, name, type: 'artist', thumbnail } satisfies Artist
|
||||||
id: navigationEndpoint.browseEndpoint.browseId,
|
case 'MUSIC_PAGE_TYPE_PLAYLIST':
|
||||||
name: cardContent.title.runs[0].text,
|
return { connection, id, name, type: 'playlist', thumbnail } satisfies Playlist
|
||||||
type: 'album',
|
|
||||||
thumbnail,
|
|
||||||
}
|
|
||||||
if (artists.length > 0) album.artists = artists
|
|
||||||
return album
|
|
||||||
} else if (pageType === 'MUSIC_PAGE_TYPE_ARTIST') {
|
|
||||||
const artist: Artist = {
|
|
||||||
connection: {
|
|
||||||
id: this.id,
|
|
||||||
type: 'youtube-music',
|
|
||||||
},
|
|
||||||
id: navigationEndpoint.browseEndpoint.browseId,
|
|
||||||
name: cardContent.title.runs[0].text,
|
|
||||||
type: 'artist',
|
|
||||||
thumbnail,
|
|
||||||
}
|
|
||||||
return artist
|
|
||||||
} else {
|
|
||||||
// NEED TO GET A SAMPLE FOR THIS
|
|
||||||
const playlist: Playlist = {
|
|
||||||
connection: {
|
|
||||||
id: this.id,
|
|
||||||
type: 'youtube-music',
|
|
||||||
},
|
|
||||||
id: navigationEndpoint.browseEndpoint.browseId,
|
|
||||||
name: cardContent.title.runs[0].text,
|
|
||||||
type: 'playlist',
|
|
||||||
}
|
|
||||||
return playlist
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -457,20 +407,6 @@ declare namespace InnerTube {
|
|||||||
title: {
|
title: {
|
||||||
runs: [runs]
|
runs: [runs]
|
||||||
}
|
}
|
||||||
strapline: [runs]
|
|
||||||
accessibilityData: accessibilityData
|
|
||||||
headerStyle: string
|
|
||||||
moreContentButton?: {
|
|
||||||
buttonRenderer: {
|
|
||||||
style: string
|
|
||||||
text: {
|
|
||||||
runs: [runs]
|
|
||||||
}
|
|
||||||
navigationEndpoint: navigationEndpoint
|
|
||||||
trackingParams: string
|
|
||||||
accessibilityData: accessibilityData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thumbnail?: musicThumbnailRenderer
|
thumbnail?: musicThumbnailRenderer
|
||||||
trackingParams: string
|
trackingParams: string
|
||||||
}
|
}
|
||||||
@@ -486,14 +422,14 @@ declare namespace InnerTube {
|
|||||||
itemSize: string
|
itemSize: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type musicDescriptionShelfRenderer = {
|
// type musicDescriptionShelfRenderer = {
|
||||||
header: {
|
// header: {
|
||||||
runs: [runs]
|
// runs: [runs]
|
||||||
}
|
// }
|
||||||
description: {
|
// description: {
|
||||||
runs: [runs]
|
// runs: [runs]
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
type musicTwoRowItemRenderer = {
|
type musicTwoRowItemRenderer = {
|
||||||
thumbnailRenderer: {
|
thumbnailRenderer: {
|
||||||
|
|||||||
Reference in New Issue
Block a user