This commit is contained in:
Simon
2025-06-04 07:35:55 +00:00
parent 8d5da3a4dc
commit 3150e57411
7 changed files with 105 additions and 12 deletions

View File

@@ -3,6 +3,7 @@ use ntex::web;
use ntex::web::HttpRequest; use ntex::web::HttpRequest;
use crate::providers::perverzija::PerverzijaProvider; use crate::providers::perverzija::PerverzijaProvider;
use crate::util::cache::VideoCache;
use crate::{providers::*, status::*, videos::*}; use crate::{providers::*, status::*, videos::*};
pub fn config(cfg: &mut web::ServiceConfig) { pub fn config(cfg: &mut web::ServiceConfig) {
@@ -163,6 +164,7 @@ async fn status(req: HttpRequest) -> Result<impl web::Responder, web::Error> {
async fn videos_post( async fn videos_post(
video_request: web::types::Json<Videos_Request>, video_request: web::types::Json<Videos_Request>,
cache: web::types::State<VideoCache>
) -> Result<impl web::Responder, web::Error> { ) -> Result<impl web::Responder, web::Error> {
let mut videos = Videos { let mut videos = Videos {
pageInfo: PageInfo { pageInfo: PageInfo {
@@ -198,7 +200,7 @@ async fn videos_post(
let featured = video_request.featured.as_deref().unwrap_or("all").to_string(); let featured = video_request.featured.as_deref().unwrap_or("all").to_string();
let provider = PerverzijaProvider::new(); let provider = PerverzijaProvider::new();
let video_items = provider let video_items = provider
.get_videos(channel, sort, query, page.to_string(), perPage.to_string(), featured) .get_videos(cache.get_ref().clone(), channel, sort, query, page.to_string(), perPage.to_string(), featured)
.await; .await;
videos.items = video_items.clone(); videos.items = video_items.clone();
Ok(web::HttpResponse::Ok().json(&videos)) Ok(web::HttpResponse::Ok().json(&videos))

View File

@@ -1,6 +1,5 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use ntex_files as fs; use ntex_files as fs;
use ntex::web; use ntex::web;
mod api; mod api;
mod status; mod status;
@@ -14,9 +13,11 @@ async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_BACKTRACE", "1"); std::env::set_var("RUST_BACKTRACE", "1");
env_logger::init(); // You need this to actually see logs env_logger::init(); // You need this to actually see logs
let cache: util::cache::VideoCache = crate::util::cache::VideoCache::new();
web::HttpServer::new(|| { web::HttpServer::new(move || {
web::App::new() web::App::new()
.state(cache.clone())
.wrap(web::middleware::Logger::default()) .wrap(web::middleware::Logger::default())
.service(web::scope("/api").configure(api::config)) .service(web::scope("/api").configure(api::config))
.service(fs::Files::new("/", "static")) .service(fs::Files::new("/", "static"))

View File

@@ -1,6 +1,6 @@
use crate::videos::{Video_Item}; use crate::{util::cache::VideoCache, videos::Video_Item};
pub mod perverzija; pub mod perverzija;
pub trait Provider{ pub trait Provider{
async fn get_videos(&self, channel: String, sort: String, query: Option<String>, page: String, per_page: String, featured: String) -> Vec<Video_Item>; async fn get_videos(&self, cache: VideoCache ,channel: String, sort: String, query: Option<String>, page: String, per_page: String, featured: String) -> Vec<Video_Item>;
} }

View File

@@ -5,6 +5,7 @@ use htmlentity::entity::{decode, ICodedDataTrait};
use reqwest::{Proxy}; use reqwest::{Proxy};
use crate::providers::Provider; use crate::providers::Provider;
use crate::util::cache::VideoCache;
use crate::util::flaresolverr::{FlareSolverrRequest, Flaresolverr}; use crate::util::flaresolverr::{FlareSolverrRequest, Flaresolverr};
use crate::util::time::parse_time_to_seconds; use crate::util::time::parse_time_to_seconds;
use crate::videos::{self, Video_Embed, Video_Item}; // Make sure Provider trait is imported use crate::videos::{self, Video_Embed, Video_Item}; // Make sure Provider trait is imported
@@ -25,7 +26,7 @@ impl PerverzijaProvider {
url: "https://tube.perverzija.com/".to_string(), url: "https://tube.perverzija.com/".to_string(),
} }
} }
async fn get(&self, page: &u8, featured: String) -> Result<Vec<Video_Item>> { async fn get(&self, cache:VideoCache ,page: &u8, featured: String) -> Result<Vec<Video_Item>> {
println!("get"); println!("get");
//TODO //TODO
@@ -43,6 +44,21 @@ impl PerverzijaProvider {
if page == &1 { if page == &1 {
url = format!("{}{}", self.url, prefix_uri); url = format!("{}{}", self.url, prefix_uri);
} }
let old_items = match cache.get(&url) {
Some((time, items)) => {
if time.elapsed().unwrap_or_default().as_secs() < 60 * 60 {
println!("Cache hit for URL: {}", url);
return Ok(items.clone());
}
else{
items.clone()
}
}
None => {
vec![]
}
};
let client = match env::var("BURP_URL").as_deref() { let client = match env::var("BURP_URL").as_deref() {
@@ -63,6 +79,12 @@ impl PerverzijaProvider {
if response.status().is_success() { if response.status().is_success() {
let text = response.text().await?; let text = response.text().await?;
let video_items: Vec<Video_Item> = self.get_video_items_from_html(text.clone()); let video_items: Vec<Video_Item> = self.get_video_items_from_html(text.clone());
if !video_items.is_empty() {
cache.remove(&url);
cache.insert(url.clone(), video_items.clone());
} else{
return Ok(old_items);
}
Ok(video_items) Ok(video_items)
} else { } else {
let flare_url = env::var("FLARE_URL").expect("FLARE_URL not set"); let flare_url = env::var("FLARE_URL").expect("FLARE_URL not set");
@@ -85,10 +107,16 @@ impl PerverzijaProvider {
return Err("Failed to solve FlareSolverr".into()); return Err("Failed to solve FlareSolverr".into());
} }
}; };
if !video_items.is_empty() {
cache.remove(&url);
cache.insert(url.clone(), video_items.clone());
} else {
return Ok(old_items);
}
Ok(video_items) Ok(video_items)
} }
} }
async fn query(&self, page: &u8, query: &str) -> Result<Vec<Video_Item>> { async fn query(&self, cache: VideoCache, page: &u8, query: &str) -> Result<Vec<Video_Item>> {
println!("query: {}", query); println!("query: {}", query);
let search_string = query.replace(" ", "+"); let search_string = query.replace(" ", "+");
let mut url = format!( let mut url = format!(
@@ -99,7 +127,21 @@ impl PerverzijaProvider {
url = format!("{}advanced-search/?_sf_s={}", self.url, search_string); url = format!("{}advanced-search/?_sf_s={}", self.url, search_string);
} }
// Check our Video Cache. If the result is younger than 1 hour, we return it.
let old_items = match cache.get(&url) {
Some((time, items)) => {
if time.elapsed().unwrap_or_default().as_secs() < 60 * 60 {
println!("Cache hit for URL: {}", url);
return Ok(items.clone());
}
else{
items.clone()
}
}
None => {
vec![]
}
};
let client = match env::var("BURP_URL").as_deref() { let client = match env::var("BURP_URL").as_deref() {
Ok(burp_url) => Ok(burp_url) =>
reqwest::Client::builder() reqwest::Client::builder()
@@ -118,6 +160,12 @@ impl PerverzijaProvider {
if response.status().is_success() { if response.status().is_success() {
let text = response.text().await?; let text = response.text().await?;
let video_items: Vec<Video_Item> = self.get_video_items_from_html_query(text.clone()); let video_items: Vec<Video_Item> = self.get_video_items_from_html_query(text.clone());
if !video_items.is_empty() {
cache.remove(&url);
cache.insert(url.clone(), video_items.clone());
} else{
return Ok(old_items);
}
Ok(video_items) Ok(video_items)
} else { } else {
let flare_url = env::var("FLARE_URL").expect("FLARE_URL not set"); let flare_url = env::var("FLARE_URL").expect("FLARE_URL not set");
@@ -140,6 +188,12 @@ impl PerverzijaProvider {
return Err("Failed to solve FlareSolverr".into()); return Err("Failed to solve FlareSolverr".into());
} }
}; };
if !video_items.is_empty() {
cache.remove(&url);
cache.insert(url.clone(), video_items.clone());
} else{
return Ok(old_items);
}
Ok(video_items) Ok(video_items)
} }
} }
@@ -353,6 +407,7 @@ impl PerverzijaProvider {
impl Provider for PerverzijaProvider { impl Provider for PerverzijaProvider {
async fn get_videos( async fn get_videos(
&self, &self,
cache: VideoCache,
_channel: String, _channel: String,
sort: String, sort: String,
query: Option<String>, query: Option<String>,
@@ -363,8 +418,8 @@ impl Provider for PerverzijaProvider {
let _ = per_page; let _ = per_page;
let _ = sort; let _ = sort;
let videos: std::result::Result<Vec<Video_Item>, Error> = match query { let videos: std::result::Result<Vec<Video_Item>, Error> = match query {
Some(q) => self.query(&page.parse::<u8>().unwrap_or(1), &q).await, Some(q) => self.query(cache, &page.parse::<u8>().unwrap_or(1), &q).await,
None => self.get(&page.parse::<u8>().unwrap_or(1), featured).await, None => self.get(cache, &page.parse::<u8>().unwrap_or(1), featured).await,
}; };
match videos { match videos {
Ok(v) => v, Ok(v) => v,

34
src/util/cache.rs Normal file
View File

@@ -0,0 +1,34 @@
use std::time::SystemTime;
use std::sync::{Arc, Mutex};
use crate::videos::Video_Item;
#[derive(Clone)]
pub struct VideoCache{
cache: Arc<Mutex<std::collections::HashMap<String, (SystemTime, Vec<Video_Item>)>>>, // url -> time+Items
}
impl VideoCache {
pub fn new() -> Self {
VideoCache {
cache: Arc::new(Mutex::new(std::collections::HashMap::new())),
}
}
pub fn get(&self, key: &str) -> Option<(SystemTime, Vec<Video_Item>)> {
let cache = self.cache.lock().ok()?;
cache.get(key).cloned()
}
pub fn insert(&self, key: String, value: Vec<Video_Item>) {
if let Ok(mut cache) = self.cache.lock() {
cache.insert(key.clone(), (SystemTime::now(), value.clone()));
}
}
pub fn remove(&self, key: &str) {
if let Ok(mut cache) = self.cache.lock() {
cache.remove(key);
}
}
}

View File

@@ -1,2 +1,3 @@
pub mod time; pub mod time;
pub mod flaresolverr; pub mod flaresolverr;
pub mod cache;

View File

@@ -5,7 +5,7 @@ use std::collections::HashMap;
#[derive(serde::Serialize, serde::Deserialize, Debug)] #[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct Videos_Request { pub struct Videos_Request {
//"versionInstallDate":"2025-06-03T18:20:20Z","languageCode":"en","appInstallDate":"2025-06-03T18:20:20Z","server":"spacemoehre","sexu //"versionInstallDate":"2025-06-03T18:20:20Z","languageCode":"en","appInstallDate":"2025-06-03T18:20:20Z","server":"spacemoehre","sexu
pub clientHash: String, // "a07b23c9b07813c65050e2a4041ca777", pub clientHash: Option<String>, // "a07b23c9b07813c65050e2a4041ca777",
pub blockedKeywords: Option<String>, // "kittens", pub blockedKeywords: Option<String>, // "kittens",
pub countryCode: Option<String>, // "DE", pub countryCode: Option<String>, // "DE",
pub clientVersion: Option<String>, // "2.1.4-22b", pub clientVersion: Option<String>, // "2.1.4-22b",