Commit Graph
704 Commits
Author SHA1 Message Date
HoneyandClaude Sonnet 4.6 252d2d3071 feat: download playlist tracks in parallel batches (MAX_PARALLEL)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 18:03:29 +02:00
HoneyandClaude Sonnet 4.6 c1a740240a fix: normalize diacritics in playlist artist matching
Use Unicode property escapes to strip only symbols (☆, !, etc.)
while keeping Unicode letters (ø, ä, é) — fixes "Kløn" becoming
"Kln" instead of staying "Kløn" in the search query.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 17:54:50 +02:00
HoneyandClaude Sonnet 4.6 afcbf81547 fix: strip parens from keywords, top-10 search, clean search query
- buildTitleKeywords: strip parenthetical tags before picking words so
  "Eleven Night (Jersey Club)" → keywords ["Eleven","Night"] instead of
  ["Eleven","Jersey"] — "Jersey" was never in the YT video title
- Cascade: add top-10 steps (3+4) with duration still active before
  dropping duration filter, so "Whispers" (position 6-10) can be found
  without falling through to the unfiltered last resort
- search query: strip non-ASCII chars from artist name so "☆NoAki☆"
  becomes "NoAki" in the query → cleaner YTM search ranking

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:49:53 +02:00
HoneyandClaude Sonnet 4.6 51d2ea257f fix: use top-2 title keywords for precise match-filter
Single-word filter was too loose: "Echoes of Eternity" produced only
"Eternity" which matched unrelated tracks. Now the top 2 longest words
are used so the filter becomes e.g.
  title ~= (?i)Eternity & title ~= (?i)Echoes?
  title ~= (?i)Amethyst & title ~= (?i)Flowers?
Both words must appear — drastically reduces false matches.
Trailing-s stays optional (Whispers? matches Whisper/Whispers).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:10:05 +02:00
HoneyandClaude Sonnet 4.6 5e7e700d6a fix: rewrite _createNdPlaylist to remove problematic Unicode regex
The normD regex used actual Unicode combining chars (U+0300-U+036F)
in the source which some build tools mangle, causing a SyntaxError at
runtime and silently killing playlist creation. Replaced with normA
that strips non-word/non-space chars via plain ASCII regex, which is
safe and achieves the same loose artist-first-word comparison.
Also fixed race condition in _pollAndCreatePlaylist — save lastStatus
before job is auto-deleted so the done check still works.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:07:26 +02:00
HoneyandClaude Sonnet 4.6 2d1c9029c5 fix: add YTM 'Songs only' filter param to search URL
Without &params=EgWKAQII..., yt-dlp gets a mixed feed of videos,
channels and playlists alongside tracks — same query that shows the
correct song first in the browser "Titel" tab returned nursery rhyme
videos and unrelated channels. This param is YTM's internal 'Songs'
filter (equivalent to clicking the Titel tab).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 15:38:35 +02:00
HoneyandClaude Sonnet 4.6 fed3df7e36 fix: normalize diacritics in playlist artist matching
normD strips accents/special chars before comparing artist first-word
so "Kløn" (iTunes) matches "Klon" (embedded tag) → "klon" === "klon"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 15:33:01 +02:00
HoneyandClaude Sonnet 4.6 971cadd8fa fix: match-filter trailing-s optional + playlist search fallback for special chars
- buildTitleKeywords: append '?' to keywords ending in 's' so regex
  "Whispers?" matches both "Whisper" (YouTube title) and "Whispers"
  (iTunes title) — fixes NoAki Whispers downloading wrong track
- _createNdPlaylist: if artist+title search returns no title match,
  retry with title-only query so tracks with special chars in artist
  name (e.g. "Kløn") are still found in Navidrome

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 14:57:51 +02:00
HoneyandClaude Sonnet 4.6 0a7591a690 fix: remove artist filter + fix playlist scan timing
backend: drop unreliable artist *= filter entirely — yt-dlp artist field
is empty for many label-distributed YTM tracks (NoAki, etc.), causing
correct results to be rejected in Steps 1-2 and falling through to Step 3
anyway. Search query already targets the right artist; title keyword +
duration are sufficient. Simplifies cascade from 8→8 steps but with fewer
wasted filter attempts.

