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.
pull/812/head
BoulderBadgeDad 5 days ago
parent e93357a385
commit ed38d60b18

@ -114,8 +114,13 @@ class MissingLyricsJob(RepairJob):
# Option A: only flag tracks LRClib actually has lyrics for. An
# instrumental returns nothing here and is silently skipped (never
# re-flagged on future scans).
# tracks.duration is stored in MILLISECONDS (schema) — LRClib's
# exact-match wants SECONDS, so convert (else exact-match never
# hits and it silently falls back to a fuzzier search).
try:
duration_s = int(duration) if duration else None
duration_s = int(int(duration) / 1000) if duration else None
if duration_s is not None and duration_s <= 0:
duration_s = None
except (TypeError, ValueError):
duration_s = None
try:

@ -112,6 +112,23 @@ def test_scan_flags_only_tracks_with_available_lyrics(tmp_path, monkeypatch):
assert findings[0]["details"]["track_title"] == "Song" # the instrumental was skipped
def test_scan_converts_duration_ms_to_seconds(tmp_path, monkeypatch):
# tracks.duration is milliseconds; LRClib wants seconds. The scan must
# convert before querying (215000ms → 215s) and store seconds in the finding.
t1 = tmp_path / "song.flac"; t1.write_bytes(b"x")
rows = [(1, "Song", "Artist", "Album", str(t1), 215000)] # 215000 ms = 215 s
seen = {}
fake_client = SimpleNamespace(
api=object(),
has_remote_lyrics=lambda title, artist, album, dur: seen.update(dur=dur) or True)
monkeypatch.setattr("core.lyrics_client.lyrics_client", fake_client)
findings = []
MissingLyricsJob().scan(_ctx(_DB(rows), findings))
assert seen["dur"] == 215 # converted to seconds
assert findings[0]["details"]["duration"] == 215
def test_scan_skips_tracks_that_already_have_lrc(tmp_path, monkeypatch):
t1 = tmp_path / "song.flac"; t1.write_bytes(b"x")
(tmp_path / "song.lrc").write_text("[00:01]hi") # already has lyrics

Loading…
Cancel
Save