From 30ff0bde4933906189415c066b0c23d2e1188162 Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Thu, 25 Jun 2026 16:11:51 -0700 Subject: [PATCH] Release 2.7.9: version bump + What's New / version modal + PR description + docker-publish default tag - _SOULSYNC_BASE_VERSION -> 2.7.9; docker-publish default version_tag -> 2.7.9 - pr_description.md rewritten for 2.7.9 (best-quality downloads + quality profile #896, Discover listening recs + Listening Mix #913, Wing It Pool, Auto-Sync lane redesign, multi-disc #927, sync labels #925, post-processing race #928) - WHATS_NEW: 2.7.8 block -> 2.7.9 (+ brief earlier-versions); VERSION_MODAL_SECTIONS: 2.7.9 highlights promoted, 2.7.8 rolled into an Earlier aggregator - RELEASE_2.7.9_discord.md: mini Discord post --- .github/workflows/docker-publish.yml | 4 +- RELEASE_2.7.9_discord.md | 13 +++++ pr_description.md | 55 +++++++++++------- web_server.py | 2 +- webui/static/helper.js | 85 ++++++++++++++++++---------- 5 files changed, 104 insertions(+), 55 deletions(-) create mode 100644 RELEASE_2.7.9_discord.md diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index a08b63a5..91daceac 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -9,9 +9,9 @@ on: workflow_dispatch: inputs: version_tag: - description: 'Version tag (e.g. 2.7.8)' + description: 'Version tag (e.g. 2.7.9)' required: true - default: '2.7.8' + default: '2.7.9' jobs: build-and-push: diff --git a/RELEASE_2.7.9_discord.md b/RELEASE_2.7.9_discord.md new file mode 100644 index 00000000..80651c39 --- /dev/null +++ b/RELEASE_2.7.9_discord.md @@ -0,0 +1,13 @@ +**SoulSync 2.7.9** is out πŸŽ‰ a big one. + +🎚️ **Best-quality downloads** β€” downloads now follow a ranked quality profile you drag to order (FLAC 24/192 β†’ mp3). best-quality mode grabs the highest-quality copy across *every* source; priority mode gets an opt-in rank-based order toggle. quarantine is folded into the Downloads page + safer imports (AcoustID fail-closed, silence/truncation guards). + +🎧 **Discover got smart** β€” "Based On Your Listening" ranks artists from who you *actually play*, and "Your Listening Mix" is a playable track playlist of their top tracks (works on any source). Fresh Tape fills properly now. + +⚑ **Wing It Pool** β€” a new spot next to Discovery Pool to review + re-match the tracks Wing It guessed at (they used to be invisible). + +πŸ” **Auto-Sync redesign** β€” the scheduling board is now clean horizontal lanes instead of a side-scrolling column wall. + +πŸ› **Fixes** β€” multi-disc albums no longer show disc-2 as "missing" (#927), playlists no longer stuck on "Never Synced" (#925), and tracks can't import while quarantined (#928). thanks @ramonskie + @nick2000713 πŸ™ + +⚠️ **re-scan your library once** so the multi-disc fix can backfill disc numbers on existing tracks. enjoy! 🎢 diff --git a/pr_description.md b/pr_description.md index 3b270a6e..c2e865ac 100644 --- a/pr_description.md +++ b/pr_description.md @@ -1,38 +1,49 @@ -# soulsync 2.7.8 β€” `dev` β†’ `main` +# soulsync 2.7.9 β€” `dev` β†’ `main` -a feature patch on top of 2.7.7 β€” playlists can now be put back in order on the server, you can re-wishlist a missed track straight from sync history, plus a couple of reported fixes. +a big one. the headline is the new **best-quality download system + a real quality profile**, plus a much smarter **Discover** page, a new **Wing It Pool**, a redesigned **Auto-Sync** board, and a pile of reported fixes (multi-disc albums, playlist sync labels, the import-vs-quarantine race). --- ## what's new -### align playlists β€” server order, not just contents -the server-playlist editor only ever cared about *which* tracks were on the server, never their order β€” and it rendered the server column in the source's order, so a playlist with the right tracks in the wrong sequence read as "in sync" when it wasn't. now it tells the truth: -- an **"out of order"** badge appears when the tracks match but the sequence differs (relative order, so missing/extra tracks don't false-flag it), and a **read-only view** shows the server's *actual* order with cover art. -- a new **"Align playlists"** action reorders the server playlist to match the source β€” **Plex** (in-place via moveItem), **Navidrome** (ordered rewrite), and **Jellyfin** (Move endpoint), all of which preserve the playlist's identity/poster. two choices for server-only extras: **mirror source** (drop them) or **keep extras** (park them at the end). it's order-only β€” it never adds the missing tracks (that's a normal sync's job) and never touches metadata, just reshuffles ids already on the server. +### best-quality downloads + a real quality profile +downloads are now driven by a **ranked-target quality profile** instead of a fixed preference. you order the formats you want (drag to reorder β€” FLAC 24/192 down to mp3, every format controllable, with "all lossless / all lossy" group shortcuts), and: +- **best-quality search mode** pools candidates across *every* source per query and grabs the highest-quality copy that meets your profile β€” not just the first/fastest match. priority mode is still there, now with an opt-in **"rank-based download order"** toggle if you want quality-first ordering there too. +- each streaming source's download tier is derived from the one global profile, so you set it once. +- AAC is an opt-in tier; old per-source Hi-Res preferences migrate into the profile automatically. -### re-add to wishlist from sync history -in the dashboard's **Recent Syncs β†’ details**, the "β†’ Wishlist" status on an unmatched track is now a button β€” click it to re-add that exact track to the wishlist with the **same context the sync used** (source playlist, cover art, everything), so it's indistinguishable from the original auto-add. the re-add and the live sync now build the *identical* payload from one shared path, so the cover and album/single classification carry through. wing-it fallback stubs (tracks that couldn't be resolved to real metadata) are correctly shown as **"Unmatched"** and aren't re-addable β€” matching what the sync itself does. +### quarantine, cleaned up + safer +- the quarantine view is **consolidated into the Downloads page** as a filter (no separate place to check), with real audio quality shown on the rows and approve/retry handled inline. +- **AcoustID fail-closed mode** (opt-in): only import tracks that actually verify, so a wrong file never lands in your library. +- **silence + truncated-download guards** catch mostly-silent preview files and downloads that are shorter than their container claims, before they import. +- a **library quality check** runs as a repair job and can flag files that are upgradeable to your preferred quality. -### fixes -- **import search said "Deezer" for Spotify Free users (#922)** β€” manual album-import told no-auth Spotify users that Deezer was their primary source. the functional source legitimately downgrades to a working fallback (the free path has no album-name search), but the *label* should name what you configured. now it reads "Spotify." -- **iTunes albums >50 tracks could still truncate (#918 follow-up)** β€” the limit=200 fix only helped fresh fetches; albums cached at 50 before the fix kept serving 50 from the persistent cache. now a cached tracklist shorter than the album's known track count self-heals on next load. +### Discover got a lot smarter +- **"Based On Your Listening"** β€” a new artist row, ranked from who you actually *play* the most (consensus + recency weighted), with a "because you listen to X, Y" reason on each card. +- **"Your Listening Mix"** β€” a playable track playlist built from those artists' top tracks. works on **any** metadata source (falls back to Deezer's public API), not just Spotify. +- **Fresh Tape** actually fills now β€” it was starving down to 5–10 tracks because future-dated albums ate the candidate budget. +- the **SoulSync Discovery** tab on the Sync page now lists *every* playlist kind (incl. the Listening Mix) so you can mirror + auto-sync them. -### under the hood -- `.gitignore` now covers **all** `database/*.db` (+ wal/shm/backup), not just `music_library` β€” so the video db and any future db can't be committed by accident. +### Wing It Pool +a new button next to **Discovery Pool** on the Mirrored Playlists tab. Wing It auto-matches tracks it couldn't match to metadata on a best-effort guess β€” those were invisible until now. the Wing It Pool opens to a two-card view (**guesses to review** + **resolved**) so you can verify or re-match what it guessed. + +### Auto-Sync Manager redesign +the scheduling board no longer scrolls sideways through a wall of columns. intervals (hourly) and days (weekly) are now **horizontal lanes** β€” empty ones collapse, busy ones grow, and the scroll position holds when you add a playlist. --- -## a brief recap of what came before -2.7.7 was a fix-heavy patch β€” the metadata-parity fix so downloads tag + path right without a manual reorganize (#915), the listening-recs foundation (#913), jellyfin atomic writes, and a big reported-issue sweep (#905/#908–#912/#914/#916–#918). 2.7.6 exported playlists TO listenbrainz + youtube liked-music sync; 2.7.5 matching & artwork accuracy; 2.7.4 re-identify; 2.7.3 the Quality Upgrade Finder; 2.7.2 playlist-folder mirroring; 2.7.1 download verification; 2.7.0 made multi-user real. +## fixes + +- **multi-disc albums showed disc-2 tracks as "missing" / under disc 1 (#927)** β€” the library scan never read the disc number, so every track was stored as disc 1. it now captures the real disc from Jellyfin/Plex/Navidrome at scan time. *(re-scan your library once to backfill existing tracks.)* +- **playlists always said "Never Synced" (#925)** β€” auto-synced/mirrored playlists were only checked against the direct-sync status, never their auto-sync status. fixed (thanks @ramonskie). +- **tracks imported while quarantined / shown "completed" (#928)** β€” a race let both the browser poll and the download monitor post-process the same finished download. an atomic claim now ensures exactly one path handles it (thanks @nick2000713). +- **library card badges hijacked the click** β€” clicking the watchlist eye or a source badge on an artist card also opened the artist detail page (and the badge's own link). badges now do only their own thing. --- -## tests -additive + scoped β€” the new write paths are their own routes that don't touch the normal sync. new seam/regression suites for the order-status detection (incl. the reported "moved to #2" case + missing/extra false-flag guards), the pure align-rewrite planner (mirror vs keep-extras, never-injects-a-foreign-track, stale-data rejection), the sync re-add payload (a direct parity assertion that the re-add == the live-sync payload, plus the wing-it skip), and the `get_primary_source_label` fix (#922). iTunes self-heal proven against the real persistent-cache shape. relevant suites green; `ruff check` clean. +## under the hood +- music automations page no longer shows video-app automations (they live in the shared engine DB). +- quality-settings tile tidied up β€” collapsible β“˜ help instead of walls of text, proper reset button, dropped the redundant per-source "quality is global" notes. +- download clients don't crash on init when the download path can't be created. -## post-merge -- [ ] tag `v2.7.8` on `main` -- [ ] docker-publish with `version_tag: 2.7.8` -- [ ] discord announce (auto-fired by the workflow) -- [ ] reply on #922 and the #918 follow-up +--- diff --git a/web_server.py b/web_server.py index 21f594af..b87f2ba7 100644 --- a/web_server.py +++ b/web_server.py @@ -40,7 +40,7 @@ logger = setup_logging(_log_level, _log_path) # App version β€” single source of truth for backup metadata, system-info, update check, etc. # Semver: MAJOR.MINOR.PATCH. Bump at each devβ†’main release. -_SOULSYNC_BASE_VERSION = "2.7.8" +_SOULSYNC_BASE_VERSION = "2.7.9" def _build_version_string(): """Append short commit hash to version when available (e.g. 2.35+abc1234).""" diff --git a/webui/static/helper.js b/webui/static/helper.js index fdcc78a7..ddcac5cd 100644 --- a/webui/static/helper.js +++ b/webui/static/helper.js @@ -3404,13 +3404,19 @@ function closeHelperSearch() { const WHATS_NEW = { // Convention: keep only the CURRENT release here, plus a single brief // "Earlier versions" summary entry. Don't accumulate old per-version blocks. - '2.7.8': [ - { date: 'June 2026 β€” 2.7.8 release' }, - { title: 'Align playlists β€” fix the order on the server', desc: 'the server-playlist editor only cared about WHICH tracks were on the server, never their order β€” and it drew the server column in the source\'s order, so a right-tracks-wrong-sequence playlist read as "in sync" when it wasn\'t. now an "out of order" badge appears when the tracks match but the sequence differs (relative order, so missing/extra don\'t false-flag), with a read-only view of the server\'s ACTUAL order. and a new "Align playlists" action reorders the server to match the source β€” Plex, Navidrome and Jellyfin, all preserving the playlist\'s identity/poster. order-only: never adds missing tracks, never touches metadata.', page: 'sync' }, - { title: 'Re-add to wishlist from sync history', desc: 'in Recent Syncs β†’ details, the "β†’ Wishlist" status on an unmatched track is now a button β€” click it to re-add that exact track with the SAME context the sync used (source playlist, cover art, everything). the re-add and the live sync build the identical payload from one shared path, so the cover and album/single classification carry through. wing-it stubs (couldn\'t be resolved) show as "Unmatched" and aren\'t re-addable, matching the sync.', page: 'dashboard' }, - { title: 'Import search said "Deezer" for Spotify Free (#922)', desc: 'manual album-import told no-auth Spotify users that Deezer was their primary source. the functional source legitimately falls back (the free path has no album-name search), but the label should name what you configured β€” now it reads "Spotify".', page: 'import' }, - { title: 'iTunes albums over 50 still truncating (#918 follow-up)', desc: 'the limit=200 fix only helped fresh fetches; albums cached at 50 before it kept serving 50 from the persistent cache. now a cached tracklist shorter than the album\'s known track count self-heals on next load.', page: 'library' }, - { title: 'Earlier versions', desc: '2.7.7 was fix-heavy β€” downloads tag + path right without a manual reorganize (#915), the listening-recs foundation (#913), jellyfin atomic writes, and a big reported-issue sweep (#905/#908–#912/#914/#916–#918). 2.7.6 exported playlists TO listenbrainz + youtube liked-music sync; 2.7.5 matching & artwork accuracy; 2.7.4 re-identify; 2.7.3 the Quality Upgrade Finder; 2.7.2 playlist-folder mirroring; 2.7.1 download verification; 2.7.0 made multi-user real.' }, + '2.7.9': [ + { date: 'June 2026 β€” 2.7.9 release' }, + { title: 'Best-quality downloads + a real quality profile', desc: 'downloads now follow a ranked-target quality profile β€” drag to order every format (FLAC 24/192 β†’ mp3, with "all lossless / all lossy" shortcuts). best-quality search mode pools candidates across EVERY source per query and grabs the highest-quality copy that meets your profile; priority mode gains an opt-in "rank-based download order" toggle. each streaming source\'s tier comes from the one profile, AAC is an opt-in tier, and old per-source Hi-Res prefs migrate in automatically.', page: 'settings' }, + { title: 'Quarantine cleaned up + safer imports', desc: 'the quarantine view is folded into the Downloads page as a filter (real audio quality on the rows, inline approve/retry). opt-in AcoustID fail-closed mode only imports tracks that actually verify; silence + truncated-download guards catch preview/short files before they import; a library quality check runs as a repair job and flags upgradeable files.', page: 'downloads' }, + { title: 'Discover β€” Based On Your Listening + Listening Mix', desc: 'a new artist row ranked from who you actually PLAY the most (consensus + recency weighted, with a "because you listen to X" reason), plus "Your Listening Mix" β€” a playable track playlist of those artists\' top tracks that works on ANY metadata source (Deezer public fallback). the SoulSync Discovery sync tab now lists every playlist kind so you can mirror + auto-sync them.', page: 'discover' }, + { title: 'Fresh Tape fills properly now', desc: 'it was starving down to 5–10 tracks because future-dated/announced albums sorted to the top and ate the candidate budget before being skipped. released albums now fill it.', page: 'discover' }, + { title: 'Wing It Pool', desc: 'a new button next to Discovery Pool on the Mirrored Playlists tab. Wing It auto-matches tracks it couldn\'t match to metadata on a best-effort guess β€” previously invisible. the Wing It Pool shows a two-card view (guesses to review + resolved) so you can verify or re-match them.', page: 'sync' }, + { title: 'Auto-Sync Manager redesign', desc: 'the scheduling board no longer scrolls sideways through a wall of columns β€” intervals (hourly) and days (weekly) are now horizontal lanes; empty ones collapse, busy ones grow, and the scroll holds when you drop a playlist in.', page: 'sync' }, + { title: 'Multi-disc albums fixed (#927)', desc: 'the scan never read the disc number, so every track stored as disc 1 β€” disc-2+ tracks showed as "missing" or under disc 1. it now captures the real disc from Jellyfin/Plex/Navidrome at scan time. re-scan once to backfill existing tracks.', page: 'library' }, + { title: 'Playlists always said "Never Synced" (#925)', desc: 'auto-synced/mirrored playlists were only checked against the direct-sync status, never their auto-sync status, so they read "Never Synced" even when synced. fixed (thanks @ramonskie).', page: 'sync' }, + { title: 'Tracks imported while quarantined (#928)', desc: 'a race let both the browser poll and the download monitor post-process the same finished download β€” imported despite quarantine, or "completed" while quarantined. an atomic claim now ensures exactly one path handles it (thanks @nick2000713).', page: 'downloads' }, + { title: 'Library card badges hijacked the click', desc: 'clicking the watchlist eye or a source badge on an artist card also opened the artist detail page (and the badge\'s own link). badges now do only their own thing β€” only the card opens detail.', page: 'library' }, + { title: 'Earlier versions', desc: '2.7.8 added Align Playlists (fix the order on the server) + re-add-to-wishlist from sync history, plus the #922 Spotify-Free label and #918 iTunes-cache fixes. 2.7.7 was a fix sweep; 2.7.6 listenbrainz/youtube export; 2.7.3 the Quality Upgrade Finder; 2.7.0 made multi-user real.' }, ], }; @@ -3441,47 +3447,66 @@ const WHATS_NEW = { // usage_note?: 'optional hint shown at the bottom' } const VERSION_MODAL_SECTIONS = [ { - title: "Align playlists β€” fix the order on the server", - description: "the headline β€” the server-playlist editor can now put a playlist back in the SOURCE's order, not just sync which tracks are on it.", + title: "Best-quality downloads + a real quality profile", + description: "the headline β€” downloads now follow a ranked-target quality profile instead of a fixed preference.", features: [ - "an \"out of order\" badge when the tracks match but the sequence differs (relative order, so missing/extra tracks don't false-flag it), plus a read-only view of the server's ACTUAL order with cover art", - "a new \"Align playlists\" action reorders the server to match the source β€” Plex, Navidrome and Jellyfin, all preserving the playlist's identity/poster", - "two choices for server-only extras (mirror source = drop them, or keep extras at the end); order-only β€” never adds missing tracks, never touches metadata", + "drag to order the formats you want (FLAC 24/192 β†’ mp3, every format controllable, with \"all lossless / all lossy\" group shortcuts)", + "best-quality search mode pools candidates across EVERY source per query and grabs the highest-quality copy that meets your profile β€” not just the first/fastest match", + "priority mode keeps its behavior, with an opt-in \"rank-based download order\" toggle; each streaming source's tier comes from the one profile; AAC is an opt-in tier, and old per-source Hi-Res prefs migrate in", + "quarantine folded into the Downloads page (real quality on the rows, inline approve/retry), opt-in AcoustID fail-closed mode, and silence/truncation guards that catch preview + short files before import", ], }, { - title: "Re-add to wishlist from sync history", - description: "in Recent Syncs β†’ details, re-wishlist a track the sync couldn't place β€” with the exact same context.", + title: "Discover, a lot smarter", + description: "Discover now learns from what you actually play.", features: [ - "the \"β†’ Wishlist\" status on an unmatched track is now a button; click it to re-add that exact track with the SAME context the sync used (source playlist, cover art, everything)", - "the re-add and the live sync build the identical payload from one shared path, so the cover and album/single classification carry through", - "wing-it stubs (couldn't be resolved to real metadata) show as \"Unmatched\" and aren't re-addable, matching what the sync does", + "\"Based On Your Listening\" β€” a new artist row ranked by who you play the most (consensus + recency weighted), with a \"because you listen to X, Y\" reason on each card", + "\"Your Listening Mix\" β€” a playable track playlist from those artists' top tracks; works on ANY metadata source (falls back to Deezer's public API), not just Spotify", + "Fresh Tape fills properly now β€” it was starving to 5–10 tracks because future-dated albums ate the candidate budget; and the SoulSync Discovery sync tab lists every playlist kind so you can mirror + auto-sync them", + ], + }, + { + title: "Wing It Pool", + description: "a place to review the tracks Wing It guessed at β€” they used to be invisible.", + features: [ + "a new button next to Discovery Pool on the Mirrored Playlists tab; Wing It auto-matches tracks it couldn't match to metadata on a best-effort guess", + "opens to a two-card view β€” guesses to review + resolved β€” so you can verify or re-match what it guessed (re-match reuses the same fix flow as Discovery Pool)", + ], + }, + { + title: "Auto-Sync Manager redesign", + description: "the scheduling board no longer scrolls sideways through a wall of columns.", + features: [ + "intervals (hourly) and days (weekly) are now horizontal lanes β€” empty ones collapse to thin strips, busy ones grow", + "the scroll position holds when you drop a playlist in (it used to snap back to the start every time)", ], }, { title: "Recent fixes", - description: "a couple of reported fixes.", + description: "reported bugs squashed this cycle.", features: [ - "#922 β€” manual import told Spotify Free users their primary source was \"Deezer\"; the search legitimately falls back (the free path can't search albums by name), but the label now reads \"Spotify\"", - "#918 follow-up β€” iTunes albums over 50 tracks could still show 50 from a stale cache; a cached tracklist shorter than the album's known track count now self-heals on next load", + "#927 β€” multi-disc albums showed disc-2 tracks as \"missing\" or under disc 1; the scan never read the disc number. it now captures the real disc from Jellyfin/Plex/Navidrome at scan time (re-scan once to backfill existing tracks)", + "#925 β€” auto-synced/mirrored playlists always read \"Never Synced\" because only the direct-sync status was checked, never the auto-sync one (thanks @ramonskie)", + "#928 β€” a race let both the browser poll and the download monitor post-process the same finished download, so a track could import while quarantined; an atomic claim fixes it (thanks @nick2000713)", + "library artist-card badges (the watchlist eye + source links) no longer hijack the click into the artist detail page β€” they do only their own thing", ], }, { - title: "Earlier in 2.7.7", - description: "2.7.7 was fix-heavy β€” downloads tag + path right the first time without a manual reorganize (#915), the listening-recs foundation (#913), jellyfin atomic writes, and a big reported-issue sweep.", + title: "Earlier in 2.7.8", + description: "2.7.8 was about playlist order + a couple of reported fixes.", features: [ - "#915 β€” post-processing + redownload now pull the full album from your PRIMARY metadata source, so the $year, real release date and album type land right the first time", - "#913 β€” listening-driven recommendations: ranks artists you'd love but don't own, scored by consensus from your top-played", - "#905/#908/#911/#918/#916/#914/#917/#910/#909/#912 β€” navidrome playlists doubling, youtube ~100 cap, wrong redownload edition, iTunes 50-track truncation, multi-disc shown missing, and the rest of the batch", + "Align playlists β€” reorder the server playlist to match the source (Plex/Navidrome/Jellyfin), with an \"out of order\" badge; order-only, never adds missing tracks", + "re-add a missed track to the wishlist straight from Recent Syncs β†’ details, with the exact same context the sync used", + "#922 β€” import label said \"Deezer\" for Spotify Free users (now reads \"Spotify\"); #918 β€” iTunes albums over 50 tracks self-heal from a stale 50-track cache", ], }, { - title: "Earlier in 2.7.6 / 2.7.5", - description: "2.7.6 went the OTHER way with playlists β€” exporting them TO listenbrainz (#903) β€” plus youtube liked-music sync (#902), a deep-scan data-loss guard (#904), and dashboard perf. before that, 2.7.5 was a fix-heavy cycle β€” matching & artwork accuracy plus a few quality-of-life features.", + title: "Earlier in 2.7.7 / 2.7.6 / 2.7.5", + description: "2.7.7 was fix-heavy (downloads tag + path right the first time #915, the listening-recs foundation #913, a big reported-issue sweep). 2.7.6 exported playlists TO listenbrainz (#903) + youtube liked-music sync (#902); 2.7.5 was matching & artwork accuracy plus quality-of-life features.", features: [ - "special-edition cover art (a \"Gustave Edition\" uses its OWN cover), deezer track numbers, and the \"The\" duplicate fix", - "HiFi 30-second previews disguised as full songs are caught and rejected (#895)", - "import M3U / M3U8 playlists (#893), name files inside playlist folders, find & add remembered, ignore-list management (#897), Unraid template fixes (#899)", + "#915 β€” post-processing + redownload pull the full album from your PRIMARY metadata source, so $year / release date / album type land right the first time", + "HiFi 30-second previews disguised as full songs are caught and rejected (#895); special-edition cover art, deezer track numbers, the \"The\" duplicate fix", + "import M3U / M3U8 playlists (#893), ignore-list management (#897), Unraid template fixes (#899), and the rest of the #905–#918 batch", ], }, {