mirror of
https://github.com/djibux/BoilR.git
synced 2026-09-01 05:53:41 +02:00
Bigpicture optimization (#69)
* Download icons when not in bigpicture mode
This commit is contained in:
@@ -45,6 +45,8 @@ wine_c_drive="/home/username/Games/gog-galaxy/drive_c" #Only for Linux, Is manda
|
|||||||
|
|
||||||
[steam]
|
[steam]
|
||||||
location="C:\\Program Files (x86)\\Steam\\" #If this value is not defined, the tool will try to find it automatically. If it can't find it, it will fail and tell you.
|
location="C:\\Program Files (x86)\\Steam\\" #If this value is not defined, the tool will try to find it automatically. If it can't find it, it will fail and tell you.
|
||||||
|
optimize_for_big_picture=false #Set icons to wide images, that big picture mode will use. This will make the icons have a wrong ratio in desktop mode, but will improve the look in big picture mode
|
||||||
|
create_collections=false #Will try to create a steam collection for each platform
|
||||||
|
|
||||||
[steamgrid_db]
|
[steamgrid_db]
|
||||||
enabled = true #If false, the whole download of custom art will be skipped.
|
enabled = true #If false, the whole download of custom art will be skipped.
|
||||||
|
|||||||
@@ -34,3 +34,4 @@ enabled = true
|
|||||||
|
|
||||||
[steam]
|
[steam]
|
||||||
create_collections = false
|
create_collections = false
|
||||||
|
optimize_for_big_picture = false
|
||||||
@@ -43,7 +43,7 @@ fn exe_shortcut(manifest: ManifestItem) -> ShortcutOwned {
|
|||||||
manifest.display_name.as_str(),
|
manifest.display_name.as_str(),
|
||||||
exe,
|
exe,
|
||||||
start_dir,
|
start_dir,
|
||||||
"",
|
exe,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ impl From<HeroicGame> for ShortcutOwned {
|
|||||||
game.title.as_str(),
|
game.title.as_str(),
|
||||||
&target,
|
&target,
|
||||||
&install_path,
|
&install_path,
|
||||||
"",
|
&target,
|
||||||
"",
|
"",
|
||||||
&game.launch_parameters.as_str(),
|
&game.launch_parameters.as_str(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ use serde::{Deserialize, Serialize};
|
|||||||
pub struct SteamSettings {
|
pub struct SteamSettings {
|
||||||
pub location: Option<String>,
|
pub location: Option<String>,
|
||||||
pub create_collections: bool,
|
pub create_collections: bool,
|
||||||
|
pub optimize_for_big_picture: bool,
|
||||||
}
|
}
|
||||||
|
|||||||
+111
-48
@@ -44,6 +44,7 @@ pub async fn download_images_for_users<'b>(
|
|||||||
search,
|
search,
|
||||||
client,
|
client,
|
||||||
download_animated,
|
download_animated,
|
||||||
|
settings.steam.optimize_for_big_picture,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
res.unwrap_or_default()
|
res.unwrap_or_default()
|
||||||
@@ -78,6 +79,7 @@ pub async fn download_images_for_users<'b>(
|
|||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct PublicGameResponseMetadata {
|
pub struct PublicGameResponseMetadata {
|
||||||
store_asset_mtime: Option<u64>,
|
store_asset_mtime: Option<u64>,
|
||||||
|
clienticon: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
@@ -109,17 +111,25 @@ async fn search_fo_to_download(
|
|||||||
search: &CachedSearch<'_>,
|
search: &CachedSearch<'_>,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
download_animated: bool,
|
download_animated: bool,
|
||||||
|
download_big_picture: bool,
|
||||||
) -> Result<Vec<ToDownload>, Box<dyn Error>> {
|
) -> Result<Vec<ToDownload>, Box<dyn Error>> {
|
||||||
let shortcuts_to_search_for = shortcuts.iter().filter(|s| {
|
let types = {
|
||||||
let images = vec![
|
let mut types = vec![
|
||||||
format!("{}_hero.png", s.app_id),
|
ImageType::Logo,
|
||||||
format!("{}p.png", s.app_id),
|
ImageType::Hero,
|
||||||
format!("{}.png", s.app_id),
|
ImageType::Grid,
|
||||||
format!("{}_logo.png", s.app_id),
|
ImageType::WideGrid,
|
||||||
format!("{}_bigpicture.png", s.app_id),
|
ImageType::Icon,
|
||||||
];
|
];
|
||||||
|
if download_big_picture {
|
||||||
|
types.push(ImageType::BigPicture);
|
||||||
|
}
|
||||||
|
types
|
||||||
|
};
|
||||||
|
|
||||||
|
let shortcuts_to_search_for = shortcuts.iter().filter(|s| {
|
||||||
// if we are missing any of the images we need to search for them
|
// if we are missing any of the images we need to search for them
|
||||||
images.iter().any(|image| !known_images.contains(image)) && !s.app_name.is_empty()
|
types.iter().map(|t| t.file_name(s.app_id)).any(|image| !known_images.contains(&image)) && !s.app_name.is_empty()
|
||||||
});
|
});
|
||||||
let shortcuts_to_search_for: Vec<&ShortcutOwned> = shortcuts_to_search_for.collect();
|
let shortcuts_to_search_for: Vec<&ShortcutOwned> = shortcuts_to_search_for.collect();
|
||||||
if shortcuts_to_search_for.is_empty() {
|
if shortcuts_to_search_for.is_empty() {
|
||||||
@@ -143,14 +153,9 @@ async fn search_fo_to_download(
|
|||||||
for (app_id, search) in search_results_a.into_iter().flatten() {
|
for (app_id, search) in search_results_a.into_iter().flatten() {
|
||||||
search_results.insert(app_id, search);
|
search_results.insert(app_id, search);
|
||||||
}
|
}
|
||||||
let types = vec![
|
|
||||||
ImageType::Logo,
|
|
||||||
ImageType::Hero,
|
|
||||||
ImageType::Grid,
|
|
||||||
ImageType::WideGrid,
|
|
||||||
ImageType::BigPicture,
|
|
||||||
];
|
|
||||||
let mut to_download = vec![];
|
let mut to_download = vec![];
|
||||||
|
let grid_folder = Path::new(user_data_folder).join("config").join("grid");
|
||||||
for image_type in types {
|
for image_type in types {
|
||||||
let images_needed = shortcuts
|
let images_needed = shortcuts
|
||||||
.iter()
|
.iter()
|
||||||
@@ -163,41 +168,59 @@ async fn search_fo_to_download(
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let shortcuts: Vec<&ShortcutOwned> = images_needed.collect();
|
let shortcuts: Vec<&ShortcutOwned> = images_needed.collect();
|
||||||
let image_search_result =
|
|
||||||
get_images_for_ids(client, &image_ids, &image_type, download_animated).await;
|
|
||||||
match image_search_result {
|
|
||||||
Ok(images) => {
|
|
||||||
let grid_folder = Path::new(user_data_folder).join("config").join("grid");
|
|
||||||
let images = images
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(index, image)| (image, shortcuts[index], image_ids[index]));
|
|
||||||
let download_for_this_type = stream::iter(images)
|
|
||||||
.filter_map(|(image, shortcut, game_id)| {
|
|
||||||
let path = grid_folder.join(image_type.file_name(shortcut.app_id));
|
|
||||||
async move {
|
|
||||||
let image_url = match image {
|
|
||||||
Ok(img) => Some(img.url.clone()),
|
|
||||||
Err(_) => get_steam_image_url(game_id, &image_type).await,
|
|
||||||
};
|
|
||||||
if let Some(url) = image_url {
|
|
||||||
Some(ToDownload {
|
|
||||||
path,
|
|
||||||
url,
|
|
||||||
app_name: shortcut.app_name.clone(),
|
|
||||||
image_type: image_type.clone(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<ToDownload>>()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
to_download.extend(download_for_this_type);
|
|
||||||
|
if let ImageType::Icon = image_type {
|
||||||
|
let mut index = 0;
|
||||||
|
for image_id in image_ids{
|
||||||
|
let shortcut = shortcuts[index];
|
||||||
|
if let Some(url) = get_steam_icon_url(image_id).await{
|
||||||
|
let path = grid_folder.join(image_type.file_name(shortcut.app_id));
|
||||||
|
to_download.push(ToDownload {
|
||||||
|
path,
|
||||||
|
url,
|
||||||
|
app_name: shortcut.app_name.clone(),
|
||||||
|
image_type: image_type.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
index = index + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let image_search_result =
|
||||||
|
get_images_for_ids(client, &image_ids, &image_type, download_animated).await;
|
||||||
|
match image_search_result {
|
||||||
|
Ok(images) => {
|
||||||
|
let images = images
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, image)| (image, shortcuts[index], image_ids[index]));
|
||||||
|
let download_for_this_type = stream::iter(images)
|
||||||
|
.filter_map(|(image, shortcut, game_id)| {
|
||||||
|
let path = grid_folder.join(image_type.file_name(shortcut.app_id));
|
||||||
|
async move {
|
||||||
|
let image_url = match image {
|
||||||
|
Ok(img) => Some(img.url.clone()),
|
||||||
|
Err(_) => get_steam_image_url(game_id, &image_type).await,
|
||||||
|
};
|
||||||
|
if let Some(url) = image_url {
|
||||||
|
Some(ToDownload {
|
||||||
|
path,
|
||||||
|
url,
|
||||||
|
app_name: shortcut.app_name.clone(),
|
||||||
|
image_type: image_type.clone(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<ToDownload>>()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
to_download.extend(download_for_this_type);
|
||||||
|
}
|
||||||
|
Err(err) => println!("Error getting images: {}", err),
|
||||||
}
|
}
|
||||||
Err(err) => println!("Error getting images: {}", err),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(to_download)
|
Ok(to_download)
|
||||||
@@ -244,15 +267,18 @@ async fn get_images_for_ids(
|
|||||||
nsfw: Some(&Nsfw::False),
|
nsfw: Some(&Nsfw::False),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let query_type = match image_type {
|
let query_type = match image_type {
|
||||||
ImageType::Hero => Hero(Some(hero_parameters)),
|
ImageType::Hero => Hero(Some(hero_parameters)),
|
||||||
ImageType::BigPicture => Grid(Some(big_picture_parameters)),
|
ImageType::BigPicture => Grid(Some(big_picture_parameters)),
|
||||||
ImageType::Grid => Grid(Some(grid_parameters)),
|
ImageType::Grid => Grid(Some(grid_parameters)),
|
||||||
ImageType::WideGrid => Grid(Some(big_picture_parameters)),
|
ImageType::WideGrid => Grid(Some(big_picture_parameters)),
|
||||||
ImageType::Logo => Logo(Some(logo_parameters)),
|
ImageType::Logo => Logo(Some(logo_parameters)),
|
||||||
|
_ => panic!("Unsupported image type"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_search_result = client.get_images_for_ids(image_ids, &query_type).await;
|
let image_search_result = client.get_images_for_ids(image_ids, &query_type).await;
|
||||||
|
|
||||||
image_search_result
|
image_search_result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,6 +312,43 @@ async fn get_steam_image_url(game_id: usize, image_type: &ImageType) -> Option<S
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_steam_icon_url(game_id: usize) -> Option<String> {
|
||||||
|
let steamgriddb_page_url = format!("https://www.steamgriddb.com/api/public/game/{}/", game_id);
|
||||||
|
let response = reqwest::get(steamgriddb_page_url).await;
|
||||||
|
match response {
|
||||||
|
Ok(response) => {
|
||||||
|
let text_response = response.json::<PublicGameResponse>().await;
|
||||||
|
match text_response {
|
||||||
|
Ok(response) => {
|
||||||
|
let game_id = response
|
||||||
|
.data
|
||||||
|
.clone()
|
||||||
|
.map(|d| d.platforms.map(|p| p.steam.map(|s| s.id)));
|
||||||
|
let mtime = response.data.map(|d| {
|
||||||
|
d.platforms
|
||||||
|
.map(|p| p.steam.map(|s| s.metadata.map(|m| m.clienticon)))
|
||||||
|
});
|
||||||
|
if let (Some(Some(Some(steam_app_id))), Some(Some(Some(Some(Some(mtime)))))) =
|
||||||
|
(game_id, mtime)
|
||||||
|
{
|
||||||
|
return Some(icon_url(&steam_app_id, &mtime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => (),
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn icon_url(steam_app_id: &str, icon_id: &str) -> String {
|
||||||
|
format!(
|
||||||
|
"https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/{}/{}.ico",
|
||||||
|
steam_app_id, icon_id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async fn download_to_download(to_download: &ToDownload) -> Result<(), Box<dyn Error>> {
|
async fn download_to_download(to_download: &ToDownload) -> Result<(), Box<dyn Error>> {
|
||||||
println!(
|
println!(
|
||||||
"Downloading {:?} for {} to {:?}",
|
"Downloading {:?} for {} to {:?}",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ pub enum ImageType {
|
|||||||
WideGrid,
|
WideGrid,
|
||||||
Logo,
|
Logo,
|
||||||
BigPicture,
|
BigPicture,
|
||||||
|
Icon
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImageType {
|
impl ImageType {
|
||||||
@@ -15,6 +16,7 @@ impl ImageType {
|
|||||||
ImageType::WideGrid => format!("{}.png", app_id),
|
ImageType::WideGrid => format!("{}.png", app_id),
|
||||||
ImageType::Logo => format!("{}_logo.png", app_id),
|
ImageType::Logo => format!("{}_logo.png", app_id),
|
||||||
ImageType::BigPicture => format!("{}_bigpicture.png", app_id),
|
ImageType::BigPicture => format!("{}_bigpicture.png", app_id),
|
||||||
|
ImageType::Icon => format!("{}.ico", app_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,6 +28,10 @@ impl ImageType {
|
|||||||
ImageType::WideGrid => format!("https://cdn.cloudflare.steamstatic.com/steam/apps/{}/header.jpg?t={}",steam_app_id,mtime),
|
ImageType::WideGrid => format!("https://cdn.cloudflare.steamstatic.com/steam/apps/{}/header.jpg?t={}",steam_app_id,mtime),
|
||||||
ImageType::Logo => format!("https://cdn.cloudflare.steamstatic.com/steam/apps/{}/logo.png?t={}",steam_app_id,mtime),
|
ImageType::Logo => format!("https://cdn.cloudflare.steamstatic.com/steam/apps/{}/logo.png?t={}",steam_app_id,mtime),
|
||||||
ImageType::BigPicture => format!("https://cdn.cloudflare.steamstatic.com/steam/apps/{}/header.jpg?t={}",steam_app_id,mtime),
|
ImageType::BigPicture => format!("https://cdn.cloudflare.steamstatic.com/steam/apps/{}/header.jpg?t={}",steam_app_id,mtime),
|
||||||
|
// This should not happen
|
||||||
|
_ => "".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::{
|
|||||||
get_shortcuts_for_user, get_shortcuts_paths, setup_proton_games, write_collections,
|
get_shortcuts_for_user, get_shortcuts_paths, setup_proton_games, write_collections,
|
||||||
Collection, ShortcutInfo, SteamUsersInfo,
|
Collection, ShortcutInfo, SteamUsersInfo,
|
||||||
},
|
},
|
||||||
steamgriddb::download_images_for_users,
|
steamgriddb::{download_images_for_users, ImageType},
|
||||||
uplay::Uplay,
|
uplay::Uplay,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -50,7 +50,11 @@ pub async fn run_sync(settings: &Settings) -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
shortcut_info.shortcuts.extend(all_shortcuts.clone());
|
shortcut_info.shortcuts.extend(all_shortcuts.clone());
|
||||||
|
|
||||||
fix_shortcut_icons(user, &mut shortcut_info.shortcuts);
|
fix_shortcut_icons(
|
||||||
|
user,
|
||||||
|
&mut shortcut_info.shortcuts,
|
||||||
|
settings.steam.optimize_for_big_picture,
|
||||||
|
);
|
||||||
|
|
||||||
save_shortcuts(&shortcut_info.shortcuts, Path::new(&shortcut_info.path));
|
save_shortcuts(&shortcut_info.shortcuts, Path::new(&shortcut_info.path));
|
||||||
|
|
||||||
@@ -86,10 +90,20 @@ fn remove_old_shortcuts(shortcut_info: &mut ShortcutInfo) {
|
|||||||
.retain(|shortcut| !shortcut.dev_kit_game_id.starts_with(&boilr_tag));
|
.retain(|shortcut| !shortcut.dev_kit_game_id.starts_with(&boilr_tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fix_shortcut_icons(user: &SteamUsersInfo, shortcuts: &mut Vec<ShortcutOwned>) {
|
fn fix_shortcut_icons(
|
||||||
|
user: &SteamUsersInfo,
|
||||||
|
shortcuts: &mut Vec<ShortcutOwned>,
|
||||||
|
big_picture_mode: bool,
|
||||||
|
) {
|
||||||
let image_folder = Path::new(&user.steam_user_data_folder)
|
let image_folder = Path::new(&user.steam_user_data_folder)
|
||||||
.join("config")
|
.join("config")
|
||||||
.join("grid");
|
.join("grid");
|
||||||
|
let image_type = if big_picture_mode {
|
||||||
|
ImageType::BigPicture
|
||||||
|
} else {
|
||||||
|
ImageType::Icon
|
||||||
|
};
|
||||||
|
|
||||||
for shortcut in shortcuts {
|
for shortcut in shortcuts {
|
||||||
#[cfg(not(target_family = "unix"))]
|
#[cfg(not(target_family = "unix"))]
|
||||||
let replace_icon = shortcut.icon.trim().eq("");
|
let replace_icon = shortcut.icon.trim().eq("");
|
||||||
@@ -100,11 +114,10 @@ fn fix_shortcut_icons(user: &SteamUsersInfo, shortcuts: &mut Vec<ShortcutOwned>)
|
|||||||
&shortcut.exe,
|
&shortcut.exe,
|
||||||
&shortcut.app_name,
|
&shortcut.app_name,
|
||||||
);
|
);
|
||||||
let new_icon = image_folder
|
let new_icon_path = image_folder.join(image_type.file_name(app_id));
|
||||||
.join(format!("{}_bigpicture.png", app_id))
|
if new_icon_path.exists() {
|
||||||
.to_string_lossy()
|
shortcut.icon = new_icon_path.to_string_lossy().to_string();
|
||||||
.to_string();
|
}
|
||||||
shortcut.icon = new_icon;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,7 +157,6 @@ fn get_platform_shortcuts(settings: &Settings) -> Vec<(String, Vec<ShortcutOwned
|
|||||||
update_platform_shortcuts(&LutrisPlatform {
|
update_platform_shortcuts(&LutrisPlatform {
|
||||||
settings: settings.lutris.clone(),
|
settings: settings.lutris.clone(),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
];
|
];
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user