diff --git a/node-youtube-dl/YouTube/classes/Playlist.ts b/node-youtube-dl/YouTube/classes/Playlist.ts new file mode 100644 index 0000000..e69de29 diff --git a/node-youtube-dl/YouTube/classes/Video.ts b/node-youtube-dl/YouTube/classes/Video.ts new file mode 100644 index 0000000..8b6a944 --- /dev/null +++ b/node-youtube-dl/YouTube/classes/Video.ts @@ -0,0 +1,93 @@ +interface VideoOptions { + id?: string; + url? : string; + title?: string; + description?: string; + duration_formatted: string; + duration: number; + uploadedAt?: string; + views: number; + thumbnail?: JSON; + channel?: JSON; + videos?: Video[]; + type : string; + ratings : { + likes: number; + dislikes: number; + } + live: boolean; + private: boolean; + tags: string[]; +} + +export class Video { + id?: string; + title?: string; + description?: string; + durationFormatted: string; + duration: number; + uploadedAt?: string; + views: number; + thumbnail?: JSON; + channel?: JSON; + videos?: Video[]; + likes: number; + dislikes: number; + live: boolean; + private: boolean; + tags: string[]; + + constructor(data : any){ + if(!data) throw new Error(`Can not initiate ${this.constructor.name} without data`) + this.id = data.id || undefined; + this.title = data.title || undefined; + this.description = data.description || undefined; + this.durationFormatted = data.duration_raw || "0:00"; + this.duration = (data.duration < 0 ? 0 : data.duration) || 0; + this.uploadedAt = data.uploadedAt || undefined; + this.views = parseInt(data.views) || 0; + this.thumbnail = data.thumbnail || {}; + this.channel = data.channel || {}; + this.likes = data.ratings?.likes as number || 0; + this.dislikes = data.ratings?.dislikes || 0; + this.live = !!data.live; + this.private = !!data.private; + this.tags = data.tags || []; + } + + get url(){ + if(!this.id) return undefined + else return `https://www.youtube.com/watch?v=${this.id}`; + } + + get type(): "video" { + return "video"; + } + + get toString(): string { + return this.url || ""; + } + + get toJSON(): VideoOptions{ + return { + id: this.id, + url: this.url, + title: this.title, + description: this.description, + duration: this.duration, + duration_formatted: this.durationFormatted, + uploadedAt: this.uploadedAt, + thumbnail: this.thumbnail, + channel: this.channel, + views: this.views, + type: this.type, + tags: this.tags, + ratings: { + likes: this.likes, + dislikes: this.dislikes + }, + live: this.live, + private: this.private + }; + } +} \ No newline at end of file diff --git a/node-youtube-dl/YouTube/index.ts b/node-youtube-dl/YouTube/index.ts new file mode 100644 index 0000000..128af5e --- /dev/null +++ b/node-youtube-dl/YouTube/index.ts @@ -0,0 +1 @@ +export { search } from './search' \ No newline at end of file diff --git a/node-youtube-dl/YouTube/search.ts b/node-youtube-dl/YouTube/search.ts new file mode 100644 index 0000000..8aed895 --- /dev/null +++ b/node-youtube-dl/YouTube/search.ts @@ -0,0 +1,10 @@ +import { url_get } from "./utils/request"; +import fs from 'fs' + + +export async function search(url:string, options? : {limit : number}) { + let body = await url_get(url) + let json_convert = body.split("var ytInitialData = ")[1].split(";")[0] + let result = JSON.parse(json_convert).contents.twoColumnSearchResultsRenderer.primaryContents.sectionListRenderer.contents[0].itemSectionRenderer.contents + console.log(result.length) +} \ No newline at end of file diff --git a/node-youtube-dl/YouTube/utils/cipher.ts b/node-youtube-dl/YouTube/utils/cipher.ts index df2c1c5..e6ebada 100644 --- a/node-youtube-dl/YouTube/utils/cipher.ts +++ b/node-youtube-dl/YouTube/utils/cipher.ts @@ -1,5 +1,5 @@ import { URL } from 'node:url' -import { url_get } from './extractor' +import { url_get } from './request' import querystring from 'node:querystring' interface formatOptions { @@ -102,7 +102,7 @@ export function js_tokens( body:string ) { return tokens } -export function deciper_signature(tokens : string[], signature :string){ +function deciper_signature(tokens : string[], signature :string){ let sig = signature.split('') let len = tokens.length for(let i = 0; i < len; i++ ){ @@ -137,7 +137,7 @@ function swappositions(array : string[], position : number){ return array } -export function download_url(format: formatOptions, sig : string){ +function download_url(format: formatOptions, sig : string){ let decoded_url; if(!format.url) return; decoded_url = format.url diff --git a/node-youtube-dl/YouTube/utils/extractor.ts b/node-youtube-dl/YouTube/utils/extractor.ts index c240591..56e79e1 100644 --- a/node-youtube-dl/YouTube/utils/extractor.ts +++ b/node-youtube-dl/YouTube/utils/extractor.ts @@ -1,14 +1,8 @@ -import fetch from 'node-fetch' +import { url_get } from './request' import { format_decipher, js_tokens } from './cipher' -export function valid_url(url : string): boolean{ - let valid_url = /^https?:\/\/(youtu\.be\/|(www\.)?youtube\.com\/(embed|watch|v|shorts)(\/|\?))/ - if(url.search(valid_url) !== -1) return true - else return false -} export async function yt_initial_data(url : string){ - if(valid_url(url)){ let body = await url_get(url) let player_response = JSON.parse(body.split("var ytInitialPlayerResponse = ")[1].split(";")[0]) let response = JSON.parse(body.split("var ytInitialData = ")[1].split(";")[0]) @@ -45,10 +39,6 @@ export async function yt_initial_data(url : string){ video_details } return final - } - else { - throw 'Not a Valid YouTube URL' - } } export async function yt_deciphered_data(url : string) { @@ -61,14 +51,3 @@ export async function yt_deciphered_data(url : string) { return data } } - -export async function url_get (url : string) : Promise{ - return new Promise(async(resolve, reject) => { - let response = await fetch(url) - - if(response.status === 200) { - resolve(await response.text()) - } - else reject(`Got ${response.status} from ${url}`) - }) -} diff --git a/node-youtube-dl/YouTube/utils/index.ts b/node-youtube-dl/YouTube/utils/index.ts new file mode 100644 index 0000000..f09bebc --- /dev/null +++ b/node-youtube-dl/YouTube/utils/index.ts @@ -0,0 +1 @@ +export { yt_initial_data, yt_deciphered_data } from './extractor' \ No newline at end of file diff --git a/node-youtube-dl/YouTube/utils/parser.ts b/node-youtube-dl/YouTube/utils/parser.ts new file mode 100644 index 0000000..13ddda5 --- /dev/null +++ b/node-youtube-dl/YouTube/utils/parser.ts @@ -0,0 +1,6 @@ +import { Video } from "../classes/Video"; + + +export function ParseSearchResult(html:string) { + +} \ No newline at end of file diff --git a/node-youtube-dl/YouTube/utils/request.ts b/node-youtube-dl/YouTube/utils/request.ts new file mode 100644 index 0000000..89e22d1 --- /dev/null +++ b/node-youtube-dl/YouTube/utils/request.ts @@ -0,0 +1,12 @@ +import fetch, { RequestInit } from 'node-fetch' + +export async function url_get (url : string, options? : RequestInit) : Promise{ + return new Promise(async(resolve, reject) => { + let response = await fetch(url, options) + + if(response.status === 200) { + resolve(await response.text()) + } + else reject(`Got ${response.status} from ${url}`) + }) +} \ No newline at end of file diff --git a/node-youtube-dl/index.ts b/node-youtube-dl/index.ts index 6ac1355..18cc5d6 100644 --- a/node-youtube-dl/index.ts +++ b/node-youtube-dl/index.ts @@ -1,8 +1,8 @@ -import { yt_deciphered_data } from "./YouTube/utils/extractor"; +import { search } from "./YouTube/"; let main = async() => { let time_start = Date.now() - await yt_deciphered_data('https://www.youtube.com/watch?v=jbMHA3P7RzU') + await search('https://www.youtube.com/results?search_query=Hello+Neghibour') let time_end = Date.now() console.log(`Time Taken : ${(time_end - time_start)/1000} seconds`) }