forked from
rocksky.app/rocksky
A decentralized music tracking and discovery platform built on AT Protocol 馃幍
1use serde::{Deserialize, Serialize};
2
3use crate::{musicbrainz, spotify, xata};
4
5#[derive(Debug, Deserialize, Clone)]
6pub struct Scrobble {
7 pub artist: String,
8 pub track: String,
9 pub timestamp: u64,
10 pub album: Option<String>,
11 pub context: Option<String>,
12 pub stream_id: Option<String>,
13 pub chosen_by_user: Option<u8>,
14 pub track_number: Option<u32>,
15 pub mbid: Option<String>,
16 pub album_artist: Option<String>,
17 pub duration: Option<u32>,
18 pub ignored: Option<bool>,
19}
20
21#[derive(Debug, Serialize, Deserialize, Default)]
22#[serde(rename_all = "camelCase")]
23pub struct Track {
24 pub title: String,
25 pub album: String,
26 pub artist: String,
27 pub album_artist: Option<String>,
28 pub duration: u32,
29 pub mbid: Option<String>,
30 pub track_number: u32,
31 pub release_date: Option<String>,
32 pub year: Option<u32>,
33 pub disc_number: u32,
34 pub album_art: Option<String>,
35 pub spotify_link: Option<String>,
36 pub label: Option<String>,
37 pub artist_picture: Option<String>,
38 pub timestamp: Option<u64>,
39}
40
41impl From<xata::track::Track> for Track {
42 fn from(track: xata::track::Track) -> Self {
43 Track {
44 title: track.title,
45 album: track.album,
46 artist: track.artist,
47 album_artist: Some(track.album_artist),
48 album_art: track.album_art,
49 spotify_link: track.spotify_link,
50 label: track.label,
51 artist_picture: None,
52 timestamp: None,
53 duration: track.duration as u32,
54 mbid: track.mb_id,
55 track_number: track.track_number as u32,
56 disc_number: track.disc_number as u32,
57 year: None,
58 release_date: None,
59 }
60 }
61}
62
63impl From<musicbrainz::recording::Recording> for Track {
64 fn from(recording: musicbrainz::recording::Recording) -> Self {
65 let artist_credit = recording
66 .artist_credit
67 .unwrap_or_default()
68 .first()
69 .map(|credit| credit.name.clone())
70 .unwrap_or_default();
71 let releases = recording.releases.unwrap_or_default();
72 let album_artist = releases
73 .first()
74 .and_then(|release| release.artist_credit.first())
75 .map(|credit| credit.name.clone());
76 let album = releases
77 .first()
78 .map(|release| release.title.clone())
79 .unwrap_or_default();
80 Track {
81 title: recording.title.clone(),
82 album,
83 artist: artist_credit,
84 album_artist,
85 duration: recording.length.unwrap_or_default(),
86 year: recording
87 .first_release_date
88 .as_ref()
89 .and_then(|date| date.split('-').next())
90 .and_then(|year| year.parse::<u32>().ok()),
91 release_date: recording.first_release_date.clone(),
92 track_number: releases
93 .first()
94 .and_then(|release| {
95 release
96 .media
97 .as_ref()
98 .and_then(|media| media.first())
99 .and_then(|media| {
100 media
101 .tracks
102 .as_ref()
103 .and_then(|tracks| tracks.first())
104 .map(|track| track.number.parse::<u32>().unwrap())
105 })
106 })
107 .unwrap_or_default(),
108 disc_number: releases
109 .first()
110 .and_then(|release| {
111 release
112 .media
113 .as_ref()
114 .and_then(|media| media.first())
115 .map(|media| media.position)
116 })
117 .unwrap_or_default(),
118 ..Default::default()
119 }
120 }
121}
122
123impl From<&spotify::types::Track> for Track {
124 fn from(track: &spotify::types::Track) -> Self {
125 Track {
126 title: track.name.clone(),
127 album: track.album.name.clone(),
128 artist: track
129 .artists
130 .iter()
131 .map(|artist| artist.name.clone())
132 .collect::<Vec<_>>()
133 .join(", "),
134 album_artist: track
135 .album
136 .artists
137 .first()
138 .map(|artist| artist.name.clone()),
139 duration: track.duration_ms as u32,
140 album_art: track.album.images.first().map(|image| image.url.clone()),
141 spotify_link: Some(track.external_urls.spotify.clone()),
142 artist_picture: track.album.artists.first().and_then(|artist| {
143 artist
144 .images
145 .as_ref()
146 .and_then(|images| images.first().map(|image| image.url.clone()))
147 }),
148 track_number: track.track_number,
149 disc_number: track.disc_number,
150 release_date: match track.album.release_date_precision.as_str() {
151 "day" => Some(track.album.release_date.clone()),
152 _ => None,
153 },
154 year: match track.album.release_date_precision.as_str() {
155 "day" => Some(
156 track
157 .album
158 .release_date
159 .split('-')
160 .next()
161 .unwrap()
162 .parse::<u32>()
163 .unwrap(),
164 ),
165 "year" => Some(track.album.release_date.parse::<u32>().unwrap()),
166 _ => None,
167 },
168 label: track.album.label.clone(),
169 ..Default::default()
170 }
171 }
172}
173
174impl From<spotify::types::Track> for Track {
175 fn from(track: spotify::types::Track) -> Self {
176 Track::from(&track)
177 }
178}