Merge pull request #124 from play-dl/developer

1.1.0
This commit is contained in:
Killer069 2021-10-09 21:36:00 +05:30 committed by GitHub
commit 3f46261a82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 223 additions and 210 deletions

View File

@ -12,7 +12,7 @@ For source specific commands :-
_This checks all type of urls that are supported by play-dl._ _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** `so` = **SoundCloud**
@ -30,6 +30,8 @@ if(check === 'yt_video') // YouTube Video
if(check === 'sp_track') // Spotify Track if(check === 'sp_track') // Spotify Track
if(check === 'so_track') // SoundCloud Track if(check === 'so_track') // SoundCloud Track
if(check === "search") // Given term is not a url. Search this term somewhere.
``` ```
### authorization() ### authorization()

View File

@ -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._ _This checks that given url is soundcloud url or not._
**Returns :** `track` | `playlist` | `false` **Returns :** `track` | `playlist` | `search` | `false`
```js ```js
let check = await so_validate(url) let check = await so_validate(url)
@ -26,6 +26,8 @@ let check = await so_validate(url)
if(!check) // Invalid SoundCloud URL if(!check) // Invalid SoundCloud URL
if(check === 'track') // SoundCloud Track 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 ] ## Classes [ Returned by `soundcloud(url)` function ]

View File

@ -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. 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() ### is_expired()
_This tells that whether the access token is expired or not_ _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` ##### toJSON() `function`
_converts class into a json format_ _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
```

View File

@ -17,7 +17,7 @@ const results = await youtube.search('post malone sunflower', options);
_This will validate url and return type or boolean_ _This will validate url and return type or boolean_
**Returns :** `video` | `playlist` | `false` **Returns :** `video` | `playlist` | `search` | `false`
```js ```js
let check = yt_validate(url) let check = yt_validate(url)
@ -27,6 +27,8 @@ if(!check) // Invalid URL
if(check === "video") //URL is video url if(check === "video") //URL is video url
if(check === "playlist") //URL is a playlist url if(check === "playlist") //URL is a playlist url
if(check === "search") // Given term is not a video ID and PlayList ID.
``` ```
## Extract ID ## Extract ID

View File

@ -1,110 +1,111 @@
import tls , { TLSSocket } from "tls"; import tls, { TLSSocket } from 'tls';
import { URL } from "url"; import { URL } from 'url';
import { Timer } from "../YouTube/classes/LiveStream"; import { Timer } from '../YouTube/classes/LiveStream';
interface ResponseOptions extends tls.ConnectionOptions{ interface ResponseOptions extends tls.ConnectionOptions {
body?: string; body?: string;
method: 'GET' | 'POST'; method: 'GET' | 'POST';
cookies? : boolean cookies?: boolean;
headers? : Object; headers?: Object;
timeout? : number timeout?: number;
} }
export class Response { export class Response {
parsed_url : URL parsed_url: URL;
statusCode : number; statusCode: number;
rawHeaders : string; rawHeaders: string;
headers : Object; headers: Object;
body : string; body: string;
socket : TLSSocket; socket: TLSSocket;
sentHeaders : string; sentHeaders: string;
sentBody : string; sentBody: string;
private options : ResponseOptions; private options: ResponseOptions;
private timer : Timer | null private timer: Timer | null;
constructor(req_url : string, options : ResponseOptions){ constructor(req_url: string, options: ResponseOptions) {
this.parsed_url = new URL(req_url) this.parsed_url = new URL(req_url);
this.sentHeaders = '' this.sentHeaders = '';
this.statusCode = 0 this.statusCode = 0;
this.sentBody = "" this.sentBody = '';
this.rawHeaders = '' this.rawHeaders = '';
this.body = '' this.body = '';
this.headers = {} this.headers = {};
this.timer = null this.timer = null;
this.options = options this.options = options;
this.socket = tls.connect({ this.socket = tls.connect(
host : this.parsed_url.hostname, {
port : Number(this.parsed_url.port) || 443, host: this.parsed_url.hostname,
socket : options.socket, port: Number(this.parsed_url.port) || 443,
rejectUnauthorized : false socket: options.socket,
}, () => this.onConnect()) rejectUnauthorized: false
if(options.headers){ },
for(const [ key, value ] of Object.entries(options.headers)){ () => this.onConnect()
this.sentHeaders += `${key}: ${value}\r\n` );
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.socket.write(
`${this.options.method} ${this.parsed_url.pathname}${this.parsed_url.search} HTTP/1.1\r\n` + `${this.options.method} ${this.parsed_url.pathname}${this.parsed_url.search} HTTP/1.1\r\n` +
`Host : ${this.parsed_url.hostname}\r\n` + `Host : ${this.parsed_url.hostname}\r\n` +
this.sentHeaders + this.sentHeaders +
`Connection: close\r\n` + `Connection: close\r\n` +
`\r\n` + `\r\n` +
this.sentBody this.sentBody
) );
} }
private parseHeaders(){ private parseHeaders() {
const head_arr = this.rawHeaders.split('\r\n') const head_arr = this.rawHeaders.split('\r\n');
this.statusCode = Number(head_arr.shift()?.split(' ')[1]) ?? -1 this.statusCode = Number(head_arr.shift()?.split(' ')[1]) ?? -1;
for(const head of head_arr){ for (const head of head_arr) {
let [ key, value ] = head.split(': ') let [key, value] = head.split(': ');
if(!value) break; if (!value) break;
key = key.trim().toLowerCase() key = key.trim().toLowerCase();
value = value.trim() value = value.trim();
if(Object.keys(this.headers).includes(key)){ if (Object.keys(this.headers).includes(key)) {
let val = (this.headers as any)[key] let val = (this.headers as any)[key];
if(typeof val === 'string') val = [val] if (typeof val === 'string') val = [val];
Object.assign(this.headers, { [key]: [...val, value] }) Object.assign(this.headers, { [key]: [...val, value] });
} } else Object.assign(this.headers, { [key]: value });
else Object.assign(this.headers, { [key] : value })
} }
} }
stream(): Promise<TLSSocket>{ stream(): Promise<TLSSocket> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.timer = new Timer(() => this.socket.end(), this.options.timeout || 1) this.timer = new Timer(() => this.socket.end(), this.options.timeout || 1);
this.socket.once('error', (err) => reject(err)) this.socket.once('error', (err) => reject(err));
this.socket.once('data', (chunk) => { this.socket.once('data', (chunk) => {
this.rawHeaders = chunk.toString('utf-8') this.rawHeaders = chunk.toString('utf-8');
this.parseHeaders() this.parseHeaders();
resolve(this.socket) resolve(this.socket);
}) });
this.socket.on('data', () => this.timer?.reuse()) this.socket.on('data', () => this.timer?.reuse());
this.socket.once('end', () => this.timer?.destroy()) this.socket.once('end', () => this.timer?.destroy());
}) });
} }
fetch(): Promise<Response>{ fetch(): Promise<Response> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.socket.setEncoding('utf-8'); 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) => { this.socket.on('data', (chunk: string) => {
if(this.rawHeaders.length === 0){ if (this.rawHeaders.length === 0) {
this.rawHeaders = chunk this.rawHeaders = chunk;
this.parseHeaders() 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', () => { this.socket.on('end', () => {
resolve(this) resolve(this);
}) });
}) });
} }
} }

View File

