v0.1.1: perf timings + single-save tag writes + coalesced browser rebuild

Diagnosing the Ctrl+I save hang on the Debian machine (GUI thread blocks
past mutter's 5s check-alive):

- lintunes/perf.py: timed() context manager logging wall-clock ms at INFO
  on lintunes.perf — instruments tag/artwork saves, file moves,
  edit_track(s)_fields, the browser rebuild, smart recompute, and the
  debounced JSON flush, so the slow machine can tell us which stage
  eats the time (journalctl --user or a terminal run).
- tagging.write_tags: ONE parse + ONE save per edit. grouping/
  compilation/bpm ride the main save via registered Easy keys
  (GRP1/TCMP/TBPM on EasyID3, cpil on EasyMP4) instead of
  _write_extra_tags re-parsing and re-saving the audio file.
- LibraryView: browser rebuilds coalesce through a 0ms single-shot
  timer — an N-track Get Info edit rebuilds the genre/artist/album
  cascade once instead of N times over the whole library.

Moving the writes off the GUI thread is deliberately deferred until the
Debian timings say which stage dominates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 18:25:56 -04:00
parent 2d02ccefd6
commit 332b47a018
7 changed files with 325 additions and 100 deletions

View File

@ -3,7 +3,33 @@
Legend: `[ ]` todo · `[~]` in progress · `[x]` done.
When a round closes, move its finished items to `tasks-done.md`.
## Round 19 (current) — version display, git self-update, BPM fix
## Round 20 (current) — Ctrl+I save hang on the Debian machine (v0.1.1)
Plan reference: `~/.claude/plans/i-m-having-some-trouble-eager-gosling.md`.
Tests in `tests/test_round20.py`. Fix-only round → patch bump **0.1.1**.
Background: on the Debian machine, OK in Get Info froze the GUI thread past
mutter's ~5 s check-alive → "Force Quit / Wait" dialog. Happens on
single-track edits. Whole save path is synchronous on the GUI thread.
- [x] Perf instrumentation: new `lintunes/perf.py` (`timed()` context
manager, INFO on the `lintunes.perf` logger → stderr/journal). Times
tag saves, artwork saves, file moves, edit_track(s)_fields, browser
rebuild, smart recompute, and the debounced JSON flush.
- [x] `tagging.write_tags` now parses + saves the file ONCE per edit:
grouping/compilation/bpm ride the same save via registered Easy keys
(GRP1/TCMP/TBPM on EasyID3, cpil on EasyMP4) instead of
`_write_extra_tags` doing a second full parse+save.
- [x] `LibraryView` coalesces browser rebuilds through a 0 ms single-shot
timer: an N-track Get Info edit rebuilds the genre/artist/album
cascade once, not N times (was O(edited × library)).
- [ ] **Diagnose on the Debian machine**: self-update, reproduce a Ctrl+I
edit, read `lintunes.perf` timings (terminal run or
`journalctl --user`) to see which stage eats the ~5 s — likely the
audio-file rewrite or the 15 MB library.json flush. Then decide on
moving that stage off the GUI thread (deliberately deferred).
## Round 19 — version display, git self-update, BPM fix
Plan reference: `~/.claude/plans/some-fixes-features-for-lintues-merry-journal.md`.
Tests land in `tests/test_round19.py`. First versioned release: **0.1.0**.