diff --git a/package-lock.json b/package-lock.json index 031c8d5..4b0b0f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "olebeh-music-player", - "version": "1.0.5", + "version": "1.0.6", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 5497faa..2108e75 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "olebeh-music-player", - "version": "1.0.5", + "version": "1.0.6", "description": "🎵 A high quality Discord Music Player that supports YouTube, Spotify and local files (for now)", "main": "./dist/index.js", "types": "./typings/index.d.ts", diff --git a/src/Player.ts b/src/Player.ts index ee9ecc9..e9f09d3 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -20,6 +20,7 @@ export class Player extends TypedEmitter { geniusAPIToken?: string readonly voiceUtils = new VoiceUtils() readonly client: Discord.Client + private _spotifyToken = false private _idleCooldowns: { [guildId: string]: NodeJS.Timer } = {} private _emptyCooldowns: { [guildId: string]: NodeJS.Timer } = {} @@ -28,7 +29,9 @@ export class Player extends TypedEmitter { this.geniusAPIToken = options?.geniusAPIToken this.client = client + if (options?.authorization) playdl.setToken(options?.authorization) + if (options?.authorization?.spotify) this._spotifyToken = true this._playerHandler() } @@ -234,7 +237,7 @@ export class Player extends TypedEmitter { let source = validation ? validation.split('_')[0] : undefined let type = validation ? validation.split('_')[1] : undefined - const YouTubeSearchResult = async (video?: YouTubeVideo, playList?: YouTubePlayList) => { + const YouTubeSearchResult = async (videos?: YouTubeVideo[], playList?: YouTubePlayList) => { const ytToTrack = (video: YouTubeVideo) => { return new Track(this, { title: video.title ?? `Unnamed track`, @@ -273,8 +276,10 @@ export class Player extends TypedEmitter { }) playlist.tracks = tracks - } else if (video) { - tracks.push(ytToTrack(video)) + } else if (videos) { + videos.slice(0, limit).forEach(video => { + tracks.push(ytToTrack(video)) + }) } return { @@ -338,13 +343,17 @@ export class Player extends TypedEmitter { if (type === `video`) { const tracks = await playdl.video_info(query) - return await YouTubeSearchResult(tracks.video_details) + return await YouTubeSearchResult([tracks.video_details]) } else if (type === `playlist`) { const playlist = await playdl.playlist_info(query) return await YouTubeSearchResult(undefined, playlist) } } else if (source === `sp`) { + if (playdl.is_expired() && this._spotifyToken) { + await playdl.refreshToken() + } + if (type === `track`) { const tracks = await playdl.spotify(query) as SpotifyTrack @@ -382,8 +391,8 @@ export class Player extends TypedEmitter { } as SearchResult } - const videos = await playdl.search(query, { source: { youtube: 'video' } }) + const videos = await playdl.search(query, { source: { youtube: 'video' }, limit }) - return await YouTubeSearchResult(videos[0]) + return await YouTubeSearchResult(videos) } } \ No newline at end of file diff --git a/src/declarations/index.ts b/src/declarations/index.ts index 6d5ed96..55f6ba4 100644 --- a/src/declarations/index.ts +++ b/src/declarations/index.ts @@ -70,7 +70,7 @@ export interface PlayerEvents { } export interface PlayerOptions { - authorization: { + authorization?: { spotify?: { client_id: string client_secret: string diff --git a/src/utils/StreamDispatcher.ts b/src/utils/StreamDispatcher.ts index f4cddd9..15600a9 100644 --- a/src/utils/StreamDispatcher.ts +++ b/src/utils/StreamDispatcher.ts @@ -68,15 +68,15 @@ export class StreamDispatcher extends EventEmitter { this.voiceConnection.on(`stateChange`, async (_, newState) => { if (newState.status === VoiceConnectionStatus.Disconnected) { if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) { - try { - await entersState(this.voiceConnection, VoiceConnectionStatus.Connecting, this.connectionTimeout) - } catch { - try { - if (this.voiceConnection.state.status !== VoiceConnectionStatus.Destroyed) this.voiceConnection.destroy(); - } catch (err) { - this.emit(`error`, err as AudioPlayerError); + await entersState(this.voiceConnection, VoiceConnectionStatus.Connecting, this.connectionTimeout).catch(() => { + if (this.voiceConnection.state.status !== VoiceConnectionStatus.Destroyed) { + try { + this.voiceConnection.destroy() + } catch (err) { + this.emit(`error`, err as AudioPlayerError) + } } - } + }) } else if (this.voiceConnection.rejoinAttempts < 5) { await new Promise((r) => setTimeout(r, (this.voiceConnection.rejoinAttempts + 1) * 5000).unref()); this.voiceConnection.rejoin(); @@ -87,13 +87,9 @@ export class StreamDispatcher extends EventEmitter { this.emit(`error`, err as AudioPlayerError); } } - } else if (newState.status === VoiceConnectionStatus.Destroyed) { - } else if (!this.readyLock && (newState.status === VoiceConnectionStatus.Connecting || newState.status === VoiceConnectionStatus.Signalling)) { this.readyLock = true; - try { - await entersState(this.voiceConnection, VoiceConnectionStatus.Ready, this.connectionTimeout) - } catch { + await entersState(this.voiceConnection, VoiceConnectionStatus.Ready, this.connectionTimeout).catch(() => { if (this.voiceConnection.state.status !== VoiceConnectionStatus.Destroyed) { try { this.voiceConnection.destroy(); @@ -101,9 +97,8 @@ export class StreamDispatcher extends EventEmitter { this.emit(`error`, err as AudioPlayerError); } } - } finally { - this.readyLock = false; - } + }) + this.readyLock = false; } });