diff --git a/.gitignore b/.gitignore index ab951f8..62aaaad 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ # will have compiled files and executables debug/ target/ +.testing/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1a4e73a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +#FROM debian +FROM consol/debian-xfce-vnc:latest +ENV REFRESHED_AT 2025_06_03 + +# Switch to root user to install additional software +USER 0 + +RUN apt update +RUN apt install -yq libssl-dev \ + curl \ + openssl \ + ca-certificates \ + fontconfig \ + fonts-dejavu \ + libxext6 \ + libxrender1 \ + libxtst6 \ + openjdk-17-jdk \ + supervisor + +RUN curl https://portswigger.net/burp/releases/download \ + -o burpsuite_community.jar + +USER 1000 \ No newline at end of file diff --git a/src/api.rs b/src/api.rs index 3a9301a..9b7f48c 100644 --- a/src/api.rs +++ b/src/api.rs @@ -176,87 +176,89 @@ async fn videos_post( // "https://pervl2.xtremestream.xyz" // .to_string(), // ); - // let mut videos = Videos { - // pageInfo: PageInfo { - // hasNextPage: true, - // resultsPerPage: 10, - // }, - // items: vec![], - // }; - // let channel: String = video_request - // .channel - // .as_deref() - // .unwrap_or("all") - // .to_string(); - // let sort: String = video_request.sort.as_deref().unwrap_or("date").to_string(); - // let mut query: Option = video_request.query.clone(); - // if video_request.query.as_deref() == Some("") { - // query = None; - // } - // let page: u8 = video_request - // .page - // .as_deref() - // .unwrap_or("1") - // .to_string() - // .parse() - // .unwrap(); - // let perPage: u8 = video_request - // .perPage - // .as_deref() - // .unwrap_or("10") - // .to_string() - // .parse() - // .unwrap(); - // let featured = video_request.featured.as_deref().unwrap_or("all").to_string(); - // let provider = PerverzijaProvider::new(); - // let video_items = provider - // .get_videos(channel, sort, query, page.to_string(), perPage.to_string(), featured) - // .await; - // videos.items = video_items.clone(); - - /// #### MOCK RESPONSE - /// - let mut format = Video_Format::new( - "https://pervl2.xtremestream.xyz/player/xs1.php?data=794a51bb65913debd98f73111705738a" - .to_string(), - "1080p".to_string(), - "m3u8".to_string(), - ); - format.add_http_header( - "Referer".to_string(), - "https://pervl2.xtremestream.xyz" - .to_string(), - ); - let videos = Videos { + let mut videos = Videos { pageInfo: PageInfo { hasNextPage: true, resultsPerPage: 10, }, - items: vec![ - Video_Item{ - duration: 110, // 110, - views: Some(14622653), // 14622653, - rating: Some(0.0), // 0.0, - id: "794a51bb65913debd98f73111705738a".to_string(), // "c85017ca87477168d648727753c4ded8a35f173e22ef93743e707b296becb299", - title: "BrazzersExxtra – Give Me A D! The Best Of Cheerleaders".to_string(), // "20 Minutes of Adorable Kittens BEST Compilation", - // url: "https://tube.perverzija.com/brazzersexxtra-give-me-a-d-the-best-of-cheerleaders/".to_string(), - // url : "https://pervl2.xtremestream.xyz/player/xs1.php?data=794a51bb65913debd98f73111705738a".to_string(), // "https://www.youtube.com/watch?v=y0sF5xhGreA", - url : "https://pervl2.xtremestream.xyz/player/index.php?data=794a51bb65913debd98f73111705738a".to_string(), - channel: "perverzija".to_string(), // "youtube", - thumb: "https://tube.perverzija.com/wp-content/uploads/2025/05/BrazzersExxtra-Give-Me-A-D-The-Best-Of-Cheerleaders.jpg".to_string(), // "https://i.ytimg.com/vi/y0sF5xhGreA/hqdefault.jpg", - uploader: Some("Brazzers".to_string()), // "The Pet Collective", - uploaderUrl: Some("https://brazzers.com".to_string()), // "https://www.youtube.com/@petcollective", - verified: Some(false), // false, - tags: Some(vec![]), // [], - uploadedAt: Some(1741142954), // 1741142954 - formats: Some(vec![format]), // Additional HTTP headers if needed - embed: None, - - } - ], + items: vec![], }; + let channel: String = video_request + .channel + .as_deref() + .unwrap_or("all") + .to_string(); + let sort: String = video_request.sort.as_deref().unwrap_or("date").to_string(); + let mut query: Option = video_request.query.clone(); + if video_request.query.as_deref() == Some("") { + query = None; + } + let page: u8 = video_request + .page + .as_deref() + .unwrap_or("1") + .to_string() + .parse() + .unwrap(); + let perPage: u8 = video_request + .perPage + .as_deref() + .unwrap_or("10") + .to_string() + .parse() + .unwrap(); + let featured = video_request.featured.as_deref().unwrap_or("all").to_string(); + let provider = PerverzijaProvider::new(); + let video_items = provider + .get_videos(channel, sort, query, page.to_string(), perPage.to_string(), featured) + .await; + videos.items = video_items.clone(); + + /// #### MOCK RESPONSE + /// + // let mut format = Video_Format::new( + // "https://pervl2.xtremestream.xyz/player/xs1.php?data=794a51bb65913debd98f73111705738a" + // .to_string(), + // "1080p".to_string(), + // "m3u8".to_string(), + // ); + // format.add_http_header( + // "Referer".to_string(), + // "https://pervl2.xtremestream.xyz" + // .to_string(), + // ); + // let videos = Videos { + // pageInfo: PageInfo { + // hasNextPage: true, + // resultsPerPage: 10, + // }, + // items: vec![ + // Video_Item{ + // duration: 110, // 110, + // views: Some(14622653), // 14622653, + // rating: Some(0.0), // 0.0, + // id: "794a51bb65913debd98f73111705738a".to_string(), // "c85017ca87477168d648727753c4ded8a35f173e22ef93743e707b296becb299", + // title: "BrazzersExxtra – Give Me A D! The Best Of Cheerleaders".to_string(), // "20 Minutes of Adorable Kittens BEST Compilation", + // // url: "https://tube.perverzija.com/brazzersexxtra-give-me-a-d-the-best-of-cheerleaders/".to_string(), + // // url : "https://pervl2.xtremestream.xyz/player/xs1.php?data=794a51bb65913debd98f73111705738a".to_string(), // "https://www.youtube.com/watch?v=y0sF5xhGreA", + // url : "https://pervl2.xtremestream.xyz/player/index.php?data=794a51bb65913debd98f73111705738a".to_string(), + // channel: "perverzija".to_string(), // "youtube", + // thumb: "https://tube.perverzija.com/wp-content/uploads/2025/05/BrazzersExxtra-Give-Me-A-D-The-Best-Of-Cheerleaders.jpg".to_string(), // "https://i.ytimg.com/vi/y0sF5xhGreA/hqdefault.jpg", + // uploader: Some("Brazzers".to_string()), // "The Pet Collective", + // uploaderUrl: Some("https://brazzers.com".to_string()), // "https://www.youtube.com/@petcollective", + // verified: Some(false), // false, + // tags: Some(vec![]), // [], + // uploadedAt: Some(1741142954), // 1741142954 + // formats: Some(vec![format]), // Additional HTTP headers if needed + // embed: None, + + // } + // ], + // }; + + // println!("Video: {:?}", videos); + // #### - println!("Video: {:?}", videos); Ok(web::HttpResponse::Ok().json(&videos)) } diff --git a/src/providers/perverzija.rs b/src/providers/perverzija.rs index 8aa68af..c574e89 100644 --- a/src/providers/perverzija.rs +++ b/src/providers/perverzija.rs @@ -28,6 +28,14 @@ impl PerverzijaProvider { } async fn get(&self, page: &u8, featured: String) -> Result> { println!("get"); + + //TODO + // let mut url = Url::parse("https://example.net")?; + // url.query_pairs_mut().append_pair("foo", "bar"); + // url.query_pairs_mut().append_pair("key", "dkhdsihdsaiufds"); + // url.query_pairs_mut().append_pair("hello", "world"); + // println!("{}", url.as_str()); + let mut prefix_uri = "".to_string(); if featured == "featured" { prefix_uri = "featured-scenes/".to_string(); @@ -36,24 +44,69 @@ impl PerverzijaProvider { if page == &1 { url = format!("{}{}", self.url, prefix_uri); } - 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(), - maxTimeout: 60000, + + let client = match env::var("BURP_URL").as_deref() { + Ok(url) => 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(url).unwrap()) + .danger_accept_invalid_certs(true) + .build()?, + Err(_) => 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") + .danger_accept_invalid_certs(true) + .build()?, }; - let response = flare.solve(req).await; - // println!("Response: {:?}", response); - 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()); + + 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: Vec = self.get_video_items_from_html(text.clone()); + Ok(video_items) + } else { + let flare_url = env::var("FLARE_URL").expect("FLARE_URL not set"); + let flare = Flaresolverr::new(flare_url); + 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 { + Ok(res) => { + // println!("FlareSolverr response: {}", res); + self.get_video_items_from_html(res.solution.response) + } + Err(e) => { + println!("Error solving FlareSolverr: {}", e); + return Err("Failed to solve FlareSolverr".into()); + } + }; + + + //########## + 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(), + maxTimeout: 60000, + }; + let response = flare.solve(req).await; + // println!("Response: {:?}", response); + match response { + Ok(html) => { + let video_items: Vec = self.get_video_items_from_html(html.solution.response.clone()); + Ok(video_items) + } + Err(e) => { + println!("Error solving FlareSolverr: {}", e); + return Err("Failed to solve FlareSolverr".into()); + } } } } @@ -79,7 +132,7 @@ impl PerverzijaProvider { let response = flare.solve(req).await; match response { Ok(html) => { - let video_items = self.get_video_items_from_html_query(html.clone()); + let video_items = self.get_video_items_from_html_query(html.solution.response.clone()); Ok(video_items) } Err(e) => { @@ -97,7 +150,7 @@ impl PerverzijaProvider { .split("video-item post") .collect::>()[1..] .to_vec(); - println!("Raw Videos: {:?}", raw_videos); + // println!("Raw Videos: {:?}", raw_videos); for video_segment in &raw_videos { let vid = video_segment.split("\n").collect::>(); // let mut index = 0; diff --git a/src/util/flaresolverr.rs b/src/util/flaresolverr.rs index 542557b..ed11cee 100644 --- a/src/util/flaresolverr.rs +++ b/src/util/flaresolverr.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use reqwest::{Client, Proxy}; +use reqwest::{header, Client, Proxy}; use serde_json::json; #[derive(serde::Serialize, serde::Deserialize, Debug)] @@ -30,19 +30,36 @@ pub struct FlaresolverrCookie { } #[derive(serde::Serialize, serde::Deserialize, Debug)] -struct FlareSolverrSolution { +pub struct FlareSolverrSolution { url: String, status: u32, - response: String, + pub response: String, headers: HashMap, cookies: Vec, userAgent: String, } +impl FlareSolverrSolution { + fn to_client(&self,){ + let mut headers = header::HeaderMap::new(); + for (h, v) in &self.headers { + println!("{}: {}", h, v); + headers.insert( + header::HeaderName::from_bytes(h.as_bytes()).unwrap(), + header::HeaderValue::from_str(v).unwrap(), + ); + } + + // let client = reqwest::Client::builder() + // .danger_accept_invalid_certs(true) + // . + // .build().unwrap(); + } +} #[derive(serde::Serialize, serde::Deserialize, Debug)] -struct FlareSolverrResponse { +pub struct FlareSolverrResponse { status: String, message: String, - solution: FlareSolverrSolution, + pub solution: FlareSolverrSolution, startTimestamp: u64, endTimestamp: u64, version: String, @@ -60,7 +77,7 @@ impl Flaresolverr { pub async fn solve( &self, request: FlareSolverrRequest, - ) -> Result> { + ) -> Result> { let client = Client::builder() .proxy(Proxy::https("http://192.168.0.101:8080").unwrap()) .proxy(Proxy::http("http://192.168.0.101:8080").unwrap()) @@ -78,7 +95,6 @@ impl Flaresolverr { .send().await?; let body: FlareSolverrResponse = response.json::().await?; - println!("FlareSolverr response: {:?}, {}", body.status, body.solution.response.len()); - Ok(body.solution.response) + Ok(body) } } diff --git a/supervisord/burpsuite.sh b/supervisord/burpsuite.sh new file mode 100644 index 0000000..e69de29 diff --git a/supervisord/hottub.sh b/supervisord/hottub.sh new file mode 100644 index 0000000..35ec3b9 --- /dev/null +++ b/supervisord/hottub.sh @@ -0,0 +1 @@ +/ \ No newline at end of file diff --git a/supervisord/supervisord.conf b/supervisord/supervisord.conf new file mode 100644 index 0000000..d24b0c3 --- /dev/null +++ b/supervisord/supervisord.conf @@ -0,0 +1,18 @@ +[supervisord] +nodaemon=true + +[program:hottub] +command=/app/supervisord/hottub.sh +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stderr_logfile=/dev/stderr +directory=/app + +[program:vnc] +command=/dockerstartup/vnc_startup.sh --wait +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stderr_logfile=/dev/stderr +directory=/headless \ No newline at end of file