✨ make artists singular and delete descriptions
This commit is contained in:
parent
dd06c5ac65
commit
aca523a303
|
|
@ -9,7 +9,7 @@ export const ThumbnailFull = type({
|
|||
|
||||
export type ArtistBasic = typeof ArtistBasic.infer
|
||||
export const ArtistBasic = type({
|
||||
artistId: "string|null",
|
||||
artistId: "string|null", // Only null for YouTube Music
|
||||
name: "string",
|
||||
})
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ export const SongDetailed = type({
|
|||
type: '"SONG"',
|
||||
videoId: "string",
|
||||
name: "string",
|
||||
artists: [ArtistBasic, "[]"],
|
||||
artist: ArtistBasic,
|
||||
album: AlbumBasic,
|
||||
duration: "number|null",
|
||||
thumbnails: [ThumbnailFull, "[]"],
|
||||
|
|
@ -35,7 +35,7 @@ export const VideoDetailed = type({
|
|||
type: '"VIDEO"',
|
||||
videoId: "string",
|
||||
name: "string",
|
||||
artists: [ArtistBasic, "[]"],
|
||||
artist: ArtistBasic,
|
||||
duration: "number|null",
|
||||
thumbnails: [ThumbnailFull, "[]"],
|
||||
})
|
||||
|
|
@ -54,7 +54,7 @@ export const AlbumDetailed = type({
|
|||
albumId: "string",
|
||||
playlistId: "string",
|
||||
name: "string",
|
||||
artists: [ArtistBasic, "[]"],
|
||||
artist: ArtistBasic,
|
||||
year: "number|null",
|
||||
thumbnails: [ThumbnailFull, "[]"],
|
||||
})
|
||||
|
|
@ -73,10 +73,9 @@ export const SongFull = type({
|
|||
type: '"SONG"',
|
||||
videoId: "string",
|
||||
name: "string",
|
||||
artists: [ArtistBasic, "[]"],
|
||||
artist: ArtistBasic,
|
||||
duration: "number",
|
||||
thumbnails: [ThumbnailFull, "[]"],
|
||||
description: "string",
|
||||
formats: "any[]",
|
||||
adaptiveFormats: "any[]",
|
||||
})
|
||||
|
|
@ -86,10 +85,9 @@ export const VideoFull = type({
|
|||
type: '"VIDEO"',
|
||||
videoId: "string",
|
||||
name: "string",
|
||||
artists: [ArtistBasic, "[]"],
|
||||
artist: ArtistBasic,
|
||||
duration: "number",
|
||||
thumbnails: [ThumbnailFull, "[]"],
|
||||
description: "string",
|
||||
unlisted: "boolean",
|
||||
familySafe: "boolean",
|
||||
paid: "boolean",
|
||||
|
|
@ -102,7 +100,6 @@ export const ArtistFull = type({
|
|||
name: "string",
|
||||
type: '"ARTIST"',
|
||||
thumbnails: [ThumbnailFull, "[]"],
|
||||
description: "string",
|
||||
topSongs: [SongDetailed, "[]"],
|
||||
topAlbums: [AlbumDetailed, "[]"],
|
||||
topSingles: [AlbumDetailed, "[]"],
|
||||
|
|
@ -117,7 +114,7 @@ export const AlbumFull = type({
|
|||
albumId: "string",
|
||||
playlistId: "string",
|
||||
name: "string",
|
||||
artists: [ArtistBasic, "[]"],
|
||||
artist: ArtistBasic,
|
||||
year: "number|null",
|
||||
thumbnails: [ThumbnailFull, "[]"],
|
||||
songs: [SongDetailed, "[]"],
|
||||
|
|
|
|||
|
|
@ -389,16 +389,12 @@ export default class YTMusic {
|
|||
* @returns Artist's Songs
|
||||
*/
|
||||
public async getArtistSongs(artistId: string): Promise<(typeof SongDetailed.infer)[]> {
|
||||
const artistData = await this.constructRequest("browse", {
|
||||
browseId: artistId,
|
||||
})
|
||||
const artistData = await this.constructRequest("browse", { browseId: artistId })
|
||||
const browseToken = traverse(artistData, "musicShelfRenderer", "title", "browseId")
|
||||
|
||||
if (browseToken instanceof Array) return []
|
||||
|
||||
const songsData = await this.constructRequest("browse", {
|
||||
browseId: browseToken,
|
||||
})
|
||||
const songsData = await this.constructRequest("browse", { browseId: browseToken })
|
||||
const continueToken = traverse(songsData, "continuation")
|
||||
const moreSongsData = await this.constructRequest(
|
||||
"browse",
|
||||
|
|
@ -409,7 +405,12 @@ export default class YTMusic {
|
|||
return [
|
||||
...traverseList(songsData, "musicResponsiveListItemRenderer"),
|
||||
...traverseList(moreSongsData, "musicResponsiveListItemRenderer"),
|
||||
].map(SongParser.parseArtistSong)
|
||||
].map(s =>
|
||||
SongParser.parseArtistSong(s, {
|
||||
artistId,
|
||||
name: traverseString(artistData, "header", "title", "text")(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { AlbumBasic, AlbumDetailed, AlbumFull, ArtistBasic } from "../@types/types"
|
||||
import checkType from "../utils/checkType"
|
||||
import { isArtist } from "../utils/filters"
|
||||
import traverse from "../utils/traverse"
|
||||
import traverseList from "../utils/traverseList"
|
||||
import traverseString from "../utils/traverseString"
|
||||
import SongParser from "./SongParser"
|
||||
|
|
@ -11,12 +13,11 @@ export default class AlbumParser {
|
|||
name: traverseString(data, "header", "title", "text")(),
|
||||
}
|
||||
|
||||
const artists: ArtistBasic[] = traverseList(data, "header", "subtitle", "runs")
|
||||
.filter(run => "navigationEndpoint" in run)
|
||||
.map(run => ({
|
||||
artistId: traverseString(run, "browseId")(),
|
||||
name: traverseString(run, "text")(),
|
||||
}))
|
||||
const artistData = traverse(data, "header", "subtitle", "runs")
|
||||
const artistBasic: ArtistBasic = {
|
||||
artistId: traverseString(artistData, "browseId")(),
|
||||
name: traverseString(artistData, "text")(),
|
||||
}
|
||||
|
||||
const thumbnails = traverseList(data, "header", "thumbnails")
|
||||
|
||||
|
|
@ -25,13 +26,13 @@ export default class AlbumParser {
|
|||
type: "ALBUM",
|
||||
...albumBasic,
|
||||
playlistId: traverseString(data, "buttonRenderer", "playlistId")(),
|
||||
artists,
|
||||
artist: artistBasic,
|
||||
year: AlbumParser.processYear(
|
||||
traverseString(data, "header", "subtitle", "text")(-1),
|
||||
),
|
||||
thumbnails,
|
||||
songs: traverseList(data, "musicResponsiveListItemRenderer").map(item =>
|
||||
SongParser.parseAlbumSong(item, artists, albumBasic, thumbnails),
|
||||
SongParser.parseAlbumSong(item, artistBasic, albumBasic, thumbnails),
|
||||
),
|
||||
},
|
||||
AlbumFull,
|
||||
|
|
@ -39,21 +40,23 @@ export default class AlbumParser {
|
|||
}
|
||||
|
||||
public static parseSearchResult(item: any): AlbumDetailed {
|
||||
const flexColumns = traverseList(item, "flexColumns")
|
||||
const columns = traverseList(item, "flexColumns", "runs").flat()
|
||||
|
||||
// No specific way to identify the title
|
||||
const title = columns[0]
|
||||
const artist = columns.find(isArtist) || columns[3]
|
||||
|
||||
return checkType(
|
||||
{
|
||||
type: "ALBUM",
|
||||
albumId: traverseString(item, "browseId")(-1),
|
||||
playlistId: traverseString(item, "overlay", "playlistId")(),
|
||||
artists: traverseList(flexColumns[1], "runs")
|
||||
.filter(run => "navigationEndpoint" in run)
|
||||
.map(run => ({
|
||||
artistId: traverseString(run, "browseId")(),
|
||||
name: traverseString(run, "text")(),
|
||||
})),
|
||||
year: AlbumParser.processYear(traverseString(flexColumns[1], "runs", "text")(-1)),
|
||||
name: traverseString(flexColumns[0], "runs", "text")(),
|
||||
artist: {
|
||||
name: traverseString(artist, "text")(),
|
||||
artistId: traverseString(artist, "browseId")() || null,
|
||||
},
|
||||
year: AlbumParser.processYear(traverseString(columns[1], "runs", "text")(-1)),
|
||||
name: traverseString(title, "text")(),
|
||||
thumbnails: traverseList(item, "thumbnails"),
|
||||
},
|
||||
AlbumDetailed,
|
||||
|
|
@ -67,7 +70,7 @@ export default class AlbumParser {
|
|||
albumId: traverseString(item, "browseId")(-1),
|
||||
playlistId: traverseString(item, "thumbnailOverlay", "playlistId")(),
|
||||
name: traverseString(item, "title", "text")(),
|
||||
artists: [artistBasic],
|
||||
artist: artistBasic,
|
||||
year: AlbumParser.processYear(traverseString(item, "subtitle", "text")(-1)),
|
||||
thumbnails: traverseList(item, "thumbnails"),
|
||||
},
|
||||
|
|
@ -82,7 +85,7 @@ export default class AlbumParser {
|
|||
albumId: traverseString(item, "browseId")(-1),
|
||||
playlistId: traverseString(item, "musicPlayButtonRenderer", "playlistId")(),
|
||||
name: traverseString(item, "title", "text")(),
|
||||
artists: [artistBasic],
|
||||
artist: artistBasic,
|
||||
year: AlbumParser.processYear(traverseString(item, "subtitle", "text")(-1)),
|
||||
thumbnails: traverseList(item, "thumbnails"),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,14 +14,11 @@ export default class ArtistParser {
|
|||
name: traverseString(data, "header", "title", "text")(),
|
||||
}
|
||||
|
||||
const description = traverseString(data, "header", "description", "text")()
|
||||
|
||||
return checkType(
|
||||
{
|
||||
type: "ARTIST",
|
||||
...artistBasic,
|
||||
thumbnails: traverseList(data, "header", "thumbnails"),
|
||||
description,
|
||||
topSongs: traverseList(data, "musicShelfRenderer", "contents").map(item =>
|
||||
SongParser.parseArtistTopSong(item, artistBasic),
|
||||
),
|
||||
|
|
@ -46,8 +43,9 @@ export default class ArtistParser {
|
|||
featuredOn:
|
||||
traverseList(data, "musicCarouselShelfRenderer")
|
||||
?.at(3)
|
||||
?.contents.map((item: any) => PlaylistParser.parseArtistFeaturedOn(item)) ??
|
||||
[],
|
||||
?.contents.map((item: any) =>
|
||||
PlaylistParser.parseArtistFeaturedOn(item, artistBasic),
|
||||
) ?? [],
|
||||
similarArtists:
|
||||
traverseList(data, "musicCarouselShelfRenderer")
|
||||
?.at(4)
|
||||
|
|
@ -58,7 +56,7 @@ export default class ArtistParser {
|
|||
}
|
||||
|
||||
public static parseSearchResult(item: any): ArtistDetailed {
|
||||
const columns = traverseList(item, "flexColumns")
|
||||
const columns = traverseList(item, "flexColumns", "runs").flat()
|
||||
|
||||
// No specific way to identify the title
|
||||
const title = columns[0]
|
||||
|
|
@ -67,7 +65,7 @@ export default class ArtistParser {
|
|||
{
|
||||
type: "ARTIST",
|
||||
artistId: traverseString(item, "browseId")(),
|
||||
name: traverseString(title, "runs", "text")(),
|
||||
name: traverseString(title, "text")(),
|
||||
thumbnails: traverseList(item, "thumbnails"),
|
||||
},
|
||||
ArtistDetailed,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { PlaylistDetailed, PlaylistFull } from "../@types/types"
|
||||
import { ArtistBasic, PlaylistDetailed, PlaylistFull } from "../@types/types"
|
||||
import checkType from "../utils/checkType"
|
||||
import { isArtist } from "../utils/filters"
|
||||
import traverse from "../utils/traverse"
|
||||
|
|
@ -53,16 +53,13 @@ export default class PlaylistParser {
|
|||
)
|
||||
}
|
||||
|
||||
public static parseArtistFeaturedOn(item: any): PlaylistDetailed {
|
||||
public static parseArtistFeaturedOn(item: any, artistBasic: ArtistBasic): PlaylistDetailed {
|
||||
return checkType(
|
||||
{
|
||||
type: "PLAYLIST",
|
||||
playlistId: traverseString(item, "navigationEndpoint", "browseId")(),
|
||||
name: traverseString(item, "runs", "text")(),
|
||||
artist: {
|
||||
artistId: traverseString(item, "browseId")(),
|
||||
name: traverseString(item, "runs", "text")(-3),
|
||||
},
|
||||
artist: artistBasic,
|
||||
thumbnails: traverseList(item, "thumbnails"),
|
||||
},
|
||||
PlaylistDetailed,
|
||||
|
|
|
|||
|
|
@ -12,15 +12,12 @@ export default class SongParser {
|
|||
type: "SONG",
|
||||
videoId: traverseString(data, "videoDetails", "videoId")(),
|
||||
name: traverseString(data, "videoDetails", "title")(),
|
||||
artists: [
|
||||
{
|
||||
artistId: traverseString(data, "videoDetails", "channelId")(),
|
||||
name: traverseString(data, "author")(),
|
||||
},
|
||||
],
|
||||
artist: {
|
||||
name: traverseString(data, "author")(),
|
||||
artistId: traverseString(data, "videoDetails", "channelId")(),
|
||||
},
|
||||
duration: +traverseString(data, "videoDetails", "lengthSeconds")(),
|
||||
thumbnails: traverseList(data, "videoDetails", "thumbnails"),
|
||||
description: traverseString(data, "description")(),
|
||||
formats: traverseList(data, "streamingData", "formats"),
|
||||
adaptiveFormats: traverseList(data, "streamingData", "adaptiveFormats"),
|
||||
},
|
||||
|
|
@ -41,12 +38,10 @@ export default class SongParser {
|
|||
type: "SONG",
|
||||
videoId: traverseString(item, "playlistItemData", "videoId")(),
|
||||
name: traverseString(title, "text")(),
|
||||
artists: [
|
||||
{
|
||||
name: traverseString(artist, "text")(),
|
||||
artistId: traverseString(artist, "browseId")(),
|
||||
},
|
||||
],
|
||||
artist: {
|
||||
name: traverseString(artist, "text")(),
|
||||
artistId: traverseString(artist, "browseId")(),
|
||||
},
|
||||
album: {
|
||||
name: traverseString(album, "text")(),
|
||||
albumId: traverseString(album, "browseId")(),
|
||||
|
|
@ -58,11 +53,10 @@ export default class SongParser {
|
|||
)
|
||||
}
|
||||
|
||||
public static parseArtistSong(item: any): SongDetailed {
|
||||
public static parseArtistSong(item: any, artistBasic: ArtistBasic): SongDetailed {
|
||||
const columns = traverseList(item, "flexColumns", "runs").flat()
|
||||
|
||||
const title = columns.find(isTitle)
|
||||
const artist = columns.find(isArtist)
|
||||
const album = columns.find(isAlbum)
|
||||
const duration = columns.find(isDuration)
|
||||
|
||||
|
|
@ -71,12 +65,7 @@ export default class SongParser {
|
|||
type: "SONG",
|
||||
videoId: traverseString(item, "playlistItemData", "videoId")(),
|
||||
name: traverseString(title, "text")(),
|
||||
artists: [
|
||||
{
|
||||
name: traverseString(artist, "text")(),
|
||||
artistId: traverseString(artist, "browseId")(),
|
||||
},
|
||||
],
|
||||
artist: artistBasic,
|
||||
album: {
|
||||
name: traverseString(album, "text")(),
|
||||
albumId: traverseString(album, "browseId")(),
|
||||
|
|
@ -99,7 +88,7 @@ export default class SongParser {
|
|||
type: "SONG",
|
||||
videoId: traverseString(item, "playlistItemData", "videoId")(),
|
||||
name: traverseString(title, "text")(),
|
||||
artists: [artistBasic],
|
||||
artist: artistBasic,
|
||||
album: {
|
||||
name: traverseString(album, "text")(),
|
||||
albumId: traverseString(album, "browseId")(),
|
||||
|
|
@ -113,7 +102,7 @@ export default class SongParser {
|
|||
|
||||
public static parseAlbumSong(
|
||||
item: any,
|
||||
artists: ArtistBasic[],
|
||||
artistBasic: ArtistBasic,
|
||||
albumBasic: AlbumBasic,
|
||||
thumbnails: ThumbnailFull[],
|
||||
): SongDetailed {
|
||||
|
|
@ -127,7 +116,7 @@ export default class SongParser {
|
|||
type: "SONG",
|
||||
videoId: traverseString(item, "playlistItemData", "videoId")(),
|
||||
name: traverseString(title, "text")(),
|
||||
artists,
|
||||
artist: artistBasic,
|
||||
album: albumBasic,
|
||||
duration: duration ? Parser.parseDuration(duration.text) : null,
|
||||
thumbnails,
|
||||
|
|
|
|||
|
|
@ -12,15 +12,12 @@ export default class VideoParser {
|
|||
type: "VIDEO",
|
||||
videoId: traverseString(data, "videoDetails", "videoId")(),
|
||||
name: traverseString(data, "videoDetails", "title")(),
|
||||
artists: [
|
||||
{
|
||||
artistId: traverseString(data, "videoDetails", "channelId")(),
|
||||
name: traverseString(data, "author")(),
|
||||
},
|
||||
],
|
||||
artist: {
|
||||
artistId: traverseString(data, "videoDetails", "channelId")(),
|
||||
name: traverseString(data, "author")(),
|
||||
},
|
||||
duration: +traverseString(data, "videoDetails", "lengthSeconds")(),
|
||||
thumbnails: traverseList(data, "videoDetails", "thumbnails"),
|
||||
description: traverseString(data, "description")(),
|
||||
unlisted: traverse(data, "unlisted"),
|
||||
familySafe: traverse(data, "familySafe"),
|
||||
paid: traverse(data, "paid"),
|
||||
|
|
@ -39,12 +36,10 @@ export default class VideoParser {
|
|||
type: "VIDEO",
|
||||
videoId: traverseString(item, "playNavigationEndpoint", "videoId")(),
|
||||
name: traverseString(title, "text")(),
|
||||
artists: [
|
||||
{
|
||||
name: traverseString(artist, "text")(),
|
||||
artistId: traverseString(artist, "browseId")(),
|
||||
},
|
||||
],
|
||||
artist: {
|
||||
name: traverseString(artist, "text")(),
|
||||
artistId: traverseString(artist, "browseId")(),
|
||||
},
|
||||
duration: Parser.parseDuration(duration.text),
|
||||
thumbnails: traverseList(item, "thumbnails"),
|
||||
}
|
||||
|
|
@ -55,7 +50,7 @@ export default class VideoParser {
|
|||
type: "VIDEO",
|
||||
videoId: traverseString(item, "videoId")(),
|
||||
name: traverseString(item, "runs", "text")(),
|
||||
artists: [artistBasic],
|
||||
artist: artistBasic,
|
||||
duration: null,
|
||||
thumbnails: traverseList(item, "thumbnails"),
|
||||
}
|
||||
|
|
@ -77,12 +72,10 @@ export default class VideoParser {
|
|||
/https:\/\/i\.ytimg\.com\/vi\/(.+)\//,
|
||||
)[1],
|
||||
name: traverseString(title, "text")(),
|
||||
artists: [
|
||||
{
|
||||
name: traverseString(artist, "text")(),
|
||||
artistId: traverseString(artist, "browseId")() || null,
|
||||
},
|
||||
],
|
||||
artist: {
|
||||
name: traverseString(artist, "text")(),
|
||||
artistId: traverseString(artist, "browseId")() || null,
|
||||
},
|
||||
duration: duration ? Parser.parseDuration(duration.text) : null,
|
||||
thumbnails: traverseList(item, "thumbnails"),
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue