game_manager_lib\services/
images.rs

1//! Serviço para gerenciar cache de imagens (capas de jogos)
2//!
3//! Fornece comandos Tauri para baixar, armazenar e limpar imagens localmente.
4//! Utiliza o diretório de dados do aplicativo para armazenar as imagens em cache.
5
6use crate::errors::AppError;
7use std::fs;
8use std::path::PathBuf;
9use tauri::{AppHandle, Manager};
10
11/// Helper: Garante que o diretório de capas existe e retorna o caminho
12fn get_covers_dir(app: &AppHandle) -> Result<PathBuf, AppError> {
13    // Busca o diretório de dados do app (ex: %APPDATA%/br.com.playlite/ no Windows)
14    let app_data_dir = app.path().app_data_dir().map_err(|e| {
15        AppError::IoError(
16            std::io::Error::new(std::io::ErrorKind::NotFound, e.to_string()).to_string(),
17        )
18    })?;
19
20    let covers_dir = app_data_dir.join("covers");
21
22    // Se a pasta não existir, cria
23    if !covers_dir.exists() {
24        fs::create_dir_all(&covers_dir).map_err(|e| AppError::IoError(e.to_string()))?;
25    }
26
27    Ok(covers_dir)
28}
29
30/// Comando: Baixa uma imagem e salva localmente
31///
32/// Retorna o caminho do arquivo salvo
33#[tauri::command]
34pub async fn cache_cover_image(
35    app: AppHandle,
36    url: String,
37    game_id: String,
38) -> Result<String, AppError> {
39    // 1. Prepara o caminho
40    let covers_dir = get_covers_dir(&app)?;
41    // Salva .jpg para simplificar
42    let file_name = format!("{}.jpg", game_id);
43    let file_path = covers_dir.join(&file_name);
44
45    // 2. Se já existe, retorna o caminho (Cache Hit)
46    if file_path.exists() {
47        return Ok(file_path.to_string_lossy().to_string());
48    }
49
50    // 3. Download (Cache Miss)
51    // Usa reqwest para baixar os bytes
52    let response = reqwest::get(&url)
53        .await
54        .map_err(|e| AppError::NetworkError(e.to_string()))?;
55
56    let bytes = response
57        .bytes()
58        .await
59        .map_err(|e| AppError::NetworkError(e.to_string()))?;
60
61    // 4. Salva no disco
62    fs::write(&file_path, bytes).map_err(|e| AppError::IoError(e.to_string()))?;
63
64    Ok(file_path.to_string_lossy().to_string())
65}
66
67/// Comando: Verifica se existe capa local para um jogo
68///
69/// Retorna o caminho absoluto se existir, ou None
70#[tauri::command]
71pub fn check_local_cover(app: AppHandle, game_id: String) -> Option<String> {
72    let covers_dir = get_covers_dir(&app).ok()?;
73    let path = covers_dir.join(format!("{}.jpg", game_id));
74
75    if path.exists() {
76        Some(path.to_string_lossy().to_string())
77    } else {
78        None
79    }
80}
81
82/// Comando: Limpa todo o cache de imagens
83#[tauri::command]
84pub fn clear_cover_cache(app: AppHandle) -> Result<String, AppError> {
85    let covers_dir = get_covers_dir(&app)?;
86
87    // Remove a pasta inteira e recria vazia
88    if covers_dir.exists() {
89        fs::remove_dir_all(&covers_dir).map_err(|e| AppError::IoError(e.to_string()))?;
90        fs::create_dir_all(&covers_dir).map_err(|e| AppError::IoError(e.to_string()))?;
91    }
92
93    Ok("Cache de imagens limpo com sucesso.".to_string())
94}