Skip to main content

ncmapi2/types/
mod.rs

1// This module was generated at https://transform.tools/json-to-rust-serde
2// However, some fields of struct was stripped for concision.
3pub type SearchSongResp = ResultResp<SearchResultSong>;
4pub type SearchArtistResp = ResultResp<SearchResultArtist>;
5pub type SearchPodcastResp = ResultResp<SearchResultPodcast>;
6pub type SearchPlaylistResp = ResultResp<SearchResultPlaylist>;
7pub type SearchAlbumResp = ResultResp<SearchResultAlbum>;
8
9#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub struct ResultResp<T> {
12    pub code: usize,
13    pub result: Option<T>,
14}
15
16#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
17#[serde(rename_all = "camelCase", default)]
18pub struct SearchResultSong {
19    pub songs: Vec<Song>,
20    pub has_more: bool,
21}
22
23#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
24#[serde(rename_all = "camelCase")]
25pub struct Song {
26    pub id: usize,
27    pub name: String,
28    #[serde(alias = "ar")]
29    pub artists: Vec<Artist>,
30    #[serde(alias = "al")]
31    pub album: Album,
32    #[serde(alias = "dt")]
33    pub duration: usize,
34    pub fee: usize,
35    #[serde(alias = "popularity")]
36    pub pop: f32,
37    // pub resource_state: bool,
38    // pub publish_time: i64,
39}
40
41#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
42#[serde(rename_all = "camelCase")]
43pub struct Artist {
44    pub id: usize,
45    pub name: Option<String>,
46}
47
48#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
49#[serde(rename_all = "camelCase")]
50pub struct Album {
51    pub id: usize,
52    pub name: Option<String>,
53    #[serde(default)]
54    pub pic_url: String,
55    pub pic: usize,
56}
57
58#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
59#[serde(rename_all = "camelCase")]
60pub struct PodcastAudio {
61    pub main_song: Song,
62    pub dj: UserProfile,
63    pub liked_count: usize,
64    pub comment_count: usize,
65}
66
67/// User created podcasts
68#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
69#[serde(rename_all = "camelCase")]
70pub struct UserPodcastsResp {
71    pub code: usize,
72    #[serde(default)]
73    pub dj_radios: Vec<Podcast>,
74    #[serde(default)]
75    pub has_more: bool,
76}
77
78#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
79#[serde(rename_all = "camelCase")]
80pub struct PodcastAudiosResp {
81    pub code: usize,
82    #[serde(default)]
83    pub programs: Vec<PodcastAudio>,
84    #[serde(default)]
85    pub more: bool,
86}
87
88#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
89#[serde(rename_all = "camelCase")]
90pub struct UserProfile {
91    pub user_id: usize,
92    pub nickname: String,
93}
94
95#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
96#[serde(rename_all = "camelCase")]
97pub struct UserAccountResp {
98    pub code: usize,
99    pub profile: Option<UserProfile>,
100}
101
102#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
103pub struct UserPlaylistResp {
104    pub code: usize,
105    #[serde(default)]
106    pub playlist: Vec<Playlist>,
107}
108
109#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
110pub struct PlaylistDetailResp {
111    pub code: usize,
112    pub playlist: Option<PlaylistDetail>,
113}
114
115#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
116#[serde(rename_all = "camelCase")]
117pub struct Playlist {
118    pub id: usize,
119    pub name: String,
120    pub description: Option<String>,
121}
122
123#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
124#[serde(rename_all = "camelCase")]
125pub struct PlaylistDetail {
126    pub id: usize,
127    pub name: String,
128    pub description: Option<String>,
129    #[serde(default)]
130    pub tracks: Vec<Song>,
131    #[serde(default)]
132    pub track_ids: Vec<Id>,
133    pub user_id: usize,
134}
135
136#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
137pub struct Id {
138    pub id: usize,
139}
140
141#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
142pub struct SongUrlResp {
143    pub code: usize,
144    #[serde(default)]
145    pub data: Vec<SongUrl>,
146}
147
148#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
149pub struct SongUrl {
150    pub id: usize,
151    pub url: String,
152    pub br: usize,
153}
154
155#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
156#[serde(rename_all = "camelCase")]
157pub struct UserCloudResp {
158    pub code: usize,
159    #[serde(default)]
160    pub has_more: bool,
161    #[serde(default)]
162    pub data: Vec<CloudSongMeta>,
163}
164
165#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
166#[serde(rename_all = "camelCase")]
167pub struct CloudSongMeta {
168    pub simple_song: Song,
169    pub song_id: usize,
170    pub song_name: String,
171    pub add_time: i128,
172    pub file_size: usize,
173    pub bitrate: usize,
174    pub file_name: String,
175}
176
177#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
178#[serde(rename_all = "camelCase")]
179pub struct RecommendedSongs {
180    #[serde(default)]
181    pub daily_songs: Vec<Song>,
182    #[serde(default)]
183    pub order_songs: Vec<Song>,
184}
185
186#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
187pub struct RecommendedSongsResp {
188    pub code: usize,
189    pub data: RecommendedSongs,
190}
191
192#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
193#[serde(rename_all = "camelCase")]
194pub struct Comment {
195    pub user: UserProfile,
196    #[serde(default)]
197    pub content: String,
198    pub time: u64,
199    pub liked_count: usize,
200    pub liked: bool,
201}
202
203#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
204#[serde(rename_all = "camelCase")]
205pub struct ResourceComments {
206    #[serde(default)]
207    pub comments: Vec<Comment>,
208    pub total_count: usize,
209    pub has_more: bool,
210}
211
212#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
213#[serde(rename_all = "camelCase")]
214pub struct ResourceCommentsResp {
215    pub code: usize,
216    pub data: ResourceComments,
217}
218
219#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
220#[serde(rename_all = "camelCase")]
221pub struct HotCommentsResp {
222    pub code: usize,
223    #[serde(default)]
224    pub hot_comments: Vec<Comment>,
225    pub has_more: bool,
226    pub total: usize,
227}
228
229#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
230#[serde(rename_all = "camelCase")]
231pub struct LyricResp {
232    pub code: usize,
233    pub sgc: bool,
234    pub sfy: bool,
235    pub qfy: bool,
236    pub lrc: Option<Lyric>,
237    pub klyric: Option<Lyric>,
238    pub tlyric: Option<Lyric>,
239}
240
241#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
242#[serde(rename_all = "camelCase")]
243pub struct Lyric {
244    #[serde(default)]
245    pub version: usize,
246    #[serde(default)]
247    pub lyric: String,
248}
249
250#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
251#[serde(rename_all = "camelCase")]
252pub struct PersonalFmResp {
253    pub code: usize,
254    #[serde(default)]
255    pub data: Vec<Song>,
256}
257
258#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
259#[serde(rename_all = "camelCase")]
260pub struct RecommendedPlaylistsResp {
261    pub code: usize,
262    #[serde(default)]
263    pub recommend: Vec<Playlist>,
264}
265
266#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
267#[serde(rename_all = "camelCase")]
268pub struct SimiSongsResp {
269    pub code: usize,
270    #[serde(default)]
271    pub songs: Vec<Song>,
272}
273
274#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
275#[serde(rename_all = "camelCase")]
276pub struct ArtistSongsResp {
277    pub code: usize,
278    #[serde(default)]
279    pub songs: Vec<Song>,
280    #[serde(default)]
281    pub more: bool,
282    #[serde(default)]
283    pub total: usize,
284}
285
286#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
287#[serde(rename_all = "camelCase")]
288pub struct ArtistSublistResp {
289    pub code: usize,
290    #[serde(default)]
291    pub data: Vec<Artist>,
292    #[serde(default)]
293    pub has_more: bool,
294}
295
296#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
297#[serde(rename_all = "camelCase")]
298pub struct Podcast {
299    pub id: usize,
300    pub name: String,
301    pub desc: String,
302    pub sub_count: usize,
303    pub category: String,
304    pub dj: UserProfile,
305}
306
307#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
308#[serde(rename_all = "camelCase")]
309pub struct SearchResultArtist {
310    #[serde(default)]
311    pub artists: Vec<Artist>,
312}
313
314#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
315#[serde(rename_all = "camelCase")]
316pub struct SearchResultPodcast {
317    #[serde(default)]
318    pub dj_radios: Vec<Podcast>,
319}
320
321#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
322#[serde(rename_all = "camelCase")]
323pub struct SearchResultPlaylist {
324    #[serde(default)]
325    pub playlists: Vec<Playlist>,
326}
327
328#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
329#[serde(rename_all = "camelCase")]
330pub struct SearchResultAlbum {
331    #[serde(default)]
332    pub albums: Vec<Album>,
333}
334
335#[cfg(test)]
336mod tests {
337
338    use serde_json::json;
339
340    use crate::{
341        types::{
342            ArtistSongsResp, ArtistSublistResp, HotCommentsResp, LyricResp, PersonalFmResp,
343            PlaylistDetailResp, PodcastAudiosResp, RecommendedPlaylistsResp, RecommendedSongsResp,
344            ResourceCommentsResp, SearchAlbumResp, SearchArtistResp, SearchPlaylistResp,
345            SearchPodcastResp, SearchSongResp, SimiSongsResp, SongUrlResp, UserAccountResp,
346            UserCloudResp, UserPlaylistResp, UserPodcastsResp,
347        },
348        NcmApi, SearchType,
349    };
350
351    // let res = resp.unwrap();
352    // let mut f = std::fs::OpenOptions::new()
353    //     .create(true)
354    //     .write(true)
355    //     .open("test-data/search_podcast.json")
356    //     .unwrap();
357    // f.write_all(res.data()).unwrap();
358
359    #[tokio::test]
360    async fn test_de_search_song() {
361        let api = NcmApi::default();
362        let resp = api.search("xusong", None).await;
363        assert!(resp.is_ok());
364
365        let res = serde_json::from_slice::<SearchSongResp>(resp.unwrap().data()).unwrap();
366        assert_eq!(res.code, 200);
367    }
368
369    #[tokio::test]
370    async fn test_de_search_artist() {
371        let api = NcmApi::default();
372        let resp = api
373            .search("xusong", Some(json!({ "type": SearchType::Artist })))
374            .await;
375        assert!(resp.is_ok());
376
377        let res = serde_json::from_slice::<SearchArtistResp>(resp.unwrap().data()).unwrap();
378        assert_eq!(res.code, 200);
379    }
380
381    #[tokio::test]
382    async fn test_de_search_playlist() {
383        let api = NcmApi::default();
384        let resp = api
385            .search("ost", Some(json!({ "type": SearchType::Collection })))
386            .await;
387        assert!(resp.is_ok());
388
389        let res = serde_json::from_slice::<SearchPlaylistResp>(resp.unwrap().data()).unwrap();
390        assert_eq!(res.code, 200);
391    }
392
393    #[tokio::test]
394    async fn test_de_search_podcast() {
395        let api = NcmApi::default();
396        let resp = api
397            .search("asmr", Some(json!({ "type": SearchType::Podcast })))
398            .await;
399        assert!(resp.is_ok());
400
401        let res = serde_json::from_slice::<SearchPodcastResp>(resp.unwrap().data()).unwrap();
402        assert_eq!(res.code, 200);
403    }
404
405    #[tokio::test]
406    async fn test_de_search_album() {
407        let api = NcmApi::default();
408        let resp = api
409            .search("Mota", Some(json!({ "type": SearchType::Album })))
410            .await;
411        assert!(resp.is_ok());
412
413        let res = serde_json::from_slice::<SearchAlbumResp>(resp.unwrap().data()).unwrap();
414        assert_eq!(res.code, 200);
415    }
416
417    #[tokio::test]
418    async fn test_de_user_account() {
419        let api = NcmApi::default();
420        let resp = api.user_account().await;
421        assert!(resp.is_ok());
422
423        let res = serde_json::from_slice::<UserAccountResp>(resp.unwrap().data()).unwrap();
424        assert_eq!(res.code, 200);
425    }
426
427    #[tokio::test]
428    async fn test_de_user_playlist() {
429        let api = NcmApi::default();
430        let uid = 49668844;
431        let resp = api.user_playlist(uid, None).await;
432        assert!(resp.is_ok());
433
434        let res = serde_json::from_slice::<UserPlaylistResp>(resp.unwrap().data()).unwrap();
435        assert_eq!(res.code, 200);
436    }
437
438    #[tokio::test]
439    async fn test_de_playlist_detail() {
440        let api = NcmApi::default();
441        const COLLECTION_ID: usize = 2484967117;
442        let resp = api.playlist_detail(COLLECTION_ID, None).await;
443        assert!(resp.is_ok());
444
445        let res = serde_json::from_slice::<PlaylistDetailResp>(resp.unwrap().data()).unwrap();
446        assert_eq!(res.code, 200);
447    }
448
449    #[tokio::test]
450    async fn test_de_song_url() {
451        let api = NcmApi::default();
452        let resp = api.song_url(&vec![28497094, 28497093]).await;
453        assert!(resp.is_ok());
454
455        let res = serde_json::from_slice::<SongUrlResp>(resp.unwrap().data()).unwrap();
456        assert_eq!(res.code, 200);
457    }
458
459    #[tokio::test]
460    async fn test_de_user_cloud() {
461        let api = NcmApi::default();
462        let resp = api.user_cloud(None).await;
463        assert!(resp.is_ok());
464
465        let res = serde_json::from_slice::<UserCloudResp>(resp.unwrap().data()).unwrap();
466        assert_eq!(res.code, 200);
467    }
468
469    #[tokio::test]
470    async fn test_de_recommended_songs() {
471        let api = NcmApi::default();
472        let resp = api.recommend_songs().await;
473        assert!(resp.is_ok());
474
475        let res = serde_json::from_slice::<RecommendedSongsResp>(resp.unwrap().data()).unwrap();
476        assert_eq!(res.code, 200);
477    }
478
479    #[tokio::test]
480    async fn test_de_comments() {
481        let api = NcmApi::default();
482        let resp = api
483            .comment(32977061, crate::api::ResourceType::Song, 10, 1, 1, 0, false)
484            .await;
485        assert!(resp.is_ok());
486
487        let res = serde_json::from_slice::<ResourceCommentsResp>(resp.unwrap().data()).unwrap();
488        assert_eq!(res.code, 200);
489    }
490
491    #[tokio::test]
492    async fn test_de_hot_comments() {
493        let api = NcmApi::default();
494        let resp = api
495            .comment_hot(32977061, crate::ResourceType::Song, None)
496            .await;
497        assert!(resp.is_ok());
498
499        let res = serde_json::from_slice::<HotCommentsResp>(resp.unwrap().data()).unwrap();
500        assert_eq!(res.code, 200);
501    }
502
503    #[tokio::test]
504    async fn test_de_lyric() {
505        let api = NcmApi::default();
506        let resp = api.lyric(17346999).await;
507        assert!(resp.is_ok());
508
509        let res = serde_json::from_slice::<LyricResp>(resp.unwrap().data()).unwrap();
510        assert_eq!(res.code, 200);
511    }
512
513    #[tokio::test]
514    async fn test_de_personal_fm() {
515        let api = NcmApi::default();
516        let resp = api.personal_fm().await;
517        assert!(resp.is_ok());
518
519        let res = serde_json::from_slice::<PersonalFmResp>(resp.unwrap().data()).unwrap();
520        assert_eq!(res.code, 200);
521    }
522
523    #[tokio::test]
524    async fn test_de_recommended_playlists() {
525        let api = NcmApi::default();
526        let resp = api.recommend_resource().await;
527        assert!(resp.is_ok());
528
529        let res = serde_json::from_slice::<RecommendedPlaylistsResp>(resp.unwrap().data()).unwrap();
530        assert_eq!(res.code, 200);
531    }
532
533    #[tokio::test]
534    async fn test_de_simi_songs() {
535        let api = NcmApi::default();
536        let resp = api.simi_song(347230, None).await;
537        assert!(resp.is_ok());
538
539        let res = serde_json::from_slice::<SimiSongsResp>(resp.unwrap().data()).unwrap();
540        assert_eq!(res.code, 200);
541    }
542
543    #[tokio::test]
544    async fn test_de_artist_songs() {
545        let api = NcmApi::default();
546        let resp = api.artist_songs(6452, None).await;
547        assert!(resp.is_ok());
548
549        let res = serde_json::from_slice::<ArtistSongsResp>(resp.unwrap().data()).unwrap();
550        assert_eq!(res.code, 200);
551    }
552
553    #[tokio::test]
554    async fn test_de_artist_sublist() {
555        let api = NcmApi::default();
556        let resp = api.artist_sublist(None).await;
557        assert!(resp.is_ok());
558
559        let res = serde_json::from_slice::<ArtistSublistResp>(resp.unwrap().data()).unwrap();
560        assert_eq!(res.code, 200);
561    }
562
563    #[tokio::test]
564    async fn test_de_user_podcast() {
565        let api = NcmApi::default();
566        let resp = api.user_podcast(1398995370).await;
567        assert!(resp.is_ok());
568
569        let res = serde_json::from_slice::<UserPodcastsResp>(resp.unwrap().data()).unwrap();
570        assert_eq!(res.code, 200);
571    }
572
573    #[tokio::test]
574    async fn test_de_podcast_audio() {
575        let api = NcmApi::default();
576        let resp = api.podcast_audio(965114264, None).await;
577        assert!(resp.is_ok());
578
579        let res = serde_json::from_slice::<PodcastAudiosResp>(resp.unwrap().data()).unwrap();
580        assert_eq!(res.code, 200);
581    }
582}