Skip to content

Add per-provider fallback threshold for download services - #3

Open
Gabriel-Lewis wants to merge 1 commit into
feat/lidarrfrom
feat/provider-fallback
Open

Add per-provider fallback threshold for download services#3
Gabriel-Lewis wants to merge 1 commit into
feat/lidarrfrom
feat/provider-fallback

Conversation

@Gabriel-Lewis

Copy link
Copy Markdown
Owner

Stacked on #2 (Lidarr) — base is feat/lidarr, so this PR shows only its own diff.

The gap

DOWNLOAD_SERVICES is already an ordered priority list (sample.env has said so all along), and StartDownload already skips tracks an earlier provider resolved:

for _, d := range c.Downloaders {
    for _, track := range *tracks {
        if track.Present { continue }

So ordering and "only try what is still missing" work today. What was missing is a time budget. MonitorDownloads only returns once tracksProcessed() reports every track Present or Skipped, and the per-track MonitorDuration stall timer resets on any byte of progress — so a provider making slow progress holds the entire run and the next service never gets a turn.

The change

MonitorConfig gains FallbackAfter, sourced per provider from SLSKD_FALLBACK_AFTER / LIDARR_FALLBACK_AFTER (minutes, default 0 = disabled, so existing setups behave exactly as before). When the budget elapses, MonitorDownloads abandons the unresolved tracks and returns; the existing track.Present skip logic hands them to the next provider.

Abandoning calls Cleanup on each unresolved track so the provider stops downloading in the background once we have moved on — Lidarr.Cleanup DELETEs the queue item with removeFromClient=true, Slskd.Cleanup removes the search and transfer. Without that, giving up would leave orphaned downloads running.

YouTube is untouched: it is synchronous and its GetConf() already returns an error signalling no monitoring.

Worked example

DOWNLOAD_SERVICES=lidarr,slskd
LIDARR_FALLBACK_AFTER=15
SLSKD_FALLBACK_AFTER=10

Tier 0 remains the existing library check (CheckTracks), which already skips anything Plex/Jellyfin/etc. already has — so the full chain is: already in library → Lidarr full albums → slskd.

Verified

  • go build ./src/main/ and go vet ./src/downloader/ ./src/config/ — both clean.
  • gofmt: no new unformatted files; the one flagged line in slskd.go sits inside a struct literal that was already misaligned upstream, and matches its neighbours.
  • 66 insertions, no deletions — purely additive.

Not exercised against a live Lidarr/slskd run; the runtime check is described below.

How to test

Set LIDARR_FALLBACK_AFTER=1 to force the path quickly, run, and confirm:

  • [monitor] fallback threshold reached, moving on to the next download service service=Lidarr
  • slskd then attempts the same tracks
  • Lidarr's queue no longer holds the abandoned items (proves Cleanup fired)

DOWNLOAD_SERVICES is already documented as an ordered priority list, and
StartDownload already skips tracks an earlier provider resolved:

    for _, d := range c.Downloaders {
        for _, track := range *tracks {
            if track.Present { continue }

What was missing is a time budget. MonitorDownloads only returns once
tracksProcessed() reports every track Present or Skipped, and the
per-track MonitorDuration stall timer resets on any byte of progress. A
provider that keeps making slow progress therefore holds the whole run,
and the next service never gets a turn.

Add MonitorConfig.FallbackAfter, sourced per provider from
SLSKD_FALLBACK_AFTER / LIDARR_FALLBACK_AFTER (minutes, default 0 =
disabled, preserving current behaviour). When the budget elapses,
MonitorDownloads abandons the still-unresolved tracks and returns, and
the existing track.Present skip logic hands them to the next provider.

Abandoning calls Cleanup on each unresolved track so the provider stops
downloading in the background once we have moved on -- Lidarr.Cleanup
DELETEs the queue item with removeFromClient=true, and Slskd.Cleanup
removes the search and transfer. Without this, giving up on a provider
would leave orphaned downloads running.

This makes chains like the following work as intended -- prefer full
albums from Lidarr, fall back to slskd for whatever it has not delivered:

    DOWNLOAD_SERVICES=lidarr,slskd
    LIDARR_FALLBACK_AFTER=15
    SLSKD_FALLBACK_AFTER=10

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ZuEbqv1CGbPub9kB3g2s4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant