1use std::ops::Deref;
2use std::path::{Path, PathBuf};
3use tracing::info;
4
5use crate::config::{Config, ConfigError};
6
7#[derive(Clone, Debug)]
12pub struct LibraryDir {
13 path: PathBuf,
14}
15
16impl LibraryDir {
17 pub fn new(path: impl Into<PathBuf>) -> Self {
18 Self { path: path.into() }
19 }
20
21 pub fn db_path(&self) -> PathBuf {
22 self.path.join("library.db")
23 }
24
25 pub fn config_path(&self) -> PathBuf {
26 self.path.join("config.yaml")
27 }
28
29 pub fn images_dir(&self) -> PathBuf {
30 self.path.join("images")
31 }
32
33 pub fn hashed_path(prefix: &str, id: &str) -> String {
37 let hex = id.replace('-', "");
38 format!("{prefix}/{}/{}/{id}", &hex[..2], &hex[2..4])
39 }
40
41 pub fn image_path(&self, id: &str) -> PathBuf {
43 self.path.join(Self::hashed_path("images", id))
44 }
45
46 pub fn torrents_dir(&self) -> PathBuf {
47 self.path.join("torrents")
48 }
49
50 pub fn torrent_file_path(&self, torrent_id: &str) -> PathBuf {
52 self.path.join(Self::hashed_path("torrents", torrent_id))
53 }
54
55 pub fn storage_dir(&self) -> PathBuf {
56 self.path.join("storage")
57 }
58
59 pub fn storage_file_path(&self, file_id: &str) -> PathBuf {
61 self.path.join(Self::hashed_path("storage", file_id))
62 }
63
64 pub fn pending_deletions_path(&self) -> PathBuf {
65 self.path.join("pending_deletions.json")
66 }
67
68 pub fn playback_state_path(&self) -> PathBuf {
69 self.path.join("playback_state.json")
70 }
71
72 pub fn asset_dirs(&self) -> Vec<PathBuf> {
74 vec![self.images_dir(), self.storage_dir(), self.torrents_dir()]
75 }
76
77 pub fn create(
82 bae_dir: &Path,
83 library_id: String,
84 library_name: String,
85 ids: &dyn crate::id_provider::IdProvider,
86 ) -> Result<Config, ConfigError> {
87 let library_dir = LibraryDir::new(bae_dir.join("libraries").join(&library_id));
88 std::fs::create_dir_all(&*library_dir)?;
89
90 let device_id = ids.new_id();
91 let config = Config::with_defaults(library_id, device_id, library_dir, library_name);
92 config.save_to_config_yaml()?;
93
94 info!("Created library at {}", config.library_dir.display());
95 Ok(config)
96 }
97}
98
99impl Deref for LibraryDir {
100 type Target = Path;
101
102 fn deref(&self) -> &Path {
103 &self.path
104 }
105}
106
107impl AsRef<Path> for LibraryDir {
108 fn as_ref(&self) -> &Path {
109 &self.path
110 }
111}
112
113impl From<PathBuf> for LibraryDir {
114 fn from(path: PathBuf) -> Self {
115 Self { path }
116 }
117}