caesura/utils/fs/
path_manager.rs

1use std::fs::create_dir;
2use std::path::PathBuf;
3
4use di::{Ref, injectable};
5use rogue_logging::Error;
6
7use crate::dependencies::*;
8use crate::options::*;
9use crate::utils::*;
10#[injectable]
11pub struct PathManager {
12    shared_options: Ref<SharedOptions>,
13    cache_options: Ref<CacheOptions>,
14}
15
16impl PathManager {
17    #[must_use]
18    pub fn get_cache_dir(&self) -> PathBuf {
19        self.cache_options
20            .cache
21            .clone()
22            .expect("cache should be set")
23    }
24
25    #[must_use]
26    pub fn get_source_torrent_path(&self, source: &Source) -> PathBuf {
27        let id = source.torrent.id;
28        let indexer = self
29            .shared_options
30            .indexer
31            .clone()
32            .expect("indexer should be set");
33        let torrents_dir = self.get_cache_dir().join("torrents");
34        if !torrents_dir.is_dir() {
35            let _ = create_dir(&torrents_dir);
36        }
37        torrents_dir.join(format!("{id}.{indexer}.torrent"))
38    }
39
40    #[must_use]
41    pub fn get_output_dir(&self) -> PathBuf {
42        self.shared_options
43            .output
44            .clone()
45            .expect("output should be set")
46    }
47
48    #[must_use]
49    pub fn get_spectrogram_dir(&self, source: &Source) -> PathBuf {
50        self.get_output_dir()
51            .join(SpectrogramName::get(&source.metadata))
52    }
53
54    #[must_use]
55    pub fn get_transcode_target_dir(&self, source: &Source, target: TargetFormat) -> PathBuf {
56        self.get_output_dir()
57            .join(TranscodeName::get(&source.metadata, target))
58    }
59
60    #[must_use]
61    pub fn get_transcode_path(
62        &self,
63        source: &Source,
64        target: TargetFormat,
65        flac: &FlacFile,
66    ) -> PathBuf {
67        let extension = target.get_file_extension();
68        let filename = flac.file_name.clone() + "." + extension.as_str();
69        let sub_path = flac.sub_dir.join(filename);
70        self.get_transcode_target_dir(source, target).join(sub_path)
71    }
72
73    #[must_use]
74    pub fn get_torrent_path(
75        &self,
76        source: &Source,
77        target: TargetFormat,
78        include_indexer: bool,
79    ) -> PathBuf {
80        let mut filename = TranscodeName::get(&source.metadata, target);
81        if include_indexer {
82            let indexer = self
83                .shared_options
84                .indexer
85                .clone()
86                .expect("indexer should be set");
87            filename.push('.');
88            filename.push_str(&indexer);
89        }
90        filename.push_str(".torrent");
91        self.get_output_dir().join(filename)
92    }
93
94    /// Get the *torrent path with suffix* if it exists.
95    ///
96    /// Example `path/to/Artist - Album [2012] [WEB FLAC].abc.torrent`
97    ///
98    /// Returns `None` if the path does not exist or an existing torrent can't be copied or
99    /// re-created with the indexer suffix.
100    ///
101    /// Returns the *torrent path with suffix* if it already exists.
102    ///
103    /// Or attempt to copy or re-create from an existing torrent file
104    /// (`path/to/Artist - Album [2012] [WEB FLAC].torrent`).
105    ///
106    /// Returns the *torrent path with suffix* if duplication is successful, else `None`
107    pub async fn get_or_duplicate_existing_torrent_path(
108        &self,
109        source: &Source,
110        target: TargetFormat,
111    ) -> Result<Option<PathBuf>, Error> {
112        let path_with_indexer = self.get_torrent_path(source, target, true);
113        if path_with_indexer.is_file() {
114            return Ok(Some(path_with_indexer));
115        }
116        let path_without_indexer = self.get_torrent_path(source, target, false);
117        if !path_without_indexer.is_file() {
118            return Ok(None);
119        }
120        let transcode_dir = self.get_transcode_target_dir(source, target);
121        let announce_url = self
122            .shared_options
123            .announce_url
124            .clone()
125            .expect("announce should be set");
126        let indexer = self
127            .shared_options
128            .indexer
129            .clone()
130            .expect("indexer should be set")
131            .to_lowercase();
132        let success = ImdlCommand::duplicate_torrent(
133            &path_without_indexer,
134            &path_with_indexer,
135            &transcode_dir,
136            announce_url,
137            indexer,
138        )
139        .await?;
140        if success {
141            Ok(Some(path_with_indexer))
142        } else {
143            Ok(None)
144        }
145    }
146}