caching
This commit is contained in:
@@ -3,6 +3,7 @@ use ntex::web;
|
||||
use ntex::web::HttpRequest;
|
||||
|
||||
use crate::providers::perverzija::PerverzijaProvider;
|
||||
use crate::util::cache::VideoCache;
|
||||
use crate::{providers::*, status::*, videos::*};
|
||||
|
||||
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(
|
||||
video_request: web::types::Json<Videos_Request>,
|
||||
cache: web::types::State<VideoCache>
|
||||
) -> Result<impl web::Responder, web::Error> {
|
||||
let mut videos = Videos {
|
||||
pageInfo: PageInfo {
|
||||
@@ -198,7 +200,7 @@ async fn videos_post(
|
||||
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)
|
||||
.get_videos(cache.get_ref().clone(), channel, sort, query, page.to_string(), perPage.to_string(), featured)
|
||||
.await;
|
||||
videos.items = video_items.clone();
|
||||
Ok(web::HttpResponse::Ok().json(&videos))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#![allow(non_snake_case)]
|
||||
use ntex_files as fs;
|
||||
|
||||
use ntex::web;
|
||||
mod api;
|
||||
mod status;
|
||||
@@ -14,9 +13,11 @@ async fn main() -> std::io::Result<()> {
|
||||
std::env::set_var("RUST_BACKTRACE", "1");
|
||||
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()
|
||||
.state(cache.clone())
|
||||
.wrap(web::middleware::Logger::default())
|
||||
.service(web::scope("/api").configure(api::config))
|
||||
.service(fs::Files::new("/", "static"))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::videos::{Video_Item};
|
||||
use crate::{util::cache::VideoCache, videos::Video_Item};
|
||||
|
||||
pub mod perverzija;
|
||||
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>;
|
||||
}
|
||||
@@ -5,6 +5,7 @@ use htmlentity::entity::{decode, ICodedDataTrait};
|
||||
use reqwest::{Proxy};
|
||||
|
||||
use crate::providers::Provider;
|
||||
use crate::util::cache::VideoCache;
|
||||
use crate::util::flaresolverr::{FlareSolverrRequest, Flaresolverr};
|
||||
use crate::util::time::parse_time_to_seconds;
|
||||
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(),
|
||||
}
|
||||
}
|
||||
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");
|
||||
|
||||
//TODO
|
||||
@@ -44,6 +45,21 @@ impl PerverzijaProvider {
|
||||
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() {
|
||||
Ok(burp_url) =>
|
||||
@@ -63,6 +79,12 @@ impl PerverzijaProvider {
|
||||
if response.status().is_success() {
|
||||
let text = response.text().await?;
|
||||
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)
|
||||
} else {
|
||||
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());
|
||||
}
|
||||
};
|
||||
if !video_items.is_empty() {
|
||||
cache.remove(&url);
|
||||
cache.insert(url.clone(), video_items.clone());
|
||||
} else {
|
||||
return Ok(old_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);
|
||||
let search_string = query.replace(" ", "+");
|
||||
let mut url = format!(
|
||||
@@ -99,7 +127,21 @@ impl PerverzijaProvider {
|
||||
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() {
|
||||
Ok(burp_url) =>
|
||||
reqwest::Client::builder()
|
||||
@@ -118,6 +160,12 @@ impl PerverzijaProvider {
|
||||
if response.status().is_success() {
|
||||
let text = response.text().await?;
|
||||
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)
|
||||
} else {
|
||||
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());
|
||||
}
|
||||
};
|
||||
if !video_items.is_empty() {
|
||||
cache.remove(&url);
|
||||
cache.insert(url.clone(), video_items.clone());
|
||||
} else{
|
||||
return Ok(old_items);
|
||||
}
|
||||
Ok(video_items)
|
||||
}
|
||||
}
|
||||
@@ -353,6 +407,7 @@ impl PerverzijaProvider {
|
||||
impl Provider for PerverzijaProvider {
|
||||
async fn get_videos(
|
||||
&self,
|
||||
cache: VideoCache,
|
||||
_channel: String,
|
||||
sort: String,
|
||||
query: Option<String>,
|
||||
@@ -363,8 +418,8 @@ impl Provider for PerverzijaProvider {
|
||||
let _ = per_page;
|
||||
let _ = sort;
|
||||
let videos: std::result::Result<Vec<Video_Item>, Error> = match query {
|
||||
Some(q) => self.query(&page.parse::<u8>().unwrap_or(1), &q).await,
|
||||
None => self.get(&page.parse::<u8>().unwrap_or(1), featured).await,
|
||||
Some(q) => self.query(cache, &page.parse::<u8>().unwrap_or(1), &q).await,
|
||||
None => self.get(cache, &page.parse::<u8>().unwrap_or(1), featured).await,
|
||||
};
|
||||
match videos {
|
||||
Ok(v) => v,
|
||||
|
||||
34
src/util/cache.rs
Normal file
34
src/util/cache.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod time;
|
||||
pub mod flaresolverr;
|
||||
pub mod cache;
|
||||
@@ -5,7 +5,7 @@ use std::collections::HashMap;
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||
pub struct Videos_Request {
|
||||
//"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 countryCode: Option<String>, // "DE",
|
||||
pub clientVersion: Option<String>, // "2.1.4-22b",
|
||||
|
||||
Reference in New Issue
Block a user