Skip to main content

game_manager_lib/services/integration/gamebrain/
models.rs

1//! Tipos publicos usados pelo frontend e pela integracao.
2
3use serde::{Deserialize, Serialize};
4
5/// Resultado simplificado usado pelo frontend.
6/// Estrutura compatível com: Wishlist, Busca, Descoberta e Similares
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct GameBrainSearchResult {
9    pub id: String,
10    pub name: String,
11    pub cover_url: Option<String>,
12    pub genre: Option<String>,
13    pub year: Option<u32>,
14    pub rating: Option<f64>,
15    pub platforms: Vec<String>,
16    pub link: Option<String>,
17}
18
19/// Todos os campos são opcionais — use apenas o que precisar.
20///
21/// # Exemplo
22///
23/// ```rust
24/// # use game_manager_lib::services::integration::gamebrain::{GameBrainSearchParams, GameBrainFilter, GameBrainFilterValue, GameBrainSort, GameBrainSortOrder};
25/// let params = GameBrainSearchParams {
26///     filters: vec![
27///         GameBrainFilter {
28///             key: "platform".into(),
29///             values: vec![GameBrainFilterValue { value: "pc".into() }],
30///             connection: Some("OR".into()),
31///         },
32///     ],
33///     sort: Some(GameBrainSort::Rating),
34///     sort_order: Some(GameBrainSortOrder::Desc),
35///     limit: Some(20),
36///     offset: None,
37/// };
38/// ```
39#[derive(Debug, Default, Clone)]
40pub struct GameBrainSearchParams {
41    /// Filtros a aplicar na busca. Os valores válidos vêm do campo `filter_options` da resposta da API.
42    pub filters: Vec<GameBrainFilter>,
43    pub sort: Option<GameBrainSort>,
44    /// Direção da ordenação. Padrão da API: descendente.
45    pub sort_order: Option<GameBrainSortOrder>,
46    /// Número máximo de resultados. Padrão da API: 10.
47    pub limit: Option<u32>,
48    pub offset: Option<u32>,
49}
50
51/// Um filtro a ser aplicado na busca.
52#[derive(Debug, Clone, Serialize)]
53pub struct GameBrainFilter {
54    /// Chave do filtro (ex: "platform", "genre", "play_mode").
55    pub key: String,
56    pub values: Vec<GameBrainFilterValue>,
57    /// Operador lógico entre os valores: "OR" ou "AND". A maioria dos filtros usa "OR". Omita para usar o padrão da API.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub connection: Option<String>,
60}
61
62/// Um valor individual de filtro (ex: "pc", "action", "single_player").
63#[derive(Debug, Clone, Serialize)]
64pub struct GameBrainFilterValue {
65    pub value: String,
66}
67
68#[derive(Debug, Clone)]
69pub enum GameBrainSort {
70    Rating,
71    ReleaseDate,
72    Price,
73}
74
75impl GameBrainSort {
76    pub(crate) fn as_str(&self) -> &'static str {
77        match self {
78            GameBrainSort::Rating => "computed_rating",
79            GameBrainSort::ReleaseDate => "release_date",
80            GameBrainSort::Price => "price",
81        }
82    }
83}
84
85#[derive(Debug, Clone)]
86pub enum GameBrainSortOrder {
87    Asc,
88    Desc,
89}
90
91impl GameBrainSortOrder {
92    pub(crate) fn as_str(&self) -> &'static str {
93        match self {
94            GameBrainSortOrder::Asc => "asc",
95            GameBrainSortOrder::Desc => "desc",
96        }
97    }
98}
99
100/// Jogo similar retornado para o frontend.
101///
102/// Subset dos campos disponíveis na resposta de /similar.
103/// Inclui screenshots e micro_trailer para a UI da aba Descoberta.
104#[derive(Debug, Clone, Serialize, Deserialize)]
105#[serde(rename_all = "camelCase")]
106pub struct SimilarGame {
107    /// ID no formato "gamebrain:{id}" para consistência com GameBrainSearchResult.
108    pub id: String,
109    pub name: String,
110    pub cover_url: Option<String>,
111    pub genre: Option<String>,
112    pub year: Option<u32>,
113    /// Rating em percentual (0–100), convertido de 0.0–1.0.
114    pub rating: Option<f64>,
115    pub link: Option<String>,
116    /// Primeiros screenshots disponíveis (máx 4 pela API).
117    pub screenshots: Vec<String>,
118    /// URL do micro-trailer em .webm (Steam CDN), se disponível.
119    pub micro_trailer: Option<String>,
120    /// Flag de conteúdo adulto — o frontend pode usar para bloquear a exibição automática de imagens.
121    pub adult_only: bool,
122}
123
124/// Mídia de um jogo retornada para a aba Mídia do GameWindow.
125///
126/// Separa os vídeos em dois grupos já classificados:
127/// - `trailers`: `.webm` do Steam CDN — reprodução direta no `<video>`
128/// - `youtube_embeds`: URLs `youtube-nocookie.com` — renderizadas em `<iframe>`
129///
130/// Essa separação acontece no backend para não vazar lógica de parsing de URL para o frontend.
131#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct GameMedia {
133    pub screenshots: Vec<String>,
134    /// `.webm` diretos (Steam CDN). Prontos para `<video src=...>`.
135    pub trailers: Vec<String>,
136    /// Embeds do YouTube (`youtube-nocookie.com/embed/...`). Prontos para `<iframe src=...>`.
137    pub youtube_embeds: Vec<String>,
138    /// Micro-trailer de loop curto, se disponível.
139    pub micro_trailer: Option<String>,
140}