mirror of
https://github.com/djibux/BoilR.git
synced 2026-09-01 14:03:42 +02:00
Download official steam images as backup (#53)
This commit is contained in:
+146
-57
@@ -4,6 +4,7 @@ use std::path::PathBuf;
|
|||||||
use std::{collections::HashMap, path::Path};
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
use futures::{stream, StreamExt};
|
use futures::{stream, StreamExt};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use steamgriddb_api::query_parameters::GridDimentions; // 0.3.1
|
use steamgriddb_api::query_parameters::GridDimentions; // 0.3.1
|
||||||
|
|
||||||
@@ -74,6 +75,33 @@ pub async fn download_images_for_users<'b>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct PublicGameResponseMetadata {
|
||||||
|
store_asset_mtime: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct PublicGameResponseSteam {
|
||||||
|
id: String,
|
||||||
|
metadata: Option<PublicGameResponseMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct PublicGameResponsePlatforms {
|
||||||
|
steam: Option<PublicGameResponseSteam>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct PublicGameResponseData {
|
||||||
|
platforms: Option<PublicGameResponsePlatforms>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct PublicGameResponse {
|
||||||
|
success: bool,
|
||||||
|
data: Option<PublicGameResponseData>,
|
||||||
|
}
|
||||||
|
|
||||||
async fn search_fo_to_download(
|
async fn search_fo_to_download(
|
||||||
known_images: Vec<String>,
|
known_images: Vec<String>,
|
||||||
user_data_folder: &str,
|
user_data_folder: &str,
|
||||||
@@ -124,7 +152,7 @@ async fn search_fo_to_download(
|
|||||||
];
|
];
|
||||||
let mut to_download = vec![];
|
let mut to_download = vec![];
|
||||||
for image_type in types {
|
for image_type in types {
|
||||||
let mut images_needed = shortcuts
|
let images_needed = shortcuts
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|s| search_results.contains_key(&s.app_id))
|
.filter(|s| search_results.contains_key(&s.app_id))
|
||||||
.filter(|s| !known_images.contains(&image_type.file_name(s.app_id)));
|
.filter(|s| !known_images.contains(&image_type.file_name(s.app_id)));
|
||||||
@@ -133,64 +161,41 @@ async fn search_fo_to_download(
|
|||||||
.filter_map(|s| search_results.get(&s.app_id))
|
.filter_map(|s| search_results.get(&s.app_id))
|
||||||
.copied()
|
.copied()
|
||||||
.collect();
|
.collect();
|
||||||
use steamgriddb_api::query_parameters::AnimtionType;
|
|
||||||
use steamgriddb_api::query_parameters::QueryType::*;
|
|
||||||
let anymation_type = if download_animated {
|
|
||||||
Some(&[AnimtionType::Animated][..])
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let big_picture_dims = [GridDimentions::D920x430, GridDimentions::D460x215];
|
|
||||||
|
|
||||||
use steamgriddb_api::query_parameters::GridQueryParameters;
|
let shortcuts: Vec<&ShortcutOwned> = images_needed.collect();
|
||||||
let big_picture_parameters = GridQueryParameters {
|
let image_search_result =
|
||||||
dimentions: Some(&big_picture_dims),
|
get_images_for_ids(client, &image_ids, &image_type, download_animated).await;
|
||||||
types: anymation_type,
|
match image_search_result {
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
use steamgriddb_api::query_parameters::HeroQueryParameters;
|
|
||||||
let hero_parameters = HeroQueryParameters {
|
|
||||||
types: anymation_type,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let grid_parameters = GridQueryParameters {
|
|
||||||
types: anymation_type,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
use steamgriddb_api::query_parameters::LogoQueryParameters;
|
|
||||||
let logo_parameters = LogoQueryParameters {
|
|
||||||
types: anymation_type,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let query_type = match image_type {
|
|
||||||
ImageType::Hero => Hero(Some(hero_parameters)),
|
|
||||||
ImageType::BigPicture => Grid(Some(big_picture_parameters)),
|
|
||||||
ImageType::Grid => Grid(Some(grid_parameters)),
|
|
||||||
ImageType::WideGrid => Grid(Some(big_picture_parameters)),
|
|
||||||
ImageType::Logo => Logo(Some(logo_parameters)),
|
|
||||||
};
|
|
||||||
|
|
||||||
match client
|
|
||||||
.get_images_for_ids(image_ids.as_slice(), &query_type)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(images) => {
|
Ok(images) => {
|
||||||
for image in images {
|
let grid_folder = Path::new(user_data_folder).join("config").join("grid");
|
||||||
if let Some(shortcut) = images_needed.next() {
|
let images = images
|
||||||
if let Ok(image) = image {
|
.iter()
|
||||||
let grid_folder = Path::new(user_data_folder).join("config/grid");
|
.enumerate()
|
||||||
let path = grid_folder.join(image_type.file_name(shortcut.app_id));
|
.map(|(index, image)| (image, shortcuts[index], image_ids[index]));
|
||||||
to_download.push(ToDownload {
|
let download_for_this_type = stream::iter(images)
|
||||||
path,
|
.filter_map(|(image, shortcut, game_id)| {
|
||||||
url: image.url,
|
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),
|
||||||
}
|
}
|
||||||
@@ -198,8 +203,90 @@ async fn search_fo_to_download(
|
|||||||
Ok(to_download)
|
Ok(to_download)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_images_for_ids(
|
||||||
|
client: &Client,
|
||||||
|
image_ids: &[usize],
|
||||||
|
image_type: &ImageType,
|
||||||
|
download_animated: bool,
|
||||||
|
) -> Result<
|
||||||
|
Vec<steamgriddb_api::response::SteamGridDbResult<steamgriddb_api::images::Image>>,
|
||||||
|
Box<dyn std::error::Error>,
|
||||||
|
> {
|
||||||
|
use steamgriddb_api::query_parameters::AnimtionType;
|
||||||
|
use steamgriddb_api::query_parameters::QueryType::*;
|
||||||
|
let anymation_type = if download_animated {
|
||||||
|
Some(&[AnimtionType::Animated][..])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let big_picture_dims = [GridDimentions::D920x430, GridDimentions::D460x215];
|
||||||
|
use steamgriddb_api::query_parameters::GridQueryParameters;
|
||||||
|
let big_picture_parameters = GridQueryParameters {
|
||||||
|
dimentions: Some(&big_picture_dims),
|
||||||
|
types: anymation_type,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
use steamgriddb_api::query_parameters::HeroQueryParameters;
|
||||||
|
let hero_parameters = HeroQueryParameters {
|
||||||
|
types: anymation_type,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let grid_parameters = GridQueryParameters {
|
||||||
|
types: anymation_type,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
use steamgriddb_api::query_parameters::LogoQueryParameters;
|
||||||
|
let logo_parameters = LogoQueryParameters {
|
||||||
|
types: anymation_type,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let query_type = match image_type {
|
||||||
|
ImageType::Hero => Hero(Some(hero_parameters)),
|
||||||
|
ImageType::BigPicture => Grid(Some(big_picture_parameters)),
|
||||||
|
ImageType::Grid => Grid(Some(grid_parameters)),
|
||||||
|
ImageType::WideGrid => Grid(Some(big_picture_parameters)),
|
||||||
|
ImageType::Logo => Logo(Some(logo_parameters)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let image_search_result = client.get_images_for_ids(image_ids, &query_type).await;
|
||||||
|
image_search_result
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_steam_image_url(game_id: usize, image_type: &ImageType) -> 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.store_asset_mtime)))
|
||||||
|
});
|
||||||
|
if let (Some(Some(Some(steam_app_id))), Some(Some(Some(Some(Some(mtime)))))) =
|
||||||
|
(game_id, mtime)
|
||||||
|
{
|
||||||
|
return Some(image_type.steam_url(steam_app_id, mtime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => (),
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
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!("Downloading {} to {:?}", to_download.url, to_download.path);
|
println!(
|
||||||
|
"Downloading {:?} for {} to {:?}",
|
||||||
|
to_download.image_type, to_download.app_name, to_download.path
|
||||||
|
);
|
||||||
let path = &to_download.path;
|
let path = &to_download.path;
|
||||||
let url = &to_download.url;
|
let url = &to_download.url;
|
||||||
let mut file = File::create(path).unwrap();
|
let mut file = File::create(path).unwrap();
|
||||||
@@ -212,4 +299,6 @@ async fn download_to_download(to_download: &ToDownload) -> Result<(), Box<dyn Er
|
|||||||
pub struct ToDownload {
|
pub struct ToDownload {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
url: String,
|
url: String,
|
||||||
|
app_name: String,
|
||||||
|
image_type: ImageType,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,4 +17,15 @@ impl ImageType {
|
|||||||
ImageType::BigPicture => format!("{}_bigpicture.png", app_id),
|
ImageType::BigPicture => format!("{}_bigpicture.png", app_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn steam_url<S:AsRef<str>>(&self,steam_app_id:S,mtime:u64) -> String{
|
||||||
|
let steam_app_id = steam_app_id.as_ref();
|
||||||
|
match self{
|
||||||
|
ImageType::Hero => format!("https://cdn.cloudflare.steamstatic.com/steam/apps/{}/library_hero.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::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),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user