Game launcher (wip), wgui refactor
[skip ci]
This commit is contained in:
103
dash-frontend/src/util/cached_fetcher.rs
Normal file
103
dash-frontend/src/util/cached_fetcher.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
use anyhow::Context;
|
||||
use serde::Deserialize;
|
||||
use wlx_common::cache_dir;
|
||||
|
||||
use crate::util::{http_client, steam_utils::AppID, various::AsyncExecutor};
|
||||
|
||||
pub struct CoverArt {
|
||||
// can be empty in case if data couldn't be fetched (use a fallback image then)
|
||||
pub compressed_image_data: Vec<u8>,
|
||||
}
|
||||
|
||||
pub async fn request_image(executor: AsyncExecutor, app_id: AppID) -> anyhow::Result<CoverArt> {
|
||||
let cache_file_path = format!("cover_arts/{}.bin", app_id);
|
||||
|
||||
// check if file already exists in cache directory
|
||||
if let Some(data) = cache_dir::get_data(&cache_file_path).await {
|
||||
return Ok(CoverArt {
|
||||
compressed_image_data: data,
|
||||
});
|
||||
}
|
||||
|
||||
let url = format!(
|
||||
"https://shared.steamstatic.com/store_item_assets/steam/apps/{}/library_600x900.jpg",
|
||||
app_id
|
||||
);
|
||||
|
||||
match http_client::get(&executor, &url).await {
|
||||
Ok(response) => {
|
||||
log::info!("Success");
|
||||
cache_dir::set_data(&cache_file_path, &response.data).await?;
|
||||
Ok(CoverArt {
|
||||
compressed_image_data: response.data,
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
// fetch failed, write an empty file
|
||||
log::error!("CoverArtFetcher: failed fetch for AppID {}: {}", app_id, e);
|
||||
cache_dir::set_data(&cache_file_path, &[]).await?;
|
||||
Ok(CoverArt {
|
||||
compressed_image_data: Vec::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
pub struct AppDetailsJSONData {
|
||||
#[allow(dead_code)]
|
||||
pub r#type: String, // "game"
|
||||
#[allow(dead_code)]
|
||||
pub name: String, // "Half-Life 3"
|
||||
#[allow(dead_code)]
|
||||
pub is_free: Option<bool>, // "false"
|
||||
pub detailed_description: Option<String>, //
|
||||
pub short_description: Option<String>, //
|
||||
pub developers: Vec<String>, // ["Valve"]
|
||||
}
|
||||
|
||||
async fn get_app_details_json_internal(
|
||||
executor: AsyncExecutor,
|
||||
cache_file_path: &str,
|
||||
app_id: AppID,
|
||||
) -> anyhow::Result<AppDetailsJSONData> {
|
||||
// check if file already exists in cache directory
|
||||
if let Some(data) = cache_dir::get_data(cache_file_path).await {
|
||||
return Ok(serde_json::from_value(serde_json::from_slice(&data)?)?);
|
||||
}
|
||||
|
||||
// Fetch from Steam API
|
||||
log::info!("Fetching app detail ID {}", app_id);
|
||||
let url = format!("https://store.steampowered.com/api/appdetails?appids={}", app_id);
|
||||
let response = http_client::get(&executor, &url).await?;
|
||||
let res_utf8 = String::from_utf8(response.data)?;
|
||||
let root = serde_json::from_str::<serde_json::Value>(&res_utf8)?;
|
||||
let body = root.get(&app_id).context("invalid body")?;
|
||||
|
||||
if !body.get("success").is_some_and(|v| v.as_bool().unwrap_or(false)) {
|
||||
anyhow::bail!("Failed");
|
||||
}
|
||||
|
||||
let data = body.get("data").context("data null")?;
|
||||
|
||||
let data_bytes = serde_json::to_vec(&data)?;
|
||||
let app_details: AppDetailsJSONData = serde_json::from_value(data.clone())?;
|
||||
|
||||
// cache for future use
|
||||
cache_dir::set_data(cache_file_path, &data_bytes).await?;
|
||||
|
||||
Ok(app_details)
|
||||
}
|
||||
|
||||
pub async fn get_app_details_json(executor: AsyncExecutor, app_id: AppID) -> Option<AppDetailsJSONData> {
|
||||
let cache_file_path = format!("app_details/{}.json", app_id);
|
||||
|
||||
match get_app_details_json_internal(executor, &cache_file_path, app_id).await {
|
||||
Ok(r) => Some(r),
|
||||
Err(e) => {
|
||||
log::error!("Failed to get app details: {:?}", e);
|
||||
let _ = cache_dir::set_data(&cache_file_path, &[]).await; // write empty data
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
use wlx_common::cache_dir;
|
||||
|
||||
use crate::util::{http_client, steam_utils::AppID, various::AsyncExecutor};
|
||||
|
||||
pub struct CoverArt {
|
||||
// can be empty in case if data couldn't be fetched (use a fallback image then)
|
||||
pub compressed_image_data: Vec<u8>,
|
||||
}
|
||||
|
||||
pub async fn request_image(executor: AsyncExecutor, app_id: AppID) -> anyhow::Result<CoverArt> {
|
||||
let cache_file_path = format!("cover_arts/{}.bin", app_id);
|
||||
|
||||
// check if file already exists in cache directory
|
||||
if let Some(data) = cache_dir::get_data(&cache_file_path).await {
|
||||
return Ok(CoverArt {
|
||||
compressed_image_data: data,
|
||||
});
|
||||
}
|
||||
|
||||
let url = format!(
|
||||
"https://shared.steamstatic.com/store_item_assets/steam/apps/{}/library_600x900.jpg",
|
||||
app_id
|
||||
);
|
||||
|
||||
match http_client::get(&executor, &url).await {
|
||||
Ok(response) => {
|
||||
log::info!("Success");
|
||||
cache_dir::set_data(&cache_file_path, &response.data).await?;
|
||||
Ok(CoverArt {
|
||||
compressed_image_data: response.data,
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
// fetch failed, write an empty file
|
||||
log::error!("CoverArtFetcher: failed fetch for AppID {}: {}", app_id, e);
|
||||
cache_dir::set_data(&cache_file_path, &[]).await?;
|
||||
Ok(CoverArt {
|
||||
compressed_image_data: Vec::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
pub mod cover_art_fetcher;
|
||||
pub mod cached_fetcher;
|
||||
pub mod desktop_finder;
|
||||
pub mod http_client;
|
||||
pub mod pactl_wrapper;
|
||||
|
||||
Reference in New Issue
Block a user