use crate::agent::{AgentBase, YaydlAgent};
use crate::definitions::SiteDefinition;
use crate::VIDEO;
use anyhow::{anyhow, Result};
use nom::Finish;
use scraper::{Html, Selector};
use url::Url;
fn get_video_info(video: &mut VIDEO, url: &str) -> Result<bool> {
if video.info.is_empty() {
let url_p = Url::parse(url)?;
let agent = YaydlAgent::init(url_p);
let local_url = url.to_owned();
let body = agent
.get(&local_url)
.call()
.expect("Could not go to the url")
.body_mut()
.read_to_string()
.expect("Could not read the site source");
video.info.push_str(&body);
}
Ok(true)
}
struct XHamsterHandler;
impl SiteDefinition for XHamsterHandler {
fn can_handle_url<'a>(
&'a self,
video: &mut VIDEO,
url: &'a str,
_webdriver_port: u16,
) -> Result<bool> {
let _not_used = get_video_info(video, url)?;
let video_info_html = Html::parse_document(video.info.as_str());
let app_selector = Selector::parse(r#"meta[name="application-name"]"#).unwrap();
let app_elem = video_info_html.select(&app_selector).next();
match app_elem {
Some(elem) => {
let app_name = elem.value().attr("content").unwrap();
match app_name == "xHamster" {
true => Ok(true),
_ => Ok(false),
}
}
None => Ok(false),
}
}
fn is_playlist<'a>(&'a self, _url: &'a str, _webdriver_port: u16) -> Result<bool> {
Ok(true)
}
fn find_video_title<'a>(
&'a self,
video: &mut VIDEO,
url: &'a str,
_webdriver_port: u16,
) -> Result<String> {
let _ = get_video_info(video, url)?;
let video_info_html = Html::parse_document(video.info.as_str());
let h1_selector = Selector::parse("h1").unwrap();
let text = video_info_html.select(&h1_selector).next();
let result = match text {
Some(txt) => txt.text().collect(),
None => return Err(anyhow!("Could not extract the video title.")),
};
Ok(result)
}
fn find_video_direct_url<'a>(
&'a self,
video: &'a mut VIDEO,
url: &'a str,
_webdriver_port: u16,
_onlyaudio: bool,
) -> Result<String> {
let _not_used = get_video_info(video, url)?;
let video_info_html = Html::parse_document(video.info.as_str());
let url_p = Url::parse(url)?;
let agent = YaydlAgent::init(url_p);
let url_selector = Selector::parse(r#"link[rel="preload"][as="fetch"]"#).unwrap();
let url_elem = video_info_html.select(&url_selector).next().unwrap();
let url_contents = url_elem.value().attr("href").unwrap();
let mut playlist_url = Url::parse(url_contents)?;
let request = agent.get(playlist_url.as_str());
let playlist_text = request
.call()
.expect("Could not go to the playlist url")
.body_mut()
.read_to_string()
.expect("Could not read the playlist source");
let playlist = m3u8_rs::parse_media_playlist(&playlist_text.as_bytes())
.finish()
.unwrap();
let video_uri = &playlist.1.segments.last().ok_or("").unwrap().uri;
playlist_url
.path_segments_mut()
.unwrap()
.pop()
.push(video_uri);
Ok(playlist_url.to_string())
}
fn does_video_exist<'a>(
&'a self,
video: &'a mut VIDEO,
url: &'a str,
_webdriver_port: u16,
) -> Result<bool> {
let _video_info = get_video_info(video, url);
Ok(!video.info.is_empty())
}
fn display_name<'a>(&'a self) -> String {
"xHamster".to_string()
}
fn find_video_file_extension<'a>(
&'a self,
_video: &'a mut VIDEO,
_url: &'a str,
_webdriver_port: u16,
_onlyaudio: bool,
) -> Result<String> {
Ok("ts".to_string())
}
fn web_driver_required<'a>(&'a self) -> bool {
false
}
}
inventory::submit! {
&XHamsterHandler as &dyn SiteDefinition
}