use crate::DbPool; use crate::providers::Provider; use crate::util::cache::VideoCache; use crate::util::time::parse_time_to_seconds; use crate::videos::{ServerOptions, VideoItem}; use error_chain::error_chain; use htmlentity::entity::{ICodedDataTrait, decode}; use std::vec; use async_trait::async_trait; error_chain! { foreign_links { Io(std::io::Error); HttpRequest(wreq::Error); } } #[derive(Debug, Clone)] pub struct PornzogProvider { url: String, } impl PornzogProvider { pub fn new() -> Self { PornzogProvider { url: "https://pornzog.com".to_string(), } } async fn query( &self, cache: VideoCache, page: u8, query: &str, sort: String, options: ServerOptions, ) -> Result> { let mut search_params = vec![format!("page={}", page), "site=hdzog".to_string()]; if !query.is_empty() { search_params.push(format!("s={}", query.replace(" ", "+"))); } let sort_string = match sort.as_str() { "relevance" => "o=relevance", "viewed" => "o=viewed", "rated" => "o=rated", "longest" => "o=longest", _ => "o=recent", }; search_params.push(format!("{}", &sort_string)); let video_url = format!("{}/search/?{}", self.url, search_params.join("&")); // Check our Video Cache. If the result is younger than 1 hour, we return it. let old_items = match cache.get(&video_url) { Some((time, items)) => { if time.elapsed().unwrap_or_default().as_secs() < 60 * 5 { return Ok(items.clone()); } else { let _ = cache.check().await; return Ok(items.clone()); } } None => { vec![] } }; let mut requester = options.requester.clone().unwrap(); let text = requester.get(&video_url, None).await.unwrap(); let video_items: Vec = self.get_video_items_from_html(text.clone()); if !video_items.is_empty() { cache.remove(&video_url); cache.insert(video_url.clone(), video_items.clone()); } else { return Ok(old_items); } Ok(video_items) } fn get_video_items_from_html(&self, html: String) -> Vec { if html.is_empty() { return vec![]; } let mut items: Vec = Vec::new(); let raw_videos = html.split("class=\"paginator\"").collect::>()[0] .split("class=\"thumb-video ") .collect::>()[1..] .to_vec(); for video_segment in &raw_videos { // let vid = video_segment.split("\n").collect::>(); // for (index, line) in vid.iter().enumerate() { // println!("Line {}: {}", index, line); // } let mut video_url: String = video_segment.split("href=\"").collect::>()[1] .split("\"") .collect::>()[0] .to_string(); if video_url.starts_with("/") { video_url = format!("{}{}", self.url, video_url); } let mut title = video_segment.split("alt=\"").collect::>()[1] .split("\"") .collect::>()[0] .to_string(); // html decode title = decode(title.as_bytes()).to_string().unwrap_or(title); let id = video_url.split("/").collect::>()[4].to_string(); let thumb = format!( "{}", video_segment.split(">()[1] .split("data-original=\"") .collect::>()[1] .split("\"") .collect::>()[0] .to_string() ); let raw_duration = video_segment .split("class=\"duration\">") .collect::>()[1] .split("<") .collect::>()[0] .to_string(); let duration = parse_time_to_seconds(raw_duration.as_str()).unwrap_or(0) as u32; // let uploader = video_segment.split("class=\"source\">").collect::>()[1] // .split(">").collect::>()[1] // .split("<").collect::>()[0] // .to_string(); let tags = video_segment.split("class=\"tags\"").collect::>()[1] .split("

") .collect::>()[0] .split(">()[1..] .iter() .map(|el| { el.split(">").collect::>()[1] .split("<") .collect::>()[0] .to_string() }) .collect::>(); let video_item = VideoItem::new( id, title, video_url.to_string(), "pornzog".to_string(), thumb, duration, ) // .uploader(uploader) .tags(tags); items.push(video_item); } return items; } } #[async_trait] impl Provider for PornzogProvider { async fn get_videos( &self, cache: VideoCache, pool: DbPool, sort: String, query: Option, page: String, per_page: String, options: ServerOptions, ) -> Vec { let _ = per_page; let _ = pool; let videos: std::result::Result, Error> = self .query( cache, page.parse::().unwrap_or(1), query.unwrap_or("".to_string()).as_str(), sort, options, ) .await; match videos { Ok(v) => v, Err(e) => { println!("Error fetching videos: {}", e); vec![] } } } }