[READ-ONLY] Mirror of https://github.com/probablykasper/ferrum. Music library app for Mac, Linux and Windows ferrum.kasper.space
electron linux macos music music-library music-player napi windows
0

Configure Feed

Select the types of activity you want to include in your feed.

Prevent serialization without generating item IDs

Kasper (Sep 26, 2024, 3:20 AM +0200) 3f573e8b ca236d9c

+49 -19
+3 -1
src-native/library.rs
··· 81 81 }, 82 82 }; 83 83 84 - Ok(versioned_library.upgrade()) 84 + let library = versioned_library.upgrade().init_libary(); 85 + println!("Initialized library: {}ms", now.elapsed().as_millis()); 86 + Ok(library) 85 87 } 86 88 87 89 pub enum TrackField {
+43 -16
src-native/library_types.rs
··· 9 9 use std::path::PathBuf; 10 10 use std::sync::RwLock; 11 11 12 - #[derive(Serialize, Deserialize, Clone, Debug)] 13 - #[serde(deny_unknown_fields)] 12 + #[derive(Clone, Debug)] 14 13 pub struct Library { 14 + /// DO NOT INSERT DIRECTLY - A corresponding item ID must be generated by .insert_track() 15 15 tracks: LinkedHashMap<TrackID, Track>, 16 16 pub trackLists: TrackLists, 17 17 /// v1 playtime has two issues: ··· 22 22 } 23 23 impl Library { 24 24 pub fn versioned(&self) -> VersionedLibrary { 25 - VersionedLibrary::V2(Cow::Borrowed(self)) 25 + VersionedLibrary::V2(V2Library { 26 + tracks: Cow::Borrowed(&self.tracks), 27 + trackLists: Cow::Borrowed(&self.trackLists), 28 + v1PlayTime: Cow::Borrowed(&self.v1PlayTime), 29 + playTime: Cow::Borrowed(&self.playTime), 30 + }) 26 31 } 27 32 } 28 33 ··· 32 37 #[serde(rename = "1")] 33 38 V1(Cow<'a, V1Library>), 34 39 #[serde(rename = "2")] 35 - V2(Cow<'a, Library>), 40 + V2(V2Library<'a>), 36 41 } 37 - impl VersionedLibrary<'_> { 38 - pub fn upgrade(self) -> Library { 42 + impl<'a> VersionedLibrary<'a> { 43 + pub fn upgrade(self) -> V2Library<'a> { 39 44 match self { 40 45 VersionedLibrary::V1(v1) => v1.into_owned().upgrade(), 41 - VersionedLibrary::V2(v2) => v2.into_owned(), 46 + VersionedLibrary::V2(v2) => v2, 42 47 } 43 48 } 44 49 } 45 50 46 51 #[derive(Serialize, Deserialize, Clone, Debug)] 47 52 #[serde(deny_unknown_fields)] 48 - pub struct V1Library { 49 - pub tracks: LinkedHashMap<TrackID, Track>, 50 - pub trackLists: TrackLists, 51 - pub playTime: Vec<PlayTime>, 53 + pub struct V2Library<'a> { 54 + pub tracks: Cow<'a, LinkedHashMap<TrackID, Track>>, 55 + pub trackLists: Cow<'a, TrackLists>, 56 + /// v1 playtime has two issues: 57 + /// - some durations are double counted (or triple, etc.) 58 + /// - timestamps aren't updated after pausing 59 + pub v1PlayTime: Cow<'a, Vec<PlayTime>>, 60 + pub playTime: Cow<'a, Vec<PlayTime>>, 52 61 } 53 - impl V1Library { 54 - pub fn upgrade(self) -> Library { 62 + impl<'a> V2Library<'a> { 63 + pub fn init_libary(self) -> Library { 55 64 let mut library = Library { 56 65 tracks: LinkedHashMap::new(), 57 - trackLists: self.trackLists, 58 - v1PlayTime: self.playTime, 66 + trackLists: self.trackLists.into_owned(), 67 + v1PlayTime: self.playTime.into_owned(), 59 68 playTime: Vec::new(), 60 69 }; 61 - for (id, track) in self.tracks { 70 + for (id, track) in self.tracks.into_owned() { 62 71 library.insert_track(id, track); 63 72 } 64 73 library 74 + } 75 + } 76 + 77 + #[derive(Serialize, Deserialize, Clone, Debug)] 78 + #[serde(deny_unknown_fields)] 79 + pub struct V1Library { 80 + pub tracks: LinkedHashMap<TrackID, Track>, 81 + pub trackLists: TrackLists, 82 + pub playTime: Vec<PlayTime>, 83 + } 84 + impl V1Library { 85 + pub fn upgrade<'a>(self) -> V2Library<'a> { 86 + V2Library { 87 + tracks: Cow::Owned(LinkedHashMap::new()), 88 + trackLists: Cow::Owned(self.trackLists), 89 + v1PlayTime: Cow::Owned(self.playTime), 90 + playTime: Cow::Owned(Vec::new()), 91 + } 65 92 } 66 93 } 67 94
+3 -2
src-native/tracks/cover.rs
··· 13 13 use std::io::{BufWriter, Cursor}; 14 14 use std::path::PathBuf; 15 15 use std::sync::{Arc, RwLock}; 16 - use std::time::UNIX_EPOCH; 16 + use std::time::{Instant, UNIX_EPOCH}; 17 17 18 18 // (modified_timestamp_ms, image_bytes) 19 19 type CacheEntry = (i64, Vec<u8>); ··· 25 25 } 26 26 27 27 fn init_cache_db(path: String) -> Result<()> { 28 + let now = Instant::now(); 28 29 let cache_db_mutex = CACHE_DB.read().unwrap(); 29 30 if cache_db_mutex.is_none() { 30 31 drop(cache_db_mutex); ··· 42 43 } 43 44 init_txn.commit().context("Could not commit cache: {}")?; 44 45 *cache_db_mutex = Some(db); 45 - println!("Initialized Cache.redb"); 46 + println!("Initialized Cache.redb: {}ms", now.elapsed().as_millis()); 46 47 } 47 48 } 48 49 Ok(())