Skip to content

Commit 9d4aa3f

Browse files
authored
Add files via upload
1 parent 12c6d4b commit 9d4aa3f

10 files changed

Lines changed: 539 additions & 74 deletions

File tree

src-tauri/Cargo.lock

Lines changed: 68 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "zgamelib"
3-
version = "1.0.0"
3+
version = "1.2.0"
44
description = "ZGameLib - Personal Game Library"
55
authors = ["TheHolyOneZ"]
66
license = "MIT"
@@ -20,6 +20,7 @@ tauri-plugin-dialog = "2"
2020
tauri-plugin-shell = "2"
2121
tauri-plugin-updater = "2"
2222
tauri-plugin-process = "2"
23+
tauri-plugin-global-shortcut = "2"
2324
serde = { version = "1", features = ["derive"] }
2425
serde_json = "1"
2526
rusqlite = { version = "0.32", features = ["bundled"] }
@@ -36,7 +37,7 @@ base64 = "0.22"
3637

3738
[target.'cfg(windows)'.dependencies]
3839
winreg = "0.52"
39-
windows = { version = "0.58", features = ["Win32_UI_WindowsAndMessaging", "Win32_Foundation", "Win32_System_Diagnostics_ToolHelp", "Win32_System_Threading"] }
40+
windows = { version = "0.58", features = ["Win32_UI_WindowsAndMessaging", "Win32_Foundation", "Win32_System_Diagnostics_ToolHelp", "Win32_System_Threading", "Win32_System_Diagnostics_Etw", "Win32_NetworkManagement_IpHelper", "Win32_System_Performance"] }
4041

4142
[features]
4243
default = ["custom-protocol"]

src-tauri/src/commands/games.rs

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use tauri::State;
22
use chrono::Utc;
33
use uuid::Uuid;
4-
use crate::db::{DbState, queries};
4+
use crate::db::{DbState, IgdbTokenState, queries};
55
use crate::models::{Game, Note, Session, CreateGamePayload, UpdateGamePayload, HltbData, WeeklyPlaytime, IgdbMetadata, LibraryGrowthEntry};
66

77
#[tauri::command]
@@ -217,7 +217,7 @@ pub fn reorder_games(state: State<DbState>, ids: Vec<String>) -> Result<(), Stri
217217
let conn = state.0.lock().map_err(|e| e.to_string())?;
218218
let tx = conn.unchecked_transaction().map_err(|e| e.to_string())?;
219219
for (i, id) in ids.iter().enumerate() {
220-
conn.execute(
220+
tx.execute(
221221
"UPDATE games SET sort_order = ?1 WHERE id = ?2",
222222
rusqlite::params![i as i64, id],
223223
).map_err(|e| e.to_string())?;
@@ -378,7 +378,7 @@ pub fn batch_update_games(
378378
if !game.tags.contains(t) { game.tags.push(t.clone()); }
379379
}
380380
}
381-
queries::update_game(&conn, &game).map_err(|e| e.to_string())?;
381+
queries::update_game(&*tx, &game).map_err(|e| e.to_string())?;
382382
}
383383
tx.commit().map_err(|e| e.to_string())?;
384384
Ok(())
@@ -418,24 +418,12 @@ pub fn get_library_growth(state: State<DbState>) -> Result<Vec<LibraryGrowthEntr
418418
Ok(month_map.into_values().collect())
419419
}
420420

421-
#[tauri::command]
422-
pub fn fetch_igdb_metadata(
423-
state: State<DbState>,
424-
game_id: String,
425-
game_name: String,
426-
client_id: String,
427-
client_secret: String,
428-
) -> Result<Option<IgdbMetadata>, String> {
429-
if client_id.trim().is_empty() || client_secret.trim().is_empty() {
430-
return Err("IGDB client_id and client_secret are required".to_string());
431-
}
432-
433-
let token_url = "https://id.twitch.tv/oauth2/token";
421+
fn fetch_fresh_igdb_token(client_id: &str, client_secret: &str, now_secs: u64) -> Result<(String, u64), String> {
434422
let token_body = format!(
435423
"client_id={}&client_secret={}&grant_type=client_credentials",
436424
client_id.trim(), client_secret.trim()
437425
);
438-
let token_resp = ureq::post(token_url)
426+
let token_resp = ureq::post("https://id.twitch.tv/oauth2/token")
439427
.set("Content-Type", "application/x-www-form-urlencoded")
440428
.timeout(std::time::Duration::from_secs(15))
441429
.send_string(&token_body)
@@ -447,6 +435,48 @@ pub fn fetch_igdb_metadata(
447435
.as_str()
448436
.ok_or("Failed to parse access token")?
449437
.to_string();
438+
let expires_in = token_json["expires_in"].as_u64().unwrap_or(3600);
439+
Ok((access_token, now_secs + expires_in))
440+
}
441+
442+
#[tauri::command]
443+
pub fn fetch_igdb_metadata(
444+
state: State<DbState>,
445+
token_state: State<IgdbTokenState>,
446+
game_id: String,
447+
game_name: String,
448+
client_id: String,
449+
client_secret: String,
450+
) -> Result<Option<IgdbMetadata>, String> {
451+
if client_id.trim().is_empty() || client_secret.trim().is_empty() {
452+
return Err("IGDB client_id and client_secret are required".to_string());
453+
}
454+
455+
let now_secs = std::time::SystemTime::now()
456+
.duration_since(std::time::UNIX_EPOCH)
457+
.map(|d| d.as_secs())
458+
.unwrap_or(0);
459+
460+
let access_token = {
461+
let mut cached = token_state.0.lock().map_err(|e| e.to_string())?;
462+
if let Some((ref token, expires_at)) = *cached {
463+
if now_secs + 60 < expires_at {
464+
token.clone()
465+
} else {
466+
drop(cached);
467+
let token = fetch_fresh_igdb_token(&client_id, &client_secret, now_secs)?;
468+
let mut c = token_state.0.lock().map_err(|e| e.to_string())?;
469+
*c = Some((token.0.clone(), token.1));
470+
token.0
471+
}
472+
} else {
473+
drop(cached);
474+
let token = fetch_fresh_igdb_token(&client_id, &client_secret, now_secs)?;
475+
let mut c = token_state.0.lock().map_err(|e| e.to_string())?;
476+
*c = Some((token.0.clone(), token.1));
477+
token.0
478+
}
479+
};
450480

451481
let query = format!(
452482
"fields name,genres.name,involved_companies.company.name,involved_companies.developer,involved_companies.publisher,first_release_date,summary; search \"{}\"; limit 5;",

0 commit comments

Comments
 (0)