mirror of
https://github.com/YuzuZensai/play-dl-test.git
synced 2026-01-31 14:58:05 +00:00
Comments are now added in functions
This commit is contained in:
@@ -9,6 +9,7 @@ interface formatOptions {
|
||||
cipher?: string;
|
||||
s?: string;
|
||||
}
|
||||
// RegExp for various js functions
|
||||
const var_js = '[a-zA-Z_\\$][a-zA-Z_0-9]*';
|
||||
const singlequote_js = `'[^'\\\\]*(:?\\\\[\\s\\S][^'\\\\]*)*'`;
|
||||
const duoblequote_js = `"[^"\\\\]*(:?\\\\[\\s\\S][^"\\\\]*)*"`;
|
||||
@@ -37,7 +38,11 @@ const reverse_regexp = new RegExp(`(?:^|,)(${key_js})${reverse_function}`, 'm');
|
||||
const slice_regexp = new RegExp(`(?:^|,)(${key_js})${slice_function}`, 'm');
|
||||
const splice_regexp = new RegExp(`(?:^|,)(${key_js})${splice_function}`, 'm');
|
||||
const swap_regexp = new RegExp(`(?:^|,)(${key_js})${swap_function}`, 'm');
|
||||
|
||||
/**
|
||||
* Function to get tokens from html5player body data.
|
||||
* @param body body data of html5player.
|
||||
* @returns Array of tokens.
|
||||
*/
|
||||
export function js_tokens(body: string) {
|
||||
const function_action = function_regexp.exec(body);
|
||||
const object_action = obj_regexp.exec(body);
|
||||
@@ -82,7 +87,12 @@ export function js_tokens(body: string) {
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to decipher signature
|
||||
* @param tokens Tokens from js_tokens function
|
||||
* @param signature Signatured format url
|
||||
* @returns deciphered signature
|
||||
*/
|
||||
function deciper_signature(tokens: string[], signature: string) {
|
||||
let sig = signature.split('');
|
||||
const len = tokens.length;
|
||||
@@ -109,14 +119,24 @@ function deciper_signature(tokens: string[], signature: string) {
|
||||
}
|
||||
return sig.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to swap positions in a array
|
||||
* @param array array
|
||||
* @param position position to switch with first element
|
||||
* @returns new array with swapped positions.
|
||||
*/
|
||||
function swappositions(array: string[], position: number) {
|
||||
const first = array[0];
|
||||
array[0] = array[position];
|
||||
array[position] = first;
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Download url with some extra parameter
|
||||
* @param format video fomat
|
||||
* @param sig deciphered signature
|
||||
* @returns void
|
||||
*/
|
||||
function download_url(format: formatOptions, sig: string) {
|
||||
let decoded_url;
|
||||
if (!format.url) return;
|
||||
@@ -132,8 +152,13 @@ function download_url(format: formatOptions, sig: string) {
|
||||
}
|
||||
format.url = parsed_url.toString();
|
||||
}
|
||||
|
||||
export async function format_decipher(formats: formatOptions[], html5player: string) {
|
||||
/**
|
||||
* Main function which handles all queries related to video format deciphering
|
||||
* @param formats video formats
|
||||
* @param html5player url of html5player
|
||||
* @returns array of format.
|
||||
*/
|
||||
export async function format_decipher(formats: formatOptions[], html5player: string): Promise<formatOptions[]> {
|
||||
const body = await request(html5player);
|
||||
const tokens = js_tokens(body);
|
||||
formats.forEach((format) => {
|
||||
|
||||
@@ -17,7 +17,11 @@ const DEFAULT_API_KEY = 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8';
|
||||
const video_pattern =
|
||||
/^((?:https?:)?\/\/)?(?:(?:www|m)\.)?((?:youtube\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(\S+)?$/;
|
||||
const playlist_pattern = /^((?:https?:)?\/\/)?(?:(?:www|m)\.)?(youtube\.com)\/(?:(playlist|watch))(.*)?((\?|\&)list=)/;
|
||||
|
||||
/**
|
||||
* Command to validate a YouTube url
|
||||
* @param url Url for validation
|
||||
* @returns type of url or false.
|
||||
*/
|
||||
export function yt_validate(url: string): 'playlist' | 'video' | false {
|
||||
if (url.indexOf('list=') === -1) {
|
||||
if (!url.match(video_pattern)) return false;
|
||||
@@ -31,7 +35,11 @@ export function yt_validate(url: string): 'playlist' | 'video' | false {
|
||||
return 'playlist';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to extract ID of YouTube url.
|
||||
* @param url ID or url of YouTube
|
||||
* @returns ID of video or playlist.
|
||||
*/
|
||||
export function extractID(url: string): string {
|
||||
if (url.startsWith('https')) {
|
||||
if (url.indexOf('list=') === -1) {
|
||||
@@ -45,7 +53,12 @@ export function extractID(url: string): string {
|
||||
}
|
||||
} else return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic function to get data from a YouTube url or ID.
|
||||
* @param url YouTube url or ID
|
||||
* @param options cookie and proxy parameters to add
|
||||
* @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')) {
|
||||
@@ -123,7 +136,11 @@ export async function video_basic_info(url: string, options: InfoOptions = {}) {
|
||||
related_videos: related
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to convert seconds to [hour : minutes : seconds] format
|
||||
* @param seconds seconds to convert
|
||||
* @returns [hour : minutes : seconds] format
|
||||
*/
|
||||
function parseSeconds(seconds: number): string {
|
||||
const d = Number(seconds);
|
||||
const h = Math.floor(d / 3600);
|
||||
@@ -135,7 +152,12 @@ function parseSeconds(seconds: number): string {
|
||||
const sDisplay = s > 0 ? (s < 10 ? `0${s}` : s) : '00';
|
||||
return hDisplay + mDisplay + sDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function which gets data from video_basic_info and deciphers it if it contains signatures.
|
||||
* @param url YouTube Video URL
|
||||
* @param options cookie and proxy parameters to add
|
||||
* @returns Data containing video_details, LiveStreamData and formats of video url.
|
||||
*/
|
||||
export async function video_info(url: string, options: InfoOptions = {}) {
|
||||
const data = await video_basic_info(url, options);
|
||||
if (data.LiveStreamData.isLive === true && data.LiveStreamData.hlsManifestUrl !== null) {
|
||||
@@ -147,8 +169,13 @@ export async function video_info(url: string, options: InfoOptions = {}) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
export async function playlist_info(url: string, options: PlaylistOptions = {}) {
|
||||
/**
|
||||
* Function to get YouTube playlist info from a playlist url.
|
||||
* @param url Playlist URL
|
||||
* @param options incomplete and proxy to add.
|
||||
* @returns YouTube Playlist
|
||||
*/
|
||||
export async function playlist_info(url: string, options: PlaylistOptions = {}): Promise<YouTubePlayList> {
|
||||
if (!url || typeof url !== 'string') throw new Error(`Expected playlist url, received ${typeof url}!`);
|
||||
let Playlist_id: string;
|
||||
if (url.startsWith('https')) {
|
||||
@@ -184,7 +211,7 @@ export async function playlist_info(url: string, options: PlaylistOptions = {})
|
||||
const videos = getPlaylistVideos(parsed, 100);
|
||||
|
||||
const data = playlistDetails[0].playlistSidebarPrimaryInfoRenderer;
|
||||
if (!data.title.runs || !data.title.runs.length) return undefined;
|
||||
if (!data.title.runs || !data.title.runs.length) throw new Error('Failed to Parse Playlist info.');
|
||||
|
||||
const author = playlistDetails[1]?.playlistSidebarSecondaryInfoRenderer.videoOwner;
|
||||
const views = data.stats.length === 3 ? data.stats[1].simpleText.replace(/[^0-9]/g, '') : 0;
|
||||
@@ -234,7 +261,12 @@ export async function playlist_info(url: string, options: PlaylistOptions = {})
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to parse Playlist from YouTube search
|
||||
* @param data html data of that request
|
||||
* @param limit No. of videos to parse
|
||||
* @returns Array of YouTubeVideo.
|
||||
*/
|
||||
export function getPlaylistVideos(data: any, limit = Infinity): YouTubeVideo[] {
|
||||
const videos = [];
|
||||
|
||||
@@ -270,7 +302,11 @@ export function getPlaylistVideos(data: any, limit = Infinity): YouTubeVideo[] {
|
||||
}
|
||||
return videos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to convert [hour : minutes : seconds] format to seconds
|
||||
* @param duration hour : minutes : seconds format
|
||||
* @returns seconds
|
||||
*/
|
||||
function parseDuration(duration: string): number {
|
||||
duration ??= '0:00';
|
||||
const args = duration.split(':');
|
||||
@@ -289,7 +325,11 @@ function parseDuration(duration: string): number {
|
||||
|
||||
return dur;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get Continuation Token
|
||||
* @param data html data of playlist url
|
||||
* @returns token
|
||||
*/
|
||||
export function getContinuationToken(data: any): string {
|
||||
const continuationToken = data.find((x: any) => Object.keys(x)[0] === 'continuationItemRenderer')
|
||||
?.continuationItemRenderer.continuationEndpoint?.continuationCommand?.token;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { YouTubeVideo } from '../classes/Video';
|
||||
import { YouTubePlayList } from '../classes/Playlist';
|
||||
import { YouTubeChannel } from '../classes/Channel';
|
||||
import { YouTube } from '..';
|
||||
|
||||
export interface ParseSearchInterface {
|
||||
type?: 'video' | 'playlist' | 'channel';
|
||||
@@ -12,11 +13,13 @@ export interface thumbnail {
|
||||
height: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export function ParseSearchResult(
|
||||
html: string,
|
||||
options?: ParseSearchInterface
|
||||
): (YouTubeVideo | YouTubePlayList | YouTubeChannel)[] {
|
||||
/**
|
||||
* Main command which converts html body data and returns the type of data requested.
|
||||
* @param html body of that request
|
||||
* @param options limit & type of YouTube search you want.
|
||||
* @returns Array of one of YouTube type.
|
||||
*/
|
||||
export function ParseSearchResult(html: string, options?: ParseSearchInterface): YouTube[] {
|
||||
if (!html) throw new Error("Can't parse Search result without data");
|
||||
if (!options) options = { type: 'video', limit: 0 };
|
||||
if (!options.type) options.type = 'video';
|
||||
@@ -45,7 +48,11 @@ export function ParseSearchResult(
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to convert [hour : minutes : seconds] format to seconds
|
||||
* @param duration hour : minutes : seconds format
|
||||
* @returns seconds
|
||||
*/
|
||||
function parseDuration(duration: string): number {
|
||||
duration ??= '0:00';
|
||||
const args = duration.split(':');
|
||||
@@ -64,7 +71,11 @@ function parseDuration(duration: string): number {
|
||||
|
||||
return dur;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to parse Channel searches
|
||||
* @param data body of that channel request.
|
||||
* @returns YouTubeChannel class
|
||||
*/
|
||||
export function parseChannel(data?: any): YouTubeChannel {
|
||||
if (!data || !data.channelRenderer) throw new Error('Failed to Parse YouTube Channel');
|
||||
const badge = data.channelRenderer.ownerBadges && data.channelRenderer.ownerBadges[0];
|
||||
@@ -93,7 +104,11 @@ export function parseChannel(data?: any): YouTubeChannel {
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to parse Video searches
|
||||
* @param data body of that video request.
|
||||
* @returns YouTubeVideo class
|
||||
*/
|
||||
export function parseVideo(data?: any): YouTubeVideo {
|
||||
if (!data || !data.videoRenderer) throw new Error('Failed to Parse YouTube Video');
|
||||
|
||||
@@ -133,7 +148,11 @@ export function parseVideo(data?: any): YouTubeVideo {
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to parse Playlist searches
|
||||
* @param data body of that playlist request.
|
||||
* @returns YouTubePlaylist class
|
||||
*/
|
||||
export function parsePlaylist(data?: any): YouTubePlayList {
|
||||
if (!data.playlistRenderer) throw new Error('Failed to Parse YouTube Playlist');
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ import https, { RequestOptions } from 'https';
|
||||
import tls from 'tls';
|
||||
import http, { ClientRequest, IncomingMessage } from 'http';
|
||||
import { URL } from 'url';
|
||||
|
||||
/**
|
||||
* Types for Proxy
|
||||
*/
|
||||
export type Proxy = ProxyOpts | string;
|
||||
|
||||
interface ProxyOpts {
|
||||
@@ -25,7 +27,12 @@ interface RequestOpts extends RequestOptions {
|
||||
method?: 'GET' | 'POST';
|
||||
proxies?: Proxy[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Main module that play-dl uses for making a https request
|
||||
* @param req_url URL to make https request to
|
||||
* @param options Request options for https request
|
||||
* @returns Incoming Message from the https request
|
||||
*/
|
||||
function https_getter(req_url: string, options: RequestOpts = {}): Promise<IncomingMessage> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const s = new URL(req_url);
|
||||
@@ -45,13 +52,23 @@ function https_getter(req_url: string, options: RequestOpts = {}): Promise<Incom
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Chooses one random number between max and min number.
|
||||
* @param min Minimum number
|
||||
* @param max Maximum number
|
||||
* @returns Random Number
|
||||
*/
|
||||
function randomIntFromInterval(min: number, max: number): number {
|
||||
let x = Math.floor(Math.random() * (max - min + 1) + min);
|
||||
if (x === 0) return 0;
|
||||
else return x - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main module that play-dl uses for proxy.
|
||||
* @param req_url URL to make https request to
|
||||
* @param req_proxy Proxies array
|
||||
* @returns Object with statusCode, head and body
|
||||
*/
|
||||
async function proxy_getter(req_url: string, req_proxy: Proxy[]): Promise<ProxyOutput> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const proxy: string | ProxyOpts = req_proxy[randomIntFromInterval(0, req_proxy.length)];
|
||||
@@ -127,7 +144,12 @@ async function proxy_getter(req_url: string, req_proxy: Proxy[]): Promise<ProxyO
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Main module which play-dl uses to make a proxy or normal request
|
||||
* @param url URL to make https request to
|
||||
* @param options Request options for https request
|
||||
* @returns body of that request
|
||||
*/
|
||||
export async function request(url: string, options?: RequestOpts): Promise<string> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (!options?.proxies) {
|
||||
@@ -160,7 +182,12 @@ export async function request(url: string, options?: RequestOpts): Promise<strin
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Main module which play-dl uses to make a request to stream url.
|
||||
* @param url URL to make https request to
|
||||
* @param options Request options for https request
|
||||
* @returns IncomingMessage from the request
|
||||
*/
|
||||
export async function request_stream(url: string, options?: RequestOpts): Promise<IncomingMessage> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let res = await https_getter(url, options).catch((err: Error) => err);
|
||||
|
||||
Reference in New Issue
Block a user