Skip to main content

autopulse_service/settings/targets/
tdarr.rs

1use crate::settings::path_filter::PathFilter;
2use crate::settings::rewrite::Rewrite;
3use crate::settings::targets::TargetProcess;
4use autopulse_database::models::ScanEvent;
5use autopulse_utils::get_url;
6use serde::{Deserialize, Serialize};
7
8use super::{Request, RequestBuilderPerform};
9
10#[derive(Serialize, Deserialize, Clone)]
11pub struct Tdarr {
12    /// URL to the Tdarr server
13    pub url: String,
14    /// Library ID for the Tdarr server
15    pub db_id: String,
16    /// Rewrite path for the file
17    pub rewrite: Option<Rewrite>,
18    /// Path filter matched against the target-rewritten path.
19    #[serde(default)]
20    pub filter: PathFilter,
21    /// HTTP request options
22    #[serde(default)]
23    pub request: Request,
24}
25
26#[derive(Serialize)]
27#[serde(rename_all = "camelCase")]
28#[doc(hidden)]
29struct ScanConfig {
30    #[serde(rename = "dbID")]
31    db_id: String,
32    array_or_path: Vec<String>,
33    mode: String,
34}
35
36#[derive(Serialize)]
37#[serde(rename_all = "camelCase")]
38#[doc(hidden)]
39struct Data {
40    scan_config: ScanConfig,
41}
42
43#[derive(Serialize)]
44#[serde(rename_all = "camelCase")]
45#[doc(hidden)]
46struct Payload {
47    data: Data,
48}
49
50impl Tdarr {
51    fn get_client(&self) -> anyhow::Result<reqwest::Client> {
52        self.request
53            .client_builder(reqwest::header::HeaderMap::new())
54            .build()
55            .map_err(Into::into)
56    }
57
58    async fn scan(&self, evs: &[&ScanEvent]) -> anyhow::Result<()> {
59        let client = self.get_client()?;
60
61        let payload = Payload {
62            data: Data {
63                scan_config: ScanConfig {
64                    db_id: self.db_id.clone(),
65                    array_or_path: evs.iter().map(|ev| ev.get_path(&self.rewrite)).collect(),
66                    mode: "scanFolderWatcher".to_string(),
67                },
68            },
69        };
70
71        let url = get_url(&self.url)?.join("/api/v2/scan-files")?;
72
73        client
74            .post(url)
75            .header("content-type", "application/json")
76            .json(&payload)
77            .perform()
78            .await
79            .map(|_| ())
80    }
81}
82
83impl TargetProcess for Tdarr {
84    async fn process(&self, evs: &[&ScanEvent]) -> anyhow::Result<Vec<String>> {
85        let mut succeeded = Vec::new();
86
87        self.scan(evs).await?;
88
89        succeeded.extend(evs.iter().map(|ev| ev.id.clone()));
90
91        Ok(succeeded)
92    }
93}