|
@@ -0,0 +1,343 @@
|
|
|
|
|
+const { MessageEmbed, Message } = require("discord.js");
|
|
|
|
|
+const { TrackUtils } = require("erela.js");
|
|
|
|
|
+const _ = require("lodash");
|
|
|
|
|
+const prettyMilliseconds = require("pretty-ms");
|
|
|
|
|
+
|
|
|
|
|
+module.exports = {
|
|
|
|
|
+ name: "search",
|
|
|
|
|
+ description: "Search a song/playlist",
|
|
|
|
|
+ usage: "[Song Name|SongURL]",
|
|
|
|
|
+ permissions: {
|
|
|
|
|
+ channel: ["VIEW_CHANNEL", "SEND_MESSAGES", "EMBED_LINKS"],
|
|
|
|
|
+ member: [],
|
|
|
|
|
+ },
|
|
|
|
|
+ aliases: ["se"],
|
|
|
|
|
+ /**
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param {import("../structures/DiscordMusicBot")} client
|
|
|
|
|
+ * @param {import("discord.js").Message} message
|
|
|
|
|
+ * @param {string[]} args
|
|
|
|
|
+ * @param {*} param3
|
|
|
|
|
+ */
|
|
|
|
|
+ run: async (client, message, args, { GuildDB }) => {
|
|
|
|
|
+ if (!message.member.voice.channel)
|
|
|
|
|
+ return client.sendTime(
|
|
|
|
|
+ message.channel,
|
|
|
|
|
+ "❌ | **You must be in a voice channel to play something!**"
|
|
|
|
|
+ );
|
|
|
|
|
+ //else if(message.guild.me.voice && message.guild.me.voice.channel.id !== message.member.voice.channel.id)return client.sendTime(message.channel, "❌ | **You must be in same voice channel as the bot is in to play something!**");
|
|
|
|
|
+
|
|
|
|
|
+ let SearchString = args.join(" ");
|
|
|
|
|
+ if (!SearchString)
|
|
|
|
|
+ return client.sendTime(
|
|
|
|
|
+ message.channel,
|
|
|
|
|
+ `**Usage - **\`${GuildDB.prefix}search [Song Name|SongURL]\``
|
|
|
|
|
+ );
|
|
|
|
|
+ let CheckNode = client.Manager.nodes.get(client.config.Lavalink.id);
|
|
|
|
|
+ if (!CheckNode || !CheckNode.connected) {
|
|
|
|
|
+ return client.sendTime(
|
|
|
|
|
+ message.channel,
|
|
|
|
|
+ "❌ | Lavalink node not connected."
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ const player = client.Manager.create({
|
|
|
|
|
+ guild: message.guild.id,
|
|
|
|
|
+ voiceChannel: message.member.voice.channel.id,
|
|
|
|
|
+ textChannel: message.channel.id,
|
|
|
|
|
+ selfDeafen: false,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (player.state != "CONNECTED") await player.connect();
|
|
|
|
|
+
|
|
|
|
|
+ let Searched = await player.search(SearchString, message.author);
|
|
|
|
|
+ if (Searched.loadType == "NO_MATCHES")
|
|
|
|
|
+ return client.sendTime(
|
|
|
|
|
+ message.channel,
|
|
|
|
|
+ "No matches found for " + SearchString
|
|
|
|
|
+ );
|
|
|
|
|
+ else {
|
|
|
|
|
+ Searched.tracks = Searched.tracks.map((s, i) => {
|
|
|
|
|
+ s.index = i;
|
|
|
|
|
+ return s;
|
|
|
|
|
+ });
|
|
|
|
|
+ let songs = _.chunk(Searched.tracks, 10);
|
|
|
|
|
+ let Pages = songs.map((songz) => {
|
|
|
|
|
+ let MappedSongs = songz.map(
|
|
|
|
|
+ (s) =>
|
|
|
|
|
+ `\`${s.index + 1}.\` [${s.title}](${
|
|
|
|
|
+ s.uri
|
|
|
|
|
+ }) \nDuration: \`${prettyMilliseconds(s.duration, {
|
|
|
|
|
+ colonNotation: true,
|
|
|
|
|
+ })}\``
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ let em = new MessageEmbed()
|
|
|
|
|
+ .setAuthor("Search Results of " + SearchString, client.config.IconURL)
|
|
|
|
|
+ .setColor("RANDOM")
|
|
|
|
|
+ .setDescription(MappedSongs.join("\n\n"));
|
|
|
|
|
+ return em;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (!Pages.length || Pages.length === 1)
|
|
|
|
|
+ return message.channel.send(Pages[0]);
|
|
|
|
|
+ else client.Pagination(message, Pages);
|
|
|
|
|
+
|
|
|
|
|
+ let w = (a) => new Promise((r) => setInterval(r, a));
|
|
|
|
|
+ await w(500); //waits 500ms cuz needed to wait for the above song search embed to send ._.
|
|
|
|
|
+ let msg = await message.channel.send(
|
|
|
|
|
+ "**Type the number of the song you want to play! Expires in `30 seconds`.**"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ let er = false;
|
|
|
|
|
+ let SongID = await message.channel
|
|
|
|
|
+ .awaitMessages((msg) => message.author.id === msg.author.id, {
|
|
|
|
|
+ max: 1,
|
|
|
|
|
+ errors: ["time"],
|
|
|
|
|
+ time: 30000,
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ er = true;
|
|
|
|
|
+ msg.edit(
|
|
|
|
|
+ "**You took too long to respond. Run the command again if you want to play something!**"
|
|
|
|
|
+ );
|
|
|
|
|
+ });
|
|
|
|
|
+ if (er) return;
|
|
|
|
|
+ /**@type {Message} */
|
|
|
|
|
+ let SongIDmsg = SongID.first();
|
|
|
|
|
+
|
|
|
|
|
+ if (!parseInt(SongIDmsg.content))
|
|
|
|
|
+ return client.sendTime("Please send correct song ID number");
|
|
|
|
|
+ let Song = Searched.tracks[parseInt(SongIDmsg.content) - 1];
|
|
|
|
|
+ if (!Song) return message.channel.send("No song found for the given ID");
|
|
|
|
|
+ player.queue.add(Song);
|
|
|
|
|
+ if (!player.playing && !player.paused && !player.queue.size)
|
|
|
|
|
+ player.play();
|
|
|
|
|
+ let SongAddedEmbed = new MessageEmbed();
|
|
|
|
|
+ SongAddedEmbed.setAuthor(`Added to queue`, client.config.IconURL);
|
|
|
|
|
+ SongAddedEmbed.setThumbnail(Song.displayThumbnail());
|
|
|
|
|
+ SongAddedEmbed.setColor("RANDOM");
|
|
|
|
|
+ SongAddedEmbed.setDescription(`[${Song.title}](${Song.uri})`);
|
|
|
|
|
+ SongAddedEmbed.addField("Author", `${Song.author}`, true);
|
|
|
|
|
+ SongAddedEmbed.addField(
|
|
|
|
|
+ "Duration",
|
|
|
|
|
+ `\`${prettyMilliseconds(player.queue.current.duration, {
|
|
|
|
|
+ colonNotation: true,
|
|
|
|
|
+ })}\``,
|
|
|
|
|
+ true
|
|
|
|
|
+ );
|
|
|
|
|
+ if (player.queue.totalSize > 1)
|
|
|
|
|
+ SongAddedEmbed.addField(
|
|
|
|
|
+ "Position in queue",
|
|
|
|
|
+ `${player.queue.size - 0}`,
|
|
|
|
|
+ true
|
|
|
|
|
+ );
|
|
|
|
|
+ message.channel.send(SongAddedEmbed);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ SlashCommand: {
|
|
|
|
|
+ options: [
|
|
|
|
|
+ {
|
|
|
|
|
+ name: "song",
|
|
|
|
|
+ value: "song",
|
|
|
|
|
+ type: 3,
|
|
|
|
|
+ required: true,
|
|
|
|
|
+ description: "Search a song/playlist",
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ /**
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param {import("../structures/DiscordMusicBot")} client
|
|
|
|
|
+ * @param {import("discord.js").Message} message
|
|
|
|
|
+ * @param {string[]} args
|
|
|
|
|
+ * @param {*} param3
|
|
|
|
|
+ */
|
|
|
|
|
+ run: async (client, interaction, args, { GuildDB }) => {
|
|
|
|
|
+ const guild = client.guilds.cache.get(interaction.guild_id);
|
|
|
|
|
+ const member = guild.members.cache.get(interaction.member.user.id);
|
|
|
|
|
+ const voiceChannel = member.voice.channel;
|
|
|
|
|
+ let awaitchannel = client.channels.cache.get(interaction.channel_id); /// thanks Reyansh for this idea ;-;
|
|
|
|
|
+ if (!member.voice.channel)
|
|
|
|
|
+ return client.sendTime(
|
|
|
|
|
+ interaction,
|
|
|
|
|
+ "❌ | **You must be in a voice channel to use this command.**"
|
|
|
|
|
+ );
|
|
|
|
|
+ if (
|
|
|
|
|
+ guild.me.voice.channel &&
|
|
|
|
|
+ !guild.me.voice.channel.equals(member.voice.channel)
|
|
|
|
|
+ )
|
|
|
|
|
+ return client.sendTime(
|
|
|
|
|
+ interaction,
|
|
|
|
|
+ `❌ | **You must be in ${guild.me.voice.channel} to use this command.**`
|
|
|
|
|
+ );
|
|
|
|
|
+ let CheckNode = client.Manager.nodes.get(client.config.Lavalink.id);
|
|
|
|
|
+ if (!CheckNode || !CheckNode.connected) {
|
|
|
|
|
+ return client.sendTime(
|
|
|
|
|
+ interaction,
|
|
|
|
|
+ "❌ | Lavalink node not connected."
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ let player = client.Manager.create({
|
|
|
|
|
+ guild: interaction.guild_id,
|
|
|
|
|
+ voiceChannel: voiceChannel.id,
|
|
|
|
|
+ textChannel: interaction.channel_id,
|
|
|
|
|
+ selfDeafen: false,
|
|
|
|
|
+ });
|
|
|
|
|
+ if (player.state != "CONNECTED") await player.connect();
|
|
|
|
|
+ let search = interaction.data.options[0].value;
|
|
|
|
|
+ let res;
|
|
|
|
|
+
|
|
|
|
|
+ if (search.match(client.Lavasfy.spotifyPattern)) {
|
|
|
|
|
+ await client.Lavasfy.requestToken();
|
|
|
|
|
+ let node = client.Lavasfy.nodes.get(client.config.Lavalink.id);
|
|
|
|
|
+ let Searched = await node.load(search);
|
|
|
|
|
+
|
|
|
|
|
+ switch (Searched.loadType) {
|
|
|
|
|
+ case "LOAD_FAILED":
|
|
|
|
|
+ if (!player.queue.current) player.destroy();
|
|
|
|
|
+ return interaction.send(`There was an error while searching`);
|
|
|
|
|
+
|
|
|
|
|
+ case "NO_MATCHES":
|
|
|
|
|
+ if (!player.queue.current) player.destroy();
|
|
|
|
|
+ return interaction.send("No results were found.");
|
|
|
|
|
+ case "TRACK_LOADED":
|
|
|
|
|
+ player.queue.add(TrackUtils.build(Searched.tracks[0], member.user));
|
|
|
|
|
+ if (!player.playing && !player.paused && !player.queue.length)
|
|
|
|
|
+ player.play();
|
|
|
|
|
+ return interaction.send(
|
|
|
|
|
+ `**Added to queue:** \`[${Searched.tracks[0].info.title}](${Searched.tracks[0].info.uri}}\`.`
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ case "PLAYLIST_LOADED":
|
|
|
|
|
+ let songs = [];
|
|
|
|
|
+ for (let i = 0; i < Searched.tracks.length; i++)
|
|
|
|
|
+ songs.push(TrackUtils.build(Searched.tracks[i], member.user));
|
|
|
|
|
+ player.queue.add(songs);
|
|
|
|
|
+
|
|
|
|
|
+ if (
|
|
|
|
|
+ !player.playing &&
|
|
|
|
|
+ !player.paused &&
|
|
|
|
|
+ player.queue.totalSize === Searched.tracks.length
|
|
|
|
|
+ )
|
|
|
|
|
+ player.play();
|
|
|
|
|
+ return interaction.send(
|
|
|
|
|
+ `**Playlist added to queue**: \n**${Searched.playlist.name}** \nEnqueued: **${Searched.playlistInfo.length} songs**`
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ try {
|
|
|
|
|
+ res = await player.search(search, member.user);
|
|
|
|
|
+ if (res.loadType === "LOAD_FAILED") {
|
|
|
|
|
+ if (!player.queue.current) player.destroy();
|
|
|
|
|
+ throw new Error(res.exception.message);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ return interaction.send(
|
|
|
|
|
+ `There was an error while searching: ${err.message}`
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ switch (res.loadType) {
|
|
|
|
|
+ case "NO_MATCHES":
|
|
|
|
|
+ if (!player.queue.current) player.destroy();
|
|
|
|
|
+ return interaction.send("No results were found.");
|
|
|
|
|
+ case "TRACK_LOADED":
|
|
|
|
|
+ player.queue.add(res.tracks[0]);
|
|
|
|
|
+ if (!player.playing && !player.paused && !player.queue.length)
|
|
|
|
|
+ player.play();
|
|
|
|
|
+ return interaction.send(
|
|
|
|
|
+ `**Added to queue:** \`[${res.tracks[0].title}](${res.tracks[0].uri})\`.`
|
|
|
|
|
+ );
|
|
|
|
|
+ case "PLAYLIST_LOADED":
|
|
|
|
|
+ player.queue.add(res.tracks);
|
|
|
|
|
+
|
|
|
|
|
+ if (
|
|
|
|
|
+ !player.playing &&
|
|
|
|
|
+ !player.paused &&
|
|
|
|
|
+ player.queue.size === res.tracks.length
|
|
|
|
|
+ )
|
|
|
|
|
+ player.play();
|
|
|
|
|
+ return interaction.send(
|
|
|
|
|
+ `**Playlist added to queue**: \n**${res.playlist.name}** \nEnqueued: **${res.playlistInfo.length} songs**`
|
|
|
|
|
+ );
|
|
|
|
|
+ case "SEARCH_RESULT":
|
|
|
|
|
+ let max = 10,
|
|
|
|
|
+ collected,
|
|
|
|
|
+ filter = (m) =>
|
|
|
|
|
+ m.author.id === interaction.member.user.id &&
|
|
|
|
|
+ /^(\d+|end)$/i.test(m.content);
|
|
|
|
|
+ if (res.tracks.length < max) max = res.tracks.length;
|
|
|
|
|
+
|
|
|
|
|
+ const results = res.tracks
|
|
|
|
|
+ .slice(0, max)
|
|
|
|
|
+ .map(
|
|
|
|
|
+ (track, index) =>
|
|
|
|
|
+ `\`${++index}\` - [${track.title}](${
|
|
|
|
|
+ track.uri
|
|
|
|
|
+ }) \n\t\`${prettyMilliseconds(track.duration, {
|
|
|
|
|
+ colonNotation: true,
|
|
|
|
|
+ })}\`\n`
|
|
|
|
|
+ )
|
|
|
|
|
+ .join("\n");
|
|
|
|
|
+
|
|
|
|
|
+ const resultss = new MessageEmbed()
|
|
|
|
|
+ .setDescription(
|
|
|
|
|
+ `${results}\n\n\t**Type the number of the song you want to play!**\n`
|
|
|
|
|
+ )
|
|
|
|
|
+ .setColor("RANDOM")
|
|
|
|
|
+ .setAuthor(`Search results for ${search}`, client.config.IconURL);
|
|
|
|
|
+ interaction.send(resultss);
|
|
|
|
|
+ try {
|
|
|
|
|
+ collected = await awaitchannel.awaitMessages(filter, {
|
|
|
|
|
+ max: 1,
|
|
|
|
|
+ time: 30e3,
|
|
|
|
|
+ errors: ["time"],
|
|
|
|
|
+ });
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ if (!player.queue.current) player.destroy();
|
|
|
|
|
+ return awaitchannel.send(
|
|
|
|
|
+ "❌ | **You didn't provide a selection**"
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const first = collected.first().content;
|
|
|
|
|
+
|
|
|
|
|
+ if (first.toLowerCase() === "cancel") {
|
|
|
|
|
+ if (!player.queue.current) player.destroy();
|
|
|
|
|
+ return awaitchannel.send("Cancelled search.");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const index = Number(first) - 1;
|
|
|
|
|
+ if (index < 0 || index > max - 1)
|
|
|
|
|
+ return awaitchannel.send(
|
|
|
|
|
+ `The number you provided was greater or less than the search total. Usage - \`(1-${max})\``
|
|
|
|
|
+ );
|
|
|
|
|
+ const track = res.tracks[index];
|
|
|
|
|
+ player.queue.add(track);
|
|
|
|
|
+
|
|
|
|
|
+ if (!player.playing && !player.paused && !player.queue.length) {
|
|
|
|
|
+ player.play();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ let SongAddedEmbed = new MessageEmbed();
|
|
|
|
|
+ SongAddedEmbed.setAuthor(`Added to queue`, client.config.IconURL);
|
|
|
|
|
+ SongAddedEmbed.setThumbnail(track.displayThumbnail());
|
|
|
|
|
+ SongAddedEmbed.setColor("RANDOM");
|
|
|
|
|
+ SongAddedEmbed.addField(
|
|
|
|
|
+ "Song",
|
|
|
|
|
+ `[${track.title}](${track.uri})`,
|
|
|
|
|
+ true
|
|
|
|
|
+ );
|
|
|
|
|
+ SongAddedEmbed.addField("Author", track.author, true);
|
|
|
|
|
+ SongAddedEmbed.addField(
|
|
|
|
|
+ "Duration",
|
|
|
|
|
+ `\`${prettyMilliseconds(track.duration, {
|
|
|
|
|
+ colonNotation: true,
|
|
|
|
|
+ })}\``,
|
|
|
|
|
+ true
|
|
|
|
|
+ );
|
|
|
|
|
+ awaitchannel.send(SongAddedEmbed);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+};
|