A decentralized music tracking and discovery platform built on AT Protocol 馃幍
at setup-tracing 178 lines 6.0 kB view raw
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}