save tracks and queue

to add new added tracks and queue to the database so it can continue playing, when the node disconnected or crashed.

still not tested yet
This commit is contained in:
Amane Serenetia 2025-01-04 02:43:50 +07:00
parent 0bf035c71f
commit 2f0c2c387c
7 changed files with 151 additions and 0 deletions

View File

@ -1,5 +1,6 @@
const { EmbedBuilder, ApplicationCommandOptionType } = require("discord.js"); const { EmbedBuilder, ApplicationCommandOptionType } = require("discord.js");
const { EMBED_COLORS, MUSIC } = require("@root/config"); const { EMBED_COLORS, MUSIC } = require("@root/config");
const Queue = require("@src/database/schemas/Queue");
/** /**
* @type {import("@structures/Command")} * @type {import("@structures/Command")}
@ -118,6 +119,8 @@ async function play({ member, guild, channel }, searchQuery, source) {
case "playlist": { case "playlist": {
player.queue.add(res.tracks); player.queue.add(res.tracks);
await saveQueueToDatabase(player);
const playlistEmbed = new EmbedBuilder() const playlistEmbed = new EmbedBuilder()
.setAuthor({ name: "Added Playlist to queue" }) .setAuthor({ name: "Added Playlist to queue" })
.setThumbnail(res.playlist.thumbnail) .setThumbnail(res.playlist.thumbnail)
@ -148,6 +151,8 @@ async function play({ member, guild, channel }, searchQuery, source) {
const track = res.tracks[0]; const track = res.tracks[0];
player.queue.add(track); player.queue.add(track);
await saveQueueToDatabase(player);
const trackEmbed = new EmbedBuilder() const trackEmbed = new EmbedBuilder()
.setAuthor({ name: "Added Track to queue" }) .setAuthor({ name: "Added Track to queue" })
.setColor(EMBED_COLORS.BOT_EMBED) .setColor(EMBED_COLORS.BOT_EMBED)
@ -184,3 +189,28 @@ async function play({ member, guild, channel }, searchQuery, source) {
return "🚫 An error occurred while searching for the song"; return "🚫 An error occurred while searching for the song";
} }
} }
// Function to save the current queue and track to the database
async function saveQueueToDatabase(player) {
const queueData = {
guildId: player.guildId,
tracks: player.queue.tracks.map(track => ({
title: track.info.title,
uri: track.info.uri,
duration: track.info.duration,
requester: track.requester.id,
})),
currentTrack: player.queue.current ? {
title: player.queue.current.info.title,
uri: player.queue.current.info.uri,
duration: player.queue.current.info.duration,
requester: player.queue.current.requester.id,
} : null,
};
await Queue.findOneAndUpdate(
{ guildId: player.guildId },
queueData,
{ upsert: true, new: true }
);
}

View File

@ -6,6 +6,7 @@ const {
ComponentType, ComponentType,
} = require("discord.js"); } = require("discord.js");
const { EMBED_COLORS, MUSIC } = require("@root/config"); const { EMBED_COLORS, MUSIC } = require("@root/config");
const Queue = require("@src/database/schemas/Queue");
/** /**
* @type {import("@structures/Command")} * @type {import("@structures/Command")}
@ -161,6 +162,9 @@ async function search({ member, guild, channel }, query, source) {
const selectedTrack = results[response.values[0]]; const selectedTrack = results[response.values[0]];
player.queue.add(selectedTrack); player.queue.add(selectedTrack);
// Save the current state to the database
await saveQueueToDatabase(player);
const trackEmbed = new EmbedBuilder() const trackEmbed = new EmbedBuilder()
.setAuthor({ name: "Added Track to queue" }) .setAuthor({ name: "Added Track to queue" })
.setDescription(`[${selectedTrack.info.title}](${selectedTrack.info.uri})`) .setDescription(`[${selectedTrack.info.title}](${selectedTrack.info.uri})`)
@ -183,3 +187,28 @@ async function search({ member, guild, channel }, query, source) {
return "🚫 Failed to register your response"; return "🚫 Failed to register your response";
} }
} }
// Function to save the current queue and track to the database
async function saveQueueToDatabase(player) {
const queueData = {
guildId: player.guildId,
tracks: player.queue.tracks.map(track => ({
title: track.info.title,
uri: track.info.uri,
duration: track.info.duration,
requester: track.requester.id,
})),
currentTrack: player.queue.current ? {
title: player.queue.current.info.title,
uri: player.queue.current.info.uri,
duration: player.queue.current.info.duration,
requester: player.queue.current.requester.id,
} : null,
};
await Queue.findOneAndUpdate(
{ guildId: player.guildId },
queueData,
{ upsert: true, new: true }
);
}

View File

@ -0,0 +1,21 @@
const mongoose = require("mongoose");
const queueSchema = new mongoose.Schema({
guildId: { type: String, required: true, unique: true },
tracks: [
{
title: String,
uri: String,
duration: Number,
requester: String,
},
],
currentTrack: {
title: String,
uri: String,
duration: Number,
requester: String,
},
});
module.exports = mongoose.model("Queue", queueSchema);

View File

@ -1,7 +1,32 @@
const Queue = require("@src/database/schemas/Queue");
module.exports = async (client, player) => { module.exports = async (client, player) => {
const guild = client.guilds.cache.get(player.guildId); const guild = client.guilds.cache.get(player.guildId);
if (!guild) return; if (!guild) return;
// Save the current track and queue to the database
const queueData = {
guildId: player.guildId,
tracks: player.queue.tracks.map(track => ({
title: track.info.title,
uri: track.info.uri,
duration: track.info.duration,
requester: track.requester.id,
})),
currentTrack: player.queue.current ? {
title: player.queue.current.info.title,
uri: player.queue.current.info.uri,
duration: player.queue.current.info.duration,
requester: player.queue.current.requester.id,
} : null,
};
await Queue.findOneAndUpdate(
{ guildId: player.guildId },
queueData,
{ upsert: true, new: true }
);
if (player.voiceChannelId) { if (player.voiceChannelId) {
await client.utils.setVoiceStatus(client, player.voiceChannelId, ""); await client.utils.setVoiceStatus(client, player.voiceChannelId, "");
} }

View File

@ -1,5 +1,6 @@
const { MUSIC, EMBED_COLORS } = require("@root/config"); const { MUSIC, EMBED_COLORS } = require("@root/config");
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require("discord.js");
const Queue = require("@src/database/schemas/Queue");
module.exports = async (client, player) => { module.exports = async (client, player) => {
const guild = client.guilds.cache.get(player.guildId); const guild = client.guilds.cache.get(player.guildId);
@ -27,4 +28,7 @@ module.exports = async (client, player) => {
10 10
); );
} }
// Clean up the queue from the database if all tracks are played
await Queue.deleteOne({ guildId: player.guildId });
}; };

View File

@ -1,5 +1,6 @@
const { autoplayFunction } = require("@handlers/player"); const { autoplayFunction } = require("@handlers/player");
const { MUSIC } = require("@root/config.js"); const { MUSIC } = require("@root/config.js");
const Queue = require("@src/database/schemas/Queue");
module.exports = async (client, player, track) => { module.exports = async (client, player, track) => {
const guild = client.guilds.cache.get(player.guildId); const guild = client.guilds.cache.get(player.guildId);
@ -14,6 +15,18 @@ module.exports = async (client, player, track) => {
await msg.delete().catch(() => {}); await msg.delete().catch(() => {});
} }
// Check if the current track was saved in the database
const queueData = await Queue.findOne({ guildId: player.guildId });
// Remove the current track from the database after it has been played
if (queueData) {
const updatedTracks = queueData.tracks.filter(t => t.uri !== track.info.uri);
await Queue.updateOne(
{ guildId: player.guildId },
{ tracks: updatedTracks, currentTrack: null }
);
}
if (player.get("autoplay") === true) { if (player.get("autoplay") === true) {
await autoplayFunction(client, track, player); await autoplayFunction(client, track, player);
} }

View File

@ -1,10 +1,39 @@
const { EmbedBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder } = require("discord.js"); const { EmbedBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder } = require("discord.js");
const { EMBED_COLORS } = require("@root/config"); const { EMBED_COLORS } = require("@root/config");
const Queue = require("@src/database/schemas/Queue");
module.exports = async (client, player, track) => { module.exports = async (client, player, track) => {
const guild = client.guilds.cache.get(player.guildId); const guild = client.guilds.cache.get(player.guildId);
if (!guild) return; if (!guild) return;
// Check if the queue exists in the database
const queueData = await Queue.findOne({ guildId: player.guildId });
if (queueData) {
// Restore the queue
player.queue.add(queueData.tracks.map(track => ({
info: {
title: track.title,
uri: track.uri,
duration: track.duration,
},
requester: { id: track.requester },
})));
if (queueData.currentTrack) {
player.queue.current = {
info: {
title: queueData.currentTrack.title,
uri: queueData.currentTrack.uri,
duration: queueData.currentTrack.duration,
},
requester: { id: queueData.currentTrack.requester },
};
}
// Clear the database entry after restoring
await Queue.deleteOne({ guildId: player.guildId });
}
if (!player.textChannelId || !track) return; if (!player.textChannelId || !track) return;
const channel = guild.channels.cache.get(player.textChannelId); const channel = guild.channels.cache.get(player.textChannelId);