Last active
February 21, 2023 23:48
-
-
Save cfsamson/1cc74144fdf316bde8eebb84595f864e to your computer and use it in GitHub Desktop.
Fantocini file downloader - when you can't manually issua a GET request
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Cargo.toml | |
// | |
// [dependencies] | |
// serde_json = "1.0.61" | |
// notify = "4.0.15" | |
// anyhow = "1.0.38" | |
// fantoccini = "0.17.1" | |
// tokio = {version="1.1.1", features= ["full"]} | |
// log = "0.4.14" | |
// env_logger = "0.8.2" | |
use std::{ | |
sync::mpsc::{self, Receiver}, | |
time::Duration, | |
}; | |
use anyhow::{bail, Result}; | |
use fantoccini::{ClientBuilder, Locator}; | |
use log::{error, info}; | |
use notify::{DebouncedEvent, ReadDirectoryChangesWatcher, RecursiveMode, Watcher}; | |
use serde_json::{json, Map, Value}; | |
#[tokio::main] | |
async fn main() { | |
env_logger::init(); | |
let download_path_absolute = "C:\\temp\\downloads"; | |
match download_report(download_path_absolute).await { | |
Ok(()) => info!("Downloaded is completed!"), | |
Err(e) => error!("{}", e), | |
}; | |
} | |
async fn download_report(download_dir: &str) -> Result<()> { | |
let capabilities = create_capabilities(download_dir); | |
let mut c = ClientBuilder::native() | |
.capabilities(capabilities) | |
.connect("http://localhost:4444") | |
.await | |
.expect("Failed to connect to webdriver"); | |
c.goto("https://www.someplace.com").await?; | |
// Start to watch for new files in the download folder | |
let download_watcher = DownloadWatcher::init(download_dir)?; | |
let download = c.find(Locator::Id("download_btn")).await?; | |
download.click().await?; | |
// Watch folder for new files, timeout if the download hasn't finished in 10 minutes | |
download_watcher.wait(Duration::from_secs(60*10))?; | |
c.close().await?; | |
Ok(()) | |
} | |
struct DownloadWatcher { | |
rx: Receiver<DebouncedEvent>, | |
_watcher: ReadDirectoryChangesWatcher, | |
} | |
impl DownloadWatcher { | |
fn init(path_to_watch: &str) -> Result<Self> { | |
let (tx, rx) = mpsc::channel(); | |
let mut _watcher = notify::watcher(tx, Duration::from_secs(0))?; | |
_watcher.watch(path_to_watch, RecursiveMode::NonRecursive)?; | |
Ok(Self { rx, _watcher }) | |
} | |
fn wait(self, timeout: Duration) -> Result<()> { | |
loop { | |
match self.rx.recv_timeout(timeout) { | |
Ok(DebouncedEvent::Create(_)) => break, | |
Ok(DebouncedEvent::Error(e, _)) => bail!("Notify error: {}", e), | |
Ok(_event) => (), | |
Err(mpsc::RecvTimeoutError::Timeout) => bail!("Download timeout"), | |
Err(e) => bail!("{}", e), | |
} | |
} | |
Ok(()) | |
} | |
} | |
fn create_capabilities(download_dir: &str) -> Map<String, Value> { | |
let capabilities = json!({ | |
"moz:firefoxOptions": { | |
"prefs": { | |
"browser.download.manager.showWhenStarting": false, | |
"browser.helperApps.neverAsk.saveToDisk": "text/csv,application/vnd.ms-excel,application/csv", // change to the contenttype of your video file | |
"browser.download.folderList": 2, | |
"browser.download.dir": download_dir | |
}, | |
"args": ["-headless"] // if you want a headless browser | |
}, | |
"timeouts": { | |
"pageLoad": 1000*60*5, | |
"implicit": 1000*60*5, | |
"script": 1000*60*5, | |
} | |
}); | |
let map= capabilities.as_object().unwrap().to_owned(); | |
map | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment