1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Default, Deserialize, Serialize)]
11pub struct ExportUrls {
12 #[serde(default)]
14 pub epub: Option<String>,
15 #[serde(default)]
17 pub html: Option<String>,
18 #[serde(default)]
20 pub txt: Option<String>,
21 #[serde(default)]
23 pub md: Option<String>,
24 #[serde(default)]
26 pub mobi: Option<String>,
27 #[serde(default)]
29 pub pdf: Option<String>,
30 #[serde(default)]
32 pub azw3: Option<String>,
33 #[serde(default)]
35 pub docx: Option<String>,
36 #[serde(default)]
38 pub fb2: Option<String>,
39 #[serde(default)]
41 pub kepub: Option<String>,
42}
43
44impl ExportUrls {
45 pub fn preferred(&self) -> Option<(String, String)> {
47 if let Some(e) = &self.epub {
48 return Some(("epub".to_string(), e.clone()));
49 }
50 self.first()
51 }
52
53 pub fn first(&self) -> Option<(String, String)> {
55 macro_rules! try_fmt {
56 ($name:literal, $field:ident) => {
57 if let Some(u) = &self.$field {
58 return Some(($name.to_string(), u.clone()));
59 }
60 };
61 }
62 try_fmt!("html", html);
63 try_fmt!("txt", txt);
64 try_fmt!("md", md);
65 try_fmt!("mobi", mobi);
66 try_fmt!("pdf", pdf);
67 try_fmt!("azw3", azw3);
68 try_fmt!("docx", docx);
69 try_fmt!("fb2", fb2);
70 try_fmt!("kepub", kepub);
71 None
72 }
73
74 pub fn available(&self) -> Vec<(String, String)> {
76 let mut out = Vec::new();
77 macro_rules! push {
78 ($name:literal, $field:ident) => {
79 if let Some(u) = &self.$field {
80 out.push(($name.to_string(), u.clone()));
81 }
82 };
83 }
84 push!("epub", epub);
85 push!("html", html);
86 push!("txt", txt);
87 push!("md", md);
88 push!("mobi", mobi);
89 push!("pdf", pdf);
90 push!("azw3", azw3);
91 push!("docx", docx);
92 push!("fb2", fb2);
93 push!("kepub", kepub);
94 out
95 }
96}
97
98#[derive(Debug, Clone, Deserialize, Serialize)]
100pub struct FicMeta {
101 pub id: String,
103 #[serde(default)]
105 pub work_id: Option<i64>,
106 pub title: String,
108 pub author: String,
110 pub chapters: i64,
112 pub words: i64,
114 pub description: String,
116 pub status: String,
118 pub source: String,
120 pub created: String,
122 pub updated: String,
124 #[serde(default)]
126 pub extra_meta: Option<serde_json::Value>,
127 #[serde(default)]
129 pub raw_extended_meta: Option<serde_json::Value>,
130 pub author_url: String,
132 pub author_local_id: String,
134 pub source_id: i64,
136 pub author_id: i64,
138}
139
140#[derive(Debug, Clone, Deserialize, Serialize)]
142pub struct ExportResponse {
143 pub err: i32,
145 #[serde(default)]
147 pub q: Option<String>,
148 #[serde(default)]
150 pub msg: Option<String>,
151 #[serde(default)]
153 pub url_id: Option<String>,
154 #[serde(default)]
156 pub slug: Option<String>,
157 #[serde(default)]
159 pub meta: Option<FicMeta>,
160 #[serde(default)]
162 pub hashes: Option<serde_json::Map<String, serde_json::Value>>,
163 #[serde(default)]
165 pub urls: Option<ExportUrls>,
166 #[serde(default)]
168 pub epub_url: Option<String>,
169 #[serde(default)]
171 pub html_url: Option<String>,
172 #[serde(default)]
174 pub txt_url: Option<String>,
175 #[serde(default)]
177 pub md_url: Option<String>,
178 #[serde(default)]
180 pub mobi_url: Option<String>,
181 #[serde(default)]
183 pub pdf_url: Option<String>,
184 #[serde(default)]
186 pub azw3_url: Option<String>,
187 #[serde(default)]
189 pub docx_url: Option<String>,
190 #[serde(default)]
192 pub fb2_url: Option<String>,
193 #[serde(default)]
195 pub kepub_url: Option<String>,
196 #[serde(default)]
198 pub notes: Option<Vec<String>>,
199}
200
201impl ExportResponse {
202 pub fn flat_urls(&self) -> ExportUrls {
204 ExportUrls {
205 epub: self.epub_url.clone(),
206 html: self.html_url.clone(),
207 txt: self.txt_url.clone(),
208 md: self.md_url.clone(),
209 mobi: self.mobi_url.clone(),
210 pdf: self.pdf_url.clone(),
211 azw3: self.azw3_url.clone(),
212 docx: self.docx_url.clone(),
213 fb2: self.fb2_url.clone(),
214 kepub: self.kepub_url.clone(),
215 }
216 }
217}
218
219#[derive(Debug, Clone, Deserialize, Serialize)]
221pub struct ConvertResponse {
222 pub err: i32,
224 #[serde(default)]
226 pub q: Option<String>,
227 #[serde(default)]
229 pub msg: Option<String>,
230 #[serde(default)]
232 pub url_id: Option<String>,
233 #[serde(default)]
235 pub format: Option<String>,
236 #[serde(default)]
238 pub hash: Option<String>,
239 #[serde(default)]
241 pub url: Option<String>,
242 #[serde(default)]
244 pub cached: Option<bool>,
245 #[serde(default)]
247 pub elapsed_ms: Option<i64>,
248}
249
250#[derive(Debug, Clone, Default, Deserialize, Serialize)]
252pub struct RecResult {
253 pub url_id: String,
255 pub title: String,
257 pub author: String,
259 #[serde(default)]
261 pub words: i64,
262 #[serde(default)]
264 pub chapters: i64,
265 #[serde(default)]
267 pub status: String,
268 #[serde(default)]
270 pub site_domain: String,
271 #[serde(default)]
273 pub summary: String,
274 #[serde(default)]
276 pub score: f64,
277 #[serde(default)]
279 pub community_score: f64,
280 #[serde(default)]
282 pub download_urls: serde_json::Map<String, serde_json::Value>,
283}
284
285#[derive(Debug, Clone, Deserialize, Serialize)]
287pub struct RecommendationsResponse {
288 pub err: i32,
290 #[serde(default)]
292 pub url_id: String,
293 #[serde(default)]
295 pub site_domain: Option<String>,
296 #[serde(default)]
298 pub recommendations: Vec<RecResult>,
299 #[serde(default)]
301 pub generated_at: String,
302}
303
304#[derive(Debug, Clone, Deserialize, Serialize)]
306pub struct PersonalRecommendationsResponse {
307 pub err: i32,
309 #[serde(default)]
311 pub enough_data: bool,
312 #[serde(default)]
314 pub recs: Vec<RecResult>,
315 #[serde(default)]
317 pub based_on: Vec<serde_json::Value>,
318 #[serde(default)]
320 pub strategies: Vec<serde_json::Value>,
321}
322
323#[derive(Debug, Clone, Deserialize, Serialize)]
325pub struct Suggestion {
326 pub id: i64,
328 pub suggested_url_id: String,
330 #[serde(default)]
332 pub comment: Option<String>,
333 pub net_votes: i64,
335 #[serde(default)]
337 pub created: Option<String>,
338}
339
340#[derive(Debug, Clone, Deserialize, Serialize)]
342pub struct VotesResponse {
343 pub err: i32,
345 pub url_id: String,
347 #[serde(default)]
349 pub suggestions: Vec<Suggestion>,
350}
351
352#[derive(Debug, Clone, Deserialize, Serialize)]
354pub struct SearchResult {
355 pub url_id: String,
357 pub title: String,
359 pub author: String,
361 pub source: String,
363 pub words: i64,
365 pub chapters: i64,
367 pub status: String,
369 pub description: String,
371 #[serde(default)]
373 pub updated: Option<String>,
374 #[serde(default)]
376 pub rank: Option<f64>,
377 #[serde(default)]
379 pub snippet: Option<String>,
380 #[serde(default)]
382 pub tags: Vec<serde_json::Value>,
383 #[serde(default)]
385 pub total_freeform: usize,
386 #[serde(default)]
388 pub comment_count: i64,
389 #[serde(default)]
391 pub kudos_count: i64,
392}
393
394#[derive(Debug, Clone, Default, Deserialize, Serialize)]
396pub struct SearchFacets {
397 #[serde(default)]
399 pub fandoms: Vec<serde_json::Value>,
400 #[serde(default)]
402 pub tags: Vec<serde_json::Value>,
403}
404
405#[derive(Debug, Clone, Deserialize, Serialize)]
407pub struct SearchResponse {
408 pub total: i64,
410 pub page: usize,
412 pub per_page: usize,
414 pub results: Vec<SearchResult>,
416 #[serde(default)]
418 pub facets: SearchFacets,
419}
420
421#[derive(Debug, Clone, Deserialize, Serialize)]
423pub struct AskResponse {
424 #[serde(flatten)]
426 pub search: SearchResponse,
427 #[serde(default)]
429 pub used_ask: bool,
430 #[serde(default)]
432 pub ask_query: Option<String>,
433 #[serde(default)]
435 pub translation: Option<serde_json::Value>,
436}
437
438#[derive(Debug, Clone, Deserialize, Serialize)]
440pub struct BodySearchResponse {
441 pub err: i32,
443 #[serde(default)]
445 pub total: i64,
446 #[serde(default)]
448 pub page: usize,
449 #[serde(default)]
451 pub per_page: usize,
452 #[serde(default)]
454 pub results: Vec<BodySearchHit>,
455}
456
457#[derive(Debug, Clone, Deserialize, Serialize)]
459pub struct BodySearchHit {
460 pub url_id: String,
462 #[serde(default)]
464 pub work_id: Option<i64>,
465 pub title: String,
467 pub author: String,
469 #[serde(default)]
471 pub source: String,
472 #[serde(default)]
474 pub words: i64,
475 #[serde(default)]
477 pub chapters: i64,
478 #[serde(default)]
480 pub status: String,
481 #[serde(default)]
483 pub description: String,
484 #[serde(default)]
486 pub body_snippet: Option<String>,
487}
488
489#[derive(Debug, Clone, Deserialize, Serialize)]
491pub struct FeedItem {
492 #[serde(default)]
494 pub work_id: i64,
495 #[serde(default)]
497 pub url_id: String,
498 #[serde(default)]
500 pub title: String,
501 #[serde(default)]
503 pub author: String,
504 #[serde(default)]
506 pub updated: String,
507 #[serde(default)]
509 pub format: String,
510 #[serde(default)]
512 pub note: Option<String>,
513}
514
515#[derive(Debug, Clone, Deserialize, Serialize)]
517pub struct FeedResponse {
518 pub err: i32,
520 #[serde(default)]
522 pub items: Vec<FeedItem>,
523 #[serde(default)]
525 pub page: i64,
526 #[serde(default)]
528 pub per_page: i64,
529 #[serde(default)]
531 pub total: i64,
532}
533
534#[derive(Debug, Clone, Deserialize, Serialize)]
536pub struct RequestItem {
537 pub id: i64,
539 pub title: String,
541 pub body: String,
543 #[serde(default)]
545 pub seed_work_id: Option<i64>,
546 pub status: String,
548 #[serde(default)]
550 pub created_at: String,
551 #[serde(default)]
553 pub answer_count: i64,
554 #[serde(default)]
556 pub upvotes: i64,
557}
558
559#[derive(Debug, Clone, Deserialize, Serialize)]
561pub struct RequestsResponse {
562 pub err: i32,
564 #[serde(default)]
566 pub items: Vec<RequestItem>,
567 #[serde(default)]
569 pub page: i64,
570 #[serde(default)]
572 pub status: String,
573}
574
575#[derive(Debug, Clone, Deserialize, Serialize)]
577pub struct ClusterRow {
578 pub id: i64,
580 pub text: String,
582 #[serde(default)]
584 pub elo_rating: f64,
585 #[serde(default)]
587 pub matches_played: i64,
588 #[serde(default)]
590 pub times_picked_best: i64,
591 #[serde(default)]
593 pub times_picked_worst: i64,
594 #[serde(default)]
596 pub suggestions: i64,
597 #[serde(default)]
599 pub status: String,
600 #[serde(default)]
602 pub controversy: i64,
603}
604
605#[derive(Debug, Clone, Deserialize, Serialize)]
607pub struct ConsensusResponse {
608 pub err: i32,
610 #[serde(default)]
612 pub leaderboard: Vec<ClusterRow>,
613 #[serde(default)]
615 pub controversy: Vec<ClusterRow>,
616}
617
618#[derive(Debug, Clone, Deserialize, Serialize)]
620pub struct AuthResponse {
621 pub token: String,
623 pub user: AuthUserModel,
625}
626
627#[derive(Debug, Clone, Deserialize, Serialize)]
629pub struct AuthUserModel {
630 pub id: i64,
632 pub username: String,
634 pub role: i16,
636 pub reputation: i64,
638 #[serde(default)]
640 pub email: Option<String>,
641 #[serde(default)]
643 pub level: i16,
644 #[serde(default)]
646 pub exp: i64,
647}
648
649#[derive(Debug, Clone, Deserialize, Serialize)]
651pub struct MeResponse {
652 pub err: i32,
654 #[serde(default)]
656 pub user: Option<AuthUserModel>,
657}
658
659#[derive(Debug, Clone, Deserialize, Serialize)]
667pub struct ForumCategory {
668 pub id: i64,
670 pub slug: String,
672 pub title: String,
674 #[serde(default)]
676 pub description: String,
677 #[serde(default)]
679 pub position: i32,
680 #[serde(default)]
682 pub is_mod_only: bool,
683 #[serde(default)]
685 pub created_at: String,
686 #[serde(default)]
688 pub topic_count: i64,
689 #[serde(default)]
691 pub last_activity_at: Option<String>,
692}
693
694#[derive(Debug, Clone, Deserialize, Serialize)]
696pub struct ForumCategoriesResponse {
697 pub err: i32,
699 #[serde(default)]
701 pub items: Vec<ForumCategory>,
702}
703
704#[derive(Debug, Clone, Deserialize, Serialize)]
706pub struct ForumTopic {
707 pub id: i64,
709 pub title: String,
711 #[serde(default)]
713 pub topic_slug: Option<String>,
714 pub author_id: i64,
716 #[serde(default)]
718 pub author_username: String,
719 #[serde(default)]
721 pub reply_count: i64,
722 #[serde(default)]
724 pub vote_score: i64,
725 #[serde(default)]
727 pub view_count: i64,
728 #[serde(default)]
730 pub last_post_id: Option<i64>,
731 #[serde(default)]
733 pub status: String,
734 #[serde(default)]
736 pub last_activity_at: String,
737 #[serde(default)]
739 pub created_at: String,
740 #[serde(default)]
742 pub unread: bool,
743}
744
745#[derive(Debug, Clone, Deserialize, Serialize)]
747pub struct ForumTopicList {
748 pub err: i32,
750 #[serde(default)]
752 pub items: Vec<ForumTopic>,
753 #[serde(default)]
755 pub next_cursor: Option<i64>,
756 #[serde(default)]
758 pub category: String,
759 #[serde(default)]
761 pub limit: i64,
762}
763
764#[derive(Debug, Clone, Deserialize, Serialize)]
766pub struct ForumQuote {
767 #[serde(default)]
769 pub author_username: String,
770 #[serde(default)]
772 pub preview: String,
773}
774
775#[derive(Debug, Clone, Deserialize, Serialize)]
777pub struct ForumPost {
778 pub id: i64,
780 pub author_id: i64,
782 #[serde(default)]
784 pub author_username: String,
785 #[serde(default)]
787 pub body: String,
788 #[serde(default)]
790 pub quote_of: Option<i64>,
791 #[serde(default)]
793 pub quote: Option<ForumQuote>,
794 #[serde(default)]
796 pub edited_at: Option<String>,
797 #[serde(default)]
799 pub deleted_at: Option<String>,
800 #[serde(default)]
802 pub created_at: String,
803 #[serde(default)]
805 pub score: i32,
806 #[serde(default)]
808 pub is_op: bool,
809}
810
811#[derive(Debug, Clone, Deserialize, Serialize)]
813pub struct ForumTopicDetail {
814 pub err: i32,
816 pub id: i64,
818 pub title: String,
820 #[serde(default)]
822 pub topic_slug: Option<String>,
823 pub author_id: i64,
825 #[serde(default)]
827 pub author_username: String,
828 #[serde(default)]
830 pub category_slug: String,
831 #[serde(default)]
833 pub category_title: String,
834 #[serde(default)]
836 pub status: String,
837 #[serde(default)]
839 pub body: String,
840 #[serde(default)]
842 pub payload: serde_json::Value,
843 #[serde(default)]
845 pub view_count: i64,
846 #[serde(default)]
848 pub created_at: String,
849 #[serde(default)]
851 pub updated_at: Option<String>,
852 #[serde(default)]
854 pub items: Vec<ForumPost>,
855 #[serde(default)]
857 pub next_cursor: Option<i64>,
858 #[serde(default)]
860 pub limit: i64,
861 #[serde(default)]
863 pub view_count_before: i64,
864}
865
866#[derive(Debug, Clone, Deserialize, Serialize)]
868pub struct ForumSearchHit {
869 #[serde(default)]
871 pub r#type: String,
872 pub topic_id: i64,
874 #[serde(default)]
876 pub topic_slug: Option<String>,
877 #[serde(default)]
879 pub post_id: Option<i64>,
880 pub author_id: i64,
882 #[serde(default)]
884 pub author_username: String,
885 #[serde(default)]
887 pub title: String,
888 #[serde(default)]
890 pub body: String,
891 #[serde(default)]
893 pub snippet: Option<String>,
894 #[serde(default)]
896 pub category_slug: String,
897 #[serde(default)]
899 pub category_title: String,
900 #[serde(default)]
902 pub created_at: String,
903}
904
905#[derive(Debug, Clone, Deserialize, Serialize)]
907pub struct ForumSearchResponse {
908 pub err: i32,
910 #[serde(default)]
912 pub q: String,
913 #[serde(default)]
915 pub results: Vec<ForumSearchHit>,
916 #[serde(default)]
918 pub next_cursor: Option<i64>,
919 #[serde(default)]
921 pub limit: i64,
922 #[serde(default)]
924 pub total: i64,
925}
926
927#[derive(Debug, Clone, Deserialize, Serialize)]
929pub struct ForumCreateTopicResponse {
930 pub err: i32,
932 #[serde(default)]
934 pub id: i64,
935 #[serde(default)]
937 pub post_id: i64,
938 #[serde(default)]
940 pub topic_slug: Option<String>,
941 #[serde(default)]
943 pub msg: String,
944}
945
946#[derive(Debug, Clone, Deserialize, Serialize)]
948pub struct ForumPostCreated {
949 pub err: i32,
951 #[serde(default)]
953 pub id: i64,
954 #[serde(default)]
956 pub msg: String,
957}
958
959#[derive(Debug, Clone, Deserialize, Serialize)]
961pub struct ForumFollowState {
962 pub err: i32,
964 #[serde(default)]
966 pub following: bool,
967 #[serde(default)]
969 pub follower_count: i64,
970}
971
972#[derive(Debug, Clone, Deserialize, Serialize)]
974pub struct ForumMarkRead {
975 pub err: i32,
977 #[serde(default)]
979 pub last_read_post_id: i64,
980 #[serde(default)]
982 pub updated_at: String,
983}
984
985#[derive(Debug, Clone, Deserialize, Serialize)]
987pub struct ForumModerationStatus {
988 pub err: i32,
990 #[serde(default)]
992 pub points_left: i16,
993 #[serde(default)]
995 pub expires_at: Option<String>,
996 #[serde(default)]
998 pub eligible: bool,
999 #[serde(default)]
1001 pub reason: Option<String>,
1002}
1003
1004#[derive(Debug, Clone, Deserialize, Serialize)]
1006pub struct ForumModQueueItem {
1007 pub post_id: i64,
1009 pub topic_id: i64,
1011 #[serde(default)]
1013 pub author_username: String,
1014 #[serde(default)]
1016 pub body: String,
1017 #[serde(default)]
1019 pub score: i32,
1020 #[serde(default)]
1022 pub mod_count: i32,
1023 #[serde(default)]
1025 pub reason: Option<String>,
1026 #[serde(default)]
1028 pub created_at: String,
1029}
1030
1031#[derive(Debug, Clone, Deserialize, Serialize)]
1033pub struct ForumModerationQueue {
1034 pub err: i32,
1036 #[serde(default)]
1038 pub items: Vec<ForumModQueueItem>,
1039 #[serde(default)]
1041 pub count: i64,
1042 #[serde(default)]
1044 pub pool_too_small: bool,
1045}
1046
1047#[derive(Debug, Clone, Deserialize, Serialize)]
1049pub struct ForumModerateResponse {
1050 pub err: i32,
1052 #[serde(default)]
1054 pub delta: i16,
1055 #[serde(default)]
1057 pub score_after: i32,
1058 #[serde(default)]
1060 pub hidden_until: Option<String>,
1061}
1062
1063#[derive(Debug, Clone, Deserialize, Serialize)]
1065pub struct ForumMetamodItem {
1066 pub action_id: i64,
1068 pub post_id: i64,
1070 pub topic_id: i64,
1072 #[serde(default)]
1074 pub excerpt: String,
1075 #[serde(default)]
1077 pub reason: String,
1078 #[serde(default)]
1080 pub delta: i16,
1081 #[serde(default)]
1083 pub score_after: i32,
1084 #[serde(default)]
1086 pub created_at: String,
1087}
1088
1089#[derive(Debug, Clone, Deserialize, Serialize)]
1091pub struct ForumMetamodQueue {
1092 pub err: i32,
1094 #[serde(default)]
1096 pub items: Vec<ForumMetamodItem>,
1097 #[serde(default)]
1099 pub count: i64,
1100 #[serde(default)]
1102 pub pool_too_small: bool,
1103}
1104
1105#[derive(Debug, Clone, Deserialize, Serialize)]
1107pub struct ForumMetamodVoteResponse {
1108 pub err: i32,
1110}