|
|
|
@ -4,63 +4,63 @@ const { Playlist } = require("./playlist")
|
|
|
|
|
const ytdl = require('ytdl-core')
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Centralize all youtube requests within a single interface.
|
|
|
|
|
* It allows searching infos (tracks, playlists, metadata) over youtube.
|
|
|
|
|
*/
|
|
|
|
|
* Centralize all youtube requests within a single interface.
|
|
|
|
|
* It allows searching infos (tracks, playlists, metadata) over youtube.
|
|
|
|
|
*/
|
|
|
|
|
class Youtube {
|
|
|
|
|
constructor() {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param {string} search The search pattern that will be sent to Youtube
|
|
|
|
|
* @return {Track[]} An array of objects representing the search results. <code>source</code> is set to <code>"youtube"</code>
|
|
|
|
|
*/
|
|
|
|
|
* @param {string} search The search pattern that will be sent to Youtube
|
|
|
|
|
* @return {Track[]} An array of objects representing the search results. <code>source</code> is set to <code>"youtube"</code>
|
|
|
|
|
*/
|
|
|
|
|
async search_track(search) {
|
|
|
|
|
const req = await fetch('https://www.youtube.com/results?search_query='
|
|
|
|
|
+ encodeURIComponent(search))
|
|
|
|
|
+ encodeURIComponent(search))
|
|
|
|
|
const body = await req.text()
|
|
|
|
|
const json = JSON.parse(body.match(/ytInitialData = (.*);<\/script>/)[1])
|
|
|
|
|
const results = json.contents.twoColumnSearchResultsRenderer.primaryContents.sectionListRenderer.contents[0].itemSectionRenderer.contents
|
|
|
|
|
return results
|
|
|
|
|
.filter(e => e.videoRenderer)
|
|
|
|
|
.map(e => {
|
|
|
|
|
return new Track({
|
|
|
|
|
url: 'https://www.youtube.com/watch?v=' + e.videoRenderer.videoId,
|
|
|
|
|
title: e.videoRenderer.title.runs[0].text,
|
|
|
|
|
length: e.videoRenderer.lengthText.simpleText,
|
|
|
|
|
source: 'youtube',
|
|
|
|
|
})
|
|
|
|
|
.filter(e => e.videoRenderer)
|
|
|
|
|
.map(e => {
|
|
|
|
|
return new Track({
|
|
|
|
|
url: 'https://www.youtube.com/watch?v=' + e.videoRenderer.videoId,
|
|
|
|
|
title: e.videoRenderer.title.runs[0].text,
|
|
|
|
|
length: e.videoRenderer.lengthText.simpleText,
|
|
|
|
|
source: 'youtube',
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Retrieve all tracks of the playlist on youtube
|
|
|
|
|
* @param {string} playlist_query an url or id of the youtube playlist. It will recognize the list=xxx pattern.
|
|
|
|
|
* @returns {Playlist}
|
|
|
|
|
*/
|
|
|
|
|
* Retrieve all tracks of the playlist on youtube
|
|
|
|
|
* @param {string} playlist_query an url or id of the youtube playlist. It will recognize the list=xxx pattern.
|
|
|
|
|
* @returns {Playlist}
|
|
|
|
|
*/
|
|
|
|
|
async get_playlist(playlist_query) {
|
|
|
|
|
const playlist_id = playlist_query.match(/list=(\w+)/)?.[1] || playlist
|
|
|
|
|
const playlist_id = playlist_query.match(/list=([\w-]+)/)?.[1] || playlist_query
|
|
|
|
|
const req = await fetch(`https://www.youtube.com/playlist?list=${playlist_id}`)
|
|
|
|
|
const body = await req.text()
|
|
|
|
|
const json = JSON.parse(body.match(/ytInitialData = (.*);<\/script>/)[1])
|
|
|
|
|
// console.log(JSON.stringify(json, null, 2))
|
|
|
|
|
const results = json.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents[0].itemSectionRenderer.contents[0].playlistVideoListRenderer.contents
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const tracks = results
|
|
|
|
|
.filter(video => video.playlistVideoRenderer.lengthText)
|
|
|
|
|
.map((video) => new Track({
|
|
|
|
|
title: video.playlistVideoRenderer.title.runs[0].text,
|
|
|
|
|
url: 'https://www.youtube.com/watch?v=' + video.playlistVideoRenderer.videoId,
|
|
|
|
|
length: video.playlistVideoRenderer.lengthText.simpleText,
|
|
|
|
|
source: 'youtube',
|
|
|
|
|
}))
|
|
|
|
|
.filter(video => video?.playlistVideoRenderer?.lengthText)
|
|
|
|
|
.map((video) => new Track({
|
|
|
|
|
title: video.playlistVideoRenderer.title.runs[0].text,
|
|
|
|
|
url: 'https://www.youtube.com/watch?v=' + video.playlistVideoRenderer.videoId,
|
|
|
|
|
length: video.playlistVideoRenderer.lengthText.simpleText,
|
|
|
|
|
source: 'youtube',
|
|
|
|
|
}))
|
|
|
|
|
return new Playlist({ tracks })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Retrieve the metadata of a YouTube video
|
|
|
|
|
* @param {string} url
|
|
|
|
|
* @returns {Track}
|
|
|
|
|
*/
|
|
|
|
|
* Retrieve the metadata of a YouTube video
|
|
|
|
|
* @param {string} url
|
|
|
|
|
* @returns {Track}
|
|
|
|
|
*/
|
|
|
|
|
async get_metadata(url) {
|
|
|
|
|
const video_infos = (await ytdl.getBasicInfo(url)).videoDetails
|
|
|
|
|
return new Track({
|
|
|
|
|