1pub mod curation;
3
4pub mod report;
5use macros::make_path_parts;
6pub use report::{JigReport, ReportId};
7
8pub mod codes;
9
10pub mod player;
11pub use player::{JigPlayerSettings, TextDirection};
12
13use chrono::{DateTime, Utc};
14use serde::{Deserialize, Serialize};
15use std::collections::{HashMap, HashSet};
16
17use super::{
18 additional_resource::AdditionalResource,
19 asset::{DraftOrLive, OrderBy, PrivacyLevel, UserOrMe},
20 category::CategoryId,
21 meta::{AffiliationId, AgeRangeId, ResourceTypeId},
22 module::LiteModule,
23 playlist::PlaylistResponse,
24 user::UserId,
25};
26use crate::domain::UpdateNonNullable;
27use crate::{api::endpoints::PathPart, domain::module::body::ThemeId};
28
29wrap_uuid! {
30 pub struct JigId
32}
33
34make_path_parts!(JigCreatePath => "/v1/jig");
35
36#[derive(Serialize, Deserialize, Debug, Default)]
40#[serde(rename_all = "camelCase")]
41pub struct JigCreateRequest {
42 #[serde(default)]
44 pub display_name: String,
45
46 #[serde(skip_serializing_if = "Vec::is_empty")]
48 #[serde(default)]
49 pub age_ranges: Vec<AgeRangeId>,
50
51 #[serde(skip_serializing_if = "Vec::is_empty")]
53 #[serde(default)]
54 pub affiliations: Vec<AffiliationId>,
55
56 #[serde(default)]
60 pub language: String,
61
62 #[serde(skip_serializing_if = "Vec::is_empty")]
64 #[serde(default)]
65 pub categories: Vec<CategoryId>,
66
67 #[serde(default)]
69 pub description: String,
70
71 #[serde(default)]
73 pub default_player_settings: JigPlayerSettings,
74}
75
76#[derive(Serialize, Deserialize, Clone, Debug)]
78#[serde(rename_all = "camelCase")]
79pub struct JigData {
80 pub created_at: DateTime<Utc>,
82
83 pub last_edited: Option<DateTime<Utc>>,
85
86 pub draft_or_live: DraftOrLive,
88
89 pub display_name: String,
91
92 pub modules: Vec<LiteModule>,
96
97 pub age_ranges: Vec<AgeRangeId>,
99
100 pub affiliations: Vec<AffiliationId>,
102
103 pub language: String,
107
108 pub categories: Vec<CategoryId>,
110
111 pub additional_resources: Vec<AdditionalResource>,
113
114 pub description: String,
116
117 pub default_player_settings: JigPlayerSettings,
119
120 pub theme: ThemeId,
122
123 pub audio_background: Option<AudioBackground>,
125
126 pub audio_effects: AudioEffects,
128
129 pub privacy_level: PrivacyLevel,
131
132 pub locked: bool,
134
135 pub other_keywords: String,
137
138 pub translated_keywords: String,
140
141 #[serde(default)]
143 pub translated_description: HashMap<String, String>,
144}
145
146#[derive(Serialize, Deserialize, Clone, Debug, Default)]
148#[serde(rename_all = "camelCase")]
149pub struct JigAdminData {
150 #[serde(default)]
152 pub rating: Option<JigRating>,
153
154 pub blocked: bool,
156
157 pub curated: bool,
159
160 pub premium: bool,
162}
163
164#[derive(Serialize, Deserialize, Clone, Debug, Default)]
166#[serde(rename_all = "camelCase")]
167pub struct JigUpdateAdminDataRequest {
168 #[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
170 pub rating: UpdateNonNullable<JigRating>,
171
172 #[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
174 pub blocked: UpdateNonNullable<bool>,
175
176 #[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
178 pub curated: UpdateNonNullable<bool>,
179
180 #[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
182 pub premium: UpdateNonNullable<bool>,
183}
184
185#[derive(Serialize, Deserialize, Clone, Debug)]
187#[serde(rename_all = "camelCase")]
188pub struct JigAdminTransferRequest {
189 pub from: UserId,
191
192 pub to: UserId,
194
195 pub jig_ids: Vec<JigId>,
197}
198
199make_path_parts!(JigTransferAdminPath => "/v1/jig/admin/transfer");
200
201#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
203#[cfg_attr(feature = "backend", derive(sqlx::Type))]
204#[serde(rename_all = "camelCase")]
205#[repr(i16)]
206pub enum JigRating {
207 #[allow(missing_docs)]
208 One = 1,
209 #[allow(missing_docs)]
210 Two = 2,
211 #[allow(missing_docs)]
212 Three = 3,
213}
214
215impl TryFrom<u8> for JigRating {
216 type Error = ();
217
218 fn try_from(num: u8) -> Result<Self, Self::Error> {
219 match num {
220 1 => Ok(Self::One),
221 2 => Ok(Self::Two),
222 3 => Ok(Self::Three),
223 _ => Err(()),
224 }
225 }
226}
227
228#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
230#[cfg_attr(feature = "backend", derive(sqlx::Type))]
231#[serde(rename_all = "camelCase")]
232#[repr(i16)]
233pub enum AudioBackground {
234 #[allow(missing_docs)]
235 FunForKids = 0,
236 #[allow(missing_docs)]
237 DancingHappy = 1,
238 #[allow(missing_docs)]
239 Jigzi1 = 2,
240 #[allow(missing_docs)]
241 Jigzi2 = 3,
242 #[allow(missing_docs)]
243 Jigzi3 = 4,
244 #[allow(missing_docs)]
245 Awestruck = 5,
246 #[allow(missing_docs)]
247 BayBounce = 6,
248 #[allow(missing_docs)]
249 CalmAndReflective = 7,
250 #[allow(missing_docs)]
251 DayWithoutRain = 8,
252 #[allow(missing_docs)]
253 DestinationFreedom = 9,
254 #[allow(missing_docs)]
255 FutureMemories = 10,
256 #[allow(missing_docs)]
257 HappyInstrumental = 11,
258 #[allow(missing_docs)]
259 HappyWhistle = 12,
260 #[allow(missing_docs)]
261 KidsInstrumental = 13,
262 #[allow(missing_docs)]
263 PartyKids = 14,
264 #[allow(missing_docs)]
265 RhythmKids = 15,
266 #[allow(missing_docs)]
267 SunKissed = 16,
268
269 #[allow(missing_docs)]
271 LegacyCuckooToYou = 101,
272 #[allow(missing_docs)]
273 LegacyFirstEtude = 102,
274 #[allow(missing_docs)]
275 LegacyHanerotHalalu = 103,
276 #[allow(missing_docs)]
277 LegacyIslandRomp = 104,
278 #[allow(missing_docs)]
279 LegacyJiTap = 105,
280 #[allow(missing_docs)]
281 LegacyMaozTzur = 106,
282 #[allow(missing_docs)]
283 LegacyModehAni = 107,
284 #[allow(missing_docs)]
285 LegacyMonkeyBars = 108,
286 #[allow(missing_docs)]
287 LegacyMorningZoo = 109,
288 #[allow(missing_docs)]
289 LegacyNapTime = 110,
290 #[allow(missing_docs)]
291 LegacyPlaylandMarch = 111,
292 #[allow(missing_docs)]
293 LegacyShehechiyanu = 112,
294 #[allow(missing_docs)]
295 LegacySunAndNoClouds = 113,
296 #[allow(missing_docs)]
297 LegacyTeddysBear = 114,
298 #[allow(missing_docs)]
299 LegacyWanderingWalrus = 115,
300 #[allow(missing_docs)]
301 LegacyWindupLullaby = 116,
302}
303
304impl AudioBackground {
305 pub fn variants() -> Vec<Self> {
307 vec![
308 Self::FunForKids,
309 Self::DancingHappy,
310 Self::Jigzi1,
311 Self::Jigzi2,
312 Self::Jigzi3,
313 Self::Awestruck,
314 Self::BayBounce,
315 Self::CalmAndReflective,
316 Self::DayWithoutRain,
317 Self::DestinationFreedom,
318 Self::FutureMemories,
319 Self::HappyInstrumental,
320 Self::HappyWhistle,
321 Self::KidsInstrumental,
322 Self::PartyKids,
323 Self::RhythmKids,
324 Self::SunKissed,
325 ]
326 }
327}
328
329#[derive(Serialize, Deserialize, Debug, Clone, Default)]
331#[serde(rename_all = "camelCase")]
332pub struct AudioEffects {
333 pub feedback_positive: HashSet<AudioFeedbackPositive>,
335
336 pub feedback_negative: HashSet<AudioFeedbackNegative>,
338}
339
340#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq, Hash)]
342#[cfg_attr(feature = "backend", derive(sqlx::Type))]
343#[serde(rename_all = "camelCase")]
344#[repr(i16)]
345pub enum AudioFeedbackNegative {
346 #[allow(missing_docs)]
347 Bang = 0,
348 #[allow(missing_docs)]
349 Boing = 1,
350 #[allow(missing_docs)]
351 Buzz = 2,
352 #[allow(missing_docs)]
353 Buzzer = 3,
354 #[allow(missing_docs)]
355 Clang = 4,
356 #[allow(missing_docs)]
357 Clicks = 5,
358 #[allow(missing_docs)]
359 Incorrect = 6,
360 #[allow(missing_docs)]
361 JumpWrong = 7,
362 #[allow(missing_docs)]
363 NotRight = 8,
364 #[allow(missing_docs)]
365 OhNo = 9,
366 #[allow(missing_docs)]
367 ShortClang = 10,
368 #[allow(missing_docs)]
369 Whir = 11,
370}
371impl AudioFeedbackNegative {
372 pub fn variants() -> Vec<AudioFeedbackNegative> {
374 vec![
375 AudioFeedbackNegative::Bang,
376 AudioFeedbackNegative::Boing,
377 AudioFeedbackNegative::Buzz,
378 AudioFeedbackNegative::Buzzer,
379 AudioFeedbackNegative::Clang,
380 AudioFeedbackNegative::Clicks,
381 AudioFeedbackNegative::Incorrect,
382 AudioFeedbackNegative::JumpWrong,
383 AudioFeedbackNegative::NotRight,
384 AudioFeedbackNegative::OhNo,
385 AudioFeedbackNegative::ShortClang,
386 AudioFeedbackNegative::Whir,
387 ]
388 }
389
390 pub fn default_options() -> Vec<Self> {
392 vec![Self::Boing, Self::Buzz, Self::JumpWrong]
393 }
394}
395
396#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq, Hash)]
398#[cfg_attr(feature = "backend", derive(sqlx::Type))]
399#[serde(rename_all = "camelCase")]
400#[repr(i16)]
401pub enum AudioFeedbackPositive {
402 #[allow(missing_docs)]
403 Correct = 0,
404 #[allow(missing_docs)]
405 Keys = 1,
406 #[allow(missing_docs)]
407 Magic = 2,
408 #[allow(missing_docs)]
409 Notes = 3,
410 #[allow(missing_docs)]
411 StarPing = 4,
412 #[allow(missing_docs)]
413 Ting = 5,
414 #[allow(missing_docs)]
415 Trumpet = 6,
416 #[allow(missing_docs)]
417 VoiceAwesome = 7,
418 #[allow(missing_docs)]
419 VoicesHurray = 8,
420 #[allow(missing_docs)]
421 VoiceYippee = 9,
422 #[allow(missing_docs)]
423 Xylophone = 10,
424 #[allow(missing_docs)]
425 Yes = 11,
426}
427impl AudioFeedbackPositive {
428 pub fn variants() -> Vec<AudioFeedbackPositive> {
430 vec![
431 AudioFeedbackPositive::Correct,
432 AudioFeedbackPositive::Keys,
433 AudioFeedbackPositive::Magic,
434 AudioFeedbackPositive::Notes,
435 AudioFeedbackPositive::StarPing,
436 AudioFeedbackPositive::Ting,
437 AudioFeedbackPositive::Trumpet,
438 AudioFeedbackPositive::VoiceAwesome,
439 AudioFeedbackPositive::VoicesHurray,
440 AudioFeedbackPositive::VoiceYippee,
441 AudioFeedbackPositive::Xylophone,
442 AudioFeedbackPositive::Yes,
443 ]
444 }
445
446 pub fn default_options() -> Vec<Self> {
448 vec![Self::VoiceYippee, Self::Xylophone]
449 }
450}
451
452#[derive(Serialize, Deserialize, Debug, Clone)]
454#[serde(rename_all = "camelCase")]
455pub struct JigResponse {
456 pub id: JigId,
458
459 pub published_at: Option<DateTime<Utc>>,
461
462 pub creator_id: Option<UserId>,
464
465 pub author_id: Option<UserId>,
467
468 pub author_name: Option<String>,
470
471 pub likes: i64,
473
474 pub plays: i64,
476
477 pub live_up_to_date: bool,
479
480 pub jig_data: JigData,
482
483 pub is_liked: bool,
485
486 pub admin_data: JigAdminData,
488}
489
490make_path_parts!(JigGetLivePath => "/v1/jig/{}/live" => JigId);
491
492make_path_parts!(JigGetDraftPath => "/v1/jig/{}/draft" => JigId);
493
494make_path_parts!(JigUpdateDraftDataPath => "/v1/jig/{}" => JigId);
495
496#[derive(Serialize, Deserialize, Debug, Default)]
498#[serde(rename_all = "camelCase")]
499pub struct JigUpdateDraftDataRequest {
500 #[serde(skip_serializing_if = "Option::is_none")]
502 #[serde(default)]
503 pub display_name: Option<String>,
504
505 #[serde(skip_serializing_if = "Option::is_none")]
509 #[serde(default)]
510 pub language: Option<String>,
511
512 #[serde(skip_serializing_if = "Option::is_none")]
514 #[serde(default)]
515 pub categories: Option<Vec<CategoryId>>,
516
517 #[serde(skip_serializing_if = "Option::is_none")]
519 #[serde(default)]
520 pub age_ranges: Option<Vec<AgeRangeId>>,
521
522 #[serde(skip_serializing_if = "Option::is_none")]
524 #[serde(default)]
525 pub affiliations: Option<Vec<AffiliationId>>,
526
527 #[serde(skip_serializing_if = "Option::is_none")]
529 #[serde(default)]
530 pub author_id: Option<UserId>,
531
532 #[serde(skip_serializing_if = "Option::is_none")]
534 #[serde(default)]
535 pub description: Option<String>,
536
537 #[serde(skip_serializing_if = "Option::is_none")]
539 #[serde(default)]
540 pub default_player_settings: Option<JigPlayerSettings>,
541
542 #[serde(skip_serializing_if = "Option::is_none")]
544 #[serde(default)]
545 pub theme: Option<ThemeId>,
546
547 #[serde(deserialize_with = "super::deserialize_optional_field")]
549 #[serde(skip_serializing_if = "Option::is_none")]
550 #[serde(default)]
551 pub audio_background: Option<Option<AudioBackground>>,
552
553 #[serde(skip_serializing_if = "Option::is_none")]
555 #[serde(default)]
556 pub audio_effects: Option<AudioEffects>,
557
558 #[serde(skip_serializing_if = "Option::is_none")]
560 #[serde(default)]
561 pub privacy_level: Option<PrivacyLevel>,
562
563 #[serde(skip_serializing_if = "Option::is_none")]
565 #[serde(default)]
566 pub other_keywords: Option<String>,
567}
568
569make_path_parts!(JigPublishPath => "/v1/jig/{}/draft/publish" => JigId);
570
571make_path_parts!(JigBrowsePath => "/v1/jig/browse");
572
573#[derive(Serialize, Deserialize, Clone, Debug, Default)]
575#[serde(rename_all = "camelCase")]
576pub struct JigBrowseQuery {
577 #[serde(default)]
579 #[serde(skip_serializing_if = "Option::is_none")]
580 pub is_published: Option<bool>,
581
582 #[serde(default)]
584 #[serde(skip_serializing_if = "Option::is_none")]
585 pub author_id: Option<UserOrMe>,
586
587 #[serde(default)]
589 #[serde(skip_serializing_if = "Option::is_none")]
590 pub page: Option<u32>,
591
592 #[serde(default)]
594 #[serde(skip_serializing_if = "Option::is_none")]
595 pub draft_or_live: Option<DraftOrLive>,
596
597 #[serde(default)]
599 #[serde(deserialize_with = "super::from_csv")]
600 #[serde(skip_serializing_if = "Vec::is_empty")]
601 pub privacy_level: Vec<PrivacyLevel>,
602
603 #[serde(default)]
605 #[serde(skip_serializing_if = "Option::is_none")]
606 pub blocked: Option<bool>,
607
608 #[serde(default)]
610 #[serde(skip_serializing_if = "Option::is_none")]
611 pub page_limit: Option<u32>,
612
613 #[serde(default)]
615 #[serde(serialize_with = "super::csv_encode_uuids")]
616 #[serde(deserialize_with = "super::from_csv")]
617 #[serde(skip_serializing_if = "Vec::is_empty")]
618 pub resource_types: Vec<ResourceTypeId>,
619
620 #[serde(default)]
622 #[serde(skip_serializing_if = "Option::is_none")]
623 pub order_by: Option<OrderBy>,
624}
625
626#[derive(Serialize, Deserialize, Clone, Debug)]
628#[serde(rename_all = "camelCase")]
629pub struct JigBrowseResponse {
630 pub jigs: Vec<JigResponse>,
632
633 pub pages: u32,
635
636 pub total_jig_count: u64,
638}
639
640make_path_parts!(JigSearchPath => "/v1/jig");
641
642#[derive(Serialize, Deserialize, Clone, Debug, Default)]
644#[serde(rename_all = "camelCase")]
645pub struct JigSearchQuery {
646 #[serde(default)]
648 #[serde(skip_serializing_if = "String::is_empty")]
649 pub q: String,
650
651 #[serde(default)]
653 #[serde(skip_serializing_if = "Option::is_none")]
654 pub page: Option<u32>,
655
656 #[serde(default)]
658 #[serde(skip_serializing_if = "Option::is_none")]
659 pub language: Option<String>,
660
661 #[serde(default)]
665 #[serde(serialize_with = "super::csv_encode_uuids")]
666 #[serde(deserialize_with = "super::from_csv")]
667 #[serde(skip_serializing_if = "Vec::is_empty")]
668 pub age_ranges: Vec<AgeRangeId>,
669
670 #[serde(default)]
674 #[serde(serialize_with = "super::csv_encode_uuids")]
675 #[serde(deserialize_with = "super::from_csv")]
676 #[serde(skip_serializing_if = "Vec::is_empty")]
677 pub affiliations: Vec<AffiliationId>,
678
679 #[serde(default)]
681 #[serde(serialize_with = "super::csv_encode_uuids")]
682 #[serde(deserialize_with = "super::from_csv")]
683 #[serde(skip_serializing_if = "Vec::is_empty")]
684 pub resource_types: Vec<ResourceTypeId>,
685
686 #[serde(default)]
688 #[serde(serialize_with = "super::csv_encode_uuids")]
689 #[serde(deserialize_with = "super::from_csv")]
690 #[serde(skip_serializing_if = "Vec::is_empty")]
691 pub categories: Vec<CategoryId>,
692
693 #[serde(default)]
695 #[serde(skip_serializing_if = "Option::is_none")]
696 pub is_published: Option<bool>,
697
698 #[serde(default)]
700 #[serde(skip_serializing_if = "Option::is_none")]
701 pub author_id: Option<UserOrMe>,
702
703 #[serde(default)]
705 #[serde(skip_serializing_if = "Option::is_none")]
706 pub author_name: Option<String>,
707
708 #[serde(default)]
710 #[serde(skip_serializing_if = "Option::is_none")]
711 pub other_keywords: Option<String>,
712
713 #[serde(default)]
715 #[serde(skip_serializing_if = "Option::is_none")]
716 pub translated_keywords: Option<String>,
717
718 #[serde(default)]
720 #[serde(deserialize_with = "super::from_csv")]
721 #[serde(skip_serializing_if = "Vec::is_empty")]
722 pub privacy_level: Vec<PrivacyLevel>,
723
724 #[serde(default)]
726 #[serde(skip_serializing_if = "Option::is_none")]
727 pub blocked: Option<bool>,
728
729 #[serde(default)]
731 #[serde(skip_serializing_if = "Option::is_none")]
732 pub page_limit: Option<u32>,
733
734 #[serde(default)]
736 #[serde(skip_serializing_if = "Option::is_none")]
737 pub is_rated: Option<bool>,
738}
739
740#[derive(Serialize, Deserialize, Clone, Debug)]
742#[serde(rename_all = "camelCase")]
743pub struct JigSearchResponse {
744 pub jigs: Vec<JigResponse>,
746
747 pub pages: u32,
749
750 pub total_jig_count: u64,
752}
753
754make_path_parts!(JigTrendingPath => "/v1/jig/trending");
755
756#[derive(Serialize, Deserialize, Clone, Debug)]
758#[serde(rename_all = "camelCase")]
759pub struct JigTrendingResponse {
760 pub jigs: Vec<JigResponse>,
762}
763
764make_path_parts!(ListLikedPath => "/v1/jig/likes");
765
766#[derive(Serialize, Deserialize, Clone, Debug, Default)]
768#[serde(rename_all = "camelCase")]
769pub struct ListLikedRequest {
770 #[serde(default)]
772 #[serde(skip_serializing_if = "Option::is_none")]
773 pub page: Option<u32>,
774
775 #[serde(default)]
777 #[serde(skip_serializing_if = "Option::is_none")]
778 pub page_limit: Option<u32>,
779}
780
781make_path_parts!(ListPlayedPath => "/v1/jig/played");
782
783#[derive(Serialize, Deserialize, Clone, Debug, Default)]
785#[serde(rename_all = "camelCase")]
786pub struct ListPlayedRequest {
787 #[serde(default)]
789 #[serde(skip_serializing_if = "Option::is_none")]
790 pub page: Option<u32>,
791
792 #[serde(default)]
794 #[serde(skip_serializing_if = "Option::is_none")]
795 pub page_limit: Option<u32>,
796}
797
798#[derive(Serialize, Deserialize, Clone, Debug)]
800#[serde(rename_all = "camelCase")]
801pub struct ListPlayedResponse {
802 pub jigs: Vec<JigResponse>,
804}
805
806make_path_parts!(JigFeaturedPath => "/v1/jig/featured");
807
808#[derive(Serialize, Deserialize, Clone, Debug)]
810#[serde(rename_all = "camelCase")]
811pub struct JigFeaturedResponse {
812 pub jigs: Vec<JigResponse>,
814}
815
816#[derive(Serialize, Deserialize, Clone, Debug)]
818#[serde(rename_all = "camelCase")]
819pub struct JigFeaturedUpdateRequest {
820 pub jigs: Vec<JigId>,
822}
823
824#[derive(Serialize, Deserialize, Clone, Debug)]
826#[serde(rename_all = "camelCase")]
827pub struct ListLikedResponse {
828 pub jigs: Vec<JigResponse>,
830
831 pub total_jig_count: u64,
833}
834
835#[derive(Serialize, Deserialize, Clone, Debug)]
837#[serde(rename_all = "camelCase")]
838pub struct JigIdResponse {
839 pub id: JigId,
841}
842
843make_path_parts!(JigClonePath => "/v1/jig/{}/clone" => JigId);
844
845make_path_parts!(JigDeletePath => "/v1/jig/{}" => JigId);
846
847make_path_parts!(JigDeleteAllPath => "/v1/jig");
848
849make_path_parts!(JigCoverPath => "/v1/jig/{}/cover" => JigId);
850
851make_path_parts!(JigCountPath => "/v1/jig/count");
852
853#[derive(Serialize, Deserialize, Clone, Debug)]
855#[serde(rename_all = "camelCase")]
856pub struct JigCountResponse {
857 pub total_count: u64,
859}
860
861make_path_parts!(JigLikePath => "/v1/jig/{}/like" => JigId);
862
863make_path_parts!(JigUnlikePath => "/v1/jig/{}/unlike" => JigId);
864
865make_path_parts!(JigLikedPath => "/v1/jig/{}/like" => JigId);
866
867#[derive(Serialize, Deserialize, Clone, Debug)]
869pub struct JigLikedResponse {
870 pub is_liked: bool,
872}
873
874make_path_parts!(JigPlayPath => "/v1/jig/{}/play" => JigId);
875
876make_path_parts!(JigAdminDataUpdatePath => "/v1/jig/{}/admin" => JigId);
877
878#[derive(Serialize, Deserialize, Clone, Debug)]
880#[serde(rename_all = "camelCase")]
881pub struct GetJigPlaylistsResponse {
882 pub playlists: Vec<PlaylistResponse>,
884}
885
886macros::make_path_parts!(GetJigPlaylistsPath => "/v1/jig/{}/playlists" => JigId);
887
888#[derive(Debug, Serialize, Deserialize, Clone)]
890pub struct AdminJigExport {
891 pub id: JigId,
893 pub description: String,
895 pub display_name: String,
897 pub premium: bool,
899 pub blocked: bool,
901 pub author_id: Option<UserId>,
903 pub author_name: Option<String>,
905 pub likes: i64,
907 pub plays: i64,
909 pub rating: Option<JigRating>,
911 pub privacy_level: PrivacyLevel,
913 pub created_at: DateTime<Utc>,
915 pub published_at: Option<DateTime<Utc>>,
917 pub language: String,
919}