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}