Files
YouTube.js/lib/core/Music.js
LuanRT 2254b69670 feat: add support for retrieving YTMusic “related” tab
+ finish lyrics parser and implement all needed YouTube Music renderers
2022-06-11 08:00:58 -03:00

89 lines
2.7 KiB
JavaScript

'use strict';
const Search = require('../parser/ytmusic/Search');
const Parser = require('../parser/contents');
const { InnertubeError, observe } = require('../utils/Utils');
/** @namespace */
class Music {
#session;
#actions;
/**
* @param {Innertube} session
* @constructor
*/
constructor(session) {
this.#session = session;
this.#actions = session.actions;
}
/**
* Search on YouTube Music.
*
* @param {string} query
* @param {object} filters - search filters
* @param {string} [filters.type] - all | song | video | album | playlist | artist
*
* @returns {Promise.<Search>}
*/
async search(query, filters) {
const response = await this.#actions.search({ query, filters, client: 'YTMUSIC' });
return new Search(response, this.#actions, { is_filtered: filters?.hasOwnProperty('type') && filters.type !== 'all' });
}
/**
* Retrieves song lyrics.
* @param {string} video_id
* @returns {Promise.<{ text: string; footer: Text }>}
*/
async getLyrics(video_id) {
const response = await this.#actions.next({ video_id, client: 'YTMUSIC' });
const data = Parser.parseResponse(response.data);
const tab = data.contents.tabs.get({ title: 'Lyrics' });
const page = await tab.endpoint.call(this.#actions, 'YTMUSIC');
if (!page) throw new InnertubeError('Invalid video id');
if (page.contents.constructor.name === 'Message')
throw new InnertubeError(page.contents.text, video_id);
const description_shelf = page.contents.contents.get({ type: 'musicDescriptionShelfRenderer' });
return {
text: description_shelf.description.toString(),
footer: description_shelf.footer
}
}
/**
* Retrieves related content.
* @param {string} video_id
* @returns {Promise.<{ sections: { header: import('../parser/contents/classes/MusicCarouselShelfBasicHeader'); items: any[]; }[]; info: string }>}
*/
async getRelated(video_id) {
const response = await this.#actions.next({ video_id, client: 'YTMUSIC' });
const data = Parser.parseResponse(response.data);
const tab = data.contents.tabs.get({ title: 'Related' });
const page = await tab.endpoint.call(this.#actions, 'YTMUSIC');
if (!page) throw new InnertubeError('Invalid video id');
const shelves = page.contents.contents.findAll({ type: 'musicCarouselShelfRenderer' });
const info = page.contents.contents.get({ type: 'musicDescriptionShelfRenderer' });
const results = {
sections: observe(shelves.map((shelf) => ({
header: shelf.header,
items: shelf.contents
}))),
info: info?.description.toString() || null
}
return results;
}
}
module.exports = Music;