frontend: add 3s delay before polling getScanStatus (gives Navidrome time
to actually start the scan), and 5s buffer after scan completes (lets DB
writes settle). Fallback to 30s fixed wait if scan API is unavailable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 14:15:09 +02:00
HoneyandClaude Sonnet 4.6 7a0a7ca455 fix: case-insensitive title filter + scan before playlist creation
backend: replace title *= (case-sensitive) with title ~= (?i) regex so
"MEMORIES" and "Echoes of Eternity" match regardless of YT title casing.
Refactor buildTitleKeyword → buildTitleKeywords returning array.

frontend: trigger Navidrome startScan after download completes and wait
for scan to finish before running _createNdPlaylist, so newly downloaded
tracks are indexed and searchable when the playlist is built.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 13:40:20 +02:00
HoneyandClaude Sonnet 4.6 42658b3cbf fix(backend): improve yt-dlp match filters for accuracy
- artistFilterWord: use longest \w+ run instead of stripping special chars,
  fixes artists like N!GHT where stripping gave NGHT (not a substring)
- buildTitleKeyword: new fn extracts most distinctive title word, added as
  title *= filter to all cascade steps to block unrelated fallback downloads
- Mix version specificity: Radio/Extended/Club Mix titles also filter on the
  qualifier word so plain versions are rejected
- Switch uploader *= to artist *= so label-uploaded tracks (Monstercat etc.)
  match by music metadata artist tag, not channel name

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 12:46:20 +02:00
HoneyandClaude Sonnet 4.6 10a85e0497 fix(ui): playlist match - use first artist only, strip punctuation, increase songCount
"Kløn, Renzyx" → search with "Kløn Alone", compare "kløn" == "kløn" (not "kløn,")
songCount raised to 20 so generic titles like "Alone" have better recall.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 12:35:19 +02:00
HoneyandClaude Sonnet 4.6 9ca6e79b7b fix(backend): treat yt-dlp exit code 101 as success
Code 101 means --max-downloads was reached — the file was downloaded
successfully. Treating it as error caused the ffmpeg/metadata step to
be skipped, leaving files with no tags.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 12:12:32 +02:00
HoneyandClaude Sonnet 4.6 5db9938f49 fix(backend): scan top 5 results per search instead of only item 1
--playlist-items 1-5 --max-downloads 1 on all filtered steps so yt-dlp
skips non-matching results (wrong artist, sped up, wrong duration) and
lands on the first result that actually passes all active filters.
Unfiltered last-resort fallbacks keep --playlist-items 1.
YouTube fallback uses ytsearch5: to match the 5-result window.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 12:00:49 +02:00
HoneyandClaude Sonnet 4.6 cf8ba70af8 fix(ui): playlist search with artist+title, artist in missing list, no bounce on job cards
- Playlist track search: use 'Artist Title' query + songCount=10 (was title-only + 5)
  fixes songs like 'Dead' by Geoxor being missed due to common-word collision
- Missing tracks now show 'Artist – Title' instead of just title
- renderJobs: update existing cards instead of full innerHTML wipe every 1.5s
  eliminates slideUp animation re-triggering on every poll tick

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 11:56:17 +02:00
HoneyandClaude Sonnet 4.6 4b6095f213 fix(backend): fix hasAudio() race condition for parallel downloads
Snapshot dir before each yt-dlp call so hasAudio() only detects
files added by the current attempt, not pre-existing files from
parallel jobs downloading to the same album directory.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 11:29:00 +02:00
HoneyandClaude Sonnet 4.6 016a231174 fix(backend): stricter duration filter + variant title filter
- Duration: ±15% (min 15s) instead of -40%/+50%
- Variant filter: reject sped/speedup/slowed/reverb/nightcore/karaoke/
  parody/remix/cover/acoustic/instrumental unless original title has keyword
