Song and Video data fetching works
This commit is contained in:
parent
7471f1e70c
commit
9479811d4c
|
|
@ -1,7 +1,6 @@
|
||||||
import AlbumParser from "./parsers/AlbumParser"
|
import AlbumParser from "./parsers/AlbumParser"
|
||||||
import ArtistParser from "./parsers/ArtistParser"
|
import ArtistParser from "./parsers/ArtistParser"
|
||||||
import axios, { AxiosInstance } from "axios"
|
import axios, { AxiosInstance } from "axios"
|
||||||
import fs from "fs"
|
|
||||||
import PlaylistParser from "./parsers/PlaylistParser"
|
import PlaylistParser from "./parsers/PlaylistParser"
|
||||||
import SearchParser from "./parsers/SearchParser"
|
import SearchParser from "./parsers/SearchParser"
|
||||||
import SongParser from "./parsers/SongParser"
|
import SongParser from "./parsers/SongParser"
|
||||||
|
|
@ -237,16 +236,28 @@ export default class YTMusic {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getSong(videoId: string) {
|
/**
|
||||||
|
* Get all possible information of a Song
|
||||||
|
*
|
||||||
|
* @param videoId Video ID
|
||||||
|
* @returns Song Data
|
||||||
|
*/
|
||||||
|
public async getSong(videoId: string): Promise<YTMusic.SongFull> {
|
||||||
const data = await this.constructRequest("player", { videoId })
|
const data = await this.constructRequest("player", { videoId })
|
||||||
|
|
||||||
fs.writeFileSync("data.json", JSON.stringify(data))
|
return SongParser.parse(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getVideo(videoId: string) {
|
/**
|
||||||
|
* Get all possible information of a Video
|
||||||
|
*
|
||||||
|
* @param videoId Video ID
|
||||||
|
* @returns Video Data
|
||||||
|
*/
|
||||||
|
public async getVideo(videoId: string): Promise<YTMusic.VideoFull> {
|
||||||
const data = await this.constructRequest("player", { videoId })
|
const data = await this.constructRequest("player", { videoId })
|
||||||
|
|
||||||
fs.writeFileSync("data.json", JSON.stringify(data))
|
return VideoParser.parse(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
10
src/index.ts
10
src/index.ts
|
|
@ -1,10 +0,0 @@
|
||||||
import YTMusic from "./YTMusic"
|
|
||||||
|
|
||||||
const ytmusic = new YTMusic()
|
|
||||||
ytmusic.initialize().then(() => {
|
|
||||||
ytmusic.search("Lilac", "PLAYLIST").then(res => {
|
|
||||||
ytmusic.getPlaylist(res[0].playlistId).then(res => {
|
|
||||||
console.log(res)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -2,6 +2,25 @@ import Parser from "./Parser"
|
||||||
import traverse from "../utils/traverse"
|
import traverse from "../utils/traverse"
|
||||||
|
|
||||||
export default class SongParser {
|
export default class SongParser {
|
||||||
|
public static parse(data: any): YTMusic.SongFull {
|
||||||
|
return {
|
||||||
|
type: "SONG",
|
||||||
|
videoId: traverse(data, "videoDetails", "videoId"),
|
||||||
|
name: traverse(data, "videoDetails", "title"),
|
||||||
|
artists: [
|
||||||
|
{
|
||||||
|
artistId: traverse(data, "videoDetails", "channelId"),
|
||||||
|
name: traverse(data, "author")
|
||||||
|
}
|
||||||
|
],
|
||||||
|
duration: +traverse(data, "videoDetails", "lengthSeconds"),
|
||||||
|
thumbnails: [traverse(data, "videoDetails", "thumbnails")].flat(),
|
||||||
|
description: traverse(data, "description"),
|
||||||
|
formats: traverse(data, "streamingData", "formats"),
|
||||||
|
adaptiveFormats: traverse(data, "streamingData", "adaptiveFormats")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static parseSearchResult(item: any): YTMusic.SongDetailed {
|
public static parseSearchResult(item: any): YTMusic.SongDetailed {
|
||||||
const flexColumns = traverse(item, "flexColumns")
|
const flexColumns = traverse(item, "flexColumns")
|
||||||
const videoId = traverse(item, "playlistItemData", "videoId")
|
const videoId = traverse(item, "playlistItemData", "videoId")
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,28 @@ import Parser from "./Parser"
|
||||||
import traverse from "../utils/traverse"
|
import traverse from "../utils/traverse"
|
||||||
|
|
||||||
export default class VideoParser {
|
export default class VideoParser {
|
||||||
|
public static parse(data: any): YTMusic.VideoFull {
|
||||||
|
return {
|
||||||
|
type: "VIDEO",
|
||||||
|
videoId: traverse(data, "videoDetails", "videoId"),
|
||||||
|
name: traverse(data, "videoDetails", "title"),
|
||||||
|
artists: [
|
||||||
|
{
|
||||||
|
artistId: traverse(data, "videoDetails", "channelId"),
|
||||||
|
name: traverse(data, "author")
|
||||||
|
}
|
||||||
|
],
|
||||||
|
views: +traverse(data, "videoDetails", "viewCount"),
|
||||||
|
duration: +traverse(data, "videoDetails", "lengthSeconds"),
|
||||||
|
thumbnails: [traverse(data, "videoDetails", "thumbnails")].flat(),
|
||||||
|
description: traverse(data, "description"),
|
||||||
|
unlisted: traverse(data, "unlisted"),
|
||||||
|
familySafe: traverse(data, "familySafe"),
|
||||||
|
paid: traverse(data, "paid"),
|
||||||
|
tags: traverse(data, "tags")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static parseSearchResult(item: any): YTMusic.VideoDetailed {
|
public static parseSearchResult(item: any): YTMusic.VideoDetailed {
|
||||||
const flexColumns = traverse(item, "flexColumns")
|
const flexColumns = traverse(item, "flexColumns")
|
||||||
const videoId = traverse(item, "playNavigationEndpoint", "videoId")
|
const videoId = traverse(item, "playNavigationEndpoint", "videoId")
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ import {
|
||||||
PLAYLIST_DETAILED,
|
PLAYLIST_DETAILED,
|
||||||
PLAYLIST_VIDEO,
|
PLAYLIST_VIDEO,
|
||||||
SONG_DETAILED,
|
SONG_DETAILED,
|
||||||
VIDEO_DETAILED
|
SONG_FULL,
|
||||||
|
VIDEO_DETAILED,
|
||||||
|
VIDEO_FULL
|
||||||
} from "./interfaces"
|
} from "./interfaces"
|
||||||
import { LIST, validate } from "validate-any"
|
import { LIST, validate } from "validate-any"
|
||||||
|
|
||||||
|
|
@ -26,10 +28,10 @@ ytmusic.initialize().then(() =>
|
||||||
ytmusic.search(query)
|
ytmusic.search(query)
|
||||||
])
|
])
|
||||||
|
|
||||||
const [artist, artistSongs, artistAlbums, album, playlist, playlistVideos] =
|
const [song, video, artist, artistSongs, artistAlbums, album, playlist, playlistVideos] =
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
// ytmusic.getSong(songs[0].videoId),
|
ytmusic.getSong(songs[0].videoId!),
|
||||||
// ytmusic.getVideo(videos[0].videoId),
|
ytmusic.getVideo(videos[0].videoId!),
|
||||||
ytmusic.getArtist(artists[0].artistId),
|
ytmusic.getArtist(artists[0].artistId),
|
||||||
ytmusic.getArtistSongs(artists[0].artistId),
|
ytmusic.getArtistSongs(artists[0].artistId),
|
||||||
ytmusic.getArtistAlbums(artists[0].artistId),
|
ytmusic.getArtistAlbums(artists[0].artistId),
|
||||||
|
|
@ -54,8 +56,8 @@ ytmusic.initialize().then(() =>
|
||||||
VIDEO_DETAILED
|
VIDEO_DETAILED
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
// [song, SONG_DETAILED],
|
[song, SONG_FULL],
|
||||||
// [video, VIDEO_DETAILED],
|
[video, VIDEO_FULL],
|
||||||
[artist, ARTIST_FULL],
|
[artist, ARTIST_FULL],
|
||||||
[artistSongs, LIST(SONG_DETAILED)],
|
[artistSongs, LIST(SONG_DETAILED)],
|
||||||
[artistAlbums, LIST(ALBUM_DETAILED)],
|
[artistAlbums, LIST(ALBUM_DETAILED)],
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import ObjectValidator from "validate-any/build/validators/ObjectValidator"
|
import ObjectValidator from "validate-any/build/validators/ObjectValidator"
|
||||||
import { 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<YTMusic.ThumbnailFull> = OBJECT({
|
||||||
url: STRING(),
|
url: STRING(),
|
||||||
|
|
@ -54,6 +54,33 @@ export const ALBUM_DETAILED: ObjectValidator<YTMusic.AlbumDetailed> = OBJECT({
|
||||||
thumbnails: LIST(THUMBNAIL_FULL)
|
thumbnails: LIST(THUMBNAIL_FULL)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const SONG_FULL: ObjectValidator<YTMusic.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<YTMusic.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<YTMusic.ArtistFull> = OBJECT({
|
export const ARTIST_FULL: ObjectValidator<YTMusic.ArtistFull> = OBJECT({
|
||||||
artistId: STRING(),
|
artistId: STRING(),
|
||||||
name: STRING(),
|
name: STRING(),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -15,6 +15,12 @@ declare namespace YTMusic {
|
||||||
thumbnails: ThumbnailFull[]
|
thumbnails: ThumbnailFull[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SongFull extends Omit<SongDetailed, "album"> {
|
||||||
|
description: string
|
||||||
|
formats: any[]
|
||||||
|
adaptiveFormats: any[]
|
||||||
|
}
|
||||||
|
|
||||||
interface VideoDetailed {
|
interface VideoDetailed {
|
||||||
type: "VIDEO"
|
type: "VIDEO"
|
||||||
videoId: string | null
|
videoId: string | null
|
||||||
|
|
@ -25,6 +31,14 @@ declare namespace YTMusic {
|
||||||
thumbnails: ThumbnailFull[]
|
thumbnails: ThumbnailFull[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface VideoFull extends VideoDetailed {
|
||||||
|
description: string
|
||||||
|
unlisted: boolean
|
||||||
|
familySafe: boolean
|
||||||
|
paid: boolean
|
||||||
|
tags: string[]
|
||||||
|
}
|
||||||
|
|
||||||
interface ArtistBasic {
|
interface ArtistBasic {
|
||||||
artistId: string | null
|
artistId: string | null
|
||||||
name: string
|
name: string
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue