Bump to v2.3, sticky sidebar header, compact idle player, Plex fixes
Version bump to 2.3 with rewritten What's New modal covering all changes since v2.2. Docker publish workflow default updated. Sidebar improvements: - Header stays pinned at top while nav and player scroll beneath it - Media player collapses to compact single-line when no track is playing, expands to full size when playback starts Fixes: - Server playlists endpoint Plex Tag object crash (getattr fix) - Server playlists tab auto-refreshes after download completion - Fixed dead code syntax error in archived version notes
This commit is contained in:
parent
4f25cf4661
commit
26b2ca60fc
5 changed files with 134 additions and 157 deletions
2
.github/workflows/docker-publish.yml
vendored
2
.github/workflows/docker-publish.yml
vendored
|
|
@ -6,7 +6,7 @@ on:
|
|||
version_tag:
|
||||
description: 'Version tag (e.g. 1.6, 1.7)'
|
||||
required: true
|
||||
default: '2.2'
|
||||
default: '2.3'
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
|
|
|
|||
238
web_server.py
238
web_server.py
|
|
@ -34,7 +34,7 @@ _log_path = config_manager.get('logging.path', 'logs/app.log')
|
|||
logger = setup_logging(_log_level, _log_path)
|
||||
|
||||
# App version — single source of truth for backup metadata, version-info endpoint, etc.
|
||||
SOULSYNC_VERSION = "2.2"
|
||||
SOULSYNC_VERSION = "2.3"
|
||||
|
||||
# Dedicated source reuse logger — writes to logs/source_reuse.log
|
||||
import logging as _logging
|
||||
|
|
@ -21493,180 +21493,120 @@ def get_version_info():
|
|||
"sections": [
|
||||
{
|
||||
"title": "Centralized Downloads Page",
|
||||
"description": "Live view of every download across the entire app in one place",
|
||||
"description": "Live view of every download across the entire app — tracks from Sync, Discover, Artists, Search, and Wishlist all in one place",
|
||||
"features": [
|
||||
"• New Downloads page in sidebar — shows all tracks from Sync, Discover, Artists, Search, and Wishlist",
|
||||
"• Live-updating list with filter pills: All, Active, Queued, Completed, Failed",
|
||||
"• Section headers group downloads by status with track counts",
|
||||
"• Track position display (3 of 19) for album and playlist batches",
|
||||
"• Album art, artist/album metadata, batch context, and error messages per row",
|
||||
"• New Downloads page in sidebar with live-updating list and nav badge",
|
||||
"• Filter pills: All, Active, Queued, Completed, Failed",
|
||||
"• Track position (3 of 19), album art, batch context, and error details per row",
|
||||
"• Clear Completed button removes finished items from the tracker",
|
||||
"• Nav badge shows active download count from any page via WebSocket",
|
||||
],
|
||||
"usage_note": "Click Downloads in the sidebar to see all active and recent downloads. The badge updates in real-time from any page."
|
||||
"usage_note": "Click Downloads in the sidebar. The badge updates in real-time from any page."
|
||||
},
|
||||
{
|
||||
"title": "First-Run Setup Wizard",
|
||||
"description": "New full-screen guided setup for first-time users",
|
||||
"description": "Full-screen guided setup that walks new users through configuration and their first download",
|
||||
"features": [
|
||||
"• 7-step wizard: Welcome, Metadata Source, Download Source, Paths & Media Server, Add Artists, First Download, Done",
|
||||
"• All 6 download sources available: Soulseek, YouTube, HiFi, Tidal, Qobuz, Deezer — with inline config and test buttons",
|
||||
"• Path fields default to /app/downloads and /app/Transfer with lock/unlock for Docker users",
|
||||
"• Media server connection (Plex/Jellyfin/Navidrome) with inline test",
|
||||
"• Add artists to watchlist with live search — shows watchlist status, add/remove in place",
|
||||
"• First download step searches metadata, finds best match, and downloads through the full pipeline",
|
||||
"• All settings save to DB identically to the Settings page — no difference in behavior",
|
||||
"• 7-step wizard: Welcome, Metadata Source, Download Source, Paths, Media Server, Add Artists, First Download",
|
||||
"• All 6 download sources with inline config and test buttons",
|
||||
"• Locked path defaults for Docker users (/app/downloads, /app/Transfer)",
|
||||
"• Add artists to watchlist with live search and remove in place",
|
||||
"• First download goes through the full matched download pipeline with metadata",
|
||||
"• Auto-shows on fresh installs, skippable, all settings save to DB",
|
||||
"• Done page with tips grid covering Sync, Wishlist, Automations, Notifications, Help, and Settings",
|
||||
],
|
||||
"usage_note": "Auto-shows for new users. Re-open anytime with ?setup=1 in the URL."
|
||||
},
|
||||
{
|
||||
"title": "Graceful Shutdown & Stability",
|
||||
"description": "Application now shuts down cleanly within 1 second instead of 60+",
|
||||
"features": [
|
||||
"• All background workers use interruptible sleep — respond to shutdown signals immediately",
|
||||
"• Docker containers no longer force-kill, preventing SQLite WAL corruption",
|
||||
"• Parallel component shutdown for scan managers, repair workers, executors",
|
||||
"• Download monitor thread safety with proper locking",
|
||||
"• Logging initialized early so import-time diagnostic messages are captured",
|
||||
"• Database initialization fixed for fresh installs — all migrations run in a single cycle",
|
||||
],
|
||||
"usage_note": "Docker users: containers now stop gracefully within the default 10-second timeout."
|
||||
},
|
||||
{
|
||||
"title": "Unknown Artist Prevention",
|
||||
"description": "Multi-layer defense against tracks downloading as 'Unknown Artist'",
|
||||
"features": [
|
||||
"• Metadata cache now rejects tracks with junk artist names — prevents caching incomplete data",
|
||||
"• Post-processing 3-tier fallback: check track_info, search result, then re-fetch from metadata API",
|
||||
"• Files never land in 'Unknown Artist' folders — guard runs before folder creation and tag embedding",
|
||||
],
|
||||
},
|
||||
{
|
||||
"title": "Deezer Multi-Artist Tagging",
|
||||
"description": "Feature tracks now tag all credited artists using Deezer's contributors field",
|
||||
"features": [
|
||||
"• ARTIST tag includes all contributors (e.g. 'Kraftklub, Domiziana') instead of just the primary",
|
||||
"• Album artist tag unchanged — folder organization unaffected",
|
||||
"• Falls back gracefully when contributors field is absent (search results)",
|
||||
],
|
||||
"usage_note": "Open with ?setup=1 URL parameter or openSetupWizard() from browser console. First-run auto-detection coming soon."
|
||||
},
|
||||
{
|
||||
"title": "Music Videos — Search & Download from YouTube",
|
||||
"description": "New Music Videos tab in enhanced and global search for finding and downloading music videos",
|
||||
"description": "Music Videos tab in enhanced and global search",
|
||||
"features": [
|
||||
"• Music Videos pill tab alongside Spotify/Deezer/iTunes/Discogs in both search bars",
|
||||
"• YouTube search returns video cards with 16:9 thumbnails, duration, channel name, view count",
|
||||
"• Click any video to download — circular progress ring on thumbnail, green checkmark on completion",
|
||||
"• Metadata matching — searches your primary source for clean artist/title before saving",
|
||||
"• Saves to configurable Music Videos directory as Artist/Title-video.mp4 (Plex global folder format)",
|
||||
"• Plex video type suffixes supported: -video, -lyrics, -live, -concert, -interview, -behindthescenes"
|
||||
"• Video cards with thumbnails, duration, channel name, view count",
|
||||
"• Click to download with progress ring — metadata matched before saving",
|
||||
"• Saves to configurable Music Videos directory (Plex format)",
|
||||
],
|
||||
"usage_note": "Set your Music Videos directory in Settings > Downloads, then search for any artist in the search bar and click the Music Videos tab."
|
||||
"usage_note": "Set your Music Videos directory in Settings > Downloads, then use the Music Videos tab in search."
|
||||
},
|
||||
{
|
||||
"title": "Lidarr Download Source (Development)",
|
||||
"description": "Use Lidarr as a download source for Usenet and torrent content",
|
||||
"description": "7th download source for Usenet and torrent content via Lidarr",
|
||||
"features": [
|
||||
"• 7th download source alongside Soulseek, YouTube, Tidal, Qobuz, HiFi, and Deezer",
|
||||
"• SoulSync handles discovery and matching, Lidarr handles downloading via its indexers",
|
||||
"• Configure with just URL + API key in Settings > Downloads",
|
||||
"• SoulSync handles discovery and matching, Lidarr handles downloading",
|
||||
"• Configure with URL + API key in Settings > Downloads",
|
||||
"• Available as standalone source or in Hybrid mode priority order",
|
||||
"• Currently in development — basic album search and download flow functional"
|
||||
],
|
||||
"usage_note": "Requires a running Lidarr instance with configured indexers and download clients. Set Download Source to 'Lidarr Only (Development)' or add to Hybrid order."
|
||||
"usage_note": "Requires a running Lidarr instance. Set Download Source to 'Lidarr Only (Development)' or add to Hybrid order."
|
||||
},
|
||||
{
|
||||
"title": "Metadata Pipeline Overhaul — Fix Unknown Artist & Source Selection",
|
||||
"description": "Major fix for tracks downloading as 'Unknown Artist' and Spotify being used when Deezer/iTunes was selected",
|
||||
"title": "Matching & Quality Improvements",
|
||||
"description": "Better album matching, per-track artist support, and placeholder detection",
|
||||
"features": [
|
||||
"• Fixed playlist pipeline (discover → sync → wishlist → download) losing artist, track number, and album year data",
|
||||
"• All discovery workers now respect your configured primary metadata source instead of always using Spotify",
|
||||
"• Centralized metadata source selection in core/metadata_service.py — one source of truth for all features",
|
||||
"• Fixed Deezer metadata cache returning incomplete data (missing track_number, release_date) from search result cache",
|
||||
"• Sync completion toast now shows which specific tracks failed to match (not just a count)",
|
||||
"• New 'Fix Unknown Artists' maintenance job — scans library for Unknown Artist tracks and corrects metadata, tags, and file paths",
|
||||
"• One-time migration purges stale discovery and Deezer cache entries on first startup after update"
|
||||
"• Album matching uses full similarity instead of word subset — 'Paradise' no longer matches 'Club Paradise'",
|
||||
"• Artist gate prevents wrong-artist downloads (Soulseek < 0.25, YouTube < 0.15 threshold)",
|
||||
"• Word boundary matching for artists — 'muse' no longer matches 'museum'",
|
||||
"• Watchlist scanner skips albums with placeholder tracks ('Track 1', 'Track 2') from unreleased tracklists",
|
||||
"• Per-track artist column for compilations and DJ mixes — tag writer uses track artist, not album artist",
|
||||
"• Centralized metadata source selection — all features respect your configured source",
|
||||
],
|
||||
"usage_note": "If you have existing Unknown Artist tracks, run the Fix Unknown Artists job from Settings > Maintenance."
|
||||
},
|
||||
{
|
||||
"title": "Matching Engine — Artist Verification Gate",
|
||||
"description": "Prevents downloading tracks from completely wrong artists on Soulseek and YouTube",
|
||||
"features": [
|
||||
"• New artist gate rejects candidates where the artist doesn't match the target (Soulseek: < 0.25, YouTube: < 0.15)",
|
||||
"• Fixed artist substring matching — 'muse' no longer matches 'museum', 'art' no longer matches 'heart'",
|
||||
"• Artist similarity now compared per path segment instead of full filename — misspelled artist names still match correctly",
|
||||
"• YouTube artist weight increased from 10% to 20% to reduce wrong-uploader matches",
|
||||
"• Seasonal discovery, personalized playlists, and playlist explorer all use configured source instead of Spotify"
|
||||
],
|
||||
"usage_note": "No action needed — matching improvements apply automatically to all new downloads."
|
||||
},
|
||||
{
|
||||
"title": "Deezer User Playlists — Browse & Download Your Library",
|
||||
"description": "New Deezer tab on the Sync page shows your personal playlists via ARL token — same flow as Spotify",
|
||||
"features": [
|
||||
"• Click Refresh to load all your Deezer playlists with track counts",
|
||||
"• Click any playlist to view tracks, then Download Missing or Sync — no discovery step needed",
|
||||
"• Existing Deezer URL import moved to 'Deezer Link' tab (unchanged)",
|
||||
"• ARL token field added to Connections tab alongside Downloads tab with bidirectional sync",
|
||||
"• Album release dates fetched for proper $year template variable support"
|
||||
],
|
||||
"usage_note": "Configure your ARL token in Settings > Connections or Downloads, then open the Deezer tab on the Sync page."
|
||||
},
|
||||
{
|
||||
"title": "Qobuz Token Auth — CAPTCHA Bypass",
|
||||
"description": "Qobuz added reCAPTCHA to their login — token auth lets you paste your session token directly",
|
||||
"features": [
|
||||
"• New 'Auth Token' field on both Connections and Downloads tabs for Qobuz",
|
||||
"• Log into play.qobuz.com in your browser, copy X-User-Auth-Token from DevTools, paste it in",
|
||||
"• Bypasses the CAPTCHA entirely — existing email/password login still works if your session is active",
|
||||
"• Token is validated and saved as a normal session — identical to email/password login"
|
||||
],
|
||||
"usage_note": "If Qobuz email/password login fails, use the Auth Token field instead."
|
||||
},
|
||||
{
|
||||
"title": "Streaming Source Matching — Artist Gate",
|
||||
"description": "Tidal, Qobuz, HiFi, and Deezer downloads no longer match to wrong artists",
|
||||
"features": [
|
||||
"• Artist similarity gate rejects candidates below 0.4 match threshold",
|
||||
"• Streaming source threshold raised from 0.55 to 0.60",
|
||||
"• No more fallback to lenient Soulseek filename matcher for structured API sources",
|
||||
"• Fixed single-char artist containment bug (e.g. 'B小町' no longer matches 'B.B. King')",
|
||||
"• YouTube and Soulseek matching completely unchanged"
|
||||
],
|
||||
"usage_note": "Downloads from official sources are now much more accurate. Check Download History for verification details."
|
||||
},
|
||||
{
|
||||
"title": "Download History — Source Provenance",
|
||||
"description": "Collapsible download history with full source tracking and AcoustID verification badges",
|
||||
"features": [
|
||||
"• Expected vs Downloaded comparison — shows what you asked for vs what the source provided",
|
||||
"• Mismatched downloads highlighted in red for easy identification",
|
||||
"• AcoustID verification badge per entry: Verified (green), Failed (red), Skipped (orange), Off (gray)",
|
||||
"• Source filename, track ID, and artist saved with every download",
|
||||
"• Click anywhere on an entry to expand/collapse details"
|
||||
],
|
||||
"usage_note": "Click 'Download History' on the Dashboard to see source provenance for new downloads."
|
||||
},
|
||||
{
|
||||
"title": "Fixes & Improvements",
|
||||
"description": "Bug fixes, quality of life improvements, and new settings",
|
||||
"description": "60+ commits of bug fixes, UX improvements, and infrastructure",
|
||||
"features": [
|
||||
"• Dismissed maintenance findings no longer reappear on next scan — dedup check now includes dismissed status",
|
||||
"• Orphan file detector: increased path matching depth to 4 segments + filename parsing fallback for unreadable tags",
|
||||
"• Media player: rapid play clicks no longer create duplicate audio streams requiring browser refresh",
|
||||
"• Logs directory auto-created on startup — prevents crash for non-Docker installations",
|
||||
"• Stale discovery data re-processed in automation pipeline — tracks with missing metadata get re-enriched",
|
||||
"• Artist names no longer stored as lowercase — fixed static method shadowing instance method. Run a database update to fix existing names.",
|
||||
"• Watchlist scanner skips future/unreleased albums — no more garbage downloads from albums not yet out",
|
||||
"• Playlist sync tracks now tagged with correct track numbers instead of always 01",
|
||||
"• Emby playlist sync fixed — integer IDs now accepted alongside Jellyfin GUIDs",
|
||||
"• Discovery fix search now tries all metadata sources (Spotify → Deezer → iTunes) with automatic fallback",
|
||||
"• Album completeness scanner skips zero-track albums to prevent auto-fill errors",
|
||||
"• Global search string escaping fixed — albums with newlines in metadata no longer crash",
|
||||
"• Download history timestamps fixed — no longer always showing 'Just now'",
|
||||
"• Discogs added to enrichment service whitelist — Enrich button now works for Discogs",
|
||||
"• Settings Connections tab redesigned with collapsible accordion services and brand-colored dots",
|
||||
"• Metadata source filter on Library page — filter artists by matched/unmatched to any service",
|
||||
"• Database Maintenance UI — VACUUM and incremental vacuum in Settings > Advanced",
|
||||
"• Music Library Paths setting — configure where your music files live for tag writing and file detection",
|
||||
"• Replace lower quality files on import — opt-in toggle in Settings > Library",
|
||||
"• HiFi API instance health check in Settings > Downloads",
|
||||
"• Debug test activity feed message removed from startup",
|
||||
"• Global search downloads now create bubble snapshots on Dashboard and Search page",
|
||||
"• Dead file findings now offer 'Remove from DB' option alongside 'Re-download' — works in bulk fix too",
|
||||
"• Deezer ARL sync and download modals rehydrate after page refresh",
|
||||
"• Deezer album data (release dates, cover art) cached in metadata cache — subsequent playlist loads are near-instant"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Artist Map — Visualize Your Music Universe",
|
||||
"description": "Three interactive canvas-based visualization modes on the Discover page",
|
||||
"features": [
|
||||
"• Watchlist Constellation — your watched artists as large nodes with similar artists orbiting around them",
|
||||
"• Genre Map — browse all artists by genre with a sidebar picker, ring-packed clusters, no artist cap",
|
||||
"• Artist Explorer — deep-dive any artist, ring 1 (direct similar) + ring 2 (extended network)",
|
||||
"• On-the-fly discovery — exploring an unknown artist fetches similar artists from MusicMap in real-time and caches them",
|
||||
"• Invalid artist names validated against Spotify/iTunes before loading the map",
|
||||
"• Offscreen canvas buffer rendering with LOD — handles 1000+ nodes smoothly",
|
||||
"• Image proxy endpoint solves CORS for canvas — Deezer, Last.fm, Discogs images now render on bubbles",
|
||||
"• Direct CORS fetch first (zero server load), proxy only as fallback for non-CORS CDNs",
|
||||
"• Server-side 5-minute cache on all map endpoints — switching genres and reopening is instant",
|
||||
"• Cache auto-invalidates on watchlist changes, scans, and new similar artist discoveries",
|
||||
"• Keyboard shortcuts (?, F for fit, S for search), mouse wheel zoom, click-to-explore",
|
||||
"• Hover constellation effect with fade animation, rich tooltips with genre tags"
|
||||
"• Plex playlists crash on Tag objects fixed — safe attribute access for non-playlist items",
|
||||
"• Music library paths now auto-save when added/removed on settings page",
|
||||
"• M3U files no longer created for single track downloads — only playlists",
|
||||
"• M3U [object Object] artist bug fixed — handles all artist format variations",
|
||||
"• Album year update 'database not defined' error fixed in post-processing",
|
||||
"• Sync tab content scrolling fixed — long lists no longer clipped",
|
||||
"• Hybrid download status shows green when any serverless source is in the order",
|
||||
"• Serverless sources (YouTube, HiFi, Qobuz) always show green in service status",
|
||||
"• Repeated slskd 401 errors suppressed after first warning",
|
||||
"• Download clients reload paths when settings change (no restart needed)",
|
||||
"• watchlist_artists table migrations include all provider ID columns in rebuilds",
|
||||
"• Emojis removed from all Python log and print statements",
|
||||
"• Interactive help coverage expanded with 30+ new entries",
|
||||
"• Docker compose includes optional slskd service block",
|
||||
"• Multi-stage Docker build reduces image size",
|
||||
"• MusicBrainz recording ID backfilled from Navidrome during scan",
|
||||
],
|
||||
"usage_note": "Navigate to Discover and click the Artist Map section. Choose Watchlist, Genre, or Explorer mode."
|
||||
},
|
||||
# v2.2 and earlier features moved to archive
|
||||
]
|
||||
}
|
||||
return jsonify(version_data)
|
||||
|
||||
_OLD_V22_NOTES = """
|
||||
{
|
||||
"title": "Wing It — Download or Sync Without Discovery",
|
||||
"description": "Bypass metadata discovery and use raw track names directly",
|
||||
|
|
@ -22320,9 +22260,7 @@ def get_version_info():
|
|||
"• Wishlist process API endpoint for external apps"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
return jsonify(version_data)
|
||||
""" # end of _OLD_V22_NOTES
|
||||
|
||||
_OLD_V2_NOTES = r"""
|
||||
"features": [
|
||||
|
|
@ -30558,7 +30496,7 @@ def get_server_playlists():
|
|||
raw_playlists = plex_client.server.playlists()
|
||||
logger.info(f"[ServerPlaylists] Plex returned {len(raw_playlists)} total playlists")
|
||||
for playlist in raw_playlists:
|
||||
if playlist.playlistType == 'audio':
|
||||
if getattr(playlist, 'playlistType', None) == 'audio':
|
||||
playlists_data.append({
|
||||
'id': str(playlist.ratingKey),
|
||||
'name': playlist.title,
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@
|
|||
|
||||
<!-- Version Section -->
|
||||
<div class="version-section">
|
||||
<button class="version-button" onclick="showVersionInfo()">v2.2</button>
|
||||
<button class="version-button" onclick="showVersionInfo()">v2.3</button>
|
||||
</div>
|
||||
|
||||
<!-- Status Section -->
|
||||
|
|
@ -6597,7 +6597,7 @@
|
|||
<!-- Header -->
|
||||
<div class="version-modal-header">
|
||||
<h2 class="version-modal-title">What's New in SoulSync</h2>
|
||||
<div class="version-modal-subtitle">Version 2.1 — Latest Changes</div>
|
||||
<div class="version-modal-subtitle">Version 2.3 — Latest Changes</div>
|
||||
</div>
|
||||
|
||||
<!-- Content Area with Scroll -->
|
||||
|
|
|
|||
|
|
@ -3043,6 +3043,10 @@ function initializeMediaPlayer() {
|
|||
const stopButton = document.getElementById('stop-button');
|
||||
const volumeSlider = document.getElementById('volume-slider');
|
||||
|
||||
// Start in idle state (no track playing)
|
||||
const player = document.getElementById('media-player');
|
||||
if (player && !currentTrack) player.classList.add('idle');
|
||||
|
||||
// Initialize HTML5 audio player
|
||||
audioPlayer = document.getElementById('audio-player');
|
||||
if (audioPlayer) {
|
||||
|
|
@ -3129,8 +3133,9 @@ function setTrackInfo(track) {
|
|||
document.getElementById('play-button').disabled = false;
|
||||
document.getElementById('stop-button').disabled = false;
|
||||
|
||||
// Hide no track message
|
||||
// Hide no track message and expand player
|
||||
document.getElementById('no-track-message').classList.add('hidden');
|
||||
document.getElementById('media-player').classList.remove('idle');
|
||||
|
||||
// Sync expanded player and media session
|
||||
updateNpTrackInfo();
|
||||
|
|
@ -3205,8 +3210,9 @@ function clearTrack() {
|
|||
// Hide loading animation
|
||||
hideLoadingAnimation();
|
||||
|
||||
// Show no track message
|
||||
// Show no track message and collapse player
|
||||
document.getElementById('no-track-message').classList.remove('hidden');
|
||||
document.getElementById('media-player').classList.add('idle');
|
||||
|
||||
// Reset queue state
|
||||
npQueue = [];
|
||||
|
|
@ -15585,6 +15591,11 @@ function processModalStatusUpdate(playlistId, data) {
|
|||
const completionMessage = `Download complete! ${completionParts.join(', ')}.`;
|
||||
showToast(completionMessage, 'success');
|
||||
|
||||
// Refresh server playlists tab so it reflects newly synced tracks
|
||||
if (typeof loadServerPlaylists === 'function') {
|
||||
setTimeout(() => loadServerPlaylists(), 2000);
|
||||
}
|
||||
|
||||
// Auto-close wishlist modal when completed (for auto-processing)
|
||||
if (playlistId === 'wishlist') {
|
||||
console.log('🔄 [Auto-Wishlist] Auto-closing completed wishlist modal to enable next cycle');
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ body {
|
|||
rgba(var(--accent-rgb), 0.14) 0%,
|
||||
rgba(var(--accent-rgb), 0.08) 30%,
|
||||
rgba(var(--accent-rgb), 0.03) 70%,
|
||||
transparent 100%);
|
||||
rgba(18, 18, 18, 1) 100%);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-top-right-radius: 20px;
|
||||
padding: 20px 24px;
|
||||
|
|
@ -267,8 +267,11 @@ body {
|
|||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
position: relative;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
|
||||
/* Subtle inner glow */
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
|
|
@ -536,6 +539,31 @@ body {
|
|||
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* Compact idle state — collapsed when nothing is playing */
|
||||
.media-player.idle {
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
margin: 4px 14px;
|
||||
}
|
||||
|
||||
.media-player.idle .player-top-progress,
|
||||
.media-player.idle .media-header,
|
||||
.media-player.idle .media-controls-row,
|
||||
.media-player.idle .media-expanded {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.media-player.idle .no-track-message {
|
||||
padding: 10px 14px;
|
||||
font-size: 0.75rem;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.media-player.idle .no-track-message svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
/* Top progress bar - thin line across full width */
|
||||
.player-top-progress {
|
||||
padding: 0 14px;
|
||||
|
|
|
|||
Loading…
Reference in a new issue