v0.20.4: the song that wasn't there
trav couldn't play the first track of his playlist. Shuffle off gave him song two; shuffle on gave him a random one. The player was right both times: library.json named a song whose file was not on the device, and skipping an unplayable file advances one slot. Tapping any song that *is* there plays exactly that song, shuffle or not. The file was missing because a gvfs-MTP mount can hold a phantom directory -- one it lists happily while the device has no such folder. Every write into it fails EIO, and mkdir(exist_ok=True) sees the phantom and does nothing, so it never heals; only remounting clears it. That folder was new because Round 52's retag moved the file under a new artist. So a copy that raises OSError now costs that song, not the sync, and the song is left out of the m3u and library.json. Aborting cost 2,400 songs for one folder; counting it present anyway put a song in the manifest that isn't on the device, which is the bug you could hear. The names come back in the summary and a dialog rather than vanishing. Planning is a worker now. plan_andtunes_sync is pure and writes nothing, but it walks every file on the device, and over MTP that is thousands of round trips -- on the GUI thread it froze the window and GNOME offered to kill LinTunes, which is how a sync got force-quit halfway through. And the sync stopped going quiet at the end. "Album art 501/501" is emitted before the last album, and then _write_index, _ship_buttons and _prune_empty_dirs ran silently: 501 exists() stats over MTP, ~840 KB of writes and a full tree walk, with the progress line frozen. They report now, and _write_index reads Art/ in one listing instead of a stat per album. andTunes 0.2.2: the wheel scrolls the other way in lists, and smoothly -- a detent adds to a pixel debt that a Choreographer callback pays off a fraction per frame, so one detent eases to a stop and a fast spin blends into one movement instead of teleporting a row at a time. Volume is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SKXUgsBBwe3qaHEjeV8ubP
This commit is contained in:
+4
-1
@@ -11,7 +11,10 @@ Legend: `[ ]` todo · `[~]` in progress · `[x]` done.
|
||||
`Library.group()` keyed albums case-folded but artists raw-case, so one artist
|
||||
spelled two ways on one album ("RJD2" / "Rjd2") took the whole library down
|
||||
with `Couldn't read library.json`. Both maps fold case now, and `Artist` has a
|
||||
`key` the way `Album` always did.** What's left is the *Parked* list, pulled in
|
||||
`key` the way `Album` always did. 0.2.2 (round 55, 2026-09-14) reversed the
|
||||
wheel in lists and made it scroll smoothly (`WheelScroll` — a pixel debt paid
|
||||
off per frame, not a row per detent); volume on the other screens is
|
||||
unchanged.** What's left is the *Parked* list, pulled in
|
||||
as trav finds he needs it. Built with
|
||||
`python3 andtunes/build.py` — plain Java, no Gradle, nothing downloaded (see
|
||||
`README.md`, *Toolchain*). Phases are andTunes' own; which LinTunes round
|
||||
|
||||
Reference in New Issue
Block a user