Skip to main content

game_manager_lib/commands/platforms/
legacy.rs

1//! Legacy - Importa jogos de Legacy Games Launcher
2
3use crate::commands::platforms::core::{format_import_empty, format_import_summary};
4use crate::database::AppState;
5use crate::errors::AppError;
6use crate::sources::legacy::LegacySource;
7use crate::utils::status_logic;
8use chrono::Utc;
9use rusqlite::params;
10use tauri::{AppHandle, Emitter, State};
11use tracing::info;
12use uuid::Uuid;
13
14/// Persiste jogos da Legacy Games nas tabelas `games` e `game_details`.
15///
16/// Difere de `persist_source_games` por também gravar `cover_url` e
17/// `description_raw` em `game_details`, que não fazem parte do `SourceGame` padrão.
18async fn persist_legacy_games(
19    state: &AppState,
20    games: Vec<crate::sources::legacy::LegacyGame>,
21) -> Result<(u32, u32), AppError> {
22    let mut conn = state.games_db.lock().map_err(|_| AppError::MutexError)?;
23    let tx = conn
24        .transaction()
25        .map_err(|e| AppError::DatabaseError(e.to_string()))?;
26
27    let mut inserted = 0u32;
28    let mut updated = 0u32;
29    let now = Utc::now().to_rfc3339();
30
31    for legacy_game in games {
32        let game = &legacy_game.source;
33
34        let exists: bool = tx
35            .query_row(
36                "SELECT EXISTS(SELECT 1 FROM games WHERE platform = ?1 AND platform_game_id = ?2)",
37                params![&game.platform, &game.platform_game_id],
38                |row| row.get(0),
39            )
40            .unwrap_or(false);
41
42        let status = status_logic::calculate_status(game.playtime_minutes.unwrap_or(0) as i32);
43
44        if !exists {
45            let new_id = Uuid::new_v4().to_string();
46
47            tx.execute(
48                "INSERT INTO games (
49                    id, name, cover_url, platform, platform_game_id,
50                    installed, status, playtime, last_played, added_at,
51                    favorite, user_rating, install_path, executable_path
52                ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, NULL, ?9, 0, NULL, ?10, ?11)",
53                params![
54                    new_id,
55                    game.name.as_deref().unwrap_or("Unknown"),
56                    legacy_game.cover_url, // cover_url vem do catálogo da Legacy
57                    game.platform,
58                    game.platform_game_id,
59                    game.installed,
60                    status,
61                    game.playtime_minutes.unwrap_or(0),
62                    now,
63                    game.install_path,
64                    game.executable_path,
65                ],
66            )
67            .map_err(|e| AppError::DatabaseError(e.to_string()))?;
68
69            // Insere metadados na tabela game_details
70            if legacy_game.description_raw.is_some() {
71                tx.execute(
72                    "INSERT OR IGNORE INTO game_details (game_id, description_raw)
73                     VALUES (?1, ?2)",
74                    params![new_id, legacy_game.description_raw],
75                )
76                .map_err(|e| AppError::DatabaseError(e.to_string()))?;
77            }
78
79            inserted += 1;
80        } else {
81            tx.execute(
82                "UPDATE games SET
83                    installed   = ?1,
84                    status      = ?2,
85                    install_path     = COALESCE(?3, install_path),
86                    executable_path  = COALESCE(?4, executable_path)
87                 WHERE platform = ?5 AND platform_game_id = ?6",
88                params![
89                    game.installed,
90                    status,
91                    game.install_path,
92                    game.executable_path,
93                    game.platform,
94                    game.platform_game_id,
95                ],
96            )
97            .map_err(|e| AppError::DatabaseError(e.to_string()))?;
98
99            updated += 1;
100        }
101    }
102
103    tx.commit()
104        .map_err(|e| AppError::DatabaseError(e.to_string()))?;
105
106    Ok((inserted, updated))
107}
108
109/// Importa a biblioteca de jogos da Legacy Games.
110///
111/// Lê o arquivo `app-state-bck.json` do launcher da Legacy Games,
112/// cruza os jogos adquiridos com o catálogo embutido e persiste os dados
113/// nas tabelas `games` e `game_details`.
114///
115/// `app_state_path` — (opcional) caminho customizado para o `app-state-bck.json`.
116/// Se omitido, usa o caminho padrão do sistema operacional.
117/// `wine_prefix` — (Linux) caminho do Wine prefix onde o Legacy Games Launcher está instalado.
118/// No Windows o parâmetro é ignorado.
119#[tauri::command]
120pub async fn import_legacy_games(
121    app: AppHandle,
122    state: State<'_, AppState>,
123    app_state_path: Option<String>,
124    wine_prefix: Option<String>,
125) -> Result<String, AppError> {
126    let path = app_state_path
127        .filter(|s| !s.trim().is_empty())
128        .map(std::path::PathBuf::from);
129
130    let prefix = wine_prefix
131        .filter(|s| !s.trim().is_empty())
132        .map(std::path::PathBuf::from);
133
134    let source = LegacySource::new_with_wine(path, prefix);
135    let games = source.fetch_games_detailed().await?;
136
137    if games.is_empty() {
138        return Ok(format_import_empty("Legacy Games"));
139    }
140
141    let (inserted, updated) = persist_legacy_games(&state, games).await?;
142    let message = format_import_summary("Legacy Games", inserted, updated);
143    info!("{}", message);
144
145    let _ = app.emit("library_updated", ());
146
147    Ok(message)
148}