fix: refresh stale provider download links on retry - #1006
Merged
rogerfar merged 1 commit intoJul 9, 2026
Conversation
rogerfar
approved these changes
Jul 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a download retry loop where Aria2 repeatedly fails with HTTP 403 because rdt-client keeps reusing an expired provider CDN signed URL stored in
Download.Path.When a download fails,
Reset()clearsLinkbut leavesPathunchanged. On the next attempt,UnrestrictLinkruns again against the same stalePath. For providers like Premiumize whereUnrestrict()is a no-op, nothing ever refreshes the URL — so the download retries forever (~1/sec) with the same dead link.This PR re-fetches download links from the provider via
GetDownloadInfos()whenRetryCount > 0, matches the correct file, updatesPath, and then proceeds with the normal unrestrict flow.How I found this
I initially suspected a long filename was causing torrents to hang. Example file:
Yakuza.Fiancé.Raise.wa.Tanin.ga.Ii.S01E05.Young.Lady.Tsubaki.1080p.B-Global.WEB-DL.JPN.AAC2.0.H.265.MSubs-ToonsHub.mkvThat turned out not to be the issue — the full download path was ~247 characters and the target folder created fine on
G:\tmp\sonarr\.The real symptom was different: the download would briefly appear in Aria2, then vanish, and the retry count climbed at ~1 per second (600+ and still going). Logs showed:
Aria2 error 22 is an HTTP failure; 403 Forbidden means the CDN rejected the request.
Ruling out other causes
I first wondered if this was an Aria2 User-Agent issue (CDN allowing browsers but blocking
aria2/1.x). That theory fell apart when I tested the exact URL rdt-client was using in a browser — it also returned 403.The breakthrough was comparing two URLs for the same file (I'm on Premiumize, not Real Debrid — the app name is legacy but the CDN behaviour is the same):
rdt-client stored link (403 in browser and Aria2):
https://3-cdn2-ovh-fra.energycdn.com/cdn3sto/sillyweasel-sto/6a43df2070da50.18300376/426800987/1782832942/321060974b14f09ec7ab5e75e8f0e4257b69d432/9667fb75a88e25ecc0ebe80729ae96462df3b47830bd8d0c6afbb8164d6b0c94/Yakuza.Fianc%C3%A9.Raise.wa.Tanin.ga.Ii.S01E05.Young.Lady.Tsubaki.1080p.B-Global.WEB-DL.JPN.AAC2.0.H.265.MSubs-ToonsHub.mkv
Fresh link from Premiumize website (downloads fine):
https://3-cdn2-ovh-fra.energycdn.com/cdn3sto/sillyweasel-sto/6a43df2070da50.18300376/426800987/1782932034/321060974b14f09ec7ab5e75e8f0e4257b69d432/4664658a67d9a451ed3c30405705af60790d28fbbf83233b0bfc7819d439680c/Yakuza.Fianc%C3%A9.Raise.wa.Tanin.ga.Ii.S01E05.Young.Lady.Tsubaki.1080p.B-Global.WEB-DL.JPN.AAC2.0.H.265.MSubs-ToonsHub.mkv
Same host, same file path — but different timestamp (
1782832942vs1782932034, ~27 hours apart) and different signature hash. The rdt-client URL was an older, expired signed CDN link.Retry Torrent worked as a workaround because it deletes and re-adds the torrent, which triggers a fresh
GetDownloadInfos()and stores new links.Root cause
Provider CDN URLs are time-limited signed links. When downloads are first created, rdt-client stores the provider link in
Download.Path(viaDownloadInfo.RestrictedLinkfromGetDownloadInfos()).On per-download retry,
TorrentRunnercallsReset()which clearsLinkbut does not updatePath. The nextUnrestrictLinkcall therefore uses the same expired URL.For Premiumize this is especially visible because
Unrestrict()is a no-op — it returns the link unchanged:So the retry loop never gets a fresh signature. Real Debrid and other providers can hit the same class of problem whenever
Pathalready holds a CDN URL that has expired andUnrestrictdoes not mint a new one.Why fix all providers, not just Premiumize
All debrid clients follow the same download lifecycle in rdt-client:
GetDownloadInfos()→ storeRestrictedLinkinDownload.PathUnrestrictLink()→ callIDebridClient.Unrestrict(Path)→ store result inDownload.LinkLinkReset()(clearsLink, keepsPath) → retryThe stale-
Pathproblem is in this shared flow, not in a single provider implementation. Refreshing fromGetDownloadInfos()on retry is provider-agnostic and safe: if the provider returns the same link, we skip the update; if it returns a fresh one, we use it.What this PR changes
DownloadLinkMatcher— matches aDownloadto aDownloadInfofrom a freshGetDownloadInfos()call by:Download.FileName)PathUpdatePath— new method on the downloads data/service layer to persist an updated restricted link.Torrents.UnrestrictLink— whenRetryCount > 0, callsTryRefreshDownloadPath()before unrestricting:Pathif a newer link is availableUnrestrict+UpdateUnrestrictedLinkflowUnit tests for
DownloadLinkMatcher(filename match, URL segment match with encoded Unicode, single-file fallback, multi-file no-match).Test plan
dotnet test server/RdtClient.Service.Test/RdtClient.Service.Test.csproj— 219 tests passedRetryCount == 0should not call refresh)