autopulse_service/settings/targets/
tdarr.rs1use 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 pub url: String,
14 pub db_id: String,
16 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}