27 lines
1.9 KiB
JavaScript
27 lines
1.9 KiB
JavaScript
// Server-authoritative queue. Votes belong to the participant id across reconnects.
|
|
export function createDJQueue() { return { enabled: false, entries: [], sequence: 0 }; }
|
|
export function queueSnapshot(queue) {
|
|
return { enabled: queue.enabled, entries: [...queue.entries].sort((a, b) => Number(b.approved) - Number(a.approved) || b.votes.size - a.votes.size || a.order - b.order).map(({ votes, order, ...entry }) => ({ ...entry, votes: [...votes] })) };
|
|
}
|
|
export function changeDJQueue(queue, message, participant, host) {
|
|
if (message.action === 'enable') { if (!host) return false; queue.enabled = !!message.enabled; return true; }
|
|
if (!queue.enabled) return false;
|
|
const entry = queue.entries.find(e => e.video.id === message.id);
|
|
if (message.action === 'suggest') {
|
|
const v = message.video; if (!v || !/^[A-Za-z0-9_-]{11}$/.test(v.id) || queue.entries.length >= 100 || queue.entries.some(e => e.video.id === v.id)) return false;
|
|
const clean = value => String(value || '').replace(/[\u0000-\u001f<>]/g, '').slice(0, 200);
|
|
queue.entries.push({ video: { id: v.id, title: clean(v.title) || v.id, channel: clean(v.channel), thumbnail: `/api/thumb/${v.id}` }, from: participant, approved: host, votes: new Set(), order: queue.sequence++ }); return true;
|
|
}
|
|
if (!entry) return false;
|
|
if (message.action === 'vote') { if (entry.votes.has(participant)) return false; entry.votes.add(participant); return true; }
|
|
if (!host) return false;
|
|
if (message.action === 'approve') { entry.approved = true; return true; }
|
|
if (message.action === 'remove') { queue.entries = queue.entries.filter(e => e !== entry); return true; }
|
|
return false;
|
|
}
|
|
export function takeDJVideo(queue) {
|
|
if (!queue.enabled) return null;
|
|
const next = queueSnapshot(queue).entries.find(e => e.approved); if (!next) return null;
|
|
queue.entries = queue.entries.filter(e => e.video.id !== next.video.id); return next.video;
|
|
}
|