Both machines now reflect each other's changes within a couple seconds, and
genuine Syncthing conflicts auto-merge with a backup and an alert.
- sync_watcher.py: QFileSystemWatcher (debounced, re-arms after atomic renames)
emits a single `changed`; the manager decides if it was external.
- library_manager: `reload_from_disk()` re-reads and reconciles disk into memory
(max play/skip counts, newest edit wins, playlist membership unioned), keeping
local unsaved edits and object identity so open views stay valid, then refreshes
the UI without touching the player. `flush()` records each file's (mtime, size)
so our own writes are never mistaken for an external change. New signals
library_reloaded / conflict_resolved.
- conflict_resolver: back up BOTH sides into .resolved/<ts>/{original,incoming}/
before merging, return list[ConflictSummary], add restore_backup(); runs at
startup and live.
- gui/conflict_dialog.py: modeless summary with Open/Restore backup; main_window
shows it from a status-bar notice and preserves scroll+selection on reload.
Tests: tests/test_round16.py (9) + full suite green (225).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The library is going live as the canonical store, synced to a second machine
via Syncthing. Track locations were stored absolute and only remapped at import,
so on a second machine (where Syncthing mounts the folder at a different path)
every location would break.
- lintunes/paths.py: to_relative/to_absolute. Locations are stored relative to
the data dir and resolved back on load, applied only at the json_storage
boundary (save_tracks/load_library). Track.location stays absolute in memory,
so the player, tagging, and art code are unchanged. The data dir and the music
move together inside one synced tree, so paths resolve wherever it's mounted —
no per-machine music_root config. Absolute paths in older library.json files
still load (back-compat).
- tests/test_round15.py: helper round-trips, back-compat, and a machine-2
scenario (save under root A, load the copied tree under root B).
- TASKS.md/tasks-done.md: mark the data-dir move + real import done; log the
benign exit-time Qt/FFmpeg teardown segfault.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Snapshot of the existing codebase before working through the TASKS.md
backlog. Real library data (data/) and the iTunes import fixture
(itunes-test-library/) are gitignored.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>