mirror of
https://github.com/MinazukiAmane/Tinasha-Bot.git
synced 2025-03-15 14:55:59 +08:00
add support lavalink v4
This commit is contained in:
parent
e1a08f2a46
commit
17b4eb0914
46
config.js
46
config.js
@ -54,37 +54,51 @@ module.exports = {
|
||||
ENABLED: true,
|
||||
IDLE_TIME: 60, // Time in seconds before the bot disconnects from an idle voice channel
|
||||
MAX_SEARCH_RESULTS: 100,
|
||||
DEFAULT_SOURCE: "YT", // YT = Youtube, YTM = Youtube Music, SC = SoundCloud
|
||||
DEFAULT_VOLUME: 50, // Default volume for the music player (0-100)
|
||||
DEFAULT_SOURCE: "ytsearch", // ytsearch = Youtube, ytmsearch = Youtube Music, spsearch = Spotify, scsearch = SoundCloud
|
||||
// Lavalink Websocket configuration
|
||||
LAVALINK_WS: {
|
||||
clientName: "Kiera-Bot", // The name of the lavalink client.
|
||||
resuming: true, // Whether Lavalink should attempt to resume existing sessions when reconnecting.
|
||||
reconnecting: {
|
||||
tries: Infinity, // Number of times to attempt reconnecting.
|
||||
delay: 20000 // Delay
|
||||
}
|
||||
},
|
||||
// Add any number of lavalink nodes here
|
||||
// Refer to https://github.com/freyacodes/Lavalink to host your own lavalink server
|
||||
LAVALINK_NODES: [
|
||||
{
|
||||
info: {
|
||||
host: "lavalink.serenetia.com",
|
||||
port: 443,
|
||||
password: "amanechan",
|
||||
auth: "amanechan",
|
||||
},
|
||||
id: "Indonesia Node secure",
|
||||
secure: true,
|
||||
},
|
||||
{
|
||||
host: "lavalink-sg.serenetia.com",
|
||||
port: 443,
|
||||
password: "amanechan",
|
||||
id: "Singapore Node secure",
|
||||
info: {
|
||||
host: "lavalinkv4.serenetia.com",
|
||||
auth: "amanechan",
|
||||
port: 433,
|
||||
secure: true,
|
||||
},
|
||||
identifier: "Indonesia V4 Secure"
|
||||
},
|
||||
{
|
||||
info: {
|
||||
host: "103.125.38.143",
|
||||
port: 3556,
|
||||
password: "amanechan",
|
||||
id: "Indonesia Node not secure",
|
||||
secure: false,
|
||||
auth: "amanechan",
|
||||
},
|
||||
identifier: "Indonesia Node not secure",
|
||||
},
|
||||
{
|
||||
host: "217.15.162.4",
|
||||
port: 23333,
|
||||
password: "amanechan",
|
||||
id: "Singapore Node not secure",
|
||||
secure: false,
|
||||
info: {
|
||||
host: "103.125.38.143",
|
||||
port: 3557,
|
||||
auth: "amanechan",
|
||||
},
|
||||
identifier: "Indonesia V4 not secure",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
1190
package-lock.json
generated
1190
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "KieraBot",
|
||||
"version": "5.5.0",
|
||||
"version": "5.5.1",
|
||||
"description": "multipurpose discord bot built using discord-js",
|
||||
"main": "bot.js",
|
||||
"author": "Amane",
|
||||
@ -24,6 +24,7 @@
|
||||
"url": "https://github.com/MinazukiAmane/Kiera-Bot/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lavaclient/plugin-queue": "^0.0.1",
|
||||
"@lavaclient/queue": "^2.1.1",
|
||||
"@lavaclient/spotify": "^3.1.0",
|
||||
"@lavaclient/types": "^2.1.1",
|
||||
@ -43,7 +44,7 @@
|
||||
"express-session": "^1.18.0",
|
||||
"fixedsize-map": "^1.0.1",
|
||||
"iso-639-1": "^3.1.0",
|
||||
"lavaclient": "^4.1.1",
|
||||
"lavaclient": "^5.0.0-rc.3",
|
||||
"module-alias": "^2.2.3",
|
||||
"moment": "^2.30.1",
|
||||
"mongoose": "^8.1.1",
|
||||
|
@ -70,8 +70,8 @@ module.exports = {
|
||||
* @param {number} level
|
||||
*/
|
||||
function setBassBoost({ client, guildId }, level) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
const bands = new Array(3).fill(null).map((_, i) => ({ band: i, gain: levels[level] }));
|
||||
player.setEqualizer(...bands);
|
||||
player.setFilters(...bands);
|
||||
return `> Set the bassboost level to \`${level}\``;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const { musicValidations } = require("@helpers/BotUtils");
|
||||
const { LoopType } = require("@lavaclient/queue");
|
||||
const { LoopType } = require("@lavaclient/plugin-queue");
|
||||
const { ApplicationCommandOptionType } = require("discord.js");
|
||||
|
||||
/**
|
||||
@ -56,7 +56,7 @@ module.exports = {
|
||||
* @param {"queue"|"track"} type
|
||||
*/
|
||||
function toggleLoop({ client, guildId }, type) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
|
||||
// track
|
||||
if (type === "track") {
|
||||
@ -66,7 +66,7 @@ function toggleLoop({ client, guildId }, type) {
|
||||
|
||||
// queue
|
||||
else if (type === "queue") {
|
||||
player.queue.setLoop(1);
|
||||
player.queue.setLoop(LoopType.Queue);
|
||||
return "Loop mode is set to `queue`";
|
||||
}
|
||||
}
|
||||
|
@ -33,36 +33,45 @@ module.exports = {
|
||||
/**
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
function nowPlaying({ client, guildId }) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
function nowPlaying({ client, guildId, member }) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
if (!player || !player.queue.current) return "🚫 No music is being played!";
|
||||
|
||||
const track = player.queue.current;
|
||||
const end = track.length > 6.048e8 ? "🔴 LIVE" : new Date(track.length).toISOString().slice(11, 19);
|
||||
const trackLength = track.info.isStream ? "🔴 LIVE" : prettyMs(track.info.length, { colonNotation: true });
|
||||
const trackPosition = track.info.isStream ? "🔴 LIVE" : prettyMs(player.position, { colonNotation: true });
|
||||
|
||||
let progressBar = "";
|
||||
if (!track.info.isStream) {
|
||||
const totalLength = track.info.length > 6.048e8 ? player.position : track.info.length;
|
||||
progressBar =
|
||||
new Date(player.position).toISOString().slice(11, 19) +
|
||||
" [" +
|
||||
splitBar(totalLength, player.position, 15)[0] +
|
||||
"] " +
|
||||
new Date(track.info.length).toISOString().slice(11, 19);
|
||||
} else {
|
||||
progressBar = "🔴 LIVE";
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(EMBED_COLORS.BOT_EMBED)
|
||||
.setAuthor({ name: "Now playing" })
|
||||
.setDescription(`[${track.title}](${track.uri})`)
|
||||
.setDescription(`[${track.info.title}](${track.info.uri})`)
|
||||
.addFields(
|
||||
{
|
||||
name: "Song Duration",
|
||||
value: "`" + prettyMs(track.length, { colonNotation: true }) + "`",
|
||||
value: "`" + trackLength + "`",
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Requested By",
|
||||
value: track.requester || "Unknown",
|
||||
value: track.requesterId || member.displayName,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "\u200b",
|
||||
value:
|
||||
new Date(player.position).toISOString().slice(11, 19) +
|
||||
" [" +
|
||||
splitBar(track.length > 6.048e8 ? player.position : track.length, player.position, 15)[0] +
|
||||
"] " +
|
||||
end,
|
||||
value: progressBar,
|
||||
inline: false,
|
||||
}
|
||||
);
|
||||
|
@ -30,7 +30,7 @@ module.exports = {
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
function pause({ client, guildId }) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
if (player.paused) return "The player is already paused.";
|
||||
|
||||
player.pause(true);
|
||||
|
@ -1,13 +1,7 @@
|
||||
const { EmbedBuilder, ApplicationCommandOptionType } = require("discord.js");
|
||||
const prettyMs = require("pretty-ms");
|
||||
const { EMBED_COLORS, MUSIC } = require("@root/config");
|
||||
const { SpotifyItemType } = require("@lavaclient/spotify");
|
||||
|
||||
const search_prefix = {
|
||||
YT: "ytsearch",
|
||||
YTM: "ytmsearch",
|
||||
SC: "scsearch",
|
||||
};
|
||||
require("@lavaclient/plugin-queue")
|
||||
|
||||
/**
|
||||
* @type {import("@structures/Command")}
|
||||
@ -54,10 +48,10 @@ module.exports = {
|
||||
async function play({ member, guild, channel }, query) {
|
||||
if (!member.voice.channel) return "🚫 You need to join a voice channel first";
|
||||
|
||||
let player = guild.client.musicManager.getPlayer(guild.id);
|
||||
let player = guild.client.musicManager.players.resolve(guild.id);
|
||||
if (player && !guild.members.me.voice.channel) {
|
||||
player.disconnect();
|
||||
await guild.client.musicManager.destroyPlayer(guild.id);
|
||||
player.voice.disconnect();
|
||||
await guild.client.musicManager.players.destroy(guild.id);
|
||||
}
|
||||
|
||||
if (player && member.voice.channel !== guild.members.me.voice.channel) {
|
||||
@ -67,65 +61,38 @@ async function play({ member, guild, channel }, query) {
|
||||
let embed = new EmbedBuilder().setColor(EMBED_COLORS.BOT_EMBED);
|
||||
let tracks;
|
||||
let description = "";
|
||||
let thumbnail;
|
||||
|
||||
try {
|
||||
if (guild.client.musicManager.spotify.isSpotifyUrl(query)) {
|
||||
if (!process.env.SPOTIFY_CLIENT_ID || !process.env.SPOTIFY_CLIENT_SECRET) {
|
||||
return "🚫 Spotify songs cannot be played. Please contact the bot owner";
|
||||
}
|
||||
|
||||
const item = await guild.client.musicManager.spotify.load(query);
|
||||
switch (item?.type) {
|
||||
case SpotifyItemType.Track: {
|
||||
const track = await item.resolveYoutubeTrack();
|
||||
tracks = [track];
|
||||
description = `[${track.info.title}](${track.info.uri})`;
|
||||
break;
|
||||
}
|
||||
|
||||
case SpotifyItemType.Artist:
|
||||
tracks = await item.resolveYoutubeTracks();
|
||||
description = `Artist: [**${item.name}**](${query})`;
|
||||
break;
|
||||
|
||||
case SpotifyItemType.Album:
|
||||
tracks = await item.resolveYoutubeTracks();
|
||||
description = `Album: [**${item.name}**](${query})`;
|
||||
break;
|
||||
|
||||
case SpotifyItemType.Playlist:
|
||||
tracks = await item.resolveYoutubeTracks();
|
||||
description = `Playlist: [**${item.name}**](${query})`;
|
||||
break;
|
||||
|
||||
default:
|
||||
return "🚫 An error occurred while searching for the song";
|
||||
}
|
||||
|
||||
if (!tracks) guild.client.logger.debug({ query, item });
|
||||
} else {
|
||||
const res = await guild.client.musicManager.rest.loadTracks(
|
||||
/^https?:\/\//.test(query) ? query : `${search_prefix[MUSIC.DEFAULT_SOURCE]}:${query}`
|
||||
const res = await guild.client.musicManager.api.loadTracks(
|
||||
/^https?:\/\//.test(query) ? query : `${MUSIC.DEFAULT_SOURCE}:${query}`
|
||||
);
|
||||
|
||||
let track;
|
||||
|
||||
switch (res.loadType) {
|
||||
case "LOAD_FAILED":
|
||||
guild.client.logger.error("Search Exception", res.exception);
|
||||
case "error":
|
||||
guild.client.logger.error("Search Exception", res.data);
|
||||
return "🚫 There was an error while searching";
|
||||
|
||||
case "NO_MATCHES":
|
||||
case "empty":
|
||||
return `No results found matching ${query}`;
|
||||
|
||||
case "PLAYLIST_LOADED":
|
||||
tracks = res.tracks;
|
||||
description = res.playlistInfo.name;
|
||||
case "playlist":
|
||||
tracks = res.data.tracks;
|
||||
description = res.data.info.name;
|
||||
thumbnail = res.data.pluginInfo.artworkUrl;
|
||||
break;
|
||||
|
||||
case "TRACK_LOADED":
|
||||
case "SEARCH_RESULT": {
|
||||
const [track] = res.tracks;
|
||||
case "track":
|
||||
track = res.data;
|
||||
tracks = [track];
|
||||
break;
|
||||
|
||||
case "search":
|
||||
track = res.data[0];
|
||||
tracks = [track];
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
guild.client.logger.debug("Unknown loadType", res);
|
||||
@ -133,7 +100,6 @@ async function play({ member, guild, channel }, query) {
|
||||
}
|
||||
|
||||
if (!tracks) guild.client.logger.debug({ query, res });
|
||||
}
|
||||
} catch (error) {
|
||||
guild.client.logger.error("Search Exception", typeof error === "object" ? JSON.stringify(error) : error);
|
||||
return "🚫 An error occurred while searching for the song";
|
||||
@ -150,6 +116,7 @@ async function play({ member, guild, channel }, query) {
|
||||
embed
|
||||
.setAuthor({ name: "Added Track to queue" })
|
||||
.setDescription(`[${track.info.title}](${track.info.uri})`)
|
||||
.setThumbnail(track.info.artworkUrl)
|
||||
.setFooter({ text: `Requested By: ${member.user.username}` });
|
||||
|
||||
fields.push({
|
||||
@ -170,6 +137,7 @@ async function play({ member, guild, channel }, query) {
|
||||
} else {
|
||||
embed
|
||||
.setAuthor({ name: "Added Playlist to queue" })
|
||||
.setThumbnail(thumbnail)
|
||||
.setDescription(description)
|
||||
.addFields(
|
||||
{
|
||||
@ -194,14 +162,15 @@ async function play({ member, guild, channel }, query) {
|
||||
|
||||
// create a player and/or join the member's vc
|
||||
if (!player?.connected) {
|
||||
player = guild.client.musicManager.createPlayer(guild.id);
|
||||
player = guild.client.musicManager.players.create(guild.id);
|
||||
player.queue.data.channel = channel;
|
||||
player.connect(member.voice.channel.id, { deafened: true });
|
||||
player.voice.connect(member.voice.channel.id, { deafened: true });
|
||||
player.setVolume(MUSIC.DEFAULT_VOLUME);
|
||||
}
|
||||
|
||||
// do queue things
|
||||
const started = player.playing || player.paused;
|
||||
player.queue.add(tracks, { requester: member.user.username, next: false });
|
||||
player.queue.add(tracks, { requester: member.user.displayName, next: false });
|
||||
if (!started) {
|
||||
await player.queue.start();
|
||||
}
|
||||
|
@ -27,13 +27,13 @@ module.exports = {
|
||||
|
||||
async messageRun(message, args) {
|
||||
const page = args.length && Number(args[0]) ? Number(args[0]) : 1;
|
||||
const response = getQueue(message, page);
|
||||
const response = await getQueue(message, page);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
const page = interaction.options.getInteger("page");
|
||||
const response = getQueue(interaction, page);
|
||||
const response = await getQueue(interaction, page);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
@ -42,8 +42,8 @@ module.exports = {
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
* @param {number} pgNo
|
||||
*/
|
||||
function getQueue({ client, guild }, pgNo) {
|
||||
const player = client.musicManager.getPlayer(guild.id);
|
||||
async function getQueue({ client, guild }, pgNo) {
|
||||
const player = client.musicManager.players.resolve(guild.id);
|
||||
if (!player) return "🚫 There is no music playing in this guild.";
|
||||
|
||||
const queue = player.queue;
|
||||
@ -58,9 +58,16 @@ function getQueue({ client, guild }, pgNo) {
|
||||
|
||||
const tracks = queue.tracks.slice(start, end);
|
||||
|
||||
if (queue.current) embed.addFields({ name: "Current", value: `[${queue.current.title}](${queue.current.uri})` });
|
||||
if (!tracks.length) embed.setDescription(`No tracks in ${page > 1 ? `page ${page}` : "the queue"}.`);
|
||||
else embed.setDescription(tracks.map((track, i) => `${start + ++i} - [${track.title}](${track.uri})`).join("\n"));
|
||||
if (queue.current) embed.addFields({ name: "Current", value: `[${queue.current.info.title}](${queue.current.info.url})` });
|
||||
|
||||
const queueList = track.map((track, index) => {
|
||||
const title = track.info.title;
|
||||
const uri = track.info.uri;
|
||||
return `${start + index + 1}. [${title}](${uri})`;
|
||||
});
|
||||
|
||||
if (!queueList.length) embed.setDescription(`No tracks in ${page > 1 ? `page ${page}` : "the queue"}.`);
|
||||
else embed.setDescription(queueList.join("\n"));
|
||||
|
||||
const maxPages = Math.ceil(queue.tracks.length / multiple);
|
||||
|
||||
|
@ -30,7 +30,7 @@ module.exports = {
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
function resumePlayer({ client, guildId }) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
if (!player.paused) return "The player is already resumed";
|
||||
player.resume();
|
||||
return "▶️ Resumed the music player";
|
||||
|
@ -6,14 +6,9 @@ const {
|
||||
ComponentType,
|
||||
} = require("discord.js");
|
||||
const prettyMs = require("pretty-ms");
|
||||
require("@lavaclient/plugin-queue")
|
||||
const { EMBED_COLORS, MUSIC } = require("@root/config");
|
||||
|
||||
const search_prefix = {
|
||||
YT: "ytsearch",
|
||||
YTM: "ytmsearch",
|
||||
SC: "scsearch",
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {import("@structures/Command")}
|
||||
*/
|
||||
@ -60,10 +55,10 @@ module.exports = {
|
||||
async function search({ member, guild, channel }, query) {
|
||||
if (!member.voice.channel) return "🚫 You need to join a voice channel first";
|
||||
|
||||
let player = guild.client.musicManager.getPlayer(guild.id);
|
||||
let player = guild.client.musicManager.players.resolve(guild.id);
|
||||
if (player && !guild.members.me.voice.channel) {
|
||||
player.disconnect();
|
||||
await guild.client.musicManager.destroyPlayer(guild.id);
|
||||
player.voice.disconnect();
|
||||
await guild.client.musicManager.players.destroy(guild.id);
|
||||
}
|
||||
if (player && member.voice.channel !== guild.members.me.voice.channel) {
|
||||
return "🚫 You must be in the same voice channel as mine";
|
||||
@ -71,8 +66,8 @@ async function search({ member, guild, channel }, query) {
|
||||
|
||||
let res;
|
||||
try {
|
||||
res = await guild.client.musicManager.rest.loadTracks(
|
||||
/^https?:\/\//.test(query) ? query : `${search_prefix[MUSIC.DEFAULT_SOURCE]}:${query}`
|
||||
res = await guild.client.musicManager.api.loadTracks(
|
||||
/^https?:\/\//.test(query) ? query : `${MUSIC.DEFAULT_SOURCE}:${query}`
|
||||
);
|
||||
} catch (err) {
|
||||
return "🚫 There was an error while searching";
|
||||
@ -81,17 +76,16 @@ async function search({ member, guild, channel }, query) {
|
||||
let embed = new EmbedBuilder().setColor(EMBED_COLORS.BOT_EMBED);
|
||||
let tracks;
|
||||
|
||||
const loadType = res.tracks.length > 0 ? res.loadType : "NO_MATCHES";
|
||||
switch (loadType) {
|
||||
case "LOAD_FAILED":
|
||||
guild.client.logger.error("Search Exception", res.exception);
|
||||
switch (res.loadType) {
|
||||
case "error":
|
||||
guild.client.logger.error("Search Exception", res.data);
|
||||
return "🚫 There was an error while searching";
|
||||
|
||||
case "NO_MATCHES":
|
||||
case "empty":
|
||||
return `No results found matching ${query}`;
|
||||
|
||||
case "TRACK_LOADED": {
|
||||
const [track] = res.tracks;
|
||||
case "track": {
|
||||
const [track] = res.data[0];
|
||||
tracks = [track];
|
||||
if (!player?.playing && !player?.paused && !player?.queue.tracks.length) {
|
||||
embed.setAuthor({ name: "Added Song to queue" });
|
||||
@ -110,7 +104,6 @@ async function search({ member, guild, channel }, query) {
|
||||
inline: true,
|
||||
});
|
||||
|
||||
// if (typeof track.displayThumbnail === "function") embed.setThumbnail(track.displayThumbnail("hqdefault"));
|
||||
if (player?.queue?.tracks?.length > 0) {
|
||||
fields.push({
|
||||
name: "Position in Queue",
|
||||
@ -122,15 +115,15 @@ async function search({ member, guild, channel }, query) {
|
||||
break;
|
||||
}
|
||||
|
||||
case "PLAYLIST_LOADED":
|
||||
tracks = res.tracks;
|
||||
case "playlist":
|
||||
tracks = res.data.tracks;
|
||||
embed
|
||||
.setAuthor({ name: "Added Playlist to queue" })
|
||||
.setDescription(res.playlistInfo.name)
|
||||
.setDescription(res.data.info.name)
|
||||
.addFields(
|
||||
{
|
||||
name: "Enqueued",
|
||||
value: `${res.tracks.length} songs`,
|
||||
value: `${res.data.tracks.length} songs`,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
@ -138,7 +131,7 @@ async function search({ member, guild, channel }, query) {
|
||||
value:
|
||||
"`" +
|
||||
prettyMs(
|
||||
res.tracks.map((t) => t.info.length).reduce((a, b) => a + b, 0),
|
||||
res.data.tracks.map((t) => t.info.length).reduce((a, b) => a + b, 0),
|
||||
{ colonNotation: true }
|
||||
) +
|
||||
"`",
|
||||
@ -148,11 +141,11 @@ async function search({ member, guild, channel }, query) {
|
||||
.setFooter({ text: `Requested By: ${member.user.username}` });
|
||||
break;
|
||||
|
||||
case "SEARCH_RESULT": {
|
||||
case "search": {
|
||||
let max = guild.client.config.MUSIC.MAX_SEARCH_RESULTS;
|
||||
if (res.tracks.length < max) max = res.tracks.length;
|
||||
if (res.data.length < max) max = res.data.length;
|
||||
|
||||
const results = res.tracks.slice(0, max);
|
||||
const results = res.data.slice(0, max);
|
||||
const options = results.map((result, index) => ({
|
||||
label: result.info.title,
|
||||
value: index.toString(),
|
||||
@ -205,12 +198,13 @@ async function search({ member, guild, channel }, query) {
|
||||
await sentMsg.delete();
|
||||
return "🚫 Failed to register your response";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// create a player and/or join the member's vc
|
||||
if (!player?.connected) {
|
||||
player = guild.client.musicManager.createPlayer(guild.id);
|
||||
player = guild.client.musicManager.players.create(guild.id);
|
||||
player.queue.data.channel = channel;
|
||||
player.connect(member.voice.channel.id, { deafened: true });
|
||||
}
|
||||
|
@ -45,10 +45,10 @@ module.exports = {
|
||||
* @param {number} time
|
||||
*/
|
||||
function seekTo({ client, guildId }, time) {
|
||||
const player = client.musicManager?.getPlayer(guildId);
|
||||
const player = client.musicManager?.players.resolve(guildId);
|
||||
const seekTo = durationToMillis(time);
|
||||
|
||||
if (seekTo > player.queue.current.length) {
|
||||
if (seekTo > player.queue.current.info.length) {
|
||||
return "The duration you provide exceeds the duration of the current track";
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ module.exports = {
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
function shuffle({ client, guildId }) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
player.queue.shuffle();
|
||||
return "🎶 Queue has been shuffled";
|
||||
}
|
||||
|
@ -17,12 +17,12 @@ module.exports = {
|
||||
},
|
||||
|
||||
async messageRun(message, args) {
|
||||
const response = skip(message);
|
||||
const response = await skip(message);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
const response = skip(interaction);
|
||||
const response = await skip(interaction);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
@ -30,12 +30,21 @@ module.exports = {
|
||||
/**
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
function skip({ client, guildId }) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
async function skip({ client, guildId }) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
|
||||
// check if current song is playing
|
||||
if (!player.queue.current) return "⏯️ There is no song currently being played";
|
||||
|
||||
const { title } = player.queue.current;
|
||||
return player.queue.next() ? `⏯️ ${title} was skipped.` : "⏯️ There is no song to skip.";
|
||||
if (!player || !player.queue.current) {
|
||||
return "⏯️ There is no song currently being played";
|
||||
}
|
||||
|
||||
const title = player.queue.current.info.title;
|
||||
|
||||
// Check if there is a next song in the queue
|
||||
if (player.queue.tracks.length === 0) {
|
||||
return "There is no next song ti skip to";
|
||||
}
|
||||
|
||||
// skip to the next song
|
||||
player.queue.next();
|
||||
return `⏯️ ${title} was skipped successfully.`;
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ module.exports = {
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
async function stop({ client, guildId }) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
player.disconnect();
|
||||
await client.musicManager.destroyPlayer(guildId);
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
player.voice.disconnect();
|
||||
await client.musicManager.players.destroy(guildId);
|
||||
return "🎶 The music player is stopped and queue has been cleared";
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ const { ApplicationCommandOptionType } = require("discord.js");
|
||||
*/
|
||||
module.exports = {
|
||||
name: "volume",
|
||||
description: "set the music player volume",
|
||||
description: "Set the music player volume",
|
||||
category: "MUSIC",
|
||||
validations: musicValidations,
|
||||
command: {
|
||||
@ -18,7 +18,7 @@ module.exports = {
|
||||
options: [
|
||||
{
|
||||
name: "amount",
|
||||
description: "Enter a value to set [0 to 100]",
|
||||
description: "Enter a value to set [1 to 100]",
|
||||
type: ApplicationCommandOptionType.Integer,
|
||||
required: false,
|
||||
},
|
||||
@ -26,14 +26,14 @@ module.exports = {
|
||||
},
|
||||
|
||||
async messageRun(message, args) {
|
||||
const amount = args[0];
|
||||
const response = await volume(message, amount);
|
||||
const amount = parseInt(args[0]);
|
||||
const response = await getVolume(message, amount);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
const amount = interaction.options.getInteger("amount");
|
||||
const response = await volume(interaction, amount);
|
||||
const amount = parseInt(interaction.options.getInteger("amount"));
|
||||
const response = await getVolume(interaction, amount);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
@ -41,12 +41,16 @@ module.exports = {
|
||||
/**
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
async function volume({ client, guildId }, volume) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
async function getVolume({ client, guildId }, amount) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
|
||||
if (!volume) return `> The player volume is \`${player.volume}\`.`;
|
||||
if (volume < 1 || volume > 100) return "you need to give me a volume between 1 and 100.";
|
||||
if (!amount) return `> The player volume is \`${player.volume}\`.`;
|
||||
|
||||
await player.setVolume(volume);
|
||||
return `🎶 Music player volume is set to \`${volume}\`.`;
|
||||
if (isNaN(amount) || amount < 0 || amount > 100) {
|
||||
return "You need to give me a volume between 1 and 100.";
|
||||
}
|
||||
|
||||
// Set the player volume
|
||||
await player.setVolume(amount);
|
||||
return `🎶 Music player volume is set to \`${amount}\`.`;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ module.exports = async (client) => {
|
||||
|
||||
// Initialize Music Manager
|
||||
if (client.config.MUSIC.ENABLED) {
|
||||
client.musicManager.connect(client.user.id);
|
||||
client.musicManager.connect({ userId: client.user.id });
|
||||
client.logger.success("Music Manager initialized");
|
||||
}
|
||||
|
||||
|
@ -21,8 +21,8 @@ module.exports = async (client, oldState, newState) => {
|
||||
setTimeout(() => {
|
||||
// if 1 (you), wait 1 minute
|
||||
if (!oldState.channel.members.size - 1) {
|
||||
const player = client.musicManager.getPlayer(guild.id);
|
||||
if (player) client.musicManager.destroyPlayer(guild.id).then(player.disconnect()); // destroy the player
|
||||
const player = client.musicManager.players.resolve(guild.id);
|
||||
if (player) client.musicManager.players.destroy(guild.id).then(player.voice.disconnect()); // destroy the player
|
||||
}
|
||||
}, client.config.MUSIC.IDLE_TIME * 1000);
|
||||
}
|
||||
|
@ -1,68 +1,52 @@
|
||||
const { EmbedBuilder } = require("discord.js");
|
||||
const { EmbedBuilder, GatewayDispatchEvents } = require("discord.js");
|
||||
const { Cluster } = require("lavaclient");
|
||||
const prettyMs = require("pretty-ms");
|
||||
const { load, SpotifyItemType } = require("@lavaclient/spotify");
|
||||
require("@lavaclient/queue/register");
|
||||
require("@lavaclient/plugin-queue");
|
||||
|
||||
/**
|
||||
* @param {import("@structures/BotClient")} client
|
||||
*/
|
||||
module.exports = (client) => {
|
||||
load({
|
||||
client: {
|
||||
id: process.env.SPOTIFY_CLIENT_ID,
|
||||
secret: process.env.SPOTIFY_CLIENT_SECRET,
|
||||
},
|
||||
autoResolveYoutubeTracks: false,
|
||||
loaders: [SpotifyItemType.Album, SpotifyItemType.Artist, SpotifyItemType.Playlist, SpotifyItemType.Track],
|
||||
});
|
||||
|
||||
const lavaclient = new Cluster({
|
||||
nodes: client.config.MUSIC.LAVALINK_NODES,
|
||||
sendGatewayPayload: (id, payload) => client.guilds.cache.get(id)?.shard?.send(payload),
|
||||
ws: client.config.MUSIC.LAVALINK_WS,
|
||||
discord: {
|
||||
sendGatewayCommand: (id, payload) => client.guilds.cache.get(id)?.shard?.send(payload),
|
||||
},
|
||||
});
|
||||
|
||||
client.ws.on("VOICE_SERVER_UPDATE", (data) => lavaclient.handleVoiceUpdate(data));
|
||||
client.ws.on("VOICE_STATE_UPDATE", (data) => lavaclient.handleVoiceUpdate(data));
|
||||
client.ws.on(GatewayDispatchEvents.VoiceStateUpdate, (data) => lavaclient.players.handleVoiceUpdate(data));
|
||||
client.ws.on(GatewayDispatchEvents.VoiceServerUpdate, (data) => lavaclient.players.handleVoiceUpdate(data));
|
||||
|
||||
lavaclient.on("nodeConnect", (node, event) => {
|
||||
client.logger.log(`Node "${node.id}" connected`);
|
||||
lavaclient.on("nodeConnected", (node, event) => {
|
||||
client.logger.log(`Node "${node.identifier}" connected`);
|
||||
});
|
||||
|
||||
lavaclient.on("nodeDisconnect", (node, event) => {
|
||||
client.logger.log(`Node "${node.id}" disconnected`);
|
||||
const reconnetInterval = 5000;
|
||||
setTimeout(() => {
|
||||
node.connect();
|
||||
}, reconnetInterval);
|
||||
lavaclient.on("nodeDisconnected", (node, event) => {
|
||||
client.logger.log(`Node "${node.identifier}" disconnected`);
|
||||
});
|
||||
|
||||
lavaclient.on("nodeError", (node, error) => {
|
||||
client.logger.error(`Node "${node.id}" encountered an error: ${error.message}.`, error);
|
||||
client.logger.error(`Node "${node.identifier}" encountered an error: ${error.message}.`, error);
|
||||
});
|
||||
|
||||
lavaclient.on("nodeDebug", (node, message) => {
|
||||
client.logger.debug(`Node "${node.id}" debug: ${message}`);
|
||||
lavaclient.on("nodeDebug", (node, event) => {
|
||||
client.logger.debug(`Node "${node.identifier}" debug: ${event.message}`);
|
||||
});
|
||||
|
||||
lavaclient.on("nodeTrackStart", (_node, queue, song) => {
|
||||
lavaclient.on("nodeTrackStart", async (_node, queue, track) => {
|
||||
const fields = [];
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({ name: "Now Playing" })
|
||||
.setColor(client.config.EMBED_COLORS.BOT_EMBED)
|
||||
.setDescription(`[${song.title}](${song.uri})`)
|
||||
.setFooter({ text: `Requested By: ${song.requester}` });
|
||||
|
||||
if (song.sourceName === "youtube") {
|
||||
const identifier = song.identifier;
|
||||
const thumbnail = `https://img.youtube.com/vi/${identifier}/hqdefault.jpg`;
|
||||
embed.setThumbnail(thumbnail);
|
||||
}
|
||||
.setDescription(`[${track.info.title}](${track.info.uri})`)
|
||||
.setFooter({ text: `Requested By: ${track.requesterId}` })
|
||||
.setThumbnail(track.info.artworkUrl);
|
||||
|
||||
fields.push({
|
||||
name: "Song Duration",
|
||||
value: "`" + prettyMs(song.length, { colonNotation: true }) + "`",
|
||||
value: "`" + prettyMs(track.info.length, { colonNotation: true }) + "`",
|
||||
inline: true,
|
||||
});
|
||||
|
||||
@ -80,7 +64,7 @@ module.exports = (client) => {
|
||||
|
||||
lavaclient.on("nodeQueueFinish", async (_node, queue) => {
|
||||
queue.data.channel.safeSend("Queue has ended.");
|
||||
await client.musicManager.destroyPlayer(queue.player.guildId).then(queue.player.disconnect());
|
||||
await client.musicManager.players.destroy(queue.player.guildId).then(() => queue.player.voice.disconnect());
|
||||
});
|
||||
|
||||
return lavaclient;
|
||||
|
@ -6,7 +6,7 @@ module.exports = class BotUtils {
|
||||
* Check if the bot is up to date
|
||||
*/
|
||||
static async checkForUpdates() {
|
||||
const response = await getJson("https://api.github.com/repos/MinazukiAmane/Kiera-Bot/releases/latest");
|
||||
const response = await getJson("https://git.serenetia.com/api/v1/repos/Serenetia/Kiera-Bot/releases/latest");
|
||||
if (!response.success) return error("VersionCheck: Failed to check for bot updates");
|
||||
if (response.data) {
|
||||
if (
|
||||
@ -15,7 +15,7 @@ module.exports = class BotUtils {
|
||||
success("VersionCheck: Your discord bot is up to date");
|
||||
} else {
|
||||
warn(`VersionCheck: ${response.data.tag_name} update is available`);
|
||||
warn("download: https://github.com/MinazukiAmane/Kiera-Bot/releases/latest");
|
||||
warn("download: https://git.serenetia.com/Serenetia/Kiera-Bot/releases/latest");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -63,7 +63,7 @@ module.exports = class BotUtils {
|
||||
static get musicValidations() {
|
||||
return [
|
||||
{
|
||||
callback: ({ client, guildId }) => client.musicManager.getPlayer(guildId),
|
||||
callback: ({ client, guildId }) => client.musicManager.players.resolve(guildId),
|
||||
message: "🚫 No music is being played!",
|
||||
},
|
||||
{
|
||||
@ -72,7 +72,7 @@ module.exports = class BotUtils {
|
||||
},
|
||||
{
|
||||
callback: ({ member, client, guildId }) =>
|
||||
member.voice?.channelId === client.musicManager.getPlayer(guildId)?.channelId,
|
||||
member.voice?.channelId === client.musicManager.players.resolve(guildId)?.voice.channelId,
|
||||
message: "🚫 You're not in the same voice channel.",
|
||||
},
|
||||
];
|
||||
|
@ -50,8 +50,8 @@ module.exports = class Validator {
|
||||
if (config.MUSIC.LAVALINK_NODES.length == 0) {
|
||||
warn("config.js: There must be at least one node for Lavalink");
|
||||
}
|
||||
if (!["YT", "YTM", "SC"].includes(config.MUSIC.DEFAULT_SOURCE)) {
|
||||
warn("config.js: MUSIC.DEFAULT_SOURCE must be either YT, YTM or SC");
|
||||
if (!["ytsearch", "ytmsearch", "spsearch", "scsearch"].includes(config.MUSIC.DEFAULT_SOURCE)) {
|
||||
warn("config.js: MUSIC.DEFAULT_SOURCE must be either ytsearch, ytmsearch, spsearch or scsearch");
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user