Merge branch '1-filters' into 'master'
Add operating system and language filtering. Closes #1 See merge request !1
This commit is contained in:
commit
768e0a1408
12
README.md
12
README.md
@ -26,6 +26,8 @@ about content hashes.
|
||||
|
||||
If you want to see the information log while running set `RUST_LOG=info`.
|
||||
|
||||
---
|
||||
|
||||
```
|
||||
gog-sync
|
||||
```
|
||||
@ -33,8 +35,18 @@ gog-sync
|
||||
Normal invocation, uses the current working directory as storage if not configured
|
||||
otherwise.
|
||||
|
||||
---
|
||||
|
||||
```
|
||||
gog-sync -s ~/Downloads/games
|
||||
```
|
||||
|
||||
Overwrite the default or configured storage path.
|
||||
|
||||
---
|
||||
|
||||
```
|
||||
gog-sync -l english -o linux,windows
|
||||
```
|
||||
|
||||
Only sync english installers and only for linux and windows systems.
|
||||
|
43
src/gog.rs
43
src/gog.rs
@ -107,7 +107,11 @@ impl<'a> Gog<'a> {
|
||||
|
||||
/// Syncs the contents of a gog account with a local folder.
|
||||
/// Uses a hash to figure out whether something has changed.
|
||||
pub fn sync(&mut self, storage_path: &str) -> Result<(), GogError> {
|
||||
pub fn sync(&mut self,
|
||||
storage_path: &str,
|
||||
os_filters: &Vec<String>,
|
||||
language_filters: &Vec<String>)
|
||||
-> Result<(), GogError> {
|
||||
let configfiles = ConfigFiles::new();
|
||||
let mut config: Config = match configfiles.load("config.json") {
|
||||
Ok(value) => value,
|
||||
@ -119,6 +123,8 @@ impl<'a> Gog<'a> {
|
||||
games: HashMap::new(),
|
||||
installers: HashMap::new(),
|
||||
extras: HashMap::new(),
|
||||
os_filters: os_filters.clone(),
|
||||
language_filters: language_filters.clone(),
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -131,7 +137,7 @@ impl<'a> Gog<'a> {
|
||||
None => u64::min_value(),
|
||||
};
|
||||
|
||||
let game = self.get_game(game_id)?;
|
||||
let game = self.get_game(game_id, &os_filters, &language_filters)?;
|
||||
let game_hash = models::get_hash(&game);
|
||||
|
||||
if game_hash_saved == game_hash {
|
||||
@ -147,6 +153,7 @@ impl<'a> Gog<'a> {
|
||||
let mut key_file = File::create(&key_path)?;
|
||||
key_file.write_all(game.cd_key.as_bytes())?
|
||||
}
|
||||
|
||||
for installer in game.installers {
|
||||
let installer_hash_saved = match config.installers.get(&installer.manual_url) {
|
||||
Some(value) => value.clone(),
|
||||
@ -174,10 +181,11 @@ impl<'a> Gog<'a> {
|
||||
}
|
||||
|
||||
for extra in game.extras {
|
||||
let extra_hash_saved = match config.installers.get(&extra.manual_url) {
|
||||
let extra_hash_saved = match config.extras.get(&extra.manual_url) {
|
||||
Some(value) => value.clone(),
|
||||
None => u64::min_value(),
|
||||
};
|
||||
|
||||
let extra_hash = models::get_hash(&extra);
|
||||
|
||||
if extra_hash_saved == extra_hash {
|
||||
@ -270,6 +278,8 @@ impl<'a> Gog<'a> {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The numbers in this list are excluded because they refer to
|
||||
// favourites, promotions and such.
|
||||
if [1, 2, 3, 4, 5].contains(&game_id_parsed) {
|
||||
continue;
|
||||
}
|
||||
@ -280,7 +290,11 @@ impl<'a> Gog<'a> {
|
||||
return Ok(game_ids);
|
||||
}
|
||||
|
||||
fn get_game(&mut self, game_id: u64) -> Result<Game, GogError> {
|
||||
fn get_game(&mut self,
|
||||
game_id: u64,
|
||||
os_filters: &Vec<String>,
|
||||
language_filters: &Vec<String>)
|
||||
-> Result<Game, GogError> {
|
||||
let game_uri = self.game_uri(game_id);
|
||||
|
||||
let response = self.http_client.get(game_uri.as_str())?;
|
||||
@ -298,17 +312,30 @@ impl<'a> Gog<'a> {
|
||||
}
|
||||
|
||||
let installer_language = match language[0].as_str() {
|
||||
Some(value) => value,
|
||||
None => "",
|
||||
Some(value) => value.to_lowercase(),
|
||||
None => String::default(),
|
||||
};
|
||||
|
||||
if installer_language == "" {
|
||||
if installer_language.is_empty() {
|
||||
error!("Skipping a language for {}", game.title);
|
||||
continue;
|
||||
}
|
||||
|
||||
if !language_filters.is_empty() && !language_filters.contains(&installer_language) {
|
||||
info!("Skipping {} for {}", &installer_language, game.title);
|
||||
continue;
|
||||
}
|
||||
|
||||
for systems in language[1].as_object() {
|
||||
for system in systems.keys() {
|
||||
if !os_filters.is_empty() && !os_filters.contains(system) {
|
||||
info!("Skipping {} {} for {}",
|
||||
&installer_language,
|
||||
system,
|
||||
game.title);
|
||||
continue;
|
||||
}
|
||||
|
||||
for real_downloads in systems.get(system) {
|
||||
for real_download in real_downloads.as_array() {
|
||||
for download in real_download {
|
||||
@ -326,7 +353,7 @@ impl<'a> Gog<'a> {
|
||||
.as_str()
|
||||
.unwrap_or("")),
|
||||
os: system.clone(),
|
||||
language: String::from(installer_language),
|
||||
language: installer_language.clone(),
|
||||
};
|
||||
|
||||
game.installers.push(installer);
|
||||
|
40
src/main.rs
40
src/main.rs
@ -9,7 +9,10 @@
|
||||
//! -V, --version Prints version information
|
||||
//!
|
||||
//! OPTIONS:
|
||||
//! -s, --storage <FOLDER> Sets the download folder (defaults to the working directory).
|
||||
//! -l, --language <FILTER> Only sync files for this comma seperated list of languages.
|
||||
//! -o, --os <FILTER> Only sync files for this comma seperated list of operating systems.
|
||||
//! Valid values are 'linux', 'mac' and 'windows'.
|
||||
//! -s, --storage <FOLDER> Sets the download folder (defaults to the working directory).
|
||||
//! ```
|
||||
|
||||
extern crate chrono;
|
||||
@ -35,7 +38,6 @@ use clap::{Arg, App};
|
||||
use gog::Gog;
|
||||
use http::Http;
|
||||
use models::Config;
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn main() {
|
||||
env_logger::init().unwrap();
|
||||
@ -50,19 +52,25 @@ fn main() {
|
||||
.value_name("FOLDER")
|
||||
.help("Sets the download folder (defaults to the working directory).")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("os")
|
||||
.short("o")
|
||||
.long("os")
|
||||
.value_name("FILTER")
|
||||
.help("Only sync files for this comma seperated list of operating systems.\n\
|
||||
Valid values are 'linux', 'mac' and 'windows'.")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("language")
|
||||
.short("l")
|
||||
.long("language")
|
||||
.value_name("FILTER")
|
||||
.help("Only sync files for this comma seperated list of languages.")
|
||||
.takes_value(true))
|
||||
.get_matches();
|
||||
|
||||
let configfiles = ConfigFiles::new();
|
||||
let config: Config = match configfiles.load("config.json") {
|
||||
Ok(value) => value,
|
||||
Err(_) => {
|
||||
Config {
|
||||
storage: String::from("."),
|
||||
games: HashMap::new(),
|
||||
installers: HashMap::new(),
|
||||
extras: HashMap::new(),
|
||||
}
|
||||
}
|
||||
Err(_) => Config::new(),
|
||||
};
|
||||
|
||||
let download_folder: &str = match matches.value_of("storage") {
|
||||
@ -70,8 +78,18 @@ fn main() {
|
||||
None => config.storage.as_str(),
|
||||
};
|
||||
|
||||
let os_filters: Vec<String> = match matches.value_of("os") {
|
||||
Some(value) => value.split(',').map(String::from).collect(),
|
||||
None => config.os_filters,
|
||||
};
|
||||
|
||||
let language_filters: Vec<String> = match matches.value_of("language") {
|
||||
Some(value) => value.split(',').map(String::from).collect(),
|
||||
None => config.language_filters,
|
||||
};
|
||||
|
||||
let mut http_client = Http::new();
|
||||
let mut gog = Gog::new(&mut http_client);
|
||||
gog.login().unwrap();
|
||||
gog.sync(download_folder).unwrap();
|
||||
gog.sync(download_folder, &os_filters, &language_filters).unwrap();
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ fn timestamp() -> i64 {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Config {
|
||||
pub storage: String,
|
||||
#[serde(default = "default_map")]
|
||||
@ -38,12 +39,33 @@ pub struct Config {
|
||||
pub installers: HashMap<String, u64>,
|
||||
#[serde(default = "default_map")]
|
||||
pub extras: HashMap<String, u64>,
|
||||
#[serde(default = "default_list")]
|
||||
pub os_filters: Vec<String>,
|
||||
#[serde(default = "default_list")]
|
||||
pub language_filters: Vec<String>,
|
||||
}
|
||||
|
||||
fn default_map() -> HashMap<String, u64> {
|
||||
HashMap::new()
|
||||
}
|
||||
|
||||
fn default_list() -> Vec<String> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new() -> Config {
|
||||
Config {
|
||||
storage: String::from("."),
|
||||
games: HashMap::new(),
|
||||
installers: HashMap::new(),
|
||||
extras: HashMap::new(),
|
||||
os_filters: Vec::new(),
|
||||
language_filters: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
Loading…
Reference in New Issue
Block a user