v0.32.0: folder tree in Rabbit Sync Settings, quieter art pass, tink, VLC-style Preferences

- Rabbit Sync Settings shows the sidebar's folder tree. A folder has its own
  tristate checkbox; a fully ticked folder is stored as device_sync.folder_ids
  and follows the folder, so playlists added to it later sync too.
- The album-art pass compares covers against the sizes the planner's device
  scan already read (plan.art_sizes) instead of an MTP stat per album, caches
  "no art" as a .none marker, and only unlinks covers that are really there.
  The summary reports covers actually updated rather than every cover.
- A quiet tink when a Rabbit sync, export or URL import finishes, with an
  on/off switch (sound_effects, on by default).
- Preferences is now General / Appearance / Integrations, a list on the left
  and the page on the right, opened big enough for the tallest page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 00:45:42 -07:00
co-authored by Claude Opus 5.5
parent 4a019d4e27
commit ba795e3c69
13 changed files with 699 additions and 80 deletions
+9
View File
@@ -377,6 +377,10 @@ persistence) → GUI (Qt widgets that read the manager and connect to its signal
`device_sync` (so it rides the Syncthing share and both machines agree);
keeping it off the `Playlist` keeps it out of the conflict-merge machinery,
and **unticking is the only way a playlist comes off the device**.
A fully ticked *folder* is stored as `device_sync.folder_ids` and follows
the folder — playlists added to it later sync too
(`device_sync_dialog.resolve_sync_playlists` is what both the dialog and
the sync read).
**The device's filesystem is case-insensitive**, so "RJD2" and "Rjd2" are one
folder there and one artist here: since Round 54 the app's `Library.group()`
keys *both* `albumsByKey` and `artistsByName` case-folded (and fetches the
@@ -401,6 +405,11 @@ persistence) → GUI (Qt widgets that read the manager and connect to its signal
(`_write_index`, buttons, pruning) must keep emitting progress — it was
minutes of silence with the line stuck on `Album art 501/501`, and
`_write_index` reads `Art/` in **one listing**, never a stat per album.
The art pass is held to the same rule (Round 70): it compares each cover
against `plan.art_sizes`, the sizes the planner's scan already read, never a
stat per album, and `art.album_art_jpeg` caches "this album has no art" as a
`<key>.none` marker, so an unchanged library costs the art pass no device
I/O and no mutagen opens.
Since Round 50 the app exists: `andtunes/app/` is plain Java against the
Android framework, built by `andtunes/build.py` (aapt2 → javac → R8 →
zipalign → apksigner) — **no Gradle, no Kotlin**, because platform 33 +