dev/playlists #13
38
channel.ts
38
channel.ts
|
|
@ -305,6 +305,44 @@ export class Channel {
|
|||
this.broadcast();
|
||||
}
|
||||
|
||||
moveTracks(indices: number[], targetIndex: number) {
|
||||
if (indices.length === 0) return;
|
||||
|
||||
// Get the tracks being moved
|
||||
const sorted = [...indices].sort((a, b) => a - b);
|
||||
const tracksToMove = sorted.map(i => this.queue[i]).filter(Boolean);
|
||||
if (tracksToMove.length === 0) return;
|
||||
|
||||
const currentTrackId = this.currentTrack?.id;
|
||||
|
||||
// Remove tracks from their current positions (from end to preserve indices)
|
||||
for (let i = sorted.length - 1; i >= 0; i--) {
|
||||
this.queue.splice(sorted[i], 1);
|
||||
}
|
||||
|
||||
// Adjust target index for removed items that were before it
|
||||
let adjustedTarget = targetIndex;
|
||||
for (const idx of sorted) {
|
||||
if (idx < targetIndex) adjustedTarget--;
|
||||
}
|
||||
|
||||
// Insert at new position
|
||||
this.queue.splice(adjustedTarget, 0, ...tracksToMove);
|
||||
|
||||
// Update currentIndex to follow the currently playing track
|
||||
if (currentTrackId) {
|
||||
const newIndex = this.queue.findIndex(t => t.id === currentTrackId);
|
||||
if (newIndex !== -1) {
|
||||
this.currentIndex = newIndex;
|
||||
}
|
||||
}
|
||||
|
||||
this.queueDirty = true;
|
||||
this.persistQueue();
|
||||
this.persistState();
|
||||
this.broadcast();
|
||||
}
|
||||
|
||||
broadcast() {
|
||||
const now = Date.now();
|
||||
const includeQueue = this.queueDirty || (now - this.lastQueueBroadcast >= 60000);
|
||||
|
|
|
|||
|
|
@ -276,6 +276,7 @@
|
|||
|
||||
// Drag start/end handlers - library always, queue/playlist with permissions
|
||||
const canDrag = type === 'library' || (type === 'queue' && canEditQueue) || (type === 'playlist' && isPlaylistOwner);
|
||||
console.log(`[Drag] wireTrackEvents: type=${type} canDrag=${canDrag} canEditQueue=${canEditQueue}`);
|
||||
if (canDrag) {
|
||||
div.ondragstart = (e) => handleDragStart(e, track, originalIndex, div);
|
||||
div.ondragend = (e) => handleDragEnd(e, div);
|
||||
|
|
@ -283,6 +284,7 @@
|
|||
|
||||
// Drop handlers - queue and playlist accept drops
|
||||
if (canEditQueue && type === 'queue') {
|
||||
console.log(`[Drag] Wiring drop handlers for queue track ${originalIndex}`);
|
||||
div.ondragover = (e) => handleDragOver(e, div, originalIndex);
|
||||
div.ondragleave = (e) => handleDragLeave(e, div);
|
||||
div.ondrop = (e) => handleDrop(e, div, originalIndex);
|
||||
|
|
@ -339,6 +341,7 @@
|
|||
}
|
||||
|
||||
function handleDragStart(e, track, index, div) {
|
||||
console.log(`[Drag] handleDragStart: type=${type} index=${index} track=${track.title || track.filename}`);
|
||||
isDragging = true;
|
||||
const trackId = track.id || track.filename;
|
||||
dragSource = type;
|
||||
|
|
@ -415,20 +418,28 @@
|
|||
}
|
||||
|
||||
function handleDrop(e, div, index) {
|
||||
console.log(`[Drag] handleDrop: type=${type} index=${index} dropTargetIndex=${dropTargetIndex} dragSource=${dragSource} draggedIndices=${draggedIndices}`);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
div.classList.remove("drop-above", "drop-below");
|
||||
element.classList.remove("drop-target");
|
||||
|
||||
if (dropTargetIndex === null) return;
|
||||
if (dropTargetIndex === null) {
|
||||
console.log(`[Drag] handleDrop: dropTargetIndex is null, aborting`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === 'queue') {
|
||||
if (dragSource === 'queue' && draggedIndices.length > 0) {
|
||||
// Reorder within queue
|
||||
const minDragged = Math.min(...draggedIndices);
|
||||
const maxDragged = Math.max(...draggedIndices);
|
||||
console.log(`[Drag] Reorder check: dropTargetIndex=${dropTargetIndex} minDragged=${minDragged} maxDragged=${maxDragged}`);
|
||||
if (dropTargetIndex < minDragged || dropTargetIndex > maxDragged + 1) {
|
||||
console.log(`[Drag] Calling reorderQueue(${draggedIndices}, ${dropTargetIndex})`);
|
||||
reorderQueue(draggedIndices, dropTargetIndex);
|
||||
} else {
|
||||
console.log(`[Drag] Skipping reorder - dropping on self`);
|
||||
}
|
||||
} else if ((dragSource === 'library' || dragSource === 'playlist') && draggedTrackIds.length > 0) {
|
||||
// Insert tracks from library or playlist
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ export async function handleModifyQueue(req: Request, server: any, channelId: st
|
|||
|
||||
try {
|
||||
const body = await req.json();
|
||||
const { add, remove, set, insertAt } = body;
|
||||
const { add, remove, set, insertAt, move, to } = body;
|
||||
|
||||
if (Array.isArray(set)) {
|
||||
const tracks = buildTracksFromIds(set, state.library);
|
||||
|
|
@ -229,6 +229,12 @@ export async function handleModifyQueue(req: Request, server: any, channelId: st
|
|||
return Response.json({ success: true, queueLength: channel.queue.length });
|
||||
}
|
||||
|
||||
// Move/reorder tracks within queue
|
||||
if (Array.isArray(move) && typeof to === "number") {
|
||||
channel.moveTracks(move, to);
|
||||
return Response.json({ success: true, queueLength: channel.queue.length });
|
||||
}
|
||||
|
||||
if (Array.isArray(remove) && remove.length > 0) {
|
||||
const indices = remove.filter((i: unknown) => typeof i === "number");
|
||||
channel.removeTracksByIndex(indices);
|
||||
|
|
|
|||
Loading…
Reference in New Issue