Commit graph

3 commits

Author SHA1 Message Date
BoulderBadgeDad
ed38d60b18 Lyrics Filler: convert track duration ms→s for LRClib (exact-match was silently defeated)
Second lock-in catch: tracks.duration is stored in MILLISECONDS (schema), but
the scan passed it to LRClib as SECONDS. LRClib's exact-match-by-duration
strategy would never hit (215000s vs the real 215s), silently falling back to
the fuzzier title/artist search and storing the wrong duration in the finding.
Now divides by 1000 (guards against 0/garbage). Lyrics were still being found
via the fallback, so no track was missed — just less precise matching and a
wrong stored value. Test pins 215000ms → 215s.
2026-06-07 19:45:10 -07:00
BoulderBadgeDad
e93357a385 Lyrics retag: fetch query from a read-only lyrics_meta, never db_data (no tag pollution)
Lock-in pass caught a real bug in 1051ef24: the retag lyrics path stuffed the
library title/artist into a plan's db_data to feed the lyrics query — but
db_data is exactly what write_tags_to_file writes ("only writes fields that
have DB values"). So an UNMATCHED track (one with no source match, meant to
get art/lyrics only) would have had its title/artist tags overwritten from
the library values — an unintended tag write on a track we never verified.

Fix: each plan now carries a separate READ-ONLY lyrics_meta
({title, artist, album}) sourced from the library track + album scope, kept
entirely out of db_data. apply_track_plans reads lyrics_meta for the query
(db_data fallback for older plans); unmatched plans keep db_data={} so no tags
are written. _fix_library_retag threads lyrics_meta through the manual-apply
path too.

Tests: +1 regression pinning that an unmatched lyrics plan calls
write_tags_to_file with EMPTY db_data (no title/artist leak) while still
fetching lyrics. 70 lyrics/retag/repair tests pass.
2026-06-07 19:42:30 -07:00
BoulderBadgeDad
1051ef2402 Lyrics: add a "Lyrics Filler" maintenance job + lyrics option in the Re-tag tool (Sokhi)
The lyrics sibling of the Cover Art Filler, plus retag integration — reusing
the existing LyricsClient (LRClib) the import pipeline already uses.

- lyrics_client: extracted the LRClib fetch (exact-match-with-duration →
  search fallback) into a shared _fetch_remote_lyrics, used by both
  create_lrc_file (unchanged behavior) and a new check-only has_remote_lyrics.
- MissingLyricsJob (core/repair_jobs/missing_lyrics.py): scans tracks with no
  .lrc sidecar and — Option A — only flags ones LRClib actually has lyrics
  for, so instrumentals/interludes are never surfaced or re-flagged. Registered
  in the job list; default OFF; respects the lrclib_enabled toggle.
- _fix_missing_lyrics (repair_worker): applies a finding by fetching + writing
  the .lrc and embedding lyrics via create_lrc_file.
- Re-tag tool: new 'lyrics' setting ('fetch'|'skip', default skip). When
  'fetch', apply_track_plans now also fetches/refreshes the .lrc per track
  (fetch-if-missing, re-embed-if-exists) — threaded through scan gates, finding
  details, the auto-apply path, and the manual fix handler. Settings UI
  auto-renders the dropdown from setting_options; no markup needed.
- Frontend: type/action/result labels for missing_lyrics + a finding detail
  render case.

Tests: 12 — has_remote_lyrics truth table, sidecar detection, scan (only-
fixable / skip-existing / lrclib-disabled), the apply handler, and retag
lyrics_action on/off. 694 repair/lyrics/cover/retag tests pass.
2026-06-07 17:27:52 -07:00