From 5bef17528a1c6edba7f5c6bec3b23e5cf381a6fc Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 30 Aug 2021 14:42:51 +0530 Subject: [PATCH 01/13] Reverted changes in 0.6.4 --- package.json | 4 ++-- play-dl/YouTube/utils/extractor.ts | 3 +-- play-dl/YouTube/utils/parser.ts | 24 +----------------------- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index dfbb75e..a516349 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,8 @@ "url": "https://github.com/play-dl/play-dl/issues" }, "engines": { - "node": ">=16.0.0" - }, + "node": ">=16.0.0" + }, "homepage": "https://github.com/play-dl/play-dl#readme", "files": [ "dist/*" diff --git a/play-dl/YouTube/utils/extractor.ts b/play-dl/YouTube/utils/extractor.ts index 16efac6..86c3176 100644 --- a/play-dl/YouTube/utils/extractor.ts +++ b/play-dl/YouTube/utils/extractor.ts @@ -2,7 +2,6 @@ import { url_get } from './request' import { format_decipher, js_tokens } from './cipher' import { Video } from '../classes/Video' import { PlayList } from '../classes/Playlist' -import { parseThumbnail } from './parser'; const DEFAULT_API_KEY = "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8"; const video_pattern = /^((?:https?:)?\/\/)?(?:(?:www|m)\.)?((?:youtube\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(\S+)?$/; @@ -30,7 +29,7 @@ export async function video_basic_info(url : string){ durationInSec : vid.lengthSeconds, durationRaw : parseSeconds(vid.lengthSeconds), uploadedDate : microformat.publishDate, - thumbnail : parseThumbnail(vid.thumbnail.thumbnails), + thumbnail : vid.thumbnail.thumbnails[vid.thumbnail.thumbnails.length - 1], channel : { name : vid.author, id : vid.channelId, diff --git a/play-dl/YouTube/utils/parser.ts b/play-dl/YouTube/utils/parser.ts index 8082f3f..681a9bd 100644 --- a/play-dl/YouTube/utils/parser.ts +++ b/play-dl/YouTube/utils/parser.ts @@ -130,7 +130,7 @@ export function parseVideo(data?: any): Video | void { description: data.videoRenderer.descriptionSnippet && data.videoRenderer.descriptionSnippet.runs[0] ? data.videoRenderer.descriptionSnippet.runs[0].text : "", duration: data.videoRenderer.lengthText ? parseDuration(data.videoRenderer.lengthText.simpleText) : 0, duration_raw: data.videoRenderer.lengthText ? data.videoRenderer.lengthText.simpleText : null, - thumbnail: parseThumbnail(data.videoRenderer.thumbnail.thumbnails), + thumbnail: data.videoRenderer.thumbnail.thumbnails[data.videoRenderer.thumbnail.thumbnails.length - 1], channel: { id: data.videoRenderer.ownerText.runs[0].navigationEndpoint.browseEndpoint.browseId || null, name: data.videoRenderer.ownerText.runs[0].text || null, @@ -149,28 +149,6 @@ export function parseVideo(data?: any): Video | void { return res; } -export function parseThumbnail(thumbnails :thumbnail[]) : thumbnail{ - let parsed : thumbnail = { - width : '', - height : '', - url : '' - } - thumbnails.forEach((thumb) => { - if(thumb.url.indexOf('maxresdefault') !== -1){ - parsed = { - width : thumb.width, - height : thumb.height, - url : thumb.url - } - } - }) - if(parsed.url.length !== 0){ - return parsed - } - else { - return thumbnails[thumbnails.length - 1] - } -} export function parsePlaylist(data?: any): PlayList | void { if (!data.playlistRenderer) return; From 7b1f082c277a13550ee6afc4c66ff630ca2260e4 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 30 Aug 2021 15:58:23 +0530 Subject: [PATCH 02/13] Socket issue tried to fix --- play-dl/YouTube/classes/LiveStream.ts | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/play-dl/YouTube/classes/LiveStream.ts b/play-dl/YouTube/classes/LiveStream.ts index 37f0183..da262f1 100644 --- a/play-dl/YouTube/classes/LiveStream.ts +++ b/play-dl/YouTube/classes/LiveStream.ts @@ -1,7 +1,7 @@ import { PassThrough } from 'stream' import got from 'got' -import Request from 'got/dist/source/core'; import { StreamType } from '../stream'; +import { Socket } from 'net' export interface FormatInterface{ url : string; @@ -17,6 +17,7 @@ export class LiveStreaming{ private interval : number private packet_count : number private timer : NodeJS.Timer | null + private socket : Socket | null private segments_urls : string[] constructor(dash_url : string, target_interval : number){ this.type = StreamType.Arbitrary @@ -26,6 +27,7 @@ export class LiveStreaming{ this.segments_urls = [] this.packet_count = 0 this.timer = null + this.socket = null this.interval = target_interval * 1000 || 0 this.stream.on('close', () => { this.cleanup() @@ -45,6 +47,8 @@ export class LiveStreaming{ private cleanup(){ clearTimeout(this.timer as NodeJS.Timer) + this.socket?.destroy() + this.socket = null this.timer = null this.url = '' this.base_url = '' @@ -88,6 +92,7 @@ export class LiveEnded{ private base_url : string; private packet_count : number private segments_urls : string[] + private socket : Socket | null constructor(dash_url : string){ this.type = StreamType.Arbitrary this.url = dash_url @@ -95,6 +100,7 @@ export class LiveEnded{ this.stream = new PassThrough({ highWaterMark : 10 * 1000 * 1000 }) this.segments_urls = [] this.packet_count = 0 + this.socket = null this.stream.on('close', () => { this.cleanup() }) @@ -112,6 +118,8 @@ export class LiveEnded{ } private cleanup(){ + this.socket?.destroy() + this.socket = null this.url = '' this.base_url = '' this.segments_urls = [] @@ -126,6 +134,10 @@ export class LiveEnded{ await this.dash_getter() if(this.packet_count === 0) this.packet_count = Number(this.segments_urls[0].split('sq/')[1].split('/')[0]) for await (let segment of this.segments_urls){ + if(this.stream.destroyed){ + this.cleanup() + break + } if(Number(segment.split('sq/')[1].split('/')[0]) !== this.packet_count){ continue } @@ -151,6 +163,7 @@ export class Stream { private per_sec_bytes : number; private duration : number; private timer : NodeJS.Timer | null + private socket : Socket | null constructor(url : string, type : StreamType, duration : number){ this.url = url this.type = type @@ -158,12 +171,14 @@ export class Stream { this.bytes_count = 0 this.per_sec_bytes = 0 this.timer = null - this.duration = duration; + this.duration = duration + this.socket = null; (duration > 300) ? this.loop_start() : this.normal_start() } private cleanup(){ clearTimeout(this.timer as NodeJS.Timer) + this.socket?.destroy() this.timer = null this.url = '' this.bytes_count = 0 @@ -176,6 +191,7 @@ export class Stream { return } let stream = got.stream(this.url) + this.socket = stream.socket as Socket stream.pipe(this.stream) } @@ -193,9 +209,10 @@ export class Stream { this.bytes_count += chunk.length this.stream.write(chunk) }) - + this.socket = stream.socket as Socket stream.on('data', () => { if(this.bytes_count > (this.per_sec_bytes * 300)){ + this.socket?.destroy() stream.destroy() } }) @@ -222,9 +239,10 @@ export class Stream { this.bytes_count += chunk.length this.stream.write(chunk) }) - + this.socket = stream.socket as Socket stream.on('data', () => { if(absolute_bytes > (this.per_sec_bytes * 300)){ + this.socket?.destroy() stream.destroy() } }) From 7f68addb6fd4e850c3c86ea7ece8ee2d6d0af432 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 30 Aug 2021 18:33:47 +0530 Subject: [PATCH 03/13] 404 Error Fixed --- package-lock.json | 4 ++-- package.json | 2 +- play-dl/YouTube/classes/LiveStream.ts | 19 +------------------ play-dl/YouTube/stream.ts | 19 +++++++++++++++++-- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9b04145..6cf2b55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "play-dl", - "version": "0.6.4", + "version": "0.6.9", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "play-dl", - "version": "0.6.4", + "version": "0.6.9", "license": "MIT", "dependencies": { "got": "^11.8.2" diff --git a/package.json b/package.json index a516349..59111b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "play-dl", - "version": "0.6.4", + "version": "0.6.9", "description": "YouTube, SoundCloud, Spotify streaming for discord.js bots", "main": "dist/index.js", "typings": "dist/index.d.ts", diff --git a/play-dl/YouTube/classes/LiveStream.ts b/play-dl/YouTube/classes/LiveStream.ts index da262f1..5f59af9 100644 --- a/play-dl/YouTube/classes/LiveStream.ts +++ b/play-dl/YouTube/classes/LiveStream.ts @@ -1,7 +1,6 @@ import { PassThrough } from 'stream' import got from 'got' import { StreamType } from '../stream'; -import { Socket } from 'net' export interface FormatInterface{ url : string; @@ -17,7 +16,6 @@ export class LiveStreaming{ private interval : number private packet_count : number private timer : NodeJS.Timer | null - private socket : Socket | null private segments_urls : string[] constructor(dash_url : string, target_interval : number){ this.type = StreamType.Arbitrary @@ -27,7 +25,6 @@ export class LiveStreaming{ this.segments_urls = [] this.packet_count = 0 this.timer = null - this.socket = null this.interval = target_interval * 1000 || 0 this.stream.on('close', () => { this.cleanup() @@ -47,8 +44,6 @@ export class LiveStreaming{ private cleanup(){ clearTimeout(this.timer as NodeJS.Timer) - this.socket?.destroy() - this.socket = null this.timer = null this.url = '' this.base_url = '' @@ -92,7 +87,6 @@ export class LiveEnded{ private base_url : string; private packet_count : number private segments_urls : string[] - private socket : Socket | null constructor(dash_url : string){ this.type = StreamType.Arbitrary this.url = dash_url @@ -100,7 +94,6 @@ export class LiveEnded{ this.stream = new PassThrough({ highWaterMark : 10 * 1000 * 1000 }) this.segments_urls = [] this.packet_count = 0 - this.socket = null this.stream.on('close', () => { this.cleanup() }) @@ -118,8 +111,6 @@ export class LiveEnded{ } private cleanup(){ - this.socket?.destroy() - this.socket = null this.url = '' this.base_url = '' this.segments_urls = [] @@ -163,7 +154,6 @@ export class Stream { private per_sec_bytes : number; private duration : number; private timer : NodeJS.Timer | null - private socket : Socket | null constructor(url : string, type : StreamType, duration : number){ this.url = url this.type = type @@ -171,14 +161,12 @@ export class Stream { this.bytes_count = 0 this.per_sec_bytes = 0 this.timer = null - this.duration = duration - this.socket = null; + this.duration = duration; (duration > 300) ? this.loop_start() : this.normal_start() } private cleanup(){ clearTimeout(this.timer as NodeJS.Timer) - this.socket?.destroy() this.timer = null this.url = '' this.bytes_count = 0 @@ -191,7 +179,6 @@ export class Stream { return } let stream = got.stream(this.url) - this.socket = stream.socket as Socket stream.pipe(this.stream) } @@ -209,10 +196,8 @@ export class Stream { this.bytes_count += chunk.length this.stream.write(chunk) }) - this.socket = stream.socket as Socket stream.on('data', () => { if(this.bytes_count > (this.per_sec_bytes * 300)){ - this.socket?.destroy() stream.destroy() } }) @@ -239,10 +224,8 @@ export class Stream { this.bytes_count += chunk.length this.stream.write(chunk) }) - this.socket = stream.socket as Socket stream.on('data', () => { if(absolute_bytes > (this.per_sec_bytes * 300)){ - this.socket?.destroy() stream.destroy() } }) diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index ae40fdf..bd6037d 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -1,3 +1,4 @@ +import got from "got/dist/source" import { video_info } from "." import { LiveEnded, LiveStreaming, Stream } from "./classes/LiveStream" @@ -34,13 +35,20 @@ function parseAudioFormats(formats : any[]){ return result } -export async function stream(url : string): Promise{ +export async function stream(url : string, error_check : boolean = false): Promise{ let info = await video_info(url) let final: any[] = []; let type : StreamType; if(info.LiveStreamData.isLive === true && info.LiveStreamData.hlsManifestUrl !== null) { return live_stream(info as InfoData) } + + if(error_check){ + let response = await got(info.video_details.url) + if(response.statusCode >= 400){ + return await stream(info.video_details.url, true) + } + } let audioFormat = parseAudioFormats(info.format) let opusFormats = filterFormat(audioFormat, "opus") @@ -62,13 +70,20 @@ export async function stream(url : string): Promise{ let final: any[] = []; let type : StreamType; if(info.LiveStreamData.isLive === true && info.LiveStreamData.hlsManifestUrl !== null) { return live_stream(info as InfoData) } + if(error_check){ + let response = await got(info.video_details.url) + if(response.statusCode >= 400){ + return await stream(info.video_details.url, true) + } + } + let audioFormat = parseAudioFormats(info.format) let opusFormats = filterFormat(audioFormat, "opus") From 2e12ca61d8d03156c2c41c382eb9355652c0f05d Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 30 Aug 2021 18:46:56 +0530 Subject: [PATCH 04/13] Stream Readme added --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 9be9c71..f22c46c 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,31 @@ const options = { const results = await youtube.search('post malone sunflower', options); ``` +# Stream +### stream(url : `string`, error_check? : `boolean`) +*This is basic to create a youtube stream from a url.* +```js + let source = await stream() // This will create a stream Class which contains type and stream to be played. + let resource = createAudioResource(source.stream, { + inputType : source.type + }) // This creates resource for playing + +let source = await stream(, true) //This will check for 404 error if any +``` +![#f03c15](https://via.placeholder.com/15/f03c15/000000?text=+) `Note : enabling error_check will take more time to start streaming` +### stream_from_info(info : `infoData`, error_check? : `boolean`) +*This is basic to create a youtube stream from a info [ from video_info function ].* +```js +let info = await video_info() + let source = await stream_from_info(info) // This will create a stream Class which contains type and stream to be played. + let resource = createAudioResource(source.stream, { + inputType : source.type + }) // This creates resource for playing + +let source = await stream_from_info(info, true) //This will check for 404 error if any +``` +![#f03c15](https://via.placeholder.com/15/f03c15/000000?text=+) `Note : enabling error_check will take more time to start streaming` # Search From f30399c0d8cd8be1a0db617a8fe26abdf3895d7c Mon Sep 17 00:00:00 2001 From: Killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 30 Aug 2021 18:47:44 +0530 Subject: [PATCH 05/13] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f22c46c..c22ac9f 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ const results = await youtube.search('post malone sunflower', options); ``` # Stream + ### stream(url : `string`, error_check? : `boolean`) *This is basic to create a youtube stream from a url.* ```js @@ -45,6 +46,7 @@ let source = await stream(, true) //This will check for 404 error if any ``` ![#f03c15](https://via.placeholder.com/15/f03c15/000000?text=+) `Note : enabling error_check will take more time to start streaming` + ### stream_from_info(info : `infoData`, error_check? : `boolean`) *This is basic to create a youtube stream from a info [ from video_info function ].* ```js @@ -58,6 +60,7 @@ let source = await stream_from_info(info, true) //This will check for 404 error ``` ![#f03c15](https://via.placeholder.com/15/f03c15/000000?text=+) `Note : enabling error_check will take more time to start streaming` + # Search ### search(url : `string`, options? : [SearchOptions](https://github.com/play-dl/play-dl/tree/main/play-dl/YouTube#searchoptions)) From 74de1739c88c227a64d20284f04e514b67501904 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 30 Aug 2021 21:05:33 +0530 Subject: [PATCH 06/13] 404 finally fixed --- play-dl/YouTube/stream.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index bd6037d..5e93f06 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -44,7 +44,7 @@ export async function stream(url : string, error_check : boolean = false): Promi } if(error_check){ - let response = await got(info.video_details.url) + let response = await got(info.format[info.format.length - 1].url) if(response.statusCode >= 400){ return await stream(info.video_details.url, true) } @@ -78,7 +78,7 @@ export async function stream_from_info(info : InfoData, error_check : boolean = } if(error_check){ - let response = await got(info.video_details.url) + let response = await got(info.format[info.format.length - 1].url) if(response.statusCode >= 400){ return await stream(info.video_details.url, true) } From 02fcb61c87d6d63c0f0aa4411f7934a12fedbfa9 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 30 Aug 2021 21:48:57 +0530 Subject: [PATCH 07/13] TCP connection fix --- play-dl/YouTube/classes/LiveStream.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/play-dl/YouTube/classes/LiveStream.ts b/play-dl/YouTube/classes/LiveStream.ts index 5f59af9..1cf5e16 100644 --- a/play-dl/YouTube/classes/LiveStream.ts +++ b/play-dl/YouTube/classes/LiveStream.ts @@ -1,6 +1,7 @@ import { PassThrough } from 'stream' import got from 'got' import { StreamType } from '../stream'; +import { Socket } from 'net' export interface FormatInterface{ url : string; @@ -17,6 +18,7 @@ export class LiveStreaming{ private packet_count : number private timer : NodeJS.Timer | null private segments_urls : string[] + private socket : Socket | null constructor(dash_url : string, target_interval : number){ this.type = StreamType.Arbitrary this.url = dash_url @@ -25,6 +27,7 @@ export class LiveStreaming{ this.segments_urls = [] this.packet_count = 0 this.timer = null + this.socket = null this.interval = target_interval * 1000 || 0 this.stream.on('close', () => { this.cleanup() @@ -44,6 +47,8 @@ export class LiveStreaming{ private cleanup(){ clearTimeout(this.timer as NodeJS.Timer) + this.socket?.destroy() + this.socket = null this.timer = null this.url = '' this.base_url = '' @@ -67,6 +72,7 @@ export class LiveStreaming{ return new Promise(async (resolve, reject) => { let stream = got.stream(this.base_url + segment) stream.on('data', (chunk: any) => this.stream.write(chunk)) + stream.once('data', () => {this.socket = stream.socket as Socket}) stream.on('end', () => { this.packet_count++ resolve('') @@ -87,6 +93,7 @@ export class LiveEnded{ private base_url : string; private packet_count : number private segments_urls : string[] + private socket : Socket | null constructor(dash_url : string){ this.type = StreamType.Arbitrary this.url = dash_url @@ -94,6 +101,7 @@ export class LiveEnded{ this.stream = new PassThrough({ highWaterMark : 10 * 1000 * 1000 }) this.segments_urls = [] this.packet_count = 0 + this.socket = null this.stream.on('close', () => { this.cleanup() }) @@ -111,6 +119,8 @@ export class LiveEnded{ } private cleanup(){ + this.socket?.destroy() + this.socket = null this.url = '' this.base_url = '' this.segments_urls = [] @@ -136,6 +146,7 @@ export class LiveEnded{ return new Promise(async (resolve, reject) => { let stream = got.stream(this.base_url + segment) stream.on('data', (chunk: any) => this.stream.write(chunk)) + stream.once('data', () => {this.socket = stream.socket as Socket}) stream.on('end', () => { this.packet_count++ resolve('') @@ -154,6 +165,7 @@ export class Stream { private per_sec_bytes : number; private duration : number; private timer : NodeJS.Timer | null + private socket : Socket | null constructor(url : string, type : StreamType, duration : number){ this.url = url this.type = type @@ -161,12 +173,15 @@ export class Stream { this.bytes_count = 0 this.per_sec_bytes = 0 this.timer = null + this.socket = null this.duration = duration; (duration > 300) ? this.loop_start() : this.normal_start() } private cleanup(){ clearTimeout(this.timer as NodeJS.Timer) + this.socket?.destroy() + this.socket = null this.timer = null this.url = '' this.bytes_count = 0 @@ -180,6 +195,7 @@ export class Stream { } let stream = got.stream(this.url) stream.pipe(this.stream) + stream.once('data', () => {this.socket = stream.socket as Socket}) } private loop_start(){ @@ -190,6 +206,7 @@ export class Stream { let stream = got.stream(this.url) stream.once('data', () => { this.per_sec_bytes = Math.ceil((stream.downloadProgress.total as number)/this.duration) + this.socket = stream.socket as Socket }) stream.on('data', (chunk: any) => { @@ -224,6 +241,7 @@ export class Stream { this.bytes_count += chunk.length this.stream.write(chunk) }) + stream.once('data', () => {this.socket = stream.socket as Socket}) stream.on('data', () => { if(absolute_bytes > (this.per_sec_bytes * 300)){ stream.destroy() From 90585192824dd3e6bad8b2ffdc5002f6161a9e55 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 30 Aug 2021 23:54:34 +0530 Subject: [PATCH 08/13] Headers added --- play-dl/YouTube/stream.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index 5e93f06..baa4a8f 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -44,7 +44,11 @@ export async function stream(url : string, error_check : boolean = false): Promi } if(error_check){ - let response = await got(info.format[info.format.length - 1].url) + let response = await got(info.format[info.format.length - 1].url, { + headers : { + "range" : `bytes=0-1` + } + }) if(response.statusCode >= 400){ return await stream(info.video_details.url, true) } @@ -78,7 +82,11 @@ export async function stream_from_info(info : InfoData, error_check : boolean = } if(error_check){ - let response = await got(info.format[info.format.length - 1].url) + let response = await got(info.format[info.format.length - 1].url, { + headers : { + "range" : `bytes=0-1` + } + }) if(response.statusCode >= 400){ return await stream(info.video_details.url, true) } From 5596f69114455007bc8c32b81e23a65ea577b137 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 31 Aug 2021 00:21:21 +0530 Subject: [PATCH 09/13] Socket Close Error Fixed --- play-dl/YouTube/classes/LiveStream.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/play-dl/YouTube/classes/LiveStream.ts b/play-dl/YouTube/classes/LiveStream.ts index 1cf5e16..85cee36 100644 --- a/play-dl/YouTube/classes/LiveStream.ts +++ b/play-dl/YouTube/classes/LiveStream.ts @@ -174,14 +174,19 @@ export class Stream { this.per_sec_bytes = 0 this.timer = null this.socket = null + this.stream.on('close', () => { + this.cleanup() + }) this.duration = duration; (duration > 300) ? this.loop_start() : this.normal_start() } private cleanup(){ clearTimeout(this.timer as NodeJS.Timer) - this.socket?.destroy() - this.socket = null + this.socket?.end() + this.socket?.on('close', () => { + console.log('Socket Closed') + }) this.timer = null this.url = '' this.bytes_count = 0 From f2d030cdc77875eaa996c33aa30ef1c42bd9645b Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 31 Aug 2021 00:23:22 +0530 Subject: [PATCH 10/13] Socket Fixed --- play-dl/YouTube/classes/LiveStream.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/play-dl/YouTube/classes/LiveStream.ts b/play-dl/YouTube/classes/LiveStream.ts index 85cee36..2aa97dd 100644 --- a/play-dl/YouTube/classes/LiveStream.ts +++ b/play-dl/YouTube/classes/LiveStream.ts @@ -183,10 +183,8 @@ export class Stream { private cleanup(){ clearTimeout(this.timer as NodeJS.Timer) - this.socket?.end() - this.socket?.on('close', () => { - console.log('Socket Closed') - }) + this.socket?.destroy() + this.socket = null this.timer = null this.url = '' this.bytes_count = 0 From eaf18cfca4849bdf4f41e87bdfe2bd9dda0258d6 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 31 Aug 2021 09:09:10 +0530 Subject: [PATCH 11/13] Validate URL + All Errors Fixed --- play-dl/YouTube/classes/LiveStream.ts | 37 +++++++++++++-------------- play-dl/YouTube/utils/extractor.ts | 5 ++++ play-dl/YouTube/utils/index.ts | 2 +- play-dl/index.ts | 2 +- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/play-dl/YouTube/classes/LiveStream.ts b/play-dl/YouTube/classes/LiveStream.ts index 2aa97dd..3743254 100644 --- a/play-dl/YouTube/classes/LiveStream.ts +++ b/play-dl/YouTube/classes/LiveStream.ts @@ -1,7 +1,7 @@ import { PassThrough } from 'stream' import got from 'got' import { StreamType } from '../stream'; -import { Socket } from 'net' +import Request from 'got/dist/source/core'; export interface FormatInterface{ url : string; @@ -18,7 +18,7 @@ export class LiveStreaming{ private packet_count : number private timer : NodeJS.Timer | null private segments_urls : string[] - private socket : Socket | null + private request : Request | null constructor(dash_url : string, target_interval : number){ this.type = StreamType.Arbitrary this.url = dash_url @@ -26,8 +26,8 @@ export class LiveStreaming{ this.stream = new PassThrough({ highWaterMark : 10 * 1000 * 1000 }) this.segments_urls = [] this.packet_count = 0 + this.request = null this.timer = null - this.socket = null this.interval = target_interval * 1000 || 0 this.stream.on('close', () => { this.cleanup() @@ -47,8 +47,8 @@ export class LiveStreaming{ private cleanup(){ clearTimeout(this.timer as NodeJS.Timer) - this.socket?.destroy() - this.socket = null + this.request?.destroy() + this.request = null this.timer = null this.url = '' this.base_url = '' @@ -71,8 +71,8 @@ export class LiveStreaming{ await (async () => { return new Promise(async (resolve, reject) => { let stream = got.stream(this.base_url + segment) + this.request = stream stream.on('data', (chunk: any) => this.stream.write(chunk)) - stream.once('data', () => {this.socket = stream.socket as Socket}) stream.on('end', () => { this.packet_count++ resolve('') @@ -93,15 +93,15 @@ export class LiveEnded{ private base_url : string; private packet_count : number private segments_urls : string[] - private socket : Socket | null + private request : Request | null constructor(dash_url : string){ this.type = StreamType.Arbitrary this.url = dash_url this.base_url = '' this.stream = new PassThrough({ highWaterMark : 10 * 1000 * 1000 }) this.segments_urls = [] + this.request = null this.packet_count = 0 - this.socket = null this.stream.on('close', () => { this.cleanup() }) @@ -119,8 +119,8 @@ export class LiveEnded{ } private cleanup(){ - this.socket?.destroy() - this.socket = null + this.request?.destroy() + this.request = null this.url = '' this.base_url = '' this.segments_urls = [] @@ -145,8 +145,8 @@ export class LiveEnded{ await (async () => { return new Promise(async (resolve, reject) => { let stream = got.stream(this.base_url + segment) + this.request = stream stream.on('data', (chunk: any) => this.stream.write(chunk)) - stream.once('data', () => {this.socket = stream.socket as Socket}) stream.on('end', () => { this.packet_count++ resolve('') @@ -165,7 +165,7 @@ export class Stream { private per_sec_bytes : number; private duration : number; private timer : NodeJS.Timer | null - private socket : Socket | null + private request : Request | null constructor(url : string, type : StreamType, duration : number){ this.url = url this.type = type @@ -173,7 +173,7 @@ export class Stream { this.bytes_count = 0 this.per_sec_bytes = 0 this.timer = null - this.socket = null + this.request = null this.stream.on('close', () => { this.cleanup() }) @@ -183,8 +183,8 @@ export class Stream { private cleanup(){ clearTimeout(this.timer as NodeJS.Timer) - this.socket?.destroy() - this.socket = null + this.request?.destroy() + this.request = null this.timer = null this.url = '' this.bytes_count = 0 @@ -197,8 +197,8 @@ export class Stream { return } let stream = got.stream(this.url) + this.request = stream stream.pipe(this.stream) - stream.once('data', () => {this.socket = stream.socket as Socket}) } private loop_start(){ @@ -207,9 +207,9 @@ export class Stream { return } let stream = got.stream(this.url) + this.request = stream stream.once('data', () => { this.per_sec_bytes = Math.ceil((stream.downloadProgress.total as number)/this.duration) - this.socket = stream.socket as Socket }) stream.on('data', (chunk: any) => { @@ -238,13 +238,12 @@ export class Stream { "range" : `bytes=${this.bytes_count}-` } }) - + this.request = stream stream.on('data', (chunk: any) => { absolute_bytes += chunk.length this.bytes_count += chunk.length this.stream.write(chunk) }) - stream.once('data', () => {this.socket = stream.socket as Socket}) stream.on('data', () => { if(absolute_bytes > (this.per_sec_bytes * 300)){ stream.destroy() diff --git a/play-dl/YouTube/utils/extractor.ts b/play-dl/YouTube/utils/extractor.ts index 86c3176..9bc406c 100644 --- a/play-dl/YouTube/utils/extractor.ts +++ b/play-dl/YouTube/utils/extractor.ts @@ -6,6 +6,11 @@ import { PlayList } from '../classes/Playlist' const DEFAULT_API_KEY = "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8"; const video_pattern = /^((?:https?:)?\/\/)?(?:(?:www|m)\.)?((?:youtube\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(\S+)?$/; +export function validate(url : string): boolean{ + if(!url.match(video_pattern)) return false + else return true +} + 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 : string; diff --git a/play-dl/YouTube/utils/index.ts b/play-dl/YouTube/utils/index.ts index 52ec51e..c87c6e8 100644 --- a/play-dl/YouTube/utils/index.ts +++ b/play-dl/YouTube/utils/index.ts @@ -1 +1 @@ -export { video_basic_info, video_info, playlist_info } from './extractor' \ No newline at end of file +export { video_basic_info, video_info, playlist_info, validate } from './extractor' \ No newline at end of file diff --git a/play-dl/index.ts b/play-dl/index.ts index 3991b71..03737c2 100644 --- a/play-dl/index.ts +++ b/play-dl/index.ts @@ -1 +1 @@ -export { playlist_info, video_basic_info, video_info, search, stream, stream_from_info } from "./YouTube"; \ No newline at end of file +export { playlist_info, video_basic_info, video_info, search, stream, stream_from_info, validate } from "./YouTube"; \ No newline at end of file From d8ba1f1b9efa152cc28a21078dfe64737b59b0eb Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 31 Aug 2021 09:16:27 +0530 Subject: [PATCH 12/13] Error check is enabled by default --- play-dl/YouTube/stream.ts | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index baa4a8f..de4c448 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -35,7 +35,7 @@ function parseAudioFormats(formats : any[]){ return result } -export async function stream(url : string, error_check : boolean = false): Promise{ +export async function stream(url : string): Promise{ let info = await video_info(url) let final: any[] = []; let type : StreamType; @@ -43,15 +43,13 @@ export async function stream(url : string, error_check : boolean = false): Promi return live_stream(info as InfoData) } - if(error_check){ - let response = await got(info.format[info.format.length - 1].url, { - headers : { - "range" : `bytes=0-1` - } - }) - if(response.statusCode >= 400){ - return await stream(info.video_details.url, true) + let response = await got(info.format[info.format.length - 1].url, { + headers : { + "range" : `bytes=0-1` } + }) + if(response.statusCode >= 400){ + return await stream(info.video_details.url) } let audioFormat = parseAudioFormats(info.format) @@ -74,22 +72,20 @@ export async function stream(url : string, error_check : boolean = false): Promi return new Stream(final[0].url, type, info.video_details.durationInSec) } -export async function stream_from_info(info : InfoData, error_check : boolean = false): Promise{ +export async function stream_from_info(info : InfoData): Promise{ let final: any[] = []; let type : StreamType; if(info.LiveStreamData.isLive === true && info.LiveStreamData.hlsManifestUrl !== null) { return live_stream(info as InfoData) } - if(error_check){ - let response = await got(info.format[info.format.length - 1].url, { - headers : { - "range" : `bytes=0-1` - } - }) - if(response.statusCode >= 400){ - return await stream(info.video_details.url, true) + let response = await got(info.format[info.format.length - 1].url, { + headers : { + "range" : `bytes=0-1` } + }) + if(response.statusCode >= 400){ + return await stream(info.video_details.url) } let audioFormat = parseAudioFormats(info.format) From b91cfdcf0066145eedb2319a3809cb98c4a8ea57 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 31 Aug 2021 09:20:47 +0530 Subject: [PATCH 13/13] ReadMe updated --- README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c22ac9f..b68dda5 100644 --- a/README.md +++ b/README.md @@ -32,22 +32,25 @@ const options = { const results = await youtube.search('post malone sunflower', options); ``` +# Validate +### validate( url : `string` ) + *Much faster and easier way to validate url.* +```js +if(validate(url)) // Will return true if url is a YouTube url +``` + # Stream -### stream(url : `string`, error_check? : `boolean`) +### stream(url : `string`) *This is basic to create a youtube stream from a url.* ```js let source = await stream() // This will create a stream Class which contains type and stream to be played. let resource = createAudioResource(source.stream, { inputType : source.type }) // This creates resource for playing - -let source = await stream(, true) //This will check for 404 error if any ``` -![#f03c15](https://via.placeholder.com/15/f03c15/000000?text=+) `Note : enabling error_check will take more time to start streaming` - -### stream_from_info(info : `infoData`, error_check? : `boolean`) +### stream_from_info(info : `infoData`) *This is basic to create a youtube stream from a info [ from video_info function ].* ```js let info = await video_info() @@ -55,11 +58,7 @@ let info = await video_info() let resource = createAudioResource(source.stream, { inputType : source.type }) // This creates resource for playing - -let source = await stream_from_info(info, true) //This will check for 404 error if any ``` -![#f03c15](https://via.placeholder.com/15/f03c15/000000?text=+) `Note : enabling error_check will take more time to start streaming` - # Search