Skip to content

Commit

Permalink
Merge pull request #14 from MotiCAT/dev
Browse files Browse the repository at this point in the history
おめでとうございます!あなたは検索コマンドと細かいバグ修正を受け取りました!
  • Loading branch information
MotiCAT authored Dec 8, 2023
2 parents 87b5bc5 + 58d217e commit 7e4ae65
Show file tree
Hide file tree
Showing 33 changed files with 201 additions and 49 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"dotenv": "^16.3.1",
"ffmpeg-static": "^5.2.0",
"tweetnacl": "^1.0.3",
"youtube-sr": "^4.3.10",
"ytdl-core": "^4.11.5"
},
"repository": {
Expand Down
8 changes: 8 additions & 0 deletions src/Events/onInteractionCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ 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 });
return;
}
const commandName = interaction.commandName;
if (commandName === 'help') return interactions.help(interaction);
Expand Down Expand Up @@ -53,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
8 changes: 7 additions & 1 deletion src/Events/onMessageCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ export async function onMessageCreate(message: Message): Promise<Awaitable<void>
if (message.author.bot || !message.content.startsWith(prefix) || !message.guild) return;
const args = message.content.slice(prefix.length).trim().split(/ +/) as string[];
const commandName = args.shift()?.toLowerCase();
if (commandName === 'help' || commandName === 'h') return commands.help(message);
if (commandName === 'help' || commandName === 'h') {
commands.help(message);
return;
}
const channel = message.member?.voice.channel;
if (!channel) {
message.reply(embeds.voiceChannelJoin);
Expand Down Expand Up @@ -66,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
6 changes: 4 additions & 2 deletions src/classes/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class YTPlayer {
});
this.player = createAudioPlayer();
this.queue = queueManager.getQueue(serverId) as Queue;
this.volume = 100 / 10;
this.volume = 0.1;
this.player
.on('subscribe', () => {
this.isPlaying = true;
Expand All @@ -52,7 +52,7 @@ export class YTPlayer {
inputType: StreamType.WebmOpus,
inlineVolume: true
});
this.resource.volume?.setVolume(0.1);
this.resource.volume?.setVolume(this.volume);
this.connection.subscribe(this.player);
this.player.play(this.resource);
}
Expand All @@ -68,6 +68,7 @@ export class YTPlayer {
public stop(): void {
this.connection.destroy();
queueManager.deleteQueue(this.serverId);
client.player = undefined;
}

public skip(): void {
Expand All @@ -76,6 +77,7 @@ export class YTPlayer {

public changeVolume(volume: number): void {
if (!this.resource) return;
this.volume = volume;
this.resource.volume?.setVolume(volume / 10);
}

Expand Down
8 changes: 2 additions & 6 deletions src/commands/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@ import ytdl from 'ytdl-core';

export async function debugCommand(message: Message) {
const url = message.content.split(' ')[1];
if (!url) {
return message.reply(embeds.noUrl);
}
if (!ytdl.validateURL(url)) {
return message.reply(embeds.invaildUrl);
}
if (!url) return message.reply(embeds.noUrl);
if (!ytdl.validateURL(url)) return message.reply(embeds.invaildUrl);
const info = await ytdl.getInfo(url);
console.table(songResolver(info));
}
4 changes: 2 additions & 2 deletions src/commands/help.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { embeds } from '../embeds';
import { Message } from 'discord.js';

export async function helpCommand(message: Message): Promise<void> {
message.reply(embeds.help);
export async function helpCommand(message: Message) {
return message.reply(embeds.help);
}
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
};
2 changes: 1 addition & 1 deletion src/commands/loop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Message } from 'discord.js';

export async function loopCommand(message: Message, args: string[]) {
const player = client?.player;
if (typeof player === 'undefined') return message.reply(embeds.videoNotPlaying);
if (!player) return message.reply(embeds.videoNotPlaying);
const queue = queueManager.queues.get(message.guildId!) as Queue;
args = args.filter((arg) => arg !== '');
if (args.length === 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/commands/nowplaying.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Message } from 'discord.js';

export async function nowplayingCommand(message: Message) {
const player = client?.player;
if (typeof player === 'undefined') return message.reply(embeds.videoNotPlaying);
if (!player) return message.reply(embeds.videoNotPlaying);
const queue = queueManager.getQueue(message.guild?.id as string) as Queue;
const info = await getSongInfo(queue.currentSong);
return message.reply(info);
Expand Down
6 changes: 2 additions & 4 deletions src/commands/pause.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@ import { Message } from 'discord.js';

export async function pauseCommand(message: Message) {
const player = client?.player;
if (typeof player === 'undefined') return message.reply(embeds.videoNotPlaying);
if (!player) return message.reply(embeds.videoNotPlaying);

if (player.player.state.status === AudioPlayerStatus.Playing) {
player.pause();
message.reply(embeds.videoPaused);
} else if (player.player.state.status === AudioPlayerStatus.Paused) {
player.resume();
message.reply(embeds.videoResumed);
} else {
message.reply(embeds.videoNotPlaying);
}
} else message.reply(embeds.videoNotPlaying);
}
4 changes: 2 additions & 2 deletions src/commands/play.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ let url: string;

export async function playCommand(message: Message) {
let player = client?.player;
if (typeof queueManager.getQueue(message.guild?.id as string) === 'undefined') {
if (!queueManager.getQueue(message.guild?.id as string)) {
queueManager.setQueue(message.guild?.id as string, new Queue());
}
const queue = queueManager.getQueue(message.guild?.id as string) as Queue;
if (typeof player === 'undefined') {
if (!player) {
client.player = new YTPlayer(
message.guild?.id as string,
message.member?.voice.channel as VoiceBasedChannel,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ytdl from 'ytdl-core';

export async function queueCommand(message: Message) {
const player = client?.player;
if (typeof player === 'undefined') return message.reply(embeds.videoNotPlaying);
if (!player) return message.reply(embeds.videoNotPlaying);
const queue = queueManager.getQueue(message.guildId!) as Queue;

const embed = new embeds.embed().setTitle('Queue').setColor('Blue').setTimestamp();
Expand Down
6 changes: 2 additions & 4 deletions src/commands/resume.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ import { Message } from 'discord.js';

export async function resumeCommand(message: Message) {
const player = client?.player;
if (typeof player === 'undefined') return message.reply(embeds.videoNotPlaying);
if (!player) return message.reply(embeds.videoNotPlaying);
if (player.player.state.status === AudioPlayerStatus.Paused) {
player.resume();
message.reply(embeds.videoResumed);
} else if (player.player.state.status === AudioPlayerStatus.Playing) {
message.reply(embeds.videoNotPaused);
} else {
message.reply(embeds.videoNotPlaying);
}
} else message.reply(embeds.videoNotPlaying);
}
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] });
}
2 changes: 1 addition & 1 deletion src/commands/skip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Message } from 'discord.js';

export async function skipCommand(message: Message) {
const player = client?.player;
if (typeof player === 'undefined') return message.reply(embeds.videoNotPlaying);
if (!player) return message.reply(embeds.videoNotPlaying);
player.skip();
return message.reply(embeds.videoNext);
}
4 changes: 1 addition & 3 deletions src/commands/stop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ export async function stopCommand(message: Message): Promise<void> {
message.guild.members.me.voice.disconnect();
client.player = undefined;
message.reply(embeds.videoStopped);
} else {
message.reply(embeds.videoNotPlaying);
}
} else message.reply(embeds.videoNotPlaying);

queueManager.queues.delete(message.guildId!);
}
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
6 changes: 5 additions & 1 deletion src/embeds/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const embeds = {
{ name: 'pause', value: '再生を一時停止/再開します。' },
{ name: 'resume', value: '再生を再開します。' },
{ name: 'nowplaying', value: '現在の曲を表示します。' },
{ name: 'volume', value: '音量を変更します。'}
{ name: 'volume', value: '音量を変更します。' }
)
.build(),
videoNotPlaying: new Builder()
Expand All @@ -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
2 changes: 1 addition & 1 deletion src/interactions/changeVolume.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export async function changeVolumeCommand(interaction: ChatInputCommandInteracti
if (!player) return interaction.reply(embeds.videoNotPlaying);

const vol = interaction.options.getInteger('volume');
if (!vol) return interaction.reply({ content: `現在の音量は${player.volume}です。` });
if (!vol) return interaction.reply({ content: `現在の音量は${player.volume * 10}です。` });
if (vol >= 100) {
player.changeVolume(100 / 10);
return interaction.reply({ content: 'ボリュームを最大に設定しました。' });
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()
);
}
}
2 changes: 1 addition & 1 deletion src/interactions/help.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { embeds } from '../embeds';
import { ChatInputCommandInteraction } from 'discord.js';

export async function helpCommand(interaction: ChatInputCommandInteraction): Promise<void> {
export async function helpCommand(interaction: ChatInputCommandInteraction) {
interaction.reply(embeds.help);
}
Loading

0 comments on commit 7e4ae65

Please sign in to comment.