mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-08-11 03:09:57 +00:00
fix(v3): decode stats:recorded filename so post-play score badge refreshes (#620)
PR #574 added a `stats:recorded` -> in-place accuracy-badge repaint so a just-earned score shows without restarting the app. But the repaint never matched a card, so the badge stayed stale until a full render() (app restart / search / re-enter the screen) -- exactly the "only updates after a restart" report. Root cause is a filename key-space mismatch. The event (like song:loading) carries the filename `encodeURIComponent`'d, because that is what playCard hands to playSong (the highway WS decodeURIComponent's it). Library cards, though, key on the DECODED localFilename (data-fn), and /api/stats/best is server-canonicalized to that same decoded key (server.py _canonical_song_filename). So repaintAccuracy's `data-fn !== key` check rejected every card and `state.accuracy[encoded]` was undefined. Decode the event filename back into the card / state.accuracy key space via a small `decFn` helper before marking dirty and repainting, fixing both the immediate repaint and the onV3SongsScreenEnter deferred path. decFn is idempotent for already-decoded names and falls back to the original on malformed input, so a real filename containing a literal '%' is never corrupted. Tests: tests/js/v3_songs_score_badge_refresh.test.js extracts the real decFn from the shipped source and proves the encoded event filename round-trips to the raw card key (incl. spaces and subfolder '/'). Claude-Session: https://claude.ai/code/session_01QbexxfTt8q2tAn436MqGWF Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: byrongamatos <xasiklas@gmail.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
byrongamatos
parent
fef870047b
commit
ee7bafbb47
+21
-1
@@ -15,6 +15,20 @@
|
||||
const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => (
|
||||
{ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
|
||||
const enc = encodeURIComponent;
|
||||
// Inverse of `enc` for matching a played song's filename back to a library
|
||||
// card. The `stats:recorded` event (like `song:loading`) carries the
|
||||
// filename exactly as it was handed to `playSong` — i.e. encodeURIComponent'd
|
||||
// (see `playCard`, and the highway WS which decodeURIComponent's it). But
|
||||
// cards key on the DECODED library filename (`cardKey` → `localFilename`),
|
||||
// and `/api/stats/best` is server-canonicalized to that same decoded key, so
|
||||
// an encoded filename matches no card and the post-play badge repaint silently
|
||||
// no-ops. Decode to land in the card/`state.accuracy` key space. Idempotent
|
||||
// for already-decoded names (no '%'); on malformed input falls back to the
|
||||
// original so a real filename containing a literal '%' is never corrupted.
|
||||
function decFn(fn) {
|
||||
if (typeof fn !== 'string' || fn.indexOf('%') === -1) return fn || '';
|
||||
try { return decodeURIComponent(fn); } catch (_) { return fn; }
|
||||
}
|
||||
|
||||
const SORTS = [
|
||||
['artist', 'Artist A–Z'], ['artist-desc', 'Artist Z–A'],
|
||||
@@ -1173,7 +1187,13 @@
|
||||
// If the library is visible right now, repaint immediately; otherwise
|
||||
// mark it dirty and onV3SongsScreenEnter applies it on return.
|
||||
sm.on('stats:recorded', (e) => {
|
||||
const fn = e && e.detail && e.detail.filename;
|
||||
// Decode to the library-card key space — the event carries the
|
||||
// encodeURIComponent'd filename, but cards (data-fn) and
|
||||
// state.accuracy key on the decoded library filename. Without this
|
||||
// the repaint below (and applyScoreRefresh's repaintAccuracy) match
|
||||
// no card, so a just-earned score stays invisible until a full
|
||||
// render() (restart / search / re-enter), which is this bug.
|
||||
const fn = decFn(e && e.detail && e.detail.filename);
|
||||
if (!fn) return;
|
||||
_dirtyScores.add(fn);
|
||||
// Only repaint now if the library is the active screen; otherwise
|
||||
|
||||
Reference in New Issue
Block a user