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
pull/253/head
Broque Thomas 4 weeks ago
parent deadfa1e82
commit 571ba6b532

@ -31,7 +31,7 @@ from config.settings import config_manager
logger = get_logger("web_server")
# App version — single source of truth for backup metadata, version-info endpoint, etc.
SOULSYNC_VERSION = "2.0"
SOULSYNC_VERSION = "2.1"
# Dedicated source reuse logger — writes to logs/source_reuse.log
import logging as _logging
@ -18490,6 +18490,18 @@ def get_version_info():
"title": "What's New in SoulSync",
"subtitle": f"Version {SOULSYNC_VERSION} — Latest Changes",
"sections": [
{
"title": "🎧 Deezer Download Source",
"description": "Download music directly from Deezer with ARL authentication",
"features": [
"• New download source: Deezer joins Soulseek, YouTube, Tidal, Qobuz, and HiFi",
"• FLAC lossless, MP3 320, and MP3 128 with automatic quality fallback",
"• ARL token authentication — paste from browser cookies, test connection in Settings",
"• Full hybrid mode support — use Deezer as primary, fallback, or in any priority order",
"• Blowfish CBC decryption handles Deezer's encrypted streams transparently",
"• AcoustID verification automatically skipped for Deezer (and Tidal/Qobuz/HiFi) — trusted API sources"
]
},
{
"title": "🔍 Cache-Powered Discovery",
"description": "Five new discover sections mined from your metadata cache — zero API calls",
@ -18566,46 +18578,71 @@ def get_version_info():
]
},
{
"title": "🎧 Scrobbling to Last.fm & ListenBrainz",
"description": "Automatically scrobble your plays from Plex, Jellyfin, or Navidrome",
"title": "🏷️ Picard-Style Album Tagging",
"description": "All tracks in an album now get the same MusicBrainz release ID automatically",
"features": [
"• Listen on your media server — SoulSync automatically scrobbles to Last.fm and/or ListenBrainz",
"• Last.fm: full web auth flow — enter API secret, click Authorize, session key stored permanently",
"• ListenBrainz: simple token-based — enable toggle and plays are submitted automatically",
"• Batch scrobbling with dedup tracking — events only scrobbled once, never duplicated",
"• Both services fully opt-in via Settings toggles"
"• Pre-flight MB release lookup before album tracks start downloading",
"• Picks ONE release, validates track count, caches for all tracks in the batch",
"• Strips Spotify edition suffixes (Super Deluxe, Remastered) for better MB matching",
"• New Album Tag Consistency repair job: scan and fix existing albums with mismatched tags"
]
},
{
"title": "🛠️ Enrichment & Repair Fixes",
"description": "Critical fixes for background workers and maintenance jobs",
"features": [
"• All 9 enrichment workers: error status items no longer auto-retry in infinite loops",
"• Cover art filler: findings no longer recreated after being fixed",
"• Spotify rate limit respected by search_tracks, search_albums, and cover art scanner",
"• Config save: 30s timeout + WAL mode fixes 'database is locked' on busy systems",
"• Enrichment workers auto-pause during DB scans and resume when complete"
]
},
{
"title": "🔗 Automation Signal Chain Fix",
"description": "Event-triggered automations now receive playlist context properly",
"features": [
"• playlist_id forwarded from events to action handlers (fixes silent 'No playlist specified')",
"• Mirrored playlist discovery no longer pre-marks tracks as discovered with wrong album art",
"• Reorganize modal now loads saved path template instead of hardcoded default",
"• Spotify enrichment worker starts unpaused by default like all other workers"
]
},
{
"title": "🧠 Personalized Discovery",
"description": "Discovery playlists now use your listening history to recommend better music",
"title": "🎨 Unified Glass UI Redesign",
"description": "Consistent visual style across all cards, modals, and buttons",
"features": [
"• Release Radar: genre affinity (+10), artist familiarity (+15), overplay penalty (-10) scoring",
"• Discovery Weekly: serendipity weighting — boosts unheard artists in your favorite genres",
"• Recent Albums: adaptive time window (21-60 days) based on how fast you consume music",
"• New 'Because You Listen To' sections: personalized carousels for your top 3 artists",
"• Familiar Favorites weighted by actual play count, not random sampling",
"• All personalization gracefully falls back for new users with no listening data"
"• Dashboard tool cards, service cards, and stat cards: unified glass style",
"• Sync page playlist cards: all sources (Spotify, YouTube, Tidal, Deezer, Mirrored, Beatport)",
"• Download missing and wishlist modals: cleaner backgrounds, softer shadows",
"• Watchlist and enhance quality buttons: glass hover with accent glow",
"• Library page: innerHTML rendering + staggered card animation for faster loads"
]
},
{
"title": "📊 Listening Stats Page",
"description": "Full stats dashboard with Chart.js visualizations of your listening habits",
"title": "🎧 Scrobbling to Last.fm & ListenBrainz",
"description": "Automatically scrobble your plays from Plex, Jellyfin, or Navidrome",
"features": [
"• Overview cards: total plays, listening time, unique artists/albums/tracks",
"• Listening activity timeline bar chart with 7d/30d/12m/all time ranges",
"• Genre breakdown doughnut chart with percentage legend",
"• Top artists visual bubbles with profile pictures + ranked lists",
"• Top albums and tracks with album art, clickable artist names",
"• Library health: format breakdown bar, unplayed tracks, enrichment coverage",
"• Sync Now button for instant data refresh from your media server",
"• Background worker polls Plex/Jellyfin/Navidrome every 30 minutes",
"• Pre-computed cache — tab switching is instant"
"• Listen on your media server — SoulSync automatically scrobbles to Last.fm and/or ListenBrainz",
"• Last.fm: full web auth flow, ListenBrainz: simple token-based",
"• Batch scrobbling with dedup tracking — events only scrobbled once"
]
},
{
"title": "🆔 SoulID Worker",
"description": "Deterministic identity system for cross-node artist/album/track matching",
"title": "🧠 Personalized Discovery + Listening Stats",
"description": "Discovery playlists use your listening history, plus a full stats dashboard",
"features": [
"• Release Radar, Discovery Weekly, and Because You Listen To: personalized by play history",
"• Listening Stats page: timeline chart, genre breakdown, top artists/albums/tracks",
"• Database storage donut chart in Library Health section",
"• Play buttons on stats page tracks with cover art"
]
}
]
}
return jsonify(version_data)
_OLD_V2_NOTES = r"""
"features": [
"• Generates soul IDs using SHA-256 hash of normalized names",
"• Artists: hash(name + debut_year) — debut year from iTunes + Deezer API verification",
@ -19160,12 +19197,7 @@ def get_version_info():
"• Fix Docker upgrade crashes from stale volume mounts and partial DB migrations",
"• Isolate service client initialization so one failure doesn't break the app",
"• Explicit content filter with configurable toggle to skip explicit tracks",
"• Full Cleanup automation for quarantine, downloads, staging, and search history"
]
}
]
}
return jsonify(version_data)
""" # end of _OLD_V2_NOTES_REMOVED
def _simple_monitor_task():

@ -239,7 +239,7 @@
</button>
<div class="volume-control">
<span class="volume-icon">
<svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/></svg>
<svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.16c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.16c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/></svg>
</span>
<input type="range" class="volume-slider" id="volume-slider" min="0" max="100" value="70">
</div>
@ -271,7 +271,7 @@
<!-- Version Section -->
<div class="version-section">
<button class="version-button" onclick="showVersionInfo()">v2.0</button>
<button class="version-button" onclick="showVersionInfo()">v2.1</button>
</div>
<!-- Status Section -->
@ -5626,7 +5626,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.0 — Latest Changes</div>
<div class="version-modal-subtitle">Version 2.1 — Latest Changes</div>
</div>
<!-- Content Area with Scroll -->

Loading…
Cancel
Save