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 reqwest::header;
6use serde::{Deserialize, Serialize};
7
8use super::RequestBuilderPerform;
9
10#[derive(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}
19
20#[derive(Serialize)]
21#[serde(rename_all = "camelCase")]
22#[doc(hidden)]
23struct ScanConfig {
24    #[serde(rename = "dbID")]
25    db_id: String,
26    array_or_path: Vec<String>,
27    mode: String,
28}
29
30#[derive(Serialize)]
31#[serde(rename_all = "camelCase")]
32#[doc(hidden)]
33struct Data {
34    scan_config: ScanConfig,
35}
36
37#[derive(Serialize)]
38#[serde(rename_all = "camelCase")]
39#[doc(hidden)]
40struct Payload {
41    data: Data,
42}
43
44impl Tdarr {
45    fn get_client(&self) -> anyhow::Result<reqwest::Client> {
46        let headers = header::HeaderMap::new();
47
48        reqwest::Client::builder()
49            .timeout(std::time::Duration::from_secs(10))
50            .default_headers(headers)
51            .build()
52            .map_err(Into::into)
53    }
54
55    async fn scan(&self, evs: &[&ScanEvent]) -> anyhow::Result<()> {
56        let client = self.get_client()?;
57
58        let payload = Payload {
59            data: Data {
60                scan_config: ScanConfig {
61                    db_id: self.db_id.clone(),
62                    array_or_path: evs.iter().map(|ev| ev.get_path(&self.rewrite)).collect(),
63                    mode: "scanFolderWatcher".to_string(),
64                },
65            },
66        };
67
68        let url = get_url(&self.url)?.join("/api/v2/scan-files")?;
69
70        client
71            .post(url)
72            .header("content-type", "application/json")
73            .json(&payload)
74            .perform()
75            .await
76            .map(|_| ())
77    }
78}
79
80impl TargetProcess for Tdarr {
81    async fn process(&self, evs: &[&ScanEvent]) -> anyhow::Result<Vec<String>> {
82        let mut succeeded = Vec::new();
83
84        self.scan(evs).await?;
85
86        succeeded.extend(evs.iter().map(|ev| ev.id.clone()));
87
88        Ok(succeeded)
89    }
90}