youtube-moosick
Version:
Unofficial Youtube music API, fully written in TypeScript
120 lines • 6.29 kB
JavaScript
import { $, $$ } from '../resources/utilities/objectScan.utility.js';
import { Thumbnails } from '../resources/generalTypes/thumbnails.js';
import { Artist } from '../resources/generalTypes/artist.js';
import { ConstantURLs, FlexColumnOffset, FlexSecondRowOffset } from '../enums.js';
import { Albums, ArtistContent, ArtistHeader, ArtistURL, Single, Videos } from '../resources/resultTypes/artistURL.js';
/**
* Parser to deal with the output generated by the Moosick#getArtist
*
* @remarks
* Do not use this class directly, unless for tests purposes
* @internal
*/
export class GetArtistParser {
static parseArtistURLPage(context) {
const subHeader = $('.musicDescriptionShelfRenderer')(context);
// Builds the header
const header = ArtistHeader.from({
artistName: context.header.musicImmersiveHeaderRenderer.title.runs[FlexColumnOffset.ONLYRUN].text,
description: subHeader.description.runs[FlexColumnOffset.ONLYRUN].text,
// probably reduce the length of this access
totalSubscribers: context.header.musicImmersiveHeaderRenderer.subscriptionButton.subscribeButtonRenderer.subscriberCountWithSubscribeText.runs[FlexColumnOffset.ONLYRUN].text,
thumbnails: this.parseMusicThumbnailRenderer($('.musicThumbnailRenderer')(context)),
});
const albums = [];
const singles = [];
const videos = [];
// Gets the carousel, there should be 5 of them
const twoRowRenderer = $$('.musicCarouselShelfRenderer')(context);
for (const itemRenderer of twoRowRenderer) {
// Gets the row name type
const rowName = $$('.header .title .text')(itemRenderer)[0].toLowerCase();
// Only parse the following, the others are not useful
const validRows = ['albums', 'singles', 'videos'];
if (!(validRows.includes(rowName))) {
break;
}
// Gets the items in the carousel
const musicItemRenderer = $$('.musicTwoRowItemRenderer')(itemRenderer);
for (const blockRenderer of musicItemRenderer) {
const runsInternal = blockRenderer.title.runs[FlexColumnOffset.ONLYRUN].text;
// eslint-disable-next-line default-case
switch (rowName) {
case 'albums': {
albums.push(Albums.from({
title: runsInternal,
browseId: blockRenderer.navigationEndpoint.browseEndpoint.browseId,
URL: `${ConstantURLs.CHANNEL_URL}${blockRenderer.navigationEndpoint.browseEndpoint.browseId}`,
year: parseInt(blockRenderer.subtitle.runs[blockRenderer.subtitle.runs.length - 1].text, 10),
thumbnails: this.parseMusicThumbnailRenderer(blockRenderer.thumbnailRenderer.musicThumbnailRenderer),
}));
break;
}
case 'singles': {
singles.push(Single.from({
title: runsInternal,
browseId: blockRenderer.navigationEndpoint.browseEndpoint.browseId,
URL: `${ConstantURLs.CHANNEL_URL}${blockRenderer.navigationEndpoint.browseEndpoint.browseId}`,
year: parseInt(blockRenderer.subtitle.runs[blockRenderer.subtitle.runs.length - 1].text, 10),
thumbnails: this.parseMusicThumbnailRenderer(blockRenderer.thumbnailRenderer.musicThumbnailRenderer),
}));
break;
}
case 'videos': {
videos.push(Videos.from({
title: runsInternal,
videoId: blockRenderer.navigationEndpoint?.watchEndpoint?.videoId ?? '',
URL: `${ConstantURLs.VIDEOLINK}${blockRenderer.navigationEndpoint?.watchEndpoint?.videoId ?? ''}`,
playlistId: blockRenderer.navigationEndpoint.watchEndpoint?.playlistId ?? '',
views: parseInt(blockRenderer.subtitle.runs[blockRenderer.subtitle.runs.length - 1].text, 10),
thumbnails: this.parseMusicThumbnailRenderer(blockRenderer.thumbnailRenderer.musicThumbnailRenderer),
author: this.parseArtistFromVideos(blockRenderer.subtitle.runs),
}));
break;
}
}
}
}
const artistContent = ArtistContent.from({
albums,
single: singles,
videos,
});
return ArtistURL.from({
headers: header,
artistContents: artistContent,
});
}
/**
* Parses thumbnails
* @param musicThumbnailRenderer - Thumbnail renderer
* @internal
*/
static parseMusicThumbnailRenderer(musicThumbnailRenderer) {
const thumbnailsProcessed = [];
musicThumbnailRenderer.thumbnail.thumbnails.forEach((item) => {
thumbnailsProcessed.push(Thumbnails.from({
url: item.url,
width: item.width,
height: item.height,
}));
});
return thumbnailsProcessed;
}
/**
* Parses artist from subtitle renderer
* @param subtitleRenderer - The subtitle run
* @internal
*/
static parseArtistFromVideos(subtitleRenderer) {
const delimiter = ' • ';
const positions = subtitleRenderer.flatMap((text, i) => text.text === delimiter ? i : []);
const artistOnly = subtitleRenderer.slice(0, positions[FlexSecondRowOffset.ARTIST]);
return artistOnly.map((element) => (Artist.from({
name: element.text,
browseId: element.navigationEndpoint?.browseEndpoint?.browseId ?? '',
url: `${ConstantURLs.CHANNEL_URL}${element.navigationEndpoint?.browseEndpoint?.browseId ?? ''}`,
})));
}
}
//# sourceMappingURL=getArtistParser.js.map