1use serde::{Deserialize, Serialize};
2use serde_repr::*;
3use strum::IntoEnumIterator;
4use strum_macros::EnumIter;
5
6use crate::format::release::*;
7use crate::format::schema::Platform;
8use crate::format::vn::VisualNovel;
9
10#[derive(Deserialize, Serialize, Debug)]
11pub struct UList {
12 pub id: Option<String>,
14 pub added: Option<u64>,
16 pub voted: Option<u64>,
18 pub lastmod: Option<u64>,
20 pub vote: Option<u8>,
22 pub started: Option<String>,
24 pub finished: Option<String>,
26 pub notes: Option<String>,
27 pub labels: Option<Vec<UListLabel>>,
29 pub vn: Option<VisualNovel>,
30 pub releases: Option<Vec<UListRelease>>,
31}
32
33#[derive(Deserialize, Serialize, Debug)]
34pub struct UListLabel {
35 pub id: Option<u32>,
36 pub label: Option<String>,
37}
38
39#[derive(Deserialize, Serialize, Debug)]
40pub struct UListRelease {
41 pub list_status: Option<UListStatus>,
42 pub id: Option<String>,
44 pub title: Option<String>,
45 pub alttitle: Option<String>,
46 pub languages: Option<Vec<ReleaseLanguage>>,
47 pub platforms: Option<Vec<Platform>>,
48 pub medium: Option<Vec<ReleaseMedia>>,
49 pub vns: Option<Vec<ReleaseVnRelation>>,
50 pub producers: Option<Vec<ReleaseProducer>>,
51 pub released: Option<String>,
52 pub minage: Option<u8>,
53 pub patch: Option<bool>,
54 pub freeware: Option<bool>,
55 pub uncensored: Option<bool>,
56 pub official: Option<bool>,
57 pub has_ero: Option<bool>,
58 pub resolution: Option<Resolution>,
59 pub engine: Option<String>,
60 pub voiced: Option<VoicedType>,
61 pub notes: Option<String>,
62 pub gtin: Option<String>,
63 pub catalog: Option<String>,
64 pub extlinks: Option<Vec<ExtLink>>,
65}
66
67#[derive(Deserialize_repr, Serialize_repr, PartialEq, Debug)]
68#[repr(u8)]
69pub enum UListStatus {
70 Unknown = 0,
71 Pending = 1,
72 Obtained = 2,
73 OnLoan = 3,
74 Deleted = 4,
75}
76
77#[derive(Deserialize, Serialize, Debug)]
78pub struct UListLabels {
79 pub labels: Option<Vec<UListLabelsInst>>,
80}
81
82#[derive(Deserialize, Serialize, Debug)]
83pub struct UListLabelsInst {
84 pub id: Option<u32>,
86 pub private: Option<bool>,
88 pub label: Option<String>,
89 pub count: Option<u32>,
90}
91
92pub struct UListLabelsFieldChoices(pub Vec<UListLabelsField>);
93
94#[derive(Serialize, EnumIter)]
95#[serde(rename_all = "snake_case")]
96pub enum UListLabelsField {
97 Count,
98}
99
100impl UListLabelsFieldChoices {
101 pub fn new() -> Self {
102 UListLabelsFieldChoices(vec![])
103 }
104
105 pub fn from(vec: Vec<UListLabelsField>) -> Self {
106 UListLabelsFieldChoices(vec)
107 }
108
109 pub fn all() -> Self {
110 let mut vec = Vec::with_capacity(UListLabelsField::iter().len());
111 for variant in UListLabelsField::iter() {
112 vec.push(variant);
113 }
114 UListLabelsFieldChoices(vec)
115 }
116
117 pub fn to_csv(&self) -> String {
118 self.0
119 .iter()
120 .map(|field| serde_json::to_string(&field).unwrap().replace("\"", ""))
121 .collect::<Vec<String>>()
122 .join(",")
123 }
124}
125
126#[derive(Deserialize, Serialize, Debug)]
127pub struct UListPatch {
128 #[serde(skip_serializing_if = "Option::is_none")]
129 vote: Option<u8>,
130 #[serde(skip_serializing_if = "Option::is_none")]
131 notes: Option<String>,
132 #[serde(skip_serializing_if = "Option::is_none")]
133 started: Option<String>,
134 #[serde(skip_serializing_if = "Option::is_none")]
135 finished: Option<String>,
136 #[serde(skip_serializing_if = "Option::is_none")]
138 labels: Option<Vec<LabelId>>,
139 #[serde(skip_serializing_if = "Option::is_none")]
141 labels_set: Option<Vec<LabelId>>,
142 #[serde(skip_serializing_if = "Option::is_none")]
144 labels_unset: Option<Vec<LabelId>>,
145}
146
147pub struct Date {
148 pub year: u16,
149 pub month: u8,
150 pub day: u8,
151}
152
153impl Date {
154 fn format(self) -> String {
155 let s = format!("{:04}-{:02}-{:02}", self.year, self.month, self.day);
156 s
157 }
158}
159
160#[derive(Deserialize_repr, Serialize_repr, PartialEq, Debug)]
161#[repr(u8)]
162pub enum LabelId {
163 Playing = 1,
164 Finished = 2,
165 Stalled = 3,
166 Dropped = 4,
167 WishList = 5,
168 BlackList = 6,
169}
170
171pub struct UListPatchBuilder {
172 pub vote: Option<u8>,
173 pub notes: Option<String>,
174 pub started: Option<String>,
175 pub finished: Option<String>,
176 pub labels: Option<Vec<LabelId>>,
177 pub labels_set: Option<Vec<LabelId>>,
178 pub labels_unset: Option<Vec<LabelId>>,
179}
180
181impl UListPatchBuilder {
182 pub fn new() -> Self {
183 UListPatchBuilder {
184 vote: None,
185 notes: None,
186 started: None,
187 finished: None,
188 labels: None,
189 labels_set: None,
190 labels_unset: None,
191 }
192 }
193
194 pub fn vote(mut self, num: u8) -> Self {
195 self.vote = Some(num.clamp(10, 100));
196 self
197 }
198
199 pub fn notes(mut self, ctx: String) -> Self {
200 self.notes = Some(ctx);
201 self
202 }
203
204 pub fn started(mut self, start: Date) -> Self {
205 self.started = Some(start.format());
206 self
207 }
208
209 pub fn finished(mut self, finish: Date) -> Self {
210 self.finished = Some(finish.format());
211 self
212 }
213
214 pub fn labels(mut self, l: Vec<LabelId>) -> Self {
215 self.labels = Some(l);
216 self
217 }
218
219 pub fn labels_set(mut self, l: Vec<LabelId>) -> Self {
220 self.labels_set = Some(l);
221 self
222 }
223
224 pub fn labels_unset(mut self, l: Vec<LabelId>) -> Self {
225 self.labels_unset = Some(l);
226 self
227 }
228
229 pub fn build(self) -> UListPatch {
230 UListPatch {
231 vote: self.vote,
232 notes: self.notes,
233 started: self.started,
234 finished: self.finished,
235 labels: self.labels,
236 labels_set: self.labels_set,
237 labels_unset: self.labels_unset,
238 }
239 }
240}