Add settings for EGS and SteamgridDB

This commit is contained in:
Philip Kristoffersen
2021-09-25 00:36:09 +02:00
parent 60dd680c33
commit 99079dcaff
13 changed files with 307 additions and 66 deletions
+2 -1
View File
@@ -1,3 +1,4 @@
/target
auth_key.txt
cache.json
cache.json
config.toml
Generated
+93
View File
@@ -2,6 +2,21 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "0.7.15"
@@ -29,6 +44,21 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "backtrace"
version = "0.3.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "base64"
version = "0.13.0"
@@ -133,6 +163,28 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "failure"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
dependencies = [
"backtrace",
"failure_derive",
]
[[package]]
name = "failure_derive"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "fnv"
version = "1.0.7"
@@ -221,6 +273,12 @@ dependencies = [
"wasi",
]
[[package]]
name = "gimli"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
[[package]]
name = "h2"
version = "0.3.4"
@@ -450,6 +508,16 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c835948974f68e0bd58636fc6c5b1fbff7b297e3046f11b3b3c18bbac012c6d"
[[package]]
name = "miniz_oxide"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
dependencies = [
"adler",
"autocfg",
]
[[package]]
name = "mio"
version = "0.7.13"
@@ -572,6 +640,12 @@ dependencies = [
"libc",
]
[[package]]
name = "object"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
[[package]]
name = "once_cell"
version = "1.8.0"
@@ -806,6 +880,12 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
[[package]]
name = "rustc-demangle"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "ryu"
version = "1.0.5"
@@ -954,6 +1034,7 @@ name = "steam_shortcuts_sync"
version = "0.1.0"
dependencies = [
"config",
"failure",
"reqwest",
"serde 1.0.130",
"serde_json",
@@ -997,6 +1078,18 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "synstructure"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa"
dependencies = [
"proc-macro2",
"quote",
"syn",
"unicode-xid",
]
[[package]]
name = "tap"
version = "1.0.1"
+2 -1
View File
@@ -12,4 +12,5 @@ serde={version="*", features=["derive"]}
serde_json="*"
tokio = { version = "1.11.0", features = ["full"] }
reqwest = { version = "*", features = ["default"] }
config = "*"
config = "*"
failure = "*"
+85 -23
View File
@@ -1,39 +1,101 @@
use super::{EpicGamesLauncherSettings, ManifestItem};
use std::env::{self, VarError};
use std::error::Error;
use std::fs::{DirEntry, File};
use std::io::BufReader;
use std::path::Path;
use std::error::Error;
use super::ManifestItem;
pub fn get_egs_manifests() -> Result<Vec<ManifestItem>, Box<dyn Error>> {
let manifest_dir_path = get_manifest_dir_path()?;
use failure::*;
#[derive(Debug, Fail)]
pub enum EpicGamesManifestsError {
#[fail(display = "Path to EpicGamesLauncher not defined, it must be defined on linux")]
PathNotDefined,
#[fail(
display = "EpicGamesLauncher path: {} could not be found. Try to specify a different path for the EpicGamesLauncher.",
path
)]
PathNotFound { path: String },
#[fail(
display = "Could not read EpicGamesLauncher manifest directory at {} error: {}",
path, error
)]
ReadDirError { path: String, error: std::io::Error },
}
pub fn get_egs_manifests(
settings: &EpicGamesLauncherSettings,
) -> Result<Vec<ManifestItem>, EpicGamesManifestsError> {
use EpicGamesManifestsError::*;
let manifest_dir_path = get_manifest_dir_path(settings)?;
let manifest_dir_result = std::fs::read_dir(&manifest_dir_path);
if let Err(err) = manifest_dir_result {
println!("Could not find manifest directory: {}", manifest_dir_path);
return Result::Err(Box::new(err));
match manifest_dir_result {
Ok(manifest_dir) => {
let manifests = manifest_dir
.filter_map(|dir| dir.ok())
.filter_map(get_manifest_item)
.filter(is_game_installed);
Ok(manifests.collect())
}
Err(err) => Err(ReadDirError {
error: err,
path: manifest_dir_path,
}),
}
let manifest_dir = manifest_dir_result?;
let manifests = manifest_dir
.filter_map(|dir| dir.ok())
.filter_map(get_manifest_item)
.filter(is_game_installed);
Ok(manifests.collect())
}
fn get_manifest_dir_path() -> Result<String, VarError> {
let key = "SYSTEMDRIVE";
let system_drive = env::var(key)?;
Ok(format!(
"{system_drive}//ProgramData//Epic//EpicGamesLauncher//Data//Manifests",
system_drive = system_drive
))
fn get_manifest_dir_path(
settings: &EpicGamesLauncherSettings,
) -> Result<String, EpicGamesManifestsError> {
use EpicGamesManifestsError::*;
if let Some(location) = &settings.location {
let path = Path::new(location).join("Data").join("Manifests");
if path.exists() {
return Ok(path.to_str().unwrap().to_string());
} else {
return Err(PathNotFound {
path: path.to_str().unwrap().to_string(),
});
}
} else {
#[cfg(target_os = "linux")]
{
//No path defined for epic gamestore, and we cannot guess on linux
return Err(PathNotDefined);
}
#[cfg(target_os = "windows")]
{
let key = "SYSTEMDRIVE";
let system_drive =
env::var(key).expect("We are on windows, we must know what the SYSTEMDRIVE is");
let path = Path::new(system_drive.as_str())
.join("ProgramData")
.join("Epic")
.join("EpicGamesLauncher")
.join("Data")
.join("Manifests");
if path.exists() {
return Ok(path.to_str().unwrap().to_string());
} else {
return Err(PathNotFound {
path: path.to_str().unwrap().to_string(),
});
}
}
}
}
fn is_game_installed(manifest:&ManifestItem) -> bool{
Path::new(manifest.manifest_location.as_str()).exists()
fn is_game_installed(manifest: &ManifestItem) -> bool {
Path::new(manifest.manifest_location.as_str()).exists()
}
fn get_manifest_item(dir_entry: DirEntry) -> Option<ManifestItem> {
fn get_manifest_item(dir_entry: DirEntry) -> Option<ManifestItem> {
if let Some(extension) = dir_entry.path().extension() {
if extension.eq("item") {
if let Ok(file) = File::open(dir_entry.path()) {
+2 -1
View File
@@ -2,4 +2,5 @@ mod get_manifests;
mod manifest_item;
mod settings;
pub use manifest_item::*;
pub use get_manifests::get_egs_manifests;
pub use get_manifests::get_egs_manifests;
pub use settings::EpicGamesLauncherSettings;
+6 -6
View File
@@ -1,12 +1,12 @@
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct EpicGamesLauncher {
enabled: bool,
location: Option<String>,
pub struct EpicGamesLauncherSettings {
pub enabled: bool,
pub location: Option<String>,
}
impl Default for EpicGamesLauncher {
impl Default for EpicGamesLauncherSettings {
fn default() -> Self {
// On windows
@@ -16,11 +16,11 @@ impl Default for EpicGamesLauncher {
// On linux
// We can notguess, so lets not enable by default
// We can not guess, so lets not enable by default
#[cfg(target_os = "linux")]
let enabled = false;
EpicGamesLauncher {
EpicGamesLauncherSettings {
enabled,
location: None,
}
+3 -1
View File
@@ -1,5 +1,7 @@
mod legendary_game;
mod get_legendary_games;
mod settings;
pub use get_legendary_games::*;
pub use legendary_game::*;
pub use legendary_game::*;
pub use settings::*;
+16
View File
@@ -0,0 +1,16 @@
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct LegendarySettings {
pub enabled: bool,
pub executable: Option<String>,
}
impl Default for LegendarySettings {
fn default() -> Self {
Self {
enabled: true,
executable: None,
}
}
}
+25 -23
View File
@@ -9,9 +9,11 @@ use std::{
mod cached_search;
mod egs;
mod legendary;
mod settings;
mod steamgriddb;
mod platform;
use crate::legendary::get_legendary_games;
use crate::{legendary::get_legendary_games, settings::Settings};
use egs::{get_egs_manifests, ManifestItem};
use std::error::Error;
use steam_shortcuts_util::{
@@ -60,35 +62,35 @@ fn get_shortcuts_for_user(user: &SteamUsersInfo) -> ShortcutInfo {
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
if !Path::new("auth_key.txt").exists() {
println!("File auth_key.txt not found, the file has been created, please get a key from https://www.steamgriddb.com/ and copy it into auth_key.txt");
File::create(Path::new("auth_key.txt"))?;
return Ok(());
}
let auth_key = std::fs::read_to_string("auth_key.txt")?;
if auth_key.trim().is_empty() {
println!("File auth_key.txt is empty please get an API key from https://www.steamgriddb.com/ and paste it into auth_key.txt");
let settings = Settings::new()?;
let auth_key = settings.steamgrid_db.auth_key;
if settings.steamgrid_db.enabled && auth_key.is_none() {
println!("auth_key not found, please add it to the steamgrid_db settings ");
return Ok(());
}
let auth_key = auth_key.unwrap();
let client = steamgriddb_api::Client::new(auth_key);
let mut search = CachedSearch::new(&client);
#[cfg(target_os = "windows")]
let egs_shortcuts = {
let egs_manifests = match get_egs_manifests() {
Ok(manifests) => manifests,
Err(e) => {
println!("Error getting manifests: {}", e);
vec![]
}
if settings.epic_games.enabled {
let egs_shortcuts = {
let egs_manifests = match get_egs_manifests(&settings.epic_games) {
Ok(manifests) => manifests,
Err(e) => {
println!("Error getting manifests for Epic Games Store: {}", e);
vec![]
}
};
let egs_shortcuts: Vec<ShortcutOwned> =
egs_manifests.iter().map(|f| f.into()).collect();
println!("Found {} installed EGS Games", egs_manifests.len());
egs_shortcuts
};
let egs_shortcuts: Vec<ShortcutOwned> = egs_manifests.iter().map(|f| f.into()).collect();
println!("Found {} installed EGS Games", egs_manifests.len());
egs_shortcuts
};
}
#[cfg(target_os = "linux")]
let legendary_shortcuts = {
+13
View File
@@ -0,0 +1,13 @@
use crate::{egs::EpicGamesLauncherSettings, legendary::LegendarySettings};
pub enum Platform{
EpicGames{
settings: EpicGamesLauncherSettings,
},
Legendary{
settings: LegendarySettings
}
}
+57 -7
View File
@@ -1,18 +1,68 @@
use std::env;
use config::{ConfigError, Config, File, Environment};
use crate::{
egs::EpicGamesLauncherSettings, legendary::LegendarySettings, steamgriddb::SteamGridDbSettings,
};
use config::{Config, ConfigError, Environment, File};
use serde::Deserialize;
use std::{env, path::Path};
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Default)]
pub struct Settings {
debug: bool,
database: EpicGamesLauncher,
pub debug: bool,
pub epic_games: EpicGamesLauncherSettings,
pub legendary: LegendarySettings,
pub steamgrid_db: SteamGridDbSettings,
}
#[derive(Debug, Deserialize, Default)]
struct SettingsOptional {
pub debug: Option<bool>,
pub epic_games: Option<EpicGamesLauncherSettings>,
pub legendary: Option<LegendarySettings>,
pub steamgrid_db: Option<SteamGridDbSettings>,
}
impl From<SettingsOptional> for Settings {
fn from(optional: SettingsOptional) -> Self {
Self {
debug: optional.debug.unwrap_or(false),
epic_games: optional.epic_games.unwrap_or(Default::default()),
legendary: optional.legendary.unwrap_or(Default::default()),
steamgrid_db: optional.steamgrid_db.unwrap_or(Default::default()),
}
}
}
//https://github.com/JosefNemec/Playnite/tree/master/source/Plugins/OriginLibrary
//https://github.com/JosefNemec/Playnite/blob/master/source/Plugins/OriginLibrary/Origin.cs#L109
impl Settings {
pub fn new() -> Result<Self, ConfigError> {
let default = Self::default();
if !Path::new("config.toml").exists() {
return Ok(default);
}
let mut s = Config::new();
// Start off by merging in the "default" configuration file
s.merge(File::with_name("config.toml").required(false))?;
// Add in the current environment file
// Default to 'development' env
// Note that this file is _optional_
let env = env::var("RUN_MODE").unwrap_or_else(|_| "development".into());
s.merge(File::with_name(&format!("config/{}", env)).required(false))?;
// Add in a local configuration file
// This file shouldn't be checked in to git
s.merge(File::with_name("local.toml").required(false))?;
// Add in settings from the environment (with a prefix of STEAM_SYNC)
// Eg.. `STEAM_SYNC_DEBUG=1 ./target/app` would set the `debug` key
s.merge(Environment::with_prefix("steam_sync"))?;
// You can deserialize (and thus freeze) the entire configuration as
let optionals: SettingsOptional = s.try_into()?;
Ok(optionals.into())
}
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
mod settings;
pub use settings::*;
pub use settings::SteamGridDbSettings;
+2 -2
View File
@@ -1,12 +1,12 @@
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct SteamGridDb {
pub struct SteamGridDbSettings {
pub enabled: bool,
pub auth_key: Option<String>,
}
impl Default for SteamGridDb {
impl Default for SteamGridDbSettings {
fn default() -> Self {
Self {
enabled: true,