diff --git a/Cargo.lock b/Cargo.lock index 89d08ed..8ffb507 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -837,7 +837,9 @@ dependencies = [ [[package]] name = "steam_shortcuts_util" -version = "1.0.0" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c2fce148525a785a93daaf7b41855fa1a2ba05052bab74f647b56256b2d3a8" dependencies = [ "ascii", "crc32fast", @@ -847,7 +849,9 @@ dependencies = [ [[package]] name = "steamgriddb_api" -version = "0.1.3" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49989dd0a9cb16bc02ea1939b513e310fcdbc31d52981d8c70bcb86a23b12d5f" dependencies = [ "reqwest", "serde", diff --git a/Cargo.toml b/Cargo.toml index e8d3d0c..e090c5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,8 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -steam_shortcuts_util={version="*", path="C:/src/Rust/steam_shortcuts_util"} -steamgriddb_api={version="*", path="C:/src/Rust/steamgriddb_api"} +steam_shortcuts_util="1.1.0" +steamgriddb_api="0.2,0" serde={version="*", features=["derive"]} serde_json="*" tokio = { version = "1.11.0", features = ["full"] } diff --git a/src/egs/get_manifests.rs b/src/egs/get_manifests.rs index 83ea96c..7d4d7cd 100644 --- a/src/egs/get_manifests.rs +++ b/src/egs/get_manifests.rs @@ -9,7 +9,6 @@ pub fn get_egs_manifests() -> Result, Box> { let manifest_dir_path = get_manifest_dir_path()?; let manifest_dir_result = std::fs::read_dir(&manifest_dir_path); if let Err(err) = manifest_dir_result { - //TODO make a new error type here instead println!("Could not find manifest directory: {}", manifest_dir_path); return Result::Err(Box::new(err)); } diff --git a/src/egs/manifest_item.rs b/src/egs/manifest_item.rs index 6c4e88c..28ec2cc 100644 --- a/src/egs/manifest_item.rs +++ b/src/egs/manifest_item.rs @@ -1,5 +1,5 @@ - use serde::{Deserialize, Serialize}; +use steam_shortcuts_util::{Shortcut, shortcut::ShortcutOwned}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ManifestItem { @@ -18,3 +18,31 @@ pub struct ManifestItem { #[serde(alias = "AppName")] pub app_name: String, } + +impl From<&ManifestItem> for ShortcutOwned { + fn from(manifest: &ManifestItem) -> Self { + let exe = format!( + "\"{}\\{}\"", + manifest.install_location, manifest.launch_executable + ); + let mut start_dir = manifest.install_location.clone(); + if !manifest.install_location.starts_with("\"") { + start_dir = format!("\"{}\"", manifest.install_location); + } + let shortcut = Shortcut::new( + 0, + manifest.display_name.as_str(), + exe.as_str(), + start_dir.as_str(), + "", + "", + "", + ); + let mut owned_shortcut = shortcut.to_owned(); + owned_shortcut.tags.push("EGS".to_owned()); + owned_shortcut.tags.push("Ready TO Play".to_owned()); + owned_shortcut.tags.push("Installed".to_owned()); + + owned_shortcut + } +} diff --git a/src/legendary/get_legendary_games.rs b/src/legendary/get_legendary_games.rs new file mode 100644 index 0000000..ea4d18d --- /dev/null +++ b/src/legendary/get_legendary_games.rs @@ -0,0 +1,14 @@ +use super::legendary_game::LegendaryGame; +use serde_json::from_str; +use std::process::Command; +use std::{error::Error}; + +pub fn get_legendary_games() -> Result, Box> { + let legendary_command = Command::new("legendary") + .arg("list-installed") + .arg("--json") + .output()?; + let json = String::from_utf8_lossy(&legendary_command.stdout); + let legendary_ouput = from_str(&json)?; + Ok(legendary_ouput) +} \ No newline at end of file diff --git a/src/legendary/legendary_game.rs b/src/legendary/legendary_game.rs new file mode 100644 index 0000000..451c5cf --- /dev/null +++ b/src/legendary/legendary_game.rs @@ -0,0 +1,38 @@ +use serde::{Deserialize, Serialize}; +use steam_shortcuts_util::{shortcut::ShortcutOwned, Shortcut}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct LegendaryGame { + pub app_name: String, + pub can_run_offline: bool, + pub title: String, + pub is_dlc: bool, + pub install_path: String, + pub executable: String, +} + +impl From<&LegendaryGame> for ShortcutOwned { + fn from(game: &LegendaryGame) -> Self { + let exe = format!("\"{}\\{}\"", game.install_path, game.executable); + let launch = format!("legendary launch {}", game.app_name); + let mut start_dir = game.install_path.clone(); + if !game.install_path.starts_with("\"") { + start_dir = format!("\"{}\"", game.install_path); + } + let shortcut = Shortcut::new( + 0, + game.title.as_str(), + launch.as_str(), + start_dir.as_str(), + exe.as_str(), + "", + "", + ); + let mut owned_shortcut = shortcut.to_owned(); + owned_shortcut.tags.push("Legendary".to_owned()); + owned_shortcut.tags.push("Ready TO Play".to_owned()); + owned_shortcut.tags.push("Installed".to_owned()); + + owned_shortcut + } +} diff --git a/src/legendary/mod.rs b/src/legendary/mod.rs new file mode 100644 index 0000000..d494711 --- /dev/null +++ b/src/legendary/mod.rs @@ -0,0 +1,5 @@ +mod legendary_game; +mod get_legendary_games; + +pub use get_legendary_games::*; +pub use legendary_game::*; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 8daa112..fe8ddbf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,8 @@ use std::{ }; mod cached_search; mod egs; +mod legendary; +use crate::legendary::get_legendary_games; use egs::{get_egs_manifests, ManifestItem}; use std::error::Error; use steam_shortcuts_util::{ @@ -22,14 +24,10 @@ pub struct ShortcutInfo { pub shortcuts: Vec, } - - fn get_shortcuts_for_user(user: &SteamUsersInfo) -> ShortcutInfo { let mut shortcuts = vec![]; let mut new_path = user.shortcut_path.clone(); if let Some(shortcut_path) = &user.shortcut_path { - // std::fs::remove_file(path) - //TODO remove unwrap let content = std::fs::read(shortcut_path).unwrap(); shortcuts = parse_shortcuts(content.as_slice()) .unwrap() @@ -60,27 +58,74 @@ fn get_shortcuts_for_user(user: &SteamUsersInfo) -> ShortcutInfo { #[tokio::main] async fn main() -> Result<(), Box> { - + 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"); + return Ok(()); + } + let client = steamgriddb_api::Client::new(auth_key); let mut search = CachedSearch::new(&client); - let egs_manifests = get_egs_manifests()?; - let egs_shortcuts: Vec = - egs_manifests.iter().map(manifest_to_shortcut).collect(); - println!("Found {} installed EGS Games", egs_manifests.len()); + #[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![] + } + }; + let egs_shortcuts: Vec = 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 = { + let legendary_games = match get_legendary_games() { + Ok(games) => games, + Err(e) => { + println!("Error getting legendary games: {}", e); + vec![] + } + }; + let legendary_shortcuts: Vec = + legendary_games.iter().map(|f| f.into()).collect(); + println!( + "Found {} installed Legendary Games", + legendary_shortcuts.len() + ); + legendary_shortcuts + }; let userinfo_shortcuts = get_shortcuts_paths()?; println!("Found {} user(s)", userinfo_shortcuts.len()); for user in userinfo_shortcuts.iter() { let shortcut_info = get_shortcuts_for_user(user); + + #[cfg(target_os = "windows")] let new_user_shortcuts: Vec<&ShortcutOwned> = shortcut_info .shortcuts .iter() .filter(|user_shortcut| !user_shortcut.tags.contains(&"EGS".to_owned())) .chain(egs_shortcuts.iter()) .collect(); + #[cfg(target_os = "linux")] + let new_user_shortcuts: Vec<&ShortcutOwned> = shortcut_info + .shortcuts + .iter() + .filter(|user_shortcut| !user_shortcut.tags.contains(&"Legendary".to_owned())) + .chain(legendary_shortcuts.iter()) + .collect(); let shortcuts = new_user_shortcuts.iter().map(|f| f.borrow()).collect(); @@ -104,14 +149,12 @@ async fn main() -> Result<(), Box> { let mut search_results = HashMap::new(); for s in shortcuts_to_search_for { println!("Searching for {}", s.app_name); - let search = search.search(s.app_id,s.app_name).await?; + let search = search.search(s.app_id, s.app_name).await?; if let Some(search) = search { search_results.insert(s.app_id, search); } } - - let types = vec![ImageType::Logo, ImageType::Hero, ImageType::Grid]; for image_type in types { let mut images_needed = shortcuts @@ -180,7 +223,6 @@ impl ImageType { } } - fn get_users_images(user: &SteamUsersInfo) -> Result, Box> { let grid_folder = Path::new(user.steam_user_data_folder.as_str()).join("config/grid"); std::fs::create_dir_all(&grid_folder)?; @@ -192,32 +234,6 @@ fn get_users_images(user: &SteamUsersInfo) -> Result, Box Ok(file_names) } -fn manifest_to_shortcut(manifest: &ManifestItem) -> ShortcutOwned { - let exe = format!( - "\"{}\\{}\"", - manifest.install_location, manifest.launch_executable - ); - let mut start_dir = manifest.install_location.clone(); - if !manifest.install_location.starts_with("\"") { - start_dir = format!("\"{}\"", manifest.install_location); - } - let shortcut = Shortcut::new( - 0, - manifest.display_name.as_str(), - exe.as_str(), - start_dir.as_str(), - "", - "", - "", - ); - let mut owned_shortcut = shortcut.to_owned(); - owned_shortcut.tags.push("EGS".to_owned()); - owned_shortcut.tags.push("Ready TO Play".to_owned()); - owned_shortcut.tags.push("Installed".to_owned()); - - owned_shortcut -} - #[derive(Debug)] struct SteamFolderNotFound { location_tried: String, @@ -267,12 +283,21 @@ struct SteamUsersInfo { /// Get the paths to the steam users shortcuts (one for each user) fn get_shortcuts_paths() -> Result, Box> { - let key = "PROGRAMFILES(X86)"; - let program_files = env::var(key)?; - let path_string = format!( - "{program_files}//Steam//userdata//", - program_files = program_files - ); + #[cfg(target_os = "windows")] + let path_string = { + let key = "PROGRAMFILES(X86)"; + let program_files = env::var(key)?; + format!( + "{program_files}//Steam//userdata//", + program_files = program_files + ) + }; + #[cfg(target_os = "linux")] + let path_string = { + let home = std::env::var("HOME")?; + format!("{}/.steam/steam/userdata/", home) + }; + let user_data_path = Path::new(path_string.as_str()); if !user_data_path.exists() { return Result::Err(Box::new(SteamFolderNotFound {