From be840ce18bf994bad174c86d53a8624d9fd0da03 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 10:32:25 +0530 Subject: [PATCH 01/13] Changed related video ID to video URL --- play-dl/YouTube/utils/extractor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/play-dl/YouTube/utils/extractor.ts b/play-dl/YouTube/utils/extractor.ts index 1d4c397..7aaba2b 100644 --- a/play-dl/YouTube/utils/extractor.ts +++ b/play-dl/YouTube/utils/extractor.ts @@ -68,7 +68,7 @@ export async function video_basic_info(url: string, cookie?: string) { const html5player = `https://www.youtube.com${body.split('"jsUrl":"')[1].split('"')[0]}`; const related: any[] = [] initial_response.contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results.forEach((res: any) => { - if(res.compactVideoRenderer) related.push(res.compactVideoRenderer.videoId) + if(res.compactVideoRenderer) related.push(`https://www.youtube.com/watch?v=${res.compactVideoRenderer.videoId}`) }) const format = []; const vid = player_response.videoDetails; From f304d6bcbddba07a63e8fa0d0d9e69ccb199d9f7 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 12:49:39 +0530 Subject: [PATCH 02/13] Quality added --- docs/README.md | 15 +++--- examples/YouTube/play - cookies.js | 6 +-- play-dl/SoundCloud/classes.ts | 28 +++++------ play-dl/SoundCloud/index.ts | 30 +++++++++--- play-dl/YouTube/classes/LiveStream.ts | 6 +-- play-dl/YouTube/stream.ts | 69 ++++++++++----------------- play-dl/YouTube/utils/extractor.ts | 13 +++-- play-dl/index.ts | 13 ++--- 8 files changed, 92 insertions(+), 88 deletions(-) diff --git a/docs/README.md b/docs/README.md index c12c8c6..6053b86 100644 --- a/docs/README.md +++ b/docs/README.md @@ -42,12 +42,15 @@ authorization() //After then you will be asked about type of data you want to cr ### Stream -#### stream(url : `string`, cookie? : `string`) +### StreamOptions : + +- quality : `number` :- Sets quality of stream [ 0 = Lowest, 1 = Medium ]. Leave this empty to get highest audio quality. +- cookie : `string` :- **[Cookies](https://github.com/play-dl/play-dl/discussions/34) are optional and are required for playing age restricted videos.** + +#### stream(url : `string`, options? : `StreamOptions`) _This is basic to create a stream from a youtube or soundcloud url._ -**[Cookies](https://github.com/play-dl/play-dl/discussions/34) are optional and are required for playing age restricted videos.** - ```js let source = await stream("url") // This will create a stream Class. @@ -56,19 +59,17 @@ let resource = createAudioResource(source.stream, { }) // This creates resource for playing ``` -### stream_from_info(info : `infoData`, cookie? : `string`) +### stream_from_info(info : `infoData`, options? : `StreamOptions`) _This is basic to create a stream from a info [ from [video_info](https://github.com/play-dl/play-dl#video_infourl--string) function or [soundcloud]() function [**Only SoundCloudTrack class is allowed**] ]._ -**[Cookies](https://github.com/play-dl/play-dl/discussions/34) are optional and are required for playing age restricted videos.** - **Note :** Here, cookies are required only for retrying purposes. ```js let source = await stream_from_info(info) // This will create a stream Class from video_info or SoundCoudTrack Class. /* OR - let source = await stream_from_info(info, cookie) This will create a stream Class and also give cookies if retrying. + let source = await stream_from_info(info, { cookie }) This will create a stream Class and also give cookies if retrying. */ let resource = createAudioResource(source.stream, { diff --git a/examples/YouTube/play - cookies.js b/examples/YouTube/play - cookies.js index 4500485..edeb9fc 100644 --- a/examples/YouTube/play - cookies.js +++ b/examples/YouTube/play - cookies.js @@ -17,13 +17,13 @@ client.on('messageCreate', async message => { }) let args = message.content.split('play ')[1].split(' ')[0] - let stream = await play.stream(args, COOKIE) + let stream = await play.stream(args, { cookie : COOKIE }) /* OR if you want to get info about youtube link and then stream it - let yt_info = await play.video_info(args, COOKIE) + let yt_info = await play.video_info(args, { cookie : COOKIE }) console.log(yt_info.video_details.title) - let stream = await play.stream_from_info(yt_info, COOKIE) + let stream = await play.stream_from_info(yt_info, { cookie : COOKIE }) */ let resource = createAudioResource(stream.stream, { diff --git a/play-dl/SoundCloud/classes.ts b/play-dl/SoundCloud/classes.ts index 30a64b3..4296021 100644 --- a/play-dl/SoundCloud/classes.ts +++ b/play-dl/SoundCloud/classes.ts @@ -22,7 +22,7 @@ interface SoundCloudTrackDeprecated { type: 'track'; } -interface SoundCloudTrackFormat { +export interface SoundCloudTrackFormat { url: string; preset: string; duration: number; @@ -90,13 +90,13 @@ export class SoundCloudTrack { id: this.id, type: this.type, url: this.url, - fetched : this.fetched, + fetched: this.fetched, durationInMs: this.durationInMs, durationInSec: this.durationInSec, publisher: this.publisher, formats: this.formats, thumbnail: this.thumbnail, - user : this.user + user: this.user }; } } @@ -169,13 +169,13 @@ export class SoundCloudPlaylist { await Promise.allSettled(work); } - get total_tracks(){ - let count = 0 + get total_tracks() { + let count = 0; this.tracks.forEach((track) => { - if(track instanceof SoundCloudTrack) count++ - else return - }) - return count + if (track instanceof SoundCloudTrack) count++; + else return; + }); + return count; } toJSON() { @@ -183,19 +183,19 @@ export class SoundCloudPlaylist { name: this.name, id: this.id, type: this.type, - sub_type : this.sub_type, + sub_type: this.sub_type, url: this.url, durationInMs: this.durationInMs, durationInSec: this.durationInSec, - tracksCount : this.tracksCount, - user : this.user, - tracks : this.tracks + tracksCount: this.tracksCount, + user: this.user, + tracks: this.tracks }; } } export class Stream { - stream : PassThrough; + stream: PassThrough; type: StreamType; private url: string; private playing_count: number; diff --git a/play-dl/SoundCloud/index.ts b/play-dl/SoundCloud/index.ts index f32a2a9..0e55580 100644 --- a/play-dl/SoundCloud/index.ts +++ b/play-dl/SoundCloud/index.ts @@ -1,7 +1,7 @@ import fs from 'fs'; import { StreamType } from '../YouTube/stream'; import { request } from '../YouTube/utils/request'; -import { SoundCloudPlaylist, SoundCloudTrack, Stream } from './classes'; +import { SoundCloudPlaylist, SoundCloudTrack, SoundCloudTrackFormat, Stream } from './classes'; let soundData: SoundDataOptions; if (fs.existsSync('.data/soundcloud.data')) { @@ -33,23 +33,31 @@ export async function soundcloud(url: string): Promise { +export async function stream(url: string, quality? : number): Promise { const data = await soundcloud(url); if (data instanceof SoundCloudPlaylist) throw new Error("Streams can't be created from Playlist url"); - const req_url = data.formats[data.formats.length - 1].url + '?client_id=' + soundData.client_id; + const HLSformats = parseHlsFormats(data.formats) + if(!quality) quality = HLSformats.length - 1; + else if(quality <= 0) quality = 0; + else if(quality > HLSformats.length) quality = HLSformats.length - 1; + const req_url = HLSformats[quality].url + '?client_id=' + soundData.client_id; const s_data = JSON.parse(await request(req_url)); - const type = data.formats[data.formats.length - 1].format.mime_type.startsWith('audio/ogg') + const type = HLSformats[quality].format.mime_type.startsWith('audio/ogg') ? StreamType.OggOpus : StreamType.Arbitrary; return new Stream(s_data.url, type); } -export async function stream_from_info(data: SoundCloudTrack): Promise { - const req_url = data.formats[data.formats.length - 1].url + '?client_id=' + soundData.client_id; +export async function stream_from_info(data: SoundCloudTrack, quality? :number): Promise { + const HLSformats = parseHlsFormats(data.formats) + if(!quality) quality = HLSformats.length - 1; + else if(quality <= 0) quality = 0; + else if(quality > HLSformats.length) quality = HLSformats.length - 1; + const req_url = HLSformats[quality].url + '?client_id=' + soundData.client_id; const s_data = JSON.parse(await request(req_url)); - const type = data.formats[data.formats.length - 1].format.mime_type.startsWith('audio/ogg') + const type = HLSformats[quality].format.mime_type.startsWith('audio/ogg') ? StreamType.OggOpus : StreamType.Arbitrary; return new Stream(s_data.url, type); @@ -77,3 +85,11 @@ export async function so_validate(url: string): Promise { + if(format.format.protocol === 'hls') result.push(format) + }); + return result; +} \ No newline at end of file diff --git a/play-dl/YouTube/classes/LiveStream.ts b/play-dl/YouTube/classes/LiveStream.ts index b93cdb7..0c32f9a 100644 --- a/play-dl/YouTube/classes/LiveStream.ts +++ b/play-dl/YouTube/classes/LiveStream.ts @@ -11,7 +11,7 @@ export interface FormatInterface { } export class LiveStreaming { - stream : PassThrough; + stream: PassThrough; type: StreamType; private base_url: string; private url: string; @@ -23,7 +23,7 @@ export class LiveStreaming { private segments_urls: string[]; private request: IncomingMessage | null; constructor(dash_url: string, target_interval: number, video_url: string) { - this.stream = new PassThrough({ highWaterMark: 10 * 1000 * 1000 }) + this.stream = new PassThrough({ highWaterMark: 10 * 1000 * 1000 }); this.type = StreamType.Arbitrary; this.url = dash_url; this.base_url = ''; @@ -121,7 +121,7 @@ export class LiveStreaming { } export class Stream { - stream : PassThrough; + stream: PassThrough; type: StreamType; private url: string; private bytes_count: number; diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index 4b54a8f..15f840d 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -9,6 +9,11 @@ export enum StreamType { Opus = 'opus' } +export interface StreamOptions { + quality?: number; + cookie?: string; +} + export interface InfoData { LiveStreamData: { isLive: boolean; @@ -33,10 +38,9 @@ function parseAudioFormats(formats: any[]) { return result; } -export async function stream(url: string, cookie?: string): Promise { - const info = await video_info(url, cookie); +export async function stream(url: string, options: StreamOptions = {}): Promise { + const info = await video_info(url, options.cookie); const final: any[] = []; - let type: StreamType; if ( info.LiveStreamData.isLive === true && info.LiveStreamData.hlsManifestUrl !== null && @@ -50,33 +54,26 @@ export async function stream(url: string, cookie?: string): Promise audioFormat.length) options.quality = audioFormat.length - 1; + final.push(audioFormat[options.quality]); + let type: StreamType = + audioFormat[options.quality].codec === 'opus' && audioFormat[options.quality].container === 'webm' + ? StreamType.WebmOpus + : StreamType.Arbitrary; return new Stream( final[0].url, type, info.video_details.durationInSec, Number(final[0].contentLength), info.video_details.url, - cookie as string + options.cookie as string ); } -export async function stream_from_info(info: InfoData, cookie?: string): Promise { +export async function stream_from_info(info: InfoData, options: StreamOptions = {}): Promise { const final: any[] = []; - let type: StreamType; if ( info.LiveStreamData.isLive === true && info.LiveStreamData.hlsManifestUrl !== null && @@ -90,34 +87,20 @@ export async function stream_from_info(info: InfoData, cookie?: string): Promise } const audioFormat = parseAudioFormats(info.format); - const opusFormats = filterFormat(audioFormat, 'opus'); - - if (opusFormats.length === 0) { - type = StreamType.Arbitrary; - if (audioFormat.length === 0) { - final.push(info.format[info.format.length - 1]); - } else { - final.push(audioFormat[audioFormat.length - 1]); - } - } else { - type = StreamType.WebmOpus; - final.push(opusFormats[opusFormats.length - 1]); - } - + if (!options.quality) options.quality = audioFormat.length - 1; + else if (options.quality <= 0) options.quality = 0; + else if (options.quality > audioFormat.length) options.quality = audioFormat.length - 1; + final.push(audioFormat[options.quality]); + let type: StreamType = + audioFormat[options.quality].codec === 'opus' && audioFormat[options.quality].container === 'webm' + ? StreamType.WebmOpus + : StreamType.Arbitrary; return new Stream( final[0].url, type, info.video_details.durationInSec, Number(final[0].contentLength), info.video_details.url, - cookie as string + options.cookie as string ); } - -function filterFormat(formats: any[], codec: string) { - const result: any[] = []; - formats.forEach((format) => { - if (format.codec === codec) result.push(format); - }); - return result; -} diff --git a/play-dl/YouTube/utils/extractor.ts b/play-dl/YouTube/utils/extractor.ts index 7aaba2b..e16d307 100644 --- a/play-dl/YouTube/utils/extractor.ts +++ b/play-dl/YouTube/utils/extractor.ts @@ -66,10 +66,13 @@ export async function video_basic_info(url: string, cookie?: string) { initial_response.contents.twoColumnWatchNextResults.results.results.contents[1]?.videoSecondaryInfoRenderer ?.owner?.videoOwnerRenderer?.badges[0]; const html5player = `https://www.youtube.com${body.split('"jsUrl":"')[1].split('"')[0]}`; - const related: any[] = [] - initial_response.contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results.forEach((res: any) => { - if(res.compactVideoRenderer) related.push(`https://www.youtube.com/watch?v=${res.compactVideoRenderer.videoId}`) - }) + const related: any[] = []; + initial_response.contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results.forEach( + (res: any) => { + if (res.compactVideoRenderer) + related.push(`https://www.youtube.com/watch?v=${res.compactVideoRenderer.videoId}`); + } + ); const format = []; const vid = player_response.videoDetails; const microformat = player_response.microformat.playerMicroformatRenderer; @@ -106,7 +109,7 @@ export async function video_basic_info(url: string, cookie?: string) { html5player, format, video_details, - related_videos : related + related_videos: related }; } diff --git a/play-dl/index.ts b/play-dl/index.ts index 5908a06..9168f89 100644 --- a/play-dl/index.ts +++ b/play-dl/index.ts @@ -7,21 +7,22 @@ import fs from 'fs'; import { sp_validate, yt_validate, so_validate } from '.'; import { SpotifyAuthorize } from './Spotify'; import { check_id, stream as so_stream, stream_from_info as so_stream_info } from './SoundCloud'; -import { InfoData, stream as yt_stream, stream_from_info as yt_stream_info } from './YouTube/stream'; +import { InfoData, stream as yt_stream, StreamOptions, stream_from_info as yt_stream_info } from './YouTube/stream'; import { SoundCloudTrack, Stream as SoStream } from './SoundCloud/classes'; import { LiveStreaming, Stream as YTStream } from './YouTube/classes/LiveStream'; -export async function stream(url: string, cookie?: string): Promise { - if (url.indexOf('soundcloud') !== -1) return await so_stream(url); - else return await yt_stream(url, cookie); +export async function stream(url: string, options: StreamOptions = {}): Promise { + if(url.length === 0) throw new Error('Stream URL has a length of 0. Check your url again.') + if (url.indexOf('soundcloud') !== -1) return await so_stream(url, options.quality); + else return await yt_stream(url, { cookie : options.cookie }); } export async function stream_from_info( info: InfoData | SoundCloudTrack, - cookie?: string + options: StreamOptions = {} ): Promise { if (info instanceof SoundCloudTrack) return await so_stream_info(info); - else return await yt_stream_info(info, cookie); + else return await yt_stream_info(info, { cookie : options.cookie }); } export async function validate(url: string): Promise { From 0b21c1caf9a463ae8e77140d829a31ee0dbd7934 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 12:50:14 +0530 Subject: [PATCH 03/13] Codes made pretty --- play-dl/SoundCloud/index.ts | 26 +++++++++++++------------- play-dl/index.ts | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/play-dl/SoundCloud/index.ts b/play-dl/SoundCloud/index.ts index 0e55580..55efd7a 100644 --- a/play-dl/SoundCloud/index.ts +++ b/play-dl/SoundCloud/index.ts @@ -33,15 +33,15 @@ export async function soundcloud(url: string): Promise { +export async function stream(url: string, quality?: number): Promise { const data = await soundcloud(url); if (data instanceof SoundCloudPlaylist) throw new Error("Streams can't be created from Playlist url"); - const HLSformats = parseHlsFormats(data.formats) - if(!quality) quality = HLSformats.length - 1; - else if(quality <= 0) quality = 0; - else if(quality > HLSformats.length) quality = HLSformats.length - 1; + const HLSformats = parseHlsFormats(data.formats); + if (!quality) quality = HLSformats.length - 1; + else if (quality <= 0) quality = 0; + else if (quality > HLSformats.length) quality = HLSformats.length - 1; const req_url = HLSformats[quality].url + '?client_id=' + soundData.client_id; const s_data = JSON.parse(await request(req_url)); const type = HLSformats[quality].format.mime_type.startsWith('audio/ogg') @@ -50,11 +50,11 @@ export async function stream(url: string, quality? : number): Promise { return new Stream(s_data.url, type); } -export async function stream_from_info(data: SoundCloudTrack, quality? :number): Promise { - const HLSformats = parseHlsFormats(data.formats) - if(!quality) quality = HLSformats.length - 1; - else if(quality <= 0) quality = 0; - else if(quality > HLSformats.length) quality = HLSformats.length - 1; +export async function stream_from_info(data: SoundCloudTrack, quality?: number): Promise { + const HLSformats = parseHlsFormats(data.formats); + if (!quality) quality = HLSformats.length - 1; + else if (quality <= 0) quality = 0; + else if (quality > HLSformats.length) quality = HLSformats.length - 1; const req_url = HLSformats[quality].url + '?client_id=' + soundData.client_id; const s_data = JSON.parse(await request(req_url)); const type = HLSformats[quality].format.mime_type.startsWith('audio/ogg') @@ -86,10 +86,10 @@ export async function so_validate(url: string): Promise { - if(format.format.protocol === 'hls') result.push(format) + if (format.format.protocol === 'hls') result.push(format); }); return result; -} \ No newline at end of file +} diff --git a/play-dl/index.ts b/play-dl/index.ts index 9168f89..87b1c57 100644 --- a/play-dl/index.ts +++ b/play-dl/index.ts @@ -12,9 +12,9 @@ import { SoundCloudTrack, Stream as SoStream } from './SoundCloud/classes'; import { LiveStreaming, Stream as YTStream } from './YouTube/classes/LiveStream'; export async function stream(url: string, options: StreamOptions = {}): Promise { - if(url.length === 0) throw new Error('Stream URL has a length of 0. Check your url again.') + if (url.length === 0) throw new Error('Stream URL has a length of 0. Check your url again.'); if (url.indexOf('soundcloud') !== -1) return await so_stream(url, options.quality); - else return await yt_stream(url, { cookie : options.cookie }); + else return await yt_stream(url, { cookie: options.cookie }); } export async function stream_from_info( @@ -22,7 +22,7 @@ export async function stream_from_info( options: StreamOptions = {} ): Promise { if (info instanceof SoundCloudTrack) return await so_stream_info(info); - else return await yt_stream_info(info, { cookie : options.cookie }); + else return await yt_stream_info(info, { cookie: options.cookie }); } export async function validate(url: string): Promise { From 76b5c6c272cf839281d99eccf6c442a682068f14 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 12:52:23 +0530 Subject: [PATCH 04/13] Docs updated --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 6053b86..8d9e790 100644 --- a/docs/README.md +++ b/docs/README.md @@ -59,7 +59,7 @@ let resource = createAudioResource(source.stream, { }) // This creates resource for playing ``` -### stream_from_info(info : `infoData`, options? : `StreamOptions`) +#### stream_from_info(info : `infoData`, options? : `StreamOptions`) _This is basic to create a stream from a info [ from [video_info](https://github.com/play-dl/play-dl#video_infourl--string) function or [soundcloud]() function [**Only SoundCloudTrack class is allowed**] ]._ From 5befd9a4f42696f3375258eacd6b4d41e1650ca7 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 13:15:07 +0530 Subject: [PATCH 05/13] Quality process updated --- play-dl/SoundCloud/index.ts | 8 ++++---- play-dl/YouTube/stream.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/play-dl/SoundCloud/index.ts b/play-dl/SoundCloud/index.ts index 55efd7a..776ff8c 100644 --- a/play-dl/SoundCloud/index.ts +++ b/play-dl/SoundCloud/index.ts @@ -39,9 +39,9 @@ export async function stream(url: string, quality?: number): Promise { if (data instanceof SoundCloudPlaylist) throw new Error("Streams can't be created from Playlist url"); const HLSformats = parseHlsFormats(data.formats); - if (!quality) quality = HLSformats.length - 1; + if (typeof quality !== 'number') quality = HLSformats.length - 1; else if (quality <= 0) quality = 0; - else if (quality > HLSformats.length) quality = HLSformats.length - 1; + else if (quality >= HLSformats.length) quality = HLSformats.length - 1; const req_url = HLSformats[quality].url + '?client_id=' + soundData.client_id; const s_data = JSON.parse(await request(req_url)); const type = HLSformats[quality].format.mime_type.startsWith('audio/ogg') @@ -52,9 +52,9 @@ export async function stream(url: string, quality?: number): Promise { export async function stream_from_info(data: SoundCloudTrack, quality?: number): Promise { const HLSformats = parseHlsFormats(data.formats); - if (!quality) quality = HLSformats.length - 1; + if (typeof quality !== 'number') quality = HLSformats.length - 1; else if (quality <= 0) quality = 0; - else if (quality > HLSformats.length) quality = HLSformats.length - 1; + else if (quality >= HLSformats.length) quality = HLSformats.length - 1; const req_url = HLSformats[quality].url + '?client_id=' + soundData.client_id; const s_data = JSON.parse(await request(req_url)); const type = HLSformats[quality].format.mime_type.startsWith('audio/ogg') diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index 15f840d..02332d0 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -54,9 +54,9 @@ export async function stream(url: string, options: StreamOptions = {}): Promise< } const audioFormat = parseAudioFormats(info.format); - if (!options.quality) options.quality = audioFormat.length - 1; + if (typeof options.quality !== 'number') options.quality = audioFormat.length - 1; else if (options.quality <= 0) options.quality = 0; - else if (options.quality > audioFormat.length) options.quality = audioFormat.length - 1; + else if (options.quality >= audioFormat.length) options.quality = audioFormat.length - 1; final.push(audioFormat[options.quality]); let type: StreamType = audioFormat[options.quality].codec === 'opus' && audioFormat[options.quality].container === 'webm' @@ -87,9 +87,9 @@ export async function stream_from_info(info: InfoData, options: StreamOptions = } const audioFormat = parseAudioFormats(info.format); - if (!options.quality) options.quality = audioFormat.length - 1; + if (typeof options.quality !== 'number') options.quality = audioFormat.length - 1; else if (options.quality <= 0) options.quality = 0; - else if (options.quality > audioFormat.length) options.quality = audioFormat.length - 1; + else if (options.quality >= audioFormat.length) options.quality = audioFormat.length - 1; final.push(audioFormat[options.quality]); let type: StreamType = audioFormat[options.quality].codec === 'opus' && audioFormat[options.quality].container === 'webm' From 844a3a4b8c53c355bfbed9406fd3cdd84a013bc1 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 15:13:45 +0530 Subject: [PATCH 06/13] Global Search added --- docs/README.md | 37 +++++++++++++++++++++++++++++++---- docs/YouTube/README.md | 18 ----------------- play-dl/SoundCloud/index.ts | 17 ++++++++++++++++ play-dl/Spotify/index.ts | 39 +++++++++++++++++++++++++++++++++++++ play-dl/YouTube/index.ts | 1 - play-dl/YouTube/search.ts | 2 +- play-dl/index.ts | 24 ++++++++++++++++++++--- 7 files changed, 111 insertions(+), 27 deletions(-) diff --git a/docs/README.md b/docs/README.md index 8d9e790..5f0fc0c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -40,14 +40,43 @@ _This creates basic spotify / soundcloud 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. ``` +### Search + +#### SearchOptions : + +- limit : `number` :- Sets total amount of results you want. +- source : { + + youtube: `video` | `playlist` | `channel` ; + + spotify: `album` | `playlist` | `track` ; + + soundcloud: `tracks` | `playlists` | `albums` ; + + } + +#### search(query : `string`, options? : [`SearchOptions`]()) + +_This is basic to search with any source._ + +**NOTE :-** If no options.source is not specified, then it will default to youtube video search. + +```js +let data = await search('Rick Roll', { limit : 1, source { youtube : "video" } }) // Searches for youtube video + +let data = await search('Rick Roll', { limit: 1, source { soundcloud : "track" } }) // Searches for spotify track. + +let data = await search('Rick Roll', { limit: 1, source { spotify : "tracks" } }) // Searches for soundcloud track. +``` + ### Stream -### StreamOptions : +#### StreamOptions : - quality : `number` :- Sets quality of stream [ 0 = Lowest, 1 = Medium ]. Leave this empty to get highest audio quality. -- cookie : `string` :- **[Cookies](https://github.com/play-dl/play-dl/discussions/34) are optional and are required for playing age restricted videos.** +- cookie : `string` :- **[Cookies](https://github.com/play-dl/play-dl/discussions/34)** are optional and are required for playing age restricted videos. -#### stream(url : `string`, options? : `StreamOptions`) +#### stream(url : `string`, options? : [`StreamOptions`]()) _This is basic to create a stream from a youtube or soundcloud url._ @@ -59,7 +88,7 @@ let resource = createAudioResource(source.stream, { }) // This creates resource for playing ``` -#### stream_from_info(info : `infoData`, options? : `StreamOptions`) +#### stream_from_info(info : `infoData`, options? : [`StreamOptions`]()) _This is basic to create a stream from a info [ from [video_info](https://github.com/play-dl/play-dl#video_infourl--string) function or [soundcloud]() function [**Only SoundCloudTrack class is allowed**] ]._ diff --git a/docs/YouTube/README.md b/docs/YouTube/README.md index f22a589..d054fd3 100644 --- a/docs/YouTube/README.md +++ b/docs/YouTube/README.md @@ -41,24 +41,6 @@ _This will return videoID or playlistID from a url_ let id = extractID(url) ``` -## Search - -### search(url : `string`, options? : [SearchOptions](https://github.com/play-dl/play-dl/tree/main/play-dl/YouTube#searchoptions)) - -_This enables all searching mechanism (video, channel, playlist)_ - -```js -const options = { - limit : 1 -} -const results = await youtube.search('never gonna give you up', options); -console.log(results[0].url); -``` - -- #### SearchOptions - - _type_ : `video` | `channel` | `playlist` - - _limit_ : `integer` - ## Video ### video_basic_info(url : `string`, cookie? : `string`) diff --git a/play-dl/SoundCloud/index.ts b/play-dl/SoundCloud/index.ts index 776ff8c..18de69b 100644 --- a/play-dl/SoundCloud/index.ts +++ b/play-dl/SoundCloud/index.ts @@ -33,6 +33,23 @@ export async function soundcloud(url: string): Promise { + const response = await request( + `https://api-v2.soundcloud.com/search/${type}?q=${query}&client_id=${soundData.client_id}&limit=${limit}` + ); + const results: (SoundCloudPlaylist | SoundCloudTrack)[] = []; + const json_data = JSON.parse(response); + json_data.collection.forEach((x: any) => { + if (type === 'tracks') results.push(new SoundCloudTrack(x)); + else results.push(new SoundCloudPlaylist(x, soundData.client_id)); + }); + return results; +} + export async function stream(url: string, quality?: number): Promise { const data = await soundcloud(url); diff --git a/play-dl/Spotify/index.ts b/play-dl/Spotify/index.ts index 0842462..df5b02a 100644 --- a/play-dl/Spotify/index.ts +++ b/play-dl/Spotify/index.ts @@ -110,6 +110,45 @@ export function is_expired(): boolean { else return false; } +export async function sp_search( + query: string, + type: 'album' | 'playlist' | 'track', + limit: number = 10 +): Promise<(SpotifyAlbum | SpotifyPlaylist | SpotifyVideo)[]> { + const results: (SpotifyAlbum | SpotifyPlaylist | SpotifyVideo)[] = []; + if (!spotifyData) throw new Error('Spotify Data is missing\nDid you forgot to do authorization ?'); + if (query.length === 0) throw new Error('Pass some query to search.'); + if (limit > 50 || limit < 0) throw new Error(`You crossed limit range of Spotify [ 0 - 50 ]`); + const response = await request( + `https://api.spotify.com/v1/search?type=${type}&q=${query.replaceAll(' ', '+')}&limit=${limit}&market=${ + spotifyData.market + }`, + { + headers: { + Authorization: `${spotifyData.token_type} ${spotifyData.access_token}` + } + } + ).catch((err: Error) => { + return err; + }); + if (response instanceof Error) throw response; + const json_data = JSON.parse(response); + if (type === 'track') { + json_data.tracks.items.forEach((track: any) => { + results.push(new SpotifyVideo(track)); + }); + } else if (type === 'album') { + json_data.albums.items.forEach((album: any) => { + results.push(new SpotifyAlbum(album, spotifyData)); + }); + } else if (type === 'playlist') { + json_data.playlists.items.forEach((playlist: any) => { + results.push(new SpotifyPlaylist(playlist, spotifyData)); + }); + } + return results; +} + export async function refreshToken(): Promise { const response = await request(`https://accounts.spotify.com/api/token`, { headers: { diff --git a/play-dl/YouTube/index.ts b/play-dl/YouTube/index.ts index a268c62..8ca7478 100644 --- a/play-dl/YouTube/index.ts +++ b/play-dl/YouTube/index.ts @@ -1,3 +1,2 @@ -export { search } from './search'; export { stream, stream_from_info } from './stream'; export * from './utils'; diff --git a/play-dl/YouTube/search.ts b/play-dl/YouTube/search.ts index f83cdc9..45cc9c4 100644 --- a/play-dl/YouTube/search.ts +++ b/play-dl/YouTube/search.ts @@ -10,7 +10,7 @@ enum SearchType { Channel = 'EgIQAg%253D%253D' } -export async function search( +export async function yt_search( search: string, options: ParseSearchInterface = {} ): Promise<(Video | Channel | PlayList)[]> { diff --git a/play-dl/index.ts b/play-dl/index.ts index 87b1c57..d98e9e8 100644 --- a/play-dl/index.ts +++ b/play-dl/index.ts @@ -1,15 +1,25 @@ -export { playlist_info, video_basic_info, video_info, search, yt_validate, extractID } from './YouTube'; +export { playlist_info, video_basic_info, video_info, yt_validate, extractID } from './YouTube'; export { spotify, sp_validate, refreshToken, is_expired } from './Spotify'; export { soundcloud, so_validate } from './SoundCloud'; +interface SearchOptions { + limit?: number; + source?: { + youtube?: 'video' | 'playlist' | 'channel'; + spotify?: 'album' | 'playlist' | 'track'; + soundcloud?: 'tracks' | 'playlists' | 'albums'; + }; +} + import readline from 'readline'; import fs from 'fs'; import { sp_validate, yt_validate, so_validate } from '.'; -import { SpotifyAuthorize } from './Spotify'; -import { check_id, stream as so_stream, stream_from_info as so_stream_info } from './SoundCloud'; +import { SpotifyAuthorize, sp_search } from './Spotify'; +import { check_id, so_search, stream as so_stream, stream_from_info as so_stream_info } from './SoundCloud'; import { InfoData, stream as yt_stream, StreamOptions, stream_from_info as yt_stream_info } from './YouTube/stream'; import { SoundCloudTrack, Stream as SoStream } from './SoundCloud/classes'; import { LiveStreaming, Stream as YTStream } from './YouTube/classes/LiveStream'; +import { yt_search } from './YouTube/search'; export async function stream(url: string, options: StreamOptions = {}): Promise { if (url.length === 0) throw new Error('Stream URL has a length of 0. Check your url again.'); @@ -17,6 +27,14 @@ export async function stream(url: string, options: StreamOptions = {}): Promise< else return await yt_stream(url, { cookie: options.cookie }); } +export async function search(query: string, options: SearchOptions = {}) { + if (!options.source) options.source = { youtube: 'video' }; + + if (options.source.youtube) return await yt_search(query, { limit: options.limit, type: options.source.youtube }); + else if (options.source.spotify) return await sp_search(query, options.source.spotify, options.limit); + else if (options.source.soundcloud) return await so_search(query, options.source.soundcloud, options.limit); +} + export async function stream_from_info( info: InfoData | SoundCloudTrack, options: StreamOptions = {} From 47380681e1e7d28bd237d8e00d80add35616505a Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 15:14:49 +0530 Subject: [PATCH 07/13] Docs updated --- docs/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 5f0fc0c..92c54e9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -97,9 +97,9 @@ _This is basic to create a stream from a info [ from [video_info](https://github ```js let source = await stream_from_info(info) // This will create a stream Class from video_info or SoundCoudTrack Class. - /* OR - let source = await stream_from_info(info, { cookie }) This will create a stream Class and also give cookies if retrying. - */ + + let source = await stream_from_info(info, { cookie }) //This will create a stream Class and also give cookies if retrying. + let resource = createAudioResource(source.stream, { inputType : source.type From 6850a6808fb9754e5abf786a376f75c36b5c31f0 Mon Sep 17 00:00:00 2001 From: Killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 15:27:12 +0530 Subject: [PATCH 08/13] Main docs updated --- docs/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/README.md b/docs/README.md index 92c54e9..665221c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -55,7 +55,7 @@ authorization() //After then you will be asked about type of data you want to cr } -#### search(query : `string`, options? : [`SearchOptions`]()) +#### search(query : `string`, options? : [`SearchOptions`](https://github.com/play-dl/play-dl/tree/main/docs#searchoptions-)) _This is basic to search with any source._ @@ -76,7 +76,7 @@ let data = await search('Rick Roll', { limit: 1, source { spotify : "tracks" } } - quality : `number` :- Sets quality of stream [ 0 = Lowest, 1 = Medium ]. Leave this empty to get highest audio quality. - cookie : `string` :- **[Cookies](https://github.com/play-dl/play-dl/discussions/34)** are optional and are required for playing age restricted videos. -#### stream(url : `string`, options? : [`StreamOptions`]()) +#### stream(url : `string`, options? : [`StreamOptions`](https://github.com/play-dl/play-dl/tree/main/docs#streamoptions-)) _This is basic to create a stream from a youtube or soundcloud url._ @@ -88,9 +88,9 @@ let resource = createAudioResource(source.stream, { }) // This creates resource for playing ``` -#### stream_from_info(info : `infoData`, options? : [`StreamOptions`]()) +#### stream_from_info(info : `infoData`, options? : [`StreamOptions`](https://github.com/play-dl/play-dl/tree/main/docs#streamoptions-)) -_This is basic to create a stream from a info [ from [video_info](https://github.com/play-dl/play-dl#video_infourl--string) function or [soundcloud]() function [**Only SoundCloudTrack class is allowed**] ]._ +_This is basic to create a stream from a info [ from [video_info](https://github.com/play-dl/play-dl#video_infourl--string) function or [soundcloud](https://github.com/play-dl/play-dl/tree/main/docs/SoundCloud#soundcloudurl--string) function [**Only SoundCloudTrack class is allowed**] ]._ **Note :** Here, cookies are required only for retrying purposes. From 842d704bf2cd268569c19d9ab0db8b62c87bd3d7 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 15:27:47 +0530 Subject: [PATCH 09/13] Package updated --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 659a431..6815000 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "play-dl", - "version": "1.0.2", + "version": "1.0.3", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 5bce5d3..438dc38 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "play-dl", - "version": "1.0.2", + "version": "1.0.3", "description": "YouTube, SoundCloud, Spotify streaming for discord.js bots", "main": "dist/index.js", "typings": "dist/index.d.ts", From 7f8d81472897a79fb7f132f68aeca5cd9c992930 Mon Sep 17 00:00:00 2001 From: Killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 15:56:30 +0530 Subject: [PATCH 10/13] Update README.md --- docs/README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 665221c..baceb8e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -81,7 +81,13 @@ let data = await search('Rick Roll', { limit: 1, source { spotify : "tracks" } } _This is basic to create a stream from a youtube or soundcloud url._ ```js -let source = await stream("url") // This will create a stream Class. +let source = await stream("url") // This will create a stream Class. Highest Quality + +let source = await stream("url", { quality : 0 }) // Lowest quality + +let source = await stream("url", { quality : 1 }) // Next to Lowest quality. + +let source = await stream("url", { cookie: COOKIE }) //This will create a stream Class and also give cookies. let resource = createAudioResource(source.stream, { inputType : source.type @@ -95,10 +101,13 @@ _This is basic to create a stream from a info [ from [video_info](https://github **Note :** Here, cookies are required only for retrying purposes. ```js - let source = await stream_from_info(info) // This will create a stream Class from video_info or SoundCoudTrack Class. +let source = await stream_from_info(info) // This will create a stream Class from video_info or SoundCoudTrack Class. Highest Quality + +let source = await stream_from_info(info, { quality : 0 }) // Lowest quality +let source = await stream_from_info(info, { quality : 1 }) // Next to Lowest quality. - let source = await stream_from_info(info, { cookie }) //This will create a stream Class and also give cookies if retrying. +let source = await stream_from_info(info, { cookie: COOKIE }) //This will create a stream Class and also give cookies if retrying. let resource = createAudioResource(source.stream, { From 89e17987a5463f82aaf5c92ca7527131588750a3 Mon Sep 17 00:00:00 2001 From: Killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 16:02:03 +0530 Subject: [PATCH 11/13] Update README.md --- docs/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index baceb8e..ca19ceb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -59,9 +59,11 @@ authorization() //After then you will be asked about type of data you want to cr _This is basic to search with any source._ -**NOTE :-** If no options.source is not specified, then it will default to youtube video search. +**NOTE :-** If options.source is not specified, then it will default to youtube video search. ```js +let data = await search('Rick Roll', { limit : 1 }) // Searches for youtube video + let data = await search('Rick Roll', { limit : 1, source { youtube : "video" } }) // Searches for youtube video let data = await search('Rick Roll', { limit: 1, source { soundcloud : "track" } }) // Searches for spotify track. From 09dfa4b9739b0e8217e23fd26e098668266eac98 Mon Sep 17 00:00:00 2001 From: Killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 18:12:23 +0530 Subject: [PATCH 12/13] Update README.md --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index ca19ceb..a64efac 100644 --- a/docs/README.md +++ b/docs/README.md @@ -66,9 +66,9 @@ let data = await search('Rick Roll', { limit : 1 }) // Searches for youtube vide let data = await search('Rick Roll', { limit : 1, source { youtube : "video" } }) // Searches for youtube video -let data = await search('Rick Roll', { limit: 1, source { soundcloud : "track" } }) // Searches for spotify track. +let data = await search('Rick Roll', { limit: 1, source { spotify : "track" } }) // Searches for spotify track. -let data = await search('Rick Roll', { limit: 1, source { spotify : "tracks" } }) // Searches for soundcloud track. +let data = await search('Rick Roll', { limit: 1, source { soundcloud : "tracks" } }) // Searches for soundcloud track. ``` ### Stream From e4015dbcf7f17cc9c893e436d7c32402bca4c5b6 Mon Sep 17 00:00:00 2001 From: Killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 24 Sep 2021 18:13:30 +0530 Subject: [PATCH 13/13] Update README.md --- docs/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index a64efac..1ea6ed9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -64,11 +64,11 @@ _This is basic to search with any source._ ```js let data = await search('Rick Roll', { limit : 1 }) // Searches for youtube video -let data = await search('Rick Roll', { limit : 1, source { youtube : "video" } }) // Searches for youtube video +let data = await search('Rick Roll', { limit : 1, source : { youtube : "video" } }) // Searches for youtube video -let data = await search('Rick Roll', { limit: 1, source { spotify : "track" } }) // Searches for spotify track. +let data = await search('Rick Roll', { limit: 1, source : { spotify : "track" } }) // Searches for spotify track. -let data = await search('Rick Roll', { limit: 1, source { soundcloud : "tracks" } }) // Searches for soundcloud track. +let data = await search('Rick Roll', { limit: 1, source : { soundcloud : "tracks" } }) // Searches for soundcloud track. ``` ### Stream