mirror of
https://github.com/djibux/BoilR.git
synced 2026-09-01 05:53:41 +02:00
Merge branch 'main' of https://github.com/PhilipK/BoilR
This commit is contained in:
@@ -59,7 +59,7 @@ If you have a problem that a game wont launch, try to manually set a proton vers
|
|||||||
|
|
||||||
## Tips for linux
|
## 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
|
## 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
|
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.
|
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.
|
||||||
|
|||||||
+2
-2
@@ -22,8 +22,8 @@ use std::error::Error;
|
|||||||
async fn main() -> Result<(), Box<dyn Error>> {
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let settings = settings::Settings::new()?;
|
let settings = settings::Settings::new()?;
|
||||||
settings::Settings::write_config_if_missing();
|
settings::Settings::write_config_if_missing();
|
||||||
let usersinfo = sync::run_sync(&settings).unwrap();
|
let usersinfo = sync::run_sync(&settings,&mut None).unwrap();
|
||||||
sync::download_images(&settings,&usersinfo).await;
|
sync::download_images(&settings,&usersinfo,&mut None).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ fn get_default_locations() -> OriginPathData {
|
|||||||
let origin_folder = Path::new(&program_data)
|
let origin_folder = Path::new(&program_data)
|
||||||
.join("Origin");
|
.join("Origin");
|
||||||
if origin_folder.exists(){
|
if origin_folder.exists(){
|
||||||
res.exe_path = Some(origin_folder.to_owned());
|
res.local_content_path = Some(origin_folder.to_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use std::{collections::HashMap, path::Path};
|
|||||||
|
|
||||||
use futures::{stream, StreamExt};
|
use futures::{stream, StreamExt};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tokio::sync::watch::Sender;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use steamgriddb_api::query_parameters::{GridDimentions, Nsfw}; // 0.3.1
|
use steamgriddb_api::query_parameters::{GridDimentions, Nsfw}; // 0.3.1
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ use steamgriddb_api::Client;
|
|||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
use crate::steam::{get_shortcuts_for_user, get_users_images, SteamUsersInfo};
|
use crate::steam::{get_shortcuts_for_user, get_users_images, SteamUsersInfo};
|
||||||
use crate::steamgriddb::ImageType;
|
use crate::steamgriddb::ImageType;
|
||||||
|
use crate::sync::SyncProgress;
|
||||||
|
|
||||||
use super::CachedSearch;
|
use super::CachedSearch;
|
||||||
|
|
||||||
@@ -23,6 +25,7 @@ pub async fn download_images_for_users<'b>(
|
|||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
users: &[SteamUsersInfo],
|
users: &[SteamUsersInfo],
|
||||||
download_animated: bool,
|
download_animated: bool,
|
||||||
|
sender:&mut Option<Sender<SyncProgress>>
|
||||||
) {
|
) {
|
||||||
let auth_key = &settings.steamgrid_db.auth_key;
|
let auth_key = &settings.steamgrid_db.auth_key;
|
||||||
if let Some(auth_key) = 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 = CachedSearch::new(&client);
|
||||||
let search = &search;
|
let search = &search;
|
||||||
let client = &client;
|
let client = &client;
|
||||||
|
if let Some(sender) = sender{
|
||||||
|
let _ = sender.send(SyncProgress::FindingImages);
|
||||||
|
}
|
||||||
let to_downloads = stream::iter(users)
|
let to_downloads = stream::iter(users)
|
||||||
.map(|user| {
|
.map(|user| {
|
||||||
let shortcut_info = get_shortcuts_for_user(user);
|
let shortcut_info = get_shortcuts_for_user(user);
|
||||||
@@ -54,9 +60,12 @@ pub async fn download_images_for_users<'b>(
|
|||||||
.collect::<Vec<Vec<ToDownload>>>()
|
.collect::<Vec<Vec<ToDownload>>>()
|
||||||
.await;
|
.await;
|
||||||
let to_downloads = to_downloads.iter().flatten().collect::<Vec<&ToDownload>>();
|
let to_downloads = to_downloads.iter().flatten().collect::<Vec<&ToDownload>>();
|
||||||
|
let total = to_downloads.len();
|
||||||
if !to_downloads.is_empty() {
|
if !to_downloads.is_empty() {
|
||||||
|
if let Some(sender) = sender{
|
||||||
|
let _ = sender.send(SyncProgress::DownloadingImages { to_download: total });
|
||||||
|
}
|
||||||
search.save();
|
search.save();
|
||||||
|
|
||||||
stream::iter(to_downloads)
|
stream::iter(to_downloads)
|
||||||
.map(|to_download| async move {
|
.map(|to_download| async move {
|
||||||
if let Err(e) = download_to_download(to_download).await {
|
if let Err(e) = download_to_download(to_download).await {
|
||||||
|
|||||||
@@ -5,3 +5,5 @@ mod synchronization;
|
|||||||
pub use synchronization::run_sync;
|
pub use synchronization::run_sync;
|
||||||
pub use synchronization::download_images;
|
pub use synchronization::download_images;
|
||||||
pub use synchronization::get_platform_shortcuts;
|
pub use synchronization::get_platform_shortcuts;
|
||||||
|
|
||||||
|
pub use synchronization::SyncProgress;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use steam_shortcuts_util::{shortcut::ShortcutOwned, shortcuts_to_bytes};
|
use steam_shortcuts_util::{shortcut::ShortcutOwned, shortcuts_to_bytes};
|
||||||
|
use tokio::sync::watch::Sender;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
egs::EpicPlatform,
|
egs::EpicPlatform,
|
||||||
@@ -24,7 +25,25 @@ use std::{fs::File, io::Write, path::Path};
|
|||||||
|
|
||||||
const BOILR_TAG: &str = "boilr";
|
const BOILR_TAG: &str = "boilr";
|
||||||
|
|
||||||
pub fn run_sync(settings: &Settings) -> Result<Vec<SteamUsersInfo>, 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<Sender<SyncProgress>>) -> Result<Vec<SteamUsersInfo>, String> {
|
||||||
|
if let Some(sender) = &sender{
|
||||||
|
let _ = sender.send(SyncProgress::Starting);
|
||||||
|
}
|
||||||
let mut userinfo_shortcuts = get_shortcuts_paths(&settings.steam)
|
let mut userinfo_shortcuts = get_shortcuts_paths(&settings.steam)
|
||||||
.map_err(|e| format!("Getting shortcut paths failed: {e}"))?;
|
.map_err(|e| format!("Getting shortcut paths failed: {e}"))?;
|
||||||
|
|
||||||
@@ -34,6 +53,9 @@ pub fn run_sync(settings: &Settings) -> Result<Vec<SteamUsersInfo>, String> {
|
|||||||
.flat_map(|s| s.1.clone())
|
.flat_map(|s| s.1.clone())
|
||||||
.filter(|s| !settings.blacklisted_games.contains(&s.app_id))
|
.filter(|s| !settings.blacklisted_games.contains(&s.app_id))
|
||||||
.collect();
|
.collect();
|
||||||
|
if let Some(sender) = &sender{
|
||||||
|
let _ = sender.send(SyncProgress::FoundGames { games_found: all_shortcuts.len() });
|
||||||
|
}
|
||||||
for shortcut in &all_shortcuts {
|
for shortcut in &all_shortcuts {
|
||||||
println!("Appid: {} name: {}", shortcut.app_id, shortcut.app_name);
|
println!("Appid: {} name: {}", shortcut.app_id, shortcut.app_name);
|
||||||
}
|
}
|
||||||
@@ -74,13 +96,13 @@ pub fn run_sync(settings: &Settings) -> Result<Vec<SteamUsersInfo>, String> {
|
|||||||
Ok(userinfo_shortcuts)
|
Ok(userinfo_shortcuts)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn download_images(settings: &Settings, userinfo_shortcuts: &Vec<SteamUsersInfo>) {
|
pub async fn download_images(settings: &Settings, userinfo_shortcuts: &Vec<SteamUsersInfo>,sender: &mut Option<Sender<SyncProgress>>) {
|
||||||
if settings.steamgrid_db.enabled {
|
if settings.steamgrid_db.enabled {
|
||||||
if settings.steamgrid_db.prefer_animated {
|
if settings.steamgrid_db.prefer_animated {
|
||||||
println!("downloading animated images");
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,17 +131,13 @@ fn fix_shortcut_icons(
|
|||||||
};
|
};
|
||||||
|
|
||||||
for shortcut in shortcuts {
|
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);
|
let replace_icon = shortcut.icon.trim().eq("") || !Path::new(shortcut.icon.trim()).exists() || shortcut.icon.eq(&shortcut.exe);
|
||||||
if replace_icon {
|
if replace_icon {
|
||||||
let app_id = steam_shortcuts_util::app_id_generator::calculate_app_id(
|
let app_id = steam_shortcuts_util::app_id_generator::calculate_app_id(
|
||||||
&shortcut.exe,
|
&shortcut.exe,
|
||||||
&shortcut.app_name,
|
&shortcut.app_name,
|
||||||
);
|
);
|
||||||
let new_icon_path = image_folder.join(image_type.file_name(app_id));
|
shortcut.icon = image_folder.join(image_type.file_name(app_id)).to_string_lossy().to_string();
|
||||||
shortcut.icon = new_icon_path.to_string_lossy().to_string();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-11
@@ -1,11 +1,11 @@
|
|||||||
use eframe::{egui, epi::{self, IconData},};
|
use eframe::{egui, epi::{self},};
|
||||||
use egui::{ScrollArea, TextureHandle, Stroke, Rounding, Image};
|
use egui::{ScrollArea, TextureHandle, Stroke, Rounding, ImageButton};
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
use steam_shortcuts_util::shortcut::ShortcutOwned;
|
use steam_shortcuts_util::shortcut::ShortcutOwned;
|
||||||
use std::error::Error;
|
use std::{error::Error};
|
||||||
use tokio::runtime::Runtime;
|
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}};
|
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,
|
settings: Settings,
|
||||||
rt: Runtime,
|
rt: Runtime,
|
||||||
ui_images: UiImages,
|
ui_images: UiImages,
|
||||||
games_to_sync:Option<Vec<(String, Vec<ShortcutOwned>)>>
|
games_to_sync:Option<Vec<(String, Vec<ShortcutOwned>)>>,
|
||||||
|
status_reciever: Receiver<SyncProgress>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl MyEguiApp {
|
impl MyEguiApp {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let runtime = Runtime::new().unwrap();
|
let runtime = Runtime::new().unwrap();
|
||||||
@@ -34,17 +37,24 @@ impl MyEguiApp {
|
|||||||
rt: runtime,
|
rt: runtime,
|
||||||
games_to_sync:None,
|
games_to_sync:None,
|
||||||
ui_images: UiImages::default(),
|
ui_images: UiImages::default(),
|
||||||
|
status_reciever: watch::channel(SyncProgress::NotStarted).1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn run_sync(&self) {
|
pub fn run_sync(&mut self) {
|
||||||
|
let (sender,mut reciever ) = watch::channel(SyncProgress::NotStarted);
|
||||||
let settings = self.settings.clone();
|
let settings = self.settings.clone();
|
||||||
|
self.status_reciever = reciever;
|
||||||
self.rt.spawn_blocking(move || {
|
self.rt.spawn_blocking(move || {
|
||||||
|
|
||||||
MyEguiApp::save_settings_to_file(&settings);
|
MyEguiApp::save_settings_to_file(&settings);
|
||||||
//TODO get status back to ui
|
//TODO get status back to ui
|
||||||
let usersinfo = sync::run_sync(&settings).unwrap();
|
let mut some_sender =Some(sender);
|
||||||
let task = download_images(&settings, &usersinfo);
|
let usersinfo = sync::run_sync(&settings,&mut some_sender).unwrap();
|
||||||
|
let task = download_images(&settings, &usersinfo,&mut some_sender);
|
||||||
block_on(task);
|
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")
|
egui::TopBottomPanel::new(egui::panel::TopBottomSide::Bottom, "Bottom Panel")
|
||||||
.show(ctx,|ui|{
|
.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 texture = self.get_import_image(ui);
|
||||||
let size = texture.size_vec2();
|
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() {
|
if ui.add(image_button).on_hover_text("Import your games into steam").clicked() {
|
||||||
self.run_sync();
|
self.run_sync();
|
||||||
}
|
}
|
||||||
@@ -325,7 +357,7 @@ impl MyEguiApp{
|
|||||||
|
|
||||||
|
|
||||||
pub fn run_sync() {
|
pub fn run_sync() {
|
||||||
let app = MyEguiApp::new();
|
let mut app = MyEguiApp::new();
|
||||||
app.run_sync();
|
app.run_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -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.
|
If you want to avoid launching into Lutris, here are a few ways that you can do that.
|
||||||
|
|
||||||
### GOG
|
### GOG
|
||||||
|
I recommend you just use Heroic. But if you really really want to use EGS you can:
|
||||||
|
|
||||||
- Install [Lutris](https://lutris.net/)
|
- Install [Lutris](https://lutris.net/)
|
||||||
- Install GOG from Lutris [here](https://lutris.net/games/gog-galaxy/)
|
- 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
|
### 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 [Lutris](https://lutris.net/)
|
||||||
- Install EGS from Lutris [here](https://lutris.net/games/epic-games-store/)
|
- 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
|
- 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
|
- Remember to set "compatability" to a newer proton version
|
||||||
- After the install, BoilR can find and add the games
|
- After the install, BoilR can find and add the games
|
||||||
|
- Validate that the found games have the correct Proton version
|
||||||
|
|||||||
Reference in New Issue
Block a user