Files
mangaBookmark/backend
sulthan 05e93a4869 fix(latest): hold the tab open until a Cloudflare challenge clears
BrowserFetcher.run navigated, waited for "body", read once, and closed
the tab - about half a second end to end. The Cloudflare interstitial has
a body too, so WaitReady was satisfied by the challenge page itself, and
the read that followed was of the interstitial rather than the site.

That made the challenge unclearable rather than merely slow. An
interstitial needs several seconds of a live page to solve itself and
write clearance into the browser's shared cookie jar; tearing the tab
down first means the clearance that would have unblocked every later
fetch is never obtained, so each call is challenged exactly like the one
before it.

run now holds one tab and re-reads until the caller's predicate reports
an answer, bounded by challengeTimeout and by the caller's own deadline.
Each caller supplies the predicate that fits its payload: kagane's
in-page fetch simply returns nothing while challenged, whereas
novelfull's payload is the DOM, and the interstitial has a DOM as well,
so that one excludes the challenge markup explicitly.

Exhausting the budget is now reported as errChallengeHeld and mapped back
to the 403 the poller already expects, keeping a challenged site distinct
from a broken transport.

Image loses its own retry loop, which run now subsumes.

Measured against a real kagane cover from a cold browser profile: no
image at all before, 4.9s to a 56710-byte image/webp after. The live
proof is TestSmokeKagane* in smoke_image_test.go, which skips unless
SMOKE_BROWSER_WS_URL names a sidecar, so `go test ./...` stays hermetic.
2026-08-08 23:03:27 +07:00
..