selene_core/library/
album.rs1use std::ops::Deref;
2
3use blake3::{Hash, hash};
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6
7use crate::{
8 database::{DatabaseEntry, DatabaseError, EntryId, Patchable, patch_option_replace},
9 library::{
10 artist::ArtistGroup,
11 cover_art::CoverArt,
12 track::{Track, TrackId},
13 },
14};
15
16pub mod frontend_impls;
17pub mod trait_impls;
18
19pub const UNKNOWN_ALBUM: &str = "UNKNOWN ALBUM";
20
21#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Hash)]
22pub struct AlbumId {
23 id: Hash,
24}
25
26impl EntryId for AlbumId {
27 type Entry = Album;
28}
29
30impl Deref for AlbumId {
31 type Target = Hash;
32
33 fn deref(&self) -> &Self::Target {
34 &self.id
35 }
36}
37
38impl AlbumId {
39 fn new(name: &str) -> Self {
40 Self {
41 id: hash(name.as_bytes()),
42 }
43 }
44}
45
46#[derive(Debug, Clone, Deserialize, Serialize)]
47pub struct Album {
48 id: AlbumId,
49
50 pub name: String,
51 pub cover_art: Option<CoverArt>,
52
53 pub(crate) tracks: Vec<TrackReference>,
55
56 pub(crate) artist_group: ArtistGroup,
57 pub disc_total: Option<u16>,
58 pub genre: Option<String>,
59 pub track_total: Option<u16>,
60 pub date: Option<DateTime<Utc>>,
61
62 version: usize,
63}
64
65impl Album {
67 pub(crate) fn new(name: String, artists: ArtistGroup, tracks: Vec<TrackReference>) -> Self {
68 let hash = AlbumId::new(&name);
69
70 Self {
71 artist_group: artists,
72 cover_art: None,
73 disc_total: None,
74 genre: None,
75 id: hash,
76 name,
77 track_total: None,
78 version: 1,
79 date: None,
80 tracks,
81 }
82 }
83
84 pub fn tracks(&self) -> Result<Vec<Track>, DatabaseError> {
85 Track::db_get_batch(self.track_refs().iter().map(|t| t.id))
86 }
87}
88
89impl Album {
91 #[must_use]
92 pub fn id(&self) -> AlbumId {
93 self.id
94 }
95
96 #[must_use]
97 pub fn name(&self) -> &str {
98 &self.name
99 }
100
101 #[must_use]
102 pub fn artists(&self) -> &ArtistGroup {
103 &self.artist_group
104 }
105
106 #[must_use]
107 pub fn track_refs(&self) -> &[TrackReference] {
108 &self.tracks
109 }
110}
111
112#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
113pub struct TrackReference {
114 pub id: TrackId,
115 pub track_num: Option<u16>,
116 pub disc_num: Option<u16>,
117}
118
119impl PartialEq for TrackReference {
120 fn eq(&self, other: &Self) -> bool {
121 self.id == other.id
122 }
123}
124
125impl Eq for TrackReference {}
126
127impl Patchable<Self> for TrackReference {
128 fn patch(&mut self, patch: Self) {
129 let Self {
130 id: _,
131 track_num,
132 disc_num,
133 } = patch;
134
135 patch_option_replace(&mut self.track_num, track_num);
136 patch_option_replace(&mut self.disc_num, disc_num);
137 }
138}