34 Commits

Author SHA1 Message Date
33d83618dc 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.
2026-07-25 23:19:21 +01:00
23ef54555e Filter domain-like garbage out of genres
MusicBrainz community tags sometimes carry review-site domain names
(e.g. "musikexpress.de", "rollingstone.de") that leaked into the genre
field. Add a shared looks_like_url predicate and apply it at ingestion
(is_genre_tag, pick_genre_string) and at report read-time
(split_genre_list, top_genre_labels) so both new and already-cached
garbage are dropped.
2026-06-29 17:21:11 +01:00
f6e1a6d4ea Format long listen times in days and center the pin dot 2026-06-09 20:35:40 +01:00
8dd316f6ae Restore source dots in dedicated report columns 2026-03-24 08:24:22 +00:00
4ccd310667 Improve report source column and mobile table layout 2026-03-23 23:08:31 +00:00
275449d6d7 Refactor enrich CLI into pipeline, fetch, and retry modes 2026-03-23 22:52:01 +00:00
02ff0b4c97 Fix incomplete MPD cover transfers, add cover revalidation, and allow retrying missing MPD genres 2026-03-23 22:33:45 +00:00
6e0432490a Some checks just to be safe + link to the project 2026-03-23 21:08:36 +00:00
d199abdc68 Cover repair for MPD 2026-03-23 19:37:48 +00:00
ed5682c887 Various issues including cover issues with MPD (corrupted/incomplete files) 2026-03-23 19:34:11 +00:00
c0295e79cc Bug fix for repeated scrobbles when track might be paused; more tests for the MPD route 2026-03-22 22:34:53 +00:00
10f3162b31 Clean-up 2026-03-22 19:56:47 +00:00
5bb968e255 README update 2026-03-22 19:55:23 +00:00
20d6861e66 Add GitHub Actions workflow for Rust projects 2026-03-22 19:46:14 +00:00
201604f37b Formatting on mobile, again 2026-03-22 19:39:39 +00:00
e07ce75bd5 Report on mobile: readability improvement & bar graph 2026-03-22 18:47:21 +00:00
db7024ab93 Colours for tracks 2026-03-22 13:10:08 +00:00
dcfd20b196 Adjusted colours 2026-03-22 13:01:29 +00:00
2668f7408d Listen source colouring 2026-03-22 12:59:37 +00:00
aaa1580c49 Genre priorities for album covers section 2026-03-22 12:38:57 +00:00
6c240b0dc9 Genre priorities 2026-03-22 12:34:53 +00:00
a7f09d8dee Unused function & pointless test 2026-03-22 12:31:11 +00:00
8580c8695b Use iTunes as the preferred default for covers 2026-03-22 12:25:44 +00:00
ba413ec03b Avoid fetching covers via MPD if it definitely does not have them 2026-03-22 12:21:48 +00:00
d1a1f9bca5 Enrichment logic fixes 2026-03-22 12:17:57 +00:00
1976df2f52 Alternative source for covers 2026-03-22 11:30:45 +00:00
b9dbd17e24 Now we also record the scrobble source 2026-03-22 09:39:16 +00:00
10483822ee Renaming to scrbblr 2026-03-22 08:46:09 +00:00
291b77c96d Covers via MPD 2026-03-21 23:50:49 +00:00
963aa4938b Covers via MPD 2026-03-21 23:40:52 +00:00
d19920a978 Clean-up 2026-03-21 23:23:15 +00:00
05d7730a01 MPD module 2026-03-21 23:16:16 +00:00
b6982eb76a Support for MPD 2026-03-21 23:15:55 +00:00
24df1854f5 The beginning of something great 2026-03-20 20:00:10 +00:00