Compare commits

...

2 Commits

Author SHA1 Message Date
Arthur POULET 93fa5b0666 Fix get_playlist when raw playlist id is given 2021-02-26 00:00:28 +01:00
Thibaut Broggi f13fa72672
Fix playlist import on non alpha numerical ids 2021-02-25 22:47:55 +01:00
2 changed files with 39 additions and 43 deletions

View File

@ -85,14 +85,10 @@ class PlaylistsManager {
async import({ message, params }) { async import({ message, params }) {
const [playlist_title, query] = params const [playlist_title, query] = params
try { const playlist = await youtube_instance.get_playlist(query)
const playlist = await youtube_instance.get_playlist(query) this.#playlists[playlist_title] = playlist
this.#playlists[playlist_title] = playlist await PlaylistsManager.writeFile(this.#filepath, this.#playlists)
await PlaylistsManager.writeFile(this.#filepath, this.#playlists) message.channel.send(`:white_check_mark: Playlist \`${playlist_title}\` imported`)
message.channel.send(`:white_check_mark: Playlist \`${playlist_title}\` imported`)
} catch (err) {
message.channel.send(`:warning: Cannot import ${query}`)
}
} }
} }

View File

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