Skip to content

Add slskd provider, Navidrome playlist sync, library paths, and queue UX#182

Open
dx616b wants to merge 59 commits into
henriquesebastiao:mainfrom
dx616b:feature/slskd-navidrome-library-sync
Open

Add slskd provider, Navidrome playlist sync, library paths, and queue UX#182
dx616b wants to merge 59 commits into
henriquesebastiao:mainfrom
dx616b:feature/slskd-navidrome-library-sync

Conversation

@dx616b

@dx616b dx616b commented May 28, 2026

Copy link
Copy Markdown

Summary

This PR adds optional Soulseek downloads via slskd, Navidrome playlist sync (Subsonic API), a global Spotify track index to skip re-downloads, improved library/M3U path handling for /downloads and /slskd, and a more usable download queue (filters, retry, playlist pruning).

Developed and tested in a fork (dx616b/downtify); happy to split into smaller PRs if preferred.

Note from contributor

I know this PR touches a lot of files. I built and tested it freehand in my own fork the way I actually run Downtify day to day—not as a stack of tiny theoretical PRs. The diff is large on purpose because the features (slskd paths, library catalog, Navidrome sync, queue UX, batch delete) grew together in real use. I am happy to refactor or split follow-ups if you prefer a different shape for upstream; this branch is my working “how I want it” snapshot.

Audio providers

  • Configurable provider order: slskdYouTube MusicYouTube
  • slskd: search, enqueue transfer, poll progress, timeouts, fallback to next provider
  • Optional leave slskd files in place under /slskd (no copy into /downloads)
  • yt-dlp search fallback when YouTube Music finds no match

Navidrome

  • After playlist downloads: library scan → match tracks → update existing playlist (avoid duplicates)
  • Optional admin credentials when the playlist owner is not an admin

Library & playlists

  • library_paths resolves slskd/… stored paths for player, M3U, and Navidrome matching
  • M3U uses absolute container paths (/downloads/…, /slskd/…)
  • Library browser and player use embedded tags; slskd media served under /media/slskd/…

Download queue (UI)

  • Status filters: in progress, downloading, waiting, done, failed
  • Per-track and bulk retry; clear completed; optional YouTube URL override on failures
  • New Spotify playlist clears done items, keeps failures/in-progress, then adds new tracks
  • Fix download to device save names (downloadSaveName() decodes URL-encoded filenames)

Docs & compose

  • README sections for slskd, Navidrome, M3U, and queue behavior
  • docker-compose.example.yml with /downloads, /slskd, and /data volumes

Test plan

  • Enable slskd in Settings, add to audio sources, download a track (success + timeout fallback)
  • Download a Spotify playlist with leave-in-place; confirm files under /slskd and M3U paths
  • Enable Navidrome sync; confirm scan + playlist update without duplicate playlists
  • Queue: filters, retry failed, new playlist drops completed rows
  • Library: download to device uses human-readable filename (spaces, not %20)
  • pytest (new tests for slskd, navidrome, library_paths, queue API, track index)

Made with Cursor

dx616b and others added 7 commits May 28, 2026 15:51
Route video-id resolution through the configured audio_providers order and add robust YouTube/YouTube Music fallback matching so UI provider selection is applied consistently at runtime.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add slskd provider with leave-in-place, track dedupe, and timeouts; fix
library/M3U path resolution for /slskd mounts; sync Navidrome playlists
in place after incremental scan; improve matching and YouTube fallback.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add slskd/Navidrome configuration guide, docker-compose.example.yml for
dx616b/spoti-to-navidrome:2.7.7, and compose quick-start in the README.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add status filters and per-track or bulk retry on the queue page, clear
completed jobs, and drop finished tracks when a new Spotify playlist starts
while keeping failures and in-progress work.

Co-authored-by: Cursor <cursoragent@cursor.com>
Bump version and refresh production dist for Docker image publish.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use downloadSaveName() so queue and library saves use real filenames
instead of URL-encoded path segments from /media/ URLs.

Co-authored-by: Cursor <cursoragent@cursor.com>
Point docker-compose.example and README quick-start at ghcr.io instead
of fork-specific publish tags.