- Cascade: YTM+YT tried at each level (dur+artist+variant → no artist → no dur → no filter)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 11:26:04 +02:00
HoneyandClaude Sonnet 4.6 34afeb77ba fix(backend): add uploader/artist filter to yt-dlp match-filter
Strips special chars from artist name (☆NoAki☆ → NoAki) and adds
uploader *= check so wrong-artist results are rejected early.
Falls back to duration-only, then no-filter if artist filter yields nothing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 10:53:32 +02:00
HoneyandClaude Sonnet 4.6 801a3ae0fd fix(backend): fix fallback order — try YT with duration filter before dropping filter
Previous order let wrong YTM results through on the no-filter fallback.
New order: YTM+filter → YT+filter → YTM no filter → YT no filter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 10:32:10 +02:00
HoneyandClaude Sonnet 4.6 ce8441d9ee fix(backend): use YouTube Music search URL instead of invalid ytmsearch1: prefix
ytmsearch1: is not a valid yt-dlp scheme — use full music.youtube.com URL with --playlist-items 1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 10:12:46 +02:00
HoneyandClaude Sonnet 4.6 49a00b673b fix(backend): use YouTube Music as primary search source for better track matching
Falls back to plain YouTube if no match found on YT Music.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 10:08:28 +02:00
Honey dcb685bc4d feat(theme): add jade-green theme 2026-04-29 00:22:57 +02:00
HoneyandClaude Sonnet 4.6 3988d18182 fix: drag-and-drop — use fromHandle bool instead of e.target check
e.target in dragstart is always the draggable item element, never the
handle child — so closest('.pl-drag-handle') always returned null and
every drag was cancelled. Now mousedown on handle sets fromHandle=true
and item.draggable=true; dragstart checks the bool instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 00:10:36 +02:00
HoneyandClaude Sonnet 4.6 ca6dd87531 fix: drag-and-drop — set draggable upfront, add Firefox setData, fix duplicate dragend
draggable=true must be set before any mouse event (not on mousedown).
Firefox requires setData() for drag to work. Removed duplicate dragend
listener that was resetting draggable=false and conflicting with the first.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:21:13 +02:00
HoneyandClaude Sonnet 4.6 33c0751db6 revert: remove official audio suffix — plain artist-title query only
official audio consistently breaks remixes and lesser-known artists.
Duration filter is the primary quality check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:16:22 +02:00
HoneyandClaude Sonnet 4.6 8deeaa6475 feat: drag-and-drop reordering for playlist tracks
Drag handle appears on hover, moves items in DOM, syncs order to
songs array, and saves to Navidrome via createPlaylist 800ms after
last drop (debounced to avoid rapid API calls).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:15:48 +02:00
HoneyandClaude Sonnet 4.6 ac5cbfb3de fix: save plModalSongs before closePlModal clears it
closePlModal() resets S.plModalSongs=[] before ids was computed,
so no songs were ever added to the playlist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:09:38 +02:00
HoneyandClaude Sonnet 4.6 8e13786e6b fix: remix detection — official audio for normal tracks, no suffix for remixes
Remix titles (remix/edit/flip/vip/etc.) are specific enough without suffix.
Normal tracks get 'official audio' to prefer audio over music videos.
Original official-audio issue was only for remixes — now caught by regex.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:08:26 +02:00
HoneyandClaude Sonnet 4.6 caa4cc1ef3 fix: remove all query suffix — rely on duration filter only
Adding 'audio' shifts results for lesser-known artists (Kanro, etc.).
Plain 'Artist - Title' matches what users find manually on YouTube.
Duration filter is the reliable quality check against wrong songs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 19:56:05 +02:00
HoneyandClaude Sonnet 4.6 dcdae19cec fix: smart query suffix — skip 'audio' for remixes/edits
Remixes already have '(Remix)' etc. in title so no suffix needed.
Normal tracks get 'audio' to filter piano covers and tutorials.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 19:20:35 +02:00
HoneyandClaude Sonnet 4.6 06c38cd427 fix: use 'audio' instead of 'official audio' in search query
'official audio' biased towards artist's main channel (wrong for remixes).
No suffix caused piano covers to rank top. 'audio' filters covers/tutorials
without over-specifying to official channels.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 19:15:21 +02:00
HoneyandClaude Sonnet 4.6 11e981215c fix: remove 'official audio' from yt-dlp search query
For remixes and edits, 'official audio' biases YouTube search towards the
artist's official channel (wrong song) instead of the specific version.
Duration filter is now the quality check — the plain query is more accurate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 19:06:08 +02:00
HoneyandClaude Sonnet 4.6 7461e44980 fix: revert to ytsearch1 with match-filter, avoid --max-downloads exit code issues
--max-downloads 1 exits with code 101 which varies by yt-dlp version — caused
ffmpeg to never run, leaving untagged files. Use ytsearch1: + --match-filter instead:
filters top result by duration, exits 0 in all cases, falls back cleanly if no match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 18:59:39 +02:00
HoneyandClaude Sonnet 4.6 03394cac68 fix: correct yt-dlp duration filter — handle exit code 101, remove --playlist-items from filtered search
--playlist-items 1 in baseArgs caused filter to only check result #1 (filter useless).
--max-downloads 1 exits with code 101 which we treated as an error — ffmpeg never ran,
leaving untagged files (→ Unknown Artist/Album in Navidrome). Now code 101 resolves
successfully and filtered search uses commonArgs without --playlist-items.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 18:55:01 +02:00
HoneyandClaude Sonnet 4.6 fb02d3faf4 feat: filter yt-dlp results by song duration to avoid wrong downloads
When iTunes/Spotify provides a track duration, search 5 YouTube results
and keep only those within 60–150% of the expected length (filters remixes,
prayer videos, etc.). Falls back to ytsearch1: if no match is found.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 18:48:00 +02:00
HoneyandClaude Sonnet 4.6 dccf8a5dab fix: use first artist only for folder path on multi-artist tracks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 18:40:53 +02:00
HoneyandClaude Sonnet 4.6 8e9521f889 revert: restore original yt-dlp search — remove broken ytmsearch/ytsearch5 changes
Reverts cc7fc80, 59562fe, 595fb2b, 626a755.
The new search logic caused wrong songs, [Unknown Album] folders and duplicate downloads.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 18:27:01 +02:00
HoneyandClaude Sonnet 4.6 626a755688 fix: suppress ytmsearch unsupported scheme error, clean up search log
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 18:22:56 +02:00
HoneyandClaude Sonnet 4.6 595fb2b7f3 fix: install yt-dlp via pip3 for latest version, fix multi-artist folder path
- Replace apk yt-dlp with pip3 install to get current version with ytmsearch support
- Split mainArtist on comma in downloadTrack so multi-artist tracks
  always land in the primary artist folder (e.g. "Artist1, Artist2" → Artist1/)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 18:18:27 +02:00
