feat: Implement image caching for game covers, enhance frontend game list item layout, add Factorio to the game list, and ignore the cache directory.

This commit is contained in:
code002lover 2025-12-04 15:42:07 +01:00
parent 04e21708b2
commit 70e1a555c0
4 changed files with 47 additions and 11 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
target/ target/
cache/

View File

@ -123,6 +123,26 @@ async fn get_game_thumbnail(
title: &str, title: &str,
game_list: &rocket::State<Mutex<Vec<Game>>>, game_list: &rocket::State<Mutex<Vec<Game>>>,
) -> Option<(rocket::http::ContentType, Vec<u8>)> { ) -> Option<(rocket::http::ContentType, Vec<u8>)> {
// 1. Sanitize title for filename
let safe_title: String = title
.chars()
.map(|c| if c.is_alphanumeric() { c } else { '_' })
.collect();
let cache_dir = "cache";
let _ = std::fs::create_dir_all(cache_dir);
let cache_path_bin = format!("{}/{}.bin", cache_dir, safe_title);
let cache_path_type = format!("{}/{}.type", cache_dir, safe_title);
// 2. Check cache
if let (Ok(bytes), Ok(type_str)) = (
std::fs::read(&cache_path_bin),
std::fs::read_to_string(&cache_path_type),
) && let Some(ct) = rocket::http::ContentType::parse_flexible(&type_str)
{
return Some((ct, bytes));
}
let games = game_list.lock().await; let games = game_list.lock().await;
let game = games.iter().find(|g| g.title == title)?; let game = games.iter().find(|g| g.title == title)?;
@ -174,6 +194,11 @@ async fn get_game_thumbnail(
.and_then(rocket::http::ContentType::parse_flexible) .and_then(rocket::http::ContentType::parse_flexible)
.unwrap_or(rocket::http::ContentType::Binary); .unwrap_or(rocket::http::ContentType::Binary);
let bytes = resp.bytes().await.ok()?.to_vec(); let bytes = resp.bytes().await.ok()?.to_vec();
// 3. Write to cache
let _ = std::fs::write(&cache_path_bin, &bytes);
let _ = std::fs::write(&cache_path_type, content_type.to_string());
Some((content_type, bytes)) Some((content_type, bytes))
} }
Err(_) => None, Err(_) => None,

View File

@ -125,9 +125,12 @@ export function GameFilter() {
style={{ style={{
textDecoration: "none", textDecoration: "none",
color: "inherit", color: "inherit",
display: "block", display: "flex",
justifyContent: "space-between",
alignItems: "center",
}} }}
> >
<div>
<strong>{game}</strong> <strong>{game}</strong>
<div <div
style={{ style={{
@ -138,7 +141,10 @@ export function GameFilter() {
> >
All {selectedPeople.size} selected would play All {selectedPeople.size} selected would play
</div> </div>
</div>
<div style={{ width: "100px", marginLeft: "1rem" }}>
<GameImage game={game} /> <GameImage game={game} />
</div>
</Link> </Link>
))} ))}
</ul> </ul>

View File

@ -45,6 +45,10 @@
{ {
"title": " Asylum Life", "title": " Asylum Life",
"would_play": true "would_play": true
},
{
"title": "Factorio",
"would_play": true
} }
] ]
}, },