use seperate info files
This commit is contained in:
parent
a8be23508c
commit
dcbd44a752
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1,6 +1,6 @@
|
||||
[root]
|
||||
name = "gog-sync"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
dependencies = [
|
||||
"chrono 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -13,6 +13,7 @@ use std;
|
||||
use std::io::{Read, Write};
|
||||
use xdg;
|
||||
use xdg::BaseDirectories;
|
||||
use std::path::Path;
|
||||
|
||||
/// Wraps `std::io::Error` and `serde_json::Error`.
|
||||
#[derive(Debug)]
|
||||
@ -116,4 +117,30 @@ impl ConfigFiles {
|
||||
Err(error) => Err(ConfigError::IOError(error)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save_to_path<T>(path: &Path, content: &T) -> Result<(), ConfigError>
|
||||
where T: Serialize
|
||||
{
|
||||
let content_toml = serde_json::to_string_pretty(content)?;
|
||||
|
||||
let mut config_file = File::create(path)?;
|
||||
match config_file.write_all(content_toml.as_bytes()) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(error) => Err(ConfigError::IOError(error)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_from_path<T>(path: &Path) -> Result<T, ConfigError>
|
||||
where T: Deserialize
|
||||
{
|
||||
let mut file = File::open(path)?;
|
||||
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
|
||||
match serde_json::from_str(contents.as_str()) {
|
||||
Ok(value) => Ok(value),
|
||||
Err(error) => Err(ConfigError::SerdeJsonError(error)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
97
src/gog.rs
97
src/gog.rs
@ -13,7 +13,7 @@
|
||||
use configfiles::{ConfigFiles, ConfigError};
|
||||
use http::{Http, HttpError};
|
||||
use models;
|
||||
use models::{Token, Content, Data, Config};
|
||||
use models::{Token, Content, ContentInfo, DataInfo, ExtraInfo, Data};
|
||||
use serde_json;
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
@ -130,35 +130,9 @@ impl<'a> Gog<'a> {
|
||||
skip_movies: bool,
|
||||
skip_games: bool)
|
||||
-> Result<(), GogError> {
|
||||
let configfiles = ConfigFiles::new();
|
||||
let mut config: Config = match configfiles.load("config.json") {
|
||||
Ok(value) => value,
|
||||
Err(_) => {
|
||||
error!("Configuration error, generating new one");
|
||||
|
||||
Config {
|
||||
game_storage: String::from(storage_path),
|
||||
movie_storage: String::from(storage_path_movies),
|
||||
content: HashMap::new(),
|
||||
data: HashMap::new(),
|
||||
extras: HashMap::new(),
|
||||
os_filters: os_filters.clone(),
|
||||
language_filters: language_filters.clone(),
|
||||
resolution_filters: resolution_filters.clone(),
|
||||
skip_movies: skip_movies,
|
||||
skip_games: skip_games,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let content_ids = self.get_content_ids()?;
|
||||
|
||||
for content_id in content_ids {
|
||||
let content_hash_saved = match config.content.get(&content_id.to_string()) {
|
||||
Some(value) => value.clone(),
|
||||
None => u64::min_value(),
|
||||
};
|
||||
|
||||
let content = match self.get_content(content_id,
|
||||
&os_filters,
|
||||
&language_filters,
|
||||
@ -170,6 +144,20 @@ impl<'a> Gog<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let content_root = if content.is_movie {
|
||||
Path::new(storage_path_movies).join(&content.title)
|
||||
} else {
|
||||
Path::new(storage_path).join(&content.title)
|
||||
};
|
||||
|
||||
let content_info_path = Path::new(&content_root).join("info.json");
|
||||
|
||||
let content_info_saved =
|
||||
match ConfigFiles::load_from_path::<ContentInfo>(&content_info_path) {
|
||||
Ok(value) => value,
|
||||
Err(_) => ContentInfo::new(),
|
||||
};
|
||||
|
||||
if (content.is_movie && skip_movies) || (!content.is_movie && skip_games) {
|
||||
info!("filtering {}", content.title);
|
||||
continue;
|
||||
@ -177,18 +165,23 @@ impl<'a> Gog<'a> {
|
||||
|
||||
let content_hash = models::get_hash(&content);
|
||||
|
||||
if content_hash_saved == content_hash {
|
||||
if content_info_saved.hash == content_hash {
|
||||
info!("{} already up to date.", &content.title);
|
||||
continue;
|
||||
}
|
||||
|
||||
let content_root = if content.is_movie {
|
||||
Path::new(storage_path_movies).join(&content.title)
|
||||
} else {
|
||||
Path::new(storage_path).join(&content.title)
|
||||
fs::create_dir_all(&content_root)?;
|
||||
|
||||
let mut content_info = ContentInfo {
|
||||
hash: content_hash,
|
||||
id: content_id,
|
||||
title: content.title.clone(),
|
||||
cd_keys: content.cd_keys.clone(),
|
||||
data: HashMap::new(),
|
||||
extras: HashMap::new(),
|
||||
};
|
||||
|
||||
fs::create_dir_all(&content_root)?;
|
||||
ConfigFiles::save_to_path(&content_info_path, &content_info)?;
|
||||
|
||||
let key_root = content_root.join("keys");
|
||||
|
||||
@ -203,10 +196,11 @@ impl<'a> Gog<'a> {
|
||||
}
|
||||
|
||||
for data in content.data {
|
||||
let data_hash_saved = match config.data.get(&data.manual_url) {
|
||||
Some(value) => value.clone(),
|
||||
let data_hash_saved = match content_info_saved.data.get(&content_id.to_string()) {
|
||||
Some(value) => value.hash,
|
||||
None => u64::min_value(),
|
||||
};
|
||||
|
||||
let data_hash = models::get_hash(&data);
|
||||
|
||||
if data_hash_saved == data_hash {
|
||||
@ -220,15 +214,22 @@ impl<'a> Gog<'a> {
|
||||
let data_uri = format!("https://embed.gog.com{}", data.manual_url);
|
||||
|
||||
info!("downloading {} for {}...", &data.manual_url, &content.title);
|
||||
self.http_client.download(data_uri.as_str(), &data_root)?;
|
||||
let filename = self.http_client.download(data_uri.as_str(), &data_root)?;
|
||||
|
||||
config.data.insert(data.manual_url, data_hash);
|
||||
configfiles.save("config.json", &config)?;
|
||||
let data_info = DataInfo {
|
||||
hash: data_hash,
|
||||
filename: filename,
|
||||
language: data.language,
|
||||
};
|
||||
|
||||
content_info.data.insert(data.manual_url.clone(), data_info);
|
||||
ConfigFiles::save_to_path(&content_info_path, &content_info)?;
|
||||
}
|
||||
|
||||
for extra in content.extras {
|
||||
let extra_hash_saved = match config.extras.get(&extra.manual_url) {
|
||||
Some(value) => value.clone(),
|
||||
let extra_hash_saved = match content_info_saved.extras
|
||||
.get(&content_id.to_string()) {
|
||||
Some(value) => value.hash,
|
||||
None => u64::min_value(),
|
||||
};
|
||||
|
||||
@ -242,14 +243,17 @@ impl<'a> Gog<'a> {
|
||||
let extra_uri = format!("https://embed.gog.com{}", extra.manual_url);
|
||||
|
||||
info!("downloading {} for {}...", &extra.name, &content.title);
|
||||
self.http_client.download(extra_uri.as_str(), &content_root)?;
|
||||
let filename = self.http_client.download(extra_uri.as_str(), &content_root)?;
|
||||
|
||||
config.extras.insert(extra.manual_url, extra_hash);
|
||||
configfiles.save("config.json", &config)?;
|
||||
let extra_info = ExtraInfo {
|
||||
hash: extra_hash,
|
||||
filename: filename,
|
||||
name: extra.name,
|
||||
};
|
||||
|
||||
content_info.extras.insert(extra.manual_url.clone(), extra_info);
|
||||
ConfigFiles::save_to_path(&content_info_path, &content_info)?;
|
||||
}
|
||||
|
||||
config.content.insert(content_id.to_string(), content_hash);
|
||||
configfiles.save("config.json", &config)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -390,6 +394,7 @@ impl<'a> Gog<'a> {
|
||||
debug!("found {:?}", &content_raw);
|
||||
|
||||
let mut content: Content = serde_json::from_str(&response)?;
|
||||
content.id = content_id;
|
||||
|
||||
let downloads = &content_raw["downloads"];
|
||||
|
||||
|
@ -131,7 +131,7 @@ impl Http {
|
||||
|
||||
/// Download a file to the specified folder without creating the folder.
|
||||
///
|
||||
/// The filename is taken from the last URI segment.
|
||||
/// The filename is taken from the last URI segment and returned in the result.
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use http::Http;
|
||||
@ -145,7 +145,7 @@ impl Http {
|
||||
pub fn download(&mut self,
|
||||
download_uri: &str,
|
||||
download_dir: &PathBuf)
|
||||
-> Result<(), HttpError> {
|
||||
-> Result<String, HttpError> {
|
||||
let download_path_tmp = Path::new(download_dir.as_os_str()).join(".progress");
|
||||
let mut file_download = File::create(&download_path_tmp)?;
|
||||
|
||||
@ -185,6 +185,6 @@ impl Http {
|
||||
Err(error) => Err(HttpError::IOError(error)),
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
Ok(file_name.to_owned())
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +84,8 @@ impl Config {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Content {
|
||||
#[serde(skip_deserializing)]
|
||||
pub id: u64,
|
||||
pub title: String,
|
||||
#[serde(skip_deserializing)]
|
||||
#[serde(rename(deserialize = "cdKey"))]
|
||||
@ -101,6 +103,47 @@ impl fmt::Display for Content {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ContentInfo {
|
||||
#[serde(skip_deserializing)]
|
||||
pub id: u64,
|
||||
pub hash: u64,
|
||||
pub title: String,
|
||||
pub cd_keys: BTreeMap<String, String>,
|
||||
pub data: HashMap<String, DataInfo>,
|
||||
pub extras: HashMap<String, ExtraInfo>,
|
||||
}
|
||||
|
||||
impl ContentInfo {
|
||||
pub fn new() -> ContentInfo {
|
||||
ContentInfo {
|
||||
id: 0,
|
||||
hash: 0,
|
||||
title: String::new(),
|
||||
cd_keys: BTreeMap::new(),
|
||||
data: HashMap::new(),
|
||||
extras: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DataInfo {
|
||||
pub hash: u64,
|
||||
pub filename: String,
|
||||
pub language: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExtraInfo {
|
||||
pub hash: u64,
|
||||
pub filename: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Hash)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
Loading…
Reference in New Issue
Block a user