HoneyandClaude Sonnet 4.6 59562fe156 fix: use ytmsearch: instead of ytmsearch3: (unsupported by yt-dlp)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 18:12:50 +02:00
HoneyandClaude Sonnet 4.6 cc7fc80c71 fix: improve yt-dlp search reliability and artist folder structure
- Switch to YouTube Music search (ytmsearch3) as primary source with
  fallback to ytsearch5 if no result found
- Add duration filter (±30s/+45s) and live-stream exclusion via
  --match-filter when iTunes trackTimeMillis is available
- Send trackTimeMillis from frontend in download payload
- Pass durationMs through downloadTrack and downloadAlbumTracks
- Use first artist only (split on comma) for folder path on multi-artist tracks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 18:03:05 +02:00
HoneyandClaude Sonnet 4.6 2b1eff2762 fix: send track/disc numbers from iTunes to backend; backend reads them for single track downloads
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:28:39 +02:00
HoneyandClaude Sonnet 4.6 45b1eb2e44 fix: Rosé Pine theme updated with official color palette
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:26:13 +02:00
HoneyandClaude Sonnet 4.6 ca907278c7 feat: add Rosé Pine theme
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:21:41 +02:00
HoneyandClaude Sonnet 4.6 8a256b9463 feat: artist cards navigate-only (no play); add Top Songs + Shuffle buttons to artist detail page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:14:07 +02:00
HoneyandClaude Sonnet 4.6 a907773afb fix: artist link quotes in album detail; card art=play / info=navigate; artist play button via quickPlayArtist
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:03:53 +02:00
HoneyandClaude Sonnet 4.6 fdb5f16332 fix: remove dead Spotify credentials; backend URL falls back to NS_BACKEND_URL env on login and auto-login
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 13:31:23 +02:00
HoneyandClaude Sonnet 4.6 abe048c4ed fix: remove bell+settings from sidebar; preserve backend/api keys on re-login
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 13:28:37 +02:00
HoneyandClaude Sonnet 4.6 85290a54f6 fix: null-safe doConnect for removed setup fields; move logout to settings with confirm; clean sidebar buttons
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 13:24:27 +02:00
HoneyandClaude Sonnet 4.6 5a994e9564 feat: add Forest theme (dark green accent on deep forest bg)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 13:18:40 +02:00