Skip to content

Commit

Permalink
Merge pull request #15 from Nich87/dev
Browse files Browse the repository at this point in the history
おめでとうございます!あなたは久しぶりのPRを受け取りました!
  • Loading branch information
MotiCAT authored Nov 10, 2024
2 parents 5fb81a5 + a0bc396 commit 167eee9
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 68 deletions.
26 changes: 14 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "tunenekosync",
"version": "1.0.2",
"version": "1.0.3",
"description": "MusicBot",
"main": "index.js",
"engines": {
"node": ">=18.x"
"node": ">=22.x"
},
"scripts": {
"test": "ts-node src/index.ts",
Expand All @@ -24,23 +24,25 @@
"license": "MIT",
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@typescript-eslint/eslint-plugin": "^6.13.1",
"@typescript-eslint/parser": "^6.13.1",
"eslint": "^8.54.0",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.0",
"prettier": "^3.1.0",
"ts-node": "^10.9.1",
"typescript": "^5.3.2"
"prettier": "^3.3.3",
"ts-node": "^10.9.2",
"typescript": "^5.6.3"
},
"dependencies": {
"@discordjs/opus": "^0.9.0",
"@discordjs/voice": "^0.16.1",
"discord.js": "^14.14.1",
"dotenv": "^16.3.1",
"@distube/ytdl-core": "^4.15.1",
"discord.js": "^14.16.3",
"dotenv": "^16.4.5",
"ffmpeg-static": "^5.2.0",
"node-cache": "^5.1.2",
"tweetnacl": "^1.0.3",
"youtube-sr": "^4.3.10",
"ytdl-core": "^4.11.5"
"youtube-sr": "^4.3.11",
"ytpl": "^2.3.0"
},
"repository": {
"type": "git",
Expand Down
35 changes: 31 additions & 4 deletions src/Utils/songResolver.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { format_count, seconds_to_time } from '../Utils/NumberUtil';
import { client } from '../index';
import { Builder } from './Builder';
import ytdl from 'ytdl-core';
import ytdl from '@distube/ytdl-core';

export function songResolver(info: ytdl.videoInfo, requestedBy?: string, requestedByAvatar?: string) {
return {
Expand All @@ -17,10 +17,36 @@ export function songResolver(info: ytdl.videoInfo, requestedBy?: string, request
};
}

export function formatProgressBar(current: number, total: number, barLength: number = 20): string {
const progress = Math.round((current / total) * barLength);
const empty = Math.max(barLength - progress, 0); // `empty` が負にならないように修正
const filled = '█'.repeat(progress); // 進行中部分(█)
const unfilled = '░'.repeat(empty); // 残り部分(░)

return `${seconds_to_time(current)} [${filled}${unfilled}] ${seconds_to_time(total)} (${Math.round((current / total) * 100)}%)`;
}


export async function getSongInfo(url: string) {
const info = await ytdl.getInfo(url);
const song = songResolver(info);
const currentDuration = seconds_to_time(Math.round(Number(client.player?.resource?.playbackDuration) / 1000));

// currentDuration が undefined または NaN の場合、デフォルトで 0 を設定
const currentDuration = Number(client.player?.resource?.playbackDuration) ? Math.round(Number(client.player?.resource?.playbackDuration) / 1000) : 0;
const totalDuration = Number(info.videoDetails.lengthSeconds);

const progressBar = formatProgressBar(currentDuration, totalDuration);

// 次の曲がキューにあるか確認
const nextSong = (await ytdl.validateURL(client.player?.queue.store[1] as string))
? await ytdl.getInfo(client.player?.queue.store[1] as string)
: null;

let footerText = '次の曲はありません';
if (nextSong) {
const nextSongInfo = songResolver(nextSong);
footerText = `次の曲: ${nextSongInfo.title}`;
}

const embed = new Builder()
.setTitle(song.title)
Expand All @@ -30,9 +56,10 @@ export async function getSongInfo(url: string) {
{ name: '投稿者', value: `[${song.author}](${song.authorUrl})` },
{ name: '再生時間', value: song.duration, inline: true },
{ name: '再生回数', value: song.views, inline: true },
{ name: '現在の位置', value: currentDuration, inline: false }
{ name: '再生位置', value: progressBar, inline: false }
)
.setColor('Green');
.setColor('Green')
.setFooter({ text: footerText });

return embed.build();
}
16 changes: 9 additions & 7 deletions src/classes/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { client } from '../index';
import type { Queue } from './queue';
import { queueManager } from './queue';
import { joinVoiceChannel, createAudioPlayer } from '@discordjs/voice';
import { createAudioResource, StreamType, AudioPlayerStatus } from '@discordjs/voice';
import { createAudioResource, StreamType, AudioPlayerStatus, DiscordGatewayAdapterCreator } from '@discordjs/voice';
import ytdl from '@distube/ytdl-core';
import { Snowflake, VoiceBasedChannel } from 'discord.js';
import ytdl from 'ytdl-core';

export class YTPlayer {
private connection: import('@discordjs/voice').VoiceConnection;
Expand All @@ -21,7 +21,7 @@ export class YTPlayer {
this.serverId = serverId;
this.messageChannelId = messageChannelId;
this.connection = joinVoiceChannel({
adapterCreator: voiceChannel.guild.voiceAdapterCreator,
adapterCreator: voiceChannel.guild.voiceAdapterCreator as DiscordGatewayAdapterCreator,
channelId: voiceChannel.id,
guildId: serverId,
selfDeaf: true,
Expand Down Expand Up @@ -87,8 +87,8 @@ export class YTPlayer {
else {
if (this.queue.store.length >= 1) this.queue.removeSong(0);
if (!this.queue.store.length) return this.stop();
await this.fetchSongData();
return this.play();
this.play();
return await this.fetchSongData();
}
}
if (this.queue.loop === 'queue') this.queue.loopQueue();
Expand All @@ -99,7 +99,9 @@ export class YTPlayer {

private async fetchSongData() {
const channel = client.channels.cache.get(this.messageChannelId);
if (!channel) return;
if (channel.isTextBased()) channel.send(await getSongInfo(this.queue.currentSong!));
if (!channel || !channel.isTextBased()) return;
if (channel.isTextBased() && 'send' in channel) {
await channel.send(await getSongInfo(this.queue.currentSong!));
}
}
}
2 changes: 1 addition & 1 deletion src/commands/debug.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { songResolver } from '../Utils/songResolver';
import { embeds } from '../embeds';
import ytdl from '@distube/ytdl-core';
import { Message } from 'discord.js';
import ytdl from 'ytdl-core';

export async function debugCommand(message: Message) {
const url = message.content.split(' ')[1];
Expand Down
2 changes: 1 addition & 1 deletion src/commands/play.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { YTPlayer } from '../classes/player';
import { Queue, queueManager } from '../classes/queue';
import { embeds } from '../embeds';
import { client } from '../index';
import ytdl from '@distube/ytdl-core';
import { Message, VoiceBasedChannel } from 'discord.js';
import ytdl from 'ytdl-core';

let url: string;

Expand Down
2 changes: 1 addition & 1 deletion src/commands/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { songResolver } from '../Utils/songResolver';
import { Queue, queueManager } from '../classes/queue';
import { embeds } from '../embeds';
import { client } from '../index';
import ytdl from '@distube/ytdl-core';
import { Message } from 'discord.js';
import ytdl from 'ytdl-core';

export async function queueCommand(message: Message) {
const player = client?.player;
Expand Down
2 changes: 1 addition & 1 deletion src/interactions/handleplay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { YTPlayer } from '../classes/player';
import { Queue, queueManager } from '../classes/queue';
import { embeds } from '../embeds';
import { client } from '../index';
import ytdl from '@distube/ytdl-core';
import { StringSelectMenuInteraction, ChannelType, VoiceBasedChannel, GuildMember } from 'discord.js';
import ytdl from 'ytdl-core';

let url: string;

Expand Down
71 changes: 44 additions & 27 deletions src/interactions/play.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { YTPlayer } from '../classes/player';
import { Queue, queueManager } from '../classes/queue';
import { embeds } from '../embeds';
import { client } from '../index';
import ytdl from '@distube/ytdl-core';
import { ChannelType, VoiceBasedChannel, ChatInputCommandInteraction, GuildMember } from 'discord.js';
import ytdl from 'ytdl-core';
import ytpl from 'ytpl';

let url: string;

Expand All @@ -26,42 +27,58 @@ export async function playCommand(interaction: ChatInputCommandInteraction) {
url = interaction.options.getString('url') as string;
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);
// Check if URL is a playlist
if (ytpl.validateID(url)) {
const playlist = await ytpl(url);
for (const video of playlist.items) queue.addSong(video.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])
.setTitle('Playlist Added')
.setDescription(`**${playlist.title}** を再生キューに追加しました。`)
.setColor('Green')
.build()
);
if (queue.length === 1) return player.play();
if (!player.isPlaying) return player.play();
} else if (ytdl.validateURL(url)) {
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()
);
}
} 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()
);
interaction.reply(embeds.invaildUrl);
}
}
Loading

0 comments on commit 167eee9

Please sign in to comment.