Co-authored-by: Cursor <cursoragent@cursor.com>
@dx616b dx616b requested a review from henriquesebastiao as a code owner May 28, 2026 18:30
@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file docker Pull requests that update docker code backend frontend translation download monitor tests labels May 28, 2026
dx616b and others added 13 commits May 28, 2026 21:57
Keep jobs queued until a parallel slot is acquired; simplify queue
filters and audio-source hint copy.

Co-authored-by: Cursor <cursoragent@cursor.com>
In progress covers active work (provider search and download); Waiting
is only tracks not started yet. Show search progress in the UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
Allow up to max_parallel_downloads concurrent slskd search/enqueue
operations and wait for transfers outside the lock so playlist jobs
are not serialized on Soulseek.

Co-authored-by: Cursor <cursoragent@cursor.com>
Refresh slskd semaphore and downloader slskd_settings on max_parallel
save so the UI limit applies without a separate slskd settings save.

Co-authored-by: Cursor <cursoragent@cursor.com>
slskd caps concurrent Soulseek searches; high Downtify parallel mostly
queues or fails without faster transfers.

Co-authored-by: Cursor <cursoragent@cursor.com>
Settings path and cookies.txt upload fix age-restricted and sign-in
errors; env DOWNTIFY_COOKIES_* remains as fallback.

Co-authored-by: Cursor <cursoragent@cursor.com>
FastAPI multipart routes require this package at import time.

Co-authored-by: Cursor <cursoragent@cursor.com>
When cookies are configured, prefer the main YouTube URL and web player
client; fall back from music.youtube.com on age-restriction errors.

Co-authored-by: Cursor <cursoragent@cursor.com>
Broadcast provider over WebSocket, keep progress text when work starts,
and label YouTube Music / YouTube steps like slskd.

Co-authored-by: Cursor <cursoragent@cursor.com>
Wire PO tokens into extractor args and fall back through broader audio
format chains before failing a YouTube download.

Co-authored-by: Cursor <cursoragent@cursor.com>
…dio.

Cookies force web clients that often return SABR-only/image formats; fall
back to ios/android without cookies. Use web_safari for cookie profile only.

Co-authored-by: Cursor <cursoragent@cursor.com>
When multiple matching files exist for one query, enqueue and wait on each
in order until one completes or download_attempts is exhausted.

Co-authored-by: Cursor <cursoragent@cursor.com>
Validate login cookies on upload/settings, drop web_creator for cookie
clients, retry up to five ytsearch results when age-gate or format fails,
and surface weak-cookie warnings in Settings.

Co-authored-by: Cursor <cursoragent@cursor.com>
dx616b and others added 2 commits June 3, 2026 01:31
Refresh M3U and Navidrome when deleting from Library; fix
invalidate_library_paths_cache imports; prune stale rows and always
invalidate path cache on reconcile.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop docker-hub-fork workflow, docker-compose.dockerhub.yml, and
docker-push script; keep fork image publishing local/manual only.

Co-authored-by: Cursor <cursoragent@cursor.com>
@henriquesebastiao henriquesebastiao linked an issue Jun 2, 2026 that may be closed by this pull request
1 task
@henriquesebastiao henriquesebastiao self-requested a review June 3, 2026 10:01
dx616b and others added 2 commits June 3, 2026 13:07
Library UI supports multi-select track delete and full playlist delete
with shared backend cleanup. Skip Navidrome library scan after deletes
and reconcile; sync playlists via API only. Validate Navidrome rows by
comparing Spotify playlist metadata to mutagen file tags instead of
filename parsing. Fix queue polling stuck state and rebuild frontend dist.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@dx616b

dx616b commented Jun 3, 2026

Copy link
Copy Markdown
Author

Hi — quick note on the size of this PR.

I know there are a lot of changes here. I built and tested everything freehand in my fork (dx616b/downtify) the way I actually use Downtify day to day, not as a chain of small theoretical PRs. The diff is large on purpose: slskd paths, library catalog, Navidrome sync, queue UX, batch delete, and related fixes grew together in real use.

This branch is my working “how I would like it” snapshot. Happy to refactor or split follow-ups if you prefer a different shape for upstream.

@henriquesebastiao

Copy link
Copy Markdown
Owner

Hi @dx616b! I don't see a problem with the size of the PR, and thank you very much for your contribution. It's great that you're testing everything manually; I think that's very important. I'll also manually test the new features as soon as possible; I've already verified that the existing features in Downtify continue to work perfectly. Due to my other activities, I don't think I'll be able to test everything today, but I want to test it by Sunday. As for the changes, we can keep them in this single PR.

@dx616b

dx616b commented Jun 3, 2026

Copy link
Copy Markdown
Author

Hi @dx616b! I don't see a problem with the size of the PR, and thank you very much for your contribution. It's great that you're testing everything manually; I think that's very important. I'll also manually test the new features as soon as possible; I've already verified that the existing features in Downtify continue to work perfectly. Due to my other activities, I don't think I'll be able to test everything today, but I want to test it by Sunday. As for the changes, we can keep them in this single PR.

Hi, it's my pleasure. It's such a great app. Ok then I will push one or two small fixes regarding logs and quality of slskd findings.

dx616b and others added 14 commits June 4, 2026 12:13
- Add shared DownloadParallelLimiter so settings changes do not reset in-flight slots
- Register batch tracks with playlist context; raise NoAudioMatchError when YouTube is exhausted
- Add track_tag_match for mix-variant last resort, probe-based verify, and duration tolerance
- Align strict duration caps; slskd holds semaphore through transfer and fixes mix import
- Default download_attempts to 5 and ffmpeg threads to 4
- SQLite WAL helpers, library cache/index fixes, Navidrome and catalog updates
- Player/Downloads UI: bulk delete, autoplay, queue progress, mobile layout and safe areas
- Tests for download pool, track tag match, downloader, and slskd responses

Co-authored-by: Cursor <cursoragent@cursor.com>
- Auto-fix import order and unused imports; noqa PLR0914 on heavy download paths
- Add Path import and named discard helper in slskd test
- Format Downloads.vue and Player.vue for prettier_action

Co-authored-by: Cursor <cursoragent@cursor.com>
…nloads.

Spotify playlist URLs open in search with correct Open on Spotify links; navbar search and a clean compact bar replace in-field action circles. Player queue and playlist filter persist across routes; M3U/Navidrome playlists refresh when retries succeed. Local make run builds and serves frontend/dist from the repo.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
In-progress tab now includes queued tracks so a new playlist batch is not hidden behind stale failures; retry Spotify embed fetches on transient HTTP errors with quieter reconcile logging.

Co-authored-by: Cursor <cursoragent@cursor.com>
Share live/karaoke/spam checks via remote_text_unacceptable for YouTube,
yt-dlp, and slskd; default duration tolerance to 15%; persist missing
settings keys to settings.json on load; fix queue tab on new downloads.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Stop auto-switching to Failed after playlist prune leaves only old
failures; switch to In progress when pending work is added instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
Make queue item updates reactive, re-queue existing failed tracks on batch
submit, sync from server after batch POST, and show waiting tracks under
In progress so the tab populates immediately.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep reactive queue updates but switch to Waiting when a new batch
queues tracks, and to In progress when downloads actually start.

Co-authored-by: Cursor <cursoragent@cursor.com>
Stay on In progress when new work is queued; show a hint when that tab
is empty but tracks are waiting on the Waiting tab.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Destructure downloadQueue for proper Vue reactivity, bump queueVersion on
changes, poll while the queue view is open, and sync after batch queueing.

Co-authored-by: Cursor <cursoragent@cursor.com>
Track playlist batches against cached Spotify metadata, surface incomplete playlists on Search with delete/download-missing actions, allow Extended Mix YouTube matches when duration fits, and poll in-progress rows every 5s so counts update during queue runs.

Co-authored-by: Cursor <cursoragent@cursor.com>
@dx616b

dx616b commented Jun 6, 2026

Copy link
Copy Markdown
Author

Hey, I think i have done whatever i had in mind as addition to this app (which fulfills what I thought would make this more complete). Hopefully i have not drifted much from your initial idea.

@BigBrownMF69

BigBrownMF69 commented Jun 7, 2026

Copy link
Copy Markdown

I freaking love u guys. As a broke college student lol, Downtify has been so amazing for me. Everything's been great, truly. Only things I wish I could enable is deleteing songs that also get dropped from the Spotify album. I discovered and used an open source de-duplicator website (spotify-dedup) earlier today and found around 700-1000 duplicate songs between all my playlists that I track😭😭. Even with 8 parallel downloads, took several days of downloading to get all my songs done but after I discovered the deduplicator and removed sooo many duplicate songs that got abandonded (not in playlist but file still exists downloaded on the drive) I will most likely have to delete everything and redownload the playlists since there were so many duplicates spread out across so many different albums. I understand that is on me though to not have checked my albums before adding them to downtify to be watched. Additionally, soulseek network does seem to have better quality going up and well above 320kbs and better artwork resolution (current downloads are all 300*300px which does look blurry on a lot of phones nowadays with big screens (aka typical pro/plus/ultra model iphones/androids). Occasionally ytmusic does download the wrong song files for certain songs so even with the correct spotify name and artists for a song, the song file itself will be off.

  • De-duplicator support (downtify deletes untracked songs or connects with an open source deduplicator by chance, or the above mentioned Mavidrome playlist checker option by chance?)
  • Artwork quality option/integration with MusicPicard for 500*500px quality album cover updating?
  • SoulSeek network compatibility for high res audio and more accurate file downloading? --> This would introduce the problem of the file naming not being uniform across all downloads, but MusicPicard could fix this and be run to output according to Downtify's preferred file and folder formatting after all initial downloads are done so that Downtify can see and recognize the same file and does not redownload it.
  • I recently found that Music Picard can run on docker and would love to give it a try.

Unfortunately I'm still very new to self-hosting, linux, dockers, github and all that so it takes me a long time between troubleshooting, online guides, forums, etc. to figure out how to get stuff up and running even with ZimaOS (Downtify being in the app store was an absolute godsend, thank you so much for that!) But I do not want to give up. Frankly I have spent half a month of all nighters/days of my summer break now messing around with my "server" and should've given up a long time ago but I refuse to and will continue and will keep trying to figure out the problems. Also I apologize if this comes off as rude or demanding in any way possible😭 I truly have no intention of that, I'm just fairly bad at wording out the thoughts in my head. I also am still unfamiliar with all the github terminology and how to use and navigate this website so I'm not fully sure if this is the correct forum/channel to post this in. I truly love this project and love u guys and the team for putting in the work that has gone into Downtify to make it as awesome as it is and helping us newbies get away from spotify and learn about selfhosting. I also want to help in anyway possible if I can. I'm not a cs major unfortunately so don't know much about coding and software outside of chatgpt. But I do have a chat gpt plus plan split between a couple other friends if you need help with iterating and stuff with chat but the daily limits get in the way please let me know and I can help. I am a Mechanical engineering major so can do 3d modelling, CAD, 3d printing, matlab, and similar stuff, which is probably not so helpful when it comes to making software, but if there is anything like that I can help with in that aspect, please let me know and I'll gladly help! I also have decent experience and troubleshooting knowledge about windows and macOS, but I'm guessing everyone on the team probably already has that too lol, but if there are ways I can help, do testing, feedback, hunt for bugs, help with UI, mess around with how it behaves on zimaOS (still a version of linux I think), reacts to changes, etc. please let me know! I also tried to find a discord and couldn't on the downtify website or on the gitbuh here and was wondering if there was a way to connect with the downtify community to help one another get it up and going, help with file pathing, to answer q/a's, or provide feedback that way? Thank you again!

@dx616b

dx616b commented Jun 7, 2026

Copy link
Copy Markdown
Author

I freaking love u guys. As a broke college student lol, Downtify has been so amazing for me. Everything's been great, truly. Only things I wish I could enable is deleteing songs that also get dropped from the Spotify album. I discovered and used an open source de-duplicator website (spotify-dedup) earlier today and found around 700-1000 duplicate songs between all my playlists that I track😭😭. Even with 8 parallel downloads, took several days of downloading to get all my songs done but after I discovered the deduplicator and removed sooo many duplicate songs that got abandonded (not in playlist but file still exists downloaded on the drive) I will most likely have to delete everything and redownload the playlists since there were so many duplicates spread out across so many different albums. I understand that is on me though to not have checked my albums before adding them to downtify to be watched. Additionally, soulseek network does seem to have better quality going up and well above 320kbs and better artwork resolution (current downloads are all 300*300px which does look blurry on a lot of phones nowadays with big screens (aka typical pro/plus/ultra model iphones/androids). Occasionally ytmusic does download the wrong song files for certain songs so even with the correct spotify name and artists for a song, the song file itself will be off.

  • De-duplicator support (downtify deletes untracked songs or connects with an open source deduplicator by chance, or the above mentioned Mavidrome playlist checker option by chance?)
  • Artwork quality option/integration with MusicPicard for 500*500px quality album cover updating?
  • SoulSeek network compatibility for high res audio and more accurate file downloading? --> This would introduce the problem of the file naming not being uniform across all downloads, but MusicPicard could fix this and be run to output according to Downtify's preferred file and folder formatting after all initial downloads are done so that Downtify can see and recognize the same file and does not redownload it.
  • I recently found that Music Picard can run on docker and would love to give it a try.

Unfortunately I'm still very new to self-hosting, linux, dockers, github and all that so it takes me a long time between troubleshooting, online guides, forums, etc. to figure out how to get stuff up and running even with ZimaOS (Downtify being in the app store was an absolute godsend, thank you so much for that!) But I do not want to give up. Frankly I have spent half a month of all nighters/days of my summer break now messing around with my "server" and should've given up a long time ago but I refuse to and will continue and will keep trying to figure out the problems. Also I apologize if this comes off as rude or demanding in any way possible😭 I truly have no intention of that, I'm just fairly bad at wording out the thoughts in my head. I also am still unfamiliar with all the github terminology and how to use and navigate this website so I'm not fully sure if this is the correct forum/channel to post this in. I truly love this project and love u guys and the team for putting in the work that has gone into Downtify to make it as awesome as it is and helping us newbies get away from spotify and learn about selfhosting. I also want to help in anyway possible if I can. I'm not a cs major unfortunately so don't know much about coding and software outside of chatgpt. But I do have a chat gpt plus plan split between a couple other friends if you need help with iterating and stuff with chat but the daily limits get in the way please let me know and I can help. I am a Mechanical engineering major so can do 3d modelling, CAD, 3d printing, matlab, and similar stuff, which is probably not so helpful when it comes to making software, but if there is anything like that I can help with in that aspect, please let me know and I'll gladly help! I also have decent experience and troubleshooting knowledge about windows and macOS, but I'm guessing everyone on the team probably already has that too lol, but if there are ways I can help, do testing, feedback, hunt for bugs, help with UI, mess around with how it behaves on zimaOS (still a version of linux I think), reacts to changes, etc. please let me know! I also tried to find a discord and couldn't on the downtify website or on the gitbuh here and was wondering if there was a way to connect with the downtify community to help one another get it up and going, help with file pathing, to answer q/a's, or provide feedback that way? Thank you again!

on this PR you will not re-download the same tracks, but just point them to different playlists. Soulseek is supported with good filtering. give it a try using this image: dx616b/spoti-to-navidrome:latest which is the one from my fork (this PR)

@BigBrownMF69

BigBrownMF69 commented Jun 7, 2026

Copy link
Copy Markdown

Thank you for your reply! Sorry for the basic questions, but what is a PR and where could I find the docker version for this one? I'd love to download it and give it a try but I mainly have experience with easier Zima OS app store 1 click installs and not too familiar with github yet.

Edit: I kept trying and got it running at one point but the docker app for it would simply keep refusing to work with Zima OS on the homepage of all the containers running, even had issues with portainer. it would show up as an option for a sec but then keep hitting "Failed to pull image: repository does not exist" error.

image

dx616b and others added 2 commits June 8, 2026 16:27
Auto-remove wrong on-disk audio during playlist refresh and Navidrome sync
when embedded tags disagree with Spotify. Rebuild the full playlist catalog
from library on partial batches so M3U/Navidrome stay complete.

Co-authored-by: Cursor <cursoragent@cursor.com>
Document slskd/Navidrome catalog work, tag-mismatch cleanup, queue/player
improvements, and dx616b/spoti-to-navidrome as the fork quick-start image.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend ci dependencies Pull requests that update a dependency file docker Pull requests that update docker code documentation Improvements or additions to documentation download frontend monitor tests translation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

connect slskd to Downtify

3 participants