Skip to content

fix(ffmpeg): give the CF-bypass stream the same retry/resume as aiohttp (#169) - #172

Merged
Rushaway merged 2 commits into
masterfrom
fix/169-cf-bypass-retry-parity
Sep 6, 2026
Merged

fix(ffmpeg): give the CF-bypass stream the same retry/resume as aiohttp (#169)#172
Rushaway merged 2 commits into
masterfrom
fix/169-cf-bypass-retry-parity

Conversation

@Rushaway

@Rushaway Rushaway commented Sep 6, 2026

Copy link
Copy Markdown
Member

Summary

Split out of #150. _stream_url_to_ffmpeg has two transports and they gave different reliability guarantees by accident of structure:

curl_cffi path (needs_cf_bypass) aiohttp path
Retry none (before) 5 attempts
Resume after drop Range: bytes=N-
Backoff sleep(0.5)

So a transient blip killed playback outright on a Cloudflare-protected clip (MyInstants) while the same blip silently recovered on a normal URL.

Changes

The curl_cffi worker thread now mirrors the aiohttp path:

  • up to 5 attempts with time.sleep(0.5) backoff;
  • bytes_downloaded tracked across attempts; a retry sends Range: bytes=<n>- so a drop resumes mid-clip instead of restarting from zero and repeating audio;
  • if a ranged retry is answered with a plain 200 (server ignored Range), the already-fed prefix is skipped from the restarted body;
  • the curl_cffi response is now close()d on every path.

The queue hand-off is factored into enqueue_chunk(), which now cancels the pending queue.put future on its 0.5s timeout instead of leaving it to maybe fire later and double-feed a chunk (the busy-poll flagged in the issue).

What is and isn't verified

  • Retry / resume / skip state machine simulated against clean, mid-stream-drop (206 resume), ignored-Range (200 + skip) and connection-failure scenarios — all reconstruct the byte stream exactly.
  • ruff / mypy clean.
  • Not verified end to end. As called out in the issue, this needs a live voice server + a real Cloudflare-protected source. The 200+skip branch assumes the restarted body is byte-identical to the original.

The two transports are still deliberately separate (curl_cffi exists for TLS impersonation aiohttp can't do).

Merge order

Batch with #164, #169, #55; sequential VERSION patch bumps (this one -> 1.8.24). Needs a one-line VERSION rebase if it doesn't merge second.

Closes #169

🤖 Generated with Claude Code

…tp (#169)

`_stream_url_to_ffmpeg` has two transports. The aiohttp path retried up to 5
times and resumed from `bytes_downloaded` with a `Range` header; the curl_cffi
path (Cloudflare-protected sources, e.g. MyInstants) did a single request with
no retry, so a transient network blip killed playback outright on exactly the
clips that are hardest to fetch.

The worker thread now mirrors the aiohttp path:

- up to 5 attempts, `time.sleep(0.5)` backoff between them;
- `bytes_downloaded` is tracked across attempts and a retry sends
  `Range: bytes=<n>-`, so a drop resumes mid-clip instead of restarting from
  zero and repeating audio;
- if a ranged retry is answered with a plain `200` (server ignored `Range`),
  the already-fed prefix is skipped from the new stream;
- the response is now closed on every path.

The queue hand-off helper (`enqueue_chunk`) is factored out of the inline
`while` loop and cancels the pending `queue.put` future on a 0.5s timeout
rather than leaving it to maybe fire later and double-feed a chunk.

Verified the retry/resume/skip state machine against clean, mid-stream-drop
(206 resume), ignored-Range (200 + skip) and connection-failure scenarios;
all reconstruct the byte stream exactly. Not verified end to end: this needs
a live voice server and a real Cloudflare-protected source, and the 200+skip
branch assumes the restarted body is byte-identical.

Bumps VERSION to 1.8.24.

Closes #169

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dolly132 added a commit to Dolly132/torchlight that referenced this pull request Sep 6, 2026

@Dolly132 Dolly132 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested and works fine as expected. no errors
LGTM

@Rushaway
Rushaway merged commit 8755df3 into master Sep 6, 2026
2 checks passed
@Rushaway
Rushaway deleted the fix/169-cf-bypass-retry-parity branch September 6, 2026 13:29
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.

CF-bypass (curl_cffi) streaming has no retry, unlike the aiohttp path

2 participants