commands/play.js (view raw)
1const path = require("node:path");
2const { SlashCommandBuilder } = require("discord.js");
3const {
4 createAudioResource,
5 createAudioPlayer,
6 joinVoiceChannel,
7 NoSubscriberBehavior,
8 AudioPlayerStatus,
9} = require("@discordjs/voice");
10
11const ytdl = require("ytdl-core");
12const ytsr = require("ytsr");
13
14async function reply_efemeral(interaction, reply) {
15 return await interaction.reply({ content: reply, ephemeral: true });
16}
17
18function get_player(resource) {
19 const player = createAudioPlayer({
20 behaviors: { noSubscriber: NoSubscriberBehavior.Pause },
21 });
22 player.on("error", (error) =>
23 console.error(
24 `Error: ${error.message} with resource ${error.resource.metadata.title}`
25 )
26 );
27 player.on(AudioPlayerStatus.Idle, () => {
28 player.stop();
29 player.subscribers.forEach((element) => element.connection.disconnect());
30 });
31
32 player.play(createAudioResource(resource));
33 return player;
34}
35
36module.exports = {
37 data: new SlashCommandBuilder()
38 .setName("play")
39 .setDescription("Play something off YouTube.")
40 .addStringOption((option) =>
41 option
42 .setName("query")
43 .setDescription("YouTube URL or search query")
44 .setRequired(true)
45 ),
46
47 async execute(interaction) {
48 const member = interaction.member;
49 if (!member)
50 return await reply_efemeral(
51 interaction,
52 "Please use this in your current server."
53 );
54
55 const user_connection = member.voice;
56 const channel = user_connection.channel;
57 if (!channel)
58 return await reply_efemeral(
59 interaction,
60 "You're not in a voice channel."
61 );
62
63 const guild = channel.guild;
64
65 // Get the YouTube URL or search query
66 const url = interaction.options.getString("query");
67
68 // If the URL is not a valid YouTube URL, treat it as a search query and try to get the first result
69
70 if (!ytdl.validateURL(url)) {
71 return await reply_efemeral(interaction, "This bot only supports URLs (for now).");
72 try {
73 const searchResults = await ytsr(url);
74 results = searchResults.items;
75
76 url = null
77 for(result in results){
78 if (result.type == "video"){
79 url = result.url;
80 console.log("Using", url)
81 break;
82 }
83 }
84 if(url == null) {
85 console.log("No results found");
86 throw new Error("No results found");
87 }
88 } catch (error) {
89 return await reply_efemeral(
90 interaction,
91 `Invalid YouTube URL or search query! ${error}`
92 );
93 }
94 }
95
96 const stream = ytdl(url, {
97 filter: "audioonly",
98 opusEncoded: true,
99 encoderArgs: ["-af", "bass=g=10,dynaudnorm=f=200"],
100 });
101
102 // Connect to the user's voice channel
103 const connection = joinVoiceChannel({
104 channelId: channel.id,
105 guildId: guild.id,
106 adapterCreator: guild.voiceAdapterCreator,
107 });
108
109 connection.subscribe(get_player(stream));
110 return await reply_efemeral(interaction, `Playing.`);
111 },
112};