fix reordering

This commit is contained in:
2025-12-12 22:26:14 -08:00
parent 6ff150cfef
commit 706f277fd3
8 changed files with 473 additions and 58 deletions

View File

@@ -32,6 +32,7 @@ let currentState = {
position: 0,
volume: 100,
queue: [],
history: [],
shuffled: false
};
@@ -39,6 +40,7 @@ let connection = null;
let player = null;
let startTime = 0;
let currentResource = null;
const MAX_HISTORY = 50; // Keep last 50 tracks in history
// Discord client
const client = new Client({
@@ -75,7 +77,22 @@ function initializeQueue() {
}
// Play next track in queue
function playNext() {
function playNext(skipToNext = false) {
// When skipping manually, add current track to history
// When track finishes naturally, move current to end of queue (continuous loop)
if (currentState.currentTrack) {
if (skipToNext) {
// Manual skip - add to history for "previous" functionality
currentState.history.unshift(currentState.currentTrack);
if (currentState.history.length > MAX_HISTORY) {
currentState.history.pop();
}
} else {
// Natural finish - move to end of queue for continuous loop
currentState.queue.push(currentState.currentTrack);
}
}
if (currentState.queue.length === 0) {
logger.info('Queue empty, reloading library');
initializeQueue();
@@ -109,6 +126,43 @@ function playNext() {
}
}
// Play previous track from history
function playPrevious() {
if (currentState.history.length === 0) {
logger.info('No previous track in history');
return false;
}
// Put current track back at the front of the queue
if (currentState.currentTrack) {
currentState.queue.unshift(currentState.currentTrack);
}
// Get previous track from history
const track = currentState.history.shift();
currentState.currentTrack = track;
currentState.position = 0;
currentState.state = 'playing';
startTime = Date.now();
logger.info(`Playing previous track: ${track.title}`);
try {
currentResource = createAudioResource(track.filepath, {
inlineVolume: true
});
currentResource.volume.setVolume(currentState.volume / 100);
player.play(currentResource);
return true;
} catch (error) {
logger.error(`Error playing previous track: ${error.message}`);
currentResource = null;
// If previous track fails, continue to next
playNext();
return false;
}
}
// Connect to voice channel
async function connectToVoice() {
try {
@@ -177,10 +231,17 @@ app.get('/health', (req, res) => {
app.get('/state', (req, res) => {
const elapsed = currentState.state === 'playing' ? Math.floor((Date.now() - startTime) / 1000) : 0;
// Queue includes current track + remaining tracks
const fullQueue = currentState.currentTrack
? [currentState.currentTrack, ...currentState.queue]
: [...currentState.queue];
res.json({
...currentState,
position: currentState.position + elapsed,
queueLength: currentState.queue.length
queueLength: currentState.queue.length,
fullQueue: fullQueue
});
});
@@ -208,10 +269,58 @@ app.post('/pause', (req, res) => {
app.post('/skip', (req, res) => {
logger.info('Skipping to next track');
playNext();
// Move current track to end of queue instead of history
if (currentState.currentTrack) {
currentState.queue.push(currentState.currentTrack);
}
// Get next track from queue
if (currentState.queue.length > 0) {
const track = currentState.queue.shift();
currentState.currentTrack = track;
currentState.position = 0;
currentState.state = 'playing';
startTime = Date.now();
try {
currentResource = createAudioResource(track.filepath, {
inlineVolume: true
});
currentResource.volume.setVolume(currentState.volume / 100);
player.play(currentResource);
} catch (error) {
logger.error(`Error playing track: ${error.message}`);
currentResource = null;
}
}
res.json({ success: true });
});
app.post('/previous', (req, res) => {
logger.info('Playing previous track');
const success = playPrevious();
res.json({ success, hasHistory: currentState.history.length > 0 });
});
app.post('/seek', (req, res) => {
const { position } = req.body;
if (typeof position !== 'number' || position < 0) {
return res.status(400).json({ error: 'Invalid position' });
}
// Note: Discord.js voice doesn't support seeking within a track
// This would require re-creating the audio resource from the seek position
// For now, we'll return an error indicating this limitation
logger.warn('Seek requested but not supported by Discord.js voice');
res.status(501).json({
error: 'Seek not supported',
message: 'Discord.js voice library does not support seeking within tracks'
});
});
app.post('/volume', (req, res) => {
const { volume } = req.body;
if (volume >= 0 && volume <= 100) {
@@ -238,6 +347,70 @@ app.post('/queue/shuffle', (req, res) => {
res.json({ success: true, shuffled: currentState.shuffled });
});
app.post('/queue/reorder', (req, res) => {
const { from, to } = req.body;
// Full queue includes current track + remaining queue
const fullQueue = currentState.currentTrack
? [currentState.currentTrack, ...currentState.queue]
: [...currentState.queue];
if (typeof from !== 'number' || typeof to !== 'number' ||
from < 0 || to < 0 ||
from >= fullQueue.length || to >= fullQueue.length) {
return res.status(400).json({ error: 'Invalid indices' });
}
// Move the track
const [track] = fullQueue.splice(from, 1);
fullQueue.splice(to, 0, track);
// Update state: first track becomes current, rest becomes queue
if (fullQueue.length > 0) {
currentState.currentTrack = fullQueue[0];
currentState.queue = fullQueue.slice(1);
// If we moved the current track and it's playing, restart it
if (from === 0 && currentState.state === 'playing') {
currentState.position = 0;
startTime = Date.now();
try {
currentResource = createAudioResource(currentState.currentTrack.filepath, {
inlineVolume: true
});
currentResource.volume.setVolume(currentState.volume / 100);
player.play(currentResource);
} catch (error) {
logger.error(`Error replaying track: ${error.message}`);
}
}
}
logger.info(`Queue reordered: moved track from ${from} to ${to}`);
res.json({ success: true, queue: fullQueue });
});
app.post('/queue/add', (req, res) => {
const { trackId } = req.body;
if (!trackId) {
return res.status(400).json({ error: 'Track ID required' });
}
const library = loadMusicLibrary();
const track = library.find(t => t.id === trackId);
if (!track) {
return res.status(404).json({ error: 'Track not found' });
}
currentState.queue.push(track);
logger.info(`Added ${track.title} to queue`);
res.json({ success: true, queue: currentState.queue });
});
app.get('/channels', async (req, res) => {
try {
const guild = await client.guilds.fetch(DISCORD_GUILD_ID);