Some fixes

This commit is contained in:
killer069 2021-12-26 15:34:31 +05:30
parent 9d24008a2b
commit 8f805bbbdd
6 changed files with 31 additions and 13 deletions

View File

@ -1,10 +1,7 @@
const useragents: string[] = [ const useragents: string[] = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Edg/96.0.1054.43',
'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko', 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36', 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0',
'Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36.0 (KHTML, like Gecko) Chrome/61.0.0.0 Safari/537.36.0', 'Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36.0 (KHTML, like Gecko) Chrome/61.0.0.0 Safari/537.36.0',
'Mozilla/5.0 (Windows; U; Windows NT 6.1) AppleWebKit/531.35.5 (KHTML, like Gecko) Version/4.0.3 Safari/531.35.5', 'Mozilla/5.0 (Windows; U; Windows NT 6.1) AppleWebKit/531.35.5 (KHTML, like Gecko) Version/4.0.3 Safari/531.35.5',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246',

View File

@ -41,7 +41,7 @@ export async function yt_search(search: string, options: ParseSearchInterface =
} }
const body = await request(url, { const body = await request(url, {
headers: { headers: {
'accept-language': 'en-US,en;q=0.9' 'accept-language': options.language || 'en-US;q=0.9'
} }
}); });
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)

View File

@ -15,6 +15,7 @@ export interface StreamOptions {
seekMode?: 'precise' | 'granular'; seekMode?: 'precise' | 'granular';
seek?: number; seek?: number;
quality?: number; quality?: number;
language?: string;
htmldata?: boolean; htmldata?: boolean;
} }
@ -46,7 +47,7 @@ export type YouTubeStream = Stream | LiveStream | SeekStream;
* @returns Stream class with type and stream for playing. * @returns Stream class with type and stream for playing.
*/ */
export async function stream(url: string, options: StreamOptions = {}): Promise<YouTubeStream> { export async function stream(url: string, options: StreamOptions = {}): Promise<YouTubeStream> {
const info = await video_stream_info(url, { htmldata: options.htmldata }); const info = await video_stream_info(url, { htmldata: options.htmldata, language: options.language });
return await stream_from_info(info, options); return await stream_from_info(info, options);
} }
/** /**

View File

@ -6,10 +6,12 @@ import { InfoData, StreamInfoData } from './constants';
interface InfoOptions { interface InfoOptions {
htmldata?: boolean; htmldata?: boolean;
language?: string;
} }
interface PlaylistOptions { interface PlaylistOptions {
incomplete?: boolean; incomplete?: boolean;
language?: string;
} }
const video_id_pattern = /^[a-zA-Z\d_-]{11,12}$/; const video_id_pattern = /^[a-zA-Z\d_-]{11,12}$/;
@ -110,7 +112,7 @@ export async function video_basic_info(url: string, options: InfoOptions = {}):
const new_url = `https://www.youtube.com/watch?v=${video_id}&has_verified=1`; const new_url = `https://www.youtube.com/watch?v=${video_id}&has_verified=1`;
body = await request(new_url, { body = await request(new_url, {
headers: { headers: {
'accept-language': 'en-US,en-IN;q=0.9,en;q=0.8,hi;q=0.7' 'accept-language': options.language || 'en-US;q=0.9'
}, },
cookies: true cookies: true
}); });
@ -120,12 +122,12 @@ export async function video_basic_info(url: string, options: InfoOptions = {}):
const player_data = body const player_data = body
.split('var ytInitialPlayerResponse = ')?.[1] .split('var ytInitialPlayerResponse = ')?.[1]
?.split(';</script>')[0] ?.split(';</script>')[0]
.split(/;\s*(var|const|let)/)[0]; .split(/;\s*"(var|const|let)"/)[0];
if (!player_data) throw new Error('Initial Player Response Data is undefined.'); if (!player_data) throw new Error('Initial Player Response Data is undefined.');
const initial_data = body const initial_data = body
.split('var ytInitialData = ')?.[1] .split('var ytInitialData = ')?.[1]
?.split(';</script>')[0] ?.split(';</script>')[0]
.split(/;\s*(var|const|let)/)[0]; .split(/;\s*"(var|const|let)"/)[0];
if (!initial_data) throw new Error('Initial Response Data is undefined.'); if (!initial_data) throw new Error('Initial Response Data is undefined.');
const player_response = JSON.parse(player_data); const player_response = JSON.parse(player_data);
const initial_response = JSON.parse(initial_data); const initial_response = JSON.parse(initial_data);
@ -340,12 +342,17 @@ export async function playlist_info(url: string, options: PlaylistOptions = {}):
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': options.language || 'en-US;q=0.9'
} }
}); });
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 response = JSON.parse(body.split('var ytInitialData = ')[1].split(';</script>')[0]); const response = JSON.parse(
body
.split('var ytInitialData = ')[1]
.split(';</script>')[0]
.split(/;\s*"(var|const|let)"/)[0]
);
if (response.alerts) { if (response.alerts) {
if (response.alerts[0].alertWithButtonRenderer?.type === 'INFO') { if (response.alerts[0].alertWithButtonRenderer?.type === 'INFO') {
if (!options.incomplete) if (!options.incomplete)

View File

@ -6,6 +6,7 @@ import { YouTube } from '..';
export interface ParseSearchInterface { export interface ParseSearchInterface {
type?: 'video' | 'playlist' | 'channel'; type?: 'video' | 'playlist' | 'channel';
limit?: number; limit?: number;
language?: string;
} }
export interface thumbnail { export interface thumbnail {
@ -28,7 +29,7 @@ export function ParseSearchResult(html: string, options?: ParseSearchInterface):
const data = html const data = html
.split('var ytInitialData = ')?.[1] .split('var ytInitialData = ')?.[1]
?.split(';</script>')[0] ?.split(';</script>')[0]
.split(/;\s*(var|const|let)/)[0]; .split(/;\s*"(var|const|let)"/)[0];
const json_data = JSON.parse(data); const json_data = JSON.parse(data);
const results = []; const results = [];
const details = const details =

View File

@ -65,6 +65,7 @@ interface SearchOptions {
deezer?: 'track' | 'playlist' | 'album'; deezer?: 'track' | 'playlist' | 'album';
}; };
fuzzy?: boolean; fuzzy?: boolean;
language?: string;
} }
import { createInterface } from 'node:readline'; import { createInterface } from 'node:readline';
@ -102,6 +103,9 @@ async function stream(url: string, options?: StreamOptions): Promise<YouTubeStre
* @param url Video / Track URL * @param url Video / Track URL
* @param options * @param options
* *
* - `number` seek : No of seconds to seek in stream.
* - `string` seekMode : Choose type of seek you want. [ "precise" | "granular" ]
* - `string` language : Sets language of searched content [ YouTube search only. ], e.g. "en-US"
* - `number` quality : Quality number. [ 0 = Lowest, 1 = Medium, 2 = Highest ] * - `number` quality : Quality number. [ 0 = Lowest, 1 = Medium, 2 = Highest ]
* - `boolean` htmldata : given data is html data or not * - `boolean` htmldata : given data is html data or not
* @returns A {@link YouTubeStream} or {@link SoundCloudStream} Stream to play * @returns A {@link YouTubeStream} or {@link SoundCloudStream} Stream to play
@ -186,6 +190,7 @@ async function search(query: string, options?: SearchOptions): Promise<YouTubeVi
* @param options * @param options
* *
* - `number` limit : No of searches you want to have. * - `number` limit : No of searches you want to have.
* - `string` language : Sets language of searched content [ YouTube search only. ], e.g. "en-US"
* - `boolean` fuzzy : Whether the search should be fuzzy or only return exact matches. Defaults to `true`. [ for `Deezer` Only ] * - `boolean` fuzzy : Whether the search should be fuzzy or only return exact matches. Defaults to `true`. [ for `Deezer` Only ]
* - `Object` source : Contains type of source and type of result you want to have * - `Object` source : Contains type of source and type of result you want to have
* ```ts * ```ts
@ -202,7 +207,12 @@ async function search(
): Promise<YouTube[] | Spotify[] | SoundCloud[] | Deezer[]> { ): Promise<YouTube[] | Spotify[] | SoundCloud[] | Deezer[]> {
if (!options.source) options.source = { youtube: 'video' }; if (!options.source) options.source = { youtube: 'video' };
query = encodeURIComponent(query); query = encodeURIComponent(query);
if (options.source.youtube) return await yt_search(query, { limit: options.limit, type: options.source.youtube }); if (options.source.youtube)
return await yt_search(query, {
limit: options.limit,
type: options.source.youtube,
language: options.language
});
else if (options.source.spotify) return await sp_search(query, options.source.spotify, options.limit); else if (options.source.spotify) return await sp_search(query, options.source.spotify, options.limit);
else if (options.source.soundcloud) return await so_search(query, options.source.soundcloud, options.limit); else if (options.source.soundcloud) return await so_search(query, options.source.soundcloud, options.limit);
else if (options.source.deezer) else if (options.source.deezer)
@ -237,8 +247,10 @@ async function stream_from_info(info: InfoData, options?: StreamOptions): Promis
* @param info YouTube video info OR SoundCloud track Class * @param info YouTube video info OR SoundCloud track Class
* @param options * @param options
* *
* - `number` seek : No of seconds to seek in stream.
* - `string` seekMode : Choose type of seek you want. [ "precise" | "granular" ]
* - `string` language : Sets language of searched content [ YouTube search only. ], e.g. "en-US"
* - `number` quality : Quality number. [ 0 = Lowest, 1 = Medium, 2 = Highest ] * - `number` quality : Quality number. [ 0 = Lowest, 1 = Medium, 2 = Highest ]
* - `Proxy[]` proxy : sends data through a proxy
* - `boolean` htmldata : given data is html data or not * - `boolean` htmldata : given data is html data or not
* @returns A {@link YouTubeStream} or {@link SoundCloudStream} Stream to play * @returns A {@link YouTubeStream} or {@link SoundCloudStream} Stream to play
*/ */