Using jest for testing instead of doing it manually
This commit is contained in:
parent
75d85764c3
commit
2154dc67ab
|
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
["@babel/preset-env", { targets: { node: "current" } }],
|
||||||
|
"@babel/preset-typescript"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -10,12 +10,21 @@
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/zS1L3NT/ts-npm-ytmusic-api"
|
"url": "https://github.com/zS1L3NT/ts-npm-ytmusic-api"
|
||||||
},
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "jest"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.25.0",
|
"axios": "^0.25.0",
|
||||||
|
"jest": "^27.4.7",
|
||||||
"tough-cookie": "^4.0.0"
|
"tough-cookie": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.17.0",
|
||||||
|
"@babel/preset-env": "^7.16.11",
|
||||||
|
"@babel/preset-typescript": "^7.16.7",
|
||||||
|
"@types/jest": "^27.4.0",
|
||||||
"@types/tough-cookie": "^4.0.1",
|
"@types/tough-cookie": "^4.0.1",
|
||||||
|
"babel-jest": "^27.4.6",
|
||||||
"typescript": "^4.5.5",
|
"typescript": "^4.5.5",
|
||||||
"validate-any": "^1.2.0"
|
"validate-any": "^1.2.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ export default class YTMusic {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const cookieString of cookieStrings) {
|
for (const cookieString of cookieStrings) {
|
||||||
const cookie = Cookie.parse(cookieString)
|
const cookie = Cookie.parse(`${cookieString}`)
|
||||||
if (!cookie) return
|
if (!cookie) return
|
||||||
|
|
||||||
this.cookiejar.setCookieSync(cookie, res.config.baseURL)
|
this.cookiejar.setCookieSync(cookie, res.config.baseURL)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,337 @@
|
||||||
|
import ObjectValidator from "validate-any/dist/validators/ObjectValidator"
|
||||||
|
import Validator from "validate-any/dist/classes/Validator"
|
||||||
|
import YTMusic, {
|
||||||
|
AlbumBasic,
|
||||||
|
AlbumDetailed,
|
||||||
|
AlbumFull,
|
||||||
|
ArtistBasic,
|
||||||
|
ArtistDetailed,
|
||||||
|
ArtistFull,
|
||||||
|
PlaylistFull,
|
||||||
|
SongDetailed,
|
||||||
|
SongFull,
|
||||||
|
ThumbnailFull,
|
||||||
|
VideoDetailed,
|
||||||
|
VideoFull
|
||||||
|
} from ".."
|
||||||
|
import {
|
||||||
|
BOOLEAN,
|
||||||
|
iValidationError,
|
||||||
|
LIST,
|
||||||
|
NULL,
|
||||||
|
NUMBER,
|
||||||
|
OBJECT,
|
||||||
|
OR,
|
||||||
|
STRING,
|
||||||
|
validate
|
||||||
|
} from "validate-any"
|
||||||
|
|
||||||
|
//#region Interfaces
|
||||||
|
const THUMBNAIL_FULL: ObjectValidator<ThumbnailFull> = OBJECT({
|
||||||
|
url: STRING(),
|
||||||
|
width: NUMBER(),
|
||||||
|
height: NUMBER()
|
||||||
|
})
|
||||||
|
|
||||||
|
const ARTIST_BASIC: ObjectValidator<ArtistBasic> = OBJECT({
|
||||||
|
artistId: OR(STRING(), NULL()),
|
||||||
|
name: STRING()
|
||||||
|
})
|
||||||
|
|
||||||
|
const ALBUM_BASIC: ObjectValidator<AlbumBasic> = OBJECT({
|
||||||
|
albumId: STRING(),
|
||||||
|
name: STRING()
|
||||||
|
})
|
||||||
|
|
||||||
|
const SONG_DETAILED: ObjectValidator<SongDetailed> = OBJECT({
|
||||||
|
type: STRING("SONG"),
|
||||||
|
videoId: OR(STRING(), NULL()),
|
||||||
|
name: STRING(),
|
||||||
|
artists: LIST(ARTIST_BASIC),
|
||||||
|
album: ALBUM_BASIC,
|
||||||
|
duration: NUMBER(),
|
||||||
|
thumbnails: LIST(THUMBNAIL_FULL)
|
||||||
|
})
|
||||||
|
|
||||||
|
const VIDEO_DETAILED: ObjectValidator<VideoDetailed> = OBJECT({
|
||||||
|
type: STRING("VIDEO"),
|
||||||
|
videoId: OR(STRING(), NULL()),
|
||||||
|
name: STRING(),
|
||||||
|
artists: LIST(ARTIST_BASIC),
|
||||||
|
views: NUMBER(),
|
||||||
|
duration: NUMBER(),
|
||||||
|
thumbnails: LIST(THUMBNAIL_FULL)
|
||||||
|
})
|
||||||
|
|
||||||
|
const ARTIST_DETAILED: ObjectValidator<ArtistDetailed> = OBJECT({
|
||||||
|
artistId: STRING(),
|
||||||
|
name: STRING(),
|
||||||
|
type: STRING("ARTIST"),
|
||||||
|
thumbnails: LIST(THUMBNAIL_FULL)
|
||||||
|
})
|
||||||
|
|
||||||
|
const ALBUM_DETAILED: ObjectValidator<AlbumDetailed> = OBJECT({
|
||||||
|
type: STRING("ALBUM"),
|
||||||
|
albumId: STRING(),
|
||||||
|
playlistId: STRING(),
|
||||||
|
name: STRING(),
|
||||||
|
artists: LIST(ARTIST_BASIC),
|
||||||
|
year: NUMBER(),
|
||||||
|
thumbnails: LIST(THUMBNAIL_FULL)
|
||||||
|
})
|
||||||
|
|
||||||
|
const SONG_FULL: ObjectValidator<SongFull> = OBJECT({
|
||||||
|
type: STRING("SONG"),
|
||||||
|
videoId: OR(STRING(), NULL()),
|
||||||
|
name: STRING(),
|
||||||
|
artists: LIST(ARTIST_BASIC),
|
||||||
|
duration: NUMBER(),
|
||||||
|
thumbnails: LIST(THUMBNAIL_FULL),
|
||||||
|
description: STRING(),
|
||||||
|
formats: LIST(OBJECT()),
|
||||||
|
adaptiveFormats: LIST(OBJECT())
|
||||||
|
})
|
||||||
|
|
||||||
|
const VIDEO_FULL: ObjectValidator<VideoFull> = OBJECT({
|
||||||
|
type: STRING("VIDEO"),
|
||||||
|
videoId: OR(STRING(), NULL()),
|
||||||
|
name: STRING(),
|
||||||
|
artists: LIST(ARTIST_BASIC),
|
||||||
|
views: NUMBER(),
|
||||||
|
duration: NUMBER(),
|
||||||
|
thumbnails: LIST(THUMBNAIL_FULL),
|
||||||
|
description: STRING(),
|
||||||
|
unlisted: BOOLEAN(),
|
||||||
|
familySafe: BOOLEAN(),
|
||||||
|
paid: BOOLEAN(),
|
||||||
|
tags: LIST(STRING())
|
||||||
|
})
|
||||||
|
|
||||||
|
const ARTIST_FULL: ObjectValidator<ArtistFull> = OBJECT({
|
||||||
|
artistId: STRING(),
|
||||||
|
name: STRING(),
|
||||||
|
type: STRING("ARTIST"),
|
||||||
|
thumbnails: LIST(THUMBNAIL_FULL),
|
||||||
|
description: OR(STRING(), NULL()),
|
||||||
|
subscribers: NUMBER(),
|
||||||
|
topSongs: LIST(
|
||||||
|
OBJECT({
|
||||||
|
type: STRING("SONG"),
|
||||||
|
videoId: STRING(),
|
||||||
|
name: STRING(),
|
||||||
|
artists: LIST(ARTIST_BASIC),
|
||||||
|
album: ALBUM_BASIC,
|
||||||
|
thumbnails: LIST(THUMBNAIL_FULL)
|
||||||
|
})
|
||||||
|
),
|
||||||
|
topAlbums: LIST(ALBUM_DETAILED)
|
||||||
|
})
|
||||||
|
|
||||||
|
const ALBUM_FULL: ObjectValidator<AlbumFull> = OBJECT({
|
||||||
|
type: STRING("ALBUM"),
|
||||||
|
albumId: STRING(),
|
||||||
|
playlistId: STRING(),
|
||||||
|
name: STRING(),
|
||||||
|
artists: LIST(ARTIST_BASIC),
|
||||||
|
year: NUMBER(),
|
||||||
|
thumbnails: LIST(THUMBNAIL_FULL),
|
||||||
|
description: OR(STRING(), NULL()),
|
||||||
|
songs: LIST(SONG_DETAILED)
|
||||||
|
})
|
||||||
|
|
||||||
|
const PLAYLIST_DETAILED: ObjectValidator<PlaylistFull> = OBJECT({
|
||||||
|
type: STRING("PLAYLIST"),
|
||||||
|
playlistId: STRING(),
|
||||||
|
name: STRING(),
|
||||||
|
artist: ARTIST_BASIC,
|
||||||
|
videoCount: NUMBER(),
|
||||||
|
thumbnails: LIST(THUMBNAIL_FULL)
|
||||||
|
})
|
||||||
|
|
||||||
|
const PLAYLIST_VIDEO: ObjectValidator<Omit<VideoDetailed, "views">> = OBJECT({
|
||||||
|
type: STRING("VIDEO"),
|
||||||
|
videoId: OR(STRING(), NULL()),
|
||||||
|
name: STRING(),
|
||||||
|
artists: LIST(ARTIST_BASIC),
|
||||||
|
duration: NUMBER(),
|
||||||
|
thumbnails: LIST(THUMBNAIL_FULL)
|
||||||
|
})
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
const issues: iValidationError[][] = []
|
||||||
|
const queries = ["Lilac", "Weekend", "Eill", "Eminem", "Lisa Hannigan"]
|
||||||
|
const _expect = (data: any, validator: Validator<any>) => {
|
||||||
|
const { errors } = validate(data, validator)
|
||||||
|
if (errors.length > 0) {
|
||||||
|
issues.push(errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(errors.length).toBe(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const ytmusic = new YTMusic()
|
||||||
|
|
||||||
|
beforeAll(() => ytmusic.initialize())
|
||||||
|
|
||||||
|
queries.forEach(query => {
|
||||||
|
describe("Query: " + query, () => {
|
||||||
|
test("Search Songs", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "SONG")
|
||||||
|
.then(songs => {
|
||||||
|
_expect(songs, LIST(SONG_DETAILED))
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Search Videos", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "VIDEO")
|
||||||
|
.then(videos => {
|
||||||
|
_expect(videos, LIST(VIDEO_DETAILED))
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Search Artists", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "ARTIST")
|
||||||
|
.then(artists => {
|
||||||
|
_expect(artists, LIST(ARTIST_DETAILED))
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Search Albums", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "ALBUM")
|
||||||
|
.then(albums => {
|
||||||
|
_expect(albums, LIST(ALBUM_DETAILED))
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Search Playlists", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "PLAYLIST")
|
||||||
|
.then(playlists => {
|
||||||
|
_expect(playlists, LIST(PLAYLIST_DETAILED))
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Search All", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query)
|
||||||
|
.then(results => {
|
||||||
|
_expect(
|
||||||
|
results,
|
||||||
|
LIST(
|
||||||
|
ALBUM_DETAILED,
|
||||||
|
ARTIST_DETAILED,
|
||||||
|
PLAYLIST_DETAILED,
|
||||||
|
SONG_DETAILED,
|
||||||
|
VIDEO_DETAILED
|
||||||
|
)
|
||||||
|
)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Get details of the first song result", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "SONG")
|
||||||
|
.then(songs => ytmusic.getSong(songs[0]!.videoId!))
|
||||||
|
.then(song => {
|
||||||
|
_expect(song, SONG_FULL)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Get details of the first video result", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "VIDEO")
|
||||||
|
.then(videos => ytmusic.getVideo(videos[0]!.videoId!))
|
||||||
|
.then(video => {
|
||||||
|
_expect(video, VIDEO_FULL)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Get details of the first artist result", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "ARTIST")
|
||||||
|
.then(artists => ytmusic.getArtist(artists[0]!.artistId!))
|
||||||
|
.then(artist => {
|
||||||
|
_expect(artist, ARTIST_FULL)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Get the songs of the first artist result", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "ARTIST")
|
||||||
|
.then(artists => ytmusic.getArtistSongs(artists[0]!.artistId!))
|
||||||
|
.then(songs => {
|
||||||
|
_expect(songs, LIST(SONG_DETAILED))
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Get the albums of the first artist result", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "ARTIST")
|
||||||
|
.then(artists => ytmusic.getArtistAlbums(artists[0]!.artistId!))
|
||||||
|
.then(albums => {
|
||||||
|
_expect(albums, LIST(ALBUM_DETAILED))
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Get details of the first album result", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "ALBUM")
|
||||||
|
.then(albums => ytmusic.getAlbum(albums[0]!.albumId!))
|
||||||
|
.then(album => {
|
||||||
|
_expect(album, ALBUM_FULL)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Get details of the first playlist result", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "PLAYLIST")
|
||||||
|
.then(playlists => ytmusic.getPlaylist(playlists[0]!.playlistId!))
|
||||||
|
.then(playlist => {
|
||||||
|
_expect(playlist, PLAYLIST_DETAILED)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Get the videos of the first playlist result", done => {
|
||||||
|
ytmusic
|
||||||
|
.search(query, "PLAYLIST")
|
||||||
|
.then(playlists => ytmusic.getPlaylistVideos(playlists[0]!.playlistId!))
|
||||||
|
.then(videos => {
|
||||||
|
_expect(videos, LIST(PLAYLIST_VIDEO))
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => console.log("Issues:", issues))
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
import Validator from "validate-any/build/classes/Validator"
|
|
||||||
import YTMusic from "../YTMusic"
|
|
||||||
import {
|
|
||||||
ALBUM_DETAILED,
|
|
||||||
ALBUM_FULL,
|
|
||||||
ARTIST_DETAILED,
|
|
||||||
ARTIST_FULL,
|
|
||||||
PLAYLIST_DETAILED,
|
|
||||||
PLAYLIST_VIDEO,
|
|
||||||
SONG_DETAILED,
|
|
||||||
SONG_FULL,
|
|
||||||
VIDEO_DETAILED,
|
|
||||||
VIDEO_FULL
|
|
||||||
} from "./interfaces"
|
|
||||||
import { LIST, validate } from "validate-any"
|
|
||||||
|
|
||||||
const queries = ["Lilac", "Weekend", "Yours Raiden", "Eminem", "Lisa Hannigan"]
|
|
||||||
const ytmusic = new YTMusic()
|
|
||||||
|
|
||||||
ytmusic.initialize().then(() =>
|
|
||||||
queries.forEach(async query => {
|
|
||||||
const [songs, videos, artists, albums, playlists, results] = await Promise.all([
|
|
||||||
ytmusic.search(query, "SONG"),
|
|
||||||
ytmusic.search(query, "VIDEO"),
|
|
||||||
ytmusic.search(query, "ARTIST"),
|
|
||||||
ytmusic.search(query, "ALBUM"),
|
|
||||||
ytmusic.search(query, "PLAYLIST"),
|
|
||||||
ytmusic.search(query)
|
|
||||||
])
|
|
||||||
|
|
||||||
const [song, video, artist, artistSongs, artistAlbums, album, playlist, playlistVideos] =
|
|
||||||
await Promise.all([
|
|
||||||
ytmusic.getSong(songs[0].videoId!),
|
|
||||||
ytmusic.getVideo(videos[0].videoId!),
|
|
||||||
ytmusic.getArtist(artists[0].artistId),
|
|
||||||
ytmusic.getArtistSongs(artists[0].artistId),
|
|
||||||
ytmusic.getArtistAlbums(artists[0].artistId),
|
|
||||||
ytmusic.getAlbum(albums[0].albumId),
|
|
||||||
ytmusic.getPlaylist(playlists[0].playlistId),
|
|
||||||
ytmusic.getPlaylistVideos(playlists[0].playlistId)
|
|
||||||
])
|
|
||||||
|
|
||||||
const tests: [any, Validator<any>][] = [
|
|
||||||
[songs, LIST(SONG_DETAILED)],
|
|
||||||
[videos, LIST(VIDEO_DETAILED)],
|
|
||||||
[artists, LIST(ARTIST_DETAILED)],
|
|
||||||
[albums, LIST(ALBUM_DETAILED)],
|
|
||||||
[playlists, LIST(PLAYLIST_DETAILED)],
|
|
||||||
[
|
|
||||||
results,
|
|
||||||
LIST(
|
|
||||||
ALBUM_DETAILED,
|
|
||||||
ARTIST_DETAILED,
|
|
||||||
PLAYLIST_DETAILED,
|
|
||||||
SONG_DETAILED,
|
|
||||||
VIDEO_DETAILED
|
|
||||||
)
|
|
||||||
],
|
|
||||||
[song, SONG_FULL],
|
|
||||||
[video, VIDEO_FULL],
|
|
||||||
[artist, ARTIST_FULL],
|
|
||||||
[artistSongs, LIST(SONG_DETAILED)],
|
|
||||||
[artistAlbums, LIST(ALBUM_DETAILED)],
|
|
||||||
[album, ALBUM_FULL],
|
|
||||||
[playlist, PLAYLIST_DETAILED],
|
|
||||||
[playlistVideos, LIST(PLAYLIST_VIDEO)]
|
|
||||||
]
|
|
||||||
|
|
||||||
for (const [value, validator] of tests) {
|
|
||||||
const result = validate(value, validator)
|
|
||||||
if (!result.success) {
|
|
||||||
console.log(JSON.stringify(value))
|
|
||||||
console.log(validator.formatSchema())
|
|
||||||
console.log(result.errors)
|
|
||||||
process.exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Valid 🎉 - ${query}`)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
||||||
import ObjectValidator from "validate-any/build/validators/ObjectValidator"
|
|
||||||
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"
|
|
||||||
|
|
||||||
export const THUMBNAIL_FULL: ObjectValidator<ThumbnailFull> = OBJECT({
|
|
||||||
url: STRING(),
|
|
||||||
width: NUMBER(),
|
|
||||||
height: NUMBER()
|
|
||||||
})
|
|
||||||
|
|
||||||
export const ARTIST_BASIC: ObjectValidator<ArtistBasic> = OBJECT({
|
|
||||||
artistId: OR(STRING(), NULL()),
|
|
||||||
name: STRING()
|
|
||||||
})
|
|
||||||
|
|
||||||
export const ALBUM_BASIC: ObjectValidator<AlbumBasic> = OBJECT({
|
|
||||||
albumId: STRING(),
|
|
||||||
name: STRING()
|
|
||||||
})
|
|
||||||
|
|
||||||
export const SONG_DETAILED: ObjectValidator<SongDetailed> = OBJECT({
|
|
||||||
type: STRING("SONG"),
|
|
||||||
videoId: OR(STRING(), NULL()),
|
|
||||||
name: STRING(),
|
|
||||||
artists: LIST(ARTIST_BASIC),
|
|
||||||
album: ALBUM_BASIC,
|
|
||||||
duration: NUMBER(),
|
|
||||||
thumbnails: LIST(THUMBNAIL_FULL)
|
|
||||||
})
|
|
||||||
|
|
||||||
export const VIDEO_DETAILED: ObjectValidator<VideoDetailed> = OBJECT({
|
|
||||||
type: STRING("VIDEO"),
|
|
||||||
videoId: OR(STRING(), NULL()),
|
|
||||||
name: STRING(),
|
|
||||||
artists: LIST(ARTIST_BASIC),
|
|
||||||
views: NUMBER(),
|
|
||||||
duration: NUMBER(),
|
|
||||||
thumbnails: LIST(THUMBNAIL_FULL)
|
|
||||||
})
|
|
||||||
|
|
||||||
export const ARTIST_DETAILED: ObjectValidator<ArtistDetailed> = OBJECT({
|
|
||||||
artistId: STRING(),
|
|
||||||
name: STRING(),
|
|
||||||
type: STRING("ARTIST"),
|
|
||||||
thumbnails: LIST(THUMBNAIL_FULL)
|
|
||||||
})
|
|
||||||
|
|
||||||
export const ALBUM_DETAILED: ObjectValidator<AlbumDetailed> = OBJECT({
|
|
||||||
type: STRING("ALBUM"),
|
|
||||||
albumId: STRING(),
|
|
||||||
playlistId: STRING(),
|
|
||||||
name: STRING(),
|
|
||||||
artists: LIST(ARTIST_BASIC),
|
|
||||||
year: NUMBER(),
|
|
||||||
thumbnails: LIST(THUMBNAIL_FULL)
|
|
||||||
})
|
|
||||||
|
|
||||||
export const SONG_FULL: ObjectValidator<SongFull> = OBJECT({
|
|
||||||
type: STRING("SONG"),
|
|
||||||
videoId: OR(STRING(), NULL()),
|
|
||||||
name: STRING(),
|
|
||||||
artists: LIST(ARTIST_BASIC),
|
|
||||||
duration: NUMBER(),
|
|
||||||
thumbnails: LIST(THUMBNAIL_FULL),
|
|
||||||
description: STRING(),
|
|
||||||
formats: LIST(OBJECT()),
|
|
||||||
adaptiveFormats: LIST(OBJECT())
|
|
||||||
})
|
|
||||||
|
|
||||||
export const VIDEO_FULL: ObjectValidator<VideoFull> = OBJECT({
|
|
||||||
type: STRING("VIDEO"),
|
|
||||||
videoId: OR(STRING(), NULL()),
|
|
||||||
name: STRING(),
|
|
||||||
artists: LIST(ARTIST_BASIC),
|
|
||||||
views: NUMBER(),
|
|
||||||
duration: NUMBER(),
|
|
||||||
thumbnails: LIST(THUMBNAIL_FULL),
|
|
||||||
description: STRING(),
|
|
||||||
unlisted: BOOLEAN(),
|
|
||||||
familySafe: BOOLEAN(),
|
|
||||||
paid: BOOLEAN(),
|
|
||||||
tags: LIST(STRING())
|
|
||||||
})
|
|
||||||
|
|
||||||
export const ARTIST_FULL: ObjectValidator<ArtistFull> = OBJECT({
|
|
||||||
artistId: STRING(),
|
|
||||||
name: STRING(),
|
|
||||||
type: STRING("ARTIST"),
|
|
||||||
thumbnails: LIST(THUMBNAIL_FULL),
|
|
||||||
description: OR(STRING(), NULL()),
|
|
||||||
subscribers: NUMBER(),
|
|
||||||
topSongs: LIST(
|
|
||||||
OBJECT({
|
|
||||||
type: STRING("SONG"),
|
|
||||||
videoId: STRING(),
|
|
||||||
name: STRING(),
|
|
||||||
artists: LIST(ARTIST_BASIC),
|
|
||||||
album: ALBUM_BASIC,
|
|
||||||
thumbnails: LIST(THUMBNAIL_FULL)
|
|
||||||
})
|
|
||||||
),
|
|
||||||
topAlbums: LIST(ALBUM_DETAILED)
|
|
||||||
})
|
|
||||||
|
|
||||||
export const ALBUM_FULL: ObjectValidator<AlbumFull> = OBJECT({
|
|
||||||
type: STRING("ALBUM"),
|
|
||||||
albumId: STRING(),
|
|
||||||
playlistId: STRING(),
|
|
||||||
name: STRING(),
|
|
||||||
artists: LIST(ARTIST_BASIC),
|
|
||||||
year: NUMBER(),
|
|
||||||
thumbnails: LIST(THUMBNAIL_FULL),
|
|
||||||
description: OR(STRING(), NULL()),
|
|
||||||
songs: LIST(SONG_DETAILED)
|
|
||||||
})
|
|
||||||
|
|
||||||
export const PLAYLIST_DETAILED: ObjectValidator<PlaylistFull> = OBJECT({
|
|
||||||
type: STRING("PLAYLIST"),
|
|
||||||
playlistId: STRING(),
|
|
||||||
name: STRING(),
|
|
||||||
artist: ARTIST_BASIC,
|
|
||||||
videoCount: NUMBER(),
|
|
||||||
thumbnails: LIST(THUMBNAIL_FULL)
|
|
||||||
})
|
|
||||||
|
|
||||||
export const PLAYLIST_VIDEO: ObjectValidator<Omit<VideoDetailed, "views">> = OBJECT({
|
|
||||||
type: STRING("VIDEO"),
|
|
||||||
videoId: OR(STRING(), NULL()),
|
|
||||||
name: STRING(),
|
|
||||||
artists: LIST(ARTIST_BASIC),
|
|
||||||
duration: NUMBER(),
|
|
||||||
thumbnails: LIST(THUMBNAIL_FULL)
|
|
||||||
})
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
import YTMusic from "../YTMusic"
|
|
||||||
|
|
||||||
const ytmusic = new YTMusic()
|
|
||||||
ytmusic.initialize().then(() => {
|
|
||||||
ytmusic.search("Lilac", "SONG").then(res => {
|
|
||||||
ytmusic.getSong(res.find(r => !!r.videoId)!.videoId!).then(res => {
|
|
||||||
console.log(res)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
const traverse = (data: any, keys: string, single = false) => {
|
|
||||||
const again = (data: any, key: string): any => {
|
|
||||||
var res = []
|
|
||||||
|
|
||||||
data.hasOwnProperty(key) && res.push(data[key])
|
|
||||||
if (single && data.hasOwnProperty(key)) {
|
|
||||||
return res.shift()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data instanceof Array) {
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
res = res.concat(again(data[i], key))
|
|
||||||
}
|
|
||||||
} else if (data instanceof Object) {
|
|
||||||
const c = Object.keys(data)
|
|
||||||
if (c.length > 0) {
|
|
||||||
for (let i = 0; i < c.length; i++) {
|
|
||||||
res = res.concat(again(data[c[i]], key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res.length == 1 ? res.shift() : res
|
|
||||||
}
|
|
||||||
|
|
||||||
let z = keys.split(":"),
|
|
||||||
value = data
|
|
||||||
for (let i = 0; i < z.length; i++) {
|
|
||||||
value = again(value, z[i])
|
|
||||||
}
|
|
||||||
console.log(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
traverse(require("./data.json"), "playNavigationEndpoint:videoId")
|
|
||||||
|
|
||||||
export default {}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
const traverse = (data: any, keys: string[], single: boolean = false) => {
|
|
||||||
const again = (data: any, key: string): any => {
|
|
||||||
let res = []
|
|
||||||
|
|
||||||
if (data instanceof Object && key in data) {
|
|
||||||
res.push(data[key])
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data instanceof Array) {
|
|
||||||
res.push(...data.map(v => again(v, key)).flat())
|
|
||||||
} else if (data instanceof Object) {
|
|
||||||
res.push(
|
|
||||||
...Object.keys(data)
|
|
||||||
.map(k => again(data[k], key))
|
|
||||||
.flat()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.length === 1 ? res[0] : res
|
|
||||||
}
|
|
||||||
|
|
||||||
let value = data
|
|
||||||
for (const key of keys) {
|
|
||||||
value = again(value, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
traverse(require("./data.json")[0], ["playNavigationEndpoint", "videoId"], true)
|
|
||||||
|
|
||||||
export default {}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
const traverse = (data: any, ...keys: string[]) => {
|
|
||||||
const again = (data: any, key: string): any => {
|
|
||||||
let res = []
|
|
||||||
|
|
||||||
if (data instanceof Object && key in data) {
|
|
||||||
res.push(data[key])
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data instanceof Array) {
|
|
||||||
res.push(...data.map(v => again(v, key)).flat())
|
|
||||||
} else if (data instanceof Object) {
|
|
||||||
res.push(
|
|
||||||
...Object.keys(data)
|
|
||||||
.map(k => again(data[k], key))
|
|
||||||
.flat()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.length === 1 ? res[0] : res
|
|
||||||
}
|
|
||||||
|
|
||||||
let value = data
|
|
||||||
for (const key of keys) {
|
|
||||||
value = again(value, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
export default traverse
|
|
||||||
Loading…
Reference in New Issue