Skip to main content

game_manager_lib/services/integration/
steamspy.rs

1//! Módulo de integração com a API do SteamSpy
2//!
3//! Usado para obter dados públicos de playtime para estima a duração de um jogo.
4
5use crate::constants::{
6    MINUTES_PER_HOUR, STEAMSPY_API_URL, STEAM_REVIEWS_TIMEOUT_SECS, USER_AGENT_STEAM,
7};
8use crate::utils::http_client::HTTP_CLIENT;
9use serde::Deserialize;
10use std::time::Duration;
11
12#[derive(Debug, Deserialize)]
13struct SteamSpyResponse {
14    median_forever: u32,
15}
16
17/// Busca tempo médio de jogo no SteamSpy (em minutos)
18pub async fn get_median_playtime(app_id: &str) -> Result<Option<u32>, String> {
19    let url = format!("{}?request=appdetails&appid={}", STEAMSPY_API_URL, app_id);
20
21    let response = HTTP_CLIENT
22        .get(&url)
23        .header("User-Agent", USER_AGENT_STEAM)
24        .timeout(Duration::from_secs(STEAM_REVIEWS_TIMEOUT_SECS))
25        .send()
26        .await
27        .map_err(|e| e.to_string())?;
28
29    if !response.status().is_success() {
30        return Ok(None);
31    }
32
33    // Tenta parsear. Se falhar (ex: jogo não trackeado), retorna None sem erro crítico
34    match response.json::<SteamSpyResponse>().await {
35        Ok(data) => {
36            // SteamSpy retorna em minutos, converter para horas
37            let median_hours = data.median_forever / (MINUTES_PER_HOUR as u32);
38            // Filtra zeros (jogos sem dados ou nunca jogados)
39            if median_hours > 0 {
40                Ok(Some(median_hours))
41            } else {
42                Ok(None)
43            }
44        }
45        Err(_) => Ok(None),
46    }
47}