From 6698a8798381518940402a19b189714631d46f83 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Sat, 9 Oct 2021 16:18:05 +0530 Subject: [PATCH 1/3] search validation added --- play-dl/Request/classes.ts | 169 +++++++++++++------------- play-dl/Request/index.ts | 43 ++++--- play-dl/SoundCloud/classes.ts | 4 +- play-dl/SoundCloud/index.ts | 4 +- play-dl/Spotify/index.ts | 4 +- play-dl/YouTube/classes/LiveStream.ts | 12 +- play-dl/YouTube/stream.ts | 16 +-- play-dl/YouTube/utils/cookie.ts | 18 +-- play-dl/YouTube/utils/extractor.ts | 25 ++-- play-dl/YouTube/utils/request.ts | 57 +++++---- play-dl/index.ts | 34 ++++-- 11 files changed, 199 insertions(+), 187 deletions(-) diff --git a/play-dl/Request/classes.ts b/play-dl/Request/classes.ts index 4fc96a2..a1f2f1b 100644 --- a/play-dl/Request/classes.ts +++ b/play-dl/Request/classes.ts @@ -1,110 +1,111 @@ -import tls , { TLSSocket } from "tls"; -import { URL } from "url"; -import { Timer } from "../YouTube/classes/LiveStream"; +import tls, { TLSSocket } from 'tls'; +import { URL } from 'url'; +import { Timer } from '../YouTube/classes/LiveStream'; -interface ResponseOptions extends tls.ConnectionOptions{ +interface ResponseOptions extends tls.ConnectionOptions { body?: string; method: 'GET' | 'POST'; - cookies? : boolean - headers? : Object; - timeout? : number + cookies?: boolean; + headers?: Object; + timeout?: number; } export class Response { - parsed_url : URL - statusCode : number; - rawHeaders : string; - headers : Object; - body : string; - socket : TLSSocket; - sentHeaders : string; - sentBody : string; - private options : ResponseOptions; - private timer : Timer | null - constructor(req_url : string, options : ResponseOptions){ - this.parsed_url = new URL(req_url) - this.sentHeaders = '' - this.statusCode = 0 - this.sentBody = "" - this.rawHeaders = '' - this.body = '' - this.headers = {} - this.timer = null - this.options = options - this.socket = tls.connect({ - host : this.parsed_url.hostname, - port : Number(this.parsed_url.port) || 443, - socket : options.socket, - rejectUnauthorized : false - }, () => this.onConnect()) - if(options.headers){ - for(const [ key, value ] of Object.entries(options.headers)){ - this.sentHeaders += `${key}: ${value}\r\n` + parsed_url: URL; + statusCode: number; + rawHeaders: string; + headers: Object; + body: string; + socket: TLSSocket; + sentHeaders: string; + sentBody: string; + private options: ResponseOptions; + private timer: Timer | null; + constructor(req_url: string, options: ResponseOptions) { + this.parsed_url = new URL(req_url); + this.sentHeaders = ''; + this.statusCode = 0; + this.sentBody = ''; + this.rawHeaders = ''; + this.body = ''; + this.headers = {}; + this.timer = null; + this.options = options; + this.socket = tls.connect( + { + host: this.parsed_url.hostname, + port: Number(this.parsed_url.port) || 443, + socket: options.socket, + rejectUnauthorized: false + }, + () => this.onConnect() + ); + if (options.headers) { + for (const [key, value] of Object.entries(options.headers)) { + this.sentHeaders += `${key}: ${value}\r\n`; } } - if(options.body) this.sentBody = options.body + if (options.body) this.sentBody = options.body; } - private onConnect(){ + private onConnect() { this.socket.write( - `${this.options.method} ${this.parsed_url.pathname}${this.parsed_url.search} HTTP/1.1\r\n` + - `Host : ${this.parsed_url.hostname}\r\n` + - this.sentHeaders + - `Connection: close\r\n` + - `\r\n` + - this.sentBody - ) + `${this.options.method} ${this.parsed_url.pathname}${this.parsed_url.search} HTTP/1.1\r\n` + + `Host : ${this.parsed_url.hostname}\r\n` + + this.sentHeaders + + `Connection: close\r\n` + + `\r\n` + + this.sentBody + ); } - private parseHeaders(){ - const head_arr = this.rawHeaders.split('\r\n') - this.statusCode = Number(head_arr.shift()?.split(' ')[1]) ?? -1 - for(const head of head_arr){ - let [ key, value ] = head.split(': ') - if(!value) break; - key = key.trim().toLowerCase() - value = value.trim() - if(Object.keys(this.headers).includes(key)){ - let val = (this.headers as any)[key] - if(typeof val === 'string') val = [val] - Object.assign(this.headers, { [key]: [...val, value] }) - } - else Object.assign(this.headers, { [key] : value }) + private parseHeaders() { + const head_arr = this.rawHeaders.split('\r\n'); + this.statusCode = Number(head_arr.shift()?.split(' ')[1]) ?? -1; + for (const head of head_arr) { + let [key, value] = head.split(': '); + if (!value) break; + key = key.trim().toLowerCase(); + value = value.trim(); + if (Object.keys(this.headers).includes(key)) { + let val = (this.headers as any)[key]; + if (typeof val === 'string') val = [val]; + Object.assign(this.headers, { [key]: [...val, value] }); + } else Object.assign(this.headers, { [key]: value }); } } - stream(): Promise{ + stream(): Promise { return new Promise((resolve, reject) => { - this.timer = new Timer(() => this.socket.end(), this.options.timeout || 1) - this.socket.once('error', (err) => reject(err)) + this.timer = new Timer(() => this.socket.end(), this.options.timeout || 1); + this.socket.once('error', (err) => reject(err)); this.socket.once('data', (chunk) => { - this.rawHeaders = chunk.toString('utf-8') - this.parseHeaders() - resolve(this.socket) - }) - this.socket.on('data', () => this.timer?.reuse()) - this.socket.once('end', () => this.timer?.destroy()) - }) + this.rawHeaders = chunk.toString('utf-8'); + this.parseHeaders(); + resolve(this.socket); + }); + this.socket.on('data', () => this.timer?.reuse()); + this.socket.once('end', () => this.timer?.destroy()); + }); } - fetch(): Promise{ + fetch(): Promise { return new Promise((resolve, reject) => { this.socket.setEncoding('utf-8'); - this.socket.once('error', (err) => reject(err)) + this.socket.once('error', (err) => reject(err)); this.socket.on('data', (chunk: string) => { - if(this.rawHeaders.length === 0){ - this.rawHeaders = chunk - this.parseHeaders() + if (this.rawHeaders.length === 0) { + this.rawHeaders = chunk; + this.parseHeaders(); + } else { + const arr = chunk.split('\r\n'); + if (arr.length > 1 && arr[0].length < 5) arr.shift(); + this.body += arr.join(''); } - else { - const arr = chunk.split('\r\n') - if(arr.length > 1 && arr[0].length < 5) arr.shift() - this.body += arr.join('') - } - }) + }); this.socket.on('end', () => { - resolve(this) - }) - }) + resolve(this); + }); + }); } -} \ No newline at end of file +} diff --git a/play-dl/Request/index.ts b/play-dl/Request/index.ts index 97bec5e..0946551 100644 --- a/play-dl/Request/index.ts +++ b/play-dl/Request/index.ts @@ -1,5 +1,4 @@ -import { Response } from "./classes"; - +import { Response } from './classes'; export type Proxy = ProxyOpts | string; @@ -16,38 +15,38 @@ interface RequestOptions { body?: string; method: 'GET' | 'POST'; proxies?: Proxy[]; - cookies? : boolean - headers? : Object; - timeout? : number + cookies?: boolean; + headers?: Object; + timeout?: number; } -interface StreamGetterOptions{ +interface StreamGetterOptions { method: 'GET' | 'POST'; - cookies? : boolean - headers : Object; + cookies?: boolean; + headers: Object; } -export function request_stream(req_url : string, options : RequestOptions = {method : "GET"}): Promise{ - return new Promise(async(resolve, reject) => { - let res = new Response(req_url, options) - await res.stream() +export function request_stream(req_url: string, options: RequestOptions = { method: 'GET' }): Promise { + return new Promise(async (resolve, reject) => { + let res = new Response(req_url, options); + await res.stream(); if (res.statusCode >= 300 && res.statusCode < 400) { res = await request_stream((res.headers as any).location, options); - await res.stream() + await res.stream(); } - resolve(res) - }) + resolve(res); + }); } -export function request(req_url : string, options : RequestOptions = {method : "GET"}): Promise{ - return new Promise(async(resolve, reject) => { - let res = new Response(req_url, options) - await res.fetch() +export function request(req_url: string, options: RequestOptions = { method: 'GET' }): Promise { + return new Promise(async (resolve, reject) => { + let res = new Response(req_url, options); + await res.fetch(); if (Number(res.statusCode) >= 300 && Number(res.statusCode) < 400) { res = await request((res.headers as any).location, options); } else if (Number(res.statusCode) > 400) { reject(new Error(`Got ${res.statusCode} from the request`)); } - resolve(res) - }) -} \ No newline at end of file + resolve(res); + }); +} diff --git a/play-dl/SoundCloud/classes.ts b/play-dl/SoundCloud/classes.ts index a854172..f1f0398 100644 --- a/play-dl/SoundCloud/classes.ts +++ b/play-dl/SoundCloud/classes.ts @@ -260,7 +260,7 @@ export class Stream { } private async loop() { - if (this.stream.destroyed ||this.time.length === 0 || this.segment_urls.length === 0) { + if (this.stream.destroyed || this.time.length === 0 || this.segment_urls.length === 0) { this.cleanup(); return; } @@ -273,7 +273,7 @@ export class Stream { return; } - this.request = stream + this.request = stream; stream.pipe(this.stream, { end: false }); stream.on('end', () => { if (this.downloaded_time >= 300) return; diff --git a/play-dl/SoundCloud/index.ts b/play-dl/SoundCloud/index.ts index 5f8a56e..e949809 100644 --- a/play-dl/SoundCloud/index.ts +++ b/play-dl/SoundCloud/index.ts @@ -126,8 +126,8 @@ export async function check_id(id: string): Promise { * @param url soundcloud url * @returns "false" | 'track' | 'playlist' */ -export async function so_validate(url: string): Promise { - if (!url.match(pattern)) return false; +export async function so_validate(url: string): Promise { + if (!url.match(pattern)) return 'search'; const data = await request( `https://api-v2.soundcloud.com/resolve?url=${url}&client_id=${soundData.client_id}` ).catch((err: Error) => err); diff --git a/play-dl/Spotify/index.ts b/play-dl/Spotify/index.ts index cd2f7d5..f4ecc84 100644 --- a/play-dl/Spotify/index.ts +++ b/play-dl/Spotify/index.ts @@ -74,8 +74,8 @@ export async function spotify(url: string): Promise { * @param url url for validation * @returns type of url or false. */ -export function sp_validate(url: string): 'track' | 'playlist' | 'album' | false { - if (!url.match(pattern)) return false; +export function sp_validate(url: string): 'track' | 'playlist' | 'album' | 'search' | false { + if (!url.match(pattern)) return 'search'; if (url.indexOf('track/') !== -1) { return 'track'; } else if (url.indexOf('album/') !== -1) { diff --git a/play-dl/YouTube/classes/LiveStream.ts b/play-dl/YouTube/classes/LiveStream.ts index 7fee2ae..4dc8fdd 100644 --- a/play-dl/YouTube/classes/LiveStream.ts +++ b/play-dl/YouTube/classes/LiveStream.ts @@ -112,7 +112,7 @@ export class LiveStreaming { }); }); } - + this.timer.reuse(); } @@ -157,7 +157,7 @@ export class Stream { this.loop(); }, 265); this.stream.on('close', () => { - this.timer.destroy() + this.timer.destroy(); this.cleanup(); }); this.loop(); @@ -178,7 +178,7 @@ export class Stream { private async loop() { if (this.stream.destroyed) { - this.timer.destroy() + this.timer.destroy(); this.cleanup(); return; } @@ -198,7 +198,7 @@ export class Stream { if (Number(stream.statusCode) >= 400) { this.cleanup(); await this.retry(); - this.timer.reuse() + this.timer.reuse(); this.loop(); return; } @@ -208,7 +208,7 @@ export class Stream { stream.once('error', async (err) => { this.cleanup(); await this.retry(); - this.timer.reuse() + this.timer.reuse(); this.loop(); }); @@ -219,7 +219,7 @@ export class Stream { stream.on('end', () => { if (end >= this.content_length) { this.timer.destroy(); - this.cleanup() + this.cleanup(); } }); } diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index dc551be..c2a8663 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -71,12 +71,10 @@ export async function stream(url: string, options: StreamOptions = {}): Promise< if (typeof options.quality !== 'number') options.quality = audioFormat.length - 1; else if (options.quality <= 0) options.quality = 0; else if (options.quality >= audioFormat.length) options.quality = audioFormat.length - 1; - if(audioFormat.length !== 0) final.push(audioFormat[options.quality]); - else final.push(info.format[info.format.length - 1]) + if (audioFormat.length !== 0) final.push(audioFormat[options.quality]); + else final.push(info.format[info.format.length - 1]); let type: StreamType = - final[0].codec === 'opus' && final[0].container === 'webm' - ? StreamType.WebmOpus - : StreamType.Arbitrary; + final[0].codec === 'opus' && final[0].container === 'webm' ? StreamType.WebmOpus : StreamType.Arbitrary; return new Stream( final[0].url, type, @@ -110,12 +108,10 @@ export async function stream_from_info(info: InfoData, options: StreamOptions = if (typeof options.quality !== 'number') options.quality = audioFormat.length - 1; else if (options.quality <= 0) options.quality = 0; else if (options.quality >= audioFormat.length) options.quality = audioFormat.length - 1; - if(audioFormat.length !== 0) final.push(audioFormat[options.quality]); - else final.push(info.format[info.format.length - 1]) + if (audioFormat.length !== 0) final.push(audioFormat[options.quality]); + else final.push(info.format[info.format.length - 1]); let type: StreamType = - final[0].codec === 'opus' && final[0].container === 'webm' - ? StreamType.WebmOpus - : StreamType.Arbitrary; + final[0].codec === 'opus' && final[0].container === 'webm' ? StreamType.WebmOpus : StreamType.Arbitrary; return new Stream( final[0].url, type, diff --git a/play-dl/YouTube/utils/cookie.ts b/play-dl/YouTube/utils/cookie.ts index 28a19da..e43293a 100644 --- a/play-dl/YouTube/utils/cookie.ts +++ b/play-dl/YouTube/utils/cookie.ts @@ -10,22 +10,22 @@ interface youtubeDataOptions { } export function getCookies(): undefined | string { - let result = '' - if(!youtubeData?.cookie) return undefined - for (const [ key, value ] of Object.entries(youtubeData.cookie)){ - result+= `${key}=${value};` + let result = ''; + if (!youtubeData?.cookie) return undefined; + for (const [key, value] of Object.entries(youtubeData.cookie)) { + result += `${key}=${value};`; } return result; } export function setCookie(key: string, value: string): boolean { if (!youtubeData?.cookie) return false; - key = key.trim() - value = value.trim() - Object.assign(youtubeData.cookie, { [key] : value }) - return true + key = key.trim(); + value = value.trim(); + Object.assign(youtubeData.cookie, { [key]: value }); + return true; } export function uploadCookie() { - if(youtubeData) fs.writeFileSync('.data/youtube.data', JSON.stringify(youtubeData, undefined, 4)); + if (youtubeData) fs.writeFileSync('.data/youtube.data', JSON.stringify(youtubeData, undefined, 4)); } diff --git a/play-dl/YouTube/utils/extractor.ts b/play-dl/YouTube/utils/extractor.ts index 8701d6f..ebda8d6 100644 --- a/play-dl/YouTube/utils/extractor.ts +++ b/play-dl/YouTube/utils/extractor.ts @@ -24,23 +24,26 @@ const playlist_pattern = * @param url Url for validation * @returns type of url or false. */ -export function yt_validate(url: string): 'playlist' | 'video' | false { +export function yt_validate(url: string): 'playlist' | 'video' | 'search' | false { if (url.indexOf('list=') === -1) { if (url.startsWith('https')) { - if (url.match(video_pattern)) return 'video'; + if (url.match(video_pattern)) { + const id = url.split('v=')[1].split('&')[0] + if(id.match(video_id_pattern)) return "video" + else return false + } else return false; } else { if (url.match(video_id_pattern)) return 'video'; else if (url.match(playlist_id_pattern)) return 'playlist'; - else return false; + else return 'search'; } } else { if (!url.match(playlist_pattern)) return false; const Playlist_id = url.split('list=')[1].split('&')[0]; if (Playlist_id.length !== 34 || !Playlist_id.startsWith('PL')) { return false; - } - else return 'playlist'; + } else return 'playlist'; } } /** @@ -49,7 +52,8 @@ export function yt_validate(url: string): 'playlist' | 'video' | false { * @returns ID of video or playlist. */ export function extractID(url: string): string { - if (!yt_validate(url)) throw new Error('This is not a YouTube url or videoId or PlaylistID'); + const check = yt_validate(url); + if (!check || check === 'search') throw new Error('This is not a YouTube url or videoId or PlaylistID'); if (url.startsWith('https')) { if (url.indexOf('list=') === -1) { let video_id: string; @@ -69,16 +73,13 @@ export function extractID(url: string): string { * @returns Data containing video_details, LiveStreamData and formats of video url. */ export async function video_basic_info(url: string, options: InfoOptions = {}) { - let video_id: string; - if (url.startsWith('https')) { - if (yt_validate(url) !== 'video') throw new Error('This is not a YouTube Watch URL'); - video_id = extractID(url); - } else video_id = url; + if (yt_validate(url) !== 'video') throw new Error('This is not a YouTube Watch URL'); + let video_id: string = extractID(url); const new_url = `https://www.youtube.com/watch?v=${video_id}&has_verified=1`; const body = await request(new_url, { proxies: options.proxy ?? undefined, headers: { 'accept-language': 'en-US,en-IN;q=0.9,en;q=0.8,hi;q=0.7' }, - cookies : true + cookies: true }); const player_response = JSON.parse(body.split('var ytInitialPlayerResponse = ')[1].split('}};')[0] + '}}'); const initial_response = JSON.parse(body.split('var ytInitialData = ')[1].split('}};')[0] + '}}'); diff --git a/play-dl/YouTube/utils/request.ts b/play-dl/YouTube/utils/request.ts index fb840b9..1b930b2 100644 --- a/play-dl/YouTube/utils/request.ts +++ b/play-dl/YouTube/utils/request.ts @@ -27,7 +27,7 @@ interface RequestOpts extends RequestOptions { body?: string; method?: 'GET' | 'POST'; proxies?: Proxy[]; - cookies? : boolean + cookies?: boolean; } /** * Main module that play-dl uses for making a https request @@ -155,12 +155,12 @@ export async function request(url: string, options: RequestOpts = {}): Promise { if (!options?.proxies || options.proxies.length === 0) { let data = ''; - let cookies_added = false - if(options.cookies){ - let cook = getCookies() + let cookies_added = false; + if (options.cookies) { + let cook = getCookies(); if (typeof cook === 'string' && options.headers) { - Object.assign(options.headers, { cookie : cook }); - cookies_added = true + Object.assign(options.headers, { cookie: cook }); + cookies_added = true; } } let res = await https_getter(url, options).catch((err: Error) => err); @@ -168,17 +168,17 @@ export async function request(url: string, options: RequestOpts = {}): Promise { x.split(';').forEach((x) => { - const arr = x.split('=') - if(arr.length <= 1 ) return; - const key = arr.shift()?.trim() as string - const value = arr.join('=').trim() + const arr = x.split('='); + if (arr.length <= 1) return; + const key = arr.shift()?.trim() as string; + const value = arr.join('=').trim(); setCookie(key, value); }); - }) - uploadCookie() + }); + uploadCookie(); } if (Number(res.statusCode) >= 300 && Number(res.statusCode) < 400) { res = await https_getter(res.headers.location as string, options); @@ -189,12 +189,12 @@ export async function request(url: string, options: RequestOpts = {}): Promise (data += c)); res.on('end', () => resolve(data)); } else { - let cookies_added = false - if(options.cookies){ - let cook = getCookies() + let cookies_added = false; + if (options.cookies) { + let cook = getCookies(); if (typeof cook === 'string' && options.headers) { - Object.assign(options.headers, { cookie : cook }); - cookies_added = true + Object.assign(options.headers, { cookie: cook }); + cookies_added = true; } } let res = await proxy_getter(url, options.proxies).catch((e: Error) => e); @@ -202,18 +202,21 @@ export async function request(url: string, options: RequestOpts = {}): Promise x.toLocaleLowerCase().startsWith('set-cookie: ')); cookies.forEach((x) => { - x.toLocaleLowerCase().split('set-cookie: ')[1].split(';').forEach((y) => { - const arr = y.split('=') - if(arr.length <= 1 ) return; - const key = arr.shift()?.trim() as string - const value = arr.join('=').trim() - setCookie(key, value); - }); + x.toLocaleLowerCase() + .split('set-cookie: ')[1] + .split(';') + .forEach((y) => { + const arr = y.split('='); + if (arr.length <= 1) return; + const key = arr.shift()?.trim() as string; + const value = arr.join('=').trim(); + setCookie(key, value); + }); }); - uploadCookie() + uploadCookie(); } if (res.statusCode >= 300 && res.statusCode < 400) { let url = res.head.filter((x) => x.startsWith('Location: ')); diff --git a/play-dl/index.ts b/play-dl/index.ts index 49a6d2f..825da70 100644 --- a/play-dl/index.ts +++ b/play-dl/index.ts @@ -90,17 +90,29 @@ export async function stream_from_info( */ export async function validate( url: string -): Promise<'so_playlist' | 'so_track' | 'sp_track' | 'sp_album' | 'sp_playlist' | 'yt_video' | 'yt_playlist' | false> { +): Promise< + | 'so_playlist' + | 'so_track' + | 'so_search' + | 'sp_track' + | 'sp_album' + | 'sp_playlist' + | 'sp_search' + | 'yt_video' + | 'yt_playlist' + | 'yt_search' + | false +> { let check; if (url.indexOf('spotify') !== -1) { check = sp_validate(url); - return check !== false ? (('sp_' + check) as 'sp_track' | 'sp_album' | 'sp_playlist') : false; + return check !== false ? (('sp_' + check) as 'sp_track' | 'sp_album' | 'sp_playlist' | 'sp_search') : false; } else if (url.indexOf('soundcloud') !== -1) { check = await so_validate(url); - return check !== false ? (('so_' + check) as 'so_playlist' | 'so_track') : false; + return check !== false ? (('so_' + check) as 'so_playlist' | 'so_track' | 'so_search') : false; } else { check = yt_validate(url); - return check !== false ? (('yt_' + check) as 'yt_video' | 'yt_playlist') : false; + return check !== false ? (('yt_' + check) as 'yt_video' | 'yt_playlist' | 'yt_search') : false; } } /** @@ -183,12 +195,12 @@ export function authorization(): void { console.log('Cookies has been added successfully.'); let cookie: Object = {}; cook.split(';').forEach((x) => { - const arr = x.split('=') - if(arr.length <= 1 ) return; - const key = arr.shift()?.trim() as string - const value = arr.join('=').trim() - Object.assign(cookie, { [key] : value }) - }) + const arr = x.split('='); + if (arr.length <= 1) return; + const key = arr.shift()?.trim() as string; + const value = arr.join('=').trim(); + Object.assign(cookie, { [key]: value }); + }); fs.writeFileSync('.data/youtube.data', JSON.stringify({ cookie }, undefined, 4)); ask.close(); }); @@ -208,4 +220,4 @@ export function attachListeners(player: EventEmitter, resource: YouTubeStream | player.removeListener(AudioPlayerStatus.AutoPaused, () => resource.pause()); player.removeListener(AudioPlayerStatus.Playing, () => resource.resume()); }); -}; \ No newline at end of file +} From f6a91254aa85334b8e168f6c34f7e0c7f2a02ab2 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Sat, 9 Oct 2021 18:59:16 +0530 Subject: [PATCH 2/3] Docs + search validate updated --- docs/README.md | 4 +++- docs/SoundCloud/README.md | 4 +++- docs/Spotify/README.md | 35 ++++++++++++++++-------------- docs/YouTube/README.md | 4 +++- play-dl/YouTube/utils/extractor.ts | 9 ++++---- play-dl/index.ts | 19 +++++----------- 6 files changed, 37 insertions(+), 38 deletions(-) diff --git a/docs/README.md b/docs/README.md index dcc1c88..75dd14b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,7 +12,7 @@ For source specific commands :- _This checks all type of urls that are supported by play-dl._ -**Returns :** `so_playlist` | `so_track` | `sp_track` | `sp_album` | `sp_playlist` | `yt_video` | `yt_playlist` | `false` +**Returns :** `so_playlist` | `so_track` | `sp_track` | `sp_album` | `sp_playlist` | `yt_video` | `yt_playlist` | `search` | `false` `so` = **SoundCloud** @@ -30,6 +30,8 @@ if(check === 'yt_video') // YouTube Video if(check === 'sp_track') // Spotify Track if(check === 'so_track') // SoundCloud Track + +if(check === "search") // Given term is not a url. Search this term somewhere. ``` ### authorization() diff --git a/docs/SoundCloud/README.md b/docs/SoundCloud/README.md index 47358d3..6b2b2bf 100644 --- a/docs/SoundCloud/README.md +++ b/docs/SoundCloud/README.md @@ -18,7 +18,7 @@ console.log(data.type) // Console logs the type of data that you got. _This checks that given url is soundcloud url or not._ -**Returns :** `track` | `playlist` | `false` +**Returns :** `track` | `playlist` | `search` | `false` ```js let check = await so_validate(url) @@ -26,6 +26,8 @@ let check = await so_validate(url) if(!check) // Invalid SoundCloud URL if(check === 'track') // SoundCloud Track URL + +if(check === "search") // Given term is not a SoundCloud URL. Search this somewhere. ``` ## Classes [ Returned by `soundcloud(url)` function ] diff --git a/docs/Spotify/README.md b/docs/Spotify/README.md index 7f7c6a8..47c353d 100644 --- a/docs/Spotify/README.md +++ b/docs/Spotify/README.md @@ -12,6 +12,25 @@ let data = await spotify(url) //Gets the data console.log(data.type) // Console logs the type of data that you got. ``` + +## Validate + +### sp_validate(url : `string`) + +_This checks that given url is spotify url or not._ + +**Returns :** `track` | `album` | `playlist` | `search` | `false` + +```js +let check = sp_validate(url) + +if(!check) // Invalid Spotify URL + +if(check === 'track') // Spotify Track URL + +if(check === "search") // Given term is a spotify url. Search it somewhere. +``` + ### is_expired() _This tells that whether the access token is expired or not_ @@ -183,19 +202,3 @@ _This will always return as "album" for this class._ ##### toJSON() `function` _converts class into a json format_ - -## Validate - -### sp_validate(url : `string`) - -_This checks that given url is spotify url or not._ - -**Returns :** `track` | `album` | `playlist` | `false` - -```js -let check = sp_validate(url) - -if(!check) // Invalid Spotify URL - -if(check === 'track') // Spotify Track URL -``` diff --git a/docs/YouTube/README.md b/docs/YouTube/README.md index 91164e7..46698b4 100644 --- a/docs/YouTube/README.md +++ b/docs/YouTube/README.md @@ -17,7 +17,7 @@ const results = await youtube.search('post malone sunflower', options); _This will validate url and return type or boolean_ -**Returns :** `video` | `playlist` | `false` +**Returns :** `video` | `playlist` | `search` | `false` ```js let check = yt_validate(url) @@ -27,6 +27,8 @@ if(!check) // Invalid URL if(check === "video") //URL is video url if(check === "playlist") //URL is a playlist url + +if(check === "search") // Given term is not a video ID and PlayList ID. ``` ## Extract ID diff --git a/play-dl/YouTube/utils/extractor.ts b/play-dl/YouTube/utils/extractor.ts index ebda8d6..d615d45 100644 --- a/play-dl/YouTube/utils/extractor.ts +++ b/play-dl/YouTube/utils/extractor.ts @@ -28,11 +28,10 @@ export function yt_validate(url: string): 'playlist' | 'video' | 'search' | fals if (url.indexOf('list=') === -1) { if (url.startsWith('https')) { if (url.match(video_pattern)) { - const id = url.split('v=')[1].split('&')[0] - if(id.match(video_id_pattern)) return "video" - else return false - } - else return false; + const id = url.split('v=')[1].split('&')[0]; + if (id.match(video_id_pattern)) return 'video'; + else return false; + } else return false; } else { if (url.match(video_id_pattern)) return 'video'; else if (url.match(playlist_id_pattern)) return 'playlist'; diff --git a/play-dl/index.ts b/play-dl/index.ts index 825da70..5830fa1 100644 --- a/play-dl/index.ts +++ b/play-dl/index.ts @@ -91,28 +91,19 @@ export async function stream_from_info( export async function validate( url: string ): Promise< - | 'so_playlist' - | 'so_track' - | 'so_search' - | 'sp_track' - | 'sp_album' - | 'sp_playlist' - | 'sp_search' - | 'yt_video' - | 'yt_playlist' - | 'yt_search' - | false + 'so_playlist' | 'so_track' | 'sp_track' | 'sp_album' | 'sp_playlist' | 'yt_video' | 'yt_playlist' | 'search' | false > { let check; + if (!url.startsWith('https')) return 'search'; if (url.indexOf('spotify') !== -1) { check = sp_validate(url); - return check !== false ? (('sp_' + check) as 'sp_track' | 'sp_album' | 'sp_playlist' | 'sp_search') : false; + return check !== false ? (('sp_' + check) as 'sp_track' | 'sp_album' | 'sp_playlist') : false; } else if (url.indexOf('soundcloud') !== -1) { check = await so_validate(url); - return check !== false ? (('so_' + check) as 'so_playlist' | 'so_track' | 'so_search') : false; + return check !== false ? (('so_' + check) as 'so_playlist' | 'so_track') : false; } else { check = yt_validate(url); - return check !== false ? (('yt_' + check) as 'yt_video' | 'yt_playlist' | 'yt_search') : false; + return check !== false ? (('yt_' + check) as 'yt_video' | 'yt_playlist') : false; } } /** From 937b1fc7ff0acbe3d0dae2db810204aab580ca79 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Sat, 9 Oct 2021 21:19:35 +0530 Subject: [PATCH 3/3] Listeners Issue fixed --- play-dl/index.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/play-dl/index.ts b/play-dl/index.ts index 5830fa1..ad9fa55 100644 --- a/play-dl/index.ts +++ b/play-dl/index.ts @@ -203,12 +203,14 @@ export function authorization(): void { } export function attachListeners(player: EventEmitter, resource: YouTubeStream | SoundCloudStream) { - player.on(AudioPlayerStatus.Paused, () => resource.pause()); - player.on(AudioPlayerStatus.AutoPaused, () => resource.pause()); - player.on(AudioPlayerStatus.Playing, () => resource.resume()); + const pauseListener = () => resource.pause() + const resumeListener = () => resource.resume() + player.on(AudioPlayerStatus.Paused, pauseListener); + player.on(AudioPlayerStatus.AutoPaused, pauseListener); + player.on(AudioPlayerStatus.Playing, resumeListener); player.once(AudioPlayerStatus.Idle, () => { - player.removeListener(AudioPlayerStatus.Paused, () => resource.pause()); - player.removeListener(AudioPlayerStatus.AutoPaused, () => resource.pause()); - player.removeListener(AudioPlayerStatus.Playing, () => resource.resume()); + player.removeListener(AudioPlayerStatus.Paused, pauseListener); + player.removeListener(AudioPlayerStatus.AutoPaused, pauseListener); + player.removeListener(AudioPlayerStatus.Playing, resumeListener); }); }