feat(network): request-throttle controls to avoid YouTube rate-limiting

Re-implements the sleepRequests/sleepInterval/maxSleepInterval feature
(--sleep-requests / --sleep-interval / --max-sleep-interval) from the
stale feat/binary-management-and-library-scale branch, ported onto
current main's structure (zod settingsSchema, decomposed NetworkCard).
All default to 0/off, preserving current behaviour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 16:34:34 -04:00
parent 61d5261e33
commit 5c88d9c8e0
7 changed files with 146 additions and 0 deletions
@@ -17,6 +17,9 @@ export function NetworkCard(): React.JSX.Element {
const styles = useSettingsStyles()
const proxy = useSettings((s) => s.proxy)
const rateLimit = useSettings((s) => s.rateLimit)
const sleepRequests = useSettings((s) => s.sleepRequests)
const sleepInterval = useSettings((s) => s.sleepInterval)
const maxSleepInterval = useSettings((s) => s.maxSleepInterval)
const useAria2c = useSettings((s) => s.useAria2c)
const aria2cConnections = useSettings((s) => s.aria2cConnections)
const youtubePlayerClient = useSettings((s) => s.youtubePlayerClient)
@@ -56,6 +59,58 @@ export function NetworkCard(): React.JSX.Element {
/>
</Field>
<Field
label="Pause between requests"
hint="Seconds yt-dlp waits between requests (--sleep-requests). The key setting for downloading a whole channel without YouTube rate-limiting you (the &quot;unavailable, try again later&quot; / 403 errors). Try 2-5s for large channels. 0 = off."
>
<SpinButton
value={sleepRequests}
min={0}
max={300}
onChange={(_, d) => {
const v = d.value ?? Number(d.displayValue)
if (typeof v === 'number' && Number.isFinite(v)) {
update({ sleepRequests: Math.min(300, Math.max(0, Math.round(v))) })
}
}}
/>
</Field>
<Field
label="Pause before each download (min)"
hint="Minimum seconds to wait before starting each download (--sleep-interval). Combined with the max below, yt-dlp waits a random amount in that range. 0 = off."
>
<SpinButton
value={sleepInterval}
min={0}
max={300}
onChange={(_, d) => {
const v = d.value ?? Number(d.displayValue)
if (typeof v === 'number' && Number.isFinite(v)) {
update({ sleepInterval: Math.min(300, Math.max(0, Math.round(v))) })
}
}}
/>
</Field>
<Field
label="Pause before each download (max)"
hint="Maximum seconds for the random pre-download pause (--max-sleep-interval). Only used when it's set above the minimum above; otherwise the minimum is used as a fixed pause."
>
<SpinButton
value={maxSleepInterval}
min={0}
max={300}
disabled={sleepInterval <= 0}
onChange={(_, d) => {
const v = d.value ?? Number(d.displayValue)
if (typeof v === 'number' && Number.isFinite(v)) {
update({ maxSleepInterval: Math.min(300, Math.max(0, Math.round(v))) })
}
}}
/>
</Field>
<Field
label="Use aria2c downloader"
hint="Multi-connection downloads for faster speeds on supported sites. Falls back to the standard downloader if the accelerator isn't available."