Skip to content

Commit ac7de35

Browse files
Refactor Paths
Store `Strings` instead of `PathBuf`s, add `view_options_file` prop, and use the paths struct in more places
1 parent 28b0009 commit ac7de35

File tree

13 files changed

+78
-91
lines changed

13 files changed

+78
-91
lines changed

ferrum-addon/addon.d.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/* eslint-disable */
33
export declare class ItunesImport {
44
static new(): ItunesImport
5-
start(path: string, tracksDir: string): Promise<ImportStatus>
5+
start(path: string): Promise<ImportStatus>
66
finish(): void
77
}
88

@@ -53,7 +53,7 @@ export declare function get_genres(): Array<string>
5353

5454
export declare function get_image(index: number): JsImage | null
5555

56-
export declare function get_paths(): PathsJs
56+
export declare function get_paths(): Paths
5757

5858
export declare function get_track(id: string): Track
5959

@@ -99,13 +99,15 @@ export declare function move_tracks(playlistId: string, itemIds: Array<ItemId>,
9999

100100
export declare function new_playlist(name: string, description: string, isFolder: boolean, parentId: string): void
101101

102-
export interface PathsJs {
102+
export interface Paths {
103+
pathSeparator: string
103104
libraryDir: string
104105
tracksDir: string
105106
libraryJson: string
107+
cacheDir: string
106108
cacheDb: string
107109
localDataDir: string
108-
pathSeparator: string
110+
viewOptionsFile: string
109111
}
110112

111113
export interface Playlist {

src-native/data.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,16 @@ use dirs_next;
77
use serde::Serialize;
88
use std::env;
99
use std::io::Write;
10-
use std::path::PathBuf;
10+
use std::path::{Path, PathBuf};
1111
use std::time::Instant;
1212

13+
pub fn path_to_string<P: AsRef<Path>>(path: P) -> String {
14+
path.as_ref()
15+
.to_str()
16+
.expect("Invalid path str")
17+
.to_string()
18+
}
19+
1320
pub struct Data {
1421
pub paths: Paths,
1522
pub library: Library,
@@ -62,19 +69,22 @@ impl Data {
6269
.context("Local data folder not found")?
6370
.join("space.kasper.ferrum");
6471
};
72+
let local_data_dir = match local_data_path {
73+
Some(path) => PathBuf::from(path),
74+
None => local_data_dir,
75+
};
6576
if let Some(library_path) = library_path {
6677
library_dir = PathBuf::from(library_path);
6778
}
6879
let paths = Paths {
69-
library_dir: library_dir.clone(),
70-
tracks_dir: library_dir.join("Tracks"),
71-
library_json: library_dir.join("Library.json"),
72-
cache_dir: cache_dir.clone(),
73-
cache_db: cache_dir.join("Cache.redb"),
74-
local_data_dir: match local_data_path {
75-
Some(path) => PathBuf::from(path),
76-
None => local_data_dir,
77-
},
80+
path_separator: std::path::MAIN_SEPARATOR_STR.into(),
81+
library_dir: path_to_string(&library_dir),
82+
tracks_dir: path_to_string(library_dir.join("Tracks")),
83+
library_json: path_to_string(library_dir.join("Library.json")),
84+
cache_dir: path_to_string(&cache_dir),
85+
cache_db: path_to_string(cache_dir.join("Cache.redb")),
86+
local_data_dir: path_to_string(&local_data_dir),
87+
view_options_file: path_to_string(local_data_dir.join("view.json")),
7888
};
7989

8090
let loaded_library = load_library(&paths)?;

src-native/data_js.rs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::FerrumStatus;
22
use crate::data::Data;
3+
use crate::library::Paths;
34
use anyhow::Result;
45
use napi::Env;
56
use rfd::MessageDialog;
@@ -56,28 +57,11 @@ pub fn load_data(
5657
return Ok(());
5758
}
5859

59-
#[napi(object)]
60-
pub struct PathsJs {
61-
pub library_dir: String,
62-
pub tracks_dir: String,
63-
pub library_json: String,
64-
pub cache_db: String,
65-
pub local_data_dir: String,
66-
pub path_separator: String,
67-
}
68-
6960
#[napi(js_name = "get_paths")]
7061
#[allow(dead_code)]
71-
pub fn get_paths(env: Env) -> PathsJs {
72-
let data: &mut Data = get_data(&env);
73-
PathsJs {
74-
library_dir: data.paths.library_dir.to_string_lossy().into(),
75-
tracks_dir: data.paths.tracks_dir.to_string_lossy().into(),
76-
library_json: data.paths.library_json.to_string_lossy().into(),
77-
cache_db: data.paths.cache_db.to_string_lossy().into(),
78-
local_data_dir: data.paths.local_data_dir.to_string_lossy().into(),
79-
path_separator: std::path::MAIN_SEPARATOR_STR.into(),
80-
}
62+
pub fn get_paths(env: Env) -> Paths {
63+
let data: &Data = get_data(&env);
64+
data.paths.clone()
8165
}
8266

8367
#[napi(js_name = "save")]

src-native/itunes_import.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::data_js::get_data;
22
use crate::get_now_timestamp;
3+
use crate::library::Paths;
34
use crate::library_types::{
45
CountObject, Folder, Library, Playlist, Track, TrackList, new_item_ids_from_track_ids,
56
};
@@ -11,7 +12,7 @@ use napi::Env;
1112
use serde::{Deserialize, Serialize};
1213
use std::collections::HashMap;
1314
use std::fs;
14-
use std::path::{Path, PathBuf};
15+
use std::path::PathBuf;
1516
use std::sync::Mutex;
1617
use time::OffsetDateTime;
1718
use time::serde::iso8601;
@@ -319,11 +320,7 @@ fn parse_file_url(value: &str) -> Result<PathBuf> {
319320
}
320321

321322
/// Parses track but does not move it to `tracks_dir`
322-
fn parse_track(
323-
xml_track: XmlTrack,
324-
start_time: i64,
325-
tracks_dir: &Path,
326-
) -> Result<(PathBuf, Track)> {
323+
fn parse_track(xml_track: XmlTrack, start_time: i64, paths: &Paths) -> Result<(PathBuf, Track)> {
327324
let xml_location = xml_track.location.context("Missing track location")?;
328325
if xml_track.track_type != Some("File".to_string()) {
329326
bail!(
@@ -358,7 +355,7 @@ fn parse_track(
358355

359356
let name = xml_track.name.unwrap_or_default();
360357
let artist = xml_track.artist.unwrap_or_default();
361-
let filename = generate_filename(tracks_dir, &artist, &name, file_type.file_extension());
358+
let filename = generate_filename(&paths, &artist, &name, file_type.file_extension());
362359

363360
let track = Track {
364361
size: file_md.len() as i64,
@@ -584,6 +581,7 @@ pub struct ItunesImport {
584581
new_library: Mutex<Option<Library>>,
585582
/// iTunes path -> Ferrum file
586583
itunes_track_paths: Mutex<HashMap<PathBuf, String>>,
584+
paths: Paths,
587585
}
588586
#[napi]
589587
impl ItunesImport {
@@ -593,18 +591,19 @@ impl ItunesImport {
593591
Ok(Self {
594592
new_library: Some(data.library.clone()).into(),
595593
itunes_track_paths: HashMap::new().into(),
594+
paths: data.paths.clone(),
596595
})
597596
}
598597
#[napi]
599-
pub async fn start(&self, path: String, tracks_dir: String) -> napi::Result<ImportStatus> {
600-
Ok(import_itunes(self, path, tracks_dir).await?)
598+
pub async fn start(&self, path: String) -> napi::Result<ImportStatus> {
599+
Ok(import_itunes(self, path).await?)
601600
}
602601
#[napi]
603602
pub fn finish(&mut self, env: Env) -> napi::Result<()> {
604603
let data = get_data(&env);
605604
let itunes_track_paths = &mut *self.itunes_track_paths.lock().unwrap();
606605
for (itunes_path, ferrum_file) in itunes_track_paths {
607-
let new_path = data.paths.tracks_dir.join(ferrum_file);
606+
let new_path = data.paths.get_track_file_path(ferrum_file);
608607
fs::copy(itunes_path, new_path).context("Error copying file")?;
609608
}
610609
let new_library = &mut self.new_library.lock().unwrap();
@@ -613,11 +612,7 @@ impl ItunesImport {
613612
}
614613
}
615614

616-
pub async fn import_itunes(
617-
itunes_import: &ItunesImport,
618-
path: String,
619-
tracks_dir: String,
620-
) -> Result<ImportStatus> {
615+
async fn import_itunes(itunes_import: &ItunesImport, path: String) -> Result<ImportStatus> {
621616
let new_library_lock = &mut *itunes_import.new_library.lock().unwrap();
622617
let mut library = match new_library_lock {
623618
Some(library) => library,
@@ -663,7 +658,7 @@ pub async fn import_itunes(
663658
errors.push(format!("Missing track artist: {artist_title}"));
664659
}
665660

666-
match parse_track(xml_track, start_time, Path::new(&tracks_dir)) {
661+
match parse_track(xml_track, start_time, &itunes_import.paths) {
667662
Ok((xml_track_path, track)) => {
668663
let generated_id = library.generate_id();
669664
// immediately insert into library so new generated ids are unique

src-native/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use anyhow::{Context, Result};
22
use serde::de::DeserializeOwned;
33
use std::fs::File;
44
use std::io::BufReader;
5-
use std::path::PathBuf;
65
use std::time::{SystemTime, UNIX_EPOCH};
76

87
#[macro_use]
@@ -58,7 +57,7 @@ fn str_to_option(s: String) -> Option<String> {
5857
}
5958
}
6059

61-
fn path_to_json<J>(path: PathBuf) -> Result<J>
60+
fn path_to_json<J>(path: &str) -> Result<J>
6261
where
6362
J: DeserializeOwned,
6463
{

src-native/library.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,23 @@ use crate::data_js::get_data;
33
use crate::library_types::{Library, VersionedLibrary};
44
use anyhow::{Context, Result, bail};
55
use napi::Env;
6-
use serde::{Deserialize, Serialize};
76
use serde_json::{Value, json};
87
use std::fs::{File, create_dir_all};
98
use std::io::{ErrorKind, Read};
109
use std::path::PathBuf;
1110
use std::time::Instant;
1211

13-
#[derive(Serialize, Deserialize)]
12+
#[derive(Clone)]
13+
#[napi(object)]
1414
pub struct Paths {
15-
pub library_dir: PathBuf,
16-
pub tracks_dir: PathBuf,
17-
pub library_json: PathBuf,
18-
pub cache_dir: PathBuf,
19-
pub cache_db: PathBuf,
20-
pub local_data_dir: PathBuf,
15+
pub path_separator: String,
16+
pub library_dir: String,
17+
pub tracks_dir: String,
18+
pub library_json: String,
19+
pub cache_dir: String,
20+
pub cache_db: String,
21+
pub local_data_dir: String,
22+
pub view_options_file: String,
2123
}
2224
impl Paths {
2325
fn ensure_dirs_exists(&self) -> Result<()> {
@@ -27,6 +29,9 @@ impl Paths {
2729
create_dir_all(&self.cache_dir)?;
2830
return Ok(());
2931
}
32+
pub fn get_track_file_path(&self, file: &str) -> PathBuf {
33+
PathBuf::from(&self.tracks_dir).join(file)
34+
}
3035
}
3136

3237
pub fn load_library(paths: &Paths) -> Result<Library> {
@@ -35,10 +40,7 @@ pub fn load_library(paths: &Paths) -> Result<Library> {
3540
paths
3641
.ensure_dirs_exists()
3742
.context("Error ensuring folder exists")?;
38-
println!(
39-
"Loading library at path: {}",
40-
paths.library_dir.to_string_lossy()
41-
);
43+
println!("Loading library at path: {}", paths.library_dir);
4244

4345
let mut library_file = match File::open(&paths.library_json) {
4446
Ok(file) => file,

src-native/library_types.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![allow(non_snake_case)]
22

3+
use crate::library::Paths;
34
use crate::playlists::{delete_file, remove_from_all_playlists};
45
use crate::{FerrumStatus, get_now_timestamp};
56
use anyhow::{Context, Result, bail};
@@ -8,7 +9,6 @@ use nanoid::nanoid;
89
use serde::{Deserialize, Serialize};
910
use std::borrow::Cow;
1011
use std::collections::HashSet;
11-
use std::path::PathBuf;
1212
use std::sync::RwLock;
1313
use std::time::Instant;
1414

@@ -138,14 +138,10 @@ impl Library {
138138
track_id_map.push(id.clone());
139139
self.track_item_ids.insert(id, item_id);
140140
}
141-
pub fn delete_track_and_file(
142-
&mut self,
143-
id: &TrackID,
144-
tracks_dir: &PathBuf,
145-
) -> Result<FerrumStatus> {
141+
pub fn delete_track_and_file(&mut self, id: &TrackID, paths: &Paths) -> Result<FerrumStatus> {
146142
let file_path = {
147143
let track = self.get_track(id)?;
148-
tracks_dir.join(&track.file)
144+
paths.get_track_file_path(&track.file)
149145
};
150146
if !file_path.exists() {
151147
return Ok(FerrumStatus::FileDeletionError(format!(

src-native/playlists.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ pub fn delete_tracks_with_item_ids(item_ids: Vec<ItemId>, env: Env) -> Result<Fe
221221
let library = &mut data.library;
222222
let track_ids = get_track_ids_from_item_ids(&item_ids);
223223
for track_id in &track_ids {
224-
let status = library.delete_track_and_file(track_id, &data.paths.tracks_dir)?;
224+
let status = library.delete_track_and_file(track_id, &data.paths)?;
225225
if status.is_err() {
226226
return Ok(status);
227227
}

src-native/tracks/import.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::data::Data;
22
use crate::library_types::Track;
33
use crate::sys_time_to_timestamp;
44
use crate::tracks::generate_filename;
5-
use anyhow::{bail, Context, Result};
5+
use anyhow::{Context, Result, bail};
66
use lofty::file::{AudioFile, TaggedFileExt};
77
use lofty::tag::{Accessor, ItemKey, TagExt};
88
use std::fs;
@@ -94,14 +94,13 @@ pub fn import(data: &Data, track_path: &Path, now: i64) -> Result<Track> {
9494
};
9595
let artist = tag.artist().map(|s| s.into_owned()).unwrap_or_default();
9696

97-
let tracks_dir = &data.paths.tracks_dir;
9897
let extension = match FileType::from_path(track_path)? {
9998
FileType::Opus => "opus",
10099
FileType::M4a => "m4a",
101100
FileType::Mp3 => "mp3",
102101
};
103-
let filename = generate_filename(tracks_dir, &artist, &title, extension);
104-
let dest_path = tracks_dir.join(&filename);
102+
let filename = generate_filename(&data.paths, &artist, &title, extension);
103+
let dest_path = data.paths.get_track_file_path(&filename);
105104

106105
fs::copy(track_path, &dest_path).context("Error copying file")?;
107106
println!(

src-native/tracks/md.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#![allow(non_snake_case)]
22

33
use super::{Tag, generate_filename};
4+
use crate::library::Paths;
45
use crate::library_types::Track;
56
use crate::{get_now_timestamp, str_to_option};
67
use anyhow::{Context, Result, bail};
78
use serde::{Deserialize, Serialize};
89
use std::fs;
9-
use std::path::PathBuf;
1010

1111
#[derive(Serialize, Deserialize, Debug)]
1212
#[napi(object)]
@@ -32,12 +32,12 @@ pub struct TrackMD {
3232
}
3333

3434
pub fn update_track_info(
35-
tracks_dir: &PathBuf,
35+
paths: &Paths,
3636
track: &mut Track,
3737
tag: &mut Tag,
3838
new_info: TrackMD,
3939
) -> Result<()> {
40-
let old_path = tracks_dir.join(&track.file);
40+
let old_path = paths.get_track_file_path(&track.file);
4141
if !old_path.exists() {
4242
bail!("File does not exist: {}", track.file);
4343
}
@@ -146,8 +146,8 @@ pub fn update_track_info(
146146

147147
// move file
148148
if new_name != track.name || new_artist != track.artist {
149-
let new_filename = generate_filename(tracks_dir, &new_artist, &new_name, &ext);
150-
let new_path = tracks_dir.join(&new_filename);
149+
let new_filename = generate_filename(&paths, &new_artist, &new_name, &ext);
150+
let new_path = paths.get_track_file_path(&new_filename);
151151
match fs::rename(old_path, new_path) {
152152
Ok(_) => {
153153
track.file = new_filename;

0 commit comments

Comments
 (0)