Fix correctness and robustness issues found in a full code review
Correctness: - MPD command reads no longer abandon a response half-way. The socket's 500 ms read timeout exists so the idle loop can poll the shutdown flag, but it applied to every read, so a slow reply left unread bytes that the next command parsed as its own. Add MpdConn::read_line/read_exact, which retry across that timeout up to a 15 s deadline, and a desynced flag that forces a reconnect when a read is genuinely abandoned. read_response now returns Option so a truncated reply is a failure rather than an empty result -- a timed-out currentsong used to look like "MPD is stopped". - resolve_cover returned a covers/<name> path even when the file was missing, so a deleted image produced a broken <img> instead of the placeholder. Gate the return value on the same existence check as the copy list. - enrich --force no longer runs DELETE FROM album_cache. That discarded pin-album entries, MPD-extracted cover paths, and any genre the re-fetch then failed to find. Select every album via all_scrobbled_albums and overwrite rows in place instead. - Album grouping, cover fallback and source attribution disagreed: the dominant_source subquery and artist_cover matched on album name alone, so two records sharing a title cross-contaminated. Extract one album_group_key_expr and use it everywhere. - Escape quotes and backslashes in MusicBrainz Lucene queries; a title containing a quote closed the term early and matched nothing. - Size the HTML cover grid from the period's own limit, so all-time no longer shows fewer covers than the table beneath it. - Fix a panic in the terminal report: top_genres ranks broad single-word genres last, so first() is not the busiest row, and a later genre with more plays overflowed the bar width. Scale to the true maximum and clamp the bar arithmetic. - Bound readpicture transfers by size and chunk count so a bogus size: header cannot drive an unbounded allocation or an endless loop. Robustness: - Kill the playerctl children before joining their reader threads. The threads block until stdout closes, which only happened because an interactive Ctrl+C signals the whole process group; under a supervisor that signals one PID, shutdown hung and left orphans. - Reject --limit and --all-time-limit below 1. SQLite reads a negative LIMIT as unlimited, silently dumping the whole library. - Set a 5 s busy_timeout, so running report against a live watch does not fail immediately with "database is locked". - Replace panics in default_db_path, covers_dir and the enrich queries with reported errors, and check PRAGMA table_info for the source column migration instead of discarding every ALTER TABLE error. Cleanups: - Collapse eight reset_*_timestamps functions into reset_retry_timestamps with a RetryScope enum. - Share one FNV-1a helper (enrich::cover_stem) between the MPD and iTunes filename generators. - Use params_from_iter to remove six duplicated query_map branches. - Extract source_dot_cell and reuse db::split_genre_list in the report. - Skip the genre lookup when only covers were requested, saving a request and a rate-limit sleep per album. - Keep the cached genre in pin-album when MusicBrainz returns nothing and a --cover-url was supplied.
This commit is contained in:
@@ -360,6 +360,11 @@ Use `--force` to re-fetch all albums from scratch (online pipeline only):
|
||||
scrbblr enrich --pipeline online --fetch all --force
|
||||
```
|
||||
|
||||
Note: `--force` revisits every scrobbled album and overwrites each cache row in
|
||||
place; it does not empty the cache first. An album whose re-fetch turns up
|
||||
nothing keeps the data it already had, so covers pinned with `pin-album` and
|
||||
covers extracted from MPD survive a forced run.
|
||||
|
||||
Genre normalisation notes:
|
||||
|
||||
- Genre labels are passed through from MusicBrainz with light cleanup only.
|
||||
|
||||
Reference in New Issue
Block a user