Tell the screens when the playlist they are showing is deleted

devices.playlist_id is ON DELETE SET NULL, so the database detached correctly — but the handler
emitted nothing, so a screen kept displaying the deleted playlist until it happened to reconnect or
was restarted. You delete a playlist to take content off the wall; the wall carried on showing it.

Every sibling mutation in this file already pushes (publish, assign), and DELETE
/devices/:id/playlist was given a push for precisely this reason: "so the screen stops, rather than
leaving the old content up until something else happens to update it".

The affected devices are read before the delete, since the association is gone the moment it runs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL
This commit is contained in:
Claude 2026-07-30 21:50:50 -05:00
parent 9ea1b5e07b
commit 4a65c4cec7

View file

@ -339,7 +339,28 @@ router.post('/:id/discard', requirePlaylistWrite, (req, res) => {
// Delete playlist
router.delete('/:id', requirePlaylistWrite, (req, res) => {
// Which screens are about to lose their playlist — read BEFORE the delete, because
// devices.playlist_id is ON DELETE SET NULL and the association is gone immediately after.
const affected = db.prepare('SELECT id FROM devices WHERE playlist_id = ?').all(req.params.id);
db.prepare('DELETE FROM playlists WHERE id = ?').run(req.params.id);
// Tell them. The database detaches correctly, but nothing was emitted — so a screen kept showing
// the deleted playlist until it happened to reconnect or was restarted. You delete a playlist to
// take content off the wall; the wall carried on regardless. Every sibling mutation here already
// pushes (publish, assign), and DELETE /devices/:id/playlist was given a push for exactly this
// reason: "so the screen stops, rather than leaving the old content up".
try {
const io = req.app.get('io');
if (io) {
const { buildPlaylistPayload } = require('../ws/deviceSocket');
const commandQueue = require('../lib/command-queue');
for (const d of affected) {
commandQueue.queueOrEmitPlaylistUpdate(io.of('/device'), d.id, buildPlaylistPayload);
}
}
} catch (e) { /* best-effort; the heartbeat refresh still picks it up */ }
res.json({ success: true });
});