From d6e1a67d13415f6978351bb4e46c427bb58f68fe Mon Sep 17 00:00:00 2001 From: Kasper Date: Thu, 26 Sep 2024 08:38:36 +0200 Subject: [PATCH] Move errors to anyhow --- src-native/data.rs | 17 +++--- src-native/data_js.rs | 9 ++-- src-native/itunes_import.rs | 72 +++++++++++-------------- src-native/lib.rs | 25 ++------- src-native/library.rs | 98 ++++++++++++++++------------------ src-native/library_types.rs | 39 +++++++------- src-native/playlists.rs | 93 ++++++++++++++++----------------- src-native/sort.rs | 9 ++-- src-native/tracks/cover.rs | 11 ++-- src-native/tracks/import.rs | 48 +++++++---------- src-native/tracks/md.rs | 54 +++++-------------- src-native/tracks/mod.rs | 36 ++++++------- src-native/tracks/tag.rs | 101 ++++++++---------------------------- src-native/view_options.rs | 19 +++---- 14 files changed, 239 insertions(+), 392 deletions(-) diff --git a/src-native/data.rs b/src-native/data.rs index 7bed3d22..7db962f2 100644 --- a/src-native/data.rs +++ b/src-native/data.rs @@ -2,10 +2,9 @@ use crate::artists::load_artists; use crate::library::{load_library, Paths}; use crate::library_types::Library; use crate::tracks::Tag; -use crate::UniResult; +use anyhow::{Context, Result}; use atomicwrites::{AllowOverwrite, AtomicFile}; use dirs_next; -use napi::Result; use serde::Serialize; use std::collections::HashSet; use std::env; @@ -34,11 +33,7 @@ impl Data { now = Instant::now(); let file_path = &self.paths.library_json; let af = AtomicFile::new(file_path, AllowOverwrite); - let result = af.write(|f| f.write_all(&json)); - match result { - Ok(_) => {} - Err(err) => throw!("Error saving: {err}"), - } + af.write(|f| f.write_all(&json)).context("Error saving")?; println!("Write: {}ms", now.elapsed().as_millis()); Ok(()) } @@ -46,7 +41,7 @@ impl Data { is_dev: bool, local_data_path: Option, library_path: Option, - ) -> UniResult { + ) -> Result { if is_dev { println!("Starting in dev mode"); } @@ -61,13 +56,13 @@ impl Data { local_data_dir = appdata_dev.join("LocalData/space.kasper.ferrum"); } else { library_dir = dirs_next::audio_dir() - .ok_or("Music folder not found")? + .context("Music folder not found")? .join("Ferrum"); cache_dir = dirs_next::cache_dir() - .ok_or("Cache folder not found")? + .context("Cache folder not found")? .join("space.kasper.ferrum"); local_data_dir = dirs_next::data_local_dir() - .ok_or("Local data folder not found")? + .context("Local data folder not found")? .join("space.kasper.ferrum"); }; let paths = Paths { diff --git a/src-native/data_js.rs b/src-native/data_js.rs index 9c0355fb..720b5742 100644 --- a/src-native/data_js.rs +++ b/src-native/data_js.rs @@ -1,8 +1,9 @@ use crate::data::Data; -use napi::{Env, JsUndefined, Result}; +use anyhow::{Context, Result}; +use napi::{Env, JsUndefined}; pub fn get_data(env: &Env) -> Result<&mut Data> { - let data = env.get_instance_data::()?.ok_or(nerr!("No data"))?; + let data = env.get_instance_data::()?.context("No data")?; return Ok(data); } @@ -43,8 +44,8 @@ pub fn get_paths(env: Env) -> Result { #[napi(js_name = "save")] #[allow(dead_code)] -pub fn save(env: Env) -> Result { +pub fn save(env: Env) -> napi::Result { let data: &mut Data = get_data(&env)?; data.save()?; - return env.get_undefined(); + env.get_undefined() } diff --git a/src-native/itunes_import.rs b/src-native/itunes_import.rs index 4c0100d1..d15765da 100644 --- a/src-native/itunes_import.rs +++ b/src-native/itunes_import.rs @@ -5,8 +5,9 @@ use crate::library_types::{ }; use crate::tracks::generate_filename; use crate::tracks::import::{read_file_metadata, FileType}; +use anyhow::{bail, Context, Result}; use lofty::file::{AudioFile, TaggedFileExt}; -use napi::{Env, Result}; +use napi::Env; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fs; @@ -61,10 +62,8 @@ impl XmlLibrary { continue; } - let track: XmlTrack = match plist::from_value(&value) { - Ok(track) => track, - Err(e) => throw!("Could not read track with id \"{key}\": {e}"), - }; + let track: XmlTrack = plist::from_value(&value) + .with_context(|| format!("Could not read track with id \"{key}"))?; tracks.insert(key, track); } let mut playlists = Vec::new(); @@ -75,10 +74,8 @@ impl XmlLibrary { .and_then(|v| v.as_string()) .unwrap_or_default() .to_string(); - let playlist: XmlPlaylist = match plist::from_value(value) { - Ok(playlist) => playlist, - Err(e) => throw!("Could not read playlist \"{name}\": {e}"), - }; + let playlist: XmlPlaylist = plist::from_value(value) + .with_context(|| format!("Could not read playlist \"{name}\""))?; playlists.push(playlist); } Ok(XmlLibraryProps { tracks, playlists }) @@ -96,13 +93,13 @@ impl XmlLibraryProps { for xml_playlist in playlists { if xml_playlist.distinguished_kind == Some(4) { if xml_music_playlist.is_some() { - throw!("Found two iTunes-generated Music playlists"); + bail!("Found two iTunes-generated Music playlists"); } else { xml_music_playlist = Some(xml_playlist); } } } - xml_music_playlist.ok_or(nerr!("No Music playlist found")) + xml_music_playlist.context("No Music playlist found") } fn take_importable_playlists(&mut self) -> Vec { let playlists = std::mem::take(&mut self.playlists); @@ -310,17 +307,14 @@ impl CountInfo { } fn parse_file_url(value: &str) -> Result { - let file_url = match url::Url::parse(value) { - Ok(url) => url, - Err(e) => throw!("Invalid track location: {}", e), - }; + let file_url = url::Url::parse(value).context("Invalid track location")?; match file_url.scheme() { "file" => {} - _ => throw!("Invalid track location scheme: {}", value), + _ => bail!("Invalid track location scheme: {}", value), } match file_url.to_file_path() { Ok(path) => Ok(path), - Err(()) => throw!("Invalid track location host: {}", value), + Err(()) => bail!("Invalid track location host: {}", value), } } @@ -330,15 +324,12 @@ fn parse_track( start_time: i64, tracks_dir: &Path, ) -> Result<(PathBuf, Track)> { - let xml_location = match xml_track.location { - Some(ref location) => location, - None => throw!("Missing track location"), - }; + let xml_location = xml_track.location.context("Missing track location")?; if xml_track.track_type != Some("File".to_string()) { - return Err(nerr!( + bail!( "Track with type {}, expected \"File\"", xml_track.track_type.as_deref().unwrap_or("unknown"), - )); + ); } // Unlike "Skip Date" etc, "Play Date" is a non-UTC Mac HFS+ timestamp, but @@ -347,15 +338,13 @@ fn parse_track( let skip = CountInfo::new(xml_track.skip_count, xml_track.skip_date); - let xml_track_path = parse_file_url(xml_location)?; + let xml_track_path = parse_file_url(&xml_location)?; // this will also checks if the file exists let file_md = read_file_metadata(&xml_track_path)?; - let tagged_file = match lofty::read_from_path(&xml_track_path) { - Ok(tagged_file) => tagged_file, - Err(e) => throw!("Failed to read file information: {}", e), - }; + let tagged_file = + lofty::read_from_path(&xml_track_path).context("Failed to read file information")?; let audio_properties = tagged_file.properties(); let file_type = FileType::from_path(&xml_track_path)?; @@ -376,11 +365,11 @@ fn parse_track( duration: audio_properties.duration().as_secs_f64(), bitrate: audio_properties .audio_bitrate() - .ok_or(nerr!("Unknown bitrate"))? + .context("Unknown bitrate")? .into(), sampleRate: audio_properties .audio_bitrate() - .ok_or(nerr!("Unknown sample rate"))? + .context("Unknown sample rate")? .into(), file: filename, dateModified: datetime_to_timestamp_millis(xml_track.date_modified), @@ -436,7 +425,7 @@ fn parse_track( let float: f32 = volume_adjustment.into(); let vol = (float / 2.55).round() as i8; if vol < -100 || vol > 100 { - throw!("Invalid volume adjustment: {}", volume_adjustment); + bail!("Invalid volume adjustment: {}", volume_adjustment); } Some(vol) } @@ -599,7 +588,7 @@ pub struct ItunesImport { #[napi] impl ItunesImport { #[napi(factory)] - pub fn new(env: Env) -> Result { + pub fn new(env: Env) -> napi::Result { let data = get_data(&env)?; Ok(Self { new_library: Some(data.library.clone()).into(), @@ -607,19 +596,19 @@ impl ItunesImport { }) } #[napi] - pub async fn start(&self, path: String, tracks_dir: String) -> Result { - import_itunes(self, path, tracks_dir).await + pub async fn start(&self, path: String, tracks_dir: String) -> napi::Result { + Ok(import_itunes(self, path, tracks_dir).await?) } #[napi] - pub fn finish(&mut self, env: Env) -> Result<()> { + pub fn finish(&mut self, env: Env) -> napi::Result<()> { let data = get_data(&env)?; let itunes_track_paths = &mut *self.itunes_track_paths.lock().unwrap(); for (itunes_path, ferrum_file) in itunes_track_paths { let new_path = data.paths.tracks_dir.join(ferrum_file); - fs::copy(itunes_path, new_path).or(Err(nerr!("Error copying file")))?; + fs::copy(itunes_path, new_path).context("Error copying file")?; } let new_library = &mut self.new_library.lock().unwrap(); - data.library = new_library.take().ok_or(nerr!("Not initialized"))?; + data.library = new_library.take().context("Not initialized")?; Ok(()) } } @@ -632,15 +621,12 @@ pub async fn import_itunes( let new_library_lock = &mut *itunes_import.new_library.lock().unwrap(); let mut library = match new_library_lock { Some(library) => library, - None => throw!("Not initialized"), + None => bail!("Not initialized"), }; let mut itunes_track_paths = itunes_import.itunes_track_paths.lock().unwrap(); let original_tracks_count = library.get_tracks().len(); let original_tracklists_count = library.trackLists.len(); - let xml_lib: XmlLibrary = match plist::from_file(path) { - Ok(book) => book, - Err(e) => throw!("Unable to parse: {e}"), - }; + let xml_lib: XmlLibrary = plist::from_file(path).context("Unable to parse")?; let mut errors = Vec::new(); let start_time = get_now_timestamp(); @@ -667,7 +653,7 @@ pub async fn import_itunes( let xml_track = xml .tracks .remove(&xml_id) - .ok_or(nerr!("Track with id {} not found", playlist_item.track_id))?; + .with_context(|| format!("Track with id {} not found", playlist_item.track_id))?; let artist_title = xml_track.artist_title(); if matches!(xml_track.name.as_deref(), Some("") | None) { diff --git a/src-native/lib.rs b/src-native/lib.rs index 7a5653a0..0463dee1 100644 --- a/src-native/lib.rs +++ b/src-native/lib.rs @@ -1,3 +1,4 @@ +use anyhow::{Context, Result}; use serde::de::DeserializeOwned; use std::fs::File; use std::io::BufReader; @@ -5,18 +6,6 @@ use std::mem; use std::path::PathBuf; use std::time::{SystemTime, UNIX_EPOCH}; -macro_rules! nerr { - ($($arg:tt)*) => { - napi::Error::from_reason(format!($($arg)*).to_owned()) - } -} - -macro_rules! throw { - ($($arg:tt)*) => { - return crate::UniResult::Err(format!($($arg)*).into()).map_err(|e| e.into()) - } -} - #[macro_use] extern crate napi_derive; @@ -85,18 +74,12 @@ impl From for UniError { } } -fn path_to_json(path: PathBuf) -> UniResult +fn path_to_json(path: PathBuf) -> Result where J: DeserializeOwned, { - let file = match File::open(path) { - Ok(f) => f, - Err(err) => throw!("Error opening file: {}", err), - }; + let file = File::open(path).context("Error opening file")?; let reader = BufReader::new(file); - let json = match serde_json::from_reader(reader) { - Ok(json) => json, - Err(err) => throw!("Error parsing file: {:?}", err), - }; + let json = serde_json::from_reader(reader).context("Error parsing file")?; Ok(json) } diff --git a/src-native/library.rs b/src-native/library.rs index 7fb63143..0224f543 100644 --- a/src-native/library.rs +++ b/src-native/library.rs @@ -1,9 +1,9 @@ use crate::library_types::{Library, VersionedLibrary}; -use crate::UniResult; +use anyhow::{bail, Context, Result}; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use std::fs::{create_dir_all, File}; -use std::io::{Error, ErrorKind, Read}; +use std::io::{ErrorKind, Read}; use std::path::PathBuf; use std::time::Instant; @@ -17,7 +17,7 @@ pub struct Paths { pub local_data_dir: PathBuf, } impl Paths { - fn ensure_dirs_exists(&self) -> Result<(), Error> { + fn ensure_dirs_exists(&self) -> Result<()> { create_dir_all(&self.library_dir)?; create_dir_all(&self.tracks_dir)?; create_dir_all(&self.local_data_dir)?; @@ -26,60 +26,50 @@ impl Paths { } } -pub fn load_library(paths: &Paths) -> UniResult { +pub fn load_library(paths: &Paths) -> Result { let mut now = Instant::now(); - match paths.ensure_dirs_exists() { - Ok(_) => {} - Err(err) => throw!("Error ensuring folder exists: {}", err), - }; + paths + .ensure_dirs_exists() + .context("Error ensuring folder exists")?; println!( "Loading library at path: {}", paths.library_dir.to_string_lossy() ); - let versioned_library = match File::open(&paths.library_json) { - Ok(mut file) => { - let mut json_str = String::new(); - match file.read_to_string(&mut json_str) { - Ok(_) => {} - Err(err) => throw!("Error reading library file: {}", err), - }; - println!("Read library: {}ms", now.elapsed().as_millis()); - now = Instant::now(); + let mut library_file = match File::open(&paths.library_json) { + Ok(file) => file, + Err(err) => match err.kind() { + ErrorKind::NotFound => return Ok(Library::new()), + _ => return Err(err).context("Error opening library file"), + }, + }; - let mut value: Value = match serde_json::from_str(&mut json_str) { - Ok(library) => library, - Err(err) => throw!("Error parsing library file: {:?}", err), - }; - // Migrate version number to string - if let Some(obj) = value.as_object_mut() { - if let Some(version_field) = obj.get_mut("version") { - if let Some(version) = version_field.as_number() { - if version.as_u64() == Some(1) { - *version_field = json!("1"); - } else if version.as_u64() == Some(2) { - *version_field = json!("2"); - } - } + let mut json_str = String::new(); + library_file + .read_to_string(&mut json_str) + .context("Error reading library file")?; + println!("Read library: {}ms", now.elapsed().as_millis()); + now = Instant::now(); + + let mut value: Value = + serde_json::from_str(&mut json_str).context("Error parsing library file")?; + // Migrate version number to string + if let Some(obj) = value.as_object_mut() { + if let Some(version_field) = obj.get_mut("version") { + if let Some(version) = version_field.as_number() { + if version.as_u64() == Some(1) { + *version_field = json!("1"); + } else if version.as_u64() == Some(2) { + *version_field = json!("2"); } } - - let versioned_library: VersionedLibrary = match serde_json::from_value(value) { - Ok(library) => library, - Err(err) => throw!("Error parsing library file: {:?}", err), - }; - - println!("Parse library: {}ms", now.elapsed().as_millis()); - versioned_library } - Err(err) => match err.kind() { - ErrorKind::NotFound => { - return Ok(Library::new()); - } - _err_kind => throw!("Error opening library file: {}", err), - }, - }; + } + + let versioned_library: VersionedLibrary = + serde_json::from_value(value).context("Error parsing library file")?; + println!("Parse library: {}ms", now.elapsed().as_millis()); let library = versioned_library.upgrade().init_libary(); println!("Initialized library: {}ms", now.elapsed().as_millis()); @@ -98,19 +88,19 @@ pub enum TrackField { #[napi(js_name = "get_default_sort_desc")] #[allow(dead_code)] -pub fn get_default_sort_desc(field: String) -> bool { +pub fn get_default_sort_desc(field: String) -> Result { if field == "index" { - return true; + return Ok(true); } - let field = get_track_field_type(&field); + let field = get_track_field_type(&field)?; let desc = match field { - Some(TrackField::String) => false, + TrackField::String => false, _ => true, }; - return desc; + Ok(desc) } -pub fn get_track_field_type(field: &str) -> Option { +pub fn get_track_field_type(field: &str) -> Result { let field = match field { "size" => TrackField::I64, "duration" => TrackField::F64, @@ -149,7 +139,7 @@ pub fn get_track_field_type(field: &str) -> Option { "playCount" => TrackField::U32, "skipCount" => TrackField::U32, "volume" => TrackField::I8, - _ => return None, + _ => bail!("Field type not found for {}", field), }; - return Some(field); + return Ok(field); } diff --git a/src-native/library_types.rs b/src-native/library_types.rs index 20c43f25..d0ca8f1b 100644 --- a/src-native/library_types.rs +++ b/src-native/library_types.rs @@ -1,7 +1,8 @@ #![allow(non_snake_case)] +use crate::get_now_timestamp; use crate::playlists::{delete_file, remove_from_all_playlists}; -use crate::{get_now_timestamp, UniResult}; +use anyhow::{bail, Context, Result}; use linked_hash_map::{Entry, LinkedHashMap}; use nanoid::nanoid; use serde::{Deserialize, Serialize}; @@ -131,13 +132,13 @@ impl Library { track_id_map.push(id.clone()); self.track_item_ids.insert(id, item_id); } - pub fn delete_track_and_file(&mut self, id: &TrackID, tracks_dir: &PathBuf) -> UniResult<()> { + pub fn delete_track_and_file(&mut self, id: &TrackID, tracks_dir: &PathBuf) -> Result<()> { let file_path = { let track = self.get_track(id)?; tracks_dir.join(&track.file) }; if !file_path.exists() { - throw!("File does not exist: {}", file_path.to_string_lossy()); + bail!("File does not exist: {}", file_path.to_string_lossy()); } remove_from_all_playlists(self, id); @@ -191,33 +192,29 @@ impl Library { children: Vec::new(), } } - pub fn get_track(&self, id: &TrackID) -> UniResult<&Track> { - match self.get_tracks().get(id) { - Some(track) => Ok(track), - None => throw!("Track with ID {} not found", id), - } + pub fn get_track(&self, id: &TrackID) -> Result<&Track> { + self.get_tracks() + .get(id) + .context("Track with ID {} not found") } - pub fn get_track_mut(&mut self, id: &TrackID) -> UniResult<&mut Track> { - match self.tracks.get_mut(id) { - Some(track) => Ok(track), - None => throw!("Track with ID {} not found", id), - } + pub fn get_track_mut(&mut self, id: &TrackID) -> Result<&mut Track> { + self.tracks + .get_mut(id) + .context("Track with ID {} not found") } - pub fn get_tracklist(&self, id: &str) -> UniResult<&TrackList> { - let tracklist = self.trackLists.get(id); - Ok(tracklist.ok_or("Playlist ID not found")?) + pub fn get_tracklist(&self, id: &str) -> Result<&TrackList> { + self.trackLists.get(id).context("Playlist ID not found") } - pub fn get_tracklist_mut(&mut self, id: &str) -> UniResult<&mut TrackList> { - let tracklist = self.trackLists.get_mut(id); - Ok(tracklist.ok_or("Playlist ID not found")?) + pub fn get_tracklist_mut(&mut self, id: &str) -> Result<&mut TrackList> { + self.trackLists.get_mut(id).context("Playlist ID not found") } - pub fn get_root_tracklist_mut(&mut self) -> UniResult<&mut Special> { + pub fn get_root_tracklist_mut(&mut self) -> Result<&mut Special> { let tracklist = self.trackLists.get_mut("root"); match tracklist { Some(TrackList::Special(special)) => match special.name { SpecialTrackListName::Root => Ok(special), }, - _ => throw!("Root playlist not found"), + _ => bail!("Root playlist not found"), } } pub fn get_parent_id(&self, id: &str) -> Option { diff --git a/src-native/playlists.rs b/src-native/playlists.rs index 7019ec8f..a7285662 100644 --- a/src-native/playlists.rs +++ b/src-native/playlists.rs @@ -4,8 +4,9 @@ use crate::library_types::{ get_track_ids_from_item_ids, new_item_ids_from_track_ids, ItemId, Library, SpecialTrackListName, TrackID, TrackList, TRACK_ID_MAP, }; -use crate::{str_to_option, UniResult}; -use napi::{Env, JsUnknown, Result}; +use crate::str_to_option; +use anyhow::{bail, Context, Result}; +use napi::{Env, JsUnknown}; use std::collections::{HashMap, HashSet}; use std::path::PathBuf; @@ -60,7 +61,7 @@ pub fn get_track_lists_details(env: Env) -> Result Result { let data: &mut Data = get_data(&env)?; let tracklist = data.library.get_tracklist(&id)?; - env.to_js_value(&tracklist) + Ok(env.to_js_value(&tracklist)?) } fn get_child_ids_recursive( @@ -71,8 +72,8 @@ fn get_child_ids_recursive( let folder_children = match library.trackLists.get(id) { Some(TrackList::Playlist(_)) => return Ok(()), Some(TrackList::Folder(folder)) => folder.children.clone(), - Some(TrackList::Special(_)) => throw!("Cannot delete special track list"), - None => throw!("No track list with id {}", id), + Some(TrackList::Special(_)) => bail!("Cannot delete special track list"), + None => bail!("No track list with id {}", id), }; for child_id in &folder_children { get_child_ids_recursive(library, &child_id, ids)?; @@ -80,19 +81,19 @@ fn get_child_ids_recursive( for new_id in folder_children { let was_new = ids.insert(new_id.clone()); if !was_new { - throw!("Duplicate track list id {new_id}"); + bail!("Duplicate track list id {new_id}"); } } Ok(()) } fn remove_child_id(library: &mut Library, parent_id: &String, child_id: &String) -> Result<()> { - let parent = match library.trackLists.get_mut(parent_id) { - Some(tracklist) => tracklist, - None => throw!("Parent id {parent_id} not found"), - }; + let parent = library + .trackLists + .get_mut(parent_id) + .with_context(|| format!("Parent id {parent_id} not found"))?; let children = match parent { - TrackList::Playlist(_) => throw!("Parent id {parent_id} not found"), + TrackList::Playlist(_) => bail!("Parent id {parent_id} not found"), TrackList::Folder(folder) => folder.children.clone(), TrackList::Special(special) => match special.name { SpecialTrackListName::Root => special.children.clone(), @@ -104,9 +105,9 @@ fn remove_child_id(library: &mut Library, parent_id: &String, child_id: &String) .filter(|id| id != child_id) .collect(); match children.len() - new_children.len() { - 0 => throw!("Parent id {child_id} does not contain child"), + 0 => bail!("Parent id {child_id} does not contain child"), 1 => (), - _ => throw!("Child id {child_id} found multiple times"), + _ => bail!("Child id {child_id} found multiple times"), }; match parent { TrackList::Playlist(_) => panic!(), @@ -123,17 +124,14 @@ fn remove_child_id(library: &mut Library, parent_id: &String, child_id: &String) #[allow(dead_code)] pub fn delete_track_list(id: String, env: Env) -> Result<()> { let data: &mut Data = get_data(&env)?; - let parent_id = data - .library - .get_parent_id(&id) - .ok_or(nerr!("No parent found"))?; + let parent_id = data.library.get_parent_id(&id).context("No parent found")?; let mut ids = HashSet::new(); ids.insert(id.clone()); get_child_ids_recursive(&mut data.library, &id, &mut ids)?; if ids.contains(&parent_id) { - throw!("Parent id {parent_id} contains itself"); + bail!("Parent id {parent_id} contains itself"); } remove_child_id(&mut data.library, &parent_id, &id)?; for id in &ids { @@ -148,8 +146,8 @@ pub fn add_tracks(playlist_id: String, track_ids: Vec, env: Env) -> Resu let data: &mut Data = get_data(&env)?; let playlist = match data.library.get_tracklist_mut(&playlist_id)? { TrackList::Playlist(playlist) => playlist, - TrackList::Folder(_) => throw!("Cannot add track to folder"), - TrackList::Special(_) => throw!("Cannot add track to special playlist"), + TrackList::Folder(_) => bail!("Cannot add track to folder"), + TrackList::Special(_) => bail!("Cannot add track to special playlist"), }; let mut new_item_ids = new_item_ids_from_track_ids(&track_ids); playlist.tracks.append(&mut new_item_ids); @@ -163,7 +161,7 @@ pub fn filter_duplicates(playlist_id: TrackID, ids: Vec, env: Env) -> Re let mut track_ids: HashSet = HashSet::from_iter(ids); let playlist = match data.library.get_tracklist_mut(&playlist_id)? { TrackList::Playlist(playlist) => playlist, - _ => throw!("Cannot check if folder/special contains track"), + _ => bail!("Cannot check if folder/special contains track"), }; for track in &playlist.get_track_ids() { if track_ids.contains(track) { @@ -180,7 +178,7 @@ pub fn remove_from_playlist(playlist_id: TrackID, item_ids: Vec, env: En let data: &mut Data = get_data(&env)?; let playlist = match data.library.get_tracklist_mut(&playlist_id)? { TrackList::Playlist(playlist) => playlist, - _ => throw!("Cannot remove track from non-playlist"), + _ => bail!("Cannot remove track from non-playlist"), }; let items_to_remove: HashSet = item_ids.into_iter().collect(); @@ -204,17 +202,16 @@ pub fn remove_from_all_playlists(library: &mut Library, id: &TrackID) { } } -pub fn delete_file(path: &PathBuf) -> UniResult<()> { +pub fn delete_file(path: &PathBuf) -> Result<()> { #[allow(unused_mut)] let mut trash_context = trash::TrashContext::new(); #[cfg(target_os = "macos")] trash_context.set_delete_method(trash::macos::DeleteMethod::NsFileManager); - match trash_context.delete(&path) { - Ok(_) => Ok(()), - Err(_) => throw!("Failed moving file to trash: {}", path.to_string_lossy()), - } + trash_context + .delete(&path) + .with_context(|| format!("Failed moving file to trash: {}", path.to_string_lossy())) } #[napi(js_name = "delete_tracks_with_item_ids")] @@ -252,13 +249,13 @@ pub fn new_playlist( } }; - let parent = match library.trackLists.get_mut(&parent_id) { - Some(parent) => parent, - None => throw!("Parent not found"), - }; + let parent = library + .trackLists + .get_mut(&parent_id) + .context("Parent not found")?; match parent { - TrackList::Playlist(_) => throw!("Parent cannot be playlist"), + TrackList::Playlist(_) => bail!("Parent cannot be playlist"), TrackList::Folder(folder) => { folder.children.push(list.id().to_string()); library.trackLists.insert(list.id().to_string(), list); @@ -280,7 +277,7 @@ pub fn update_playlist(id: String, name: String, description: String, env: Env) let data: &mut Data = get_data(&env)?; match data.library.trackLists.get_mut(&id) { - Some(TrackList::Special(_)) => throw!("Cannot edit special playlists"), + Some(TrackList::Special(_)) => bail!("Cannot edit special playlists"), Some(TrackList::Playlist(playlist)) => { playlist.name = name; playlist.description = str_to_option(description); @@ -289,13 +286,13 @@ pub fn update_playlist(id: String, name: String, description: String, env: Env) folder.name = name; folder.description = str_to_option(description); } - None => throw!("Playlist not found"), + None => bail!("Playlist not found"), }; return Ok(()); } -fn get_all_tracklist_children(data: &Data, playlist_id: &str) -> UniResult> { +fn get_all_tracklist_children(data: &Data, playlist_id: &str) -> Result> { let direct_children = match data.library.get_tracklist(playlist_id)? { TrackList::Folder(folder) => &folder.children, TrackList::Special(special) => &special.children, @@ -320,14 +317,14 @@ fn get_all_tracklist_children(data: &Data, playlist_id: &str) -> UniResult( library: &'a mut Library, id: &'a str, -) -> UniResult<&'a mut Vec> { +) -> Result<&'a mut Vec> { let children = match library.trackLists.get_mut(id) { Some(TrackList::Folder(folder)) => &mut folder.children, Some(TrackList::Special(special)) => match special.name { SpecialTrackListName::Root => &mut special.children, }, - None => throw!("Attempted to move from/to non-existant folder"), - _ => throw!("Attempted to move from/to non-folder"), + None => bail!("Attempted to move from/to non-existant folder"), + _ => bail!("Attempted to move from/to non-folder"), }; Ok(children) } @@ -344,8 +341,8 @@ pub fn move_playlist( let data: &mut Data = get_data(&env)?; match data.library.trackLists.get(&id) { - Some(TrackList::Special(_)) => throw!("Cannot move special playlist"), - None => throw!("List not found"), + Some(TrackList::Special(_)) => bail!("Cannot move special playlist"), + None => bail!("List not found"), _ => {} }; @@ -353,19 +350,19 @@ pub fn move_playlist( get_children_if_user_editable(&mut data.library, &to_id)?; if id == to_id { - throw!("Cannot move playlist into itself"); + bail!("Cannot move playlist into itself"); } let from_id_children = get_all_tracklist_children(&data, &id)?; if from_id_children.contains(&to_id) { - throw!("Cannot move playlist to a child of itself"); + bail!("Cannot move playlist to a child of itself"); } let children = get_children_if_user_editable(&mut data.library, &from_id)?; - let i = match children.iter().position(|child_id| child_id == &id) { - None => throw!("Could not find playlist"), - Some(i) => i, - }; + let i = children + .iter() + .position(|child_id| child_id == &id) + .context("Could not find playlist")?; children.remove(i); let to_folder_children = get_children_if_user_editable(&mut data.library, &to_id)?; @@ -391,7 +388,7 @@ pub fn move_tracks( let data: &mut Data = get_data(&env)?; let playlist = match data.library.get_tracklist_mut(&playlist_id)? { TrackList::Playlist(playlist) => playlist, - _ => return Err(nerr!("Cannot rearrange tracks in non-playlist")), + _ => bail!("Cannot rearrange tracks in non-playlist"), }; let item_ids_set: HashSet = item_ids.iter().cloned().collect(); @@ -416,7 +413,7 @@ pub fn move_tracks( Ok(()) } -pub fn get_tracklist_item_ids(library: &Library, playlist_id: &str) -> UniResult> { +pub fn get_tracklist_item_ids(library: &Library, playlist_id: &str) -> Result> { match library.get_tracklist(playlist_id)? { TrackList::Playlist(playlist) => Ok(playlist.tracks.clone()), TrackList::Folder(folder) => { diff --git a/src-native/sort.rs b/src-native/sort.rs index 0ce38acc..45c8f60f 100644 --- a/src-native/sort.rs +++ b/src-native/sort.rs @@ -2,8 +2,8 @@ use crate::library::{get_track_field_type, TrackField}; use crate::library_types::{ItemId, Library, Track, TRACK_ID_MAP}; use crate::page::TracksPageOptions; use crate::playlists::get_tracklist_item_ids; -use crate::UniResult; use alphanumeric_sort::compare_str; +use anyhow::Result; use std::cmp::Ordering; use std::time::Instant; @@ -86,7 +86,7 @@ fn get_field_bool(track: &Track, sort_key: &str) -> Option { } } -pub fn sort(options: TracksPageOptions, library: &Library) -> UniResult> { +pub fn sort(options: TracksPageOptions, library: &Library) -> Result> { let now = Instant::now(); let id_map = TRACK_ID_MAP.read().unwrap(); @@ -104,10 +104,7 @@ pub fn sort(options: TracksPageOptions, library: &Library) -> UniResult field, - None => throw!("Field type not found for {}", options.sort_key), - }; + let field = get_track_field_type(&options.sort_key)?; let subsort_field = options.group_album_tracks && match options.sort_key.as_str() { "dateAdded" | "albumName" | "comments" | "genre" | "year" | "artist" => true, diff --git a/src-native/tracks/cover.rs b/src-native/tracks/cover.rs index e699b9a6..ccd67692 100644 --- a/src-native/tracks/cover.rs +++ b/src-native/tracks/cover.rs @@ -1,5 +1,5 @@ use super::Tag; -use anyhow::Context; +use anyhow::{anyhow, bail, Context, Result}; use fast_image_resize::images::Image; use fast_image_resize::{IntoImageView, Resizer}; use image::codecs::jpeg::JpegEncoder; @@ -7,7 +7,6 @@ use image::codecs::png::PngEncoder; use image::{ImageEncoder, ImageFormat, ImageReader}; use lazy_static::lazy_static; use napi::bindgen_prelude::Buffer; -use napi::Result; use redb::{Database, TableDefinition}; use std::fs; use std::io::{BufWriter, Cursor}; @@ -121,11 +120,11 @@ pub async fn read_small_cover_async( path: String, index: u16, cache_db_path: String, -) -> Result> { +) -> napi::Result> { if path == "" { - throw!("path must not be empty") + return Err(anyhow!("path must not be empty").into()); } else if cache_db_path == "" { - throw!("cache_db_path must not be empty") + return Err(anyhow!("cache_db_path must not be empty").into()); } init_cache_db(cache_db_path)?; @@ -210,7 +209,7 @@ fn to_resized_image(image_bytes: Vec, max_size: u32) -> Result> { .into_inner() .context("Error getting inner img buffer")? } - _ => throw!("Unsupported image type"), + _ => bail!("Unsupported image type"), }; Ok(img_bytes) } diff --git a/src-native/tracks/import.rs b/src-native/tracks/import.rs index c289cc29..b5d00cf0 100644 --- a/src-native/tracks/import.rs +++ b/src-native/tracks/import.rs @@ -1,7 +1,8 @@ use crate::data::Data; use crate::library_types::Track; +use crate::sys_time_to_timestamp; use crate::tracks::generate_filename; -use crate::{sys_time_to_timestamp, UniResult}; +use anyhow::{bail, Context, Result}; use lofty::file::{AudioFile, TaggedFileExt}; use lofty::tag::{Accessor, ItemKey, TagExt}; use std::fs; @@ -14,21 +15,21 @@ pub enum FileType { Opus, } impl FileType { - pub fn from_path(path: &Path) -> UniResult { + pub fn from_path(path: &Path) -> Result { let ext = path.extension().unwrap_or_default().to_string_lossy(); match ext.as_ref() { "mp3" => Ok(FileType::Mp3), "m4a" => Ok(FileType::M4a), "opus" => Ok(FileType::Opus), - _ => throw!("Unsupported file extension {}", ext), + _ => bail!("Unsupported file extension {}", ext), } } - pub fn from_lofty_file_type(lofty_type: lofty::file::FileType) -> UniResult { + pub fn from_lofty_file_type(lofty_type: lofty::file::FileType) -> Result { match lofty_type { lofty::file::FileType::Mpeg => Ok(FileType::Mp3), lofty::file::FileType::Mp4 => Ok(FileType::M4a), lofty::file::FileType::Opus => Ok(FileType::Opus), - _ => throw!("Unsupported file type {:?}", lofty_type), + _ => bail!("Unsupported file type {:?}", lofty_type), } } pub fn file_extension(&self) -> &'static str { @@ -45,17 +46,17 @@ impl std::fmt::Display for FileType { } } -pub fn read_file_metadata(path: &Path) -> UniResult { +pub fn read_file_metadata(path: &Path) -> Result { match std::fs::metadata(path) { Ok(file_md) => Ok(file_md), Err(err) => match err.kind() { - std::io::ErrorKind::NotFound => throw!("File does not exist"), - _ => throw!("Unable to access file: {}", err), + std::io::ErrorKind::NotFound => bail!("File does not exist"), + _ => bail!("Unable to access file: {}", err), }, } } -pub fn import(data: &Data, track_path: &Path, now: i64) -> UniResult { +pub fn import(data: &Data, track_path: &Path, now: i64) -> Result { let file_md = read_file_metadata(track_path)?; let mut date_modified = match file_md.modified() { @@ -63,19 +64,13 @@ pub fn import(data: &Data, track_path: &Path, now: i64) -> UniResult { Err(_) => now, }; - let probe = match lofty::probe::Probe::open(track_path) { - Ok(f) => { - let parse_options = lofty::config::ParseOptions::new() - .read_properties(true) - .parsing_mode(lofty::config::ParsingMode::Strict); - f.options(parse_options) - } - Err(e) => throw!("File does not exist: {}", e), - }; - let mut tagged_file = match probe.read() { - Ok(f) => f, - Err(e) => throw!("Unable to read file: {}", e), - }; + let parse_options = lofty::config::ParseOptions::new() + .read_properties(true) + .parsing_mode(lofty::config::ParsingMode::Strict); + let probe = lofty::probe::Probe::open(track_path) + .context("File does not exist")? + .options(parse_options); + let mut tagged_file = probe.read().context("Unable to read file")?; let properties = tagged_file.properties().clone(); let mut tag_changed = false; @@ -108,10 +103,7 @@ pub fn import(data: &Data, track_path: &Path, now: i64) -> UniResult { let filename = generate_filename(tracks_dir, &artist, &title, extension); let dest_path = tracks_dir.join(&filename); - match fs::copy(track_path, &dest_path) { - Ok(_) => (), - Err(e) => throw!("Error copying file: {e}"), - }; + fs::copy(track_path, &dest_path).context("Error copying file")?; println!( "{} -> {}", track_path.to_string_lossy(), @@ -119,10 +111,10 @@ pub fn import(data: &Data, track_path: &Path, now: i64) -> UniResult { ); if tag_changed { - println!("Writing:::::::"); + println!("Writing tag to imported file"); match tag.save_to_path(&dest_path, lofty::config::WriteOptions::default()) { Ok(_) => (), - Err(e) => throw!("Unable to tag file {}: {e}", dest_path.to_string_lossy()), + Err(e) => bail!("Unable to tag file {}: {e}", dest_path.to_string_lossy()), }; // manually set date_modified because the date_modified doens't seem to // immediately update after tag.write_to_path(). diff --git a/src-native/tracks/md.rs b/src-native/tracks/md.rs index d33297e4..91593dd5 100644 --- a/src-native/tracks/md.rs +++ b/src-native/tracks/md.rs @@ -1,9 +1,9 @@ #![allow(non_snake_case)] -use super::tag::SetInfoError; use super::{generate_filename, Tag}; use crate::library_types::Track; -use crate::{get_now_timestamp, str_to_option, UniResult}; +use crate::{get_now_timestamp, str_to_option}; +use anyhow::{bail, Context, Result}; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; @@ -36,10 +36,10 @@ pub fn update_track_info( track: &mut Track, tag: &mut Tag, new_info: TrackMD, -) -> UniResult<()> { +) -> Result<()> { let old_path = tracks_dir.join(&track.file); if !old_path.exists() { - throw!("File does not exist: {}", track.file); + bail!("File does not exist: {}", track.file); } let ext = old_path.extension().unwrap_or_default().to_string_lossy(); @@ -95,10 +95,7 @@ pub fn update_track_info( // year let new_year_i32 = match new_info.year.as_ref() { "" => None, - value => match value.parse() { - Ok(n) => Some(n), - Err(_) => throw!("Invalid year"), - }, + value => Some(value.parse().context("Invalid year")?), }; let new_year_i64 = new_year_i32.map(i64::from); match new_year_i32 { @@ -109,53 +106,28 @@ pub fn update_track_info( // track_number, track_count let new_track_number: Option = match new_info.trackNum.as_ref() { "" => None, - value => match value.parse() { - Ok(n) => Some(n), - Err(_) => throw!("Invalid track number"), - }, + value => Some(value.parse().context("Invalid track number")?), }; let new_track_count: Option = match new_info.trackCount.as_ref() { "" => None, - value => match value.parse() { - Ok(n) => Some(n), - Err(_) => throw!("Invalid track count"), - }, - }; - match tag.set_track_info(new_track_number, new_track_count) { - Ok(()) => {} - // don't set tag at all if number is required - Err(SetInfoError::NumberRequired) => tag.set_track_info(None, None)?, - Err(e) => Err(e)?, - } + value => Some(value.parse().context("Invalid track count")?), + }; + tag.set_track_info(new_track_number, new_track_count); // disc_number, disc_count let new_disc_number: Option = match new_info.discNum.as_ref() { "" => None, - value => match value.parse() { - Ok(n) => Some(n), - Err(_) => throw!("Invalid disc number"), - }, + value => Some(value.parse().context("Invalid disc number")?), }; let new_disc_count: Option = match new_info.discCount.as_ref() { "" => None, - value => match value.parse() { - Ok(n) => Some(n), - Err(_) => throw!("Invalid disc count"), - }, - }; - match tag.set_disc_info(new_disc_number, new_disc_count) { - Ok(()) => {} - // don't set tag at all if number is required - Err(SetInfoError::NumberRequired) => tag.set_disc_info(None, None)?, - Err(e) => Err(e)?, + value => Some(value.parse().context("Invalid disc count")?), }; + tag.set_disc_info(new_disc_number, new_disc_count); let new_bpm: Option = match new_info.bpm.as_ref() { "" => None, - value => match value.parse() { - Ok(n) => Some(n), - Err(_) => throw!("Invalid bpm"), - }, + value => Some(value.parse().context("Invalid bpm")?), }; match new_bpm { None => tag.remove_bpm(), diff --git a/src-native/tracks/mod.rs b/src-native/tracks/mod.rs index 37adb473..1b6e8628 100644 --- a/src-native/tracks/mod.rs +++ b/src-native/tracks/mod.rs @@ -2,7 +2,8 @@ use crate::data::Data; use crate::data_js::get_data; use crate::get_now_timestamp; use crate::library_types::{ItemId, MsSinceUnixEpoch, Track, TrackID, TRACK_ID_MAP}; -use napi::{Env, JsArrayBuffer, JsBuffer, JsObject, Result, Task}; +use anyhow::{anyhow, bail, Context, Result}; +use napi::{Env, JsArrayBuffer, JsBuffer, JsObject, Task}; use std::fs; use std::path::{Path, PathBuf}; @@ -102,7 +103,7 @@ pub fn add_skip(track_id: String, env: Env) -> Result<()> { pub fn add_play_time(id: TrackID, start: MsSinceUnixEpoch, dur_ms: i64, env: Env) -> Result<()> { let data: &mut Data = get_data(&env)?; let tracks = data.library.get_tracks(); - tracks.get(&id).ok_or(nerr!("Track ID not found"))?; + tracks.get(&id).context("Track ID not found")?; data.library.playTime.push((id, start, dur_ms)); Ok(()) } @@ -112,7 +113,7 @@ struct ReadCover(PathBuf, usize); impl Task for ReadCover { type Output = Vec; type JsValue = JsBuffer; - fn compute(&mut self) -> Result { + fn compute(&mut self) -> napi::Result { let path = &self.0; let index = self.1; @@ -120,20 +121,20 @@ impl Task for ReadCover { let image = match tag.get_image_consume(index)? { Some(image) => image, None => { - return Err(nerr!("No image")); + return Err(anyhow!("No image").into()); } }; Ok(image.data) } - fn resolve(&mut self, env: Env, output: Self::Output) -> Result { + fn resolve(&mut self, env: Env, output: Self::Output) -> napi::Result { let result = env.create_buffer_copy(output)?; return Ok(result.into_raw()); } } #[napi(js_name = "read_cover_async", ts_return_type = "Promise")] #[allow(dead_code)] -pub fn read_cover_async(track_id: String, index: u16, env: Env) -> Result { +pub fn read_cover_async(track_id: String, index: u16, env: Env) -> napi::Result { let data: &mut Data = get_data(&env)?; let track = id_to_track(&env, &track_id)?; let tracks_dir = &data.paths.tracks_dir; @@ -239,16 +240,12 @@ pub fn get_image(index: u32, env: Env) -> Result> { pub fn set_image(index: u32, path_str: String, env: Env) -> Result<()> { let data: &mut Data = get_data(&env)?; let path = data.paths.tracks_dir.join(path_str); - match &mut data.current_tag { - Some(tag) => { - let new_bytes = match fs::read(&path) { - Ok(b) => b, - Err(e) => throw!("Error reading that file: {}", e), - }; - tag.set_image(index as usize, new_bytes)?; - } - None => throw!("No tag loaded"), + let tag = match &mut data.current_tag { + Some(tag) => tag, + None => bail!("No tag loaded"), }; + let new_bytes = fs::read(&path).context("Error reading that file")?; + tag.set_image(index as usize, new_bytes)?; Ok(()) } @@ -257,10 +254,11 @@ pub fn set_image(index: u32, path_str: String, env: Env) -> Result<()> { pub fn set_image_data(index: u32, bytes: JsArrayBuffer, env: Env) -> Result<()> { let bytes: Vec = bytes.into_value()?.to_vec(); let data: &mut Data = get_data(&env)?; - match &mut data.current_tag { - Some(tag) => tag.set_image(index as usize, bytes)?, - None => throw!("No tag loaded"), + let tag = match &mut data.current_tag { + Some(tag) => tag, + None => bail!("No tag loaded"), }; + tag.set_image(index as usize, bytes)?; Ok(()) } @@ -285,7 +283,7 @@ pub fn update_track_info(track_id: String, info: md::TrackMD, env: Env) -> Resul let tag = match &mut data.current_tag { Some(tag) => tag, - None => throw!("No tag loaded"), + None => bail!("No tag loaded"), }; md::update_track_info(&data.paths.tracks_dir, track, tag, info)?; diff --git a/src-native/tracks/tag.rs b/src-native/tracks/tag.rs index f8ab6b4a..6c0755ae 100644 --- a/src-native/tracks/tag.rs +++ b/src-native/tracks/tag.rs @@ -1,33 +1,10 @@ -use crate::{UniError, UniResult}; +use anyhow::{bail, Context, Result}; use lofty::picture::{MimeType, Picture}; use lofty::tag::ItemKey; use lofty::{file::TaggedFileExt, tag::Accessor, tag::TagExt}; use std::io::Cursor; use std::path::{Path, PathBuf}; -pub enum SetInfoError { - NumberRequired, - Other(String), -} -impl ToString for SetInfoError { - fn to_string(self: &SetInfoError) -> String { - match self { - SetInfoError::NumberRequired => "Number required".to_string(), - SetInfoError::Other(s) => s.to_string(), - } - } -} -impl From for napi::Error { - fn from(err: SetInfoError) -> napi::Error { - napi::Error::from_reason(err.to_string()) - } -} -impl From for UniError { - fn from(err: SetInfoError) -> UniError { - err.to_string().into() - } -} - pub struct Image { pub data: Vec, } @@ -43,28 +20,22 @@ pub struct Tag { tag: lofty::tag::Tag, } impl Tag { - pub fn read_from_path(path: &PathBuf) -> UniResult { + pub fn read_from_path(path: &PathBuf) -> Result { if !path.exists() { - throw!("File does not exist: {}", path.to_string_lossy()); + bail!("File does not exist: {}", path.to_string_lossy()); } let ext = path.extension().unwrap_or_default().to_string_lossy(); let tag = match ext.as_ref() { "mp3" | "m4a" | "opus" => { - let probe = match lofty::probe::Probe::open(path) { - Ok(f) => { - let parse_options = lofty::config::ParseOptions::new() - .read_properties(false) - .parsing_mode(lofty::config::ParsingMode::Strict); - f.options(parse_options) - } - Err(e) => throw!("File does not exist: {}", e), - }; + let parse_options = lofty::config::ParseOptions::new() + .read_properties(false) + .parsing_mode(lofty::config::ParsingMode::Strict); + let probe = lofty::probe::Probe::open(path) + .context("File does not exist")? + .options(parse_options); - let mut tagged_file = match probe.read() { - Ok(f) => f, - Err(e) => throw!("Unable to read file: {}", e), - }; + let mut tagged_file = probe.read().context("Unable to read file")?; let tag = match tagged_file.remove(tagged_file.primary_tag_type()) { Some(t) => t.clone(), @@ -73,19 +44,14 @@ impl Tag { Tag { tag } } - _ => throw!("Unsupported file extension: {}", ext), + _ => bail!("Unsupported file extension: {}", ext), }; Ok(tag) } - pub fn write_to_path(&mut self, path: &Path) -> UniResult<()> { - match self - .tag + pub fn write_to_path(&mut self, path: &Path) -> Result<()> { + self.tag .save_to_path(path, lofty::config::WriteOptions::default()) - { - Ok(_) => {} - Err(e) => throw!("Unable to tag file: {}", e), - }; - Ok(()) + .context("Unable to tag file") } pub fn remove_title(&mut self) { self.tag.remove_title() @@ -143,13 +109,7 @@ impl Tag { let u = if value < 0 { 0 } else { value as u32 }; self.tag.set_year(u); } - /// For some tag types, `total` cannot exist without `number`. In those - /// cases, `total` is assumed to be `None`. - pub fn set_track_info( - &mut self, - number: Option, - total: Option, - ) -> Result<(), SetInfoError> { + pub fn set_track_info(&mut self, number: Option, total: Option) -> () { match number { Some(number) => self.tag.set_track(number), None => self.tag.remove_track(), @@ -158,16 +118,8 @@ impl Tag { Some(total) => self.tag.set_track_total(total), None => self.tag.remove_track_total(), } - - Ok(()) } - /// For some tag types, `total` cannot exist without `number`. In those - /// cases, `total` is assumed to be `None`. - pub fn set_disc_info( - &mut self, - number: Option, - total: Option, - ) -> Result<(), SetInfoError> { + pub fn set_disc_info(&mut self, number: Option, total: Option) -> () { match number { Some(number) => self.tag.set_disk(number), None => self.tag.remove_disk(), @@ -176,8 +128,6 @@ impl Tag { Some(total) => self.tag.set_disk_total(total), None => self.tag.remove_disk_total(), } - - Ok(()) } pub fn remove_bpm(&mut self) { self.tag.remove_key(&ItemKey::Bpm); @@ -195,22 +145,20 @@ impl Tag { pub fn set_comment(&mut self, value: &str) { self.tag.set_comment(value.to_string()) } - pub fn set_image(&mut self, index: usize, data: Vec) -> UniResult<()> { + pub fn set_image(&mut self, index: usize, data: Vec) -> Result<()> { let mut reader = Cursor::new(data); - let picture = match lofty::picture::Picture::from_reader(&mut reader) { - Ok(picture) => picture, - Err(e) => throw!("Unable to read picture: {}", e), - }; + let picture = + lofty::picture::Picture::from_reader(&mut reader).context("Unable to read picture")?; match picture.mime_type() { Some(lofty::picture::MimeType::Png | lofty::picture::MimeType::Jpeg) => { self.tag.set_picture(index, picture); } - _ => throw!("Unsupported picture type"), + _ => bail!("Unsupported picture type"), } Ok(()) } - pub fn get_image_ref(&self, index: usize) -> UniResult> { + pub fn get_image_ref(&self, index: usize) -> Result> { let pictures = self.tag.pictures(); match pictures.get(index) { Some(pic) => { @@ -219,16 +167,13 @@ impl Tag { index: index.try_into().expect("usize conv"), total_images: pictures.len().try_into().expect("usize conv"), data, - mime_type: match pic.mime_type() { - Some(mime_type) => mime_type.clone(), - _ => throw!("No mime type"), - }, + mime_type: pic.mime_type().context("No mime type")?.clone(), })) } None => Ok(None), } } - pub fn get_image_consume(mut self, index: usize) -> UniResult> { + pub fn get_image_consume(mut self, index: usize) -> Result> { if self.tag.picture_count() <= index.try_into().expect("usize conv") { return Ok(None); } diff --git a/src-native/view_options.rs b/src-native/view_options.rs index fc4d5582..5513267e 100644 --- a/src-native/view_options.rs +++ b/src-native/view_options.rs @@ -1,10 +1,11 @@ use crate::data::Data; use crate::data_js::get_data; use crate::library::Paths; -use crate::{path_to_json, UniResult}; +use crate::path_to_json; +use anyhow::{Context, Result}; use atomicwrites::AtomicFile; use atomicwrites::OverwriteBehavior::AllowOverwrite; -use napi::{Env, Result}; +use napi::Env; use serde::{Deserialize, Serialize}; use std::io::Write; @@ -25,18 +26,12 @@ impl ViewOptions { }, } } - pub fn save(&self, paths: &Paths) -> UniResult<()> { - let json_str = match serde_json::to_string(self) { - Ok(json_str) => json_str, - Err(_) => throw!("Error saving view.json"), - }; + pub fn save(&self, paths: &Paths) -> Result<()> { + let json_str = serde_json::to_string(self).context("Error saving view.json")?; let file_path = paths.local_data_dir.join("view.json"); let af = AtomicFile::new(file_path, AllowOverwrite); - let result = af.write(|f| f.write_all(json_str.as_bytes())); - match result { - Ok(_) => {} - Err(_) => throw!("Error writing view.json"), - }; + af.write(|f| f.write_all(json_str.as_bytes())) + .context("Error writing view.json")?; Ok(()) } }