Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

おめでとうございます!あなたは検索コマンドと細かいバグ修正を受け取りました! #14

Merged
merged 8 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading