autopulse_service/settings/targets/
tdarr.rs

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