use indicatif::{ProgressBar, ProgressStyle};
use regex::Regex;
use reqwest::blocking::Client;
use reqwest::header;
use reqwest::Url;
use std::fs;
use std::io;
use std::io::{copy, Read};
use std::path::Path;
use std::process;
struct DownloadProgress<R> {
inner: R,
progress_bar: ProgressBar,
}
impl<R: Read> Read for DownloadProgress<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf).map(|n| {
self.progress_bar.inc(n as u64);
n
})
}
}
pub fn find_video(url: String, download: bool) {
let content = get_html(&url);
let title = {
let re = Regex::new("<title>(.*) - Pornhub.com</title>").unwrap();
let i = match re.captures(&content) {
Some(i) => i.get(1).unwrap().as_str().to_string(),
None => "video".to_string(),
};
i.replace("&", "&")
};
let url = get_direct_url(&content);
println!("Direct URL: {}", &url);
if download {
download_video(&url, &title);
println!("Saved");
}
}
fn download_video(url: &String, name: &String) {
let total_size: u64 = {
let resp = ureq::head(url).call();
resp.header("content-length").unwrap().parse().unwrap()
};
let name = format!("{}.mp4", name);
println!("Saving as: {}", name);
let url = Url::parse(url).unwrap();
let client = Client::new();
let mut request = client.get(url.as_str());
let pb = ProgressBar::new(total_size);
pb.set_style(ProgressStyle::default_bar()
.template("{spinner:.yellow} [{elapsed_precise}] [{bar:40.yellow/blue}] {bytes}/{total_bytes} ({eta})")
.progress_chars("#>-"));
let file = Path::new(&name);
if file.exists() {
let size = file.metadata().unwrap().len() - 1;
request = request.header(header::RANGE, format!("bytes={}-", size));
pb.inc(size);
}
let mut source = DownloadProgress {
progress_bar: pb,
inner: request.send().unwrap(),
};
let mut dest = fs::OpenOptions::new()
.create(true)
.append(true)
.open(&file)
.unwrap();
let _ = copy(&mut source, &mut dest).unwrap();
}
fn get_html(url: &String) -> String {
let user_agent = "Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 635) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537";
let resp = ureq::request("GET", &url)
.set("User-Agent", user_agent)
.call();
let result = resp.into_string().unwrap();
result
}
fn get_direct_url(html: &String) -> String {
let re_not_found = Regex::new("Error Page Not Found").unwrap();
let re_1080p = Regex::new("\"quality_1080p\":\"(.*)\",\"quality_720p\"").unwrap();
let re_720p = Regex::new("\"quality_720p\":\"(.*)\",\"quality_240p\"").unwrap();
let re_480p = Regex::new("\"quality_480p\":\"(.*)\",\"media").unwrap();
let re_240p = Regex::new("\"quality_240p\":\"(.*)\",\"quality_480p\"").unwrap();
if re_not_found.is_match(&html) {
eprintln!("Video is probably deleted from the ph");
process::exit(1);
}
let mut result = match re_1080p.captures(&html) {
Some(i) => i.get(1).unwrap().as_str().to_string().replace("\\/", "/"),
None => "Error".to_string(),
};
if result == "Error" {
result = match re_720p.captures(&html) {
Some(i) => i.get(1).unwrap().as_str().to_string().replace("\\/", "/"),
None => "Error".to_string(),
};
}
if result == "Error" {
result = match re_480p.captures(&html) {
Some(i) => i.get(1).unwrap().as_str().to_string().replace("\\/", "/"),
None => "Error".to_string(),
};
}
if result == "Error" {
result = match re_240p.captures(&html) {
Some(i) => i.get(1).unwrap().as_str().to_string().replace("\\/", "/"),
None => "Error".to_string(),
};
}
if result == "Error" {
eprintln!("Couldn't find direct download link");
process::exit(1);
}
result
}