From c712f2d8c601a7e1752f337d8335472016fe800d Mon Sep 17 00:00:00 2001 From: watchdogsrox Date: Thu, 29 Apr 2021 04:38:15 -0400 Subject: [PATCH 01/26] Fixed spotify album/playlist loading Utilizing map which results in a much faster spotify playlist/album loading --- src/Player.ts | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index a46af6e..cf067b5 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -175,17 +175,15 @@ export class Player extends EventEmitter { } break; - // todo: make spotify playlist/album load faster - case 'spotify_album': - case 'spotify_playlist': { - this.emit(PlayerEvents.PLAYLIST_PARSE_START, null, message); - const playlist = await spotify.getData(query); - if (!playlist) return void this.emit(PlayerEvents.NO_RESULTS, message, query); + // todo: make spotify playlist/album load faster + case 'spotify_album': + case 'spotify_playlist': { + this.emit(PlayerEvents.PLAYLIST_PARSE_START, null, message); + const playlist = await spotify.getData(query); + if (!playlist) return void this.emit(PlayerEvents.NO_RESULTS, message, query); - // tslint:disable:no-shadowed-variable - const tracks = []; - - for (const item of playlist.tracks.items) { + //Much faster loading + const tracks = await Promise.all(playlist.tracks.items.map(async (track) => { const sq = queryType === 'spotify_album' ? `${item.artists[0].name} - ${item.name}` @@ -197,8 +195,26 @@ export class Player extends EventEmitter { pl: true }); - if (data[0]) tracks.push(data[0]); - } + return results[0]; + })); + +// // tslint:disable:no-shadowed-variable +// const tracks = []; + +// for (const item of playlist.tracks.items) { +// const sq = +// queryType === 'spotify_album' +// ? `${item.artists[0].name} - ${item.name}` +// : `${item.track.artists[0].name} - ${item.name}`; +// const data = await Util.ytSearch(sq, { +// limit: 1, +// player: this, +// user: message.author, +// pl: true +// }); + +// if (data[0]) tracks.push(data[0]); +// } if (!tracks.length) return void this.emit(PlayerEvents.NO_RESULTS, message, query); From fd0450bf18e1a2132478e8a24a76b730a566df37 Mon Sep 17 00:00:00 2001 From: watchdogsrox Date: Thu, 29 Apr 2021 04:49:31 -0400 Subject: [PATCH 02/26] Update Player.ts --- src/Player.ts | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index cf067b5..e204c87 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -182,7 +182,6 @@ export class Player extends EventEmitter { const playlist = await spotify.getData(query); if (!playlist) return void this.emit(PlayerEvents.NO_RESULTS, message, query); - //Much faster loading const tracks = await Promise.all(playlist.tracks.items.map(async (track) => { const sq = queryType === 'spotify_album' @@ -198,24 +197,6 @@ export class Player extends EventEmitter { return results[0]; })); -// // tslint:disable:no-shadowed-variable -// const tracks = []; - -// for (const item of playlist.tracks.items) { -// const sq = -// queryType === 'spotify_album' -// ? `${item.artists[0].name} - ${item.name}` -// : `${item.track.artists[0].name} - ${item.name}`; -// const data = await Util.ytSearch(sq, { -// limit: 1, -// player: this, -// user: message.author, -// pl: true -// }); - -// if (data[0]) tracks.push(data[0]); -// } - if (!tracks.length) return void this.emit(PlayerEvents.NO_RESULTS, message, query); const pl = { From 892fc29a1806224e3c094c0a2b528b06f3b2d89d Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Sun, 9 May 2021 18:09:06 +0545 Subject: [PATCH 03/26] spotify --- src/Player.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index a12b9e2..8cc97ad 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -177,18 +177,18 @@ export class Player extends EventEmitter { } break; - // todo: make spotify playlist/album load faster case 'spotify_album': case 'spotify_playlist': { this.emit(PlayerEvents.PLAYLIST_PARSE_START, null, message); const playlist = await spotify.getData(query); if (!playlist) return void this.emit(PlayerEvents.NO_RESULTS, message, query); - const tracks = await Promise.all(playlist.tracks.items.map(async (track) => { + const tracks = await Promise.all(playlist.tracks.items.map(async (item: any) => { const sq = queryType === 'spotify_album' ? `${item.artists[0].name} - ${item.name}` : `${item.track.artists[0].name} - ${item.name}`; + const data = await Util.ytSearch(sq, { limit: 1, player: this, @@ -196,7 +196,7 @@ export class Player extends EventEmitter { pl: true }); - return results[0]; + return data[0]; })); if (!tracks.length) return void this.emit(PlayerEvents.NO_RESULTS, message, query); From 3a09c172480c30f635f84e3bb3f084b896893591 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Sun, 9 May 2021 18:09:20 +0545 Subject: [PATCH 04/26] formatting --- src/Player.ts | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index 8cc97ad..1c55cc5 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -177,27 +177,29 @@ export class Player extends EventEmitter { } break; - case 'spotify_album': - case 'spotify_playlist': { - this.emit(PlayerEvents.PLAYLIST_PARSE_START, null, message); - const playlist = await spotify.getData(query); - if (!playlist) return void this.emit(PlayerEvents.NO_RESULTS, message, query); + case 'spotify_album': + case 'spotify_playlist': { + this.emit(PlayerEvents.PLAYLIST_PARSE_START, null, message); + const playlist = await spotify.getData(query); + if (!playlist) return void this.emit(PlayerEvents.NO_RESULTS, message, query); - const tracks = await Promise.all(playlist.tracks.items.map(async (item: any) => { - const sq = - queryType === 'spotify_album' - ? `${item.artists[0].name} - ${item.name}` - : `${item.track.artists[0].name} - ${item.name}`; + const tracks = await Promise.all( + playlist.tracks.items.map(async (item: any) => { + const sq = + queryType === 'spotify_album' + ? `${item.artists[0].name} - ${item.name}` + : `${item.track.artists[0].name} - ${item.name}`; - const data = await Util.ytSearch(sq, { - limit: 1, - player: this, - user: message.author, - pl: true - }); + const data = await Util.ytSearch(sq, { + limit: 1, + player: this, + user: message.author, + pl: true + }); - return data[0]; - })); + return data[0]; + }) + ); if (!tracks.length) return void this.emit(PlayerEvents.NO_RESULTS, message, query); From ea4dc26671d08f49beba7ae79b78f888c5bd34c9 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Sun, 9 May 2021 18:19:25 +0545 Subject: [PATCH 05/26] jsdoc --- src/Player.ts | 53 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index 1c55cc5..ed2bf8e 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -131,6 +131,14 @@ export class Player extends EventEmitter { return this.Extractors.delete(extractorName); } + /** + * Internal method to search tracks + * @param {DiscordMessage} message The message + * @param {string} query The query + * @param {boolean} [firstResult=false] If it should return the first result + * @returns {Promise} + * @private + */ private _searchTracks(message: Message, query: string, firstResult?: boolean): Promise { return new Promise(async (resolve) => { let tracks: Track[] = []; @@ -379,7 +387,7 @@ export class Player extends EventEmitter { * Play a song * @param {DiscordMessage} message The discord.js message object * @param {string|Track} query Search query, can be `Player.Track` instance - * @param {Boolean} [firstResult] If it should play the first result + * @param {Boolean} [firstResult=false] If it should play the first result * @example await player.play(message, "never gonna give you up", true) * @returns {Promise} */ @@ -990,6 +998,13 @@ export class Player extends EventEmitter { return this.skip(message); } + /** + * Internal method to handle VoiceStateUpdate events + * @param {DiscordVoiceState} oldState The old voice state + * @param {DiscordVoiceState} newState The new voice state + * @returns {void} + * @private + */ private _handleVoiceStateUpdate(oldState: VoiceState, newState: VoiceState): void { const queue = this.queues.find((g) => g.guildID === oldState.guild.id); if (!queue) return; @@ -1023,7 +1038,14 @@ export class Player extends EventEmitter { } } - private _addTrackToQueue(message: Message, track: Track): Queue { + /** + * Internal method used to add tracks to the queue + * @param {DiscordMessage} message The discord message + * @param {Track} track The track + * @returns {Queue} + * @private + */ + _addTrackToQueue(message: Message, track: Track): Queue { const queue = this.getQueue(message); if (!queue) this.emit( @@ -1037,7 +1059,14 @@ export class Player extends EventEmitter { return queue; } - private _addTracksToQueue(message: Message, tracks: Track[]): Queue { + /** + * Same as `_addTrackToQueue` but used for multiple tracks + * @param {DiscordMessage} message Discord message + * @param {Track[]} tracks The tracks + * @returns {Queue} + * @private + */ + _addTracksToQueue(message: Message, tracks: Track[]): Queue { const queue = this.getQueue(message); if (!queue) throw new PlayerError( @@ -1085,6 +1114,13 @@ export class Player extends EventEmitter { }); } + /** + * Internal method used to init stream playing + * @param {Queue} queue The queue + * @param {boolean} firstPlay If this is a first play + * @returns {Promise} + * @private + */ private async _playTrack(queue: Queue, firstPlay: boolean): Promise { if (queue.stopped) return; @@ -1139,6 +1175,14 @@ export class Player extends EventEmitter { }); } + /** + * Internal method to play audio + * @param {Queue} queue The queue + * @param {boolean} updateFilter If this method was called for audio filter update + * @param {number} [seek] Time in ms to seek to + * @returns {Promise} + * @private + */ private _playStream(queue: Queue, updateFilter: boolean, seek?: number): Promise { return new Promise(async (resolve) => { const ffmpeg = Util.checkFFmpeg(); @@ -1323,7 +1367,8 @@ export default Player; */ /** - * Emitted when an error is triggered + * Emitted when an error is triggered. + * This event should handled properly by the users otherwise it might crash the process! * @event Player#error * @param {String} error It can be `NotConnected`, `UnableToJoin`, `NotPlaying`, `ParseError`, `LiveVideo` or `VideoUnavailable`. * @param {DiscordMessage} message The message From 5b8b6e0c0d4763474255860a84603677637850b4 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Sun, 9 May 2021 18:26:54 +0545 Subject: [PATCH 06/26] jsdoc --- src/Player.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Player.ts b/src/Player.ts index ed2bf8e..42b8837 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -39,7 +39,19 @@ export class Player extends EventEmitter { * @type {DiscordCollection} */ public queues = new Collection(); + + /** + * Collection of results collectors + * @type {DiscordCollection>} + * @private + */ private _resultsCollectors = new Collection>(); + + /** + * Collection of cooldowns timeout + * @type {DiscordCollection} + * @private + */ private _cooldownsTimeout = new Collection(); /** From f5a48bc433423ccf5f25a071af34dd51e9f5a7f6 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Sun, 9 May 2021 18:31:18 +0545 Subject: [PATCH 07/26] soundcloud link --- src/utils/Util.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/Util.ts b/src/utils/Util.ts index 7826f5d..86d28c6 100644 --- a/src/utils/Util.ts +++ b/src/utils/Util.ts @@ -65,6 +65,8 @@ export class Util { * @returns {QueryType} */ static getQueryType(query: string): QueryType { + // @todo: better validation + if (query.match(/soundcloud.app.goo.gl/)) return 'soundcloud_track'; if (SoundcloudValidateURL(query) && !query.includes('/sets/')) return 'soundcloud_track'; if (SoundcloudValidateURL(query) && query.includes('/sets/')) return 'soundcloud_playlist'; if (spotifySongRegex.test(query)) return 'spotify_song'; From 903bfaae46f9434f1f14df70d794327b35d77a38 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Sun, 9 May 2021 18:50:36 +0545 Subject: [PATCH 08/26] bump soundcloud-scraper --- package.json | 2 +- src/utils/Util.ts | 2 -- yarn.lock | 8 ++++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 69cea7b..e894ace 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "homepage": "https://github.com/Androz2091/discord-player#readme", "dependencies": { "discord-ytdl-core": "^5.0.3", - "soundcloud-scraper": "^4.0.3", + "soundcloud-scraper": "^4.0.4", "spotify-url-info": "^2.2.0", "youtube-sr": "^4.0.6", "ytdl-core": "^4.7.0" diff --git a/src/utils/Util.ts b/src/utils/Util.ts index 86d28c6..7826f5d 100644 --- a/src/utils/Util.ts +++ b/src/utils/Util.ts @@ -65,8 +65,6 @@ export class Util { * @returns {QueryType} */ static getQueryType(query: string): QueryType { - // @todo: better validation - if (query.match(/soundcloud.app.goo.gl/)) return 'soundcloud_track'; if (SoundcloudValidateURL(query) && !query.includes('/sets/')) return 'soundcloud_track'; if (SoundcloudValidateURL(query) && query.includes('/sets/')) return 'soundcloud_playlist'; if (spotifySongRegex.test(query)) return 'spotify_song'; diff --git a/yarn.lock b/yarn.lock index 14800c2..cf8a6a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3917,10 +3917,10 @@ sort-array@^2.0.0: object-get "^2.1.0" typical "^2.6.0" -soundcloud-scraper@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/soundcloud-scraper/-/soundcloud-scraper-4.0.3.tgz#cd7ed1d7b6ed1d7729fd7580c011281f652b920f" - integrity sha512-A0a6sVJ2wkkWIX8Ft3L63sfHBlFDRAaPFif+SWi07KCNLh8YTcylw45pts76pndxlupKwV2NgOTIYeF/F9tg8w== +soundcloud-scraper@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/soundcloud-scraper/-/soundcloud-scraper-4.0.4.tgz#dfd6a45dc6e63fac7d6b31f2ba1d23a199ca4fb6" + integrity sha512-ei3KuPsVZRiq9j2GN580gQwVGZUWMdkmDAANSPm8qweUa4/UnKAnYiUsc/6volZsQiGsnJAP9+8HECDxNcTg6A== dependencies: cheerio "^1.0.0-rc.3" m3u8stream "^0.8.0" From 4184dcb6f9b401197c8e0d714247cc96ff8c63c4 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Sun, 9 May 2021 18:57:50 +0545 Subject: [PATCH 09/26] fix soundcloud duration --- src/Player.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index 42b8837..40158ed 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -164,7 +164,7 @@ export class Player extends EventEmitter { const track = new Track(this, { title: data.title, url: data.url, - duration: Util.buildTimeCode(Util.parseMS(data.duration / 1000)), + duration: Util.buildTimeCode(Util.parseMS(data.duration)), description: data.description, thumbnail: data.thumbnail, views: data.playCount, @@ -317,7 +317,7 @@ export class Player extends EventEmitter { const r = new Track(this, { title: song.title, url: song.url, - duration: Util.buildTimeCode(Util.parseMS(song.duration / 1000)), + duration: Util.buildTimeCode(Util.parseMS(song.duration)), description: song.description, thumbnail: song.thumbnail ?? 'https://soundcloud.com/pwa-icon-192.png', views: song.playCount ?? 0, From aff8a5ac29a52bdf39e01e202408e0d8ad0ad2af Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Sun, 9 May 2021 19:01:11 +0545 Subject: [PATCH 10/26] make linter happy --- src/Player.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Player.ts b/src/Player.ts index 40158ed..f72c0cb 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -203,6 +203,7 @@ export class Player extends EventEmitter { const playlist = await spotify.getData(query); if (!playlist) return void this.emit(PlayerEvents.NO_RESULTS, message, query); + // tslint:disable-next-line:no-shadowed-variable const tracks = await Promise.all( playlist.tracks.items.map(async (item: any) => { const sq = @@ -280,6 +281,7 @@ export class Player extends EventEmitter { this.emit(PlayerEvents.PLAYLIST_PARSE_END, playlist, message); // @ts-ignore + // tslint:disable-next-line:no-shadowed-variable const tracks = playlist.videos as Track[]; if (this.isPlaying(message)) { @@ -968,6 +970,7 @@ export class Player extends EventEmitter { return { uptime: this.client.uptime, connections: this.client.voice.connections.size, + // tslint:disable:no-shadowed-variable users: this.client.voice.connections.reduce( (a, c) => a + c.channel.members.filter((a) => a.user.id !== this.client.user.id).size, 0 From 18e64801e81fb25ec1f174929c5b4a83649ac1e9 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Sun, 9 May 2021 19:01:49 +0545 Subject: [PATCH 11/26] homepage --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e894ace..4d254d1 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "bugs": { "url": "https://github.com/Androz2091/discord-player/issues" }, - "homepage": "https://github.com/Androz2091/discord-player#readme", + "homepage": "https://discord-player.js.org", "dependencies": { "discord-ytdl-core": "^5.0.3", "soundcloud-scraper": "^4.0.4", From 3582f1c2ad2b8117596d02a5bc1982ba46194b2c Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Sun, 9 May 2021 22:02:01 +0545 Subject: [PATCH 12/26] jsdoc --- src/Player.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Player.ts b/src/Player.ts index f72c0cb..56279e7 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -1091,6 +1091,13 @@ export class Player extends EventEmitter { return queue; } + /** + * Internal method used to create queue + * @param {DiscordMessage} message The message + * @param {Track} track The track + * @returns {Promise} + * @private + */ private _createQueue(message: Message, track: Track): Promise { return new Promise((resolve) => { const channel = message.member.voice ? message.member.voice.channel : null; From 49087bcec13d696edfbb23075a483c1751d1b59a Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 10:56:28 +0545 Subject: [PATCH 13/26] spotify --- .gitattributes | 1 + src/Player.ts | 18 +++++++++++++++--- src/types/types.ts | 1 + src/utils/Util.ts | 6 +++--- 4 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..94f480d --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf \ No newline at end of file diff --git a/src/Player.ts b/src/Player.ts index 56279e7..bc4bfa5 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -187,7 +187,10 @@ export class Player extends EventEmitter { if (matchSpotifyURL) { const spotifyData = await spotify.getPreview(query).catch(() => {}); if (spotifyData) { - tracks = await Util.ytSearch(`${spotifyData.artist} - ${spotifyData.title}`, { + const searchString = this.options.disableArtistSearch + ? spotifyData.title + : `${spotifyData.artist} - ${spotifyData.title}`; + tracks = await Util.ytSearch(searchString, { user: message.author, player: this, limit: 1 @@ -208,8 +211,16 @@ export class Player extends EventEmitter { playlist.tracks.items.map(async (item: any) => { const sq = queryType === 'spotify_album' - ? `${item.artists[0].name} - ${item.name}` - : `${item.track.artists[0].name} - ${item.name}`; + ? `${ + this.options.disableArtistSearch + ? item.artists[0].name + : `${item.artists[0].name} - ` + }${item.name}` + : `${ + this.options.disableArtistSearch + ? item.track.artists[0].name + : `${item.track.artists[0].name} - ` + }${item.name}`; const data = await Util.ytSearch(sq, { limit: 1, @@ -1422,6 +1433,7 @@ export default Player; * @property {YTDLDownloadOptions} [ytdlDownloadOptions={}] The download options passed to `ytdl-core` * @property {Boolean} [useSafeSearch=false] If it should use `safe search` method for youtube searches * @property {Boolean} [disableAutoRegister=false] If it should disable auto-registeration of `@discord-player/extractor` + * @property {Boolean} [disableArtistSearch=false] If it should disable artist search for spotify */ /** diff --git a/src/types/types.ts b/src/types/types.ts index 9e57e90..629188d 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -13,6 +13,7 @@ export interface PlayerOptions { ytdlDownloadOptions?: downloadOptions; useSafeSearch?: boolean; disableAutoRegister?: boolean; + disableArtistSearch?: boolean; } export type FiltersName = keyof QueueFilters; diff --git a/src/utils/Util.ts b/src/utils/Util.ts index 7826f5d..c444c84 100644 --- a/src/utils/Util.ts +++ b/src/utils/Util.ts @@ -4,7 +4,7 @@ import YouTube from 'youtube-sr'; import { Track } from '../Structures/Track'; // @ts-ignore import { validateURL as SoundcloudValidateURL } from 'soundcloud-scraper'; -import { VoiceChannel } from 'discord.js'; +import { StageChannel, VoiceChannel } from 'discord.js'; const spotifySongRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:track\/|\?uri=spotify:track:)((\w|-){22})/; const spotifyPlaylistRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:playlist\/|\?uri=spotify:playlist:)((\w|-){22})/; @@ -190,10 +190,10 @@ export class Util { /** * Checks if the given voice channel is empty - * @param {DiscordVoiceChannel} channel The voice channel + * @param {DiscordVoiceChannel|DiscordStageChannel} channel The voice channel * @returns {Boolean} */ - static isVoiceEmpty(channel: VoiceChannel): boolean { + static isVoiceEmpty(channel: VoiceChannel | StageChannel): boolean { return channel.members.filter((member) => !member.user.bot).size === 0; } From e16811b4c8dd78252346148b33cab9ed13b7d9c1 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 11:00:24 +0545 Subject: [PATCH 14/26] remove stage channels for now --- src/Player.ts | 8 +++++--- src/utils/Util.ts | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index bc4bfa5..ad5730a 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -1046,15 +1046,17 @@ export class Player extends EventEmitter { if (!oldState.channelID || newState.channelID) { const emptyTimeout = this._cooldownsTimeout.get(`empty_${oldState.guild.id}`); - const channelEmpty = Util.isVoiceEmpty(queue.voiceConnection.channel); + + // @todo: stage channels + const channelEmpty = Util.isVoiceEmpty(queue.voiceConnection.channel as VoiceChannel); if (!channelEmpty && emptyTimeout) { clearTimeout(emptyTimeout); this._cooldownsTimeout.delete(`empty_${oldState.guild.id}`); } } else { - if (!Util.isVoiceEmpty(queue.voiceConnection.channel)) return; + if (!Util.isVoiceEmpty(queue.voiceConnection.channel as VoiceChannel)) return; const timeout = setTimeout(() => { - if (!Util.isVoiceEmpty(queue.voiceConnection.channel)) return; + if (!Util.isVoiceEmpty(queue.voiceConnection.channel as VoiceChannel)) return; if (!this.queues.has(queue.guildID)) return; queue.voiceConnection.channel.leave(); this.queues.delete(queue.guildID); diff --git a/src/utils/Util.ts b/src/utils/Util.ts index c444c84..7826f5d 100644 --- a/src/utils/Util.ts +++ b/src/utils/Util.ts @@ -4,7 +4,7 @@ import YouTube from 'youtube-sr'; import { Track } from '../Structures/Track'; // @ts-ignore import { validateURL as SoundcloudValidateURL } from 'soundcloud-scraper'; -import { StageChannel, VoiceChannel } from 'discord.js'; +import { VoiceChannel } from 'discord.js'; const spotifySongRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:track\/|\?uri=spotify:track:)((\w|-){22})/; const spotifyPlaylistRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:playlist\/|\?uri=spotify:playlist:)((\w|-){22})/; @@ -190,10 +190,10 @@ export class Util { /** * Checks if the given voice channel is empty - * @param {DiscordVoiceChannel|DiscordStageChannel} channel The voice channel + * @param {DiscordVoiceChannel} channel The voice channel * @returns {Boolean} */ - static isVoiceEmpty(channel: VoiceChannel | StageChannel): boolean { + static isVoiceEmpty(channel: VoiceChannel): boolean { return channel.members.filter((member) => !member.user.bot).size === 0; } From d5e29d7cddc9da524e1761729445c1a8e4682b60 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 11:16:10 +0545 Subject: [PATCH 15/26] some update --- package.json | 1 + src/Player.ts | 4 ++-- yarn.lock | 5 +++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4d254d1..9648526 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "@discordjs/opus": "^0.5.0", "@types/node": "^14.14.41", "@types/ws": "^7.4.1", + "discord-api-types": "^0.18.1", "discord.js": "^12.5.3", "discord.js-docgen": "discordjs/docgen#ts-patch", "jsdoc-babel": "^0.5.0", diff --git a/src/Player.ts b/src/Player.ts index ad5730a..0676862 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -229,7 +229,7 @@ export class Player extends EventEmitter { pl: true }); - return data[0]; + if (data.length) return data[0]; }) ); @@ -238,7 +238,7 @@ export class Player extends EventEmitter { const pl = { ...playlist, tracks, - duration: tracks.reduce((a, c) => a + c.durationMS, 0), + duration: tracks?.reduce((a, c) => a + (c?.durationMS ?? 0), 0) ?? 0, thumbnail: playlist.images[0]?.url ?? tracks[0].thumbnail }; diff --git a/yarn.lock b/yarn.lock index cf8a6a4..936db89 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1785,6 +1785,11 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +discord-api-types@^0.18.1: + version "0.18.1" + resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.18.1.tgz#5d08ed1263236be9c21a22065d0e6b51f790f492" + integrity sha512-hNC38R9ZF4uaujaZQtQfm5CdQO58uhdkoHQAVvMfIL0LgOSZeW575W8H6upngQOuoxWd8tiRII3LLJm9zuQKYg== + discord-ytdl-core@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/discord-ytdl-core/-/discord-ytdl-core-5.0.3.tgz#a31560f0bede41d6fc969377083ae958deac2b72" From 5386bbc91427bc727986996d7e0215f1930c4c16 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 13:49:30 +0545 Subject: [PATCH 16/26] fix spotify track name --- src/Player.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index 0676862..8221bb6 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -209,18 +209,19 @@ export class Player extends EventEmitter { // tslint:disable-next-line:no-shadowed-variable const tracks = await Promise.all( playlist.tracks.items.map(async (item: any) => { + const sq = queryType === 'spotify_album' ? `${ this.options.disableArtistSearch ? item.artists[0].name : `${item.artists[0].name} - ` - }${item.name}` + }${item.name ?? item.track.name}` : `${ this.options.disableArtistSearch ? item.track.artists[0].name : `${item.track.artists[0].name} - ` - }${item.name}`; + }${item.name ?? item.track.name}`; const data = await Util.ytSearch(sq, { limit: 1, From 4d0fa222b29391a1823f476449f896ae288149a5 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 13:56:03 +0545 Subject: [PATCH 17/26] enums --- src/Player.ts | 3 +-- src/utils/Constants.ts | 54 +++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index 8221bb6..b23647c 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -209,14 +209,13 @@ export class Player extends EventEmitter { // tslint:disable-next-line:no-shadowed-variable const tracks = await Promise.all( playlist.tracks.items.map(async (item: any) => { - const sq = queryType === 'spotify_album' ? `${ this.options.disableArtistSearch ? item.artists[0].name : `${item.artists[0].name} - ` - }${item.name ?? item.track.name}` + }${item.name ?? item.track.name}` : `${ this.options.disableArtistSearch ? item.track.artists[0].name diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts index ef5eb1b..afa41d5 100644 --- a/src/utils/Constants.ts +++ b/src/utils/Constants.ts @@ -1,33 +1,33 @@ import { PlayerOptions as DP_OPTIONS } from '../types/types'; -export const PlayerEvents = { - BOT_DISCONNECT: 'botDisconnect', - CHANNEL_EMPTY: 'channelEmpty', - CONNECTION_CREATE: 'connectionCreate', - ERROR: 'error', - MUSIC_STOP: 'musicStop', - NO_RESULTS: 'noResults', - PLAYLIST_ADD: 'playlistAdd', - PLAYLIST_PARSE_END: 'playlistParseEnd', - PLAYLIST_PARSE_START: 'playlistParseStart', - QUEUE_CREATE: 'queueCreate', - QUEUE_END: 'queueEnd', - SEARCH_CANCEL: 'searchCancel', - SEARCH_INVALID_RESPONSE: 'searchInvalidResponse', - SEARCH_RESULTS: 'searchResults', - TRACK_ADD: 'trackAdd', - TRACK_START: 'trackStart' -}; +export enum PlayerEvents { + BOT_DISCONNECT = 'botDisconnect', + CHANNEL_EMPTY = 'channelEmpty', + CONNECTION_CREATE = 'connectionCreate', + ERROR = 'error', + MUSIC_STOP = 'musicStop', + NO_RESULTS = 'noResults', + PLAYLIST_ADD = 'playlistAdd', + PLAYLIST_PARSE_END = 'playlistParseEnd', + PLAYLIST_PARSE_START = 'playlistParseStart', + QUEUE_CREATE = 'queueCreate', + QUEUE_END = 'queueEnd', + SEARCH_CANCEL = 'searchCancel', + SEARCH_INVALID_RESPONSE = 'searchInvalidResponse', + SEARCH_RESULTS = 'searchResults', + TRACK_ADD = 'trackAdd', + TRACK_START = 'trackStart' +} -export const PlayerErrorEventCodes = { - LIVE_VIDEO: 'LiveVideo', - NOT_CONNECTED: 'NotConnected', - UNABLE_TO_JOIN: 'UnableToJoin', - NOT_PLAYING: 'NotPlaying', - PARSE_ERROR: 'ParseError', - VIDEO_UNAVAILABLE: 'VideoUnavailable', - MUSIC_STARTING: 'MusicStarting' -}; +export enum PlayerErrorEventCodes { + LIVE_VIDEO = 'LiveVideo', + NOT_CONNECTED = 'NotConnected', + UNABLE_TO_JOIN = 'UnableToJoin', + NOT_PLAYING = 'NotPlaying', + PARSE_ERROR = 'ParseError', + VIDEO_UNAVAILABLE = 'VideoUnavailable', + MUSIC_STARTING = 'MusicStarting' +} export const PlayerOptions: DP_OPTIONS = { leaveOnEnd: true, From de40d183a65f1453a14c5bb84359937c7486708c Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 14:28:23 +0545 Subject: [PATCH 18/26] fix spotify playlist list --- src/Player.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index b23647c..e43139e 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -207,7 +207,7 @@ export class Player extends EventEmitter { if (!playlist) return void this.emit(PlayerEvents.NO_RESULTS, message, query); // tslint:disable-next-line:no-shadowed-variable - const tracks = await Promise.all( + let tracks = await Promise.all( playlist.tracks.items.map(async (item: any) => { const sq = queryType === 'spotify_album' @@ -232,7 +232,8 @@ export class Player extends EventEmitter { if (data.length) return data[0]; }) ); - + + tracks = tracks.filter(f => !!f); if (!tracks.length) return void this.emit(PlayerEvents.NO_RESULTS, message, query); const pl = { From c2ff70955f0d9b74550a1bfd0d09a081d4308c74 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 14:54:35 +0545 Subject: [PATCH 19/26] stream time --- src/Structures/Queue.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Structures/Queue.ts b/src/Structures/Queue.ts index 1cee68b..0a173f2 100644 --- a/src/Structures/Queue.ts +++ b/src/Structures/Queue.ts @@ -156,7 +156,12 @@ export class Queue extends EventEmitter { * @type {Number} */ get currentStreamTime(): number { - return this.voiceConnection?.dispatcher?.streamTime + this.additionalStreamTime || 0; + const NC = this.filters.nightcore ? 1.25 : null; + const VW = this.filters.vaporwave ? 0.8 : null; + const streamTime = this.voiceConnection?.dispatcher?.streamTime + this.additionalStreamTime || 0; + + if (NC && VW) return streamTime * (NC + VW); + return NC ? streamTime * NC : VW ? (streamTime * VW) : streamTime; } /** From 9e187a4d2bc1c2e833bc1620ffbd304fa3aa4192 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 14:57:10 +0545 Subject: [PATCH 20/26] prettier --- src/Player.ts | 4 ++-- src/Structures/Queue.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index e43139e..c91d60d 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -232,8 +232,8 @@ export class Player extends EventEmitter { if (data.length) return data[0]; }) ); - - tracks = tracks.filter(f => !!f); + + tracks = tracks.filter((f) => !!f); if (!tracks.length) return void this.emit(PlayerEvents.NO_RESULTS, message, query); const pl = { diff --git a/src/Structures/Queue.ts b/src/Structures/Queue.ts index 0a173f2..a8fa7a5 100644 --- a/src/Structures/Queue.ts +++ b/src/Structures/Queue.ts @@ -161,7 +161,7 @@ export class Queue extends EventEmitter { const streamTime = this.voiceConnection?.dispatcher?.streamTime + this.additionalStreamTime || 0; if (NC && VW) return streamTime * (NC + VW); - return NC ? streamTime * NC : VW ? (streamTime * VW) : streamTime; + return NC ? streamTime * NC : VW ? streamTime * VW : streamTime; } /** From c6830f87c0a34ad220e5c76b28197879fcb81adb Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 15:38:24 +0545 Subject: [PATCH 21/26] fix: youtube playlists being undefined --- src/Player.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Player.ts b/src/Player.ts index c91d60d..44f44f2 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -290,6 +290,10 @@ export class Player extends EventEmitter { // @ts-ignore playlist.requestedBy = message.author; + Object.defineProperty(playlist, "tracks", { + get: () => playlist.videos ?? [] + }); + this.emit(PlayerEvents.PLAYLIST_PARSE_END, playlist, message); // @ts-ignore From 29b54029e6d4816f7dc6ab85c8b5e3bc1363f186 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 15:44:05 +0545 Subject: [PATCH 22/26] spotify playlists data --- src/Player.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Player.ts b/src/Player.ts index 44f44f2..1a8d84e 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -240,7 +240,8 @@ export class Player extends EventEmitter { ...playlist, tracks, duration: tracks?.reduce((a, c) => a + (c?.durationMS ?? 0), 0) ?? 0, - thumbnail: playlist.images[0]?.url ?? tracks[0].thumbnail + thumbnail: playlist.images[0]?.url ?? tracks[0].thumbnail, + title: playlist.title ?? playlist.name ?? "" }; this.emit(PlayerEvents.PLAYLIST_PARSE_END, pl, message); @@ -254,6 +255,7 @@ export class Player extends EventEmitter { (e) => void this.emit(PlayerEvents.ERROR, e, message) )) as Queue; this.emit(PlayerEvents.TRACK_START, message, queue.tracks[0], queue); + this.emit(PlayerEvents.PLAYLIST_ADD, message, queue, pl); this._addTracksToQueue(message, tracks); } From f27cf860384872a99f98e41a2c73a1308eafe54f Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 15:45:13 +0545 Subject: [PATCH 23/26] emit PlaylistAdd before TrackStart --- src/Player.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Player.ts b/src/Player.ts index 1a8d84e..be209e5 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -254,8 +254,8 @@ export class Player extends EventEmitter { const queue = (await this._createQueue(message, track).catch( (e) => void this.emit(PlayerEvents.ERROR, e, message) )) as Queue; - this.emit(PlayerEvents.TRACK_START, message, queue.tracks[0], queue); this.emit(PlayerEvents.PLAYLIST_ADD, message, queue, pl); + this.emit(PlayerEvents.TRACK_START, message, queue.tracks[0], queue); this._addTracksToQueue(message, tracks); } From 5602a4c360a2a6e8d566ba4540095df683aff315 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 15:47:05 +0545 Subject: [PATCH 24/26] prettier --- src/Player.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Player.ts b/src/Player.ts index be209e5..d10b4f0 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -241,7 +241,7 @@ export class Player extends EventEmitter { tracks, duration: tracks?.reduce((a, c) => a + (c?.durationMS ?? 0), 0) ?? 0, thumbnail: playlist.images[0]?.url ?? tracks[0].thumbnail, - title: playlist.title ?? playlist.name ?? "" + title: playlist.title ?? playlist.name ?? '' }; this.emit(PlayerEvents.PLAYLIST_PARSE_END, pl, message); @@ -292,7 +292,7 @@ export class Player extends EventEmitter { // @ts-ignore playlist.requestedBy = message.author; - Object.defineProperty(playlist, "tracks", { + Object.defineProperty(playlist, 'tracks', { get: () => playlist.videos ?? [] }); From dd325ffb3057ea10129726944857677f281e9306 Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 15:52:43 +0545 Subject: [PATCH 25/26] v4.0.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9648526..7dbd47d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "discord-player", - "version": "4.0.6", + "version": "4.0.7", "description": "Complete framework to facilitate music commands using discord.js", "main": "lib/index.js", "types": "lib/index.d.ts", From a8668e0b3f719176ad7ba3e841096a53c7bf077a Mon Sep 17 00:00:00 2001 From: Snowflake107 Date: Mon, 10 May 2021 16:07:52 +0545 Subject: [PATCH 26/26] remove useless dep --- package.json | 1 - yarn.lock | 5 ----- 2 files changed, 6 deletions(-) diff --git a/package.json b/package.json index 7dbd47d..8092060 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,6 @@ "@discordjs/opus": "^0.5.0", "@types/node": "^14.14.41", "@types/ws": "^7.4.1", - "discord-api-types": "^0.18.1", "discord.js": "^12.5.3", "discord.js-docgen": "discordjs/docgen#ts-patch", "jsdoc-babel": "^0.5.0", diff --git a/yarn.lock b/yarn.lock index 936db89..cf8a6a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1785,11 +1785,6 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -discord-api-types@^0.18.1: - version "0.18.1" - resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.18.1.tgz#5d08ed1263236be9c21a22065d0e6b51f790f492" - integrity sha512-hNC38R9ZF4uaujaZQtQfm5CdQO58uhdkoHQAVvMfIL0LgOSZeW575W8H6upngQOuoxWd8tiRII3LLJm9zuQKYg== - discord-ytdl-core@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/discord-ytdl-core/-/discord-ytdl-core-5.0.3.tgz#a31560f0bede41d6fc969377083ae958deac2b72"