mirror of
https://github.com/screentinker/screentinker.git
synced 2026-05-15 07:32:23 -06:00
Phase 2: playlists API returns display_count, is_auto_generated + assign endpoint
List and detail endpoints now include display_count (devices using this playlist). New POST /:id/assign endpoint sets a playlist on a device and pushes the update. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
33a5be39ed
commit
6f01d319f5
|
|
@ -44,9 +44,10 @@ function requirePlaylistOwnership(req, res, next) {
|
||||||
// List playlists
|
// List playlists
|
||||||
router.get('/', (req, res) => {
|
router.get('/', (req, res) => {
|
||||||
const playlists = db.prepare(`
|
const playlists = db.prepare(`
|
||||||
SELECT p.*, COUNT(pi.id) as item_count
|
SELECT p.*, COUNT(DISTINCT pi.id) as item_count, COUNT(DISTINCT d.id) as display_count
|
||||||
FROM playlists p
|
FROM playlists p
|
||||||
LEFT JOIN playlist_items pi ON p.id = pi.playlist_id
|
LEFT JOIN playlist_items pi ON p.id = pi.playlist_id
|
||||||
|
LEFT JOIN devices d ON d.playlist_id = p.id
|
||||||
WHERE p.user_id = ?
|
WHERE p.user_id = ?
|
||||||
GROUP BY p.id
|
GROUP BY p.id
|
||||||
ORDER BY p.name ASC
|
ORDER BY p.name ASC
|
||||||
|
|
@ -62,7 +63,7 @@ router.post('/', (req, res) => {
|
||||||
db.prepare('INSERT INTO playlists (id, user_id, name, description) VALUES (?, ?, ?, ?)')
|
db.prepare('INSERT INTO playlists (id, user_id, name, description) VALUES (?, ?, ?, ?)')
|
||||||
.run(id, req.user.id, name.trim(), (description || '').trim());
|
.run(id, req.user.id, name.trim(), (description || '').trim());
|
||||||
res.status(201).json(db.prepare(`
|
res.status(201).json(db.prepare(`
|
||||||
SELECT p.*, 0 as item_count FROM playlists p WHERE p.id = ?
|
SELECT p.*, 0 as item_count, 0 as display_count FROM playlists p WHERE p.id = ?
|
||||||
`).get(id));
|
`).get(id));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -80,7 +81,8 @@ router.get('/:id', requirePlaylistOwnership, (req, res) => {
|
||||||
WHERE pi.playlist_id = ?
|
WHERE pi.playlist_id = ?
|
||||||
ORDER BY pi.sort_order ASC
|
ORDER BY pi.sort_order ASC
|
||||||
`).all(req.params.id);
|
`).all(req.params.id);
|
||||||
res.json({ ...req.playlist, items, item_count: items.length });
|
const displayCount = db.prepare('SELECT COUNT(*) as count FROM devices WHERE playlist_id = ?').get(req.params.id).count;
|
||||||
|
res.json({ ...req.playlist, items, item_count: items.length, display_count: displayCount });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update playlist
|
// Update playlist
|
||||||
|
|
@ -276,4 +278,29 @@ router.post('/:id/items/reorder', requirePlaylistOwnership, (req, res) => {
|
||||||
res.json(items);
|
res.json(items);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Assign playlist to a device
|
||||||
|
router.post('/:id/assign', requirePlaylistOwnership, (req, res) => {
|
||||||
|
const { device_id } = req.body;
|
||||||
|
if (!device_id) return res.status(400).json({ error: 'device_id required' });
|
||||||
|
|
||||||
|
const device = db.prepare('SELECT id, user_id FROM devices WHERE id = ?').get(device_id);
|
||||||
|
if (!device) return res.status(404).json({ error: 'Device not found' });
|
||||||
|
if (!['admin', 'superadmin'].includes(req.user.role) && device.user_id !== req.user.id) {
|
||||||
|
return res.status(403).json({ error: 'Device not owned by you' });
|
||||||
|
}
|
||||||
|
|
||||||
|
db.prepare('UPDATE devices SET playlist_id = ? WHERE id = ?').run(req.params.id, device_id);
|
||||||
|
|
||||||
|
// Push update to device
|
||||||
|
try {
|
||||||
|
const io = req.app.get('io');
|
||||||
|
if (io) {
|
||||||
|
const { buildPlaylistPayload } = require('../ws/deviceSocket');
|
||||||
|
io.of('/device').to(device_id).emit('device:playlist-update', buildPlaylistPayload(device_id));
|
||||||
|
}
|
||||||
|
} catch (e) { /* silent */ }
|
||||||
|
|
||||||
|
res.json({ success: true });
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue