~nicohman/wyvern

8b281f40f286b2ffa0484f8adcabe5e9b36ee016 — nicohman 5 years ago 4257098
Add --id option to extras
2 files changed, 103 insertions(+), 82 deletions(-)

M src/args.rs
M src/main.rs
M src/args.rs => src/args.rs +2 -0
@@ 29,6 29,8 @@ pub enum Command {
        all: bool,
        #[structopt(short = "f", long = "first", help = "Download the first search result")]
        first: bool,
        #[structopt(short = "i", long = "id", help = "Download a game's extras by id")]
        id: Option<i64>,
        game: Option<String>,
    },
    #[derive(Default)]

M src/main.rs => src/main.rs +101 -82
@@ 229,7 229,13 @@ fn parse_args(
                error!("Did not specify a game to download. Exiting.");
            }
        }
        Extras { game, all, first } => {
        Extras {
            game,
            all,
            first,
            id,
        } => {
            let mut details: GameDetails;
            if let Some(search) = game {
                if let Ok(results) =
                    gog.get_filtered_products(FilterParams::from_one(Search(search.clone())))


@@ 249,94 255,107 @@ fn parse_args(
                        i = select.interact().unwrap();
                    }
                    info!("Fetching game details");
                    let details = gog.get_game_details(e[i].id).unwrap();
                    println!("Downloading extras for game {}", details.title);
                    let folder_name = PathBuf::from(format!("{} Extras", details.title));
                    if fs::metadata(&folder_name).is_err() {
                        fs::create_dir(&folder_name).expect("Couldn't create extras folder");
                    }
                    let mut picked: Vec<usize> = vec![];

                    details = gog.get_game_details(e[i].id).unwrap();
                } else {
                    error!("Could not search for games.");

                    return Ok(gog);
                }
            } else if let Some(id) = id {
                if let Ok(fetched) = gog.get_game_details(id) {
                    details = fetched;
                } else {
                    error!("Could not fetch game details. Are you sure that the id is right?");

                    return Ok(gog);
                }
            } else {
                error!("Did not specify a game.");

                return Ok(gog);
            }
            println!("Downloading extras for game {}", details.title);
            let folder_name = PathBuf::from(format!("{} Extras", details.title));
            if fs::metadata(&folder_name).is_err() {
                fs::create_dir(&folder_name).expect("Couldn't create extras folder");
            }
            let mut picked: Vec<usize> = vec![];
            if !all {
                let mut check = Checkboxes::new();
                let mut checks = check.with_prompt("Pick the extras you want to download");
                for ex in details.extras.iter() {
                    checks.item(&ex.name);
                }
                picked = checks.interact().unwrap();
            }
            let extra_responses: Vec<Result<reqwest::Response, Error>> = details
                .extras
                .iter()
                .enumerate()
                .filter(|(i, _x)| {
                    if !all {
                        let mut check = Checkboxes::new();
                        let mut checks = check.with_prompt("Pick the extras you want to download");
                        for ex in details.extras.iter() {
                            checks.item(&ex.name);
                        }
                        picked = checks.interact().unwrap();
                        return picked.contains(i);
                    } else {
                        return true;
                    }
                    let extra_responses: Vec<Result<reqwest::Response, Error>> = details
                        .extras
                        .iter()
                        .enumerate()
                        .filter(|(i, _x)| {
                            if !all {
                                return picked.contains(i);
                })
                .map(|(_i, x)| {
                    info!("Finding URL");
                    let mut url = "https://gog.com".to_string() + &x.manual_url;
                    let mut response;
                    loop {
                        let temp_response = gog.client_noredirect.borrow().get(&url).send();
                        if temp_response.is_ok() {
                            response = temp_response.unwrap();
                            let headers = response.headers();
                            // GOG appears to be inconsistent with returning either 301/302, so this just checks for a redirect location.
                            if headers.contains_key("location") {
                                url = headers
                                    .get("location")
                                    .unwrap()
                                    .to_str()
                                    .unwrap()
                                    .to_string();
                            } else {
                                return true;
                            }
                        })
                        .map(|(_i, x)| {
                            info!("Finding URL");
                            let mut url = "https://gog.com".to_string() + &x.manual_url;
                            let mut response;
                            loop {
                                let temp_response = gog.client_noredirect.borrow().get(&url).send();
                                if temp_response.is_ok() {
                                    response = temp_response.unwrap();
                                    let headers = response.headers();
                                    // GOG appears to be inconsistent with returning either 301/302, so this just checks for a redirect location.
                                    if headers.contains_key("location") {
                                        url = headers
                                            .get("location")
                                            .unwrap()
                                            .to_str()
                                            .unwrap()
                                            .to_string();
                                    } else {
                                        break;
                                    }
                                } else {
                                    return Err(temp_response.err().unwrap().into());
                                }
                                break;
                            }
                            Ok(response)
                        })
                        .collect();
                    for extra in extra_responses.into_iter() {
                        let mut extra = extra.expect("Couldn't fetch extra");
                        let mut real_response = gog
                            .client_noredirect
                            .borrow()
                            .get(extra.url().clone())
                            .send()
                            .expect("Couldn't fetch extra data");
                        let name = extra
                            .url()
                            .path_segments()
                            .unwrap()
                            .last()
                            .unwrap()
                            .to_string();
                        let n_path = folder_name.join(&name);
                        if fs::metadata(&n_path).is_ok() {
                            warn!("This extra has already been downloaded. Skipping.");
                            continue;
                        } else {
                            return Err(temp_response.err().unwrap().into());
                        }
                        println!("Starting download of {}", name);
                        let pb = ProgressBar::new(extra.content_length().unwrap());
                        pb.set_style(ProgressStyle::default_bar()
                                         .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")
                                         .progress_chars("#>-"));
                        let mut pb_read = pb.wrap_read(real_response);
                        let mut file = File::create(n_path).expect("Couldn't create file");
                        io::copy(&mut pb_read, &mut file).expect("Couldn't copy to target file");
                        pb.finish();
                    }
                } else {
                    error!("Could not search for games.")
                    Ok(response)
                })
                .collect();
            for extra in extra_responses.into_iter() {
                let mut extra = extra.expect("Couldn't fetch extra");
                let mut real_response = gog
                    .client_noredirect
                    .borrow()
                    .get(extra.url().clone())
                    .send()
                    .expect("Couldn't fetch extra data");
                let name = extra
                    .url()
                    .path_segments()
                    .unwrap()
                    .last()
                    .unwrap()
                    .to_string();
                let n_path = folder_name.join(&name);
                if fs::metadata(&n_path).is_ok() {
                    warn!("This extra has already been downloaded. Skipping.");
                    continue;
                }
            } else {
                error!("Did not specify a game.");
                println!("Starting download of {}", name);
                let pb = ProgressBar::new(extra.content_length().unwrap());
                pb.set_style(ProgressStyle::default_bar()
                                         .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")
                                         .progress_chars("#>-"));
                let mut pb_read = pb.wrap_read(real_response);
                let mut file = File::create(n_path).expect("Couldn't create file");
                io::copy(&mut pb_read, &mut file).expect("Couldn't copy to target file");
                pb.finish();
            }
        }
        Interactive => {