rustfm_scraper/models/
recent_tracks.rs

1use chrono::prelude::*;
2use serde::Deserialize;
3
4#[derive(Debug, Deserialize)]
5pub struct RecentTracksResponse {
6    #[serde(rename = "recenttracks")]
7    pub recent_tracks: RecentTracks,
8}
9
10#[derive(Debug, Deserialize)]
11pub struct RecentTracks {
12    #[serde(rename = "@attr")]
13    pub attr: Attr,
14    #[serde(rename = "track")]
15    pub tracks: Vec<Track>,
16}
17
18#[derive(Debug, Deserialize)]
19pub struct Attr {
20    page: String,
21    #[serde(rename = "perPage")]
22    per_page: String,
23    user: String,
24    total: String,
25    #[serde(rename = "totalPages")]
26    total_pages: String,
27}
28
29impl Attr {
30    pub fn page(&self) -> i32 {
31        self.page.parse().unwrap_or(0)
32    }
33
34    pub fn per_page(&self) -> i32 {
35        self.per_page.parse().unwrap_or(0)
36    }
37
38    pub fn total_tracks(&self) -> i32 {
39        self.total.parse().unwrap_or(0)
40    }
41
42    pub fn total_pages(&self) -> i32 {
43        self.total_pages.parse().unwrap_or(0)
44    }
45
46    pub fn last_page(&self) -> bool {
47        self.page() == self.total_pages()
48    }
49
50    pub fn single_page(&self) -> bool {
51        self.total_pages() == 1
52    }
53
54    pub fn single_track(&self) -> bool {
55        self.total_tracks() == 1
56    }
57}
58
59#[derive(Clone, Debug, Deserialize)]
60pub struct Track {
61    #[serde(rename = "@attr")]
62    pub attr: Option<TrackAttr>,
63    pub artist: Artist,
64    pub album: Album,
65    // Skip `image`
66    pub streamable: String,
67    pub date: Option<Date>,
68    pub name: String,
69    pub mbid: String,
70    loved: String,
71}
72
73impl PartialEq for Track {
74    fn eq(&self, other: &Self) -> bool {
75        self.combined_title().eq(&other.combined_title())
76    }
77}
78
79impl Track {
80    pub fn combined_title(&self) -> String {
81        format!("{} - {} - {}", self.name, self.artist.name, self.album.text)
82    }
83
84    pub fn loved(&self) -> bool {
85        self.loved == "1"
86    }
87
88    pub fn now_playing(&self) -> bool {
89        match &self.attr {
90            Some(attr) => attr.now_playing == "true",
91            None => false,
92        }
93    }
94
95    pub fn date(&self) -> Date {
96        self.date.clone().unwrap()
97    }
98}
99
100#[derive(Clone, Debug, Deserialize)]
101pub struct TrackAttr {
102    #[serde(rename = "nowplaying")]
103    now_playing: String,
104}
105
106#[derive(Clone, Debug, Deserialize)]
107pub struct Artist {
108    pub url: String,
109    pub mbid: String,
110    pub name: String,
111}
112
113#[derive(Clone, Debug, Deserialize)]
114pub struct Album {
115    pub mbid: String,
116    #[serde(rename = "#text")]
117    pub text: String,
118}
119
120#[derive(Clone, Debug, Deserialize)]
121pub struct Date {
122    uts: String,
123    #[serde(rename = "#text")]
124    text: String,
125}
126
127impl Date {
128    pub fn time_stamp(&self) -> i64 {
129        let timestamp: i64 = self.uts.parse().unwrap();
130        let dt = NaiveDateTime::from_timestamp(timestamp, 0);
131
132        dt.timestamp()
133    }
134
135    pub fn datetime_utc(&self) -> DateTime<Utc> {
136        DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(self.time_stamp(), 0), Utc)
137    }
138
139    pub fn datetime_local(&self) -> DateTime<Local> {
140        let dt = self.datetime_utc().naive_utc();
141
142        Local::from_utc_datetime(&Local, &dt)
143    }
144}