From def7635a8702d8f587207ecd8178fe56834a0d6c Mon Sep 17 00:00:00 2001 From: trav Date: Mon, 14 Sep 2026 12:51:40 -0700 Subject: [PATCH] v0.20.3: one artist spelled two ways The sync was fine. Everything it put on the Rabbit was there and correct -- 2,432 media files, 208 covers, a manifest whose every field type-checks against the parser -- and andTunes still answered "No library / Couldn't read library.json". Fifteen tracks took all 2,439 songs down with them. Library.group() keyed albumsByKey case-folded and artistsByName raw-case, and only ever built the Artist inside `if (album == null)`. So the second track of an album whose artist is spelled differently found the album already there, skipped the block that would have made the artist, and dereferenced the null that came back. Six artists in trav's library are spelled two ways: RJD2/Rjd2, Toro Y Moi/Toro y Moi, FatBoy Slim/Fatboy Slim, LOVING/Loving, Land Of The Loops/Land of the Loops, Salami Rose Joe Louis/salami rose joe louis. It had worked until the 12th because that sync was the first to carry both spellings of one of those albums. Both maps fold case now, and the artist is fetched-or-made before the album block and held, so no lookup left in group() can come back null. Artist gains a key the way Album always had one, and ListActivity navigates by it -- ALBUM_ROW already passed album.key, so artists just stopped being the exception. The device filesystem is case-insensitive, so those two spellings are one folder there. plan_andtunes_sync compared exact strings and saw every such file as stale *and* missing, deleting and re-copying it over MTP on every sync forever; the diff and the collision rule both fold now. plan.stale still carries the device's own spelling, since that is what _delete_stale unlinks by. Verified on the Rabbit: 2,439 songs listed, RJD2 one row of 12 songs. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01SKXUgsBBwe3qaHEjeV8ubP --- CLAUDE.md | 9 + andtunes/TASKS.md | 8 +- .../main/java/me/teafry/andtunes/Library.java | 34 ++-- .../java/me/teafry/andtunes/ListActivity.java | 4 +- andtunes/build.py | 4 +- lintunes/__init__.py | 2 +- lintunes/android/andTunes.apk | Bin 62871 -> 62871 bytes lintunes/android/andTunes.json | 2 +- lintunes/andtunes/sync.py | 18 +- scripts/make_dev_library.py | 7 + tasks-done.md | 42 +++++ tests/test_round54.py | 160 ++++++++++++++++++ 12 files changed, 265 insertions(+), 25 deletions(-) create mode 100644 tests/test_round54.py diff --git a/CLAUDE.md b/CLAUDE.md index 69325b0..9552632 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -338,6 +338,15 @@ 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**. + **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 + artist before the album block, holding it — the raw-case lookup afterwards is + what NPE'd on the second track of a two-spelling album and blanked the whole + library), and `plan_andtunes_sync` folds both the collision rule and the + device diff, which had been re-copying every such file over MTP every sync. + `plan.stale` still carries the device's own spelling — that is what + `_delete_stale` unlinks by. 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 + diff --git a/andtunes/TASKS.md b/andtunes/TASKS.md index 52a8edc..3db06ee 100644 --- a/andtunes/TASKS.md +++ b/andtunes/TASKS.md @@ -7,8 +7,12 @@ A music player for the Rabbit R1 that never scans anything: LinTunes writes Legend: `[ ]` todo · `[~]` in progress · `[x]` done. **Status: phases 1–3 done (2026-09-11, LinTunes rounds 50–51, andTunes -0.2.0).** What's left is the *Parked* list, pulled in as trav finds he needs -it. Built with +0.2.0); 0.2.1 (LinTunes round 54, 2026-09-14) fixed the grouping crash — +`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 +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 each lands in is decided when it starts. diff --git a/andtunes/app/src/main/java/me/teafry/andtunes/Library.java b/andtunes/app/src/main/java/me/teafry/andtunes/Library.java index 3b4941b..b5e9bf9 100644 --- a/andtunes/app/src/main/java/me/teafry/andtunes/Library.java +++ b/andtunes/app/src/main/java/me/teafry/andtunes/Library.java @@ -51,7 +51,7 @@ final class Library { } static final class Artist { - String name, sortKey; + String key, name, sortKey; final ArrayList albums = new ArrayList<>(); final ArrayList tracks = new ArrayList<>(); // alphabetical } @@ -168,7 +168,9 @@ final class Library { } checkFormat(format); for (Playlist p : lib.playlists) { - for (Long id : playlistIds.get(p.id)) { + List members = playlistIds.get(p.id); + if (members == null) continue; // two playlists sharing an id + for (Long id : members) { Track t = lib.byId.get(id); if (t != null) p.tracks.add(t); } @@ -257,32 +259,38 @@ final class Library { String who = !t.albumArtist.isEmpty() ? t.albumArtist : !t.artist.isEmpty() ? t.artist : UNKNOWN_ARTIST; String albumName = t.album.isEmpty() ? UNKNOWN_ALBUM : t.album; - String key = who.toLowerCase(Locale.ROOT) + "" + // Both maps fold case, or "RJD2" and "Rjd2" share one album while + // owning two artist entries — and the second track of that album + // skips the block that would have made the artist. Fetched and + // held here, so no lookup below can come back null. + String whoKey = who.toLowerCase(Locale.ROOT); + Artist artist = artistsByName.get(whoKey); + if (artist == null) { + artist = new Artist(); + artist.key = whoKey; + artist.name = who; + artist.sortKey = sortKey(who); + artistsByName.put(whoKey, artist); + artists.add(artist); + } + String key = whoKey + "" + albumName.toLowerCase(Locale.ROOT); Album album = albumsByKey.get(key); if (album == null) { album = new Album(); album.key = key; album.name = albumName; - album.artist = who; + album.artist = artist.name; album.sortKey = sortKey(albumName); albumsByKey.put(key, album); albums.add(album); - Artist artist = artistsByName.get(who); - if (artist == null) { - artist = new Artist(); - artist.name = who; - artist.sortKey = sortKey(who); - artistsByName.put(who, artist); - artists.add(artist); - } artist.albums.add(album); } album.tracks.add(t); if (album.art.isEmpty() && !t.art.isEmpty()) album.art = t.art; if (t.year > 0 && (album.year == 0 || t.year < album.year)) album.year = t.year; t.albumRef = album; - artistsByName.get(who).tracks.add(t); + artist.tracks.add(t); } for (Album a : albums) { Collections.sort(a.tracks, (x, y) -> x.disc != y.disc ? x.disc - y.disc diff --git a/andtunes/app/src/main/java/me/teafry/andtunes/ListActivity.java b/andtunes/app/src/main/java/me/teafry/andtunes/ListActivity.java index a21f7a0..d6ac0fb 100644 --- a/andtunes/app/src/main/java/me/teafry/andtunes/ListActivity.java +++ b/andtunes/app/src/main/java/me/teafry/andtunes/ListActivity.java @@ -301,10 +301,10 @@ public class ListActivity extends BaseActivity { open(PLAYLIST, ((Library.Playlist) row.ref).id); break; case ARTIST_ROW: - open(ARTIST, ((Library.Artist) row.ref).name); + open(ARTIST, ((Library.Artist) row.ref).key); break; case ALL_SONGS: - open(ARTIST_SONGS, ((Library.Artist) row.ref).name); + open(ARTIST_SONGS, ((Library.Artist) row.ref).key); break; case ALBUM_ROW: open(ALBUM, ((Library.Album) row.ref).key); diff --git a/andtunes/build.py b/andtunes/build.py index 5c37394..06fbff1 100644 --- a/andtunes/build.py +++ b/andtunes/build.py @@ -26,8 +26,8 @@ import sys import zipfile from pathlib import Path -VERSION_NAME = "0.2.0" -VERSION_CODE = 2 +VERSION_NAME = "0.2.1" +VERSION_CODE = 3 PACKAGE = "me.teafry.andtunes" MIN_SDK = 26 diff --git a/lintunes/__init__.py b/lintunes/__init__.py index dfe003b..ccdd8f9 100644 --- a/lintunes/__init__.py +++ b/lintunes/__init__.py @@ -1,3 +1,3 @@ """LinTunes — iTunes-style music library manager and player for Linux.""" -__version__ = "0.20.2" +__version__ = "0.20.3" diff --git a/lintunes/android/andTunes.apk b/lintunes/android/andTunes.apk index 5293081e98b88e39bea3cfbb00cbf24a3cda58bb..de60aee9cabaa11ae027e4dd58aca4e73052e1fd 100644 GIT binary patch delta 30950 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%0AX~ZRhYckq_(lFxwbz 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 H_YD6R-u)(< diff --git a/lintunes/android/andTunes.json b/lintunes/android/andTunes.json index 4afad13..ebae942 100644 --- a/lintunes/android/andTunes.json +++ b/lintunes/android/andTunes.json @@ -1 +1 @@ -{"version_name": "0.2.0", "version_code": 2} +{"version_name": "0.2.1", "version_code": 3} diff --git a/lintunes/andtunes/sync.py b/lintunes/andtunes/sync.py index b566c9d..68bccce 100644 --- a/lintunes/andtunes/sync.py +++ b/lintunes/andtunes/sync.py @@ -192,9 +192,11 @@ def plan_andtunes_sync(playlists, tracks_by_id, root: Path, device=None, # Same collision rule as the per-playlist sync: every member of a # colliding group gets the [track_id] suffix, so a name never depends on # which playlist happened to be walked first. + # Folded, because the device's filesystem is case-insensitive: two songs + # whose paths differ only in case are one file there, not two. by_rel: dict[str, list[MediaItem]] = {} for item in items.values(): - by_rel.setdefault(item.rel, []).append(item) + by_rel.setdefault(item.rel.lower(), []).append(item) for group in by_rel.values(): if len(group) > 1: for item in group: @@ -231,19 +233,27 @@ def plan_andtunes_sync(playlists, tracks_by_id, root: Path, device=None, expected |= {art_relpath(key) for key in plan.albums} expected.add(MANIFEST_NAME) + # Compared case-folded: the device filesystem is case-insensitive, so a + # song filed under "Toro y Moi" here and "Toro Y Moi" there is the same + # file. Exact-string matching saw it as stale *and* missing and re-copied + # it over MTP every single sync. + on_device_folded = {rel.lower(): size for rel, size in on_device.items()} + expected_folded = {rel.lower() for rel in expected} + for item in plan.items: if item.convert_to: # Its FLAC size is unknown until the worker converts it. - item.device_size = on_device.get(item.rel) + item.device_size = on_device_folded.get(item.rel.lower()) plan.copies.append(item) plan.bytes_to_copy += item.size - elif on_device.get(item.rel) == item.size: + elif on_device_folded.get(item.rel.lower()) == item.size: plan.kept += 1 else: plan.copies.append(item) plan.bytes_to_copy += item.size + # plan.stale keeps the device's own spelling — _delete_stale unlinks by it. for rel, size in sorted(on_device.items()): - if rel not in expected: + if rel.lower() not in expected_folded: plan.stale.append(rel) plan.bytes_freed += size return plan diff --git a/scripts/make_dev_library.py b/scripts/make_dev_library.py index 7fc9bc8..a3685a6 100644 --- a/scripts/make_dev_library.py +++ b/scripts/make_dev_library.py @@ -26,6 +26,9 @@ The edge cases here are not decoration. Each one has bitten something: * a multi-disc release → the "2-04" prefix; * a compilation whose album_artist differs → album grouping and album art keying; +* one artist spelled two ways on one album → the case-folded + ("RJD2" / "Rjd2") grouping in the app and + the folded device diff; * a dangling location → the "skipped" counters; * a 200-character title → the 150-char truncation; * non-ASCII and an emoji → UTF-8 all the way to @@ -152,6 +155,10 @@ EDGE_TRACKS = [ ("Song", "Twin Records", "Doubles", ".mp3", "collision A"), ("Song", "Twin Records", "Doubles", ".mp3", "collision B"), ("Orphan Take", "", "", ".mp3", "no artist, no album"), + ("Iced Lightning", "RJD2", "Since We Last Spoke", ".mp3", + "one artist spelled two ways, sharing an album"), + ("Making Days Longer", "Rjd2", "Since We Last Spoke", ".mp3", + "the other spelling — the pair is the point"), ("わたしの音楽 🎧", "Sakura Denwa", "東京の夜", ".mp3", "non-ASCII + emoji"), ("A Title That Simply Refuses To Stop Going On And On " * 4, "Verbose", "Excess", ".mp3", "200+ characters, hits the 150-char truncation"), diff --git a/tasks-done.md b/tasks-done.md index 955c7b7..3ece031 100644 --- a/tasks-done.md +++ b/tasks-done.md @@ -1,5 +1,47 @@ ## Done +### Round 54 (2026-09-14) — one artist spelled two ways (v0.20.3, andTunes 0.2.1) + +trav synced to the Rabbit, the sync reported success, and andTunes answered +with `No library / Couldn't read library.json`. The sync was fine. Everything +it wrote was on the device and correct — 2,432 media files, 208 covers, a +manifest whose every field type-checks against the parser. The app was the bug, +and it took all 2,439 songs down over fifteen of them. + +- [x] **The diagnosis**, read off the device: a `NullPointerException` on + `Library$Artist.tracks` inside `load` (R8 inlines `group()` into it). + `group()` keyed `albumsByKey` **case-folded** and `artistsByName` + **raw-case**, and only ever built the `Artist` inside + `if (album == null)`. So the second track of an album whose artist is + spelled differently found the album already there, skipped the block that + would have made the artist, and dereferenced the null that came back. + Replaying the algorithm over the real manifest: 15 tracks, six artists + spelled two ways — `RJD2`/`Rjd2`, `Toro Y Moi`/`Toro y Moi`, + `FatBoy Slim`/`Fatboy Slim`, `LOVING`/`Loving`, + `Land Of The Loops`/`Land of the Loops`, + `Salami Rose Joe Louis`/`salami rose joe louis`. It worked on the 11th + because the 12th's sync was the first to carry both spellings of one of + those albums. +- [x] **Both maps fold case now**, and the artist is fetched-or-made *before* + the album block and held in a local, so there is no lookup left in + `group()` that can return null. `Artist` gains a `key` (the folded name), + the way `Album` already had one, and `ListActivity` navigates by it — + `ALBUM_ROW` already passed `album.key`, so artists just stopped being the + exception. `playlistIds.get` in `load()` got the same treatment. +- [x] **The device diff folds case too.** `/sdcard` is case-insensitive, so + those two spellings are one folder there; `plan_andtunes_sync` compared + exact strings and saw every such file as stale **and** missing, deleting + and re-copying it over MTP on every sync forever. The collision rule + folds as well, so two songs whose paths differ only by case get the + `[track_id]` suffix instead of one silently overwriting the other. + `plan.stale` still carries the device's own spelling — that is what + `_delete_stale` unlinks by. +- [x] **The fixture grew the shape** (`scripts/make_dev_library.py`): one + artist spelled two ways on one shared album, next to the other naming + edge cases. `tests/test_round54.py` pins the desktop half (the Java + grouping has no harness — it was verified on the device: 2,439 songs + listed, and RJD2 one row of 12 songs where there had been a crash). + ### Round 52 (2026-09-11) — one fingerprint, six artists (v0.20.1) trav's "Dionne Farris - I Know" kept being identified as Jay-Z, with ID3 tags diff --git a/tests/test_round54.py b/tests/test_round54.py new file mode 100644 index 0000000..6d8e9ce --- /dev/null +++ b/tests/test_round54.py @@ -0,0 +1,160 @@ +"""Round 54: one artist spelled two ways. + +trav's Rabbit showed `No library / Couldn't read library.json` on a sync that +had worked perfectly. The manifest was fine; the app's grouping wasn't. +`Library.group()` keyed albums case-folded but artists raw-case, and only +created the artist inside the `album == null` branch — so the second track of +an album whose artist was spelled with different case ("RJD2" / "Rjd2") found +the album already built, skipped artist creation, and dereferenced a null. +Fifteen tracks across six artists took all 2,439 songs down with them. + +The Java half has no test harness. What's pinned here is the desktop half of +the same root cause: the device filesystem is case-insensitive, so those two +spellings are **one** folder there, and `plan_andtunes_sync`'s exact-string +diff saw every such file as stale *and* missing and re-copied it over MTP on +every sync forever. +""" + +import json + +import pytest + +from lintunes.andtunes.layout import media_relpath +from lintunes.andtunes.sync import AndTunesSyncWorker, plan_andtunes_sync +from lintunes.models import Track +from lintunes.models.playlist import Playlist, PlaylistType + + +@pytest.fixture(autouse=True) +def _private_cache(tmp_path, monkeypatch): + monkeypatch.setenv("XDG_CACHE_HOME", str(tmp_path / "cache")) + + +DATA = b"x" * 64 + + +def _track(tid, name, artist, album="Since We Last Spoke", *, tmp_path): + path = tmp_path / "local" / f"{tid}.mp3" + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(DATA) + return Track(track_id=tid, name=name, artist=artist, album=album, + location=str(path), total_time=60_000, kind="MPEG audio file") + + +def _playlist(*tids): + return Playlist(name="Mix", persistent_id="AAAA0001", + playlist_type=PlaylistType.REGULAR, track_ids=list(tids)) + + +def _root(tmp_path): + return tmp_path / "device" / "Music" / "andTunes" + + +def _on_device(root, rel, data=DATA): + path = root / rel + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(data) + return path + + +def _both_spellings(tmp_path): + return { + 1: _track(1, "Iced Lightning", "RJD2", tmp_path=tmp_path), + 2: _track(2, "Making Days Longer", "Rjd2", tmp_path=tmp_path), + } + + +# ---- the two spellings are one folder on the device ---- + +def test_the_two_spellings_ask_for_one_device_folder(tmp_path): + """Different rel paths, but the device can only hold one of the two.""" + tracks = _both_spellings(tmp_path) + assert media_relpath(tracks[1]).startswith("Media/RJD2/") + assert media_relpath(tracks[2]).startswith("Media/Rjd2/") + folders = {media_relpath(t).split("/")[1].lower() for t in tracks.values()} + assert folders == {"rjd2"} + + +def test_a_file_filed_under_the_other_spelling_is_kept_not_recopied(tmp_path): + """The churn: it used to be stale *and* missing, every sync, forever.""" + tracks = _both_spellings(tmp_path) + root = _root(tmp_path) + # What a case-insensitive filesystem actually ends up holding: whichever + # spelling made the folder first wins, and both songs land inside it. + _on_device(root, "Media/RJD2/Since We Last Spoke/Iced Lightning.mp3") + _on_device(root, "Media/RJD2/Since We Last Spoke/Making Days Longer.mp3") + + plan = plan_andtunes_sync([_playlist(1, 2)], tracks, root) + + assert plan.kept == 2 + assert plan.copies == [] + assert plan.stale == [] + assert plan.bytes_to_copy == 0 + + +def test_a_real_change_still_copies(tmp_path): + """Folding the diff must not blind it to a file whose size moved.""" + tracks = _both_spellings(tmp_path) + root = _root(tmp_path) + _on_device(root, "Media/RJD2/Since We Last Spoke/Iced Lightning.mp3") + _on_device(root, "Media/RJD2/Since We Last Spoke/Making Days Longer.mp3", + b"short") + + plan = plan_andtunes_sync([_playlist(1, 2)], tracks, root) + + assert plan.kept == 1 + assert [item.track_id for item in plan.copies] == [2] + + +def test_a_file_under_neither_spelling_is_still_stale(tmp_path): + tracks = _both_spellings(tmp_path) + root = _root(tmp_path) + _on_device(root, "Media/RJD2/Since We Last Spoke/Iced Lightning.mp3") + _on_device(root, "Media/RJD2/Since We Last Spoke/Making Days Longer.mp3") + _on_device(root, "Media/Someone Else/Old Record/Gone.mp3") + + plan = plan_andtunes_sync([_playlist(1, 2)], tracks, root) + + # The device's own spelling, because _delete_stale unlinks by that name. + assert plan.stale == ["Media/Someone Else/Old Record/Gone.mp3"] + + +# ---- names that collide only by case ---- + +def test_two_songs_colliding_only_by_case_both_get_the_id_suffix(tmp_path): + """One file on the device, so one of them would have silently won.""" + tracks = { + 1: _track(1, "Iced Lightning", "RJD2", tmp_path=tmp_path), + 2: _track(2, "Iced Lightning", "Rjd2", tmp_path=tmp_path), + } + plan = plan_andtunes_sync([_playlist(1, 2)], tracks, _root(tmp_path)) + + rels = {item.track_id: item.rel for item in plan.items} + assert rels[1].endswith("Iced Lightning [1].mp3") + assert rels[2].endswith("Iced Lightning [2].mp3") + assert len({rel.lower() for rel in rels.values()}) == 2 + + +# ---- both spellings survive into the manifest ---- + +def test_the_manifest_still_carries_both_tracks(tmp_path): + tracks = _both_spellings(tmp_path) + root = _root(tmp_path) + plan = plan_andtunes_sync([_playlist(1, 2)], tracks, root) + + worker = AndTunesSyncWorker(plan) + out = {} + worker.finished.connect(lambda s: out.setdefault("finished", s)) + worker.failed.connect(lambda m: out.setdefault("failed", m)) + worker._run() + assert "failed" not in out, out.get("failed") + + manifest = json.loads((root / "library.json").read_text(encoding="utf-8")) + by_id = {row["id"]: row for row in manifest["tracks"]} + assert by_id[1]["artist"] == "RJD2" + assert by_id[2]["artist"] == "Rjd2" + # Each keeps its own spelling in the path it asks for; the device resolves + # both to the one folder it actually has. + assert by_id[1]["path"].startswith("Media/RJD2/") + assert by_id[2]["path"].startswith("Media/Rjd2/") + assert manifest["playlists"][0]["tracks"] == [1, 2]