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`.
|
If you want to see the information log while running set `RUST_LOG=info`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
```
|
```
|
||||||
gog-sync
|
gog-sync
|
||||||
```
|
```
|
||||||
@ -33,8 +35,18 @@ gog-sync
|
|||||||
Normal invocation, uses the current working directory as storage if not configured
|
Normal invocation, uses the current working directory as storage if not configured
|
||||||
otherwise.
|
otherwise.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
```
|
```
|
||||||
gog-sync -s ~/Downloads/games
|
gog-sync -s ~/Downloads/games
|
||||||
```
|
```
|
||||||
|
|
||||||
Overwrite the default or configured storage path.
|
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.
|
/// Syncs the contents of a gog account with a local folder.
|
||||||
/// Uses a hash to figure out whether something has changed.
|
/// 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 configfiles = ConfigFiles::new();
|
||||||
let mut config: Config = match configfiles.load("config.json") {
|
let mut config: Config = match configfiles.load("config.json") {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
@ -119,6 +123,8 @@ impl<'a> Gog<'a> {
|
|||||||
games: HashMap::new(),
|
games: HashMap::new(),
|
||||||
installers: HashMap::new(),
|
installers: HashMap::new(),
|
||||||
extras: 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(),
|
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);
|
let game_hash = models::get_hash(&game);
|
||||||
|
|
||||||
if game_hash_saved == game_hash {
|
if game_hash_saved == game_hash {
|
||||||
@ -147,6 +153,7 @@ impl<'a> Gog<'a> {
|
|||||||
let mut key_file = File::create(&key_path)?;
|
let mut key_file = File::create(&key_path)?;
|
||||||
key_file.write_all(game.cd_key.as_bytes())?
|
key_file.write_all(game.cd_key.as_bytes())?
|
||||||
}
|
}
|
||||||
|
|
||||||
for installer in game.installers {
|
for installer in game.installers {
|
||||||
let installer_hash_saved = match config.installers.get(&installer.manual_url) {
|
let installer_hash_saved = match config.installers.get(&installer.manual_url) {
|
||||||
Some(value) => value.clone(),
|
Some(value) => value.clone(),
|
||||||
@ -174,10 +181,11 @@ impl<'a> Gog<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for extra in game.extras {
|
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(),
|
Some(value) => value.clone(),
|
||||||
None => u64::min_value(),
|
None => u64::min_value(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let extra_hash = models::get_hash(&extra);
|
let extra_hash = models::get_hash(&extra);
|
||||||
|
|
||||||
if extra_hash_saved == extra_hash {
|
if extra_hash_saved == extra_hash {
|
||||||
@ -270,6 +278,8 @@ impl<'a> Gog<'a> {
|
|||||||
continue;
|
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) {
|
if [1, 2, 3, 4, 5].contains(&game_id_parsed) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -280,7 +290,11 @@ impl<'a> Gog<'a> {
|
|||||||
return Ok(game_ids);
|
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 game_uri = self.game_uri(game_id);
|
||||||
|
|
||||||
let response = self.http_client.get(game_uri.as_str())?;
|
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() {
|
let installer_language = match language[0].as_str() {
|
||||||
Some(value) => value,
|
Some(value) => value.to_lowercase(),
|
||||||
None => "",
|
None => String::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if installer_language == "" {
|
if installer_language.is_empty() {
|
||||||
error!("Skipping a language for {}", game.title);
|
error!("Skipping a language for {}", game.title);
|
||||||
continue;
|
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 systems in language[1].as_object() {
|
||||||
for system in systems.keys() {
|
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_downloads in systems.get(system) {
|
||||||
for real_download in real_downloads.as_array() {
|
for real_download in real_downloads.as_array() {
|
||||||
for download in real_download {
|
for download in real_download {
|
||||||
@ -326,7 +353,7 @@ impl<'a> Gog<'a> {
|
|||||||
.as_str()
|
.as_str()
|
||||||
.unwrap_or("")),
|
.unwrap_or("")),
|
||||||
os: system.clone(),
|
os: system.clone(),
|
||||||
language: String::from(installer_language),
|
language: installer_language.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
game.installers.push(installer);
|
game.installers.push(installer);
|
||||||
|
38
src/main.rs
38
src/main.rs
@ -9,6 +9,9 @@
|
|||||||
//! -V, --version Prints version information
|
//! -V, --version Prints version information
|
||||||
//!
|
//!
|
||||||
//! OPTIONS:
|
//! OPTIONS:
|
||||||
|
//! -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).
|
//! -s, --storage <FOLDER> Sets the download folder (defaults to the working directory).
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
@ -35,7 +38,6 @@ use clap::{Arg, App};
|
|||||||
use gog::Gog;
|
use gog::Gog;
|
||||||
use http::Http;
|
use http::Http;
|
||||||
use models::Config;
|
use models::Config;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::init().unwrap();
|
env_logger::init().unwrap();
|
||||||
@ -50,19 +52,25 @@ fn main() {
|
|||||||
.value_name("FOLDER")
|
.value_name("FOLDER")
|
||||||
.help("Sets the download folder (defaults to the working directory).")
|
.help("Sets the download folder (defaults to the working directory).")
|
||||||
.takes_value(true))
|
.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();
|
.get_matches();
|
||||||
|
|
||||||
let configfiles = ConfigFiles::new();
|
let configfiles = ConfigFiles::new();
|
||||||
let config: Config = match configfiles.load("config.json") {
|
let config: Config = match configfiles.load("config.json") {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(_) => {
|
Err(_) => Config::new(),
|
||||||
Config {
|
|
||||||
storage: String::from("."),
|
|
||||||
games: HashMap::new(),
|
|
||||||
installers: HashMap::new(),
|
|
||||||
extras: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let download_folder: &str = match matches.value_of("storage") {
|
let download_folder: &str = match matches.value_of("storage") {
|
||||||
@ -70,8 +78,18 @@ fn main() {
|
|||||||
None => config.storage.as_str(),
|
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 http_client = Http::new();
|
||||||
let mut gog = Gog::new(&mut http_client);
|
let mut gog = Gog::new(&mut http_client);
|
||||||
gog.login().unwrap();
|
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)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub storage: String,
|
pub storage: String,
|
||||||
#[serde(default = "default_map")]
|
#[serde(default = "default_map")]
|
||||||
@ -38,12 +39,33 @@ pub struct Config {
|
|||||||
pub installers: HashMap<String, u64>,
|
pub installers: HashMap<String, u64>,
|
||||||
#[serde(default = "default_map")]
|
#[serde(default = "default_map")]
|
||||||
pub extras: HashMap<String, u64>,
|
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> {
|
fn default_map() -> HashMap<String, u64> {
|
||||||
HashMap::new()
|
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(Hash)]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
Loading…
Reference in New Issue
Block a user