diff --git a/Readme.md b/Readme.md index 5c58660..8340321 100644 --- a/Readme.md +++ b/Readme.md @@ -59,7 +59,7 @@ If you have a problem that a game wont launch, try to manually set a proton vers ## Tips for linux -If you are running linux and are running into problems check [tips for linux seciton](tips_for_linux.md) +If you are running linux (this includes Steam Dekc) and are running into problems check [tips for linux seciton](tips_for_linux.md) ## Configuration @@ -70,6 +70,20 @@ Most people will not have to configure anything, just open BoilR and click Synch This tool turns things into Steam, therefor boiler, And it is written in **R**ust so therefor: BoilR -## License +## I found a bug, what do it do? +Check that there is not already an issue for it [here](https://github.com/PhilipK/BoilR/issues) +If not, create a new issue and I will have a look at it (remember to write which OS you are using). + +## I have a great idea / I would like support for a specific platform, what do I do? +Check out the [discussions](https://github.com/PhilipK/BoilR/discussions) and feel free to create new discussions for your idea. + +## How can I help/contribute? +If you are a coder, you can fork this repo and then create a pull request, they are very welcome! +If you are not a developer (or you don't like to code in Rust) spread the work and create issues/discussions for anything. + +## Can I donate to support BoilR? +Nope, please don't, donate it to your favorite charity instead, and if you don't have one of those may I suggest something like [GiveWell](https://www.givewell.org/). + +## License This project is dual license MIT or Apache 2.0 , it is up to you. In short, you can do what you want with this project, but if in doubt read the license files. diff --git a/src/main.rs b/src/main.rs index b91f946..a69ae4c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,8 +22,8 @@ use std::error::Error; async fn main() -> Result<(), Box> { let settings = settings::Settings::new()?; settings::Settings::write_config_if_missing(); - let usersinfo = sync::run_sync(&settings).unwrap(); - sync::download_images(&settings,&usersinfo).await; + let usersinfo = sync::run_sync(&settings,&mut None).unwrap(); + sync::download_images(&settings,&usersinfo,&mut None).await; Ok(()) } diff --git a/src/origin/origin_platform.rs b/src/origin/origin_platform.rs index f6bb60a..438e63d 100644 --- a/src/origin/origin_platform.rs +++ b/src/origin/origin_platform.rs @@ -175,7 +175,7 @@ fn get_default_locations() -> OriginPathData { let origin_folder = Path::new(&program_data) .join("Origin"); if origin_folder.exists(){ - res.exe_path = Some(origin_folder.to_owned()); + res.local_content_path = Some(origin_folder.to_owned()); } } res diff --git a/src/steamgriddb/downloader.rs b/src/steamgriddb/downloader.rs index e7fec18..12a10a2 100644 --- a/src/steamgriddb/downloader.rs +++ b/src/steamgriddb/downloader.rs @@ -5,6 +5,7 @@ use std::{collections::HashMap, path::Path}; use futures::{stream, StreamExt}; use serde::{Deserialize, Serialize}; +use tokio::sync::watch::Sender; use std::error::Error; use steamgriddb_api::query_parameters::{GridDimentions, Nsfw}; // 0.3.1 @@ -14,6 +15,7 @@ use steamgriddb_api::Client; use crate::settings::Settings; use crate::steam::{get_shortcuts_for_user, get_users_images, SteamUsersInfo}; use crate::steamgriddb::ImageType; +use crate::sync::SyncProgress; use super::CachedSearch; @@ -23,6 +25,7 @@ pub async fn download_images_for_users<'b>( settings: &Settings, users: &[SteamUsersInfo], download_animated: bool, + sender:&mut Option> ) { let auth_key = &settings.steamgrid_db.auth_key; if let Some(auth_key) = auth_key { @@ -32,6 +35,9 @@ pub async fn download_images_for_users<'b>( let search = CachedSearch::new(&client); let search = &search; let client = &client; + if let Some(sender) = sender{ + let _ = sender.send(SyncProgress::FindingImages); + } let to_downloads = stream::iter(users) .map(|user| { let shortcut_info = get_shortcuts_for_user(user); @@ -54,9 +60,12 @@ pub async fn download_images_for_users<'b>( .collect::>>() .await; let to_downloads = to_downloads.iter().flatten().collect::>(); + let total = to_downloads.len(); if !to_downloads.is_empty() { + if let Some(sender) = sender{ + let _ = sender.send(SyncProgress::DownloadingImages { to_download: total }); + } search.save(); - stream::iter(to_downloads) .map(|to_download| async move { if let Err(e) = download_to_download(to_download).await { @@ -73,7 +82,7 @@ pub async fn download_images_for_users<'b>( } } else { println!("Steamgrid DB Auth Key not found, please add one as described here: https://github.com/PhilipK/steam_shortcuts_sync#configuration"); - } + } } #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/src/sync/mod.rs b/src/sync/mod.rs index da9fd68..230e452 100644 --- a/src/sync/mod.rs +++ b/src/sync/mod.rs @@ -4,4 +4,6 @@ mod synchronization; pub use synchronization::run_sync; pub use synchronization::download_images; -pub use synchronization::get_platform_shortcuts; \ No newline at end of file +pub use synchronization::get_platform_shortcuts; + +pub use synchronization::SyncProgress; \ No newline at end of file diff --git a/src/sync/synchronization.rs b/src/sync/synchronization.rs index f8a997e..57e8c7a 100644 --- a/src/sync/synchronization.rs +++ b/src/sync/synchronization.rs @@ -1,4 +1,5 @@ use steam_shortcuts_util::{shortcut::ShortcutOwned, shortcuts_to_bytes}; +use tokio::sync::watch::Sender; use crate::{ egs::EpicPlatform, @@ -11,7 +12,7 @@ use crate::{ Collection, ShortcutInfo, SteamUsersInfo, }, steamgriddb::{download_images_for_users, ImageType}, - uplay::Uplay, + uplay::Uplay, }; #[cfg(target_family = "unix")] @@ -24,7 +25,25 @@ use std::{fs::File, io::Write, path::Path}; const BOILR_TAG: &str = "boilr"; -pub fn run_sync(settings: &Settings) -> Result, String> { + +pub enum SyncProgress{ + NotStarted, + Starting, + FoundGames{ + games_found:usize + }, + FindingImages, + DownloadingImages{ + to_download:usize, + }, + Done +} + + +pub fn run_sync(settings: &Settings, sender: &mut Option>) -> Result, String> { + if let Some(sender) = &sender{ + let _ = sender.send(SyncProgress::Starting); + } let mut userinfo_shortcuts = get_shortcuts_paths(&settings.steam) .map_err(|e| format!("Getting shortcut paths failed: {e}"))?; @@ -34,6 +53,9 @@ pub fn run_sync(settings: &Settings) -> Result, String> { .flat_map(|s| s.1.clone()) .filter(|s| !settings.blacklisted_games.contains(&s.app_id)) .collect(); + if let Some(sender) = &sender{ + let _ = sender.send(SyncProgress::FoundGames { games_found: all_shortcuts.len() }); + } for shortcut in &all_shortcuts { println!("Appid: {} name: {}", shortcut.app_id, shortcut.app_name); } @@ -69,18 +91,18 @@ pub fn run_sync(settings: &Settings) -> Result, String> { let duration = start_time.elapsed(); println!("Finished synchronizing games in: {:?}", duration); - } + } Ok(userinfo_shortcuts) } -pub async fn download_images(settings: &Settings, userinfo_shortcuts: &Vec) { +pub async fn download_images(settings: &Settings, userinfo_shortcuts: &Vec,sender: &mut Option>) { if settings.steamgrid_db.enabled { if settings.steamgrid_db.prefer_animated { println!("downloading animated images"); - download_images_for_users(settings, userinfo_shortcuts, true).await; + download_images_for_users(settings, userinfo_shortcuts, true,sender).await; } - download_images_for_users(settings, userinfo_shortcuts, false).await; + download_images_for_users(settings, userinfo_shortcuts, false,sender).await; } } @@ -108,18 +130,14 @@ fn fix_shortcut_icons( ImageType::Icon }; - for shortcut in shortcuts { - #[cfg(not(target_family = "unix"))] - let replace_icon = shortcut.icon.trim().eq("") || !Path::new(shortcut.icon.trim()).exists(); - #[cfg(target_family = "unix")] - let replace_icon = shortcut.icon.trim().eq("") || !Path::new(shortcut.icon.trim()).exists() ||shortcut.icon.eq(&shortcut.exe); + for shortcut in shortcuts { + let replace_icon = shortcut.icon.trim().eq("") || !Path::new(shortcut.icon.trim()).exists() || shortcut.icon.eq(&shortcut.exe); if replace_icon { let app_id = steam_shortcuts_util::app_id_generator::calculate_app_id( &shortcut.exe, &shortcut.app_name, ); - let new_icon_path = image_folder.join(image_type.file_name(app_id)); - shortcut.icon = new_icon_path.to_string_lossy().to_string(); + shortcut.icon = image_folder.join(image_type.file_name(app_id)).to_string_lossy().to_string(); } } } diff --git a/src/ui/uiapp.rs b/src/ui/uiapp.rs index cb3ca51..6177c5a 100644 --- a/src/ui/uiapp.rs +++ b/src/ui/uiapp.rs @@ -1,11 +1,11 @@ -use eframe::{egui, epi::{self, IconData},}; -use egui::{ScrollArea, TextureHandle, Stroke, Rounding, Image}; +use eframe::{egui, epi::{self},}; +use egui::{ScrollArea, TextureHandle, Stroke, Rounding, ImageButton}; use futures::executor::block_on; use steam_shortcuts_util::shortcut::ShortcutOwned; -use std::error::Error; -use tokio::runtime::Runtime; +use std::{error::Error}; +use tokio::{runtime::Runtime, sync::watch::{Receiver, self}}; -use crate::{settings::Settings, sync::{download_images, self}, }; +use crate::{settings::Settings, sync::{download_images, self, SyncProgress}}; use super::{ui_images::{get_import_image, get_logo, get_logo_icon}, ui_colors::{TEXT_COLOR, BACKGROUND_COLOR, BG_STROKE_COLOR, ORANGE, PURLPLE, LIGHT_ORANGE}}; @@ -22,9 +22,12 @@ struct MyEguiApp { settings: Settings, rt: Runtime, ui_images: UiImages, - games_to_sync:Option)>> + games_to_sync:Option)>>, + status_reciever: Receiver, } + + impl MyEguiApp { pub fn new() -> Self { let runtime = Runtime::new().unwrap(); @@ -34,17 +37,24 @@ impl MyEguiApp { rt: runtime, games_to_sync:None, ui_images: UiImages::default(), + status_reciever: watch::channel(SyncProgress::NotStarted).1, } } - pub fn run_sync(&self) { - let settings = self.settings.clone(); - self.rt.spawn_blocking(move || { - + pub fn run_sync(&mut self) { + let (sender,mut reciever ) = watch::channel(SyncProgress::NotStarted); + let settings = self.settings.clone(); + self.status_reciever = reciever; + self.rt.spawn_blocking(move || { + MyEguiApp::save_settings_to_file(&settings); //TODO get status back to ui - let usersinfo = sync::run_sync(&settings).unwrap(); - let task = download_images(&settings, &usersinfo); + let mut some_sender =Some(sender); + let usersinfo = sync::run_sync(&settings,&mut some_sender).unwrap(); + let task = download_images(&settings, &usersinfo,&mut some_sender); block_on(task); + if let Some(sender) = some_sender{ + let _ = sender.send(SyncProgress::Done); + } }); } @@ -93,9 +103,31 @@ impl epi::App for MyEguiApp { egui::TopBottomPanel::new(egui::panel::TopBottomSide::Bottom, "Bottom Panel") .show(ctx,|ui|{ + { + let status = &*self.status_reciever.borrow(); + match status{ + SyncProgress::NotStarted => {}, + SyncProgress::Starting => { + ui.label("Starting Import"); + }, + SyncProgress::FoundGames { games_found } => { + ui.label(format!("Found {} games to import",games_found)); + }, + SyncProgress::FindingImages => { + ui.label(format!("Searching for images")); + }, + SyncProgress::DownloadingImages { to_download } => { + ui.label(format!("Downloading {} images ",to_download)); + }, + SyncProgress::Done =>{ + ui.label(format!("Done importing games")); + }, + }; + } + let texture = self.get_import_image(ui); let size = texture.size_vec2(); - let image_button = Image::new(texture, size); + let image_button = ImageButton::new(texture, size); if ui.add(image_button).on_hover_text("Import your games into steam").clicked() { self.run_sync(); } @@ -325,7 +357,7 @@ impl MyEguiApp{ pub fn run_sync() { - let app = MyEguiApp::new(); + let mut app = MyEguiApp::new(); app.run_sync(); } diff --git a/tips_for_linux.md b/tips_for_linux.md index ad4ba97..d627c29 100644 --- a/tips_for_linux.md +++ b/tips_for_linux.md @@ -4,6 +4,7 @@ If you are on Linux, and want to use one of the launchers that is not available If you want to avoid launching into Lutris, here are a few ways that you can do that. ### GOG +I recommend you just use Heroic. But if you really really want to use EGS you can: - Install [Lutris](https://lutris.net/) - Install GOG from Lutris [here](https://lutris.net/games/gog-galaxy/) @@ -13,7 +14,7 @@ If you want to avoid launching into Lutris, here are a few ways that you can do ### Epic -I recommend you just use [Legendary](https://github.com/derrod/legendary). But if you really really want to use EGS you can: +I recommend you just use Heroic, Rare or [Legendary](https://github.com/derrod/legendary). But if you really really want to use EGS you can: - Install [Lutris](https://lutris.net/) - Install EGS from Lutris [here](https://lutris.net/games/epic-games-store/) @@ -27,3 +28,4 @@ I recommend you just use [Legendary](https://github.com/derrod/legendary). But i - Run the installer by adding it to steam via the "add a non-steam game" option - Remember to set "compatability" to a newer proton version - After the install, BoilR can find and add the games +- Validate that the found games have the correct Proton version