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 }
9 Commits (4feedff8f5e03a076c86a435aed7bc2f58ef0712)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
f11b91a5c6 |
Service worker for cover art + PWA manifest
Addresses #365 (reported by JohnBaumb), parts 3 & 5. Client-side IDB / sessionStorage data cache (part 4) deferred to its own PR. Cover art on Library and Discover used to re-fetch from the source CDN on every page visit. Now a service worker caches images locally in CacheStorage with cache-first strategy — second visit serves art instantly with zero network round-trips. PWA manifest added so the app is installable to home screen / desktop. Service worker (`webui/static/sw.js`): - Cache-first for images: 10 known CDN hosts (Spotify, Last.fm, Apple, Deezer, Discogs, MusicBrainz CAA, YouTube thumbnails) plus the local `/api/image-proxy` endpoint plus same-origin .png/.jpg/ .webp/.gif/.svg paths. Cross-origin file-extension matches are refused so we don't accidentally cache trackers. - Stale-while-revalidate for `/static/*`: serve cached instantly, refresh in background. Combined with the existing `?v=static_v` cache-bust, deploys still ship live (different query → different cache entry, old ages out). - HTML / API / everything else: no caching, pass through. - Cache-versioned (CACHE_VERSION = 'v1'); activate handler wipes any cache whose name doesn't match the current version. - skipWaiting + clients.claim so deploys propagate to open tabs without requiring a full close-and-reopen. PWA manifest (`webui/static/manifest.json`): - Standalone display mode, theme color #1db954 (matches --accent-rgb). - Two icons (192, 512) with both `any` and `maskable` purpose, generated from favicon.png with aspect-preserving transparent padding so the existing logo lands inside the safe zone for OS-applied masks. Wiring: - `web_server.py` adds a `/sw.js` route that serves the file from root scope (a service worker only controls URLs at or below its served path; `/static/sw.js` would scope to `/static/*` only). `Cache-Control: no-cache` on the SW response so deploys propagate on next page load instead of being pinned by the 1yr static cache the rest of /static/ uses. - `webui/index.html` adds the manifest link, theme-color meta, and an apple-touch-icon for iOS. - `webui/static/init.js` registers the SW on `window.load`. Feature-detected — no-op on browsers without serviceWorker support or on non-secure origins (SW requires https or localhost). One bug caught + fixed during line-by-line self-review: `_staleWhileRevalidate` could return null to `respondWith()` when both the cache miss AND the network fetch failed (the `.catch(() => null)` collapsed the rejection to null, which then short-circuited through the falsy chain). Now explicitly awaits the network promise and falls back to `Response.error()` when it resolves to null — matches the `_cacheFirst` pattern. Browser-verified: sw.js registers, status "activated and is running" in DevTools. 603 tests pass. |
4 weeks ago |
|
|
b547909604 |
Address PR review feedback from JohnBaumb and Cin
Four fixes from the review:
**library.js — back button stack (JohnBaumb):**
Replace the single-slot `artistDetailPageState.originPage` with an origin
stack. Chained navigation like Search → Artist A → similar Artist B →
similar Artist C now walks back one step at a time (C → B → A → Search)
instead of jumping straight to Search and skipping A and B.
`navigateToArtistDetail` takes an optional `{skipOriginPush}` flag so the
back button can re-enter a prior artist without re-pushing onto the stack.
Fresh entries from a non-artist page clear any stale stack from a prior
chain. Duplicate-click detection avoids pushing the same target twice.
Label derivation (`_updateArtistDetailBackButtonLabel`) reads the stack top
so the button says "Back to <ArtistName>" mid-chain and "Back to Search"
at the root.
**library.js — checkArtistEnhanceEligibility after library upgrade (Cin):**
The quality-analysis endpoint only works on library PKs. After the
library-upgrade branch rewrites `currentArtistId` from the source ID to
the library PK, the check was still using the original closure arg, so
upgraded source artists never hit `/api/library/artist/<id>/quality-analysis`.
Use `artistDetailPageState.currentArtistId` so the call gets the resolved id.
**init.js — isPageAllowed + home page recursion (Cin):**
- artist-detail is reachable from both Library and Search results now, so
permission check accepts either grant (plus legacy 'downloads'/'artists'
aliases). Search-only profiles can open source artists; legacy artists-only
profiles no longer recurse on the home redirect.
- `getProfileHomePage` rewrites 'artists' → 'search' (it already rewrote
'downloads') so legacy home_page values resolve correctly.
- Legacy-compat expanded in isPageAllowed to treat 'artists' as equivalent
to 'search' in both directions.
**init.js — profile edit forms dropping values on save (Cin):**
Both pageLabels maps (admin edit form + self-edit form) referenced the
legacy 'downloads'/'artists' keys. When editing a profile saved with
`home_page: 'search'` and `allowed_pages: ['search', 'library']`, the
home select didn't render a 'search' option, and the allowed_pages
checkboxes used 'downloads' as their value — so saving the form dropped
both values.
Update both maps to use 'search' as the canonical key. Add
`_normalizeLegacyAllowedPages` and `_normalizeLegacyHomePage` helpers that
migrate any legacy ids in allowed_pages/home_page on read, so a legacy
profile's first save upgrades its stored ids to the new canonical form.
|
1 month ago |
|
|
1aedc2ddcf |
Don't highlight sidebar Library when on /artist-detail
Cin: arriving at artist-detail from Search/Discover/Watchlist highlighted the Library sidebar entry, which is misleading — the user didn't navigate via Library. The hardcoded mapping was a holdover from when artist-detail was reached only from the (now retired) Artists page. Drop the special case so artist-detail behaves like playlist-explorer: no [data-page] match in the sidebar, no highlight. The user's actual origin page is already preserved on the back button. The deep-link fallback in _getPageFromPath (artist-detail → library) is left intact: if someone pastes /artist-detail in the URL bar with no state to render, library is still the most sensible landing page, and sidebar-highlighting Library in that scenario is correct because they're literally on Library. |
1 month ago |
|
|
93f1941829 |
Unify artist detail: route source artists to standalone page, retire inline Artists page
Completes the artist-detail unification. Source artists now land on the same /artist-detail page as library artists (with the source-aware backend endpoint from earlier this session handling the data fetch). The inline Artists page is gone — artists.js deleted, #artists-page HTML block removed, /artists URL aliases to /search. Source-artist callsites re-migrated from selectArtistForDetail to navigateToArtistDetail (search results, global widget, download modal, Discover hero / Your Artists cards / artmap context / genre deep-dive, watchlist artist detail). Visual upgrade to standalone hero: added .artist-detail-hero-bg + .artist-detail-hero-overlay (blurred image bg, dark gradient — same treatment as the inline page). library.js sets the bg image when loading an artist. Library-only UI hidden via CSS for source artists (existing rules from the previous commit cover Enhanced toggle, Status filter, completion bars, enrichment coverage, Top Tracks sidebar, Radio / Enhance buttons). Final 2 helpers (lazyLoadArtistImages used by wishlist-tools, showCompletionError used by completion checker) moved from artists.js into shared-helpers.js. The inline-page candidate set was dropped from _resolveSimilarArtistsTargets. init.js: 'artists' alias added at top of navigateToPage (same pattern as the existing 'downloads' alias). 'case artists:' handler removed from loadPageData. _getPageFromPath now maps artist-detail to library as its parent (matches the existing nav highlight at init.js:2161). tests/test_script_split_integrity.py: artists.js removed from SPLIT_MODULES; KNOWN_CROSS_FILE_DUPES updated to point escapeHtml at shared-helpers.js instead of artists.js. 354/354 tests pass. Net delta: -1700 lines. Stays at 2.39. Once you've verified end-to-end (library artist -> hero looks like inline visual; source artist from Search -> same page, similar artists works, no 404s; /artists URL -> /search), a follow-up commit bumps to 2.40 with the full WHATS_NEW entry that's already prepped. |
1 month ago |
|
|
1a8071d6ec |
Revert "Retire artists.js and inline Artists page, ship unification at 2.40"
This reverts commit
|
1 month ago |
|
|
71ff5cb5c3 |
Retire artists.js and inline Artists page, ship unification at 2.40
Part D + E of the deferred cleanup + the final version bump that
publishes the whole Search/Artists unification project.
Deletions:
- webui/static/artists.js (1903 lines) — removed entirely. The 2
remaining externally-referenced helpers (lazyLoadArtistImages +
showCompletionError) moved into shared-helpers.js first.
- webui/index.html — 140-line #artists-page HTML block and the
<script src="artists.js"> tag both removed.
init.js wiring:
- 'case artists:' removed from loadPageData switch (no page to init).
- navigateToPage top-level alias extended: 'artists' → 'search'
(same pattern as the existing 'downloads' → 'search' alias).
Legacy /artists bookmarks land on the unified Search page, the
natural place to find an artist now.
- _getPageFromPath now maps artist-detail → library as its parent
(was artists). Matches the existing library-nav-highlight at
init.js:2161.
Version bump:
- _SOULSYNC_BASE_VERSION 2.39 → 2.40.
- WHATS_NEW entries lose the 'unreleased' scaffolding and gain a
new top entry summarizing the unified artist-detail page + the
final artists.js retirement.
- version-info modal gets a 'Search & Artists Unification' section
at the top.
- The _getLatestWhatsNewVersion filter added during the unreleased-
tracking phase is rolled back — entries now display as soon as
they land in WHATS_NEW, matching the pre-unification behaviour.
Test suite:
- tests/test_script_split_integrity.py SPLIT_MODULES updated:
'artists.js' dropped, 'shared-helpers.js' added. escapeHtml's
cross-file dupe list entry updated to reference shared-helpers.
- 354/354 tests pass.
User-visible result after this commit:
- Sidebar: Search, Downloads, Discover, Library, Wishlist, etc. —
no more Artists entry.
- Click any artist anywhere: lands on the same /artist-detail page.
- Search page has a source dropdown; Soulseek is just another option.
- Legacy /downloads and /artists URLs alias to /search.
- Version button shows v2.3 (Docker major); "What's New" panel
opens to the unification summary.
Closes the project Cin requested in Discord. Future work: source-aware
/api/artist-detail could be extended to fall back through the whole
source priority chain when a specific source is given but returns no
discography. Not needed for the current flows.
|
1 month ago |
|
|
f203b3e46d |
Remove embedded Download Manager from Search page, bump to 2.44
Phase 3c of the Search/Artists unification. The Search page carried
a second copy of the Download Manager (active + finished queues,
clear/cancel-all buttons) that was hidden by default and duplicated
the dedicated Downloads page. That duplicate is now gone.
Removed:
- Side-panel HTML block and the toggle button that showed/hid it
- ~290 lines of polling + render infra in downloads.js: loadDownloads-
Data, startDownloadPolling/stopDownloadPolling, updateDownload-
Queues, renderQueue, updateTabCounts/updateDownloadStats,
initializeDownloadTabs/switchDownloadTab, cancelDownloadItem,
clearFinishedDownloads, cancelAllDownloads, and the
activeDownloads/finishedDownloads globals
- initializeDownloadManagerToggle and its call from init.js
- Stopped hitting /api/downloads/status every second on the Search
page (the dedicated Downloads page already polls its own view)
CSS grid for the Search page collapsed from '1fr 370px' to '1fr' now
that the right panel is gone. Unused .controls-panel__* / .download-
manager__* / .downloads-side-panel CSS rules kept in place — harmless,
can be pruned later.
|
1 month ago |
|
|
6992e2e5b5 |
Rename Search page id from 'downloads' to 'search', bump to 2.43
Phase 3b of the Search/Artists unification. The Search page's
internal id was 'downloads', which clashed with the actual Downloads
page (id 'active-downloads') and confused anyone reading the code.
Renamed to 'search' across HTML, navigation, DOM selectors, and the
deep-link route list.
Backwards compat: navigateToPage('downloads') aliases to 'search'
at the top of the function; /downloads URL still serves index.html
and the client router resolves the page correctly; profile ACL
checks accept both 'search' and 'downloads' so existing profiles
with 'downloads' in allowed_pages keep working without migration.
Sidebar label unchanged. Zero visual change — pure internal tidy.
|
1 month ago |
|
|
a66c4d06e1 |
Split monolithic script.js (78K lines) into 17 domain modules
Extracts the single 77,957-line script.js into focused modules: core.js (874) - Global state, confirm dialog, websocket, constants init.js (2358) - Initialization, personal settings, navigation media-player.js (2398) - Media player, audio, visualizer, radio settings.js (3657) - Settings page, quality profiles, API keys, auth search.js (1542) - Search functionality, page data loading sync-spotify.js (2538) - Spotify sync, YouTube backend, hero section downloads.js (6398) - Wing It, batched polling, cancel, notifications wishlist-tools.js (7234) - Wishlist, matched downloads, tools, retag sync-services.js (9076) - Tidal, Deezer, Beatport, YouTube, ListenBrainz sync artists.js (4610) - Artists page, artist downloads api-monitor.js (3798) - API rate monitor gauges library.js (6652) - Library, artist detail, enhanced management beatport-ui.js (3902) - Beatport sliders, genre browser discover.js (8920) - Discover page and all sub-sections enrichment.js (3551) - All enrichment workers, library repair stats-automations.js (7575) - Stats, automations, issues, import pages-extra.js (2874) - Playlist explorer, server playlists, active downloads Load order: core.js first (globals), init.js last (DOMContentLoaded). All other modules define functions and load in any order. No functional changes - pure extraction along existing section boundaries. |
1 month ago |