1use music_player_types::types::{RemoteTrackUrl, Song, Track as TrackType};
2use sea_orm::{entity::prelude::*, ActiveValue};
3use serde::{Deserialize, Serialize};
4use upnp_client::types::Metadata;
5
6use crate::{album, artist, select_result};
7
8#[derive(Clone, Debug, Default, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
9#[sea_orm(table_name = "track")]
10pub struct Model {
11 #[sea_orm(primary_key, auto_increment = false)]
12 pub id: String,
13 pub title: String,
14 pub artist: String,
15 pub genre: String,
16 pub year: Option<u32>,
17 pub track: Option<u32>,
18 pub bitrate: Option<u32>,
19 pub sample_rate: Option<u32>,
20 pub bit_depth: Option<u8>,
21 pub channels: Option<u8>,
22 pub duration: Option<f32>,
23 pub uri: String,
24 pub album_id: Option<String>,
25 pub artist_id: Option<String>,
26 #[sea_orm(ignore)]
27 pub artists: Vec<artist::Model>,
28 #[sea_orm(ignore)]
29 pub album: album::Model,
30}
31
32#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
33pub enum Relation {
34 #[sea_orm(
35 belongs_to = "super::album::Entity",
36 from = "Column::AlbumId",
37 to = "super::album::Column::Id"
38 )]
39 Album,
40 #[sea_orm(
41 belongs_to = "super::artist::Entity",
42 from = "Column::ArtistId",
43 to = "super::artist::Column::Id"
44 )]
45 Artist,
46}
47
48impl Related<super::album::Entity> for Entity {
49 fn to() -> RelationDef {
50 Relation::Album.def()
51 }
52}
53
54impl Related<super::playlist::Entity> for Entity {
55 fn to() -> RelationDef {
56 super::playlist_tracks::Relation::Playlist.def()
57 }
58
59 fn via() -> Option<RelationDef> {
60 Some(super::playlist_tracks::Relation::Track.def().rev())
61 }
62}
63
64impl Related<super::artist::Entity> for Entity {
65 fn to() -> RelationDef {
66 super::artist_tracks::Relation::Artist.def()
67 }
68
69 fn via() -> Option<RelationDef> {
70 Some(super::artist_tracks::Relation::Track.def().rev())
71 }
72}
73
74impl ActiveModelBehavior for ActiveModel {}
75
76#[derive(Debug)]
77pub struct TrackToAlbum;
78
79impl Linked for TrackToAlbum {
80 type FromEntity = super::track::Entity;
81 type ToEntity = super::album::Entity;
82
83 fn link(&self) -> Vec<RelationDef> {
84 vec![
85 super::album::Relation::Track.def().rev(),
86 super::track::Relation::Album.def(),
87 ]
88 }
89}
90
91#[derive(Debug)]
92pub struct TrackToArtist;
93
94impl Linked for TrackToArtist {
95 type FromEntity = super::track::Entity;
96 type ToEntity = super::artist::Entity;
97
98 fn link(&self) -> Vec<RelationDef> {
99 vec![
100 super::artist_tracks::Relation::Track.def().rev(),
101 super::artist_tracks::Relation::Artist.def(),
102 ]
103 }
104}
105
106#[derive(Debug)]
107pub struct TrackToPlaylist;
108
109impl Linked for TrackToPlaylist {
110 type FromEntity = super::track::Entity;
111 type ToEntity = super::playlist::Entity;
112
113 fn link(&self) -> Vec<RelationDef> {
114 vec![
115 super::playlist_tracks::Relation::Track.def().rev(),
116 super::playlist_tracks::Relation::Playlist.def(),
117 ]
118 }
119}
120
121impl From<&Song> for ActiveModel {
122 fn from(song: &Song) -> Self {
123 let id = format!("{:x}", md5::compute(song.uri.as_ref().unwrap()));
124 Self {
125 id: ActiveValue::set(id),
126 artist: ActiveValue::Set(song.artist.clone()),
127 title: ActiveValue::Set(song.title.clone()),
128 genre: ActiveValue::Set(song.genre.clone()),
129 year: ActiveValue::Set(song.year),
130 track: ActiveValue::Set(song.track),
131 bitrate: ActiveValue::Set(song.bitrate),
132 sample_rate: ActiveValue::Set(song.sample_rate),
133 bit_depth: ActiveValue::Set(song.bit_depth),
134 channels: ActiveValue::Set(song.channels),
135 duration: ActiveValue::Set(Some(song.duration.as_secs_f32())),
136 uri: ActiveValue::Set(song.uri.clone().unwrap_or_default()),
137 album_id: ActiveValue::Set(Some(format!(
138 "{:x}",
139 md5::compute(format!("{}", song.album))
140 ))),
141 artist_id: ActiveValue::Set(Some(format!(
142 "{:x}",
143 md5::compute(song.album_artist.to_owned())
144 ))),
145 }
146 }
147}
148
149impl From<select_result::PlaylistTrack> for Model {
150 fn from(playlist_track: select_result::PlaylistTrack) -> Self {
151 Self {
152 id: playlist_track.track_id,
153 title: playlist_track.track_title,
154 artist: playlist_track.track_artist,
155 uri: playlist_track.track_uri,
156 album_id: Some(playlist_track.album_id.clone()),
157 artist_id: Some(playlist_track.artist_id.clone()),
158 duration: Some(playlist_track.track_duration),
159 album: album::Model {
160 id: playlist_track.album_id,
161 title: playlist_track.album_title,
162 cover: playlist_track.album_cover,
163 ..Default::default()
164 },
165 artists: vec![artist::Model {
166 id: playlist_track.artist_id,
167 name: playlist_track.artist_name,
168 ..Default::default()
169 }],
170 ..Default::default()
171 }
172 }
173}
174
175impl From<TrackType> for Model {
176 fn from(track: TrackType) -> Self {
177 let track_album = track.album.unwrap();
178 Self {
179 id: track.id,
180 title: track.title,
181 artist: track.artist,
182 uri: track.uri,
183 album_id: Some(track_album.id.clone()),
184 artist_id: if track.artists.is_empty() {
185 None
186 } else {
187 Some(track.artists[0].id.clone())
188 },
189 duration: track.duration,
190 album: album::Model {
191 id: track_album.id,
192 title: track_album.title,
193 cover: track_album.cover,
194 year: track_album.year,
195 ..Default::default()
196 },
197 artists: track.artists.into_iter().map(Into::into).collect(),
198 ..Default::default()
199 }
200 }
201}
202
203impl Into<TrackType> for Model {
204 fn into(self) -> TrackType {
205 TrackType {
206 id: self.id,
207 title: self.title,
208 artist: self.artist,
209 uri: self.uri,
210 duration: self.duration,
211 album: Some(self.album.into()),
212 artists: self.artists.into_iter().map(Into::into).collect(),
213 ..Default::default()
214 }
215 }
216}
217
218impl Into<Metadata> for Model {
219 fn into(self) -> Metadata {
220 Metadata {
221 title: self.title,
222 artist: Some(self.artist),
223 album: Some(self.album.title),
224 album_art_uri: self.album.cover,
225 ..Default::default()
226 }
227 }
228}
229
230impl RemoteTrackUrl for Model {
231 fn with_remote_track_url(&self, base_url: &str) -> Self {
232 Self {
233 uri: format!("{}/tracks/{}", base_url, self.id),
234 ..self.clone()
235 }
236 }
237}