From aea2cda627d7bff4c23adc6e8b11ec32fa34a27d Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 18 May 2026 17:27:34 +0000 Subject: [PATCH] pimpbunny fix --- src/proxies/pimpbunny.rs | 45 ++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/proxies/pimpbunny.rs b/src/proxies/pimpbunny.rs index 376ef32..93a2011 100644 --- a/src/proxies/pimpbunny.rs +++ b/src/proxies/pimpbunny.rs @@ -147,28 +147,33 @@ impl PimpbunnyProxy { .collect() } - /// Returns true if the URL appears to serve video content (not an "access denied" response). - async fn url_is_accessible(url: &str, requester: &mut Requester) -> bool { - // Range: bytes=0-1 keeps the response body tiny while still probing auth. - match requester - .get_raw_with_headers( - url, - vec![("Range".to_string(), "bytes=0-1".to_string())], - ) - .await - { - Ok(resp) => { - let s = resp.status().as_u16(); - // 200 / 206 = success; 301/302/307 = redirect (follows, so we see final status) - // Treat anything that isn't a client-error 4xx as accessible. - s < 400 || s == 416 // 416 = Range Not Satisfiable means the server accepted auth - } - Err(_) => false, + /// GET the decoded URL without following redirects and return the Location header + /// if the server responds with a 302, or None if it responds with anything else + /// (including 403 "access denied"). + /// + /// The PHPSESSID cookie — acquired when we fetched the detail page — must be + /// forwarded; the server won't issue the 302 without it. + async fn follow_302(url: &str, requester: &Requester) -> Option { + let client = wreq::Client::builder() + .redirect(wreq::redirect::Policy::none()) + .build() + .ok()?; + let mut req = client.get(url); + if let Some(cookie) = requester.cookie_header_for_url(url) { + req = req.header("Cookie", cookie); } + let resp = req.send().await.ok()?; + if resp.status().as_u16() != 302 { + return None; + } + resp.headers() + .get("location") + .and_then(|v| v.to_str().ok()) + .map(|s| s.to_string()) } /// Try to decode the video URL using the KVS algorithm extracted from kt_player.js. - /// Returns the decoded URL if the server accepts it, None otherwise. + /// Returns the CDN redirect target (Location from the 302) on success, None otherwise. async fn try_decode(detail_url: &str, requester: &mut Requester) -> Option { let html = requester.get(detail_url, None).await.ok()?; @@ -183,8 +188,8 @@ impl PimpbunnyProxy { let Some(decoded) = Self::decode_encoded_url(encoded_url, &license_code) else { continue; }; - if Self::url_is_accessible(&decoded, requester).await { - return Some(decoded); + if let Some(location) = Self::follow_302(&decoded, requester).await { + return Some(location); } }