game thumbnails

This commit is contained in:
2025-11-14 09:03:05 +01:00
parent 567d293455
commit 833c8afedf
198 changed files with 129 additions and 71 deletions
Generated
+13 -12
View File
@@ -1763,9 +1763,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "1.8.0" version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1744436df46f0bde35af3eda22aeaba453aada65d8f1c171cd8a5f59030bd69f" checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
dependencies = [ dependencies = [
"atomic-waker", "atomic-waker",
"bytes", "bytes",
@@ -1784,9 +1784,9 @@ dependencies = [
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.17" version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bytes", "bytes",
@@ -2245,6 +2245,7 @@ dependencies = [
name = "lanspread-tauri-deno-ts" name = "lanspread-tauri-deno-ts"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"base64 0.22.1",
"eyre", "eyre",
"lanspread-compat", "lanspread-compat",
"lanspread-db", "lanspread-db",
@@ -4661,9 +4662,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]] [[package]]
name = "tauri" name = "tauri"
version = "2.9.2" version = "2.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bceb52453e507c505b330afe3398510e87f428ea42b6e76ecb6bd63b15965b5" checksum = "9e492485dd390b35f7497401f67694f46161a2a00ffd800938d5dd3c898fb9d8"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@@ -4712,9 +4713,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-build" name = "tauri-build"
version = "2.5.1" version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a924b6c50fe83193f0f8b14072afa7c25b7a72752a2a73d9549b463f5fe91a38" checksum = "87d6f8cafe6a75514ce5333f115b7b1866e8e68d9672bf4ca89fc0f35697ea9d"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cargo_toml", "cargo_toml",
@@ -4734,9 +4735,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-codegen" name = "tauri-codegen"
version = "2.5.0" version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c1fe64c74cc40f90848281a90058a6db931eb400b60205840e09801ee30f190" checksum = "b7ef707148f0755110ca54377560ab891d722de4d53297595380a748026f139f"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"brotli", "brotli",
@@ -4761,9 +4762,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-macros" name = "tauri-macros"
version = "2.5.0" version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "260c5d2eb036b76206b9fca20b7be3614cfd21046c5396f7959e0e64a4b07f2f" checksum = "71664fd715ee6e382c05345ad258d6d1d50f90cf1b58c0aa726638b33c2a075d"
dependencies = [ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
+1
View File
@@ -11,6 +11,7 @@ members = [
resolver = "2" resolver = "2"
[workspace.dependencies] [workspace.dependencies]
base64 = "0.22"
bytes = { version = "1", features = ["serde"] } bytes = { version = "1", features = ["serde"] }
chrono = "0.4" chrono = "0.4"
clap = { version = "4", features = ["derive"] } clap = { version = "4", features = ["derive"] }
-1
View File
@@ -60,7 +60,6 @@ impl From<EtiGame> for Game {
genre: eti_game.genre_de, genre: eti_game.genre_de,
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
size: (eti_game.game_size * 1024.0 * 1024.0 * 1024.0) as u64, size: (eti_game.game_size * 1024.0 * 1024.0 * 1024.0) as u64,
thumbnail: None,
downloaded: false, downloaded: false,
installed: false, installed: false,
eti_game_version: None, eti_game_version: None,
-14
View File
@@ -3,7 +3,6 @@
use std::{collections::HashMap, fmt, path::Path}; use std::{collections::HashMap, fmt, path::Path};
use bytes::Bytes;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// Read version from version.ini file /// Read version from version.ini file
@@ -52,8 +51,6 @@ pub struct Game {
pub genre: String, pub genre: String,
/// size in bytes: example: 3455063152 /// size in bytes: example: 3455063152
pub size: u64, pub size: u64,
/// thumbnail image
pub thumbnail: Option<Bytes>,
/// indicates that the ETI bundle exists locally /// indicates that the ETI bundle exists locally
#[serde(default)] #[serde(default)]
pub downloaded: bool, pub downloaded: bool,
@@ -128,17 +125,6 @@ impl GameDB {
db db
} }
pub fn add_thumbnails(&mut self, thumbs_dir: &Path) {
for game in self.games.values_mut() {
let asset = thumbs_dir.join(format!("{}.jpg", game.id));
if let Ok(data) = std::fs::read(&asset) {
game.thumbnail = Some(Bytes::from(data));
} else {
tracing::warn!("Thumbnail missing: {}", game.id);
}
}
}
#[must_use] #[must_use]
pub fn get_game_by_id<S>(&self, id: S) -> Option<&Game> pub fn get_game_by_id<S>(&self, id: S) -> Option<&Game>
where where
-1
View File
@@ -1251,7 +1251,6 @@ async fn load_local_game_db(game_dir: &str) -> eyre::Result<GameDB> {
version: "1.0".to_string(), version: "1.0".to_string(),
genre: String::new(), genre: String::new(),
size, size,
thumbnail: None,
downloaded, downloaded,
installed, installed,
eti_game_version: local_version.clone(), eti_game_version: local_version.clone(),
@@ -34,6 +34,7 @@ lanspread-mdns = { path = "../../lanspread-mdns" }
lanspread-compat = { path = "../../lanspread-compat" } lanspread-compat = { path = "../../lanspread-compat" }
# external # external
base64 = { workspace = true }
eyre = { workspace = true } eyre = { workspace = true }
log = { workspace = true } log = { workspace = true }
mimalloc = { workspace = true } mimalloc = { workspace = true }
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

@@ -268,6 +268,23 @@ async fn get_peer_count(state: tauri::State<'_, LanSpreadState>) -> tauri::Resul
Ok(0) Ok(0)
} }
#[tauri::command]
async fn get_game_thumbnail(
game_id: String,
app_handle: tauri::AppHandle,
) -> tauri::Result<String> {
use base64::Engine;
let resource_path = app_handle.path().resolve(
format!("assets/{game_id}.jpg"),
tauri::path::BaseDirectory::Resource,
)?;
let image_data = std::fs::read(&resource_path)?;
let base64_data = base64::engine::general_purpose::STANDARD.encode(&image_data);
Ok(format!("data:image/jpeg;base64,{base64_data}"))
}
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
fn run_as_admin(file: &str, params: &str, dir: &str) -> bool { fn run_as_admin(file: &str, params: &str, dir: &str) -> bool {
use std::{ffi::OsStr, os::windows::ffi::OsStrExt}; use std::{ffi::OsStr, os::windows::ffi::OsStrExt};
@@ -817,7 +834,8 @@ pub fn run() {
run_game, run_game,
update_game_directory, update_game_directory,
update_game, update_game,
get_peer_count get_peer_count,
get_game_thumbnail
]) ])
.manage(lanspread_state) .manage(lanspread_state)
.setup({ .setup({
@@ -35,7 +35,8 @@
"binaries/unrar" "binaries/unrar"
], ],
"resources": [ "resources": [
"game.db" "game.db",
"assets/*"
] ]
} }
} }
+61 -9
View File
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event'; import { listen } from '@tauri-apps/api/event';
import { open } from '@tauri-apps/plugin-dialog'; import { open } from '@tauri-apps/plugin-dialog';
@@ -9,6 +9,8 @@ import "./App.css";
const FILE_STORAGE = 'launcher-settings.json'; const FILE_STORAGE = 'launcher-settings.json';
const GAME_DIR_KEY = 'game-directory'; const GAME_DIR_KEY = 'game-directory';
const CHECKING_PEERS_TIMEOUT_MS = 5000; const CHECKING_PEERS_TIMEOUT_MS = 5000;
const FALLBACK_THUMBNAIL =
'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwA/8A8A';
// enum with install status // enum with install status
enum InstallStatus { enum InstallStatus {
@@ -39,6 +41,39 @@ interface Game {
peer_count: number; peer_count: number;
} }
interface GameThumbnailProps {
gameId: string;
alt: string;
getThumbnailUrl: (gameId: string) => Promise<string>;
}
const GameThumbnail = ({ gameId, alt, getThumbnailUrl }: GameThumbnailProps) => {
const [thumbnailUrl, setThumbnailUrl] = useState('');
useEffect(() => {
let isMounted = true;
const loadThumbnail = async () => {
const url = await getThumbnailUrl(gameId);
if (isMounted) {
setThumbnailUrl(url);
}
};
void loadThumbnail();
return () => {
isMounted = false;
};
}, [gameId, getThumbnailUrl]);
if (!thumbnailUrl) {
return null;
}
return <img src={thumbnailUrl} alt={alt} />;
};
const App = () => { const App = () => {
const [gameItems, setGameItems] = useState<Game[]>([]); const [gameItems, setGameItems] = useState<Game[]>([]);
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
@@ -46,6 +81,24 @@ const App = () => {
const [currentFilter, setCurrentFilter] = useState<GameFilter>('available'); const [currentFilter, setCurrentFilter] = useState<GameFilter>('available');
const [totalPeerCount, setTotalPeerCount] = useState(0); const [totalPeerCount, setTotalPeerCount] = useState(0);
const checkingPeersTimeouts = useRef<Record<string, ReturnType<typeof setTimeout>>>({}); const checkingPeersTimeouts = useRef<Record<string, ReturnType<typeof setTimeout>>>({});
const [thumbnails, setThumbnails] = useState<Map<string, string>>(new Map());
const getThumbnailUrl = useCallback(async (gameId: string): Promise<string> => {
// Check cache first
if (thumbnails.has(gameId)) {
return thumbnails.get(gameId)!;
}
try {
const thumbnailUrl = await invoke<string>('get_game_thumbnail', { gameId });
setThumbnails(prev => new Map(prev).set(gameId, thumbnailUrl));
return thumbnailUrl;
} catch {
// Return a small placeholder for missing images
setThumbnails(prev => new Map(prev).set(gameId, FALLBACK_THUMBNAIL));
return FALLBACK_THUMBNAIL;
}
}, [thumbnails]);
const getFilteredGames = (games: Game[], filter: GameFilter): Game[] => { const getFilteredGames = (games: Game[], filter: GameFilter): Game[] => {
switch (filter) { switch (filter) {
@@ -549,13 +602,13 @@ const App = () => {
No games found matching your search and filters. No games found matching your search and filters.
</div> </div>
) : null} ) : null}
{filteredAndSearchedGames.map((item) => { {filteredAndSearchedGames.map((item) => (
const uint8Array = new Uint8Array(item.thumbnail);
const binaryString = uint8Array.reduce((acc, byte) => acc + String.fromCharCode(byte), '');
const thumbnailUrl = `data:image/jpeg;base64,${btoa(binaryString)}`;
return (
<div key={item.id} className="item"> <div key={item.id} className="item">
<img src={thumbnailUrl} alt={`${item.name} thumbnail`} /> <GameThumbnail
gameId={item.id}
alt={`${item.name} thumbnail`}
getThumbnailUrl={getThumbnailUrl}
/>
<div className="item-name">{item.name}</div> <div className="item-name">{item.name}</div>
<div className="description"> <div className="description">
<span className="desc-text">{item.description.slice(0, 10)}</span> <span className="desc-text">{item.description.slice(0, 10)}</span>
@@ -591,8 +644,7 @@ const App = () => {
</div> </div>
</div> </div>
</div> </div>
); ))}
})}
</div> </div>
</main> </main>
); );