v0.17.0: the desktop already knows what the songs are
The first half of andTunes, a music player for the Rabbit R1. Auxio re-reads Android's MediaStore on every launch, which is the "your songs will show up here" hang — so the answer isn't a faster scanner, it's not scanning at all. LinTunes already knows the artist, album and year of every file it just copied, so it writes them into Music/andTunes/library.json and the app reads one file instead of indexing a filesystem. New lintunes/andtunes/: layout.py (a de-duplicated Media/<Artist>/<Album>/ tree, so a song in three playlists is stored once), manifest.py (pure, Qt-free), art.py (one 480 px cover per album via QImage, cached and invalidated by the audio file's mtime — which is exactly what embedding new art moves), and sync.py, a third sibling of plan_export/ExportWorker. Three rules the code depends on: planning never renders art (a mutagen open per album, and planning runs on the GUI thread); the index is written last and after a cancel lists only tracks whose files actually landed; and every delete goes through layout.assert_inside, which is why the old Music/<Playlist>/ folders are structurally unreachable rather than merely un-referenced. Connections gains "Sync to Rabbit" and "Rabbit Sync Settings…" — the ticked set is the device's contents, so unticking is how a playlist comes off, which nothing could do before. The selection rides preferences.json so both machines agree. The old per-playlist sync stays, renamed "(Auxio)": removing it now would leave the device full of files and nothing able to open them until the app exists. The app itself is rounds 48-50; its board is andtunes/TASKS.md, including the measured screen facts (480x640 px at density override 160 — one dp is half its usual physical size on a 2.88" panel). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015wrTys5U1fLb4pBD2LKWzV
This commit is contained in:
@@ -33,6 +33,14 @@ DEFAULTS = {
|
||||
"acoustid": {
|
||||
"api_key": "",
|
||||
},
|
||||
# Which playlists belong on the andTunes device, by persistent_id. Kept
|
||||
# here rather than on the Playlist so it stays out of the conflict-merge
|
||||
# machinery — and because riding the syncthing share is the point: both
|
||||
# machines should agree on what the Rabbit is carrying.
|
||||
"device_sync": {
|
||||
"playlist_ids": [],
|
||||
"copy_art": True,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +97,15 @@ class Preferences(QObject):
|
||||
def acoustid(self) -> dict:
|
||||
return self._data["acoustid"]
|
||||
|
||||
def update_device_sync(self, **fields):
|
||||
self._data["device_sync"].update(fields)
|
||||
self.save()
|
||||
self.changed.emit()
|
||||
|
||||
@property
|
||||
def device_sync(self) -> dict:
|
||||
return self._data["device_sync"]
|
||||
|
||||
def save(self):
|
||||
self._path.parent.mkdir(parents=True, exist_ok=True)
|
||||
tmp = self._path.with_suffix(".json.tmp")
|
||||
|
||||
Reference in New Issue
Block a user