game_manager_lib\commands\metadata/
covers.rs1use super::shared::{fetch_rawg_metadata, EnrichProgress};
6use crate::constants::RAWG_RATE_LIMIT_MS;
7use crate::database;
8use crate::database::AppState;
9use crate::errors::AppError;
10use rusqlite::params;
11use std::time::Duration;
12use tauri::{AppHandle, Emitter, Manager, State};
13use tokio::time::sleep;
14use tracing::info;
15
16#[tauri::command]
18pub async fn fetch_missing_covers(app: AppHandle) -> Result<(), AppError> {
19 let app_handle = app.clone();
20 let api_key = database::get_secret(&app, "rawg_api_key")?;
21 if api_key.is_empty() {
22 return Err(AppError::ValidationError(
23 "API Key da RAWG não configurada.".to_string(),
24 ));
25 }
26
27 tauri::async_runtime::spawn(async move {
28 info!("Iniciando busca de capas faltantes com cache...");
29
30 let state: State<AppState> = app_handle.state();
31 let mut total_updated = 0;
32 let mut total_failed = 0;
33
34 let games_without_cover: Vec<(String, String)> = {
35 let conn = state.library_db.lock().unwrap();
36 let mut stmt = conn
37 .prepare("SELECT id, name FROM games WHERE cover_url IS NULL OR cover_url = ''")
38 .unwrap();
39
40 stmt.query_map([], |row| -> rusqlite::Result<(String, String)> {
41 Ok((row.get(0)?, row.get(1)?))
42 })
43 .unwrap()
44 .flatten()
45 .collect()
46 };
47
48 if !games_without_cover.is_empty() {
49 let count = games_without_cover.len();
50
51 for (index, (game_id, name)) in games_without_cover.into_iter().enumerate() {
52 let _ = app_handle.emit(
53 "enrich_progress",
54 EnrichProgress {
55 current: (index + 1) as i32,
56 total_found: count as i32,
57 last_game: format!("Capa: {}", name),
58 status: "running".to_string(),
59 },
60 );
61
62 let img_url = {
64 let cache_conn = state.metadata_db.lock().unwrap();
65 let result = tokio::task::block_in_place(|| {
66 let rt = tokio::runtime::Handle::current();
67 rt.block_on(async {
68 fetch_rawg_metadata(&api_key, &name, &cache_conn)
69 .await
70 .and_then(|d| d.background_image)
71 })
72 });
73 result
74 };
75
76 if let Some(img) = img_url {
77 let conn = state.library_db.lock().unwrap();
78 if conn
79 .execute(
80 "UPDATE games SET cover_url = ?1 WHERE id = ?2",
81 params![img, game_id],
82 )
83 .is_ok()
84 {
85 total_updated += 1;
86 } else {
87 total_failed += 1;
88 }
89 } else {
90 total_failed += 1;
91 }
92
93 sleep(Duration::from_millis(RAWG_RATE_LIMIT_MS)).await;
94 }
95 }
96
97 info!(
98 "Busca de capas finalizada: {} sucesso, {} falhas",
99 total_updated, total_failed
100 );
101 let _ = app_handle.emit("enrich_complete", "Busca de capas finalizada.");
102 });
103
104 Ok(())
105}