Skip to main content

selene_core/library/
album.rs

1use 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    /// Do not modify this variable without handling dangling references
54    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
65// Core
66impl 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
89// Accessors
90impl 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}