Skip to main content

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