Bigpicture optimization (#69)

* Download icons  when not in bigpicture mode
This commit is contained in:
Philip Kristoffersen
2022-04-01 17:40:39 +02:00
committed by GitHub
parent a1ea4dadb0
commit 077f445175
8 changed files with 148 additions and 63 deletions
+2
View File
@@ -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.
+2 -1
View File
@@ -33,4 +33,5 @@ enabled = true
enabled = true enabled = true
[steam] [steam]
create_collections = false create_collections = false
optimize_for_big_picture = false
+1 -1
View File
@@ -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,
"", "",
"", "",
) )
+1 -1
View File
@@ -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(),
); );
+1
View File
@@ -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
View File
@@ -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 {:?}",
+8 -2
View File
@@ -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),
} }
} }
@@ -25,7 +27,11 @@ impl ImageType {
ImageType::Grid => format!("https://cdn.cloudflare.steamstatic.com/steam/apps/{}/library_600x900_2x.jpg?t={}",steam_app_id,mtime), ImageType::Grid => format!("https://cdn.cloudflare.steamstatic.com/steam/apps/{}/library_600x900_2x.jpg?t={}",steam_app_id,mtime),
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()
}
} }
} }
+22 -10
View File
@@ -1,7 +1,7 @@
use steam_shortcuts_util::{shortcut::ShortcutOwned, shortcuts_to_bytes}; use steam_shortcuts_util::{shortcut::ShortcutOwned, shortcuts_to_bytes};
use crate::{ use crate::{
egs::EpicPlatform, egs::EpicPlatform,
legendary::LegendaryPlatform, legendary::LegendaryPlatform,
lutris::lutris_platform::LutrisPlatform, lutris::lutris_platform::LutrisPlatform,
platform::Platform, platform::Platform,
@@ -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")]
{ {