Reformat code according to new RFC style

This commit is contained in:
2017-06-04 20:01:37 +02:00
parent ffc0cc8a8c
commit 63e4fd3b07
2 changed files with 105 additions and 80 deletions

View File

@@ -26,8 +26,6 @@ use presentation::Presentation;
// TODO: Old "Publish To Go" packages get sweeped from the server and you have to request a new one; // TODO: Old "Publish To Go" packages get sweeped from the server and you have to request a new one;
// Implement this // Implement this
// TODO: sometimes you need to access the video listing at least once using moodle; emulate this // TODO: sometimes you need to access the video listing at least once using moodle; emulate this
// TODO: Add aliases with semester postfix so other can contribute aliases; move to separate file
// split into files in general?
const MAX_RETRIES: u8 = 10; const MAX_RETRIES: u8 = 10;
@@ -54,26 +52,36 @@ fn main() {
let matches = App::new("TumMediasiteDownloader") let matches = App::new("TumMediasiteDownloader")
.author("Boris-Chengbiao Zhou <bobo1239@web.de>") .author("Boris-Chengbiao Zhou <bobo1239@web.de>")
.about("Downloads \'catalogs\' from the TUM's Mediasite lecture archive.") .about("Downloads \'catalogs\' from the TUM's Mediasite lecture archive.")
.arg(Arg::with_name("CATALOG_NAME") .arg(
.help("name of the catalog e.g. from the URL:\n\ 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\ https://streams.tum.de/Mediasite/Catalog/catalogs/era-2016 -> era-2016\n\
special cases (WS16/17; login included): DS, EIDI, ERA") special cases (WS16/17; login included): DS, EIDI, ERA, ..."
)
.required(true) .required(true)
.index(1)) .index(1)
.arg(Arg::with_name("OUTPUT_DIRECTORY") )
.arg(
Arg::with_name("OUTPUT_DIRECTORY")
.help("where to output the downloaded files") .help("where to output the downloaded files")
.required(true) .required(true)
.index(2)) .index(2)
.arg(Arg::with_name("username") )
.arg(
Arg::with_name("username")
.short("u") .short("u")
.help("username for login; can be omitted if the user from .env should be used",) .help("username for login; can be omitted if the user from .env should be used")
.requires("password") .requires("password")
.takes_value(true)) .takes_value(true)
.arg(Arg::with_name("password") )
.arg(
Arg::with_name("password")
.short("p") .short("p")
.help("password for login; can be omitted if the user from .env should be used",) .help("password for login; can be omitted if the user from .env should be used")
.requires("username") .requires("username")
.takes_value(true)) .takes_value(true)
)
.get_matches(); .get_matches();
let catalog_name = matches.value_of("CATALOG_NAME").unwrap(); let catalog_name = matches.value_of("CATALOG_NAME").unwrap();
@@ -128,12 +136,14 @@ fn get_auth() {
form_data.insert("UserName", &*username); form_data.insert("UserName", &*username);
form_data.insert("Password", &*password); form_data.insert("Password", &*password);
let res = try_to_get_valid_response(|client| { let res = try_to_get_valid_response(
|client| {
client client
.post("https://streams.tum.de/Mediasite/Login") .post("https://streams.tum.de/Mediasite/Login")
.form(&form_data) .form(&form_data)
}, },
|res| res.headers().get::<SetCookie>().is_some()); |res| res.headers().get::<SetCookie>().is_some(),
);
// FIXME: We're somehow only getting "302 Object moved" instead of the actual response // FIXME: We're somehow only getting "302 Object moved" instead of the actual response
// => We can't determine if the login was successful // => We can't determine if the login was successful
// (we still get a MediasiteAuth cookie that is useless) // (we still get a MediasiteAuth cookie that is useless)
@@ -156,14 +166,18 @@ fn download_catalog(catalog_name: &str, out_dir: &Path) {
let catalog_id = get_catalog_id(catalog_name); let catalog_id = get_catalog_id(catalog_name);
let json = get_json(&catalog_id); let json = get_json(&catalog_id);
let presentations = json_to_presentations(&json); let presentations = json_to_presentations(&json);
println!("Starting to download {} presentations!", println!(
presentations.len()); "Starting to download {} presentations!",
presentations.len()
);
for (i, presentation) in presentations.iter().enumerate() { for (i, presentation) in presentations.iter().enumerate() {
println!("\nDownloading {}/{}: {}", println!(
"\nDownloading {}/{}: {}",
i + 1, i + 1,
presentations.len(), presentations.len(),
presentation.name()); presentation.name()
);
for _ in 0..MAX_RETRIES { for _ in 0..MAX_RETRIES {
match presentation.download(out_dir) { match presentation.download(out_dir) {
Ok(()) => break, Ok(()) => break,
@@ -189,8 +203,10 @@ fn get_catalog_id(name: &str) -> String {
let prefix = "CatalogId: '"; let prefix = "CatalogId: '";
let idx = body.find(prefix) let idx = body.find(prefix)
.expect("Failed to find CatalogId on the catalog page! Perhaps you got the wrong catalog \ .expect(
name or an invalid login? Maybe you need to open the page in a browser once..."); "Failed to find CatalogId on the catalog page! Perhaps you got the wrong catalog \
name or an invalid login? Maybe you need to open the page in a browser once..."
);
let pre_len = prefix.len(); let pre_len = prefix.len();
// Assuming all catalog ids follow this pattern! // Assuming all catalog ids follow this pattern!
let len = "a6fca0c1-0be4-4e66-83b7-bcdc4eb5e95e".len(); let len = "a6fca0c1-0be4-4e66-83b7-bcdc4eb5e95e".len();
@@ -218,12 +234,14 @@ fn get_json(catalog_id: &str) -> String {
data.insert("CurrentFolderId", catalog_id); data.insert("CurrentFolderId", catalog_id);
data.insert("ItemsPerPage", "500"); data.insert("ItemsPerPage", "500");
let mut res = try_to_get_response(|client| { let mut res = try_to_get_response(
|client| {
client client
.post("https://streams.tum.de/Mediasite/Catalog/Data/GetPresentationsForFolder") .post("https://streams.tum.de/Mediasite/Catalog/Data/GetPresentationsForFolder")
.header(construct_cookie()) .header(construct_cookie())
.json(&data) .json(&data)
}); }
);
read_response_body(&mut res) read_response_body(&mut res)
} }
@@ -232,14 +250,16 @@ fn construct_cookie() -> Cookie {
} }
fn try_to_get_response<F>(f: F) -> Response fn try_to_get_response<F>(f: F) -> Response
where F: Fn(&Client) -> RequestBuilder where
F: Fn(&Client) -> RequestBuilder,
{ {
try_to_get_valid_response(f, |_| true) try_to_get_valid_response(f, |_| true)
} }
fn try_to_get_valid_response<F1, F2>(f1: F1, f2: F2) -> Response fn try_to_get_valid_response<F1, F2>(f1: F1, f2: F2) -> Response
where F1: Fn(&Client) -> RequestBuilder, where
F2: Fn(&Response) -> bool F1: Fn(&Client) -> RequestBuilder,
F2: Fn(&Response) -> bool,
{ {
for retries in 0..MAX_RETRIES { for retries in 0..MAX_RETRIES {
if retries > 0 { if retries > 0 {

View File

@@ -32,10 +32,11 @@ impl Presentation {
} }
pub(crate) fn download(&self, out_dir: &Path) -> Result<(), DownloadError> { pub(crate) fn download(&self, out_dir: &Path) -> Result<(), DownloadError> {
fn download_to_file_and_check<F: Fn(&Path) -> bool>(response: &mut Response, fn download_to_file_and_check<F: Fn(&Path) -> bool>(
response: &mut Response,
out_file: &Path, out_file: &Path,
check: F) check: F,
-> Result<(), io::Error> { ) -> Result<(), io::Error> {
println!("Output file: {}", out_file.display()); println!("Output file: {}", out_file.display());
if out_file.exists() { if out_file.exists() {
println!("File is present already. Checking validity..."); println!("File is present already. Checking validity...");
@@ -56,14 +57,10 @@ impl Presentation {
match *self { match *self {
Presentation::PublishToGo { ref download_url, .. } => { Presentation::PublishToGo { ref download_url, .. } => {
let mut response = try_to_get_valid_response(|client| { let mut response = try_to_get_valid_response(
client |client| client.get(download_url).header(construct_cookie()),
.get(download_url) |resp| resp.headers().get::<ContentDisposition>().is_some(),
.header(construct_cookie()) );
},
|resp| {
resp.headers().get::<ContentDisposition>().is_some()
});
let filename = { let filename = {
let content_disposition = let content_disposition =
@@ -74,8 +71,10 @@ impl Presentation {
match *param { match *param {
DispositionParam::Filename(ref charset, _, ref vec) => { DispositionParam::Filename(ref charset, _, ref vec) => {
assert_eq!(&Charset::Ext("UTF-8".to_string()), charset); assert_eq!(&Charset::Ext("UTF-8".to_string()), charset);
name = Some(String::from_utf8(vec.to_vec()) name = Some(
.expect("Suggested filename isn't valid UTF-8!",)); String::from_utf8(vec.to_vec())
.expect("Suggested filename isn't valid UTF-8!")
);
} }
_ => continue, _ => continue,
} }
@@ -95,22 +94,26 @@ impl Presentation {
.. ..
} => { } => {
let videos = { let videos = {
let payload = format!("{{\"getPlayerOptionsRequest\":{{\ let payload = format!(
"{{\"getPlayerOptionsRequest\":{{\
\"ResourceId\":\"{}\",\ \"ResourceId\":\"{}\",\
\"QueryString\":\"{}\"\ \"QueryString\":\"{}\"\
}}}}", }}}}",
resource_id, resource_id,
query_string); query_string
);
let url = "https://streams.tum.de/Mediasite/PlayerService/\ let url = "https://streams.tum.de/Mediasite/PlayerService/\
PlayerService.svc/json/GetPlayerOptions"; PlayerService.svc/json/GetPlayerOptions";
let mut res = try_to_get_response(|client| { let mut res = try_to_get_response(
|client| {
client client
.post(url) .post(url)
.header(construct_cookie()) .header(construct_cookie())
.header(ContentType::json()) .header(ContentType::json())
.body(&*payload) .body(&*payload)
}); }
);
let json_text = read_response_body(&mut res); let json_text = read_response_body(&mut res);
if json_text.contains("You are not authorized to view the requested content") { if json_text.contains("You are not authorized to view the requested content") {
@@ -127,13 +130,11 @@ impl Presentation {
vec vec
}; };
for (i, download_url) in videos.iter().enumerate() { for (i, download_url) in videos.iter().enumerate() {
let mut response = try_to_get_valid_response(|client| { let mut response =
client.get(download_url).header(construct_cookie()) try_to_get_valid_response(
}, |client| client.get(download_url).header(construct_cookie()),
|resp| { |resp| resp.status() == &StatusCode::Ok,
resp.status() == );
&StatusCode::Ok
});
// TODO: Support formats besides mp4 // TODO: Support formats besides mp4
// extract extension from url or somewehre else... // extract extension from url or somewehre else...
let filename = format!("{} - {}.mp4", fix_filename(self.name()), i + 1); let filename = format!("{} - {}.mp4", fix_filename(self.name()), i + 1);
@@ -211,9 +212,11 @@ fn download_to_file(response: &mut Response, path: &Path) -> Result<(), io::Erro
let now = Instant::now(); let now = Instant::now();
if now - last > Duration::from_millis(update_duration_millis) { if now - last > Duration::from_millis(update_duration_millis) {
print!("{:.*} kB/s \r", print!(
"{:.*} kB/s \r",
2, 2,
done as f64 * 1000.0 / update_duration_millis as f64 / 1024.0); done as f64 * 1000.0 / update_duration_millis as f64 / 1024.0
);
::std::io::stdout() ::std::io::stdout()
.flush() .flush()
.expect("Failed flushing the terminal!"); .expect("Failed flushing the terminal!");
@@ -261,9 +264,11 @@ fn check_video(path: &Path) -> bool {
match command { match command {
Ok(output) => output.stderr.is_empty(), Ok(output) => output.stderr.is_empty(),
Err(_) => { Err(_) => {
println!("Failed to check {} with ffmpeg. Perhaps ffmpeg isn't in your path. \ println!(
"Failed to check {} with ffmpeg. Perhaps ffmpeg isn't in your path. \
Skipping check...", Skipping check...",
path.display()); path.display()
);
true true
} }
} }