@ -1,5 +1,4 @@
import { Response } from "./classes"; import { Response } from './classes';
export type Proxy = ProxyOpts | string; export type Proxy = ProxyOpts | string;
@ -16,38 +15,38 @@ interface RequestOptions {
body?: string; body?: string;
method: 'GET' | 'POST'; method: 'GET' | 'POST';
proxies?: Proxy[]; proxies?: Proxy[];
cookies? : boolean cookies?: boolean;
headers? : Object; headers?: Object;
timeout? : number timeout?: number;
} }
interface StreamGetterOptions{ interface StreamGetterOptions {
method: 'GET' | 'POST'; method: 'GET' | 'POST';
cookies? : boolean cookies?: boolean;
headers : Object; headers: Object;
} }
export function request_stream(req_url : string, options : RequestOptions = {method : "GET"}): Promise<Response>{ export function request_stream(req_url: string, options: RequestOptions = { method: 'GET' }): Promise<Response> {
return new Promise(async(resolve, reject) => { return new Promise(async (resolve, reject) => {
let res = new Response(req_url, options) let res = new Response(req_url, options);
await res.stream() await res.stream();
if (res.statusCode >= 300 && res.statusCode < 400) { if (res.statusCode >= 300 && res.statusCode < 400) {
res = await request_stream((res.headers as any).location, options); 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<Response>{ export function request(req_url: string, options: RequestOptions = { method: 'GET' }): Promise<Response> {
return new Promise(async(resolve, reject) => { return new Promise(async (resolve, reject) => {
let res = new Response(req_url, options) let res = new Response(req_url, options);
await res.fetch() await res.fetch();
if (Number(res.statusCode) >= 300 && Number(res.statusCode) < 400) { if (Number(res.statusCode) >= 300 && Number(res.statusCode) < 400) {
res = await request((res.headers as any).location, options); res = await request((res.headers as any).location, options);
} else if (Number(res.statusCode) > 400) { } else if (Number(res.statusCode) > 400) {
reject(new Error(`Got ${res.statusCode} from the request`)); reject(new Error(`Got ${res.statusCode} from the request`));
} }
resolve(res) resolve(res);
}) });
} }

View File

@ -260,7 +260,7 @@ export class Stream {
} }
private async loop() { 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(); this.cleanup();
return; return;
} }
@ -273,7 +273,7 @@ export class Stream {
return; return;
} }
this.request = stream this.request = stream;
stream.pipe(this.stream, { end: false }); stream.pipe(this.stream, { end: false });
stream.on('end', () => { stream.on('end', () => {
if (this.downloaded_time >= 300) return; if (this.downloaded_time >= 300) return;

View File

@ -126,8 +126,8 @@ export async function check_id(id: string): Promise<boolean> {
* @param url soundcloud url * @param url soundcloud url
* @returns "false" | 'track' | 'playlist' * @returns "false" | 'track' | 'playlist'
*/ */
export async function so_validate(url: string): Promise<false | 'track' | 'playlist'> { export async function so_validate(url: string): Promise<false | 'track' | 'playlist' | 'search'> {
if (!url.match(pattern)) return false; if (!url.match(pattern)) return 'search';
const data = await request( const data = await request(
`https://api-v2.soundcloud.com/resolve?url=${url}&client_id=${soundData.client_id}` `https://api-v2.soundcloud.com/resolve?url=${url}&client_id=${soundData.client_id}`
).catch((err: Error) => err); ).catch((err: Error) => err);

View File

@ -74,8 +74,8 @@ export async function spotify(url: string): Promise<Spotify> {
* @param url url for validation * @param url url for validation
* @returns type of url or false. * @returns type of url or false.
*/ */
export function sp_validate(url: string): 'track' | 'playlist' | 'album' | false { export function sp_validate(url: string): 'track' | 'playlist' | 'album' | 'search' | false {
if (!url.match(pattern)) return false; if (!url.match(pattern)) return 'search';
if (url.indexOf('track/') !== -1) { if (url.indexOf('track/') !== -1) {
return 'track'; return 'track';
} else if (url.indexOf('album/') !== -1) { } else if (url.indexOf('album/') !== -1) {

View File

@ -112,7 +112,7 @@ export class LiveStreaming {
}); });
}); });
} }
this.timer.reuse(); this.timer.reuse();
} }
@ -157,7 +157,7 @@ export class Stream {
this.loop(); this.loop();
}, 265); }, 265);
this.stream.on('close', () => { this.stream.on('close', () => {
this.timer.destroy() this.timer.destroy();
this.cleanup(); this.cleanup();
}); });
this.loop(); this.loop();
@ -178,7 +178,7 @@ export class Stream {
private async loop() { private async loop() {
if (this.stream.destroyed) { if (this.stream.destroyed) {
this.timer.destroy() this.timer.destroy();
this.cleanup(); this.cleanup();
return; return;
} }
@ -198,7 +198,7 @@ export class Stream {
if (Number(stream.statusCode) >= 400) { if (Number(stream.statusCode) >= 400) {
this.cleanup(); this.cleanup();
await this.retry(); await this.retry();
this.timer.reuse() this.timer.reuse();
this.loop(); this.loop();
return; return;
} }
@ -208,7 +208,7 @@ export class Stream {
stream.once('error', async (err) => { stream.once('error', async (err) => {
this.cleanup(); this.cleanup();
await this.retry(); await this.retry();
this.timer.reuse() this.timer.reuse();
this.loop(); this.loop();
}); });
@ -219,7 +219,7 @@ export class Stream {
stream.on('end', () => { stream.on('end', () => {
if (end >= this.content_length) { if (end >= this.content_length) {
this.timer.destroy(); this.timer.destroy();
this.cleanup() this.cleanup();
} }
}); });
} }

View File

@ -71,12 +71,10 @@ export async function stream(url: string, options: StreamOptions = {}): Promise<
if (typeof options.quality !== 'number') options.quality = audioFormat.length - 1; if (typeof options.quality !== 'number') options.quality = audioFormat.length - 1;
else if (options.quality <= 0) options.quality = 0; else if (options.quality <= 0) options.quality = 0;
else if (options.quality >= audioFormat.length) options.quality = audioFormat.length - 1; else if (options.quality >= audioFormat.length) options.quality = audioFormat.length - 1;
if(audioFormat.length !== 0) final.push(audioFormat[options.quality]); if (audioFormat.length !== 0) final.push(audioFormat[options.quality]);
else final.push(info.format[info.format.length - 1]) else final.push(info.format[info.format.length - 1]);
let type: StreamType = let type: StreamType =
final[0].codec === 'opus' && final[0].container === 'webm' final[0].codec === 'opus' && final[0].container === 'webm' ? StreamType.WebmOpus : StreamType.Arbitrary;
? StreamType.WebmOpus
: StreamType.Arbitrary;
return new Stream( return new Stream(
final[0].url, final[0].url,
type, 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; if (typeof options.quality !== 'number') options.quality = audioFormat.length - 1;
else if (options.quality <= 0) options.quality = 0; else if (options.quality <= 0) options.quality = 0;
else if (options.quality >= audioFormat.length) options.quality = audioFormat.length - 1; else if (options.quality >= audioFormat.length) options.quality = audioFormat.length - 1;
if(audioFormat.length !== 0) final.push(audioFormat[options.quality]); if (audioFormat.length !== 0) final.push(audioFormat[options.quality]);
else final.push(info.format[info.format.length - 1]) else final.push(info.format[info.format.length - 1]);
let type: StreamType = let type: StreamType =
final[0].codec === 'opus' && final[0].container === 'webm' final[0].codec === 'opus' && final[0].container === 'webm' ? StreamType.WebmOpus : StreamType.Arbitrary;
? StreamType.WebmOpus
: StreamType.Arbitrary;
return new Stream( return new Stream(
final[0].url, final[0].url,
type, type,

View File

@ -10,22 +10,22 @@ interface youtubeDataOptions {
} }
export function getCookies(): undefined | string { export function getCookies(): undefined | string {
let result = '' let result = '';
if(!youtubeData?.cookie) return undefined if (!youtubeData?.cookie) return undefined;
for (const [ key, value ] of Object.entries(youtubeData.cookie)){ for (const [key, value] of Object.entries(youtubeData.cookie)) {
result+= `${key}=${value};` result += `${key}=${value};`;
} }
return result; return result;
} }
export function setCookie(key: string, value: string): boolean { export function setCookie(key: string, value: string): boolean {
if (!youtubeData?.cookie) return false; if (!youtubeData?.cookie) return false;
key = key.trim() key = key.trim();
value = value.trim() value = value.trim();
Object.assign(youtubeData.cookie, { [key] : value }) Object.assign(youtubeData.cookie, { [key]: value });
return true return true;
} }
export function uploadCookie() { 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));
} }

View File

@ -24,23 +24,25 @@ const playlist_pattern =
* @param url Url for validation * @param url Url for validation
* @returns type of url or false. * @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.indexOf('list=') === -1) {
if (url.startsWith('https')) { if (url.startsWith('https')) {
if (url.match(video_pattern)) return 'video'; if (url.match(video_pattern)) {
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 { } else {
if (url.match(video_id_pattern)) return 'video'; if (url.match(video_id_pattern)) return 'video';
else if (url.match(playlist_id_pattern)) return 'playlist'; else if (url.match(playlist_id_pattern)) return 'playlist';
else return false; else return 'search';
} }
} else { } else {
if (!url.match(playlist_pattern)) return false; if (!url.match(playlist_pattern)) return false;
const Playlist_id = url.split('list=')[1].split('&')[0]; const Playlist_id = url.split('list=')[1].split('&')[0];
if (Playlist_id.length !== 34 || !Playlist_id.startsWith('PL')) { if (Playlist_id.length !== 34 || !Playlist_id.startsWith('PL')) {
return false; return false;
} } else return 'playlist';
else return 'playlist';
} }
} }
/** /**
@ -49,7 +51,8 @@ export function yt_validate(url: string): 'playlist' | 'video' | false {
* @returns ID of video or playlist. * @returns ID of video or playlist.
*/ */
export function extractID(url: string): string { 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.startsWith('https')) {
if (url.indexOf('list=') === -1) { if (url.indexOf('list=') === -1) {
let video_id: string; let video_id: string;
@ -69,16 +72,13 @@ export function extractID(url: string): string {
* @returns Data containing video_details, LiveStreamData and formats of video url. * @returns Data containing video_details, LiveStreamData and formats of video url.
*/ */
export async function video_basic_info(url: string, options: InfoOptions = {}) { export async function video_basic_info(url: string, options: InfoOptions = {}) {
let video_id: string; if (yt_validate(url) !== 'video') throw new Error('This is not a YouTube Watch URL');
if (url.startsWith('https')) { let video_id: string = extractID(url);
if (yt_validate(url) !== 'video') throw new Error('This is not a YouTube Watch URL');
video_id = extractID(url);
} else video_id = url;
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`;
const body = await request(new_url, { const body = await request(new_url, {
proxies: options.proxy ?? undefined, proxies: options.proxy ?? undefined,
headers: { 'accept-language': 'en-US,en-IN;q=0.9,en;q=0.8,hi;q=0.7' }, 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 player_response = JSON.parse(body.split('var ytInitialPlayerResponse = ')[1].split('}};')[0] + '}}');
const initial_response = JSON.parse(body.split('var ytInitialData = ')[1].split('}};')[0] + '}}'); const initial_response = JSON.parse(body.split('var ytInitialData = ')[1].split('}};')[0] + '}}');

View File

@ -27,7 +27,7 @@ interface RequestOpts extends RequestOptions {
body?: string; body?: string;
method?: 'GET' | 'POST'; method?: 'GET' | 'POST';
proxies?: Proxy[]; proxies?: Proxy[];
cookies? : boolean cookies?: boolean;
} }
/** /**
* Main module that play-dl uses for making a https request * Main module that play-dl uses for making a https request
@ -155,12 +155,12 @@ export async function request(url: string, options: RequestOpts = {}): Promise<s
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
if (!options?.proxies || options.proxies.length === 0) { if (!options?.proxies || options.proxies.length === 0) {
let data = ''; let data = '';
let cookies_added = false let cookies_added = false;
if(options.cookies){ if (options.cookies) {
let cook = getCookies() let cook = getCookies();
if (typeof cook === 'string' && options.headers) { if (typeof cook === 'string' && options.headers) {
Object.assign(options.headers, { cookie : cook }); Object.assign(options.headers, { cookie: cook });
cookies_added = true cookies_added = true;
} }
} }
let res = await https_getter(url, options).catch((err: Error) => err); let res = await https_getter(url, options).catch((err: Error) => err);
@ -168,17 +168,17 @@ export async function request(url: string, options: RequestOpts = {}): Promise<s
reject(res); reject(res);
return; return;
} }
if(res.headers && res.headers['set-cookie'] && cookies_added){ if (res.headers && res.headers['set-cookie'] && cookies_added) {
res.headers['set-cookie'].forEach((x) => { res.headers['set-cookie'].forEach((x) => {
x.split(';').forEach((x) => { x.split(';').forEach((x) => {
const arr = x.split('=') const arr = x.split('=');
if(arr.length <= 1 ) return; if (arr.length <= 1) return;
const key = arr.shift()?.trim() as string const key = arr.shift()?.trim() as string;
const value = arr.join('=').trim() const value = arr.join('=').trim();
setCookie(key, value); setCookie(key, value);
}); });
}) });
uploadCookie() uploadCookie();
} }
if (Number(res.statusCode) >= 300 && Number(res.statusCode) < 400) { if (Number(res.statusCode) >= 300 && Number(res.statusCode) < 400) {
res = await https_getter(res.headers.location as string, options); res = await https_getter(res.headers.location as string, options);
@ -189,12 +189,12 @@ export async function request(url: string, options: RequestOpts = {}): Promise<s
res.on('data', (c) => (data += c)); res.on('data', (c) => (data += c));
res.on('end', () => resolve(data)); res.on('end', () => resolve(data));
} else { } else {
let cookies_added = false let cookies_added = false;
if(options.cookies){ if (options.cookies) {
let cook = getCookies() let cook = getCookies();
if (typeof cook === 'string' && options.headers) { if (typeof cook === 'string' && options.headers) {
Object.assign(options.headers, { cookie : cook }); Object.assign(options.headers, { cookie: cook });
cookies_added = true cookies_added = true;
} }
} }
let res = await proxy_getter(url, options.proxies).catch((e: Error) => e); 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<s
reject(res); reject(res);
return; return;
} }
if(res.head && cookies_added){ if (res.head && cookies_added) {
let cookies = res.head.filter((x) => x.toLocaleLowerCase().startsWith('set-cookie: ')); let cookies = res.head.filter((x) => x.toLocaleLowerCase().startsWith('set-cookie: '));
cookies.forEach((x) => { cookies.forEach((x) => {
x.toLocaleLowerCase().split('set-cookie: ')[1].split(';').forEach((y) => { x.toLocaleLowerCase()
const arr = y.split('=') .split('set-cookie: ')[1]
if(arr.length <= 1 ) return; .split(';')
const key = arr.shift()?.trim() as string .forEach((y) => {
const value = arr.join('=').trim() const arr = y.split('=');
setCookie(key, value); 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) { if (res.statusCode >= 300 && res.statusCode < 400) {
let url = res.head.filter((x) => x.startsWith('Location: ')); let url = res.head.filter((x) => x.startsWith('Location: '));

View File

@ -90,8 +90,11 @@ export async function stream_from_info(
*/ */
export async function validate( export async function validate(
url: string url: string
): Promise<'so_playlist' | 'so_track' | 'sp_track' | 'sp_album' | 'sp_playlist' | 'yt_video' | 'yt_playlist' | false> { ): Promise<
'so_playlist' | 'so_track' | 'sp_track' | 'sp_album' | 'sp_playlist' | 'yt_video' | 'yt_playlist' | 'search' | false
> {
let check; let check;
if (!url.startsWith('https')) return 'search';
if (url.indexOf('spotify') !== -1) { if (url.indexOf('spotify') !== -1) {
check = sp_validate(url); 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') : false;
@ -183,12 +186,12 @@ export function authorization(): void {
console.log('Cookies has been added successfully.'); console.log('Cookies has been added successfully.');
let cookie: Object = {}; let cookie: Object = {};
cook.split(';').forEach((x) => { cook.split(';').forEach((x) => {
const arr = x.split('=') const arr = x.split('=');
if(arr.length <= 1 ) return; if (arr.length <= 1) return;
const key = arr.shift()?.trim() as string const key = arr.shift()?.trim() as string;
const value = arr.join('=').trim() const value = arr.join('=').trim();
Object.assign(cookie, { [key] : value }) Object.assign(cookie, { [key]: value });
}) });
fs.writeFileSync('.data/youtube.data', JSON.stringify({ cookie }, undefined, 4)); fs.writeFileSync('.data/youtube.data', JSON.stringify({ cookie }, undefined, 4));
ask.close(); ask.close();
}); });
@ -200,12 +203,14 @@ export function authorization(): void {
} }
export function attachListeners(player: EventEmitter, resource: YouTubeStream | SoundCloudStream) { export function attachListeners(player: EventEmitter, resource: YouTubeStream | SoundCloudStream) {
player.on(AudioPlayerStatus.Paused, () => resource.pause()); const pauseListener = () => resource.pause()
player.on(AudioPlayerStatus.AutoPaused, () => resource.pause()); const resumeListener = () => resource.resume()
player.on(AudioPlayerStatus.Playing, () => resource.resume()); player.on(AudioPlayerStatus.Paused, pauseListener);
player.on(AudioPlayerStatus.AutoPaused, pauseListener);
player.on(AudioPlayerStatus.Playing, resumeListener);
player.once(AudioPlayerStatus.Idle, () => { player.once(AudioPlayerStatus.Idle, () => {
player.removeListener(AudioPlayerStatus.Paused, () => resource.pause()); player.removeListener(AudioPlayerStatus.Paused, pauseListener);
player.removeListener(AudioPlayerStatus.AutoPaused, () => resource.pause()); player.removeListener(AudioPlayerStatus.AutoPaused, pauseListener);
player.removeListener(AudioPlayerStatus.Playing, () => resource.resume()); player.removeListener(AudioPlayerStatus.Playing, resumeListener);
}); });
}; }