Skip to content

feat: add Subsonic playlist sync source#139

Open
BlackJocker1995 wants to merge 1 commit into
TheRealSavi:mainfrom
BlackJocker1995:feat/subsonic-source
Open

feat: add Subsonic playlist sync source#139
BlackJocker1995 wants to merge 1 commit into
TheRealSavi:mainfrom
BlackJocker1995:feat/subsonic-source

Conversation

@BlackJocker1995

Copy link
Copy Markdown

Add a new SubsonicManager module that syncs playlists from Subsonic-compatible servers (Navidrome, Airsonic, Gonic, original Subsonic) to the iPod. No tracks are downloaded — this is a playlist-only sync that references songs already in the iPod library by db_track_id, using fuzzy (title, artist) matching with curly-quote normalisation.

Architecture (mirrors PodcastManager pattern)
SubsonicManager/
client.py OpenSubsonic REST API client (token+salt auth)
plan_builder.py Builds SyncPlan with playlists_to_add/_to_edit
mapping.py Subsonic song → PCTrack mapping (unused, retained)
artwork.py getCoverArt + Navidrome placeholder detection

Settings & UI
Settings → Subsonic page: server URL/user/password, Test Connection,
per-playlist checkbox selection with Refresh button.
Sidebar: Sync Subsonic button.
Sync-time mapping dialog (QTabWidget, two tabs):
Tab 1 Mapping — choose which iPod playlist each Subsonic list
maps to (New / existing playlist).
Tab 2 Sync Mode — Remote→Local (Overwrite), Remote→Local (Add).
Local→Remote modes shown greyed out for future Subsonic write
support.

Sync flow
User clicks Sync Subsonic → dialog fetches playlist names →
user chooses mapping & mode → SubsonicPlanWorker builds plan
(playlists_to_add for new, playlists_to_edit for mapped with
merge/overwrite) → Sync Review preview → execute writes playlists
only (no file transfers — to_add is always empty).

Key design decisions

  • Playlist-only: no song download; references existing iPod tracks.
  • Fuzzy match: _match_key normalises curly quotes, case, punctuation.
  • Merge semantics: positive playlist_mappings id = merge (keep existing
    • add new); negative id = overwrite (replace entirely).
  • Deterministic playlist ids: blake2b(subsonic_id + name) → stable across re-syncs.
  • Credentials stored in plaintext settings.json (matches Last.fm convention).

Tests: 123 pass (49 Subsonic-specific + 74 regression). ruff clean.

Add a new SubsonicManager module that syncs playlists from
Subsonic-compatible servers (Navidrome, Airsonic, Gonic, original
Subsonic) to the iPod.  No tracks are downloaded — this is a
playlist-only sync that references songs already in the iPod library
by db_track_id, using fuzzy (title, artist) matching with curly-quote
normalisation.

Architecture (mirrors PodcastManager pattern)
  SubsonicManager/
    client.py        OpenSubsonic REST API client (token+salt auth)
    plan_builder.py  Builds SyncPlan with playlists_to_add/_to_edit
    mapping.py       Subsonic song → PCTrack mapping (unused, retained)
    artwork.py       getCoverArt + Navidrome placeholder detection

Settings & UI
  Settings → Subsonic page: server URL/user/password, Test Connection,
    per-playlist checkbox selection with Refresh button.
  Sidebar: Sync Subsonic button.
  Sync-time mapping dialog (QTabWidget, two tabs):
    Tab 1 Mapping — choose which iPod playlist each Subsonic list
      maps to (New / existing playlist).
    Tab 2 Sync Mode — Remote→Local (Overwrite), Remote→Local (Add).
      Local→Remote modes shown greyed out for future Subsonic write
      support.

Sync flow
  User clicks Sync Subsonic → dialog fetches playlist names →
  user chooses mapping & mode → SubsonicPlanWorker builds plan
  (playlists_to_add for new, playlists_to_edit for mapped with
  merge/overwrite) → Sync Review preview → execute writes playlists
  only (no file transfers — to_add is always empty).

Key design decisions
  - Playlist-only: no song download; references existing iPod tracks.
  - Fuzzy match: _match_key normalises curly quotes, case, punctuation.
  - Merge semantics: positive playlist_mappings id = merge (keep existing
    + add new); negative id = overwrite (replace entirely).
  - Deterministic playlist ids: blake2b(subsonic_id + name) → stable
    across re-syncs.
  - Credentials stored in plaintext settings.json (matches Last.fm
    convention).

Tests: 123 pass (49 Subsonic-specific + 74 regression).  ruff clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant