Not exporting namespace anymore

This commit is contained in:
Zechariah 2021-12-31 00:54:47 +08:00
parent 5a458d5557
commit 08ea5a47b6
12 changed files with 177 additions and 165 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "ytmusic-api", "name": "ytmusic-api",
"version": "1.0.2", "version": "1.0.3",
"description": "YouTube Music API", "description": "YouTube Music API",
"main": "build/index.js", "main": "build/index.js",
"types": "build/index.d.ts", "types": "build/index.d.ts",

View File

@ -6,10 +6,21 @@ import SearchParser from "./parsers/SearchParser"
import SongParser from "./parsers/SongParser" import SongParser from "./parsers/SongParser"
import traverse from "./utils/traverse" import traverse from "./utils/traverse"
import VideoParser from "./parsers/VideoParser" import VideoParser from "./parsers/VideoParser"
import YTMusic from "." import {
AlbumDetailed,
AlbumFull,
ArtistDetailed,
ArtistFull,
PlaylistFull,
SearchResult,
SongDetailed,
SongFull,
VideoDetailed,
VideoFull
} from "."
import { Cookie, CookieJar } from "tough-cookie" import { Cookie, CookieJar } from "tough-cookie"
export default class Api { export default class YTMusic {
private cookiejar: CookieJar private cookiejar: CookieJar
private config?: Record<string, string> private config?: Record<string, string>
private client: AxiosInstance private client: AxiosInstance
@ -206,12 +217,12 @@ export default class Api {
* @param query Query string * @param query Query string
* @param category Type of search results to receive * @param category Type of search results to receive
*/ */
public async search(query: string, category: "SONG"): Promise<YTMusic.SongDetailed[]> public async search(query: string, category: "SONG"): Promise<SongDetailed[]>
public async search(query: string, category: "VIDEO"): Promise<YTMusic.VideoDetailed[]> public async search(query: string, category: "VIDEO"): Promise<VideoDetailed[]>
public async search(query: string, category: "ARTIST"): Promise<YTMusic.ArtistDetailed[]> public async search(query: string, category: "ARTIST"): Promise<ArtistDetailed[]>
public async search(query: string, category: "ALBUM"): Promise<YTMusic.AlbumDetailed[]> public async search(query: string, category: "ALBUM"): Promise<AlbumDetailed[]>
public async search(query: string, category: "PLAYLIST"): Promise<YTMusic.PlaylistFull[]> public async search(query: string, category: "PLAYLIST"): Promise<PlaylistFull[]>
public async search(query: string): Promise<YTMusic.SearchResult[]> public async search(query: string): Promise<SearchResult[]>
public async search(query: string, category?: string) { public async search(query: string, category?: string) {
const searchData = await this.constructRequest("search", { const searchData = await this.constructRequest("search", {
query, query,
@ -242,7 +253,7 @@ export default class Api {
* @param videoId Video ID * @param videoId Video ID
* @returns Song Data * @returns Song Data
*/ */
public async getSong(videoId: string): Promise<YTMusic.SongFull> { public async getSong(videoId: string): Promise<SongFull> {
const data = await this.constructRequest("player", { videoId }) const data = await this.constructRequest("player", { videoId })
return SongParser.parse(data) return SongParser.parse(data)
@ -254,7 +265,7 @@ export default class Api {
* @param videoId Video ID * @param videoId Video ID
* @returns Video Data * @returns Video Data
*/ */
public async getVideo(videoId: string): Promise<YTMusic.VideoFull> { public async getVideo(videoId: string): Promise<VideoFull> {
const data = await this.constructRequest("player", { videoId }) const data = await this.constructRequest("player", { videoId })
return VideoParser.parse(data) return VideoParser.parse(data)
@ -266,7 +277,7 @@ export default class Api {
* @param artistId Artist ID * @param artistId Artist ID
* @returns Artist Data * @returns Artist Data
*/ */
public async getArtist(artistId: string): Promise<YTMusic.ArtistFull> { public async getArtist(artistId: string): Promise<ArtistFull> {
const data = await this.constructRequest("browse", { browseId: artistId }) const data = await this.constructRequest("browse", { browseId: artistId })
return ArtistParser.parse(data, artistId) return ArtistParser.parse(data, artistId)
@ -278,7 +289,7 @@ export default class Api {
* @param artistId Artist ID * @param artistId Artist ID
* @returns Artist's Songs * @returns Artist's Songs
*/ */
public async getArtistSongs(artistId: string): Promise<YTMusic.SongDetailed[]> { public async getArtistSongs(artistId: string): Promise<SongDetailed[]> {
const artistData = await this.constructRequest("browse", { browseId: artistId }) const artistData = await this.constructRequest("browse", { browseId: artistId })
const browseToken = traverse(artistData, "musicShelfRenderer", "title", "browseId") const browseToken = traverse(artistData, "musicShelfRenderer", "title", "browseId")
@ -302,7 +313,7 @@ export default class Api {
* @param artistId Artist ID * @param artistId Artist ID
* @returns Artist's Albums * @returns Artist's Albums
*/ */
public async getArtistAlbums(artistId: string): Promise<YTMusic.AlbumDetailed[]> { public async getArtistAlbums(artistId: string): Promise<AlbumDetailed[]> {
const artistData = await this.constructRequest("browse", { browseId: artistId }) const artistData = await this.constructRequest("browse", { browseId: artistId })
const artistAlbumsData = traverse(artistData, "musicCarouselShelfRenderer")[0] const artistAlbumsData = traverse(artistData, "musicCarouselShelfRenderer")[0]
const browseBody = traverse(artistAlbumsData, "moreContentButton", "browseEndpoint") const browseBody = traverse(artistAlbumsData, "moreContentButton", "browseEndpoint")
@ -323,7 +334,7 @@ export default class Api {
* @param albumId Album ID * @param albumId Album ID
* @returns Album Data * @returns Album Data
*/ */
public async getAlbum(albumId: string): Promise<YTMusic.AlbumFull> { public async getAlbum(albumId: string): Promise<AlbumFull> {
const data = await this.constructRequest("browse", { browseId: albumId }) const data = await this.constructRequest("browse", { browseId: albumId })
return AlbumParser.parse(data, albumId) return AlbumParser.parse(data, albumId)
@ -335,7 +346,7 @@ export default class Api {
* @param playlistId Playlist ID * @param playlistId Playlist ID
* @returns Playlist Data * @returns Playlist Data
*/ */
public async getPlaylist(playlistId: string): Promise<YTMusic.PlaylistFull> { public async getPlaylist(playlistId: string): Promise<PlaylistFull> {
if (playlistId.startsWith("PL")) playlistId = "VL" + playlistId if (playlistId.startsWith("PL")) playlistId = "VL" + playlistId
const data = await this.constructRequest("browse", { browseId: playlistId }) const data = await this.constructRequest("browse", { browseId: playlistId })
@ -348,9 +359,7 @@ export default class Api {
* @param playlistId Playlist ID * @param playlistId Playlist ID
* @returns Playlist's Videos * @returns Playlist's Videos
*/ */
public async getPlaylistVideos( public async getPlaylistVideos(playlistId: string): Promise<Omit<VideoDetailed, "views">[]> {
playlistId: string
): Promise<Omit<YTMusic.VideoDetailed, "views">[]> {
if (playlistId.startsWith("PL")) playlistId = "VL" + playlistId if (playlistId.startsWith("PL")) playlistId = "VL" + playlistId
const playlistData = await this.constructRequest("browse", { browseId: playlistId }) const playlistData = await this.constructRequest("browse", { browseId: playlistId })

View File

@ -1,15 +1,12 @@
import Api from "./Api" import YTMusic from "./YTMusic"
declare namespace YTMusic { export interface ThumbnailFull {
export { Api }
export interface ThumbnailFull {
url: string url: string
width: number width: number
height: number height: number
} }
export interface SongDetailed { export interface SongDetailed {
type: "SONG" type: "SONG"
videoId: string | null videoId: string | null
name: string name: string
@ -17,15 +14,15 @@ declare namespace YTMusic {
album: AlbumBasic album: AlbumBasic
duration: number duration: number
thumbnails: ThumbnailFull[] thumbnails: ThumbnailFull[]
} }
export interface SongFull extends Omit<SongDetailed, "album"> { export interface SongFull extends Omit<SongDetailed, "album"> {
description: string description: string
formats: any[] formats: any[]
adaptiveFormats: any[] adaptiveFormats: any[]
} }
export interface VideoDetailed { export interface VideoDetailed {
type: "VIDEO" type: "VIDEO"
videoId: string | null videoId: string | null
name: string name: string
@ -33,67 +30,66 @@ declare namespace YTMusic {
views: number views: number
duration: number duration: number
thumbnails: ThumbnailFull[] thumbnails: ThumbnailFull[]
} }
export interface VideoFull extends VideoDetailed { export interface VideoFull extends VideoDetailed {
description: string description: string
unlisted: boolean unlisted: boolean
familySafe: boolean familySafe: boolean
paid: boolean paid: boolean
tags: string[] tags: string[]
} }
export interface ArtistBasic { export interface ArtistBasic {
artistId: string | null artistId: string | null
name: string name: string
} }
export interface ArtistDetailed extends ArtistBasic { export interface ArtistDetailed extends ArtistBasic {
type: "ARTIST" type: "ARTIST"
artistId: string artistId: string
thumbnails: ThumbnailFull[] thumbnails: ThumbnailFull[]
} }
export interface ArtistFull extends ArtistDetailed { export interface ArtistFull extends ArtistDetailed {
description: string | null description: string | null
subscribers: number subscribers: number
topSongs: Omit<SongDetailed, "duration">[] topSongs: Omit<SongDetailed, "duration">[]
topAlbums: AlbumDetailed[] topAlbums: AlbumDetailed[]
} }
export interface AlbumBasic { export interface AlbumBasic {
albumId: string albumId: string
name: string name: string
} }
export interface AlbumDetailed extends AlbumBasic { export interface AlbumDetailed extends AlbumBasic {
type: "ALBUM" type: "ALBUM"
playlistId: string playlistId: string
artists: ArtistBasic[] artists: ArtistBasic[]
year: number year: number
thumbnails: ThumbnailFull[] thumbnails: ThumbnailFull[]
} }
export interface AlbumFull extends AlbumDetailed { export interface AlbumFull extends AlbumDetailed {
description: string | null description: string | null
songs: SongDetailed[] songs: SongDetailed[]
} }
export interface PlaylistFull { export interface PlaylistFull {
type: "PLAYLIST" type: "PLAYLIST"
playlistId: string playlistId: string
name: string name: string
artist: ArtistBasic artist: ArtistBasic
videoCount: number videoCount: number
thumbnails: ThumbnailFull[] thumbnails: ThumbnailFull[]
} }
export type SearchResult = export type SearchResult =
| SongDetailed | SongDetailed
| VideoDetailed | VideoDetailed
| AlbumDetailed | AlbumDetailed
| ArtistDetailed | ArtistDetailed
| PlaylistFull | PlaylistFull
}
export default YTMusic export default YTMusic

View File

@ -1,9 +1,9 @@
import SongParser from "./SongParser" import SongParser from "./SongParser"
import traverse from "../utils/traverse" import traverse from "../utils/traverse"
import YTMusic from ".." import { AlbumDetailed, AlbumFull, ArtistBasic } from ".."
export default class AlbumParser { export default class AlbumParser {
public static parse(data: any, albumId: string): YTMusic.AlbumFull { public static parse(data: any, albumId: string): AlbumFull {
const albumBasic = { const albumBasic = {
albumId, albumId,
name: traverse(data, "header", "title", "text").at(0) name: traverse(data, "header", "title", "text").at(0)
@ -30,7 +30,7 @@ export default class AlbumParser {
} }
} }
public static parseSearchResult(item: any): YTMusic.AlbumDetailed { public static parseSearchResult(item: any): AlbumDetailed {
const flexColumns = traverse(item, "flexColumns") const flexColumns = traverse(item, "flexColumns")
return { return {
@ -46,10 +46,7 @@ export default class AlbumParser {
} }
} }
public static parseArtistAlbum( public static parseArtistAlbum(item: any, artistBasic: ArtistBasic): AlbumDetailed {
item: any,
artistBasic: YTMusic.ArtistBasic
): YTMusic.AlbumDetailed {
return { return {
type: "ALBUM", type: "ALBUM",
albumId: [traverse(item, "browseId")].flat().at(-1), albumId: [traverse(item, "browseId")].flat().at(-1),
@ -61,10 +58,7 @@ export default class AlbumParser {
} }
} }
public static parseArtistTopAlbums( public static parseArtistTopAlbums(item: any, artistBasic: ArtistBasic): AlbumDetailed {
item: any,
artistBasic: YTMusic.ArtistBasic
): YTMusic.AlbumDetailed {
return { return {
type: "ALBUM", type: "ALBUM",
albumId: traverse(item, "browseId").at(-1), albumId: traverse(item, "browseId").at(-1),

View File

@ -2,10 +2,10 @@ import AlbumParser from "./AlbumParser"
import Parser from "./Parser" import Parser from "./Parser"
import SongParser from "./SongParser" import SongParser from "./SongParser"
import traverse from "../utils/traverse" import traverse from "../utils/traverse"
import YTMusic from ".." import { ArtistDetailed, ArtistFull } from ".."
export default class ArtistParser { export default class ArtistParser {
public static parse(data: any, artistId: string): YTMusic.ArtistFull { public static parse(data: any, artistId: string): ArtistFull {
const artistBasic = { const artistBasic = {
artistId, artistId,
name: traverse(data, "header", "title", "text").at(0) name: traverse(data, "header", "title", "text").at(0)
@ -29,7 +29,7 @@ export default class ArtistParser {
} }
} }
public static parseSearchResult(item: any): YTMusic.ArtistDetailed { public static parseSearchResult(item: any): ArtistDetailed {
const flexColumns = traverse(item, "flexColumns") const flexColumns = traverse(item, "flexColumns")
return { return {

View File

@ -1,8 +1,8 @@
import traverse from "../utils/traverse" import traverse from "../utils/traverse"
import YTMusic from ".." import { PlaylistFull } from ".."
export default class PlaylistParser { export default class PlaylistParser {
public static parse(data: any, playlistId: string): YTMusic.PlaylistFull { public static parse(data: any, playlistId: string): PlaylistFull {
return { return {
type: "PLAYLIST", type: "PLAYLIST",
playlistId, playlistId,
@ -20,7 +20,7 @@ export default class PlaylistParser {
} }
} }
public static parseSearchResult(item: any): YTMusic.PlaylistFull { public static parseSearchResult(item: any): PlaylistFull {
const flexColumns = traverse(item, "flexColumns") const flexColumns = traverse(item, "flexColumns")
const artistId = traverse(flexColumns[1], "browseId") const artistId = traverse(flexColumns[1], "browseId")

View File

@ -4,10 +4,10 @@ import PlaylistParser from "./PlaylistParser"
import SongParser from "./SongParser" import SongParser from "./SongParser"
import traverse from "../utils/traverse" import traverse from "../utils/traverse"
import VideoParser from "./VideoParser" import VideoParser from "./VideoParser"
import YTMusic from ".." import { SearchResult } from ".."
export default class SearchParser { export default class SearchParser {
public static parse(item: any): YTMusic.SearchResult { public static parse(item: any): SearchResult {
const flexColumns = traverse(item, "flexColumns") const flexColumns = traverse(item, "flexColumns")
const type = traverse(flexColumns[1], "runs", "text").at(0) as const type = traverse(flexColumns[1], "runs", "text").at(0) as
| "Song" | "Song"

View File

@ -1,9 +1,9 @@
import Parser from "./Parser" import Parser from "./Parser"
import traverse from "../utils/traverse" import traverse from "../utils/traverse"
import YTMusic from ".." import { AlbumBasic, ArtistBasic, SongDetailed, SongFull, ThumbnailFull } from ".."
export default class SongParser { export default class SongParser {
public static parse(data: any): YTMusic.SongFull { public static parse(data: any): SongFull {
return { return {
type: "SONG", type: "SONG",
videoId: traverse(data, "videoDetails", "videoId"), videoId: traverse(data, "videoDetails", "videoId"),
@ -22,7 +22,7 @@ export default class SongParser {
} }
} }
public static parseSearchResult(item: any): YTMusic.SongDetailed { public static parseSearchResult(item: any): SongDetailed {
const flexColumns = traverse(item, "flexColumns") const flexColumns = traverse(item, "flexColumns")
const videoId = traverse(item, "playlistItemData", "videoId") const videoId = traverse(item, "playlistItemData", "videoId")
@ -43,7 +43,7 @@ export default class SongParser {
} }
} }
public static parseArtistSong(item: any): YTMusic.SongDetailed { public static parseArtistSong(item: any): SongDetailed {
const flexColumns = traverse(item, "flexColumns") const flexColumns = traverse(item, "flexColumns")
const videoId = traverse(item, "playlistItemData", "videoId") const videoId = traverse(item, "playlistItemData", "videoId")
@ -69,8 +69,8 @@ export default class SongParser {
public static parseArtistTopSong( public static parseArtistTopSong(
item: any, item: any,
artistBasic: YTMusic.ArtistBasic artistBasic: ArtistBasic
): Omit<YTMusic.SongDetailed, "duration"> { ): Omit<SongDetailed, "duration"> {
const flexColumns = traverse(item, "flexColumns") const flexColumns = traverse(item, "flexColumns")
const videoId = traverse(item, "playlistItemData", "videoId") const videoId = traverse(item, "playlistItemData", "videoId")
@ -89,10 +89,10 @@ export default class SongParser {
public static parseAlbumSong( public static parseAlbumSong(
item: any, item: any,
artists: YTMusic.ArtistBasic[], artists: ArtistBasic[],
albumBasic: YTMusic.AlbumBasic, albumBasic: AlbumBasic,
thumbnails: YTMusic.ThumbnailFull[] thumbnails: ThumbnailFull[]
): YTMusic.SongDetailed { ): SongDetailed {
const flexColumns = traverse(item, "flexColumns") const flexColumns = traverse(item, "flexColumns")
const videoId = traverse(item, "playlistItemData", "videoId") const videoId = traverse(item, "playlistItemData", "videoId")

View File

@ -1,9 +1,9 @@
import Parser from "./Parser" import Parser from "./Parser"
import traverse from "../utils/traverse" import traverse from "../utils/traverse"
import YTMusic from ".." import { VideoDetailed, VideoFull } from ".."
export default class VideoParser { export default class VideoParser {
public static parse(data: any): YTMusic.VideoFull { public static parse(data: any): VideoFull {
return { return {
type: "VIDEO", type: "VIDEO",
videoId: traverse(data, "videoDetails", "videoId"), videoId: traverse(data, "videoDetails", "videoId"),
@ -25,7 +25,7 @@ export default class VideoParser {
} }
} }
public static parseSearchResult(item: any): YTMusic.VideoDetailed { public static parseSearchResult(item: any): VideoDetailed {
const flexColumns = traverse(item, "flexColumns") const flexColumns = traverse(item, "flexColumns")
const videoId = traverse(item, "playNavigationEndpoint", "videoId") const videoId = traverse(item, "playNavigationEndpoint", "videoId")
@ -43,7 +43,7 @@ export default class VideoParser {
} }
} }
public static parsePlaylistVideo(item: any): Omit<YTMusic.VideoDetailed, "views"> { public static parsePlaylistVideo(item: any): Omit<VideoDetailed, "views"> {
const flexColumns = traverse(item, "flexColumns") const flexColumns = traverse(item, "flexColumns")
const videoId = traverse(item, "playNavigationEndpoint", "videoId") const videoId = traverse(item, "playNavigationEndpoint", "videoId")

View File

@ -1,5 +1,5 @@
import Validator from "validate-any/build/classes/Validator" import Validator from "validate-any/build/classes/Validator"
import YTMusicApi from "../Api" import YTMusic from "../YTMusic"
import { import {
ALBUM_DETAILED, ALBUM_DETAILED,
ALBUM_FULL, ALBUM_FULL,
@ -15,7 +15,7 @@ import {
import { LIST, validate } from "validate-any" import { LIST, validate } from "validate-any"
const queries = ["Lilac", "Weekend", "Yours Raiden", "Eminem", "Lisa Hannigan"] const queries = ["Lilac", "Weekend", "Yours Raiden", "Eminem", "Lisa Hannigan"]
const ytmusic = new YTMusicApi() const ytmusic = new YTMusic()
ytmusic.initialize().then(() => ytmusic.initialize().then(() =>
queries.forEach(async query => { queries.forEach(async query => {

View File

@ -1,24 +1,37 @@
import ObjectValidator from "validate-any/build/validators/ObjectValidator" import ObjectValidator from "validate-any/build/validators/ObjectValidator"
import YTMusic from "../index" import {
AlbumBasic,
AlbumDetailed,
AlbumFull,
ArtistBasic,
ArtistDetailed,
ArtistFull,
PlaylistFull,
SongDetailed,
SongFull,
ThumbnailFull,
VideoDetailed,
VideoFull
} from "../index"
import { BOOLEAN, LIST, NULL, NUMBER, OBJECT, OR, STRING } from "validate-any" import { BOOLEAN, LIST, NULL, NUMBER, OBJECT, OR, STRING } from "validate-any"
export const THUMBNAIL_FULL: ObjectValidator<YTMusic.ThumbnailFull> = OBJECT({ export const THUMBNAIL_FULL: ObjectValidator<ThumbnailFull> = OBJECT({
url: STRING(), url: STRING(),
width: NUMBER(), width: NUMBER(),
height: NUMBER() height: NUMBER()
}) })
export const ARTIST_BASIC: ObjectValidator<YTMusic.ArtistBasic> = OBJECT({ export const ARTIST_BASIC: ObjectValidator<ArtistBasic> = OBJECT({
artistId: OR(STRING(), NULL()), artistId: OR(STRING(), NULL()),
name: STRING() name: STRING()
}) })
export const ALBUM_BASIC: ObjectValidator<YTMusic.AlbumBasic> = OBJECT({ export const ALBUM_BASIC: ObjectValidator<AlbumBasic> = OBJECT({
albumId: STRING(), albumId: STRING(),
name: STRING() name: STRING()
}) })
export const SONG_DETAILED: ObjectValidator<YTMusic.SongDetailed> = OBJECT({ export const SONG_DETAILED: ObjectValidator<SongDetailed> = OBJECT({
type: STRING("SONG"), type: STRING("SONG"),
videoId: OR(STRING(), NULL()), videoId: OR(STRING(), NULL()),
name: STRING(), name: STRING(),
@ -28,7 +41,7 @@ export const SONG_DETAILED: ObjectValidator<YTMusic.SongDetailed> = OBJECT({
thumbnails: LIST(THUMBNAIL_FULL) thumbnails: LIST(THUMBNAIL_FULL)
}) })
export const VIDEO_DETAILED: ObjectValidator<YTMusic.VideoDetailed> = OBJECT({ export const VIDEO_DETAILED: ObjectValidator<VideoDetailed> = OBJECT({
type: STRING("VIDEO"), type: STRING("VIDEO"),
videoId: OR(STRING(), NULL()), videoId: OR(STRING(), NULL()),
name: STRING(), name: STRING(),
@ -38,14 +51,14 @@ export const VIDEO_DETAILED: ObjectValidator<YTMusic.VideoDetailed> = OBJECT({
thumbnails: LIST(THUMBNAIL_FULL) thumbnails: LIST(THUMBNAIL_FULL)
}) })
export const ARTIST_DETAILED: ObjectValidator<YTMusic.ArtistDetailed> = OBJECT({ export const ARTIST_DETAILED: ObjectValidator<ArtistDetailed> = OBJECT({
artistId: STRING(), artistId: STRING(),
name: STRING(), name: STRING(),
type: STRING("ARTIST"), type: STRING("ARTIST"),
thumbnails: LIST(THUMBNAIL_FULL) thumbnails: LIST(THUMBNAIL_FULL)
}) })
export const ALBUM_DETAILED: ObjectValidator<YTMusic.AlbumDetailed> = OBJECT({ export const ALBUM_DETAILED: ObjectValidator<AlbumDetailed> = OBJECT({
type: STRING("ALBUM"), type: STRING("ALBUM"),
albumId: STRING(), albumId: STRING(),
playlistId: STRING(), playlistId: STRING(),
@ -55,7 +68,7 @@ export const ALBUM_DETAILED: ObjectValidator<YTMusic.AlbumDetailed> = OBJECT({
thumbnails: LIST(THUMBNAIL_FULL) thumbnails: LIST(THUMBNAIL_FULL)
}) })
export const SONG_FULL: ObjectValidator<YTMusic.SongFull> = OBJECT({ export const SONG_FULL: ObjectValidator<SongFull> = OBJECT({
type: STRING("SONG"), type: STRING("SONG"),
videoId: OR(STRING(), NULL()), videoId: OR(STRING(), NULL()),
name: STRING(), name: STRING(),
@ -67,7 +80,7 @@ export const SONG_FULL: ObjectValidator<YTMusic.SongFull> = OBJECT({
adaptiveFormats: LIST(OBJECT()) adaptiveFormats: LIST(OBJECT())
}) })
export const VIDEO_FULL: ObjectValidator<YTMusic.VideoFull> = OBJECT({ export const VIDEO_FULL: ObjectValidator<VideoFull> = OBJECT({
type: STRING("VIDEO"), type: STRING("VIDEO"),
videoId: OR(STRING(), NULL()), videoId: OR(STRING(), NULL()),
name: STRING(), name: STRING(),
@ -82,7 +95,7 @@ export const VIDEO_FULL: ObjectValidator<YTMusic.VideoFull> = OBJECT({
tags: LIST(STRING()) tags: LIST(STRING())
}) })
export const ARTIST_FULL: ObjectValidator<YTMusic.ArtistFull> = OBJECT({ export const ARTIST_FULL: ObjectValidator<ArtistFull> = OBJECT({
artistId: STRING(), artistId: STRING(),
name: STRING(), name: STRING(),
type: STRING("ARTIST"), type: STRING("ARTIST"),
@ -102,7 +115,7 @@ export const ARTIST_FULL: ObjectValidator<YTMusic.ArtistFull> = OBJECT({
topAlbums: LIST(ALBUM_DETAILED) topAlbums: LIST(ALBUM_DETAILED)
}) })
export const ALBUM_FULL: ObjectValidator<YTMusic.AlbumFull> = OBJECT({ export const ALBUM_FULL: ObjectValidator<AlbumFull> = OBJECT({
type: STRING("ALBUM"), type: STRING("ALBUM"),
albumId: STRING(), albumId: STRING(),
playlistId: STRING(), playlistId: STRING(),
@ -114,7 +127,7 @@ export const ALBUM_FULL: ObjectValidator<YTMusic.AlbumFull> = OBJECT({
songs: LIST(SONG_DETAILED) songs: LIST(SONG_DETAILED)
}) })
export const PLAYLIST_DETAILED: ObjectValidator<YTMusic.PlaylistFull> = OBJECT({ export const PLAYLIST_DETAILED: ObjectValidator<PlaylistFull> = OBJECT({
type: STRING("PLAYLIST"), type: STRING("PLAYLIST"),
playlistId: STRING(), playlistId: STRING(),
name: STRING(), name: STRING(),
@ -123,7 +136,7 @@ export const PLAYLIST_DETAILED: ObjectValidator<YTMusic.PlaylistFull> = OBJECT({
thumbnails: LIST(THUMBNAIL_FULL) thumbnails: LIST(THUMBNAIL_FULL)
}) })
export const PLAYLIST_VIDEO: ObjectValidator<Omit<YTMusic.VideoDetailed, "views">> = OBJECT({ export const PLAYLIST_VIDEO: ObjectValidator<Omit<VideoDetailed, "views">> = OBJECT({
type: STRING("VIDEO"), type: STRING("VIDEO"),
videoId: OR(STRING(), NULL()), videoId: OR(STRING(), NULL()),
name: STRING(), name: STRING(),

View File

@ -1,6 +1,6 @@
import YTMusicApi from "../Api" import YTMusic from "../YTMusic"
const ytmusic = new YTMusicApi() const ytmusic = new YTMusic()
ytmusic.initialize().then(() => { ytmusic.initialize().then(() => {
ytmusic.search("Lilac", "SONG").then(res => { ytmusic.search("Lilac", "SONG").then(res => {
ytmusic.getSong(res.find(r => !!r.videoId)!.videoId!).then(res => { ytmusic.getSong(res.find(r => !!r.videoId)!.videoId!).then(res => {