mirror of https://github.com/Nezreka/SoulSync.git
dev
main
fix/quarantine-source-dedup
release/2.5.3
fix/disable-beatport-features
johnbaumb-discover-redesign
1.0
1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
2.0
2.1
2.2
2.3
2.4.0
2.4.1
2.4.2
2.5.0
2.5.1
2.5.2
2.5.3
2.5.4
2.5.5
2.5.6
2.5.7
2.5.9
2.6.0
2.6.1
v0.65
${ noResults }
2 Commits (dev)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
9f2813fce4 |
Add cross-section dedup to all-libraries listing layer
Followup to the all-libraries-mode commit. Without dedup, a Plex Home family where two users both have "Drake" in their music libraries would see "Drake" twice in SoulSync's library list — Plex returns distinct ratingKeys for each section's copy of the same artist. Dedup design — applied selectively, NOT everywhere: - ``_dedupe_artists(artists)``: groups by lowercased title, picks the canonical entry by ``leafCount`` (more tracks wins). Active ONLY in all-libraries mode; single-library mode is a no-op fast path with zero behavior change. - ``_dedupe_albums(albums)``: same but keys on (lowercased parentTitle, lowercased title) so two artists with identically-titled albums (e.g. self-titled releases) stay separate. Applied to: - ``get_all_artists()`` — public listing for the library view - ``get_library_stats()`` — count matches what user sees in the list Deliberately NOT applied to: - ``get_all_artist_ids()`` / ``get_all_album_ids()`` — these feed removal detection (compare returned ratingKey set against DB-linked ratingKeys to decide what's been removed). Deduping here would falsely flag non-canonical ratingKeys as "removed" and prune SoulSync's DB tracks that are linked to them. Pinned by two CRITICAL tests. - ``_all_tracks()`` — track count stays raw because the same track in two sections IS two distinct files / Plex entries, not a logical duplicate. - ``_search_general()`` and ``search_tracks`` Stage 1/2 — search results stay raw so cross-section matches aren't lost. Stage 1 may miss cross-section tracks for the same artist but Stage 2's server-wide track search catches them. Logging: when raw vs deduped artist counts differ, ``get_all_artists`` logs both so users can see "Found 4697 artists across all music sections (4521 unique after cross-section dedup)" — surfaces the overlap clearly. Tests: 8 new tests in test_plex_all_libraries.py pin: - canonical pick by leafCount (artists + albums) - case-insensitive name match - single-library no-op path (zero behavior change for those users) - album dedup keys on (artist, title) so different-artist same-title albums stay separate - ``get_all_artists`` listing applies dedup - ``get_all_artist_ids`` does NOT dedup (CRITICAL — removal detection) - ``get_all_album_ids`` does NOT dedup (CRITICAL — removal detection) - ``get_library_stats`` uses deduped counts for artists/albums but raw count for tracks Existing pre-stat test updated to use distinct mock instances — ``[MagicMock()] * 5`` creates five references to one mock which now correctly collapses under dedup. 71/71 media_server tests green, 2162/2162 full suite green. Honest known limitation acknowledged in WHATS_NEW + version modal: write-back (genre / poster / metadata updates) targets one ratingKey at a time — only updates the canonical section's copy of an artist if it exists in multiple. Other section's copy stays unchanged. Document and revisit if it matters. |
3 weeks ago |
|
|
620c41f1ac |
Add "All Libraries (combined)" mode to PlexClient
GitHub issue #505 (PopeBruhLXIX): users with multiple Plex music libraries (e.g. one per Plex Home user, or two folder roots split across separate library sections) only saw one library inside SoulSync because the connection settings forced you to pick a single library section. SoulSync's PlexClient stored exactly one ``self.music_library`` section reference and every read scanned only that one. This change adds an opt-in "All Libraries (combined)" dropdown option that flips the client into a server-wide read mode where every read method (``get_all_artists`` / ``get_all_album_ids`` / ``search_tracks`` / ``get_library_stats`` / etc) dispatches through ``server.library.search(libtype=...)`` instead of querying a single section. One Plex API call replaces N per-section iterations; Plex handles the aggregation server-side. Implementation: - ``ALL_LIBRARIES_SENTINEL`` (``'__all_libraries__'``) — module-level constant used as the saved DB preference value when the user picks the synthetic "All Libraries" entry. Detection is one string compare in ``_find_music_library`` / ``set_music_library_by_name``. Existing preferences (real library names) are unaffected. - ``self._all_libraries_mode`` (private flag) + ``is_all_libraries_mode()`` (public accessor for external callers). When True, ``music_library`` may stay None — ``is_fully_configured()`` recognizes the mode and still returns True so dispatch sites don't bail. - New private helpers ``_can_query``, ``_get_music_sections``, ``_all_artists``, ``_all_albums``, ``_all_tracks``, ``_search_general``, ``_search_artists_by_name``. Single dispatch point for the section-vs-server branch — every read method funnels through them so future drift fails at one place. - New public helpers for downstream callers: - ``get_recently_added_albums(maxresults, libtype)`` — used by DatabaseUpdateWorker's deep-scan recent-content sweep - ``get_recently_updated_albums(limit)`` — same - ``get_music_library_locations()`` — returns folder roots, used by web_server.py's file-path resolver - ``trigger_library_scan`` and ``is_library_scanning`` fan out across every music section in all-libraries mode. - ``get_available_music_libraries`` prepends a synthetic ``{'title': 'All Libraries (combined)', 'value': sentinel}`` entry ONLY when more than one music library exists. Single-library users don't get the extra option. ``value`` field is the canonical identifier the frontend submits to ``/api/plex/select-music-library`` (real libraries: title; synthetic: sentinel string). Backward- compatible — entries without ``value`` fall back to ``title``. Three crash points fixed in downstream consumers (would have failed during a deep scan after the user picked all-libraries mode): 1. ``database_update_worker.py:411`` — bailed out with "No music library found in Plex" because ``not self.media_client.music_library`` evaluated True in all-libraries mode (music_library is None there). Now uses ``is_fully_configured()`` which recognizes the mode. This was the root cause of the deep scan never starting. 2. ``database_update_worker.py:_get_recent_albums_plex`` — reached ``self.media_client.music_library.recentlyAdded()`` / ``.search()`` directly, AttributeError in all-libraries mode. Now routes through the new helper methods. 3. ``web_server.py:10947`` (file-path resolver) — accessed ``music_library.locations``; gated on ``music_library`` truthy so it didn't crash, but silently skipped all-libraries-mode locations. Now uses ``get_music_library_locations()`` which unions across sections. Plus polish: - ``/api/plex/clear-library`` also resets ``_all_libraries_mode`` so a fresh "select library" flow doesn't inherit stale mode state. - ``/api/plex/music-libraries`` surfaces "All Libraries (combined)" as ``current_library`` when in mode (settings UI displays correctly). - Frontend ``loadPlexMusicLibraries`` uses ``library.value || library.title`` so the sentinel-keyed option submits the sentinel string, not the human-readable label. Pre-select match handles both paths. Honest tradeoffs (documented as known limitations): - Same artist appearing in multiple Plex sections shows as separate entries in SoulSync (no dedup). Plex returns distinct ratingKeys for each. Cosmetic; revisit if it bites users. - Write-back (genre / poster updates) targets one ratingKey at a time — only updates that section's copy. Other sections' copies stay unchanged. - All-libraries mode includes any audiobook library that Plex classifies as ``type='artist'``. Edge case, opt-in only. Tests: 21 new tests in tests/media_server/test_plex_all_libraries.py pin both single-library mode (regression guard) and all-libraries mode for every refactored method. Existing test_plex_pinning.py fixture updated to initialize the new flag. 63/63 media_server tests green, 2148/2148 full suite green. |
3 weeks ago |