From 497b1aa61dad84ea9e748c69190dfbc4e75bed95 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 23 Aug 2021 13:05:40 +0530 Subject: [PATCH 1/4] added some new properties --- play-dl/YouTube/classes/Video.ts | 8 ++++---- play-dl/YouTube/utils/extractor.ts | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/play-dl/YouTube/classes/Video.ts b/play-dl/YouTube/classes/Video.ts index bb1969e..0d51d22 100644 --- a/play-dl/YouTube/classes/Video.ts +++ b/play-dl/YouTube/classes/Video.ts @@ -6,8 +6,8 @@ interface VideoOptions { url? : string; title?: string; description?: string; - duration_formatted: string; - duration: number; + durationRaw: string; + durationInSec: number; uploadedAt?: string; views: number; thumbnail?: { @@ -84,8 +84,8 @@ export class Video { url: this.url, title: this.title, description: this.description, - duration: this.duration, - duration_formatted: this.durationFormatted, + durationInSec: this.duration, + durationRaw: this.durationFormatted, uploadedAt: this.uploadedAt, thumbnail: this.thumbnail?.toJSON(), channel: { diff --git a/play-dl/YouTube/utils/extractor.ts b/play-dl/YouTube/utils/extractor.ts index 986e5d3..7d3e30e 100644 --- a/play-dl/YouTube/utils/extractor.ts +++ b/play-dl/YouTube/utils/extractor.ts @@ -23,7 +23,8 @@ export async function video_basic_info(url : string){ url : 'https://www.youtube.com/watch?v=' + vid.videoId, title : vid.title, description : vid.shortDescription, - duration : vid.lengthSeconds, + durationInSec : vid.lengthSeconds, + durationRaw : parseSeconds(vid.lengthSeconds), uploadedDate : microformat.publishDate, thumbnail : { width : vid.thumbnail.thumbnails[vid.thumbnail.thumbnails.length - 1].width, @@ -56,6 +57,18 @@ export async function video_basic_info(url : string){ } } +function parseSeconds(seconds : number): string { + let d = Number(seconds); + var h = Math.floor(d / 3600); + var m = Math.floor(d % 3600 / 60); + var s = Math.floor(d % 3600 % 60); + + var hDisplay = h > 0 ? (h < 10 ? `0${h}` : h) + ':' : ""; + var mDisplay = m > 0 ? (m < 10 ? `0${m}` : m) + ':' : "00:"; + var sDisplay = s > 0 ? (s < 10 ? `0${s}` : s) : "00"; + return hDisplay + mDisplay + sDisplay; +} + export async function video_info(url : string) { let data = await video_basic_info(url) if(data.LiveStreamData.isLive === true && data.LiveStreamData.hlsManifestUrl !== null){ From 415c0c0f2cbc32a5d43da438d5c1830feefb1f4b Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 23 Aug 2021 15:22:18 +0530 Subject: [PATCH 2/4] feat new properties --- play-dl/YouTube/classes/Video.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/play-dl/YouTube/classes/Video.ts b/play-dl/YouTube/classes/Video.ts index 0d51d22..40ce821 100644 --- a/play-dl/YouTube/classes/Video.ts +++ b/play-dl/YouTube/classes/Video.ts @@ -37,8 +37,8 @@ export class Video { url? : string; title?: string; description?: string; - durationFormatted: string; - duration: number; + durationRaw: string; + durationInSec: number; uploadedAt?: string; views: number; thumbnail?: Thumbnail; @@ -57,8 +57,8 @@ export class Video { this.url = `https://www.youtube.com/watch?v=${this.id}` 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.durationRaw = data.duration_raw || "0:00"; + this.durationInSec = (data.duration < 0 ? 0 : data.duration) || 0; this.uploadedAt = data.uploadedAt || undefined; this.views = parseInt(data.views) || 0; this.thumbnail = data.thumbnail || {}; @@ -84,8 +84,8 @@ export class Video { url: this.url, title: this.title, description: this.description, - durationInSec: this.duration, - durationRaw: this.durationFormatted, + durationInSec: this.durationInSec, + durationRaw: this.durationRaw, uploadedAt: this.uploadedAt, thumbnail: this.thumbnail?.toJSON(), channel: { From 5dd4122d9f53689e7b9b27a4b9c5c210cab7ab79 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 23 Aug 2021 23:34:10 +0530 Subject: [PATCH 3/4] PlayList and Video Error Fixed --- play-dl/YouTube/utils/extractor.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/play-dl/YouTube/utils/extractor.ts b/play-dl/YouTube/utils/extractor.ts index 7d3e30e..936e9c5 100644 --- a/play-dl/YouTube/utils/extractor.ts +++ b/play-dl/YouTube/utils/extractor.ts @@ -8,7 +8,10 @@ const video_pattern = /^((?:https?:)?\/\/)?(?:(?:www|m)\.)?((?:youtube\.com|yout export async function video_basic_info(url : string){ if(!url.match(video_pattern)) throw new Error('This is not a YouTube URL') - let video_id = url.split('watch?v=')[1].split('&')[0] + let video_id : string; + if(url.includes('youtu.be/')) video_id = url.split('youtu.be/')[1] + else if(url.includes('youtube.com/embed/')) video_id = url.split('youtube.com/embed/')[1] + else video_id = url.split('watch?v=')[1].split('&')[0]; let new_url = 'https://www.youtube.com/watch?v=' + video_id let body = await url_get(new_url) let player_response = JSON.parse(body.split("var ytInitialPlayerResponse = ")[1].split("}};")[0] + '}}') @@ -113,7 +116,10 @@ export async function playlist_info(url : string) { let body = await url_get(new_url) let response = JSON.parse(body.split("var ytInitialData = ")[1].split(";")[0]) - if(response.alerts && response.alerts[0].alertRenderer.type === 'ERROR') throw new Error(`While parsing playlist url\n ${response.alerts[0].alertRenderer.text.runs[0].text}`) + if(response.alerts){ + if(response.alerts[0].alertRenderer?.type === 'ERROR') throw new Error(`While parsing playlist url\n ${response.alerts[0].alertRenderer.text.runs[0].text}`) + else throw new Error('While parsing playlist url\n Unknown Playlist Error') + } let rawJSON = `${body.split('{"playlistVideoListRenderer":{"contents":')[1].split('}],"playlistId"')[0]}}]`; let parsed = JSON.parse(rawJSON); From 6252494615c1039112cef4bd0bbdcc9d89995e42 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 24 Aug 2021 12:50:06 +0530 Subject: [PATCH 4/4] Stream fixes --- play-dl/YouTube/classes/LiveStream.ts | 96 ++++++++++++++++++++++++--- play-dl/YouTube/stream.ts | 4 +- 2 files changed, 90 insertions(+), 10 deletions(-) diff --git a/play-dl/YouTube/classes/LiveStream.ts b/play-dl/YouTube/classes/LiveStream.ts index 57f6562..f09671f 100644 --- a/play-dl/YouTube/classes/LiveStream.ts +++ b/play-dl/YouTube/classes/LiveStream.ts @@ -195,16 +195,96 @@ export class LiveEnded{ export class Stream { type : StreamType - private piping_stream : Request - private playing_stream : PassThrough - constructor(url : string, type : StreamType){ + stream : PassThrough + private url : string + private bytes_count : number; + private per_sec_bytes : number; + private duration : number; + private timer : NodeJS.Timer | null + constructor(url : string, type : StreamType, duration : number){ + this.url = url this.type = type - this.piping_stream = got.stream(url) - this.playing_stream = new PassThrough({ highWaterMark : 10 * 1000 * 1000 }) - this.piping_stream.pipe(this.playing_stream) + this.stream = new PassThrough({ highWaterMark : 10 * 1000 * 1000 }) + this.bytes_count = 0 + this.per_sec_bytes = 0 + this.timer = null + this.duration = duration; + (duration > 300) ? this.loop_start() : this.normal_start() } - get stream(){ - return this.playing_stream + private cleanup(){ + clearTimeout(this.timer as NodeJS.Timer) + this.timer = null + this.url = '' + this.bytes_count = 0 + this.per_sec_bytes = 0 + } + + private normal_start(){ + if(this.stream.destroyed){ + this.cleanup() + return + } + let stream = got.stream(this.url) + stream.pipe(this.stream) + } + + private loop_start(){ + if(this.stream.destroyed){ + this.cleanup() + return + } + let stream = got.stream(this.url) + stream.once('data', () => { + this.per_sec_bytes = Math.ceil((stream.downloadProgress.total as number)/this.duration) + }) + + stream.on('data', (chunk) => { + this.bytes_count += chunk.length + this.stream.write(chunk) + }) + + stream.on('data', () => { + if(this.bytes_count > (this.per_sec_bytes * 300)){ + stream.destroy() + } + }) + + this.timer = setTimeout(() => { + this.loop() + }, 270 * 1000) + } + + private loop(){ + if(this.stream.destroyed){ + this.cleanup() + return + } + let absolute_bytes : number = 0 + let stream = got.stream(this.url, { + headers : { + "range" : `bytes=${this.bytes_count}-` + } + }) + + stream.on('data', (chunk) => { + absolute_bytes += chunk.length + this.bytes_count += chunk.length + this.stream.write(chunk) + }) + + stream.on('data', () => { + if(absolute_bytes > (this.per_sec_bytes * 300)){ + stream.destroy() + } + }) + + stream.on('end', () => { + this.cleanup() + }) + + this.timer = setTimeout(() => { + this.loop() + }, 270 * 1000) } } diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index 0140c50..00db863 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -65,7 +65,7 @@ export async function stream(url : string, options : StreamOptions = { low_laten final.push(info.format[info.format.length - 1]) } - return new Stream(final[0].url, type) + return new Stream(final[0].url, type, info.video_details.durationInSec) } export async function stream_from_info(info : InfoData, options : StreamOptions = { low_latency : false, preferred_quality : "144p" }): Promise{ @@ -94,7 +94,7 @@ export async function stream_from_info(info : InfoData, options : StreamOptions final.push(info.format[info.format.length - 1]) } - return new Stream(final[0].url, type) + return new Stream(final[0].url, type, info.video_details.durationInSec) } function filterFormat(formats : any[], codec : string){