Merge branch 'developer' of https://github.com/play-dl/play-dl into developer

This commit is contained in:
killer069 2021-12-02 14:01:15 +05:30
commit 9a9aabc4d8
3 changed files with 60 additions and 60 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "play-dl", "name": "play-dl",
"version": "1.4.2", "version": "1.4.3",
"description": "YouTube, SoundCloud, Spotify, Deezer searching and streaming for discord.js bots", "description": "YouTube, SoundCloud, Spotify, Deezer searching and streaming for discord.js bots",
"main": "dist/index.js", "main": "dist/index.js",
"typings": "dist/index.d.ts", "typings": "dist/index.d.ts",

View File

@ -23,9 +23,9 @@ export type YouTube = YouTubeVideo | YouTubeChannel | YouTubePlayList;
export async function yt_search(search: string, options: ParseSearchInterface = {}): Promise<YouTube[]> { export async function yt_search(search: string, options: ParseSearchInterface = {}): Promise<YouTube[]> {
let url = 'https://www.youtube.com/results?search_query=' + search; let url = 'https://www.youtube.com/results?search_query=' + search;
options.type ??= 'video'; options.type ??= 'video';
if (!url.match('&sp=')) { if (url.indexOf('&sp=') === -1) {
url += '&sp='; url += '&sp=';
switch (options?.type) { switch (options.type) {
case 'channel': case 'channel':
url += SearchType.Channel; url += SearchType.Channel;
break; break;
@ -35,16 +35,17 @@ export async function yt_search(search: string, options: ParseSearchInterface =
case 'video': case 'video':
url += SearchType.Video; url += SearchType.Video;
break; break;
default:
throw new Error(`Unknown search type: ${options.type}`);
} }
} }
const body = await request(url, { const body = await request(url, {
headers: { headers: {
'accept-language': 'en-US,en-IN;q=0.9,en;q=0.8,hi;q=0.7', 'accept-language': 'en-US,en;q=0.9',
'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36', 'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36',
} }
}); });
if (body.indexOf('Our systems have detected unusual traffic from your computer network.') !== -1) if (body.indexOf('Our systems have detected unusual traffic from your computer network.') !== -1)
throw new Error('Captcha page: YouTube has detected that you are a bot!'); throw new Error('Captcha page: YouTube has detected that you are a bot!');
const data = ParseSearchResult(body, options); return ParseSearchResult(body, options);
return data;
} }

View File

@ -22,7 +22,8 @@ export interface thumbnail {
export function ParseSearchResult(html: string, options?: ParseSearchInterface): YouTube[] { export function ParseSearchResult(html: string, options?: ParseSearchInterface): YouTube[] {
if (!html) throw new Error("Can't parse Search result without data"); if (!html) throw new Error("Can't parse Search result without data");
if (!options) options = { type: 'video', limit: 0 }; if (!options) options = { type: 'video', limit: 0 };
if (!options.type) options.type = 'video'; else if (!options.type) options.type = 'video';
const hasLimit = typeof options.limit === 'number' && options.limit > 0;
const data = html const data = html
.split('var ytInitialData = ')?.[1] .split('var ytInitialData = ')?.[1]
@ -33,21 +34,27 @@ export function ParseSearchResult(html: string, options?: ParseSearchInterface):
const details = const details =
json_data.contents.twoColumnSearchResultsRenderer.primaryContents.sectionListRenderer.contents[0] json_data.contents.twoColumnSearchResultsRenderer.primaryContents.sectionListRenderer.contents[0]
.itemSectionRenderer.contents; .itemSectionRenderer.contents;
for (let i = 0; i < details.length; i++) { for (const detail of details) {
if (typeof options.limit === 'number' && options.limit > 0 && results.length === options.limit) break; if (hasLimit && results.length === options.limit) break;
if (!details[i].videoRenderer && !details[i].channelRenderer && !details[i].playlistRenderer) continue; if (!detail.videoRenderer && !detail.channelRenderer && !detail.playlistRenderer) continue;
if (options.type === 'video') { switch (options.type) {
const parsed = parseVideo(details[i]); case 'video': {
if (!parsed) continue; const parsed = parseVideo(detail);
results.push(parsed); if (parsed) results.push(parsed);
} else if (options.type === 'channel') { break;
const parsed = parseChannel(details[i]); }
if (!parsed) continue; case 'channel': {
results.push(parsed); const parsed = parseChannel(detail);
} else if (options.type === 'playlist') { if (parsed) results.push(parsed);
const parsed = parsePlaylist(details[i]); break;
if (!parsed) continue; }
results.push(parsed); case 'playlist': {
const parsed = parsePlaylist(detail);
if (parsed) results.push(parsed);
break;
}
default:
throw new Error(`Unknown search type: ${options.type}`);
} }
} }
return results; return results;
@ -58,7 +65,7 @@ export function ParseSearchResult(html: string, options?: ParseSearchInterface):
* @returns seconds * @returns seconds
*/ */
function parseDuration(duration: string): number { function parseDuration(duration: string): number {
duration ??= '0:00'; if (!duration) return 0;
const args = duration.split(':'); const args = duration.split(':');
let dur = 0; let dur = 0;
@ -82,29 +89,24 @@ function parseDuration(duration: string): number {
*/ */
export function parseChannel(data?: any): YouTubeChannel { export function parseChannel(data?: any): YouTubeChannel {
if (!data || !data.channelRenderer) throw new Error('Failed to Parse YouTube Channel'); if (!data || !data.channelRenderer) throw new Error('Failed to Parse YouTube Channel');
const badge = data.channelRenderer.ownerBadges && data.channelRenderer.ownerBadges[0]; const badge = data.channelRenderer.ownerBadges?.[0]?.metadataBadgeRenderer?.style?.toLowerCase();
const url = `https://www.youtube.com${ const url = `https://www.youtube.com${
data.channelRenderer.navigationEndpoint.browseEndpoint.canonicalBaseUrl || data.channelRenderer.navigationEndpoint.browseEndpoint.canonicalBaseUrl ||
data.channelRenderer.navigationEndpoint.commandMetadata.webCommandMetadata.url data.channelRenderer.navigationEndpoint.commandMetadata.webCommandMetadata.url
}`; }`;
const thumbnail = data.channelRenderer.thumbnail.thumbnails[data.channelRenderer.thumbnail.thumbnails.length - 1];
const res = new YouTubeChannel({ const res = new YouTubeChannel({
id: data.channelRenderer.channelId, id: data.channelRenderer.channelId,
name: data.channelRenderer.title.simpleText, name: data.channelRenderer.title.simpleText,
icon: { icon: {
url: data.channelRenderer.thumbnail.thumbnails[ url: thumbnail.url.replace('//', 'https://'),
data.channelRenderer.thumbnail.thumbnails.length - 1 width: thumbnail.width,
].url.replace('//', 'https://'), height: thumbnail.height
width: data.channelRenderer.thumbnail.thumbnails[data.channelRenderer.thumbnail.thumbnails.length - 1]
.width,
height: data.channelRenderer.thumbnail.thumbnails[data.channelRenderer.thumbnail.thumbnails.length - 1]
.height
}, },
url: url, url: url,
verified: Boolean(badge?.metadataBadgeRenderer?.style?.toLowerCase().includes('verified')), verified: Boolean(badge?.includes('verified')),
artist: Boolean(badge?.metadataBadgeRenderer?.style?.toLowerCase().includes('artist')), artist: Boolean(badge?.includes('artist')),
subscribers: data.channelRenderer.subscriberCountText?.simpleText subscribers: data.channelRenderer.subscriberCountText?.simpleText ?? '0 subscribers'
? data.channelRenderer.subscriberCountText.simpleText
: '0 subscribers'
}); });
return res; return res;
@ -117,30 +119,29 @@ export function parseChannel(data?: any): YouTubeChannel {
export function parseVideo(data?: any): YouTubeVideo { export function parseVideo(data?: any): YouTubeVideo {
if (!data || !data.videoRenderer) throw new Error('Failed to Parse YouTube Video'); if (!data || !data.videoRenderer) throw new Error('Failed to Parse YouTube Video');
const badge = data.videoRenderer.ownerBadges && data.videoRenderer.ownerBadges[0]; const channel = data.videoRenderer.ownerText.runs[0];
const badge = data.videoRenderer.ownerBadges?.[0]?.metadataBadgeRenderer?.style?.toLowerCase();
const res = new YouTubeVideo({ const res = new YouTubeVideo({
id: data.videoRenderer.videoId, id: data.videoRenderer.videoId,
url: `https://www.youtube.com/watch?v=${data.videoRenderer.videoId}`, url: `https://www.youtube.com/watch?v=${data.videoRenderer.videoId}`,
title: data.videoRenderer.title.runs[0].text, title: data.videoRenderer.title.runs[0].text,
description: description: data.videoRenderer.detailedMetadataSnippets?.[0].snippetText.runs.length
data.videoRenderer.detailedMetadataSnippets &&
data.videoRenderer.detailedMetadataSnippets[0].snippetText.runs[0]
? data.videoRenderer.detailedMetadataSnippets[0].snippetText.runs.map((run: any) => run.text).join('') ? data.videoRenderer.detailedMetadataSnippets[0].snippetText.runs.map((run: any) => run.text).join('')
: '', : '',
duration: data.videoRenderer.lengthText ? parseDuration(data.videoRenderer.lengthText.simpleText) : 0, duration: data.videoRenderer.lengthText ? parseDuration(data.videoRenderer.lengthText.simpleText) : 0,
duration_raw: data.videoRenderer.lengthText ? data.videoRenderer.lengthText.simpleText : null, duration_raw: data.videoRenderer.lengthText ? data.videoRenderer.lengthText.simpleText : null,
thumbnail: data.videoRenderer.thumbnail.thumbnails[data.videoRenderer.thumbnail.thumbnails.length - 1], thumbnail: data.videoRenderer.thumbnail.thumbnails[data.videoRenderer.thumbnail.thumbnails.length - 1],
channel: { channel: {
id: data.videoRenderer.ownerText.runs[0].navigationEndpoint.browseEndpoint.browseId || null, id: channel.navigationEndpoint.browseEndpoint.browseId || null,
name: data.videoRenderer.ownerText.runs[0].text || null, name: channel.text || null,
url: `https://www.youtube.com${ url: `https://www.youtube.com${
data.videoRenderer.ownerText.runs[0].navigationEndpoint.browseEndpoint.canonicalBaseUrl || channel.navigationEndpoint.browseEndpoint.canonicalBaseUrl ||
data.videoRenderer.ownerText.runs[0].navigationEndpoint.commandMetadata.webCommandMetadata.url channel.navigationEndpoint.commandMetadata.webCommandMetadata.url
}`, }`,
icons: data.videoRenderer.channelThumbnailSupportedRenderers.channelThumbnailWithLinkRenderer.thumbnail icons: data.videoRenderer.channelThumbnailSupportedRenderers.channelThumbnailWithLinkRenderer.thumbnail
.thumbnails, .thumbnails,
verified: Boolean(badge?.metadataBadgeRenderer?.style?.toLowerCase().includes('verified')), verified: Boolean(badge?.includes('verified')),
artist: Boolean(badge?.metadataBadgeRenderer?.style?.toLowerCase().includes('artist')) artist: Boolean(badge?.includes('artist'))
}, },
uploadedAt: data.videoRenderer.publishedTimeText?.simpleText ?? null, uploadedAt: data.videoRenderer.publishedTimeText?.simpleText ?? null,
views: data.videoRenderer.viewCountText?.simpleText?.replace(/[^0-9]/g, '') ?? 0, views: data.videoRenderer.viewCountText?.simpleText?.replace(/[^0-9]/g, '') ?? 0,
@ -157,26 +158,24 @@ export function parseVideo(data?: any): YouTubeVideo {
export function parsePlaylist(data?: any): YouTubePlayList { export function parsePlaylist(data?: any): YouTubePlayList {
if (!data || !data.playlistRenderer) throw new Error('Failed to Parse YouTube Playlist'); if (!data || !data.playlistRenderer) throw new Error('Failed to Parse YouTube Playlist');
const thumbnail =
data.playlistRenderer.thumbnails[0].thumbnails[data.playlistRenderer.thumbnails[0].thumbnails.length - 1];
const channel = data.playlistRenderer.shortBylineText.runs?.[0];
const res = new YouTubePlayList( const res = new YouTubePlayList(
{ {
id: data.playlistRenderer.playlistId, id: data.playlistRenderer.playlistId,
title: data.playlistRenderer.title.simpleText, title: data.playlistRenderer.title.simpleText,
thumbnail: { thumbnail: {
id: data.playlistRenderer.playlistId, id: data.playlistRenderer.playlistId,
url: data.playlistRenderer.thumbnails[0].thumbnails[ url: thumbnail.url,
data.playlistRenderer.thumbnails[0].thumbnails.length - 1 height: thumbnail.height,
].url, width: thumbnail.width
height: data.playlistRenderer.thumbnails[0].thumbnails[
data.playlistRenderer.thumbnails[0].thumbnails.length - 1
].height,
width: data.playlistRenderer.thumbnails[0].thumbnails[
data.playlistRenderer.thumbnails[0].thumbnails.length - 1
].width
}, },
channel: { channel: {
id: data.playlistRenderer.shortBylineText.runs?.[0].navigationEndpoint.browseEndpoint.browseId, id: channel?.navigationEndpoint.browseEndpoint.browseId,
name: data.playlistRenderer.shortBylineText.runs?.[0].text, name: channel?.text,
url: `https://www.youtube.com${data.playlistRenderer.shortBylineText.runs?.[0].navigationEndpoint.commandMetadata.webCommandMetadata.url}` url: `https://www.youtube.com${channel?.navigationEndpoint.commandMetadata.webCommandMetadata.url}`
}, },
videos: parseInt(data.playlistRenderer.videoCount.replace(/[^0-9]/g, '')) videos: parseInt(data.playlistRenderer.videoCount.replace(/[^0-9]/g, ''))
}, },