diff --git a/Cargo.lock b/Cargo.lock index 15478d2..32e30c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -25,6 +34,9 @@ name = "anyhow" version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +dependencies = [ + "backtrace", +] [[package]] name = "async-channel" @@ -43,6 +55,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64ct" version = "1.5.3" @@ -464,12 +491,15 @@ dependencies = [ [[package]] name = "geezshade" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", "copypasta", "isahc", "native-dialog", + "semver", + "serde", + "serde_json", "zip", ] @@ -494,6 +524,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" + [[package]] name = "hmac" version = "0.12.1" @@ -759,6 +795,15 @@ dependencies = [ "objc", ] +[[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.17.0" @@ -933,6 +978,18 @@ dependencies = [ "thiserror", ] +[[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.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + [[package]] name = "schannel" version = "0.1.21" @@ -948,11 +1005,42 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +[[package]] +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" + [[package]] name = "serde" version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] [[package]] name = "sha1" diff --git a/Cargo.toml b/Cargo.toml index 8965a84..32874f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,12 +2,15 @@ name = "geezshade" description = "Automated ReShade setup for FFXIV with GShade presets" authors = ["NotNite "] -version = "0.1.0" +version = "0.2.0" edition = "2021" [dependencies] -anyhow = "1.0.68" +anyhow = { version = "1.0.68", features = ["backtrace"] } copypasta = "0.8.1" isahc = "1.7.2" native-dialog = "0.6.3" +semver = "1.0.16" +serde = { version = "1.0.152", features = ["derive"] } +serde_json = "1.0.91" zip = "0.6.3" diff --git a/src/main.rs b/src/main.rs index e23dff7..bc4c48c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,36 @@ use copypasta::{ClipboardContext, ClipboardProvider}; use isahc::{prelude::*, ReadResponseExt, Request}; use native_dialog::{FileDialog, MessageDialog, MessageType}; +use serde::Deserialize; use std::{io::Cursor, path::PathBuf}; use zip::ZipArchive; -const USER_AGENT: &str = "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0"; +#[derive(Deserialize, Debug, Clone)] +struct GeezShadeConfig { + reshade_url: String, + gshade_shaders_url: String, + gshade_presets_url: String, -const RESHADE_URL: &str = "https://reshade.me/downloads/ReShade_Setup_5.6.0_Addon.exe"; -const GSHADE_SHADERS_URL: &str = - "https://github.com/Mortalitas/GShade/archive/refs/heads/master.zip"; -const GSHADE_PRESETS_URL: &str = - "https://github.com/Mortalitas/GShade-Presets/archive/refs/heads/master.zip"; + geezshade_version: String, + geezshade_user_agent: String, +} -fn get_file(path: &str) -> anyhow::Result> { +fn get_geezshade_config() -> anyhow::Result { + let req = Request::get("https://notnite.com/geezshade.json").header( + "User-Agent", + format!("GeezShade/{}", env!("CARGO_PKG_VERSION")), + ); + + let mut resp = req.body(())?.send()?; + let text = resp.text()?; + + let config: GeezShadeConfig = serde_json::from_str(&text)?; + Ok(config) +} + +fn get_file(path: &str, user_agent: String) -> anyhow::Result> { let req = Request::get(path) - .header("User-Agent", USER_AGENT) + .header("User-Agent", user_agent) .redirect_policy(isahc::config::RedirectPolicy::Follow); let mut resp = req.body(())?.send()?; @@ -22,9 +38,9 @@ fn get_file(path: &str) -> anyhow::Result> { Ok(resp.bytes()?) } -fn get_reshade(xiv_install: PathBuf) -> anyhow::Result<()> { +fn get_reshade(xiv_install: PathBuf, config: GeezShadeConfig) -> anyhow::Result<()> { println!("fetching reshade"); - let reshade_installer = get_file(RESHADE_URL)?; + let reshade_installer = get_file(&config.reshade_url, config.geezshade_user_agent)?; println!("extracting dll"); let mut zip = zip::ZipArchive::new(Cursor::new(reshade_installer))?; @@ -37,10 +53,13 @@ fn get_reshade(xiv_install: PathBuf) -> anyhow::Result<()> { Ok(()) } -fn get_gshade_presets(xiv_install: PathBuf) -> anyhow::Result<()> { +fn get_gshade_presets(xiv_install: PathBuf, config: GeezShadeConfig) -> anyhow::Result<()> { println!("fetching presets"); - let gshade_shaders = get_file(GSHADE_SHADERS_URL)?; - let gshade_presets = get_file(GSHADE_PRESETS_URL)?; + let gshade_shaders = get_file( + &config.gshade_shaders_url, + config.geezshade_user_agent.clone(), + )?; + let gshade_presets = get_file(&config.gshade_presets_url, config.geezshade_user_agent)?; println!("opening presets"); let shaders_zip = zip::ZipArchive::new(Cursor::new(gshade_shaders))?; @@ -138,9 +157,33 @@ fn get_game_exe() -> anyhow::Result { } } -fn do_the_thing(xiv_install: PathBuf) -> anyhow::Result<()> { - get_reshade(xiv_install.clone())?; - get_gshade_presets(xiv_install.clone())?; +fn show_error(message: &str, error: String) { + MessageDialog::new() + .set_title("GeezShade") + .set_text(&format!("{}\n\nAn error message will be copied to your clipboard. Please report this to geezshade@notnite.com.", message)) + .set_type(MessageType::Error) + .show_alert().unwrap(); + + let mut clipboard = ClipboardContext::new().unwrap(); + clipboard.set_contents(error).unwrap(); +} + +fn do_the_thing(xiv_install: PathBuf, config: GeezShadeConfig) -> anyhow::Result<()> { + if let Err(e) = get_reshade(xiv_install.clone(), config.clone()) { + show_error( + "Failed to download ReShade. You will have to manually install ReShade yourself.", + format!("{:?}", e), + ); + return Ok(()); + } + + if let Err(e) = get_gshade_presets(xiv_install.clone(), config) { + show_error( + "Failed to download GShade shaders & presets. Please try again later.", + format!("{:?}", e), + ); + return Ok(()); + } println!("making screenshot folders"); std::fs::create_dir_all(xiv_install.join("reshade-screenshots"))?; @@ -167,28 +210,50 @@ SavePath=.\reshade-screenshots } fn main() -> anyhow::Result<()> { + let config = get_geezshade_config(); + + let config = match config { + Ok(config) => config, + Err(e) => { + show_error( + "An error occured trying to fetch information required for GeezShade.", + format!("{:?}", e), + ); + + std::process::exit(1); + } + }; + + let semver_current = semver::Version::parse(env!("CARGO_PKG_VERSION")).unwrap(); + let semver_latest = semver::Version::parse(&config.geezshade_version).unwrap(); + + if semver_latest > semver_current { + let choice = MessageDialog::new() + .set_title("GeezShade") + .set_text("A new version of GeezShade is available to download.\nPlease go to https://notnite.com/geezshade for the latest version.\nNot updating may break the installation process, but it is not required.\n\nContinue anyways?") + .set_type(MessageType::Warning) + .show_confirm()?; + + if !choice { + return Ok(()); + } + } + let game_exe = get_game_exe()?; let xiv_install = game_exe.parent().unwrap(); let choice = MessageDialog::new() - .set_title("GeezShade") - .set_text("GeezShade will now download ReShade and the GShade presets.\nMake a backup before of your presets and settings before continuing.\n\nContinue?") - .set_type(MessageType::Info) - .show_confirm()?; + .set_title("GeezShade") + .set_text("GeezShade will now download ReShade and the GShade presets.\nMake a backup before of your presets and settings before continuing.\n\nContinue?") + .set_type(MessageType::Info) + .show_confirm()?; if !choice { return Ok(()); } - if let Err(e) = do_the_thing(xiv_install.to_path_buf()) { - MessageDialog::new() - .set_title("GeezShade") - .set_text("An error occurred installing ReShade.\nThis error will be copied to your clipboard.\nPlease report this error to geezshade@notnite.com.") - .set_type(MessageType::Error) - .show_alert()?; - - let mut clipboard = ClipboardContext::new().unwrap(); - clipboard.set_contents(e.to_string()).unwrap(); + if let Err(e) = do_the_thing(xiv_install.to_path_buf(), config) { + show_error("An error occured.", format!("{:?}", e)); return Err(e); }