Use clap to provide a CLI
This commit is contained in:
90
src/main.rs
90
src/main.rs
@@ -1,3 +1,4 @@
|
||||
extern crate clap;
|
||||
extern crate cookie;
|
||||
extern crate dotenv;
|
||||
extern crate json;
|
||||
@@ -7,12 +8,13 @@ extern crate reqwest;
|
||||
extern crate zip;
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, BufReader, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read, BufReader, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::{Instant, Duration};
|
||||
|
||||
use clap::{App, Arg};
|
||||
use json::JsonValue;
|
||||
use reqwest::{Client, Response, RedirectPolicy, RequestBuilder};
|
||||
use reqwest::header::{Cookie, Charset, SetCookie};
|
||||
@@ -67,39 +69,68 @@ impl<'a> From<&'a JsonValue> for Presentation {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let catalog_def = DS;
|
||||
let matches = App::new("TumMediasiteDownloader")
|
||||
.author("Boris-Chengbiao Zhou <bobo1239@web.de>")
|
||||
.about("Downloads \'catalogs\' from the TUM's Mediasite lecture archive.")
|
||||
.arg(Arg::with_name("CATALOG_NAME")
|
||||
.help("name of the catalog e.g. from the URL:\n\
|
||||
https://streams.tum.de/Mediasite/Catalog/catalogs/era-2016 -> era-2016\n\
|
||||
special cases (WS16/17; login included): DS, EIDI, ERA")
|
||||
.required(true)
|
||||
.index(1))
|
||||
.arg(Arg::with_name("OUTPUT_DIRECTORY")
|
||||
.help("where to output the downloaded files")
|
||||
.required(true)
|
||||
.index(2))
|
||||
.arg(Arg::with_name("username")
|
||||
.short("u")
|
||||
.help("username for login; can be omitted if the user from .env should be used")
|
||||
.requires("password")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("password")
|
||||
.short("p")
|
||||
.help("password for login; can be omitted if the user from .env should be used")
|
||||
.requires("username")
|
||||
.takes_value(true))
|
||||
.get_matches();
|
||||
|
||||
let out_dir = get_output_directory();
|
||||
let catalog_def = match matches.value_of("CATALOG_NAME").unwrap() {
|
||||
"DS" => DS,
|
||||
"EIDI" => EIDI,
|
||||
"ERA" => ERA,
|
||||
n => {
|
||||
if let Some(username) = matches.value_of("username") {
|
||||
let password = matches.value_of("password").unwrap();
|
||||
(n, Some((username, password)))
|
||||
} else {
|
||||
(n, None)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let out_dir = Path::new(matches.value_of("OUTPUT_DIRECTORY").unwrap());
|
||||
if out_dir.exists() {
|
||||
assert!(out_dir.is_dir());
|
||||
} else {
|
||||
::std::fs::create_dir_all(out_dir).expect("Failed to create output directory!");
|
||||
}
|
||||
|
||||
let default_login = get_default_login();
|
||||
let (catalog_name, (username, password)) = if let Some((user, pass)) = catalog_def.1 {
|
||||
(catalog_def.0, (user.to_string(), pass.to_string()))
|
||||
} else {
|
||||
(catalog_def.0, default_login)
|
||||
(catalog_def.0, get_default_login())
|
||||
};
|
||||
|
||||
println!("Preparing to download catalog \"{}\"!", catalog_name);
|
||||
|
||||
let auth = get_auth(&username, &password);
|
||||
// let out_dir = Path::new("/run/media/bobo1239/30E0E835E0E7FECA/downloaded");
|
||||
// let out_dir = Path::new("out");
|
||||
download_catalog(catalog_name, &out_dir, &auth);
|
||||
}
|
||||
|
||||
fn get_output_directory() -> PathBuf {
|
||||
// The first argument is (usually) the executable
|
||||
let path_str = env::args_os().nth(1).expect("No output directory specified!");
|
||||
let path = Path::new(&path_str);
|
||||
if path.exists() {
|
||||
assert!(path.is_dir());
|
||||
} else {
|
||||
::std::fs::create_dir_all(path).expect("Failed to create output directory!");
|
||||
}
|
||||
path.to_owned()
|
||||
download_catalog(catalog_name, out_dir, &auth);
|
||||
}
|
||||
|
||||
fn get_default_login() -> (String, String) {
|
||||
dotenv::dotenv().expect("Missing .env!");
|
||||
if dotenv::dotenv().is_err() {
|
||||
println!("No .env found!");
|
||||
}
|
||||
|
||||
let username = env::var("TUM_USERNAME").expect("Missing TUM_USERNAME environment variable!");
|
||||
let password = env::var("TUM_PASSWORD").expect("Missing TUM_PASSWORD environment variable!");
|
||||
@@ -118,6 +149,13 @@ fn get_auth(username: &str, password: &str) -> String {
|
||||
.form(&form_data)
|
||||
},
|
||||
|res| res.headers().get::<SetCookie>().is_some());
|
||||
// FIXME: We're somehow only getting "Object moved" instead of the actual response
|
||||
// => We can't determine if the login was successful
|
||||
// (we still get a MediasiteAuth cookie that is useless)
|
||||
// let body = read_response_body(&mut res);
|
||||
// if body.contains("Unknown username or bad password.") {
|
||||
// panic!("Unknown username or bad password!");
|
||||
// }
|
||||
|
||||
let set_cookie: &SetCookie = res.headers().get().unwrap();
|
||||
let cookie = cookie::Cookie::parse(set_cookie.0[0].to_string())
|
||||
@@ -151,7 +189,9 @@ fn get_catalog_id(name: &str, auth: &str) -> String {
|
||||
let body = read_response_body(&mut res);
|
||||
|
||||
let prefix = "CatalogId: '";
|
||||
let idx = body.find(prefix).expect("Failed to find CatalogId on the catalog page!");
|
||||
let idx = body.find(prefix)
|
||||
.expect("Failed to find CatalogId on the catalog page! Perhaps you got the wrong catalog \
|
||||
name or an invalid login?");
|
||||
let pre_len = prefix.len();
|
||||
// Assuming all catalog ids follow this pattern!
|
||||
let len = "a6fca0c1-0be4-4e66-83b7-bcdc4eb5e95e".len();
|
||||
@@ -211,7 +251,7 @@ fn download_presentation(presentation: &Presentation, out_dir: &Path, auth: &str
|
||||
let len = match reader.read(&mut buf) {
|
||||
Ok(0) => break,
|
||||
Ok(len) => len,
|
||||
Err(ref e) if e.kind() == ::std::io::ErrorKind::Interrupted => continue,
|
||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
|
||||
Err(e) => panic!(e),
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user