game_manager_lib\commands/
plataforms.rs

1//! Módulo de importação de bibliotecas de plataformas externas (Steam, Epic, GOG).
2//!
3//! Fornece comandos para importar jogos em lote de serviços como Steam,
4//! conectando-se às APIs públicas e populando o banco de dados local.
5//!
6//! **Nota:** Atualmente, apenas Steam é suportado.
7
8use crate::constants::{self};
9use crate::database::AppState;
10use crate::errors::AppError;
11use crate::services::steam;
12use crate::utils::status_logic;
13use chrono::{TimeZone, Utc};
14use rusqlite::params;
15use tauri::State;
16use tracing::info;
17use uuid::Uuid;
18
19/// Importa toda a biblioteca de jogos Steam do usuário.
20///
21/// Conecta-se à API Steam para buscar a lista completa de jogos possuídos
22/// e adiciona todos ao banco de dados local com informações básicas.
23///
24/// **Processo:**
25/// 1. Busca jogos via Steam WEB API ('IPlayerService/GetOwnedGames')
26/// 2. Monta URLs de capas usando CDN da Steam
27/// 3. Converte playtime de minutos para horas
28/// 4. Insere em lote usando transação SQL
29/// 5. Usa 'INSERT OR IGNORE' para evitar duplicatas
30///
31/// **Nota:**
32/// - Biblioteca privada retorna erro de autenticação
33/// - Jogos gratuitos jogados são incluídos automaticamente
34/// - Jogos gratuitos não jogados ou que foram desinstalados podem não são serem retornados pela API
35/// - Tempo de jogo é arredondado para horas inteiras
36/// - Esta operação não aplica rate limit por usar apenas uma chamada de API.
37#[tauri::command]
38pub async fn import_steam_library(
39    state: State<'_, AppState>,
40    api_key: String,
41    steam_id: String,
42) -> Result<String, AppError> {
43    // Busca jogos via Steam API
44    let steam_games = steam::list_steam_games(&api_key, &steam_id)
45        .await
46        .map_err(AppError::NetworkError)?;
47
48    if steam_games.is_empty() {
49        return Ok("Nenhum jogo encontrado.".to_string());
50    }
51
52    let mut inserted = 0;
53    let mut updated = 0;
54    let now = Utc::now().to_rfc3339();
55
56    let conn = state.library_db.lock()?;
57
58    for game in steam_games {
59        let exists: bool = conn
60            .query_row(
61                "SELECT EXISTS(SELECT 1 FROM games WHERE platform = 'Steam' AND platform_id = ?1)",
62                params![game.appid],
63                |row| row.get(0),
64            )
65            .unwrap_or(false);
66
67        let status = status_logic::calculate_status(game.playtime_forever);
68
69        // Converte Unix Timestamp (Steam) para ISO 8601 (Banco)
70        let last_played_iso = if game.rtime_last_played > 0 {
71            Some(
72                Utc.timestamp_opt(game.rtime_last_played, 0)
73                    .unwrap()
74                    .to_rfc3339(),
75            )
76        } else {
77            None
78        };
79
80        // Insere ou atualiza registro
81        if !exists {
82            let new_id = Uuid::new_v4().to_string();
83            let cover = format!(
84                "{}/steam/apps/{}/library_600x900.jpg",
85                constants::STEAM_CDN_URL,
86                game.appid
87            );
88
89            conn.execute(
90                "INSERT INTO games (
91                    id, name, cover_url, platform, platform_id,
92                    status, playtime, last_played, added_at, favorite, user_rating
93                ) VALUES (?1, ?2, ?3, 'Steam', ?4, ?5, ?6, ?7, ?8, 0, NULL)",
94                params![
95                    new_id,
96                    game.name,
97                    cover,
98                    game.appid,
99                    status,
100                    game.playtime_forever,
101                    last_played_iso,
102                    now
103                ],
104            )
105            .ok();
106            inserted += 1;
107        } else {
108            conn.execute(
109                "UPDATE games SET
110                    playtime = ?1,
111                    status = ?2,
112                    last_played = COALESCE(?3, last_played)
113                 WHERE platform = 'Steam' AND platform_id = ?4",
114                params![game.playtime_forever, status, last_played_iso, game.appid],
115            )
116            .ok();
117            updated += 1;
118        }
119    }
120
121    let message = format!("{} novos, {} atualizados", inserted, updated);
122    info!("{}", message);
123
124    Ok(message)
125}