Skip to content

Local files: serve genre from tags and studio labels - #118

Merged
fnyaker merged 1 commit into
masterfrom
claude/blissful-cannon-q0ur8z
Oct 14, 2026
Merged

fnyaker merged 1 commit into
masterfrom
claude/blissful-cannon-q0ur8z

Conversation

@fnyaker

@fnyaker fnyaker commented Oct 14, 2026

Copy link
Copy Markdown
Owner

Extends the analysis API to serve genres for uploaded/local files using their own tags and studio-applied labels, bringing them to parity with Deezer tracks.

Summary

Local files (uploads, library imports) now have their genre served by the API just like Deezer tracks. The genre comes from three sources in priority order: studio tags (admin-applied), the file's own tags (what the uploader wrote), or nothing. This required changes across the analysis pipeline, the web player, and supporting infrastructure.

Key changes

Backend analysis & API:

  • supysonic/deezer/analysis.py: Added file_genre() to extract and normalize genre from a local file's tags, matching against studio tags and known vocabularies. Updated payload_for() to include file-sourced genres. Modified _decide_style() to use file genres as a fallback before heuristics.
  • supysonic/webui/analysis.py: Refactored _key() to handle both Deezer UUIDs and local file UUIDs uniformly. Updated _rows_for() to serve genres for local files with studio tags or file tags, and _queue_missing() to accept local file IDs.
  • supysonic/webui/__init__.py: Queue local file analysis on upload, like Deezer tracks.

Web player & analysis:

  • webapp/src/lib/analysis.js: Added MISS_TTL (5 min) for negative verdicts vs. VERDICT_TTL (24 hr) for positive ones. Added generation revalidation: when no request has been made for 30s, a track change asks for the generation alone to catch server-side label changes without re-asking cached tracks.
  • webapp/src/lib/audio/engine.js: Removed live classifier (liveRange always false) — the genre is now only the server's answer or nothing.
  • webapp/rhythm/src/style.rs & webapp/src/lib/audio/rhythm-core.js: Added classify flag to disable live family rules; when off, dominant is -1 and confidence 0.

Silence trimming refinement:

  • supysonic/webui/edges.py: Introduced MAX_EDGE_TRIM (10s) — quiet stretches longer than this are music, not edges. Silence in the middle of a track never moves bounds. Updated test expectations to reflect the new logic.
  • webapp/src/components/Player.svelte: Added validation that trim bounds don't exceed EDGE_MAX or apply to files of different length (re-archives).

UI & settings:

  • webapp/src/components/HardReload.svelte & webapp/src/lib/hardreload.js: New "reload from scratch" feature for Settings → Diagnostic, clearing device-learnt state (cached analyses, edges, glitch routes, look-ahead) while preserving login, settings, queue, and offline copies. Handles GPU crashes that leave WebGL unavailable.
  • webapp/src/components/VisualizerSettings.svelte: Integrated hard-reload button.
  • webapp/src/components/TrackRow.svelte: Fixed grid layout when album column is absent (phone-narrow side panel on desktop).

Deezer integration:

  • supysonic/deezer/provider.py & supysonic/deezer/importer.py: Added get_new_release_albums() and sync_new_albums() to import "Nouveautés pour toi" — the new-releases mix plus every new album whole, as one playlist.
  • deezerpy/gw.py: Added get_module_page() to fetch CMS module pages (e.g., the new-releases grid).

Config & tests:

  • config.sample, config/supysonic.conf.example, supysonic/config.py: Added import_new_albums option.
  • tests/test_webui.py: Updated upload test to verify analysis is queued; refined silence-trim tests.
  • tests/test_deezer.py: Added tests for new-album import.
  • `webapp/

https://claude.ai/code/session_01F5yXmv8AwwJ4dbUES2LiEJ

…trims, hard reload, new albums playlist

- The player's analyser no longer classifies anything (style.rs `classify`,
  off from engine.js): a served genre pins the family, none served means no
  genre. A client's ask is measured whatever heads exist.
- Local files (uploads, library files, YouTube rows) are asked about by their
  UUID: /api/analyses, /api/analysis/<id>, primeAnalyses and the tag sheet all
  dropped them, so an upload never had a genre, tagged or not. An upload is
  measured as it lands, and the genre written in a local file's tags is served
  (below a studio tag). A label moves the verdict generation, and a device
  whose queue is all cached checks it on a track change.
- Silence trimming only ever touches the edges: at most 10 s at either end,
  never past a decode that stopped short, and the player drops bounds measured
  on a file of another length.
- Réglages: "Recharger l'application de zéro" (unregisters the service worker,
  empties the shell cache, forgets device-learnt state, keeps settings,
  session and downloads); the animation settings say when WebGL was refused.
- "Nouveautés pour toi" en vrac: every new album, whole, in one local
  playlist "Deezer · Nouveautés en vrac" on each sync.
- Track rows lay out on their own width: in the full-screen player's side
  panel a title was left one letter wide.
- Nothing starts a background analysis under app.testing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F5yXmv8AwwJ4dbUES2LiEJ
@fnyaker
fnyaker merged commit a3beb3a into master Oct 14, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants