use crate::DbPool; use crate::api::ClientVersion; use crate::providers::Provider; use crate::status::*; use crate::util::cache::VideoCache; use crate::util::parse_abbreviated_number; use crate::util::time::parse_time_to_seconds; use crate::videos::{ServerOptions, VideoItem}; use async_trait::async_trait; use error_chain::error_chain; use htmlentity::entity::{ICodedDataTrait, decode}; use std::vec; error_chain! { foreign_links { Io(std::io::Error); HttpRequest(wreq::Error); } errors { Parse(msg: String) { description("parse error") display("parse error: {}", msg) } } } #[derive(Debug, Clone)] pub struct PornhubProvider { url: String, } impl PornhubProvider { pub fn new() -> Self { Self { url: "https://www.pornhub.com".to_string(), } } fn build_channel(&self, _clientversion: ClientVersion) -> Channel { Channel { id: "pornhub".to_string(), name: "Pornhub".to_string(), description: "Pornhub Free Videos".to_string(), premium: false, favicon: "https://www.google.com/s2/favicons?sz=64&domain=pornhub.com".to_string(), status: "active".to_string(), categories: vec![], options: vec![ChannelOption { id: "sort".to_string(), title: "Sort".to_string(), description: "Sort the Videos".to_string(), systemImage: "list.number".to_string(), colorName: "blue".to_string(), options: vec![ FilterOption { id: "mr".to_string(), title: "Most Recent".to_string(), }, FilterOption { id: "mv".to_string(), title: "Most Viewed".to_string(), }, FilterOption { id: "tr".to_string(), title: "Top Rated".to_string(), }, FilterOption { id: "lg".to_string(), title: "Longest".to_string(), }, FilterOption { id: "cm".to_string(), title: "Newest".to_string(), }, ], multiSelect: false, }], nsfw: true, cacheDuration: Some(1800), } } async fn get( &self, cache: VideoCache, page: u8, sort: &str, options: ServerOptions, ) -> Result> { let video_url = format!("{}/video?o={}&page={}", self.url, sort, page); 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()); } Some((_, items)) => items.clone(), None => vec![], }; let mut requester = match options.requester.clone() { Some(r) => r, None => return Ok(old_items), }; let text = match requester.get(&video_url, None).await { Ok(t) => t, Err(_) => return Ok(old_items), }; let video_items = self.get_video_items_from_html(text, "