Skip to main content

game_manager_lib/services/integration/
nexus.rs

1use crate::utils::text::{normalize_for_matching, strip_edition_suffix};
2
3use serde::Deserialize;
4
5// === STRUCTS ===
6
7#[derive(Debug, Deserialize)]
8pub struct NexusGame {
9    pub id: i64,
10    pub name: String,
11    pub domain_name: String,
12    pub genre: Option<String>,
13    pub approved_date: Option<i64>,
14}
15
16// === NEXUS - CLIENTE ===
17
18pub async fn fetch_nexus_games(api_key: &str) -> Result<Vec<NexusGame>, reqwest::Error> {
19    let client = reqwest::Client::new();
20
21    let response = client
22        .get("https://api.nexusmods.com/v1/games.json")
23        .header("accept", "application/json")
24        .header("apikey", api_key)
25        .header("User-Agent", "Playlite/1.0.0 (Windows_NT 10.0; x64)")
26        .send()
27        .await?
28        .error_for_status()?;
29
30    response.json::<Vec<NexusGame>>().await
31}
32
33// === NEXUS - MATCHING ===
34
35/// Normaliza nome de jogo para matching com o catálogo do Nexus, com as mesmas regras de usadas em séries/tags.
36fn normalize_title(name: &str) -> String {
37    normalize_for_matching(&strip_edition_suffix(name))
38}
39
40pub fn find_best_nexus_match<'a>(
41    game_name: &str,
42    nexus_games: &'a [NexusGame],
43) -> Option<&'a NexusGame> {
44    let normalized_target = normalize_title(game_name);
45
46    // 1. Match exato normalizado primeiro
47    if let Some(exact) = nexus_games
48        .iter()
49        .find(|g| normalize_title(&g.name) == normalized_target)
50    {
51        return Some(exact);
52    }
53
54    // 2. Fallback fuzzy — só aceita acima de um limiar alto
55    const SIMILARITY_THRESHOLD: f64 = 0.92;
56
57    nexus_games
58        .iter()
59        .map(|g| {
60            let score = strsim::jaro_winkler(&normalized_target, &normalize_title(&g.name));
61            (g, score)
62        })
63        .filter(|(_, score)| *score >= SIMILARITY_THRESHOLD)
64        .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
65        .map(|(g, _)| g)
66}