Commit graph

372 commits

Author SHA1 Message Date
Broque Thomas
2990b571b4 Add Clear Cache & Use Fallback button to Spotify settings
Always-visible button in Spotify API section that clears the OAuth
token cache, pauses enrichment, and switches to the configured
fallback metadata source. Also fixed the dashboard service card to
show the actual active source name (Spotify/iTunes/Deezer) instead
of always showing "Spotify" with an amber fallback indicator.
2026-03-30 17:20:33 -07:00
Broque Thomas
69346ec313 Add Playlist Explorer — visual discovery tree for expanding playlists
New dedicated Explorer page with interactive node graph visualization.
Users select a mirrored playlist, choose Albums or Discographies mode,
and the app builds a branching tree: playlist root → artist nodes →
album nodes → track nodes. Supports all metadata sources (Spotify,
iTunes, Deezer) with source-aware discovery cache integration.

Features:
- Streaming NDJSON builds tree progressively as artist data arrives
- Circular artist nodes with photos, rounded album nodes with art
- SVG bezier connections that draw in on completion, fade on hover
- Click artist to expand albums, double-click album for track listing
- Single-click albums to select, Select All/Deselect for bulk ops
- Wishlist confirmation modal with per-album progress (NDJSON streaming)
- Artist nodes glow when any of their albums are selected
- Playlist picker with source tabs, discovery % gate (50% minimum)
- Zoom (scroll/pinch/buttons), pan (right/middle-drag), fit-to-view
- Metadata cache for discographies and album track listings
- Owned album detection from library database
- Fallback track-name matching when album names are missing
2026-03-30 17:13:30 -07:00
Broque Thomas
c5652b0d4b Add API call counts and Spotify budget to dashboard service chips
Enrichment chips now show live activity: 24h call count for all
services and daily budget usage (used/3,000) with gradient progress
bar for Spotify. Tracking is centralized in _get_enrichment_status
using cumulative stat diffs over a rolling deque — no worker files
modified. Added section header, "Configure →" label for unconfigured
services, and full 1h/24h breakdown in tooltips.
2026-03-30 13:20:22 -07:00
Broque Thomas
525a09c840 Fix collaborative album artist not applied to single downloads (#215)
Single path template was missing _artists_list and _itunes_artist_id
context keys, so the collab mode first-artist extraction in
_apply_path_template had nothing to work with — $albumartist resolved
to the full multi-artist string. Added both keys matching the exact
pattern used by album and playlist modes, including the iTunes
spotify_album.external_urls fallback. Updated settings UI hints to
show $albumartist as available for single and playlist templates.
2026-03-30 11:37:05 -07:00
Broque Thomas
32adc66fe3 Show all services on dashboard with click-to-configure (#219)
Dashboard now displays all enrichment services as live-status chips
below the core service cards. Each chip shows Running, Idle, Paused,
Stopped, or Not Configured state with color-coded left border accents.
Unconfigured services appear dimmed with dashed borders — clicking any
configurable chip navigates to Settings → Connections and scrolls to
the relevant service section.

Also fixes the Spotify card always being labeled "Apple Music" when
using iTunes fallback — card now always says "Spotify" with an amber
"Using iTunes/Deezer" indicator when fallback is active.
2026-03-30 10:04:13 -07:00
Broque Thomas
ab8e44dafd Add Qobuz credentials to Settings Connections tab (#218)
Qobuz login was only available on the Downloads tab when Qobuz was
selected as download source. But Qobuz credentials are also needed
for the enrichment worker which runs independently. Users saw
"Connect Qobuz in Settings" on the dashboard but couldn't find it.

Adds a Qobuz section to Settings → Connections (same pattern as
Tidal's existing Connections section). checkQobuzAuthStatus() now
syncs both the Connections and Downloads tab sections. Login from
either tab updates both. No backend changes — same API endpoints.
2026-03-30 08:45:30 -07:00
Broque Thomas
59587162cd Add metadata cache maintenance and health monitoring
Cache maintenance:
- Input validation rejects junk entities (Unknown Artist, empty names)
  from being cached, with exemptions for synthetic entries (_features,
  _tracks suffixes)
- CacheEvictorJob expanded to 4 phases: TTL eviction, junk cleanup,
  orphaned search cleanup, MusicBrainz failed lookup cleanup
- MusicBrainz null results now expire after 30 days (was 90) so failed
  lookups get retried sooner

Cache health UI:
- Polished modal accessible from Dashboard "Cache Health" button and
  repair dashboard health bar
- Shows health status banner (healthy/fair/poor), stat cards, source
  breakdown with colored progress bars, type pills, and metrics table
- Repair dashboard shows compact bar with health dot indicator
2026-03-30 07:40:20 -07:00
Broque Thomas
3c47281ce5 Redesign Watch All Unwatched as polished preview modal
Replaces the fire-and-forget button with a premium modal that shows
exactly which artists will be added before confirming. Features:

- Glassmorphic modal with stat cards, two-column artist grid, search
  filter, collapsible ineligible section, and loading spinner
- Source-aware filtering: only shows artists with the active source's
  ID (Spotify/iTunes/Deezer) as eligible
- Frontend and backend both paginate at 400 to avoid SQLite variable
  limit (SQLITE_MAX_VARIABLE_NUMBER=999) that silently broke queries
  above ~500 artists
- Backend source detection aligned with frontend — uses only the
  active source's ID, falls back to configured metadata source
2026-03-29 18:12:42 -07:00
Broque Thomas
b5b03a2b86 Add Download Discography feature on artist detail page
New "Download Discography" button in artist hero section opens a modal
showing the full catalog — albums, EPs, and singles — with filter
toggles, select/deselect all, and per-album owned/missing indicators.

Modal features:
- Glassmorphic design with artist image blurred background header
- Filter pills for Albums/EPs/Singles with instant grid filtering
- Album cards with cover art, year, track count, and checkbox
- Owned albums dimmed and unchecked by default, missing pre-selected
- Live NDJSON streaming: each album updates in real-time as processed
- "Process Wishlist Now" button after completion
- Albums sorted by track count (Deluxe first) to prevent duplicate
  folder contexts from standard/deluxe edition ordering

Backend: NDJSON streaming endpoint POST /api/artist/<id>/download-discography
- Fetches tracks per album via active metadata client
- Adds to wishlist with dedup (no slow fuzzy matching)
- Streams one JSON line per album as it completes
- Works on both Artists search page and Library artist detail page
2026-03-27 22:15:05 -07:00
Broque Thomas
b49806a83a Add collaborative album artist handling with per-source resolution
New setting in Settings → Library → File Organization: "Collaborative
Album Artist" — choose between first listed artist (default) or all
artists combined for $albumartist in folder paths and album_artist tag.

Per-source resolution:
- Spotify: artists array has separate objects — picks first directly
- Deezer: API already returns first artist only — no change needed
- iTunes: combined string ("Larry June, Curren$y & The Alchemist") —
  resolves via artistId API lookup to get primary name ("Larry June").
  Safe for "Tyler, the Creator" and "Simon & Garfunkel" because their
  IDs resolve to the same combined name (no change).

Applied to both folder path ($albumartist template) and album_artist
metadata tag for consistency. Track artist tag always keeps all artists.
iTunes lookup only fires when source is iTunes (numeric ID + not Deezer).
2026-03-27 13:39:27 -07:00
Broque Thomas
a33f891fa6 Add per-artist watchlist lookback period override
New "Scan Lookback" dropdown in the watchlist artist config modal.
Each artist can override the global lookback period (7d to entire
discography). Default is "Use Global Setting" (NULL in DB).

- Database: lookback_days INTEGER DEFAULT NULL on watchlist_artists,
  auto-migrated on startup
- Scanner: checks per-artist lookback_days first, falls back to
  global discovery_lookback_period if NULL
- Backend: GET/POST /api/watchlist/artist/<id>/config includes
  lookback_days. Changing lookback clears last_scan_timestamp to
  force a rescan with the new window
- Frontend: dropdown with 8 options in artist config modal
- Fully backwards compatible — existing artists unchanged
2026-03-27 08:17:02 -07:00
Broque Thomas
9fcbd323a5 Add stream source setting, auto-update yt-dlp on container start
Stream source:
- New setting in Settings → Downloads: "Stream / Preview Source"
- Options: YouTube (instant, default) or Active Download Source
- YouTube streams require no auth and are instant
- If active source is Soulseek, automatically falls back to YouTube
- Uses direct client search (bypasses orchestrator's download mode)
- Config key: download_source.stream_source

Docker:
- entrypoint.sh now runs pip install -U yt-dlp on every container
  start, so Docker users always have the latest yt-dlp without
  rebuilding the image
2026-03-26 19:27:35 -07:00
Broque Thomas
f19db4ecce Add launch PIN lock screen with credential-based recovery
Security:
- Toggle in Settings → Advanced: "Require PIN to access SoulSync"
- Full-screen lock overlay on every page load when enabled
- PIN validated server-side against admin profile (bcrypt hash)
- Inline PIN creation if admin has no PIN set, change PIN button if set
- One-time session flag: verify-launch-pin sets it, /profiles/current
  consumes it — every page load re-requires PIN

Recovery:
- "Forgot PIN?" on lock screen switches to credential verification
- User pastes any configured API key/token/secret (Spotify, Tidal,
  Plex, Jellyfin, Navidrome, ListenBrainz, AcoustID, Last.fm, Genius)
- Server checks against all 9 stored values — any match clears PIN
  and disables lock, with toast guiding to Settings to set a new one

Profile switch integration:
- Entering PIN during profile switch also sets launch_pin_verified
  flag, preventing double-PIN prompt on the subsequent page reload

Updated version modal and helper What's New with this feature.
2026-03-26 13:15:36 -07:00
Broque Thomas
f6709c7cc3 Add library ownership badges to enhanced search results
Search results now show "In Library" badges on albums and tracks
that already exist in the user's library. Badges appear with a
staggered fade-in animation after results render (non-blocking).

- Backend: /api/enhanced-search/library-check endpoint builds
  owned album/track sets in 2 queries, O(1) lookups per result
- Frontend: async call after render, 30ms stagger per badge
- Tracks in library get play button rewired for direct playback
  from media server instead of searching download sources
- Fixed enhanced search album card text not visible (info div
  now absolute-positioned with gradient overlay)
- Download manager panel hidden by default for more search space
2026-03-25 19:39:19 -07:00
Broque Thomas
38ba6ddbc1 Add interactive contextual help system with floating helper button
New feature: click the floating ? button (bottom-right corner) to
enter help mode. Click any UI element to see a popover explaining
what it is and how to use it. Covers Dashboard + Sidebar + Watchlist.

- Floating button always visible above modals (z-index 999999)
- Click interception via capture phase prevents accidental actions
- Popover with smart positioning (right/left/below fallback)
- Arrow pointing to target element with accent highlight pulse
- "View full documentation" links navigate to the correct docs section
- Escape key dismisses popover or exits help mode
- Works inside modals (watchlist, artist config, global settings)
- 45+ contextual help entries covering sidebar nav, service cards,
  stat cards, all 9 tool cards, watchlist modal buttons, artist
  config options, content filters, and activity feed
- Separate helper.js file for maintainability
2026-03-25 17:34:43 -07:00
Broque Thomas
d248c36da1 Redesign Artists page: rich hero section, full-bleed cards, multi-source genres
Artists page hero section:
- Large portrait artist photo (400x480px, rounded rectangle)
- Blurred saturated background from artist image
- 2.6em bold name with text shadow
- Real service logo badges (Spotify, MusicBrainz, Deezer, iTunes,
  Last.fm, Genius, Tidal, Qobuz) — matching library page
- Genre pills merged from metadata cache + Last.fm tags
- Last.fm bio with read more/show less toggle
- Last.fm listener count + playcount stats (large bold numbers)
- Backend enriches discography response with artist_info from
  metadata cache + library (all service IDs, Last.fm data, genres)

Album/Single/EP cards:
- Full-bleed cover art filling entire card with gradient overlay
- Album name + year overlaid at bottom over dark gradient
- Image zoom on hover, accent glow for dynamic-glow cards
- Responsive grid (220px desktop, 170px tablet, 140px mobile)

Similar artist cards:
- Full-bleed image cards matching library artist card style
- Gradient overlay with name at bottom, aspect-ratio 0.8
- Grid-controlled sizing via existing responsive breakpoints

Genre explorer (multi-source):
- Queries all allowed sources (iTunes+Deezer always, Spotify when
  authed) via _get_genre_allowed_sources() helper
- Deezer genre support: genre_id mapping from search results,
  one-time backfill from stored raw_json, album-to-artist propagation
- Genre deep dive deduplicates artists across sources
- Source dots on artists/tracks in deep dive modal
- Artist clicks route through source-specific client
- Album endpoint falls back across sources when IDs don't match
- Genre explorer cached 24hr in-memory, positioned at top of
  Discover page below hero slider

All changes mobile responsive with proper breakpoints.
2026-03-25 11:49:51 -07:00
Broque Thomas
89cfea0fe7 Add per-source quality fallback toggle for streaming downloads (#187)
Each streaming source (Tidal, Qobuz, HiFi, Deezer) now has an "Allow
quality fallback" checkbox in Settings. When disabled, the source only
tries the exact quality selected — if unavailable, it skips and lets
the orchestrator try the next source. Default is ON (current behavior).
2026-03-24 11:42:47 -07:00
Broque Thomas
96fa3fe388 Add SoulSync logo to sidebar header next to app name 2026-03-23 21:24:39 -07:00
Broque Thomas
e652726c22 Invert Tidal/Qobuz hero badges, add Artist Radio button and Last.fm play buttons
- Tidal and Qobuz SVG logos inverted on artist detail hero badges
- New Artist Radio button: clears queue, plays random artist track, enables radio
- Play buttons on Last.fm top tracks (hover reveal, resolves from library)
- Fixed inline JS escaping with data attribute delegation
2026-03-23 20:42:33 -07:00
Broque Thomas
571ba6b532 Version 2.1: Deezer downloads, cache discovery, stats, glass UI, album consistency
Major version bump with 40+ commits of features and fixes:
- Deezer as 6th download source (ARL auth, FLAC/MP3, Blowfish decrypt)
- Cache-powered discovery: 5 sections + Genre Deep Dive modal
- Listening Stats page with charts and play buttons
- Picard-style MB release preflight for consistent album tagging
- Album Tag Consistency repair job
- Unified glass UI across dashboard, sync, and modals
- Mobile responsive overhaul for all pages
- Enrichment fixes: retry loops, rate limits, worker pause during scans
- AcoustID skip for trusted API sources
2026-03-23 16:45:23 -07:00
Broque Thomas
2ae5050ef1 Add Deezer download source: client, settings UI, ARL authentication
- New core/deezer_download_client.py: full download client with ARL auth,
  Blowfish decryption, quality fallback (FLAC/MP3 320/MP3 128), search,
  thread-safe download tracking. Not yet integrated into orchestrator.
- Settings UI: Deezer download quality selector, ARL token input, test
  connection button. Appears in download source dropdown and hybrid list.
- Test endpoint: /api/deezer-download/test verifies ARL and returns tier.
- Added deezer_download to settings save whitelist and sensitive paths.
- Fixed Spotify enrichment worker default to unpaused (like other workers).
2026-03-23 15:06:40 -07:00
Broque Thomas
e3d70da55a Add DB storage visualization + cache-powered discovery sections + Genre Deep Dive
- Stats page: database storage donut chart with per-table breakdown and total size
- Discover page: 5 new sections mined from metadata cache (zero API calls):
  Undiscovered Albums, New In Your Genres, From Your Labels, Deep Cuts, Genre Explorer
- Genre Deep Dive modal: artists (clickable → artist page), popular tracks,
  albums with download flow, related genre pills, in-library badges
- All cache queries filtered by active metadata source (Spotify/iTunes/Deezer)
- Stale cache entries (404) gracefully fall back to name+artist resolution
- Album cards show "In Library" badge, artist avatars scaled by prominence
2026-03-22 21:35:18 -07:00
Broque Thomas
93005298ee Cap Opus bitrate at 256kbps, fix lossy copy flavor text, redesign artist action buttons 2026-03-22 16:34:36 -07:00
Broque Thomas
8c84189121 Add per-artist enrichment coverage rings to artist hero section 2026-03-22 15:56:12 -07:00
Broque Thomas
9e75731f6c Add scrobbling to Last.fm/ListenBrainz + update What's New
Scrobbling:
- Last.fm: API signing, web auth flow, batch scrobble (50/request)
- ListenBrainz: submit_listens (batch 1000, listen_type=import)
- Worker hook: scrobbles unscrobbled events after each poll
- DB: scrobbled_lastfm/scrobbled_listenbrainz tracking columns
- Settings: API secret input, authorize button, scrobble toggles
- Config: lastfm.api_secret, lastfm.session_key, *.scrobble_enabled

What's New: added all features from this session (scrobbling,
personalized discovery, stats page, SoulID, lossy codecs, import,
hero redesign, Hydrabase, orphan fixes, year collection).
2026-03-22 14:38:53 -07:00
Broque Thomas
cfb0e85564 Add Listening Stats page with media server play data integration
Full stats dashboard that polls Plex/Jellyfin/Navidrome for play
history and presents it with Chart.js visualizations:

Backend:
- ListeningStatsWorker polls active server every 30 min
- listening_history DB table with dedup, play_count/last_played on tracks
- get_play_history() and get_track_play_counts() for all 3 servers
- Pre-computed cache for all time ranges (7d/30d/12m/all) rebuilt each sync
- Single cached endpoint serves all stats data instantly
- Stats query methods: top artists/albums/tracks, timeline, genres, health

Frontend:
- New Stats nav page with glassmorphic container matching dashboard style
- Overview cards (plays, time, artists, albums, tracks) with accent hover
- Listening timeline bar chart (Chart.js)
- Genre breakdown doughnut chart with legend
- Top artists visual bubbles with profile pictures + ranked list
- Top albums and tracks ranked lists with album art
- Library health: format breakdown bar, unplayed count, enrichment coverage
- Recently played timeline with relative timestamps
- Time range pills with instant switching via cache
- Sync Now button with spinner, last synced timestamp
- Clickable artist names navigate to library artist detail
- Last.fm global listeners shown alongside personal play counts
- SoulID badges on matched artists
- Empty state when no data synced yet
- Mobile responsive layout

DB migrations: listening_history table, play_count/last_played columns,
all with idempotent CREATE IF NOT EXISTS / PRAGMA checks.
2026-03-22 13:18:14 -07:00
Broque Thomas
491b89a1d2 Redesign library artist hero with Last.fm integration
- Add get_artist_top_tracks to Last.fm client (up to 100 tracks)
- Include lastfm_listeners, lastfm_playcount, lastfm_tags, lastfm_bio,
  and soul_id in artist detail API response
- New endpoint: /api/artist/<id>/lastfm-top-tracks for lazy loading
- Hero layout: image (160px) | center (name, badges, genres, bio,
  listener/play stats, progress bars) | right card (scrollable top
  100 tracks from Last.fm)
- Badges 36px with hover lift, bio in subtle card with Read More
  toggle, Last.fm tags merged with existing genres
- Numbers formatted: 1234567 → 1.2M
- Graceful degradation: sections hidden when Last.fm data unavailable
2026-03-21 23:04:34 -07:00
Broque Thomas
f9fc95c9f5 Add Opus and AAC codec options to lossy copy (Blasphemy Mode)
Lossy copy now supports MP3, Opus, and AAC (M4A) codecs with a
configurable dropdown in settings. Each codec uses the appropriate
ffmpeg encoder (libmp3lame/libopus/aac) and Mutagen tag writer
(ID3/Vorbis/MP4). Quality tag, filename substitution, and Blasphemy
Mode file cleanup all work per-codec. Backward compatible — existing
configs default to MP3.
2026-03-21 20:19:36 -07:00
Broque Thomas
2d511d0a16 Add SoulID worker with API-based debut year disambiguation
SoulID worker generates deterministic soul IDs for all library entities:
  - Artists: hash(name + debut_year) — searches iTunes + Deezer APIs,
    verifies correct artist by matching discography against local DB
    albums via MusicMatchingEngine, pools years from both sources and
    picks the earliest. Falls back to hash(name) if no match found.
  - Albums: hash(artist + album)
  - Tracks: song ID hash(artist + track) + album ID hash(artist + album + track)

Dashboard button with trans2.png logo, rainbow spinner, hover tooltip.
Worker orb with rainbow effect. SoulSync badge on library artist cards.
DB migration adds soul_id columns with indexes to artists/albums/tracks.
Migration version flag auto-resets artist soul IDs when algorithm changes.
2026-03-21 10:21:06 -07:00
Broque Thomas
10361bb837 Complete Hydrabase as selectable fallback metadata source
- Remove redundant enable checkbox — fallback dropdown is the enable
- Hydrabase option only appears in dropdown when connected
- Connect/disconnect dynamically adds/removes dropdown option
- _is_hydrabase_active checks fallback_source == hydrabase (not config toggle)
- Fallback client returns hydrabase_client when selected, iTunes if disconnected
- Auto-reconnect respects fallback selection for dev_mode handling
- hydrabase added to settings save service list for persistence
- Status shows green Connected on page load when auto-connected
2026-03-20 14:18:10 -07:00
Broque Thomas
2f9491c71b Expose Hydrabase as a configurable metadata source (no dev mode needed)
Add Hydrabase section to Settings → Connections with enable toggle,
WebSocket URL, API key, auto-connect, and connect/disconnect button.
_is_hydrabase_active() now checks hydrabase.enabled config in addition
to dev_mode — either path activates it. Default disabled, zero change
for existing users. Dev admin page stays behind dev mode password.
2026-03-20 13:41:02 -07:00
Broque Thomas
fc4e16337a Redesign hybrid mode with N-source priority ordering
Replace fixed primary/secondary hybrid dropdowns with an ordered list
of all 5 download sources. Users enable/disable each source and reorder
with up/down arrows to set download priority. Sources are tried in
order until one returns results.

- New hybrid_order config field (backward compat with legacy primary/secondary)
- Download orchestrator loops ordered list with per-source error handling
- Sortable source list UI with icons, toggle switches, priority numbers
- Source-specific settings shown for all enabled hybrid sources
- Seamless migration from legacy 2-source to N-source format
2026-03-19 18:51:52 -07:00
Broque Thomas
42b457f9d6 Redesign settings page with modern tabbed single-column layout
Replace 3-column glassmorphic card wall with centered single-column
tabbed interface. Horizontal pill tab bar (Connections, Downloads,
Library, Appearance, Advanced) with category switching.

- Kill glassmorphic cards, accent gradient bars, and box shadows
- Clean section headers with subtle dividers
- Horizontal setting rows (label left, control right)
- Custom styled select dropdowns with SVG arrow
- Quality Profile moved into Downloads tab (conditionally visible)
- Help text wraps to new line below controls
- Path inputs and template inputs properly styled
- Mobile responsive (rows stack, tab bar scrolls)
- Zero functional changes — all element IDs and JS logic preserved
2026-03-19 15:59:55 -07:00
Broque Thomas
e715ceef3e Add multi-source search tabs for enhanced search (Spotify/iTunes/Deezer)
Search results now show switchable tabs for alternate metadata sources.
Primary source renders immediately, alternate sources load in parallel
and tabs appear progressively as each completes.

- New /api/enhanced-search/source/<name> endpoint for per-source queries
- Source-aware routing via ?source= param on discography, album tracks,
  album detail, and artist image endpoints (prevents numeric ID
  misrouting between iTunes and Deezer)
- Source override stored on artistsPageState for consistent navigation
- Tabs styled with source brand colors, show result counts
- All additive — users who ignore tabs see zero behavioral change
2026-03-19 13:23:43 -07:00
Broque Thomas
b9c83a50fa Add Soulseek peer queue filtering and configurable download timeout
- Add max_peer_queue setting to skip peers with long queues (soft filter
  with fallback to unfiltered if all results removed)
- Add download_timeout setting replacing hardcoded 10-minute limit
- Include quality_score (peer health: upload speed, free slots, queue
  length) in result ranking — was calculated but never used in sort key
- New UI controls in Soulseek settings section
2026-03-19 11:47:37 -07:00
Broque Thomas
b9732156cd Add per-tag granular toggle settings for all 47 embedded tags
Replace category-based tag settings (10 toggles) with per-tag controls
grouped by source service in an accordion UI. Each of the 11 service
groups (Spotify, iTunes, MusicBrainz, Deezer, AudioDB, Tidal, Qobuz,
Last.fm, Genius, General) has a master toggle that disables all child
tags, with individual toggles for fine-grained control. ISRC and
copyright fallback chains are now per-source toggleable. Genre merge
contributions from each source are independently controllable. All
tags default to enabled for backward compatibility.
2026-03-18 16:17:20 -07:00
Broque Thomas
d3bff90fd6 Add Picard-compatible MusicBrainz tags and per-category tag settings
Post-processing now writes all 18 MusicBrainz tags that Picard writes:
Release Group ID, Album Artist ID, Release Track ID, Release Type,
Status, Country, Original Date, Media, Barcode, Catalog #, ASIN,
Script, Total Discs (plus the 5 already supported). One cached API
call per album via get_release with recordings include.

New "Tags to Embed" settings section with 10 category toggles (all
enabled by default): MusicBrainz IDs, Release Info, Source IDs, ISRC,
BPM, Mood & Style, Copyright & Label, Genre Merging, URLs, Quality.
Each shows inline description of what it includes.
2026-03-18 15:49:36 -07:00
Broque Thomas
4a7f297b2c Add minimum peer upload speed setting and fix quality scoring tiers
New dropdown in Soulseek settings lets users filter out slow peers at
search time (Any/1/2/3/4/5/10 Mbps). Passes minimumPeerUploadSpeed
to slskd API in bytes/sec.

Also fixes quality scoring tiers which were using wrong units — old
thresholds (5000, 1000, 500) treated bytes/sec values as kbps,
making speed scoring effectively meaningless. Now uses correct
bytes/sec thresholds based on real peer data.
2026-03-18 14:07:39 -07:00
Broque Thomas
2656927f79 Beatport enrichment progress, metadata cache fixes, per-source cache clearing
- Fix enrichment progress never updating: remove `continue` that skipped
  progress_callback for successful tracks in enrich_chart_tracks
- Split chart/extract into two-step flow: extract raw tracks, then enrich
  via polling endpoint with live progress overlay updates
- Move Beatport enrichment cache to persistent metadata cache system
- Fix metadata cache detail modal for Beatport (URL entity_ids with slashes)
- Add per-source Clear dropdown (Spotify/iTunes/Deezer/Beatport) to cache browser
- Remove debug logging from enrichment progress tracking
2026-03-18 08:39:02 -07:00
Broque Thomas
fbf44123ec Add Beatport download bubbles, enrichment cache, and batch enrichment
- Persistent download bubble cards on Beatport page and dashboard,
  matching the existing artist/search bubble UX with click-to-reopen,
  green checkmark on completion, and snapshot persistence
- In-memory enrichment cache (2h TTL, thread-safe) skips re-scraping
  when the same chart is clicked twice
- Batch enrichment replaces one-by-one HTTP requests with a single
  POST, using WebSocket progress events for overlay updates
- Fix _beatportModalOpening guard blocking modal open after fast
  cached enrichment by resetting the flag in openBeatportChartAsDownloadModal
- Hide Browse/My Playlists tabs — Browse is now the only Beatport view
2026-03-17 21:41:04 -07:00
Broque Thomas
27a0cf8b81 Add Sync History feature with live re-sync progress and source detection
- New sync_history DB table tracks last 100 syncs with full cached context
- Records history for all sync types: Spotify, Tidal, Deezer, YouTube,
  Beatport, ListenBrainz, Mirrored playlists, and Download Missing flows
- Sync History button on sync page with modal showing entries, source
  filter tabs, stats badges, and pagination
- Re-sync button: server syncs expand card inline with live progress bar,
  matched/failed counts, and cancel button; download syncs open download modal
- Re-syncs update the original entry (moves to top) instead of creating duplicates
- Delete button (x) on each entry with smooth remove animation
- Fix mirrored playlist source detection (youtube_mirrored_ matched youtube_)
- Fix broken server import thumbnails with URL validation
2026-03-17 20:39:41 -07:00
Broque Thomas
a9d0607d25 Add hi-res FLAC to CD quality downsampling in post-processing
New toggle under Post-Download Conversion: automatically converts 24-bit
or high sample rate FLAC files to 16-bit/44.1kHz after download, replacing
the original. Uses ffmpeg with temp file + verify + atomic swap for safety.
Runs before lossy copy so MP3s are made from the downsampled version.
Also prevents bit depth strict mode from rejecting files that will be
downsampled anyway.
2026-03-17 11:53:56 -07:00
Broque Thomas
cc62541a65 Add Select All, Fix Selected & Fix All to Library Maintenance findings 2026-03-17 09:25:21 -07:00
Broque Thomas
4c6e2fe1ec Revamp automation page: 2-col grid, duplicate, search/filter, templates, grouping
- Switch user automations to 2-column grid layout (matches system automations)
- Add duplicate button on non-system cards with POST /api/automations/<id>/duplicate
- Add search/filter bar (text search + trigger/action dropdowns) shown at 6+ automations
- Add Inspiration section with 8 starter templates that pre-fill the builder
- Add folder-style automation grouping with group_name DB column, dropdown
  popover for assignment, collapsible group sections, and builder group input
2026-03-17 07:40:14 -07:00
Broque Thomas
46d3309835 Revamp watchlist & wishlist buttons with dark glass design and animated gradient border
- Dark translucent background with backdrop blur instead of bright colored fills
- Animated flowing gradient border using CSS mask-composite technique
- Color-tinted labels and count badges (amber for watchlist, accent for wishlist)
- Shimmer sweep clipped inside button bounds
- Structured HTML: separate icon, label, badge, and shimmer elements
- Badge pulses when count > 0
- Worker orbs: 7s delay before collapsing back after mouse leaves header
2026-03-16 18:10:10 -07:00
Broque Thomas
775307c2b5 Add worker orbs animation to dashboard header
Worker buttons shrink to floating colored orbs with physics-based
movement, spark emissions from active workers, connection lines, and
center gravity. Hovering the header expands orbs back to full buttons
with staggered spring animation. Desktop only, toggleable in Settings
under UI Appearance.
2026-03-16 16:47:37 -07:00
Broque Thomas
42a4285e09 Add clear findings button to library maintenance modal
Per-job and per-status filtering — respects active toolbar filters so
users can clear e.g. only track number findings or only dismissed items.
Confirmation uses the app's styled modal instead of browser confirm().
2026-03-16 15:37:33 -07:00
Broque Thomas
d6fd206efa Update sidebar version button to v2.0 2026-03-16 14:05:41 -07:00
Broque Thomas
a8f95592af Bump version to 2.0 with Deezer metadata source and latest changes
Add Deezer Metadata Source section to release notes covering configurable
fallback, source badges, auto-matching, and backward compatibility.
Update HiFi section with improved failover wording and add HiFi 500
failover fix to bug fixes list.
2026-03-16 14:02:46 -07:00
Broque Thomas
46ac46134b Add Deezer as configurable free metadata fallback source alongside iTunes
Users can now choose between iTunes/Apple Music and Deezer as their free
metadata source in Settings. Spotify always takes priority when authenticated;
the fallback handles all lookups when it's not.

Core changes:
- DeezerClient: full metadata interface (search, albums, artists, tracks)
  matching iTunesClient's API surface with identical dataclass return types
- SpotifyClient: configurable _fallback property switches between iTunes/Deezer
  based on live config reads (no restart needed)
- MetadataService, web_server, watchlist_scanner, api/search, repair_worker,
  seasonal_discovery, personalized_playlists: all direct iTunesClient imports
  replaced with fallback-aware helpers

Database:
- deezer_artist_id on watchlist_artists and similar_artists tables
- deezer_track_id/album_id/artist_id on discovery_pool and discovery_cache
- Full CRUD for Deezer IDs: add, read, update, backfill, metadata enrichment
- Watchlist duplicate detection by artist name prevents re-adding across sources
- SimilarArtist dataclass and all query/insert methods handle Deezer columns

Bug fixes found during review:
- Similar artist backfill was writing Deezer IDs into iTunes columns
- Discover hero was storing resolved Deezer IDs in wrong column
- Status cache not invalidating on settings save (source name lag)
- Watchlist add allowing duplicates when switching metadata sources
2026-03-16 13:12:12 -07:00
Broque Thomas
a02d14a23a Add URL history pills for YouTube, Deezer, and Spotify Link sync tabs
Saves successfully loaded playlist URLs to localStorage and displays
them as clickable pills between the input bar and playlist container.
Clicking a pill re-loads that URL; X button removes it. Max 10 per
source, most recent first. Source-colored hover accents match each
tab's brand styling.

Also fixes duplicate playlist bug — YouTube and Spotify Public now
check for already-loaded playlists before making API calls, preventing
broken duplicate cards when the same URL is entered twice.
2026-03-16 10:35:45 -07:00
Broque Thomas
837c5ff680 Add persistent library history tracking downloads and server imports
New library_history table logs every completed download and every new
track imported from Plex/Jellyfin/Navidrome. A "History" button next
to "Recent Activity" on the dashboard opens a modal with Downloads and
Server Imports tabs, album art thumbnails, quality/source badges, and
pagination.
2026-03-16 09:36:05 -07:00
Broque Thomas
ec389c5ae8 Add HiFi as free lossless download source via public hifi-api instances
New download mode alongside Soulseek, YouTube, Tidal, and Qobuz. Uses
community-run REST API instances (no auth required) that serve Tidal CDN
FLAC streams. Features quality fallback chain (hires→lossless→high→low),
automatic instance rotation on failure, and full hybrid mode support.

Also fixes 6 missing streaming source checks for HiFi and Qobuz in the
frontend that were blocking playback with "format not supported" errors.
2026-03-15 22:53:34 -07:00
Broque Thomas
483e45cbc0 Add Spotify Link tab for public playlist/album scraping without API credentials
Scrapes Spotify's embed endpoint to extract track data from any public
playlist or album URL. Full discovery flow with Deezer parity: parse →
card → discovery modal → live progress → sync → download missing.

- New scraper: core/spotify_public_scraper.py (embed endpoint parsing)
- 12 API endpoints mirroring Deezer's discovery/sync/download flow
- WebSocket live discovery updates via spotify_public_discovery_states
- Green-branded tab, cards, and input styling (#1DB954)
- Album vs playlist detection with distinct card icons (💿/🎵)
- Download persistence: card click reopens download modal after close
- Card phase reset on cancel/completion (closeDownloadMissingModal)
- Backend download linking for spotify_public_ and deezer_ prefixes
- Completion handlers (V2 + no-missing-tracks) for both platforms
- Source URLs stored on mirrored playlists for future auto-refresh
2026-03-15 21:25:05 -07:00
Broque Thomas
0742cc45e6 Add hemisphere setting for seasonal playlists on Discover page
Southern hemisphere users now see correct seasons (e.g. March = Autumn,
December = Summer). Holidays (Halloween, Christmas, Valentine's) stay
calendar-fixed regardless of hemisphere.

- Hemisphere dropdown in Discovery Pool Settings
- GET/POST /api/discovery/hemisphere endpoints
- Season detection offsets months by 6 for southern hemisphere
- Stored in metadata table, defaults to northern
2026-03-15 18:49:51 -07:00
Broque Thomas
f08550140f Add whistle logo to maintenance modal header & harden fix handlers
- Add whisoul.png to modal header with subtitle text and gradient background
- Responsive: smaller logo on mobile, hide subtitle
- Share _resolve_file_path in repair_worker for cross-environment path compat
- Use path resolution in orphan and duplicate file deletion
- Guard directory cleanup against removing the transfer folder itself
- Restore correct button label text on fix error recovery
2026-03-15 13:25:40 -07:00
Broque Thomas
7a706e8c11 Add fix actions for maintenance findings (dead files, orphans, duplicates, etc.)
- New fix_finding() dispatcher in repair_worker with per-type handlers:
  dead_file (remove DB entry), orphan_file (delete from disk),
  track_number_mismatch (update DB), missing_cover_art (apply artwork URL),
  metadata_gap (apply found fields), duplicate_tracks (keep best quality)
- New POST /api/repair/findings/<id>/fix endpoint
- Frontend: contextual fix buttons per finding type, bulk "Fix Selected"
- Removed path_mismatch from fixable types (dry-run preview only)
2026-03-15 12:51:18 -07:00
Broque Thomas
61ed4086e0 Redesign maintenance findings/history tabs with dashboard & fix path resolution bugs
- Add findings dashboard with summary stats and per-job clickable filter chips
- Redesign findings cards with expandable detail panels and per-type renderers
- Redesign history tab with status dots, stat pills, and full timestamps
- Fix dead file cleaner false positives by using suffix-based path resolution
- Fix orphan file detector false positives by matching via path suffixes
- Add help text modal for each repair job card
- Enlarge maintenance modal (1100px wide, 90vh tall)
2026-03-15 12:20:02 -07:00
Broque Thomas
4635ea895b include a '?' to include more details for each job. 2026-03-15 11:19:09 -07:00
Broque Thomas
cae2bd0c62 Add granular post-processing toggles for metadata services, cover art, and lyrics 2026-03-14 22:45:50 -07:00
Broque Thomas
8f0b9518bc Add per-profile ListenBrainz support with personal settings modal 2026-03-14 20:12:19 -07:00
Broque Thomas
9a22c49a0e Add FLAC bit depth fallback option to quality profile 2026-03-14 19:24:25 -07:00
Broque Thomas
7e19e66ef3 Add quality enhance button to upgrade existing library tracks & Add iTunes fallback to Quality Enhance endpoint for full metadata source parity 2026-03-14 17:09:08 -07:00
Broque Thomas
3bbbfb125e Add $albumtype template variable with smart EP/Single/Album detection 2026-03-14 12:40:25 -07:00
Broque Thomas
945f86c643 Library Repair Worker: multi-job background maintenance daemon with 10 jobs, findings system, and management modal 2026-03-14 09:09:18 -07:00
Broque Thomas
6de3ab7cef Add universal metadata cache for Spotify & iTunes API responses with browsable dashboard tool 2026-03-14 01:26:45 -07:00
Broque Thomas
c54e52e18d Add Spotify Library discovery section, instrumental filter, custom exclusion terms & album download modal fixes 2026-03-14 00:21:44 -07:00
Broque Thomas
a5e72cff05 Add instrumental filter & custom exclusion terms to watchlist content filters 2026-03-13 23:09:12 -07:00
Broque Thomas
32f1cc946c Improve watchlist cross-provider matching accuracy and add manual artist linking UI 2026-03-13 22:28:13 -07:00
Broque Thomas
0e89155c15 Add watchlist settings gear button to artist detail and artist card pages 2026-03-13 22:07:54 -07:00
Broque Thomas
e1a5bf678a Add library issue reporting system with actionable detail modal 2026-03-13 21:14:57 -07:00
Broque Thomas
57a8bdd107 Add album file reorganization to Enhanced Library Manager 2026-03-13 18:43:54 -07:00
Broque Thomas
4dfefc70df Polish settings page styling — premium header, toggle switches, refined inputs 2026-03-13 16:29:02 -07:00
Broque Thomas
f9bdabc0e4 Add particle background toggle & optimize accent color caching 2026-03-13 16:05:22 -07:00
Broque Thomas
a557074d3c Add Spotify rate limit modal with live countdown and ban duration escalation 2026-03-13 15:36:24 -07:00
Broque Thomas
55186c6a51 Add Deezer playlist sync tab with discovery, fix modal, and cache persistence 2026-03-13 12:29:49 -07:00
Broque Thomas
e8df863205 enhanced library write all modal and confirmation dialog 2026-03-12 16:57:38 -07:00
Broque Thomas
a3bf858558 Seamless Spotify rate limit UX — replace intrusive modal with ambient indicators 2026-03-12 12:45:59 -07:00
Broque Thomas
691e026208 Fix Tidal API search — correct endpoint casing, JSON:API Accept header, and best-match selection 2026-03-11 22:51:51 -07:00
Broque Thomas
35d6068f99 fix worker logos 2026-03-11 21:39:25 -07:00
Broque Thomas
ac2c710a1e Tidal & Qobuz Background Enrichment Workers 2026-03-11 21:26:20 -07:00
Broque Thomas
589d5bed79 settings page changes 2026-03-11 19:09:52 -07:00
Broque Thomas
e748434500 arrange settings page 2026-03-11 19:05:42 -07:00
Broque Thomas
f41db1bb27 reorganize settings page 2026-03-11 18:53:57 -07:00
Broque Thomas
0d547255d9 Move Soulseek settings to Download Source section & conditional source visibility 2026-03-11 18:33:11 -07:00
Broque Thomas
70c32aa640 Hybrid Mode Redesign 2026-03-11 18:10:35 -07:00
Broque Thomas
fb04d0f4bc Full qobuz support 2026-03-11 17:43:27 -07:00
Broque Thomas
636af1f2f8 Fix docs scroll spy jumping to wrong section due to duplicate element ID 2026-03-11 10:48:18 -07:00
Broque Thomas
0aa8950436 fix build a playlist functionality and update the ui 2026-03-11 07:52:58 -07:00
Broque Thomas
c06fd044a1 Profile Permissions & Page Access Control 2026-03-10 23:23:43 -07:00
Broque Thomas
f91626ef18 Per-Page Particle Animations 2026-03-10 19:46:31 -07:00
Broque Thomas
40521fa499 Sidebar audio visualizer with 5 reactive styles and settings toggle 2026-03-10 16:56:47 -07:00
Broque Thomas
a682f814f7 Sidebar SVG icons, larger page header icons, and accent-colored nav 2026-03-10 16:18:07 -07:00
Broque Thomas
1b0fca9009 Service Badges, Page Headers, Docs Page, and Bug Fixe 2026-03-10 14:47:11 -07:00
Broque Thomas
51b5469e85 Add page icons & gradient shimmer to all page headers 2026-03-10 13:12:50 -07:00
Broque Thomas
87d567151e iTunes storefront fallback with configurable country setting 2026-03-10 12:13:21 -07:00
Broque Thomas
dc7140c459 Add Last.fm and Genius to on-demand enrichment, settings reload, and enrich dropdown parity 2026-03-10 09:12:36 -07:00
Broque Thomas
f8d23ec37c Add Last.fm and Genius API clients with settings integration 2026-03-09 22:35:10 -07:00
Broque Thomas
e71ae7a5f7 Import file tab on sync page to create mirrored playlists from CSV/TXT files 2026-03-09 22:03:13 -07:00
Broque Thomas
aa93458ed3 Configurable ListenBrainz API endpoint for self-hosted instances 2026-03-09 20:52:33 -07:00
Broque Thomas
bbccd3524f Explicit content filter with configurable toggle to skip explicit tracks during downloads 2026-03-09 20:39:40 -07:00
Broque Thomas
b9d5d4e277 update page icons 2026-03-09 18:06:44 -07:00
Broque Thomas
eac97a6c2b Smart Spotify rate limit detection with global ban, auto-suppression, and frontend modal 2026-03-09 16:05:33 -07:00
Broque Thomas
cc4502e5f8 Add server sync option to enhanced library write-tags flow 2026-03-09 14:17:56 -07:00
Broque Thomas
ea1441d09d "Write Tags to File" in the Enhanced Library Manager 2026-03-09 11:17:01 -07:00
Broque Thomas
5f58432ca4 Redesigned media player with expanded Now Playing modal and smart radio 2026-03-09 10:13:42 -07:00
Broque Thomas
5b79ca1e88 redesign the media player in sidebar 2026-03-09 08:02:05 -07:00
Broque Thomas
7c50f350c0 Add a library management interface to the artist detail page with inline metadata editing, per-service manual matching, bulk operations, and full track/album management. 2026-03-08 23:37:02 -07:00
Broque Thomas
41edb31e07 Replace sidebar donation dropdown with support modal 2026-03-08 17:33:20 -07:00
Broque Thomas
f9e8c8dadd Add themed confirm dialog modal replacing all native browser confirms 2026-03-08 11:16:11 -07:00
Broque Thomas
266d044797 Add Backup Manager dashboard tool card with list, download, restore & delete 2026-03-08 10:46:03 -07:00
Broque Thomas
b90c270d54 Add Download Now button to wishlist modal and library page download bubbles 2026-03-07 00:11:15 -08:00
Broque Thomas
7647ac22ed Add Discovery Pool dashboard tool card and revamp modal with premium category-card design 2026-03-06 11:59:45 -08:00
Broque Thomas
9f416475e2 Live automation progress tracking with real-time output panels 2026-03-05 20:39:26 -08:00
Broque Thomas
4bd3e776bd css changes 2026-03-05 16:57:14 -08:00
Broque Thomas
da707dcf0a Full automation engine expansion with scheduling, triggers, actions, and UI polish 2026-03-05 15:13:32 -08:00
Broque Thomas
75f9b7364a User configurable youtube rate limiting and optional cookies for bot detection 2026-03-05 10:50:06 -08:00
Broque Thomas
60f93d5858 hydrabase changes 2026-03-04 19:48:12 -08:00
Broque Thomas
b30e1f60bd Add Mirrored Playlists — persistent cross-service playlist archive
Automatically mirrors every parsed playlist (Spotify, Tidal, YouTube, Beatport) to a local database so they're always accessible — even if a service subscription lapses or the browser closes.
  - New "Mirrored" tab on the Sync page with source-branded cards showing discovery/download status
  - Auto-mirrors on successful parse (upsert — re-parsing updates the existing mirror, no duplicates)
  - Click any mirrored playlist to browse its full track list, then run it through the discovery pipeline
  - Cards dynamically reflect live state: Discovering → Discovered → Downloading → Downloaded
  - Download modal rehydrates after page refresh — click a "Downloading..." card to resume viewing progress
  - All phase transitions (start, complete, cancel, error, modal close) keep card and backend state in sync
  - Profile-scoped via profile_id, consistent with other features
2026-03-04 18:27:18 -08:00
Broque Thomas
b2fa222228 fix hydrabse album.tracks 2026-03-04 15:12:03 -08:00
Broque Thomas
4fee005dee Add multi-profile support with Netflix-style profile picker
Allow multiple users to share a single SoulSync instance with isolated personal data. Each profile gets its own watchlist, wishlist, discovery pool, similar artists, and bubble snapshots — while sharing the same music library, database, and service credentials.

  - Netflix-style profile picker on startup when multiple profiles exist
  - Optional PIN protection per profile; admin PIN required when >1 profiles
  - Admin-only profile management (create, edit, rename, delete)
  - Profile avatar images via URL with colored-initial fallback
  - Zero-downtime SQLite migration — all existing data maps to auto-created
    admin profile
  - Single-user installs see no changes — profile system is invisible until
    a second profile is created
  - WebSocket count emitters scoped to profile rooms (watchlist/wishlist)
  - Background scanners (watchlist, wishlist, discovery) iterate all profiles
2026-03-04 10:46:08 -08:00
Broque Thomas
0f428dc45c Add WebSocket real-time updates with automatic HTTP polling fallback
Migrates 38 HTTP polling loops to WebSocket push events across 6 phases: service status, dashboard stats, enrichment workers, tool progress, sync/discovery progress, and scan status. All original HTTP polling is preserved as automatic fallback — if WebSocket is unavailable or disconnects, the app seamlessly reverts to its previous behavior. Includes 162 tests verifying event delivery, data shape, and HTTP parity. Also fixes a copy-paste bug in Beatport sync error cleanup.
2026-03-03 18:26:29 -08:00
Broque Thomas
d9aa8303a7 Add SoulSync REST API (v1) with API key authentication
Adds a full public REST API at /api/v1/ with 32 endpoints covering library, search, downloads, wishlist, watchlist, playlists, system status, and settings. Includes API key authentication (Bearer token), per-endpoint rate limiting, and consistent JSON response format. API keys can be generated and managed from the Settings page. No changes to existing functionality — the API delegates to the same backend services the web UI uses.
2026-03-03 09:49:00 -08:00
Broque Thomas
df33adf6a7 include 'add to watchlist' button to each artist in library. 2026-03-02 10:04:10 -08:00
Broque Thomas
1f73ba4f94 view recommended artists. 2026-03-02 09:12:35 -08:00
Broque Thomas
8f2dd66aee add a 'watch all' button on hero slider to quickly add all artists in slider. 2026-03-02 08:40:22 -08:00
Broque Thomas
c279f2e4fa Design retag layout 2026-03-01 22:52:27 -08:00
Broque Thomas
71fe5b83eb css changes 2026-03-01 15:34:51 -08:00
Broque Thomas
4fba18b25e Feat: Custom accent colors. 2026-03-01 15:29:37 -08:00
Broque Thomas
1aa6cdc9b6 Rebuild the import feature and move it to its own page. 2026-03-01 14:18:55 -08:00
Broque Thomas
afa495756f Version 1.7 update 2026-02-28 21:58:13 -08:00
Broque Thomas
acfc26a4bd Add Tidal as a download source with full pipeline integration
Adds Tidal as a third download source alongside Soulseek and YouTube. Uses the tidalapi library with device-flow authentication to search and download tracks in configurable quality (Low/High/Lossless/HiRes) with automatic fallback. Integrates into the download orchestrator for all modes (Tidal Only, Hybrid with fallback chain), the transfer monitor, post-processing pipeline, and file finder. Frontend includes download settings with quality selector, device auth flow, and dynamic sidebar/dashboard labels that reflect the active download source. No breaking changes for existing users.
2026-02-28 21:47:19 -08:00
Broque Thomas
698b1fa4f3 clear current downloads 2026-02-27 11:18:13 -08:00
Broque Thomas
2dc72a39b7 Add music library selection for Navidrome
SoulSync was importing from all Navidrome libraries regardless of user access restrictions. Added a "Music Library"   dropdown in Navidrome settings that lets users scope imports to a specific music folder. Uses the Subsonic musicFolderId       parameter on artist, album, and search API calls. Selecting "All Libraries" reverts to the previous behavior.
2026-02-27 09:37:58 -08:00
Broque Thomas
b814ae17ce Add quarantine clear API and folder sweeper
Add a POST /api/quarantine/clear endpoint to delete all files and folders inside the ss_quarantine directory (uses docker_resolve_path and reports removed item count). Implement _sweep_empty_download_directories() to walk the downloads folder bottom-up and remove empty directories (preserves root download dir, skips hidden entries, robust against locked/non-empty dirs). Wire the sweeper into existing cleanup flows: clear_finished_downloads(), the periodic _simple_monitor_task(), and the failed-tracks post-cleanup path so leftover empty folders are removed. Also add a Clear Quarantine button in the web UI and a clearQuarantine() client function to call the new API and show feedback.
2026-02-26 11:40:13 -08:00
Broque Thomas
44b5032f17 Add discography filters to artist detail page
Introduce interactive discography filters on the artist detail page. Adds filter UI markup (category, content, ownership) in index.html and styles in style.css. Implements filter state, initialization, reset and apply logic in script.js; tags release cards with data attributes (live/compilation/featured) using regex heuristics, updates visibility and per-section owned/missing counts, and re-applies filters when releases are updated. Integrates filter setup into page init and resets filters when loading artist data.
2026-02-26 10:17:53 -08:00
Broque Thomas
477615593e Increase Jellyfin API timeout default to 120
Raise the default Jellyfin API timeout for bulk operations from 30s to 120s to better handle slow servers and large database syncs. Updated core/jellyfin_client.py to set bulk_timeout to 120, webui/index.html to show 120s in the settings input, and webui/static/script.js to use 120 as the fallback when loading settings. Aligns UI and client behavior to reduce timeout errors during heavy syncs.
2026-02-26 08:28:08 -08:00
Broque Thomas
70156bdb98 Configurable Jellyfin API timeout and retries
Add a configurable API timeout for Jellyfin bulk requests and improve fetch retry behavior. UI: adds an "API Timeout (seconds)" field (15–300s, default 30) in webui/index.html and persists it via webui/static/script.js (load/save). Client: jellyfin_client.py now reads api_timeout from config_manager, uses it as the bulk timeout and computes a sensible non-bulk timeout (max(5, bulk_timeout//6)). Fetch loops for tracks and albums were hardened: reducing batch size now resets consecutive failure counters, log messages were clarified, and the stopping/retry thresholds were adjusted to avoid premature aborts at minimum batch sizes.
2026-02-26 08:21:20 -08:00
Broque Thomas
35a03d6839 Add global watchlist override and UI
Introduce a global watchlist override feature and UI to control release/content filters across all watchlist artists. Backend: add /api/watchlist/global-config (GET/POST) for reading/updating global settings, validation to require at least one release type when override is enabled, and _apply_watchlist_global_overrides() to apply settings to WatchlistArtist objects. Scanners (manual and automatic) now call _apply_watchlist_global_overrides() and perform additional checks (_should_include_release, _should_include_track) to skip releases/tracks according to config. Frontend: add a Global Watchlist Settings modal, controls (release types, content filters, include-all shortcut), save/validation logic, banners/notices when global override is active, and integration into the watchlist modal and per-artist config. Styles: add supporting CSS for the modal and banners. Small cleanup/whitespace adjustments included.
2026-02-24 22:09:08 -08:00
Broque Thomas
1283041836 Integrate Hydrabase P2P metadata client
Add Hydrabase support as an optional/dev metadata source and comparison tool.

- Add core/hydrabase_client.py: synchronous Hydrabase WebSocket client that normalizes results to Track/Artist/Album types and exposes raw access.
- Update config/settings.py: add hydrabase settings (url, api_key, auto_connect) and getter.
- Update web_server.py: integrate HydrabaseClient, initialize client alongside the existing HydrabaseWorker, add auto-reconnect using saved config, persist credentials on connect/disconnect, add endpoints for status and stored comparisons, background comparison runner (Hydrabase vs Spotify vs iTunes), and adapt multiple search endpoints to optionally use Hydrabase as the primary metadata source with fallbacks.
- Update web UI (webui/index.html, webui/static/script.js, webui/static/style.css): add network stats and source comparison UI, pre-fill saved credentials, show peer count, load/display comparisons, update disconnect behavior to disable dev mode, and add Hydrabase badge styling.

Behavioral notes: when dev mode + Hydrabase are active, searches can be served from Hydrabase and comparisons to Spotify/iTunes are run in background; when Hydrabase fails the code falls back to Spotify/iTunes. Saved Hydrabase credentials are persisted for auto-reconnect; disconnect disables dev mode and auto_connect.

Files touched: config/settings.py, core/hydrabase_client.py, web_server.py, webui/index.html, webui/static/script.js, webui/static/style.css.
2026-02-24 08:11:48 -08:00
Broque Thomas
317d5c1770 Add Retag tool (DB, backend, frontend)
Introduce a new Retag tool to track and re-tag previously downloaded albums/singles. Changes include:

- Database: add migration hook and create retag_groups and retag_tracks tables, indexes, and many helper methods (add/find/update/delete groups & tracks, stats, trimming).
- Backend (web_server): capture completed album/single downloads into the retag tables, implement retag execution logic (_execute_retag) to fetch album metadata, match tracks, update tags, move files, download cover art, and update DB. Add thread-safe globals, executor, and REST endpoints for stats, listing groups, group tracks, album search, execute, status, and delete.
- Frontend (webui): add Retag Tool card, modals, search UI, JS to list groups/tracks, search albums, start retag operations, poll status, and update UI; include help content. Add CSS for modals and components.

The migration is invoked during DB init to ensure existing installations create the new tables. The tool caps stored groups (default 100) and avoids duplicate track entries.
2026-02-23 20:39:04 -08:00
Broque Thomas
2e6550ec53 Disable M3U export by default
Set m3u_export.enabled default to false and update the UI so the M3U auto-save checkbox is unchecked unless explicitly enabled. Changes: config/settings.py flips the default to false, webui/index.html removes the checked attribute from the checkbox, and webui/static/script.js adjusts the logic to only check the box when settings.m3u_export.enabled === true. This prevents automatic M3U exports for users who don't explicitly opt in.
2026-02-23 12:14:53 -08:00
Broque Thomas
2ba48f917d Add server-side M3U export and UI setting
Introduce M3U export feature with UI control and server-side saving. Adds a new m3u_export config option (enabled flag) and a checkbox in the settings UI. The web endpoint /api/save-playlist-m3u now checks the m3u_export setting (unless force=true), builds the target folder using a new _compute_m3u_folder() helper (leveraging existing template logic with sensible fallbacks), sanitizes filenames, and writes .m3u files into the computed folder. Frontend JS loads/saves the new setting, supplies album/artist metadata when auto-saving, and both autoSave and manual export now POST M3U data to the server (manual export uses force=true). Also changed browser download filename extension to .m3u and added minor logging/response behavior.
2026-02-23 11:59:16 -08:00
snuffomega
e7ff1b2081 feat(settings): lock container path fields with unlock toggle
Prevent accidental misconfiguration of Docker container-internal paths
(Slskd Download Dir, Matched Transfer Dir, Import Staging Dir) by making
them read-only by default.

Repurposes the non-functional Browse button into a per-field Unlock/Lock
toggle. Adds a warning blurb below the Download Settings header so users
understand these are container paths, not host paths.
2026-02-23 13:11:13 -05:00
Broque Thomas
129f69fce9 Add Blasphemy Mode to delete FLAC after MP3
Introduce an optional "Blasphemy Mode" that deletes the original FLAC after a verified MP3 copy is created.

- config: add lossy_copy.delete_original (default: false).
- webui/index.html & static script: add checkbox and warning in settings UI and persist the setting.
- web_server.py: make _create_lossy_copy return the MP3 path when it deletes the FLAC (otherwise None); validate the MP3 using mutagen before removing the FLAC; rename associated .lrc files if present; update post-processing to use the final processed path in logs and wishlist checks and to consider .mp3 variants when FLAC may have been removed.

Behavior is off by default and includes safety checks and logging to avoid accidental deletion of originals.
2026-02-22 23:23:52 -08:00
Broque Thomas
24bfc2462d Add Spotify & iTunes workers; update repair worker
Add full-featured SpotifyWorker and iTunesWorker background workers to enrich artists, albums, and tracks with external metadata using batch cascading searches, fuzzy name matching, ID validation, and DB backfills. Update RepairWorker to re-read the transfer path from the database each scan, resolve host paths when running in Docker, and trigger immediate rescans when the transfer path changes; remove the static config_manager dependency. Also include supporting changes to the database layer and web UI/server (stats, controls, and styles) to integrate the new workers and reflect updated worker status.
2026-02-22 22:29:10 -08:00
Broque Thomas
ce474749d5 Add library repair worker and UI
Introduce a RepairWorker to scan the transfer folder and automatically detect/repair broken album track numbers (e.g. the "all tracks = 01" bug). The worker uses mutagen to read/write tags, fuzzy-matches titles against an album tracklist (Spotify/iTunes via a SpotifyClient), updates filenames and the tracks DB file_path when renamed, and caches album tracklists. It also adds DB schema support (repair_status, repair_last_checked, and an index).

Integrates the worker into the web server: initializes and starts the worker, and exposes /api/repair/status, /api/repair/pause and /api/repair/resume endpoints. Adds UI elements (button, tooltip), client-side JS to poll and control the worker, CSS for visuals/animations, and a new image asset (whisoul.png).
2026-02-21 15:00:23 -08:00
Broque Thomas
e7dfb423dc Add Active Downloads dashboard and UI fixes
Introduce an "Active Downloads" section to the dashboard and wire up client-side plumbing to populate and update it. Adds escapeForInlineJs to safely embed values into inline JS attributes and replaces several inline onclick usages (search/genre/listenbrainz/artist buttons) to prevent quoting issues. Implements updateDashboardDownloads, createDashboardDiscoverBubble, and integrates dashboard updates into artist/search/discover flows (including register/discover download persistence and monitor hooks). Adds dashboard-specific CSS for discover/artist bubbles and minor style fixes (artist image sizing, keyframe formatting) plus a mobile CSS tweak for artist images.
2026-02-21 08:51:51 -08:00
Broque Thomas
49a6c58ea8 Add Hydrabase P2P mirror worker
Introduce a Hydrabase P2P mirror worker and integrate it into the web UI and server flows. Adds core/hydrabase_worker.py: a background thread with a capped queue (1000), enqueue API, rate limiting, basic stats (sent/dropped/errors), and logic to send JSON requests over a provided WebSocket (responses received and discarded). Integrates the worker into web_server.py (import, startup init, status/pause/resume endpoints, and enqueues queries from multiple search endpoints when dev mode is enabled). Adds UI elements, JavaScript polling/toggle logic, and CSS styling for a Hydrabase status button in webui (index.html, static/script.js, static/style.css) to display and control worker state.
2026-02-21 02:15:43 -08:00
Broque Thomas
35fd7bb294 Add Hydrabase dev UI and WebSocket support
Introduce a developer-only Hydrabase testing UI and backend WebSocket integration. Adds a simple dev-mode toggle (password 'hydratest') and new API endpoints (/api/dev-mode, /api/hydrabase/connect, /api/hydrabase/disconnect, /api/hydrabase/status, /api/hydrabase/send) that use websocket-client to connect/send raw JSON to a Hydrabase instance. Frontend changes include a Hydrabase nav/page, payload editors, response panel, dev-mode UI in Settings, associated JS handlers, CSS styling, and an icon asset. Also add websocket-client to requirements.
2026-02-21 00:32:04 -08:00