diff --git a/src/Player.ts b/src/Player.ts index 910edb1..c5f7d28 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -7,6 +7,7 @@ import Track from "./Structures/Track"; import { QueryResolver } from "./utils/QueryResolver"; import YouTube from "youtube-sr"; import { Util } from "./utils/Util"; +import Spotify from "spotify-url-info"; // @ts-ignore import { Client as SoundCloud } from "soundcloud-scraper"; @@ -138,6 +139,27 @@ class DiscordPlayer extends EventEmitter { return res; } + case QueryType.SPOTIFY_SONG: { + const spotifyData = await Spotify.getData(query).catch(() => {}); + if (!spotifyData) return []; + const spotifyTrack = new Track(this, { + title: spotifyData.name, + description: spotifyData.description ?? "", + author: spotifyData.artists[0]?.name ?? "Unknown Artist", + url: spotifyData.external_urls?.spotify ?? query, + thumbnail: + spotifyData.album?.images[0]?.url ?? spotifyData.preview_url?.length + ? `https://i.scdn.co/image/${spotifyData.preview_url?.split("?cid=")[1]}` + : "https://www.scdn.co/i/_global/twitter_card-default.jpg", + duration: Util.buildTimeCode(Util.parseMS(spotifyData.duration_ms)), + views: 0, + requestedBy: options.requestedBy, + fromPlaylist: false, + source: "spotify" + }); + + return [spotifyTrack]; + } default: return []; } diff --git a/src/Structures/Queue.ts b/src/Structures/Queue.ts index e978785..d8d8be0 100644 --- a/src/Structures/Queue.ts +++ b/src/Structures/Queue.ts @@ -6,6 +6,7 @@ import { PlayerOptions, PlayOptions, QueueRepeatMode } from "../types/types"; import ytdl from "discord-ytdl-core"; import { AudioResource, StreamType } from "@discordjs/voice"; import { Util } from "../utils/Util"; +import YouTube from "youtube-sr"; class Queue { public readonly guild: Guild; @@ -119,7 +120,7 @@ class Queue { return await this.play(Util.last(this.previousTracks), { immediate: true }); } - async play(src?: Track, options: PlayOptions = {}) { + async play(src?: Track, options: PlayOptions = {}): Promise { if (!this.connection || !this.connection.voiceConnection) throw new Error("Voice connection is not available, use .connect()!"); if (src && (this.playing || this.tracks.length) && !options.immediate) return this.addTrack(src); const track = options.filtersUpdate ? this.current : src ?? this.tracks.shift(); @@ -128,7 +129,15 @@ class Queue { this.previousTracks.push(track); let stream; if (["youtube", "spotify"].includes(track.raw.source)) { - stream = ytdl(track.raw.source === "spotify" ? track.raw.engine : track.url, { + if (track.raw.source === "spotify" && !track.raw.engine) { + track.raw.engine = await YouTube.search(`${track.author} ${track.title}`, { type: "video" }) + .then((x) => x[0].url) + .catch(() => null); + } + const link = track.raw.source === "spotify" ? track.raw.engine : track.url; + if (!link) return void this.play(this.tracks.shift(), { immediate: true }); + + stream = ytdl(link, { // because we don't wanna decode opus into pcm again just for volume, let discord.js handle that opusEncoded: false, fmt: "s16le", @@ -136,13 +145,16 @@ class Queue { seek: options.seek }); } else { - stream = ytdl.arbitraryStream(track.raw.source === "soundcloud" ? await track.raw.engine.downloadProgressive() : (track.raw.engine as string), { - // because we don't wanna decode opus into pcm again just for volume, let discord.js handle that - opusEncoded: false, - fmt: "s16le", - encoderArgs: options.encoderArgs ?? [], - seek: options.seek - }); + stream = ytdl.arbitraryStream( + track.raw.source === "soundcloud" ? await track.raw.engine.downloadProgressive() : typeof track.raw.engine === "function" ? await track.raw.engine() : track.raw.engine, + { + // because we don't wanna decode opus into pcm again just for volume, let discord.js handle that + opusEncoded: false, + fmt: "s16le", + encoderArgs: options.encoderArgs ?? [], + seek: options.seek + } + ); } const resource: AudioResource = this.connection.createStream(stream, {