Skip to content

Commit

Permalink
✨ Create search commands
Browse files Browse the repository at this point in the history
  • Loading branch information
Nich87 committed Dec 8, 2023
1 parent a82ef47 commit f8291e9
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 2 deletions.
7 changes: 7 additions & 0 deletions src/Events/onInteractionCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { interactions } from '../interactions';
import { BaseInteraction, Awaitable, ChannelType, GuildMember } from 'discord.js';

export async function onInteractionCreate(interaction: BaseInteraction): Promise<Awaitable<void>> {
if (interaction.isStringSelectMenu()) {
interactions.searchplay(interaction);
return;
}
if (!interaction.isChatInputCommand()) return;
if (!interaction.guild) {
interaction.reply({ content: 'This command can only be used in a server!', ephemeral: true });
Expand Down Expand Up @@ -54,6 +58,9 @@ export async function onInteractionCreate(interaction: BaseInteraction): Promise
case 'nowplaying':
interactions.nowplaying(interaction);
break;
case 'search':
interactions.search(interaction);
break;
default:
interaction.reply(embeds.unknownCommand);
break;
Expand Down
3 changes: 3 additions & 0 deletions src/Events/onMessageCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ export async function onMessageCreate(message: Message): Promise<Awaitable<void>
case 'current':
commands.nowplaying(message);
break;
case 'search':
commands.search(message);
break;
default:
message.reply(embeds.unknownCommand);
break;
Expand Down
4 changes: 3 additions & 1 deletion src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { pauseCommand } from './pause';
import { playCommand } from './play';
import { queueCommand } from './queue';
import { resumeCommand } from './resume';
import { searchCommand } from './search';
import { skipCommand } from './skip';
import { stopCommand } from './stop';

Expand All @@ -19,5 +20,6 @@ export const commands = {
queue: queueCommand,
resume: resumeCommand,
skip: skipCommand,
stop: stopCommand
stop: stopCommand,
search: searchCommand
};
28 changes: 28 additions & 0 deletions src/commands/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { embeds } from '../embeds';
import { Message, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, ActionRowBuilder } from 'discord.js';
import ytsr from 'youtube-sr';

export async function searchCommand(message: Message) {
const videos = await ytsr.search(message.content.split(' ').slice(1).join(' '), {
type: 'video'
});

if (!videos.length) return message.reply(embeds.noResult);

const menu = new StringSelectMenuBuilder()
.setCustomId('search')
.setPlaceholder('Select a video')
.addOptions(
videos.map((video, index) =>
new StringSelectMenuOptionBuilder()
.setLabel(`${index + 1}. ${video.title}`)
.setValue(video.url)
.setDescription(String(video.durationFormatted))
.setEmoji('🎵')
)
);

const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(menu);

message.reply({ content: 'Select a video', components: [row] });
}
4 changes: 4 additions & 0 deletions src/deploy-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ const commands = [
.setName('play')
.setDescription('Play a song')
.addStringOption((option) => option.setName('url').setDescription('The song to play').setRequired(true)),
new SlashCommandBuilder()
.setName('search')
.setDescription('Search for a song')
.addStringOption((option) => option.setName('query').setDescription('Enter search words').setRequired(true)),
new SlashCommandBuilder().setName('pause').setDescription('Pause the current song'),
new SlashCommandBuilder().setName('resume').setDescription('Resume the current song'),
new SlashCommandBuilder().setName('skip').setDescription('Skip the current song'),
Expand Down
4 changes: 4 additions & 0 deletions src/embeds/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export const embeds = {
.addFields({ name: 'Error', value: '有効なURLを指定してください。' })
.setColor('Red')
.build(),
noResult: new Builder()
.addFields({ name: 'Error', value: '検索結果が見つかりませんでした。' })
.setColor('Red')
.build(),
voiceChannnelPermission: new Builder()
.addFields({ name: 'Error', value: 'ボイスチャンネルに参加する権限がありません。' })
.setColor('Red')
Expand Down
68 changes: 68 additions & 0 deletions src/interactions/handleplay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { YTPlayer } from '../classes/player';
import { Queue, queueManager } from '../classes/queue';
import { embeds } from '../embeds';
import { client } from '../index';
import { StringSelectMenuInteraction, ChannelType, VoiceBasedChannel, GuildMember } from 'discord.js';
import ytdl from 'ytdl-core';

let url: string;

export async function searchPlayCommand(interaction: StringSelectMenuInteraction) {
let player = client?.player;
if (!queueManager.getQueue(interaction.guild?.id as string)) {
queueManager.setQueue(interaction.guild?.id as string, new Queue());
}
const queue = queueManager.getQueue(interaction.guild?.id as string) as Queue;
if (!interaction.channel) return;
if (!(interaction.member instanceof GuildMember)) return;
if (!player) {
client.player = new YTPlayer(
interaction.guild?.id as string,
interaction.member?.voice.channel as VoiceBasedChannel,
interaction.channel?.id
);
player = client.player;
}

url = interaction.values[0];
const channel = interaction.member?.voice.channel;
if (!url) return interaction.reply(embeds.noUrl);
if (!ytdl.validateURL(url)) return interaction.reply(embeds.invaildUrl);
if (!channel) return interaction.reply(embeds.voiceChannelJoin);
if (channel.type !== ChannelType.GuildVoice) return;
if (!channel.joinable) return interaction.reply(embeds.voiceChannnelJoined);
if (!channel.speakable) return interaction.reply(embeds.voiceChannnelPermission);

if (!queue.length || !player.isPlaying) {
queue.addSong(url);
const info = await ytdl.getInfo(url);
interaction.reply(
new embeds.embed()
.setTitle('Success')
.setDescription(`**[${info.videoDetails.title}](${info.videoDetails.video_url})を再生します。**`)
.addFields({
name: info.videoDetails.title,
value: `投稿者: [${info.videoDetails.author.name}](${info.videoDetails.author.channel_url})`
})
.setImage(info.videoDetails.thumbnails[0].url.split('?')[0])
.setColor('Green')
.build()
);
if (queue.length === 1) return player.play();
} else {
queue.addSong(url);
const info = await ytdl.getInfo(url);
interaction.reply(
new embeds.embed()
.setTitle('Info')
.setDescription(`**[${info.videoDetails.title}](${info.videoDetails.video_url})をキューに追加しました。**`)
.addFields({
name: info.videoDetails.title,
value: `投稿者: [${info.videoDetails.author.name}](${info.videoDetails.author.channel_url})`
})
.setImage(info.videoDetails.thumbnails[0].url.split('?')[0])
.setColor('Yellow')
.build()
);
}
}
6 changes: 5 additions & 1 deletion src/interactions/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { changeVolumeCommand } from './changeVolume';
import { searchPlayCommand } from './handleplay';
import { helpCommand } from './help';
import { loopCommand } from './loop';
import { nowplayingCommand } from './nowplaying';
import { pauseCommand } from './pause';
import { playCommand } from './play';
import { queueCommand } from './queue';
import { resumeCommand } from './resume';
import { searchCommand } from './search';
import { skipCommand } from './skip';
import { stopCommand } from './stop';

Expand All @@ -19,5 +21,7 @@ export const interactions = {
queue: queueCommand,
resume: resumeCommand,
skip: skipCommand,
stop: stopCommand
stop: stopCommand,
search: searchCommand,
searchplay: searchPlayCommand
};
34 changes: 34 additions & 0 deletions src/interactions/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { embeds } from '../embeds';
import {
ChatInputCommandInteraction,
StringSelectMenuBuilder,
StringSelectMenuOptionBuilder,
ActionRowBuilder
} from 'discord.js';
import ytsr from 'youtube-sr';

export async function searchCommand(interaction: ChatInputCommandInteraction) {
interaction.deferReply();
const videos = await ytsr.search(interaction.options.getString('query') as string, {
type: 'video'
});

if (!videos.length) return interaction.followUp(embeds.noResult);

const menu = new StringSelectMenuBuilder()
.setCustomId('search')
.setPlaceholder('Select a video')
.addOptions(
videos.map((video, index) =>
new StringSelectMenuOptionBuilder()
.setLabel(`${index + 1}. ${video.title}`)
.setValue(video.url)
.setDescription(String(video.durationFormatted))
.setEmoji('🎵')
)
);

const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(menu);

interaction.followUp({ content: 'Select a video', components: [row] });
}

0 comments on commit f8291e9

Please sign in to comment.