From 918ed1a125602d023e1eb2937bf3c55429f63c3d Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 1 Jun 2025 11:16:26 +0000 Subject: [PATCH] flaresolverr for loading behind cloudflare --- src/api.rs | 2 +- src/providers/perverzija.rs | 115 ++++++++++++++++-------------------- src/util/flaresolverr.rs | 64 ++++++++++---------- 3 files changed, 84 insertions(+), 97 deletions(-) diff --git a/src/api.rs b/src/api.rs index c646caa..656458e 100644 --- a/src/api.rs +++ b/src/api.rs @@ -173,7 +173,7 @@ async fn videos_post( ); format.add_http_header( "Referer".to_string(), - "https://pervl2.xtremestream.xyz/player/index.php?data=794a51bb65913debd98f73111705738a" + "https://pervl2.xtremestream.xyz" .to_string(), ); let mut videos = Videos { diff --git a/src/providers/perverzija.rs b/src/providers/perverzija.rs index 8c86b00..992372e 100644 --- a/src/providers/perverzija.rs +++ b/src/providers/perverzija.rs @@ -1,8 +1,9 @@ use std::vec; - +use std::env; use error_chain::error_chain; use htmlentity::entity::{decode, ICodedDataTrait}; -use reqwest::Proxy; +use reqwest::{header, Proxy}; +use serde_json::json; use crate::providers::Provider; use crate::util::flaresolverr::{FlareSolverrRequest, Flaresolverr}; @@ -34,73 +35,56 @@ impl PerverzijaProvider { if page == &1 { url = format!("{}{}", self.url, prefix_uri); } - let client = reqwest::Client::builder() - .user_agent("Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/33.0 Mobile/15E148 Safari/605.1.15") - // .proxy(Proxy::https("http://192.168.0.101:8080").unwrap()) - // .danger_accept_invalid_certs(true) - .build()?; - let response = client.get(url.clone()).send().await?; - // print!("Response: {:?}\n", response); - if response.status().is_success() { - let text = response.text().await?; - let video_items = self.get_video_items_from_html(text.clone()); - Ok(video_items) - } else { - let flare = Flaresolverr::new("http://192.168.0.103:8191/v1".to_string()); - let result = flare - .solve(FlareSolverrRequest { - cmd: "request.get".to_string(), - url: url.clone(), - maxTimeout: 60000, - }) - .await; - println!("FlareSolverr result: {:?}", result); - let video_items = match result { - Err(e) => { - println!("Error solving FlareSolverr: {}", e); - return Err("Failed to solve FlareSolverr".into()); - } - Ok(res) => self.get_video_items_from_html(res), - }; + let flare_url = env::var("FLARE_URL").expect("FLARE_URL not set"); + let flare = Flaresolverr::new(flare_url); - Ok(video_items) + let req = FlareSolverrRequest { + cmd: "request.get".to_string(), + url: url.clone(), + session: "hottub".to_string(), + maxTimeout: 60000, + }; + let response = flare.solve(req).await; + match response { + Ok(html) => { + let video_items = self.get_video_items_from_html(html.clone()); + Ok(video_items) + } + Err(e) => { + println!("Error solving FlareSolverr: {}", e); + return Err("Failed to solve FlareSolverr".into()); + } } } async fn query(&self, page: &u8, query: &str) -> Result> { let search_string = query.replace(" ", "+"); - let mut url = format!("{}advanced-search/?_sf_s={}&sf_paged={}", self.url, search_string, page); + let mut url = format!( + "{}advanced-search/?_sf_s={}&sf_paged={}", + self.url, search_string, page + ); if page == &1 { url = format!("{}advanced-search/?_sf_s={}", self.url, search_string); } - let client = reqwest::Client::builder() - .user_agent("Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/33.0 Mobile/15E148 Safari/605.1.15") - // .proxy(Proxy::https("http://192.168.0.101:8080").unwrap()) - // .danger_accept_invalid_certs(true) - .build()?; - let response = client.get(url.clone()).send().await?; - if response.status().is_success() { - let text = response.text().await?; - let video_items = self.get_video_items_from_html_query(text.clone()); - Ok(video_items) - } else { - let flare = Flaresolverr::new("http://192.168.0.103:8191/v1".to_string()); - let result = flare - .solve(FlareSolverrRequest { - cmd: "request.get".to_string(), - url: url.clone(), - maxTimeout: 60000, - }) - .await; - println!("FlareSolverr result: {:?}", result); - let video_items = match result { - Err(e) => { - println!("Error solving FlareSolverr: {}", e); - return Err("Failed to solve FlareSolverr".into()); - } - Ok(res) => self.get_video_items_from_html_query(res), - }; - Ok(video_items) + let flare_url = env::var("FLARE_URL").expect("FLARE_URL not set"); + let flare = Flaresolverr::new(flare_url); + + let req = FlareSolverrRequest { + cmd: "request.get".to_string(), + url: url.clone(), + session: "hottub".to_string(), + maxTimeout: 60000, + }; + let response = flare.solve(req).await; + match response { + Ok(html) => { + let video_items = self.get_video_items_from_html_query(html.clone()); + Ok(video_items) + } + Err(e) => { + println!("Error solving FlareSolverr: {}", e); + return Err("Failed to solve FlareSolverr".into()); + } } } @@ -118,10 +102,10 @@ impl PerverzijaProvider { if vid.len() > 20 { continue; } - for line in vid.clone() { - println!("{}: {}\n\n", index, line); - index += 1; - } + // for line in vid.clone() { + // println!("{}: {}\n\n", index, line); + // index += 1; + // } let mut title = vid[1].split(">").collect::>()[1] .split("<") @@ -240,7 +224,7 @@ impl PerverzijaProvider { let thumb_index = match vid.len() { 18 => 14, 13 => 8, - _=> { + _ => { println!("Unexpected video segment length: {}", vid.len()); continue; } @@ -295,6 +279,7 @@ impl PerverzijaProvider { return items; } } + impl Provider for PerverzijaProvider { async fn get_videos( &self, diff --git a/src/util/flaresolverr.rs b/src/util/flaresolverr.rs index 75c9c68..1a92e48 100644 --- a/src/util/flaresolverr.rs +++ b/src/util/flaresolverr.rs @@ -1,11 +1,13 @@ use std::collections::HashMap; -use reqwest::Proxy; +use reqwest::{Client, Proxy}; +use serde_json::json; #[derive(serde::Serialize, serde::Deserialize, Debug)] pub struct FlareSolverrRequest { pub cmd: String, pub url: String, + pub session: String, pub maxTimeout: u32, } @@ -20,25 +22,25 @@ pub struct FlaresolverrCookie { httpOnly: bool, //true, secure: bool, //true, session: bool, //false, - sameSite: String, //"None", + sameSite: Option, //"None", priority: String, //"Medium", sameParty: bool, //false, sourceScheme: String, //"Secure", - sourcePort: u8, //443, - partitionKey: String, //"https://perverzija.com" + sourcePort: u32, //443, + partitionKey: Option, //"https://perverzija.com" } -#[derive(serde::Serialize, serde::Deserialize, Debug)] -pub struct FlareSolverrSolution { - url: String, //"https://pervl4.xtremestream.xyz/player/index.php?data=af8a224ded8ec0eadd5d93a746de9d97", - status: u8, - response: String, // "You can't access the video directly", +#[derive(serde::Serialize, serde::Deserialize, Debug)] +struct FlareSolverrSolution { + url: String, + status: u32, + response: String, headers: HashMap, - cookies: Vec, //[], - userAgent: String, //"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" + cookies: Vec, + userAgent: String, } #[derive(serde::Serialize, serde::Deserialize, Debug)] -pub struct FlareSolverrResponse { +struct FlareSolverrResponse { status: String, message: String, solution: FlareSolverrSolution, @@ -48,33 +50,33 @@ pub struct FlareSolverrResponse { } pub struct Flaresolverr { url: String, + session: String } impl Flaresolverr { pub fn new(url: String) -> Self { - Flaresolverr { url } + Flaresolverr { + url: url, + session: "hottub".to_string() } } pub async fn solve( &self, request: FlareSolverrRequest, ) -> Result> { - let client = reqwest::Client::builder() - // .user_agent("Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/33.0 Mobile/15E148 Safari/605.1.15") - // .proxy(Proxy::https("http://192.168.0.101:8080").unwrap()) - // .danger_accept_invalid_certs(true) - .build()?; - let response = client.post(&self.url).json(&request).send().await?; - println!("FlareSolverr response: {:?}", response); - if response.status().is_success() { - let json_response: FlareSolverrResponse = - response.json::().await?; - Ok(json_response.solution.response) - } else { - Err(format!( - "Failed to solve FlareSolverr request: HTTP {}", - response.status() - ) - .into()) - } + let client = Client::new(); + + let response = client + .post("http://192.168.0.103:8191/v1") + .header("Content-Type", "application/json") + .json(&json!({ + "cmd": request.cmd, + "url": request.url, + "session": request.session, + "maxTimeout": request.maxTimeout, + })) + .send().await?; + + let body: FlareSolverrResponse = response.json::().await?; + Ok(body.solution.response) } }