From 377a6954e369c19dbec0fcd3096819ea0467e980 Mon Sep 17 00:00:00 2001 From: Honey Date: Thu, 21 May 2026 08:45:16 +0200 Subject: [PATCH] fix: radio mode uses getSimilarSongs2 for artist/genre-aware playback - Dedup now checks only the last 50 queued songs instead of the entire queue, so the radio doesn't stall on small libraries once every similar song has been seen - If every candidate is a recent duplicate (tiny library), allow up to 5 repeats rather than returning empty and letting the queue run dry - Add second _queueGen guard after the getRandomSongs fallback await Co-Authored-By: Claude Sonnet 4.6 --- src/player.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/player.js b/src/player.js index 27607ce..3fdd34b 100644 --- a/src/player.js +++ b/src/player.js @@ -641,22 +641,31 @@ export async function fillRadioQueue() { try { const seed = S.queue[S.qIdx]; let newSongs = []; + + // 1. Try similar songs seeded from the current track if (seed?.id) { const r = await api('getSimilarSongs2', `&id=${seed.id}&count=20`); newSongs = r.similarSongs2?.song || []; } - // Fall back to random if similar songs unavailable (no Last.fm config, unknown track, etc.) + if (gen !== _queueGen) return; + + // 2. Fall back to random if similar songs unavailable or empty if (!newSongs.length) { const r = await api('getRandomSongs', '&size=20'); newSongs = r.randomSongs?.song || []; } - // Bail if playQueue() was called while we were awaiting — appending to a - // replaced queue would desync native (setQueue already wiped the old one). if (gen !== _queueGen) return; - // Deduplicate against songs already queued - const existingIds = new Set(S.queue.map(s => s.id)); - newSongs = newSongs.filter(s => !existingIds.has(s.id)); if (!newSongs.length) return; + + // Deduplicate only against the last 50 queued songs so the radio never + // stalls on a small library. Songs cycle back after ~50 tracks rather than + // blocking forever once they've been seen once. + const recentIds = new Set(S.queue.slice(-50).map(s => s.id)); + const deduped = newSongs.filter(s => !recentIds.has(s.id)); + // If every candidate was a recent duplicate (very small library), allow + // repeats rather than letting the queue run dry and music stop. + newSongs = deduped.length > 0 ? deduped : newSongs.slice(0, 5); + const prevLen = S.queue.length; S.queue.push(...newSongs); renderQueue();