diff --git a/webui/static/docs.js b/webui/static/docs.js index 176ab088..aaaa1d43 100644 --- a/webui/static/docs.js +++ b/webui/static/docs.js @@ -3,14 +3,37 @@ // =============================== function docsImg(src, alt) { - return `${alt}`; + return `
+ ${alt} + ${alt} +
`; +} + +function openDocsLightbox(wrapper) { + const img = wrapper.querySelector('.docs-screenshot'); + if (!img) return; + const existing = document.querySelector('.docs-lightbox'); + if (existing) existing.remove(); + const overlay = document.createElement('div'); + overlay.className = 'docs-lightbox'; + overlay.innerHTML = `${img.alt}`; + document.body.appendChild(overlay); + requestAnimationFrame(() => overlay.classList.add('active')); + const close = () => { + overlay.classList.remove('active'); + setTimeout(() => overlay.remove(), 250); + }; + overlay.addEventListener('click', close); + document.addEventListener('keydown', function handler(e) { + if (e.key === 'Escape') { close(); document.removeEventListener('keydown', handler); } + }); } const DOCS_SECTIONS = [ { id: 'getting-started', title: 'Getting Started', - icon: '/static/dashboard.png', + icon: '/static/dashboard.jpg', children: [ { id: 'gs-overview', title: 'Overview' }, { id: 'gs-first-setup', title: 'First-Time Setup' }, @@ -23,7 +46,7 @@ const DOCS_SECTIONS = [

Overview

SoulSync is a self-hosted music download, sync, and library management platform. It connects to Spotify, Apple Music/iTunes, Tidal, Qobuz, YouTube, and Beatport for metadata, and uses Soulseek (via slskd) as the primary download source. Your library is served through Plex, Jellyfin, or Navidrome.

- ${docsImg('gs-overview.png', 'SoulSync dashboard overview')} + ${docsImg('gs-overview.jpg', 'SoulSync dashboard overview')}

🎵 Download Music

Search and download tracks in FLAC, MP3, and more from Soulseek, YouTube, Tidal, or Qobuz, with automatic metadata tagging and file organization.

🔄 Playlist Sync

Mirror playlists from Spotify, YouTube, Tidal, and Beatport. Discover official metadata and sync to your media server.

@@ -42,7 +65,7 @@ const DOCS_SECTIONS = [
  • Spotify (Recommended) — Connect Spotify for the richest metadata. Create an app at developer.spotify.com, enter your Client ID and Secret, then click Authenticate.
  • Download Path — Set your download and transfer paths in the Download Settings section. The transfer path should point to your media server's monitored folder.
  • - ${docsImg('gs-first-setup.png', 'Settings page first-time setup')} + ${docsImg('gs-first-setup.jpg', 'Settings page first-time setup')}
    💡
    You can start using SoulSync with just one download source (Soulseek, YouTube, Tidal, or Qobuz). Spotify and other services add metadata enrichment but aren't strictly required — iTunes/Apple Music is always available as a free fallback.
    @@ -66,7 +89,7 @@ const DOCS_SECTIONS = [ ListenBrainzListening history and recommendationsURL + Token - ${docsImg('gs-connecting.png', 'Service credentials connected')} + ${docsImg('gs-connecting.jpg', 'Service credentials connected')}

    Understanding the Interface

    @@ -82,7 +105,7 @@ const DOCS_SECTIONS = [
  • Import — Import music files from a staging folder with album/track matching
  • Settings — Configure services, download preferences, quality profiles, and more
  • - ${docsImg('gs-interface.png', 'SoulSync interface layout')} + ${docsImg('gs-interface.jpg', 'SoulSync interface layout')}

    Version & Updates: Click the version number in the sidebar footer to open the What's New modal, which shows detailed release notes for every feature and fix. SoulSync automatically checks for updates by comparing your running version against the latest GitHub commit. If an update is available, a banner appears in the modal. Docker users are notified when a new image has been pushed to the repo.

    @@ -105,7 +128,7 @@ const DOCS_SECTIONS = [ Staging Path/app/StagingFor the Import feature only. Drop audio files here to import them into your library via the Import page. - ${docsImg('gs-folders.png', 'Download settings folder configuration')} + ${docsImg('gs-folders.jpg', 'Download settings folder configuration')}

    How Files Flow

    ℹ️
    @@ -121,6 +144,7 @@ const DOCS_SECTIONS = [

    Docker Setup: The Full Picture

    + ${docsImg('gs-folder-docker.jpg', 'Docker folder mapping')}

    In Docker, every app runs in its own isolated container with its own filesystem. Volume mounts in docker-compose create "bridges" between your host folders and the container. But SoulSync doesn't automatically know where those bridges go — you have to tell it via the Settings page.

    Here's what happens with a properly configured setup:

    @@ -215,7 +239,7 @@ const DOCS_SECTIONS = [ # Download Path: /app/downloads
    # Transfer Path: /app/Transfer
    - ${docsImg('gs-docker.png', 'Docker compose configuration')} + ${docsImg('gs-docker.jpg', 'Docker compose configuration')}

    Setup Checklist

    Go through every item. If you miss any single one, the pipeline will break:

    @@ -296,7 +320,7 @@ const DOCS_SECTIONS = [ { id: 'workflows', title: 'Quick Start Workflows', - icon: '/static/help.png', + icon: '/static/help.jpg', children: [ { id: 'wf-first', title: 'What Should I Do First?' }, { id: 'wf-download', title: 'How to: Download an Album' }, @@ -430,7 +454,7 @@ const DOCS_SECTIONS = [ { id: 'dashboard', title: 'Dashboard', - icon: '/static/dashboard.png', + icon: '/static/dashboard.jpg', children: [ { id: 'dash-overview', title: 'Overview & Stats' }, { id: 'dash-workers', title: 'Enrichment Workers' }, @@ -445,7 +469,7 @@ const DOCS_SECTIONS = [

    Overview & Stats

    The dashboard is your command center. At the top you'll see service status indicators for Spotify, your media server, and Soulseek — showing connected/disconnected state at a glance. Below that, stat cards display your library totals: artists, albums, tracks, and total library size.

    Stats update in real-time via WebSocket — no page refresh needed.

    - ${docsImg('dash-overview.png', 'Dashboard overview')} + ${docsImg('dash-overview.jpg', 'Dashboard overview')}

    Enrichment Workers

    @@ -462,7 +486,7 @@ const DOCS_SECTIONS = [

    Tidal

    Tidal IDs, artist images, album labels, explicit flags, ISRCs

    Qobuz

    Qobuz IDs, artist images, album labels, genres, explicit flags

    - ${docsImg('dash-workers.png', 'Enrichment workers status')} + ${docsImg('dash-workers.jpg', 'Enrichment workers status')}
    ℹ️
    Workers retry "not found" items every 30 days and errored items every 7 days. You can pause/resume any worker from the dashboard.

    Rate Limit Protection: Workers include smart rate limiting for all APIs. If Spotify returns a rate limit with a Retry-After greater than 60 seconds, the app seamlessly switches to iTunes/Apple Music — an amber indicator appears in the sidebar, searches automatically use Apple Music, and the enrichment worker pauses. When the ban expires, everything recovers automatically. No action needed from the user.

    @@ -481,7 +505,7 @@ const DOCS_SECTIONS = [ Backup ManagerCreate, download, restore, and delete database backups. Rolling cleanup keeps the 5 most recent. - ${docsImg('dash-tools.png', 'Dashboard tool cards')} + ${docsImg('dash-tools.jpg', 'Dashboard tool cards')}
    💡
    Each tool card has a help button (?) that opens detailed instructions for that specific tool.
    @@ -494,7 +518,7 @@ const DOCS_SECTIONS = [
  • Review the tag differences — mismatches are highlighted
  • Click Retag to write the corrected metadata to the audio files
  • - ${docsImg('dash-retag.png', 'Retag tool interface')} + ${docsImg('dash-retag.jpg', 'Retag tool interface')}

    The retag operation writes title, artist, album artist, album, track number, disc number, year, and genre. Cover art can optionally be re-embedded.

    @@ -507,7 +531,7 @@ const DOCS_SECTIONS = [
  • Delete — Remove individual backups
  • Rolling Cleanup — Automatically keeps only the 5 most recent backups to save disk space
  • - ${docsImg('dash-backup.png', 'Backup manager')} + ${docsImg('dash-backup.jpg', 'Backup manager')}

    The system automation Auto-Backup Database creates a backup every 3 days automatically. You can adjust the interval in Automations.

    @@ -531,7 +555,7 @@ const DOCS_SECTIONS = [ { id: 'sync', title: 'Playlist Sync', - icon: '/static/sync.png', + icon: '/static/sync.jpg', children: [ { id: 'sync-overview', title: 'Overview' }, { id: 'sync-spotify', title: 'Spotify Playlists' }, @@ -547,7 +571,7 @@ const DOCS_SECTIONS = [

    Overview

    The Sync page lets you import playlists from Spotify, YouTube, Tidal, and Beatport. Once imported, playlists are mirrored — they persist in your SoulSync instance and can be refreshed, discovered, and synced to your wishlist for downloading.

    - ${docsImg('sync-overview.png', 'Playlist sync page')} + ${docsImg('sync-overview.jpg', 'Playlist sync page')}

    Spotify Playlists

    @@ -558,13 +582,13 @@ const DOCS_SECTIONS = [
  • Download Missing — Opens a modal showing tracks not in your library, with download controls
  • Sync Playlist — Adds tracks to your wishlist for automated downloading
  • - ${docsImg('sync-spotify.png', 'Spotify playlists loaded')} + ${docsImg('sync-spotify.jpg', 'Spotify playlists loaded')}
    💡
    Spotify-sourced playlists are auto-discovered at confidence 1.0 during refresh — no separate discovery step needed.

    YouTube Playlists

    Paste a YouTube playlist URL into the input field and click Parse Playlist. SoulSync extracts the track list and attempts to match each track to official Spotify/iTunes metadata.

    - ${docsImg('sync-youtube.png', 'YouTube playlist import')} + ${docsImg('sync-youtube.jpg', 'YouTube playlist import')}
    ⚠️
    YouTube tracks often have non-standard titles (e.g., "Artist - Song (Official Video)"). The discovery pipeline handles this, but some manual fixes may be needed for edge cases.
    @@ -595,7 +619,7 @@ const DOCS_SECTIONS = [

    Genre Browser — Browse 12+ electronic music genres (House, Techno, Drum & Bass, Trance, etc.) with per-genre views: Top 10 tracks, staff picks, hype rankings, latest releases, and new charts.

    Charts — Top 100 and Hype charts with full track listings. Each track can be manually matched against Spotify for metadata, then synced and downloaded.

    - ${docsImg('sync-beatport.png', 'Beatport genre browser')} + ${docsImg('sync-beatport.jpg', 'Beatport genre browser')}
    ℹ️
    Beatport data is cached with a configurable TTL. The system automation Refresh Beatport Cache runs every 24 hours to keep content fresh.
    @@ -607,7 +631,7 @@ const DOCS_SECTIONS = [
  • Download progress survives page refresh
  • Each profile has its own mirrored playlists
  • - ${docsImg('sync-mirror.png', 'Mirrored playlist cards')} + ${docsImg('sync-mirror.jpg', 'Mirrored playlist cards')}

    M3U Export

    @@ -631,7 +655,7 @@ const DOCS_SECTIONS = [ { id: 'search', title: 'Music Downloads', - icon: '/static/search.png', + icon: '/static/search.jpg', children: [ { id: 'search-enhanced', title: 'Enhanced Search' }, { id: 'search-basic', title: 'Basic Search' }, @@ -651,13 +675,13 @@ const DOCS_SECTIONS = [
  • Click a track to search Soulseek for that specific song
  • Preview tracks — Play button on search result tracks lets you stream a preview directly from your download source before committing to a download
  • - ${docsImg('dl-enhanced-search.png', 'Enhanced search results')} + ${docsImg('dl-enhanced-search.jpg', 'Enhanced search results')}

    Basic Search

    Toggle to Basic Search mode for direct Soulseek queries. This shows raw search results with detailed info: format, bitrate, quality score, file size, uploader name, upload speed, and availability.

    Filters let you narrow results by type (Albums/Singles), format (FLAC/MP3/OGG/AAC/WMA), and sort by relevance, quality, size, bitrate, duration, or uploader speed.

    - ${docsImg('dl-basic-search.png', 'Basic Soulseek search')} + ${docsImg('dl-basic-search.jpg', 'Basic Soulseek search')}

    Download Sources

    @@ -685,7 +709,7 @@ const DOCS_SECTIONS = [

    Downloads can be started from multiple places: Enhanced Search results, artist discography, Download Missing modal, wishlist auto-processing, and playlist sync.

    Download Candidate Selection: If a download fails or no suitable source is found, you can view the cached search candidates and manually pick an alternative file from a different user. This lets you recover failed downloads without restarting the entire search.

    - ${docsImg('dl-candidates.png', 'Download candidate selection')} + ${docsImg('dl-candidates.jpg', 'Download candidate selection')}

    Post-Processing Pipeline

    @@ -699,7 +723,7 @@ const DOCS_SECTIONS = [
  • Lossy Copy — If enabled in settings, a lower-bitrate copy is created alongside the original (useful for mobile device syncing).
  • Media Server Scan — Your media server (Plex/Jellyfin) is notified to scan for the new file. Navidrome auto-detects changes.
  • - ${docsImg('dl-post-processing.png', 'Post-processing pipeline complete')} + ${docsImg('dl-post-processing.jpg', 'Post-processing pipeline complete')}
    ℹ️
    Quarantine: Files that fail AcoustID verification are moved to a quarantine folder instead of your library. You can review quarantined files and manually approve or delete them. The automation engine can trigger notifications when files are quarantined.
    @@ -714,7 +738,7 @@ const DOCS_SECTIONS = [

    Each format has configurable bitrate ranges and a priority order. Enable Fallback to accept any quality when preferred formats aren't available.

    - ${docsImg('dl-quality-profiles.png', 'Quality profile settings')} + ${docsImg('dl-quality-profiles.jpg', 'Quality profile settings')}

    Download Manager

    @@ -725,7 +749,7 @@ const DOCS_SECTIONS = [ { id: 'discover', title: 'Discover Artists', - icon: '/static/discover.png', + icon: '/static/discover.jpg', children: [ { id: 'disc-hero', title: 'Featured Artists' }, { id: 'disc-playlists', title: 'Discovery Playlists' }, @@ -743,7 +767,7 @@ const DOCS_SECTIONS = [
  • Watch All — Add all featured artists to your watchlist at once
  • View Recommended — See 50+ similar artists with enrichment data
  • - ${docsImg('disc-hero.png', 'Featured artist hero slider')} + ${docsImg('disc-hero.jpg', 'Featured artist hero slider')}

    Discovery & Personalized Playlists

    @@ -762,15 +786,16 @@ const DOCS_SECTIONS = [ Familiar FavoritesLibraryWell-known tracks from artists you follow - ${docsImg('disc-playlists.png', 'Discovery playlist cards')} + ${docsImg('disc-playlists.jpg', 'Discovery playlist cards')}

    Each playlist can be played in the media player, downloaded, or synced to your media server.

    Genre Browser — Filter discovery pool content by specific genres. Browse available genres and view top tracks within each genre category.

    + ${docsImg('disc-genre-browser.jpg', 'Genre browser')}

    ListenBrainz Playlists — If ListenBrainz is configured, the Discover page also shows personalized playlists generated from your listening history: Created For You, Your Playlists, and Collaborative playlists.

    Build Custom Playlist

    Search for 1–5 artists, select them, and click Generate to create a custom playlist from their catalogs. You can then download or sync the generated playlist.

    - ${docsImg('disc-build-playlist.png', 'Build custom playlist')} + ${docsImg('disc-build-playlist.jpg', 'Build custom playlist')}

    Seasonal & Curated Content

    @@ -784,14 +809,14 @@ const DOCS_SECTIONS = [

    Time Machine

    Browse discovery pool content by decade — tabs from the 1950s through the 2020s. Each decade pulls top tracks from pool artists active in that era.

    - ${docsImg('disc-time-machine.png', 'Time Machine decade browser')} + ${docsImg('disc-time-machine.jpg', 'Time Machine decade browser')}
    ` }, { id: 'artists', title: 'Artists & Watchlist', - icon: '/static/artists.png', + icon: '/static/artists.jpg', children: [ { id: 'art-search', title: 'Artist Search' }, { id: 'art-detail', title: 'Artist Detail & Discography' }, @@ -804,7 +829,7 @@ const DOCS_SECTIONS = [

    Artist Detail & Discography

    @@ -817,7 +842,7 @@ const DOCS_SECTIONS = [

    At the top, View on buttons link to the artist on each matched external service (Spotify, Apple Music, MusicBrainz, Deezer, AudioDB, Last.fm, Genius, Tidal, Qobuz). Service badges on artist cards also indicate which services have matched this artist.

    Similar Artists appear as clickable bubbles below the discography for further exploration and discovery.

    - ${docsImg('art-detail.png', 'Artist detail page')} + ${docsImg('art-detail.jpg', 'Artist detail page')}

    Watchlist

    @@ -829,7 +854,7 @@ const DOCS_SECTIONS = [
  • Use Watch All to add all recommended artists at once
  • Watch All Unwatched — Bulk-add every library artist that isn't already on your watchlist
  • - ${docsImg('art-watchlist.png', 'Watchlist page')} + ${docsImg('art-watchlist.jpg', 'Watchlist page')}

    New Release Scanning

    @@ -840,7 +865,7 @@ const DOCS_SECTIONS = [
  • Recent wishlist additions feed
  • Stats: artists scanned, new tracks found, tracks added to wishlist
  • - ${docsImg('art-scan.png', 'New release scan panel')} + ${docsImg('art-scan.jpg', 'New release scan panel')}

    Wishlist

    @@ -854,7 +879,7 @@ const DOCS_SECTIONS = [

    Manual Processing: Use the Process Wishlist automation action to trigger processing on demand. Options include processing all items, albums only, or singles only.

    Cleanup: The Cleanup Wishlist action removes duplicates (same track added multiple times) and items you already own in your library.

    ℹ️
    Each wishlist item tracks its source (watchlist scan, playlist sync, manual), number of retry attempts, last error message, and status (pending, downloading, failed, complete).
    - ${docsImg('art-wishlist.png', 'Wishlist queue')} + ${docsImg('art-wishlist.jpg', 'Wishlist queue')}

    Watchlist Settings

    @@ -866,7 +891,7 @@ const DOCS_SECTIONS = [ { id: 'automations', title: 'Automations', - icon: '/static/automation.png', + icon: '/static/automation.jpg', children: [ { id: 'auto-overview', title: 'Overview' }, { id: 'auto-builder', title: 'Builder' }, @@ -881,7 +906,7 @@ const DOCS_SECTIONS = [

    Overview

    Automations let you schedule tasks and react to events with a visual WHEN → DO → THEN builder. Create custom workflows like "When a download completes, update the database, then notify me on Discord."

    Each automation card shows its trigger/action flow, last run time, next scheduled run (with countdown), and a Run Now button for instant execution.

    - ${docsImg('auto-overview.png', 'Automations page')} + ${docsImg('auto-overview.jpg', 'Automations page')}

    Builder

    @@ -892,7 +917,7 @@ const DOCS_SECTIONS = [
  • THEN (Post-Action) — Up to 3 notification or signal actions after the DO completes
  • Add Conditions to filter when the automation runs. Match modes: All (AND) or Any (OR). Operators: contains, equals, starts_with, not_contains.

    - ${docsImg('auto-builder.png', 'Automation builder')} + ${docsImg('auto-builder.jpg', 'Automation builder')}

    All Triggers

    @@ -971,7 +996,7 @@ const DOCS_SECTIONS = [

    Use the Run Now button on any automation card to execute it immediately, regardless of its schedule. The result (success/failure) updates in real-time on the card. Running automations display a glow effect on their card.

    Stall detection: If an automation action runs for more than 2 hours without completing, it is automatically flagged as stalled and terminated to prevent resource leaks.

    The Dashboard activity feed also logs every automation execution with timestamps, so you can review the full history of what ran and when.

    - ${docsImg('auto-history.png', 'Automation execution history')} + ${docsImg('auto-history.jpg', 'Automation execution history')}

    System Automations

    @@ -991,14 +1016,14 @@ const DOCS_SECTIONS = [ Full CleanupEvery 12 hours - ${docsImg('auto-system.png', 'System automations')} + ${docsImg('auto-system.jpg', 'System automations')}
    ` }, { id: 'library', title: 'Music Library', - icon: '/static/library.png', + icon: '/static/library.jpg', children: [ { id: 'lib-standard', title: 'Standard View' }, { id: 'lib-enhanced', title: 'Enhanced Library Manager' }, @@ -1013,7 +1038,7 @@ const DOCS_SECTIONS = [

    The Library page shows all artists in your collection as cards with images, album/track counts, and service badges (Spotify, MusicBrainz, Deezer, AudioDB, iTunes, Last.fm, Genius, Tidal, Qobuz) indicating which services have matched this artist.

    Use the search bar, alphabet navigation (A–Z, #), and watchlist filter (All/Watched/Unwatched) to browse. Click any artist card to view their discography.

    The artist detail page shows albums, EPs, and singles as cards with completion percentages. Filter by category, content type (live/compilations/featured), or status (owned/missing). At the top, View on buttons link to the artist on each matched external service.

    - ${docsImg('lib-standard.png', 'Library artist grid')} + ${docsImg('lib-standard.jpg', 'Library artist grid')}

    Enhanced Library Manager

    @@ -1026,7 +1051,7 @@ const DOCS_SECTIONS = [
  • Play tracks — Queue button adds tracks to the media player
  • Delete — Remove tracks or albums from the database (files on disk are never touched)
  • - ${docsImg('lib-enhanced.png', 'Enhanced Library Manager')} + ${docsImg('lib-enhanced.jpg', 'Enhanced Library Manager')}

    Service Matching

    @@ -1042,7 +1067,7 @@ const DOCS_SECTIONS = [
  • Optionally enable Embed cover art and Sync to server
  • Click Write Tags to apply changes to the file
  • - ${docsImg('lib-tags.png', 'Tag preview modal')} + ${docsImg('lib-tags.jpg', 'Tag preview modal')}

    Supports MP3, FLAC, OGG, and M4A via Mutagen. After writing, optional server sync pushes metadata to Plex (per-track update), Jellyfin (library scan), or Navidrome (auto-detects).

    @@ -1053,7 +1078,7 @@ const DOCS_SECTIONS = [
  • Write Tags — Batch write tags to all selected tracks with live progress
  • Clear Selection — Deselect all
  • - ${docsImg('lib-bulk.png', 'Bulk operations bar')} + ${docsImg('lib-bulk.jpg', 'Bulk operations bar')}

    Download Missing Tracks

    @@ -1065,7 +1090,7 @@ const DOCS_SECTIONS = [ { id: 'import', title: 'Import Music', - icon: '/static/import.png', + icon: '/static/import.jpg', children: [ { id: 'imp-setup', title: 'Staging Setup' }, { id: 'imp-workflow', title: 'Import Workflow' }, @@ -1079,7 +1104,7 @@ const DOCS_SECTIONS = [

    Set your staging folder path in Settings → Download Settings. Place audio files you want to import into this folder. SoulSync scans the folder and detects albums from the file structure.

    Place albums in subfolders (e.g., Artist - Album/) and loose singles at the root level.

    The import page header shows the total files in staging and their combined size.

    - ${docsImg('imp-staging.png', 'Import staging page')} + ${docsImg('imp-staging.jpg', 'Import staging page')}
    💡
    Files not showing up? Check that your staging folder path is correct in Settings and that the folder has read permissions. Docker users: make sure the staging volume mount is configured in your docker-compose.yml.
    @@ -1091,7 +1116,7 @@ const DOCS_SECTIONS = [
  • Match tracks — Drag-and-drop staged files onto album track slots, or let auto-match attempt it
  • Review the match and click Confirm to import — files are tagged, organized, and added to your library
  • - ${docsImg('imp-matching.png', 'Track matching interface')} + ${docsImg('imp-matching.jpg', 'Track matching interface')}

    Singles Import

    @@ -1116,14 +1141,14 @@ const DOCS_SECTIONS = [
  • Map columns to the correct fields (Artist, Album, Track)
  • SoulSync searches for each track on Spotify/iTunes and adds matches to your wishlist for downloading
  • - ${docsImg('imp-textfile.png', 'Text file import')} + ${docsImg('imp-textfile.jpg', 'Text file import')}
    ` }, { id: 'player', title: 'Media Player', - icon: '/static/library.png', + icon: '/static/library.jpg', children: [ { id: 'player-controls', title: 'Playback Controls' }, { id: 'player-streaming', title: 'Streaming & Sources' }, @@ -1134,8 +1159,9 @@ const DOCS_SECTIONS = [

    Playback Controls

    The sidebar media player is always visible when a track is loaded. It shows album art, track info, a seekable progress bar, and playback controls (play/pause, previous, next, volume, repeat, shuffle).

    + ${docsImg('player-sidebar.jpg', 'Sidebar media player')}

    Click the sidebar player to open the Now Playing modal — a full-screen experience with large album art, ambient glow (dominant color from cover art), a frequency-driven audio visualizer, and expanded controls.

    - ${docsImg('player-nowplaying.png', 'Now Playing modal')} + ${docsImg('player-nowplaying.jpg', 'Now Playing modal')}

    Streaming & Sources

    @@ -1152,7 +1178,7 @@ const DOCS_SECTIONS = [

    Add tracks to the queue from the Enhanced Library Manager or download results. Manage the queue in the Now Playing modal: reorder, remove individual tracks, or clear all.

    Smart Radio mode (toggle in queue header) automatically adds similar tracks when the queue runs out, based on genre, mood, style, and artist similarity. Playback continues seamlessly.

    Repeat modes: Off → Repeat All (loop queue) → Repeat One. Shuffle randomizes the next track from the remaining queue.

    - ${docsImg('player-queue.png', 'Queue panel')} + ${docsImg('player-queue.jpg', 'Queue panel')}

    Keyboard Shortcuts

    @@ -1175,7 +1201,7 @@ const DOCS_SECTIONS = [ { id: 'settings', title: 'Settings', - icon: '/static/settings.png', + icon: '/static/settings.jpg', children: [ { id: 'set-services', title: 'Service Credentials' }, { id: 'set-media', title: 'Media Server Setup' }, @@ -1198,7 +1224,6 @@ const DOCS_SECTIONS = [
  • AcoustID — API key from acoustid.org (enables fingerprint verification)
  • ListenBrainz — Base URL + token for listening history and playlist import
  • - ${docsImg('settings-credentials.png', 'Service credentials')}

    Media Server Setup

    @@ -1211,7 +1236,7 @@ const DOCS_SECTIONS = [ NavidromeURL + Username + PasswordSelect the Music Folder to monitor. Navidrome auto-detects new files, so SoulSync doesn't need to trigger scans — just place files in the right folder. - ${docsImg('settings-media-server.png', 'Media server setup')} + ${docsImg('settings-media-server.jpg', 'Media server setup')}

    The media player streams audio directly from your connected server — tracks play through your Plex, Jellyfin, or Navidrome instance without needing local file access.

    💡
    Navidrome users: If artist images are broken after upgrading, use the Fix Navidrome URLs tool in Settings to convert old image URL formats to the correct Subsonic API format.
    @@ -1226,7 +1251,7 @@ const DOCS_SECTIONS = [
  • Lossy Copy — When enabled, creates a lower-bitrate MP3 copy of every downloaded file. Configure the output bitrate (default 320kbps) and output folder. Optionally delete the original lossless file after creating the lossy copy. Useful for syncing to mobile devices or streaming servers with bandwidth constraints.
  • Content Filtering — Toggle explicit content filtering to control whether explicit tracks appear in search results and downloads.
  • - ${docsImg('settings-downloads.png', 'Download settings')} + ${docsImg('settings-downloads.jpg', 'Download settings')}
    ⚠️
    Docker users: Always use container-side paths in these settings (e.g., /app/downloads, /app/Transfer). Never use host paths like /mnt/music — the container can't access those. Your docker-compose volumes section is where host paths are mapped to container paths. See Getting Started → Folder Setup for a complete walkthrough.
    @@ -1242,7 +1267,7 @@ const DOCS_SECTIONS = [
  • Soulseek Search Timeout — How long to wait for Soulseek search results before giving up (seconds).
  • Discovery Lookback Period — How many weeks back to check for new releases during watchlist scans.
  • - ${docsImg('settings-processing.png', 'Processing settings')} + ${docsImg('settings-processing.jpg', 'Processing settings')}

    Quality Profiles

    @@ -1264,7 +1289,7 @@ const DOCS_SECTIONS = [ { id: 'profiles', title: 'Multi-Profile', - icon: '/static/settings.png', + icon: '/static/settings.jpg', children: [ { id: 'prof-overview', title: 'How Profiles Work' }, { id: 'prof-manage', title: 'Managing Profiles' }, @@ -1298,7 +1323,8 @@ const DOCS_SECTIONS = [
  • Profile 1 (admin) cannot be deleted
  • PINs are 4-6 digits. If you forget your PIN, the admin can reset it from Manage Profiles. The admin PIN protects settings and destructive operations when multiple profiles exist.

    - ${docsImg('profiles-picker.png', 'Profile picker')} + ${docsImg('profiles-picker.jpg', 'Profile picker')} + ${docsImg('profiles-create.jpg', 'Profile creation')}

    Permissions & Page Access

    @@ -1308,7 +1334,7 @@ const DOCS_SECTIONS = [
  • Can Download Music — Toggle whether the profile can initiate downloads. When disabled, all download buttons are hidden and the backend blocks download API calls with a 403 error.
  • Enhanced Library Manager — The Enhanced view toggle on artist detail pages is only available to admin profiles. Non-admin users see the Standard view only.
  • - ${docsImg('profiles-permissions.png', 'Profile permissions')} + ${docsImg('profiles-permissions.jpg', 'Profile permissions')}

    If the admin removes a page that was set as a user's home page, the home page automatically resets. Navigation guards prevent users from accessing restricted pages even via direct URL or browser history.

    ℹ️
    Existing profiles created before permissions were added have full access to all pages by default. The admin must explicitly restrict access per profile.
    @@ -1327,7 +1353,7 @@ const DOCS_SECTIONS = [ { id: 'api', title: 'REST API', - icon: '/static/settings.png', + icon: '/static/settings.jpg', children: [ { id: 'api-auth', title: 'Authentication' }, { id: 'api-system', title: 'System & Status' }, diff --git a/webui/static/docs/art-detail.jpg b/webui/static/docs/art-detail.jpg new file mode 100644 index 00000000..566beb9b Binary files /dev/null and b/webui/static/docs/art-detail.jpg differ diff --git a/webui/static/docs/art-scan.jpg b/webui/static/docs/art-scan.jpg new file mode 100644 index 00000000..4ecf78e3 Binary files /dev/null and b/webui/static/docs/art-scan.jpg differ diff --git a/webui/static/docs/art-search.jpg b/webui/static/docs/art-search.jpg new file mode 100644 index 00000000..5b25dc2a Binary files /dev/null and b/webui/static/docs/art-search.jpg differ diff --git a/webui/static/docs/art-watchlist.jpg b/webui/static/docs/art-watchlist.jpg new file mode 100644 index 00000000..935630de Binary files /dev/null and b/webui/static/docs/art-watchlist.jpg differ diff --git a/webui/static/docs/art-wishlist.jpg b/webui/static/docs/art-wishlist.jpg new file mode 100644 index 00000000..a17efef2 Binary files /dev/null and b/webui/static/docs/art-wishlist.jpg differ diff --git a/webui/static/docs/auto-builder.jpg b/webui/static/docs/auto-builder.jpg new file mode 100644 index 00000000..50677f39 Binary files /dev/null and b/webui/static/docs/auto-builder.jpg differ diff --git a/webui/static/docs/auto-history.jpg b/webui/static/docs/auto-history.jpg new file mode 100644 index 00000000..25db12fe Binary files /dev/null and b/webui/static/docs/auto-history.jpg differ diff --git a/webui/static/docs/auto-overview.jpg b/webui/static/docs/auto-overview.jpg new file mode 100644 index 00000000..5cdb890c Binary files /dev/null and b/webui/static/docs/auto-overview.jpg differ diff --git a/webui/static/docs/auto-system.jpg b/webui/static/docs/auto-system.jpg new file mode 100644 index 00000000..0c42b3cd Binary files /dev/null and b/webui/static/docs/auto-system.jpg differ diff --git a/webui/static/docs/dash-backup.jpg b/webui/static/docs/dash-backup.jpg new file mode 100644 index 00000000..59eb35ca Binary files /dev/null and b/webui/static/docs/dash-backup.jpg differ diff --git a/webui/static/docs/dash-overview.jpg b/webui/static/docs/dash-overview.jpg new file mode 100644 index 00000000..b518655b Binary files /dev/null and b/webui/static/docs/dash-overview.jpg differ diff --git a/webui/static/docs/dash-retag.jpg b/webui/static/docs/dash-retag.jpg new file mode 100644 index 00000000..1b384694 Binary files /dev/null and b/webui/static/docs/dash-retag.jpg differ diff --git a/webui/static/docs/dash-tools.jpg b/webui/static/docs/dash-tools.jpg new file mode 100644 index 00000000..0787e027 Binary files /dev/null and b/webui/static/docs/dash-tools.jpg differ diff --git a/webui/static/docs/dash-workers.jpg b/webui/static/docs/dash-workers.jpg new file mode 100644 index 00000000..8ba12217 Binary files /dev/null and b/webui/static/docs/dash-workers.jpg differ diff --git a/webui/static/docs/disc-build-playlist.jpg b/webui/static/docs/disc-build-playlist.jpg new file mode 100644 index 00000000..672f9a11 Binary files /dev/null and b/webui/static/docs/disc-build-playlist.jpg differ diff --git a/webui/static/docs/disc-genre-browser.jpg b/webui/static/docs/disc-genre-browser.jpg new file mode 100644 index 00000000..30bb5155 Binary files /dev/null and b/webui/static/docs/disc-genre-browser.jpg differ diff --git a/webui/static/docs/disc-hero.jpg b/webui/static/docs/disc-hero.jpg new file mode 100644 index 00000000..47adeefc Binary files /dev/null and b/webui/static/docs/disc-hero.jpg differ diff --git a/webui/static/docs/disc-playlists.jpg b/webui/static/docs/disc-playlists.jpg new file mode 100644 index 00000000..c558cba6 Binary files /dev/null and b/webui/static/docs/disc-playlists.jpg differ diff --git a/webui/static/docs/disc-time-machine.jpg b/webui/static/docs/disc-time-machine.jpg new file mode 100644 index 00000000..0beb5119 Binary files /dev/null and b/webui/static/docs/disc-time-machine.jpg differ diff --git a/webui/static/docs/dl-basic-search.jpg b/webui/static/docs/dl-basic-search.jpg new file mode 100644 index 00000000..c17fdc79 Binary files /dev/null and b/webui/static/docs/dl-basic-search.jpg differ diff --git a/webui/static/docs/dl-candidates.jpg b/webui/static/docs/dl-candidates.jpg new file mode 100644 index 00000000..7baac53f Binary files /dev/null and b/webui/static/docs/dl-candidates.jpg differ diff --git a/webui/static/docs/dl-enhanced-search.jpg b/webui/static/docs/dl-enhanced-search.jpg new file mode 100644 index 00000000..c7dfc9b7 Binary files /dev/null and b/webui/static/docs/dl-enhanced-search.jpg differ diff --git a/webui/static/docs/dl-post-processing.jpg b/webui/static/docs/dl-post-processing.jpg new file mode 100644 index 00000000..4e1b6e1a Binary files /dev/null and b/webui/static/docs/dl-post-processing.jpg differ diff --git a/webui/static/docs/dl-quality-profiles.jpg b/webui/static/docs/dl-quality-profiles.jpg new file mode 100644 index 00000000..667d604f Binary files /dev/null and b/webui/static/docs/dl-quality-profiles.jpg differ diff --git a/webui/static/docs/gs-connecting.jpg b/webui/static/docs/gs-connecting.jpg new file mode 100644 index 00000000..0f3f68a6 Binary files /dev/null and b/webui/static/docs/gs-connecting.jpg differ diff --git a/webui/static/docs/gs-docker.jpg b/webui/static/docs/gs-docker.jpg new file mode 100644 index 00000000..412eb1a6 Binary files /dev/null and b/webui/static/docs/gs-docker.jpg differ diff --git a/webui/static/docs/gs-first-setup.jpg b/webui/static/docs/gs-first-setup.jpg new file mode 100644 index 00000000..57e383a6 Binary files /dev/null and b/webui/static/docs/gs-first-setup.jpg differ diff --git a/webui/static/docs/gs-folder-docker.jpg b/webui/static/docs/gs-folder-docker.jpg new file mode 100644 index 00000000..2bad9792 Binary files /dev/null and b/webui/static/docs/gs-folder-docker.jpg differ diff --git a/webui/static/docs/gs-folders.jpg b/webui/static/docs/gs-folders.jpg new file mode 100644 index 00000000..2b00d190 Binary files /dev/null and b/webui/static/docs/gs-folders.jpg differ diff --git a/webui/static/docs/gs-interface.jpg b/webui/static/docs/gs-interface.jpg new file mode 100644 index 00000000..f6e09f7f Binary files /dev/null and b/webui/static/docs/gs-interface.jpg differ diff --git a/webui/static/docs/gs-overview.jpg b/webui/static/docs/gs-overview.jpg new file mode 100644 index 00000000..ad34981e Binary files /dev/null and b/webui/static/docs/gs-overview.jpg differ diff --git a/webui/static/docs/imp-matching.jpg b/webui/static/docs/imp-matching.jpg new file mode 100644 index 00000000..9b8355ea Binary files /dev/null and b/webui/static/docs/imp-matching.jpg differ diff --git a/webui/static/docs/imp-staging.jpg b/webui/static/docs/imp-staging.jpg new file mode 100644 index 00000000..4261910a Binary files /dev/null and b/webui/static/docs/imp-staging.jpg differ diff --git a/webui/static/docs/imp-textfile.jpg b/webui/static/docs/imp-textfile.jpg new file mode 100644 index 00000000..fcf25a0f Binary files /dev/null and b/webui/static/docs/imp-textfile.jpg differ diff --git a/webui/static/docs/lib-bulk.jpg b/webui/static/docs/lib-bulk.jpg new file mode 100644 index 00000000..732b716e Binary files /dev/null and b/webui/static/docs/lib-bulk.jpg differ diff --git a/webui/static/docs/lib-enhanced.jpg b/webui/static/docs/lib-enhanced.jpg new file mode 100644 index 00000000..5bed4350 Binary files /dev/null and b/webui/static/docs/lib-enhanced.jpg differ diff --git a/webui/static/docs/lib-standard.jpg b/webui/static/docs/lib-standard.jpg new file mode 100644 index 00000000..4016a2c9 Binary files /dev/null and b/webui/static/docs/lib-standard.jpg differ diff --git a/webui/static/docs/lib-tags.jpg b/webui/static/docs/lib-tags.jpg new file mode 100644 index 00000000..e18b8a5b Binary files /dev/null and b/webui/static/docs/lib-tags.jpg differ diff --git a/webui/static/docs/player-nowplaying.jpg b/webui/static/docs/player-nowplaying.jpg new file mode 100644 index 00000000..8a37375a Binary files /dev/null and b/webui/static/docs/player-nowplaying.jpg differ diff --git a/webui/static/docs/player-queue.jpg b/webui/static/docs/player-queue.jpg new file mode 100644 index 00000000..b54ab190 Binary files /dev/null and b/webui/static/docs/player-queue.jpg differ diff --git a/webui/static/docs/player-sidebar.jpg b/webui/static/docs/player-sidebar.jpg new file mode 100644 index 00000000..3959634e Binary files /dev/null and b/webui/static/docs/player-sidebar.jpg differ diff --git a/webui/static/docs/profiles-create.jpg b/webui/static/docs/profiles-create.jpg new file mode 100644 index 00000000..7ded42f0 Binary files /dev/null and b/webui/static/docs/profiles-create.jpg differ diff --git a/webui/static/docs/profiles-permissions.jpg b/webui/static/docs/profiles-permissions.jpg new file mode 100644 index 00000000..ced7ab70 Binary files /dev/null and b/webui/static/docs/profiles-permissions.jpg differ diff --git a/webui/static/docs/profiles-picker.jpg b/webui/static/docs/profiles-picker.jpg new file mode 100644 index 00000000..05fcf5ed Binary files /dev/null and b/webui/static/docs/profiles-picker.jpg differ diff --git a/webui/static/docs/settings-downloads.jpg b/webui/static/docs/settings-downloads.jpg new file mode 100644 index 00000000..d42c674c Binary files /dev/null and b/webui/static/docs/settings-downloads.jpg differ diff --git a/webui/static/docs/settings-media-server.jpg b/webui/static/docs/settings-media-server.jpg new file mode 100644 index 00000000..992a7a5e Binary files /dev/null and b/webui/static/docs/settings-media-server.jpg differ diff --git a/webui/static/docs/settings-processing.jpg b/webui/static/docs/settings-processing.jpg new file mode 100644 index 00000000..61d05646 Binary files /dev/null and b/webui/static/docs/settings-processing.jpg differ diff --git a/webui/static/docs/sync-beatport.jpg b/webui/static/docs/sync-beatport.jpg new file mode 100644 index 00000000..c461a8a6 Binary files /dev/null and b/webui/static/docs/sync-beatport.jpg differ diff --git a/webui/static/docs/sync-mirror.jpg b/webui/static/docs/sync-mirror.jpg new file mode 100644 index 00000000..bcbdde16 Binary files /dev/null and b/webui/static/docs/sync-mirror.jpg differ diff --git a/webui/static/docs/sync-overview.jpg b/webui/static/docs/sync-overview.jpg new file mode 100644 index 00000000..bbbc0c00 Binary files /dev/null and b/webui/static/docs/sync-overview.jpg differ diff --git a/webui/static/docs/sync-spotify.jpg b/webui/static/docs/sync-spotify.jpg new file mode 100644 index 00000000..bbbc0c00 Binary files /dev/null and b/webui/static/docs/sync-spotify.jpg differ diff --git a/webui/static/docs/sync-youtube.jpg b/webui/static/docs/sync-youtube.jpg new file mode 100644 index 00000000..71e70d52 Binary files /dev/null and b/webui/static/docs/sync-youtube.jpg differ diff --git a/webui/static/style.css b/webui/static/style.css index 510d5f31..6467087b 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -34683,13 +34683,101 @@ tr.tag-diff-same { } /* Screenshots */ +.docs-screenshot-wrapper { + display: flex; + flex-direction: column; + align-items: center; + margin: 20px 0; + cursor: pointer; +} + +.docs-screenshot-wrapper:hover .docs-screenshot { + border-color: rgba(var(--accent-light-rgb), 0.3); + box-shadow: 0 8px 40px rgba(0, 0, 0, 0.5), 0 0 20px rgba(var(--accent-light-rgb), 0.08); + transform: translateY(-2px); +} + +.docs-screenshot-wrapper:hover .docs-screenshot-label { + color: rgba(255, 255, 255, 0.6); +} + .docs-screenshot { width: 100%; - max-width: 900px; - border-radius: 12px; + max-width: 800px; + border-radius: 10px; border: 1px solid rgba(255, 255, 255, 0.08); - margin: 16px 0; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); + transition: all 0.25s ease; + opacity: 0; + animation: docImgFadeIn 0.4s ease forwards; +} + +.docs-screenshot-label { + font-size: 11px; + color: rgba(255, 255, 255, 0.35); + margin-top: 8px; + letter-spacing: 0.3px; + transition: color 0.25s ease; +} + +@keyframes docImgFadeIn { + from { opacity: 0; transform: translateY(8px); } + to { opacity: 1; transform: translateY(0); } +} + +/* Lightbox overlay for full-size image viewing */ +.docs-lightbox { + position: fixed; + inset: 0; + z-index: 10000; + background: rgba(0, 0, 0, 0.88); + backdrop-filter: blur(8px); + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.25s ease; + cursor: zoom-out; +} + +.docs-lightbox.active { + opacity: 1; +} + +.docs-lightbox img { + max-width: 92vw; + max-height: 90vh; + border-radius: 10px; + box-shadow: 0 16px 64px rgba(0, 0, 0, 0.6); + transform: scale(0.92); + transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1); +} + +.docs-lightbox.active img { + transform: scale(1); +} + +.docs-lightbox-close { + position: absolute; + top: 20px; + right: 24px; + width: 36px; + height: 36px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(255, 255, 255, 0.15); + color: rgba(255, 255, 255, 0.7); + font-size: 18px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s ease; +} + +.docs-lightbox-close:hover { + background: rgba(255, 255, 255, 0.2); + color: #fff; } /* Bullet lists */ @@ -34911,18 +34999,16 @@ tr.tag-diff-same { margin: 16px 0 4px; } -/* Screenshot enhancements */ -.docs-screenshot { - display: block; - loading: lazy; -} - -.docs-screenshot-caption { - font-size: 12px; - color: rgba(255, 255, 255, 0.4); - text-align: center; - margin: -8px 0 16px; - font-style: italic; +/* Screenshot responsive adjustments */ +@media (max-width: 600px) { + .docs-screenshot { + max-width: 100%; + border-radius: 8px; + } + .docs-lightbox img { + max-width: 98vw; + border-radius: 6px; + } } /* Mobile */