Docs + Pretty code

This commit is contained in:
killer069 2021-10-12 14:09:14 +05:30
parent 229bbc7a11
commit bd4afbe82a
11 changed files with 118 additions and 89 deletions

View File

@ -42,6 +42,33 @@ _This creates basic spotify / soundcloud / youtube data to be stored locally._
authorization() //After then you will be asked about type of data you want to create and then follow the steps properly. authorization() //After then you will be asked about type of data you want to create and then follow the steps properly.
``` ```
### setToken(options : `TokenOptions`)
_This sets token without using file._
```js
setToken({
spotify : {
client_id : "ID"
client_secret : "Secret"
refresh_token : "Token"
market : "Country Code"
}
}) // Setting Spotify Token [ To get refresh_token, just run through authorization, and set file save to No ]
setToken({
soundcloud : {
client_id : "ID"
}
}) // Setting SoundCloud Token
setToken({
youtube : {
cookie : "Cookies"
}
}) // Warning : Using setToken for youtube cookies will only update cookies present in memory only.
```
### Search ### Search
#### SearchOptions : #### SearchOptions :

View File

@ -15,7 +15,7 @@ export class Proxy {
socket: TLSSocket; socket: TLSSocket;
sentHeaders: string; sentHeaders: string;
private options: ProxyOptions; private options: ProxyOptions;
constructor(parsed_url: URL, options: ProxyOptions){ constructor(parsed_url: URL, options: ProxyOptions) {
this.parsed_url = parsed_url; this.parsed_url = parsed_url;
this.sentHeaders = ''; this.sentHeaders = '';
this.statusCode = 0; this.statusCode = 0;
@ -42,10 +42,10 @@ export class Proxy {
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`
); );
} }

View File

@ -1,12 +1,12 @@
import http, { ClientRequest, IncomingMessage } from 'http'; import http, { ClientRequest, IncomingMessage } from 'http';
import https ,{ RequestOptions } from 'https'; import https, { RequestOptions } from 'https';
import { URL } from 'url'; import { URL } from 'url';
import { getCookies, setCookie, uploadCookie } from '../YouTube/utils/cookie'; import { getCookies, setCookie, uploadCookie } from '../YouTube/utils/cookie';
import { Proxy } from './classes'; import { Proxy } from './classes';
export type ProxyOptions = ProxyOpts | string; export type ProxyOptions = ProxyOpts | string;
interface RequestOpts extends RequestOptions{ interface RequestOpts extends RequestOptions {
body?: string; body?: string;
method?: 'GET' | 'POST'; method?: 'GET' | 'POST';
proxies?: ProxyOptions[]; proxies?: ProxyOptions[];
@ -83,8 +83,7 @@ export function request(req_url: string, options: RequestOpts = { method: 'GET'
res.setEncoding('utf-8'); res.setEncoding('utf-8');
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();
@ -115,7 +114,7 @@ export function request(req_url: string, options: RequestOpts = { method: 'GET'
} else if (res.statusCode > 400) { } else if (res.statusCode > 400) {
reject(new Error(`GOT ${res.statusCode} from proxy request`)); reject(new Error(`GOT ${res.statusCode} from proxy request`));
} }
resolve(res.body) resolve(res.body);
} }
}); });
} }
@ -126,7 +125,7 @@ export function request(req_url: string, options: RequestOpts = { method: 'GET'
* @param max Maximum number * @param max Maximum number
* @returns Random Number * @returns Random Number
*/ */
function randomIntFromInterval(min: number, max: number): number { function randomIntFromInterval(min: number, max: number): number {
let x = Math.floor(Math.random() * (max - min + 1) + min); let x = Math.floor(Math.random() * (max - min + 1) + min);
if (x === 0) return 0; if (x === 0) return 0;
else return x - 1; else return x - 1;
@ -137,10 +136,10 @@ export function request(req_url: string, options: RequestOpts = { method: 'GET'
* @param req_proxy Proxies array * @param req_proxy Proxies array
* @returns Object with statusCode, head and body * @returns Object with statusCode, head and body
*/ */
function proxy_getter(req_url : string, req_proxy : ProxyOptions[], headers? : Object): Promise<Proxy>{ function proxy_getter(req_url: string, req_proxy: ProxyOptions[], headers?: Object): Promise<Proxy> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const proxy: string | ProxyOpts = req_proxy[randomIntFromInterval(0, req_proxy.length)]; const proxy: string | ProxyOpts = req_proxy[randomIntFromInterval(0, req_proxy.length)];
const parsed_url = new URL(req_url) const parsed_url = new URL(req_url);
let opts: ProxyOpts; let opts: ProxyOpts;
if (typeof proxy === 'string') { if (typeof proxy === 'string') {
const parsed = new URL(proxy); const parsed = new URL(proxy);
@ -175,14 +174,14 @@ function proxy_getter(req_url : string, req_proxy : ProxyOptions[], headers? : O
}); });
} }
req.on('connect', async function (res, socket) { req.on('connect', async function (res, socket) {
const conn_proxy = new Proxy(parsed_url, { method : "GET", socket : socket, headers : headers }) const conn_proxy = new Proxy(parsed_url, { method: 'GET', socket: socket, headers: headers });
await conn_proxy.fetch() await conn_proxy.fetch();
socket.end() socket.end();
resolve(conn_proxy) resolve(conn_proxy);
}) });
req.on('error', (e: Error) => reject(e)); req.on('error', (e: Error) => reject(e));
req.end(); req.end();
}) });
} }
/** /**
@ -191,7 +190,7 @@ function proxy_getter(req_url : string, req_proxy : ProxyOptions[], headers? : O
* @param options Request options for https request * @param options Request options for https request
* @returns Incoming Message from the https request * @returns Incoming Message from the https request
*/ */
function https_getter(req_url: string, options: RequestOpts = {}): Promise<IncomingMessage> { function https_getter(req_url: string, options: RequestOpts = {}): Promise<IncomingMessage> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const s = new URL(req_url); const s = new URL(req_url);
options.method ??= 'GET'; options.method ??= 'GET';

View File

@ -212,7 +212,7 @@ export class Stream {
private time: number[]; private time: number[];
private segment_urls: string[]; private segment_urls: string[];
constructor(url: string, type: StreamType = StreamType.Arbitrary) { constructor(url: string, type: StreamType = StreamType.Arbitrary) {
this.stream = new Readable({ highWaterMark: 10 * 1000 * 1000, read(){} }); this.stream = new Readable({ highWaterMark: 10 * 1000 * 1000, read() {} });
this.type = type; this.type = type;
this.url = url; this.url = url;
this.downloaded_time = 0; this.downloaded_time = 0;
@ -275,8 +275,8 @@ export class Stream {
this.request = stream; this.request = stream;
stream.on('data', (c) => { stream.on('data', (c) => {
this.stream.push(c) this.stream.push(c);
}) });
stream.on('end', () => { stream.on('end', () => {
if (this.downloaded_time >= 300) return; if (this.downloaded_time >= 300) return;
else this.loop(); else this.loop();

View File

@ -152,6 +152,6 @@ function parseHlsFormats(data: SoundCloudTrackFormat[]) {
return result; return result;
} }
export function setSoundCloudToken(options : SoundDataOptions){ export function setSoundCloudToken(options: SoundDataOptions) {
soundData = options soundData = options;
} }

View File

@ -5,7 +5,7 @@ import fs from 'fs';
let spotifyData: SpotifyDataOptions; let spotifyData: SpotifyDataOptions;
if (fs.existsSync('.data/spotify.data')) { if (fs.existsSync('.data/spotify.data')) {
spotifyData = JSON.parse(fs.readFileSync('.data/spotify.data').toString()); spotifyData = JSON.parse(fs.readFileSync('.data/spotify.data').toString());
spotifyData.file = true spotifyData.file = true;
} }
/** /**
* Spotify Data options that are stored in spotify.data file. * Spotify Data options that are stored in spotify.data file.
@ -21,7 +21,7 @@ export interface SpotifyDataOptions {
expires_in?: number; expires_in?: number;
expiry?: number; expiry?: number;
market?: string; market?: string;
file? : boolean file?: boolean;
} }
const pattern = /^((https:)?\/\/)?open.spotify.com\/(track|album|playlist)\//; const pattern = /^((https:)?\/\/)?open.spotify.com\/(track|album|playlist)\//;
@ -91,7 +91,7 @@ export function sp_validate(url: string): 'track' | 'playlist' | 'album' | 'sear
* @param data Sportify Data options to validate * @param data Sportify Data options to validate
* @returns boolean. * @returns boolean.
*/ */
export async function SpotifyAuthorize(data: SpotifyDataOptions, file : boolean): Promise<boolean> { export async function SpotifyAuthorize(data: SpotifyDataOptions, file: boolean): Promise<boolean> {
const response = await request(`https://accounts.spotify.com/api/token`, { const response = await request(`https://accounts.spotify.com/api/token`, {
headers: { headers: {
'Authorization': `Basic ${Buffer.from(`${data.client_id}:${data.client_secret}`).toString('base64')}`, 'Authorization': `Basic ${Buffer.from(`${data.client_id}:${data.client_secret}`).toString('base64')}`,
@ -117,13 +117,13 @@ export async function SpotifyAuthorize(data: SpotifyDataOptions, file : boolean)
token_type: resp_json.token_type, token_type: resp_json.token_type,
market: data.market market: data.market
}; };
if(file) fs.writeFileSync('.data/spotify.data', JSON.stringify(spotifyData, undefined, 4)); if (file) fs.writeFileSync('.data/spotify.data', JSON.stringify(spotifyData, undefined, 4));
else { else {
console.log(`Client ID : ${spotifyData.client_id}`) console.log(`Client ID : ${spotifyData.client_id}`);
console.log(`Client Secret : ${spotifyData.client_secret}`) console.log(`Client Secret : ${spotifyData.client_secret}`);
console.log(`Refresh Token : ${spotifyData.refresh_token}`) console.log(`Refresh Token : ${spotifyData.refresh_token}`);
console.log(`Market : ${spotifyData.market}`) console.log(`Market : ${spotifyData.market}`);
console.log(`\nPaste above info in setToken function.`) console.log(`\nPaste above info in setToken function.`);
} }
return true; return true;
} }
@ -207,12 +207,12 @@ export async function refreshToken(): Promise<boolean> {
spotifyData.expires_in = Number(resp_json.expires_in); spotifyData.expires_in = Number(resp_json.expires_in);
spotifyData.expiry = Date.now() + (resp_json.expires_in - 1) * 1000; spotifyData.expiry = Date.now() + (resp_json.expires_in - 1) * 1000;
spotifyData.token_type = resp_json.token_type; spotifyData.token_type = resp_json.token_type;
if(spotifyData.file) fs.writeFileSync('.data/spotify.data', JSON.stringify(spotifyData, undefined, 4)); if (spotifyData.file) fs.writeFileSync('.data/spotify.data', JSON.stringify(spotifyData, undefined, 4));
return true; return true;
} }
export function setSpotifyToken(options: SpotifyDataOptions) { export function setSpotifyToken(options: SpotifyDataOptions) {
spotifyData = options spotifyData = options;
spotifyData.file = false spotifyData.file = false;
refreshToken() refreshToken();
} }

View File

@ -23,7 +23,7 @@ export class LiveStreaming {
private segments_urls: string[]; private segments_urls: string[];
private request: IncomingMessage | null; private request: IncomingMessage | null;
constructor(dash_url: string, target_interval: number, video_url: string) { constructor(dash_url: string, target_interval: number, video_url: string) {
this.stream = new Readable({ highWaterMark: 10 * 1000 * 1000, read(){} }); this.stream = new Readable({ highWaterMark: 10 * 1000 * 1000, read() {} });
this.type = StreamType.Arbitrary; this.type = StreamType.Arbitrary;
this.url = dash_url; this.url = dash_url;
this.base_url = ''; this.base_url = '';
@ -102,8 +102,8 @@ export class LiveStreaming {
} }
this.request = stream; this.request = stream;
stream.on('data', (c) => { stream.on('data', (c) => {
this.stream.push(c) this.stream.push(c);
}) });
stream.on('end', () => { stream.on('end', () => {
this.packet_count++; this.packet_count++;
resolve(''); resolve('');
@ -143,7 +143,7 @@ export class Stream {
video_url: string, video_url: string,
options: StreamOptions options: StreamOptions
) { ) {
this.stream = new Readable({ highWaterMark : 10 * 1000 * 1000, read(){} }); this.stream = new Readable({ highWaterMark: 10 * 1000 * 1000, read() {} });
this.url = url; this.url = url;
this.quality = options.quality as number; this.quality = options.quality as number;
this.proxy = options.proxy || undefined; this.proxy = options.proxy || undefined;
@ -204,8 +204,8 @@ export class Stream {
} }
this.request = stream; this.request = stream;
stream.on('data', (c) => { stream.on('data', (c) => {
this.stream.push(c) this.stream.push(c);
}) });
stream.once('error', async (err) => { stream.once('error', async (err) => {
this.cleanup(); this.cleanup();

View File

@ -3,12 +3,12 @@ import fs from 'fs';
let youtubeData: youtubeDataOptions; let youtubeData: youtubeDataOptions;
if (fs.existsSync('.data/youtube.data')) { if (fs.existsSync('.data/youtube.data')) {
youtubeData = JSON.parse(fs.readFileSync('.data/youtube.data').toString()); youtubeData = JSON.parse(fs.readFileSync('.data/youtube.data').toString());
youtubeData.file = true youtubeData.file = true;
} }
interface youtubeDataOptions { interface youtubeDataOptions {
cookie?: Object; cookie?: Object;
file? : boolean; file?: boolean;
} }
export function getCookies(): undefined | string { export function getCookies(): undefined | string {
@ -29,11 +29,12 @@ export function setCookie(key: string, value: string): boolean {
} }
export function uploadCookie() { export function uploadCookie() {
if (youtubeData.cookie && youtubeData.file) fs.writeFileSync('.data/youtube.data', JSON.stringify(youtubeData, undefined, 4)); if (youtubeData.cookie && youtubeData.file)
fs.writeFileSync('.data/youtube.data', JSON.stringify(youtubeData, undefined, 4));
} }
export function setCookieToken(options : { cookie : string }){ export function setCookieToken(options: { cookie: string }) {
let cook = options.cookie let cook = options.cookie;
let cookie: Object = {}; let cookie: Object = {};
cook.split(';').forEach((x) => { cook.split(';').forEach((x) => {
const arr = x.split('='); const arr = x.split('=');
@ -42,6 +43,6 @@ export function setCookieToken(options : { cookie : string }){
const value = arr.join('=').trim(); const value = arr.join('=').trim();
Object.assign(cookie, { [key]: value }); Object.assign(cookie, { [key]: value });
}); });
youtubeData = { cookie } youtubeData = { cookie };
youtubeData.file = false youtubeData.file = false;
} }

View File

@ -30,7 +30,8 @@ export function yt_validate(url: string): 'playlist' | 'video' | 'search' | fals
if (url.match(video_pattern)) { if (url.match(video_pattern)) {
let id: string; let id: string;
if (url.includes('youtu.be/')) id = url.split('youtu.be/')[1].split(/(\?|\/|&)/)[0]; if (url.includes('youtu.be/')) id = url.split('youtu.be/')[1].split(/(\?|\/|&)/)[0];
else if (url.includes('youtube.com/embed/')) id = url.split('youtube.com/embed/')[1].split(/(\?|\/|&)/)[0]; else if (url.includes('youtube.com/embed/'))
id = url.split('youtube.com/embed/')[1].split(/(\?|\/|&)/)[0];
else id = url.split('watch?v=')[1].split(/(\?|\/|&)/)[0]; else id = url.split('watch?v=')[1].split(/(\?|\/|&)/)[0];
if (id.match(video_id_pattern)) return 'video'; if (id.match(video_id_pattern)) return 'video';
else return false; else return false;
@ -57,7 +58,8 @@ export function extractID(url: string): string {
if (url.indexOf('list=') === -1) { if (url.indexOf('list=') === -1) {
let video_id: string; let video_id: string;
if (url.includes('youtu.be/')) video_id = url.split('youtu.be/')[1].split(/(\?|\/|&)/)[0]; if (url.includes('youtu.be/')) video_id = url.split('youtu.be/')[1].split(/(\?|\/|&)/)[0];
else if (url.includes('youtube.com/embed/')) video_id = url.split('youtube.com/embed/')[1].split(/(\?|\/|&)/)[0]; else if (url.includes('youtube.com/embed/'))
video_id = url.split('youtube.com/embed/')[1].split(/(\?|\/|&)/)[0];
else video_id = url.split('watch?v=')[1].split(/(\?|\/|&)/)[0]; else video_id = url.split('watch?v=')[1].split(/(\?|\/|&)/)[0];
return video_id; return video_id;
} else { } else {

View File

@ -1,7 +1,7 @@
export { playlist_info, video_basic_info, video_info, yt_validate, extractID, YouTube, YouTubeStream } from './YouTube'; export { playlist_info, video_basic_info, video_info, yt_validate, extractID, YouTube, YouTubeStream } from './YouTube';
export { spotify, sp_validate, refreshToken, is_expired, Spotify } from './Spotify'; export { spotify, sp_validate, refreshToken, is_expired, Spotify } from './Spotify';
export { soundcloud, so_validate, SoundCloud, SoundCloudStream } from './SoundCloud'; export { soundcloud, so_validate, SoundCloud, SoundCloudStream } from './SoundCloud';
export { setToken } from './token' export { setToken } from './token';
enum AudioPlayerStatus { enum AudioPlayerStatus {
Idle = 'idle', Idle = 'idle',
@ -116,9 +116,9 @@ export function authorization(): void {
output: process.stdout output: process.stdout
}); });
ask.question('Do you want to save data in a file ? (Yes / No): ', (msg) => { ask.question('Do you want to save data in a file ? (Yes / No): ', (msg) => {
let file : boolean; let file: boolean;
if(msg.toLowerCase() === 'yes') file = true if (msg.toLowerCase() === 'yes') file = true;
else if(msg.toLowerCase() === 'no') file = false else if (msg.toLowerCase() === 'no') file = false;
else { else {
console.log("That option doesn't exist. Try again..."); console.log("That option doesn't exist. Try again...");
ask.close(); ask.close();
@ -170,8 +170,8 @@ export function authorization(): void {
}); });
}); });
} else if (msg.toLowerCase().startsWith('sc')) { } else if (msg.toLowerCase().startsWith('sc')) {
if(!file){ if (!file) {
console.log("You already had a client ID, just paste that in setToken function."); console.log('You already had a client ID, just paste that in setToken function.');
ask.close(); ask.close();
return; return;
} }
@ -191,8 +191,8 @@ export function authorization(): void {
ask.close(); ask.close();
}); });
} else if (msg.toLowerCase().startsWith('yo')) { } else if (msg.toLowerCase().startsWith('yo')) {
if(!file){ if (!file) {
console.log("You already had cookie, just paste that in setToken function."); console.log('You already had cookie, just paste that in setToken function.');
ask.close(); ask.close();
return; return;
} }
@ -220,12 +220,12 @@ export function authorization(): void {
ask.close(); ask.close();
} }
}); });
}) });
} }
export function attachListeners(player: EventEmitter, resource: YouTubeStream | SoundCloudStream) { export function attachListeners(player: EventEmitter, resource: YouTubeStream | SoundCloudStream) {
const pauseListener = () => resource.pause() const pauseListener = () => resource.pause();
const resumeListener = () => resource.resume() const resumeListener = () => resource.resume();
player.on(AudioPlayerStatus.Paused, pauseListener); player.on(AudioPlayerStatus.Paused, pauseListener);
player.on(AudioPlayerStatus.AutoPaused, pauseListener); player.on(AudioPlayerStatus.AutoPaused, pauseListener);
player.on(AudioPlayerStatus.Playing, resumeListener); player.on(AudioPlayerStatus.Playing, resumeListener);

View File

@ -1,24 +1,24 @@
import { setSoundCloudToken } from "./SoundCloud"; import { setSoundCloudToken } from './SoundCloud';
import { setSpotifyToken } from "./Spotify"; import { setSpotifyToken } from './Spotify';
import { setCookieToken } from "./YouTube/utils/cookie"; import { setCookieToken } from './YouTube/utils/cookie';
interface tokenOptions { interface tokenOptions {
spotify? : { spotify?: {
client_id : string client_id: string;
client_secret : string; client_secret: string;
refresh_token : string refresh_token: string;
market : string market: string;
} };
soundcloud? : { soundcloud?: {
client_id : string client_id: string;
} };
youtube? : { youtube?: {
cookie : string cookie: string;
} };
} }
export function setToken(options : tokenOptions){ export function setToken(options: tokenOptions) {
if(options.spotify) setSpotifyToken(options.spotify) if (options.spotify) setSpotifyToken(options.spotify);
if(options.soundcloud) setSoundCloudToken(options.soundcloud) if (options.soundcloud) setSoundCloudToken(options.soundcloud);
if(options.youtube) setCookieToken(options.youtube) if (options.youtube) setCookieToken(options.youtube);
} }