autopulse_service/settings/triggers/mod.rs
1/// Lidarr - Lidarr trigger
2///
3/// This trigger is used to process a file from Lidarr
4///
5/// # Example
6///
7/// ```yml
8/// triggers:
9/// my_lidarr:
10/// type: lidarr
11/// ```
12///
13/// or
14///
15/// ```yml
16/// triggers:
17/// my_lidarr:
18/// type: lidarr
19/// rewrite:
20/// from: "/downloads/music"
21/// to: "/music"
22/// timer:
23/// wait: 30
24/// excludes: [ "ignored_target" ]
25/// ```
26///
27/// See [`Lidarr`] for all options
28pub mod lidarr;
29/// Manual - Manual trigger
30///
31/// This trigger is used to manually process a file. Often used when implementing a custom trigger
32///
33/// Note: A default route of `/triggers/manual` is provided
34///
35/// # Example
36///
37/// ```yml
38/// triggers:
39/// my_manual:
40/// type: manual
41/// ```
42///
43/// or
44///
45/// ```yml
46/// triggers:
47/// my_manual:
48/// type: manual
49/// rewrite:
50/// from: "/downloads/stuff"
51/// to: "/stuff"
52/// timer:
53/// wait: 30
54/// excludes: [ "ignored_target" ]
55/// ```
56///
57/// See [`Manual`] for all options
58/// and
59/// [`ManualQueryParams`](manual::ManualQueryParams) for query parameters
60pub mod manual;
61/// Notify - Notify trigger
62///
63/// Cross-platform monitoring for a directory to process based on file events
64///
65/// # Example
66///
67/// ```yml
68/// triggers:
69/// my_notify:
70/// type: notify
71/// paths:
72/// - "/path/to/monitor"
73/// ```
74///
75/// or
76///
77/// ```yml
78/// triggers:
79/// my_notify:
80/// type: notify
81/// paths:
82/// - "/downloads"
83/// recursive: false
84/// rewrite:
85/// from: "/downloads"
86/// to: "/media"
87/// timer:
88/// wait: 30
89/// excludes: [ "ignored_target" ]
90/// ```
91///
92/// See [`Notify`] for all options
93pub mod notify;
94/// Radarr - Radarr trigger
95///
96/// This trigger is used to process a file from Radarr
97///
98/// # Example
99///
100/// ```yml
101/// triggers:
102/// my_radarr:
103/// type: radarr
104/// ```
105///
106/// or
107///
108/// ```yml
109/// triggers:
110/// my_radarr:
111/// type: radarr
112/// rewrite:
113/// from: "/downloads/movies"
114/// to: "/movies"
115/// timer:
116/// wait: 30
117/// excludes: [ "ignored_target" ]
118/// ```
119///
120/// See [`Radarr`] for all options
121pub mod radarr;
122/// Readarr - Readarr trigger
123///
124/// This trigger is used to process a file from Readarr
125///
126/// # Example
127///
128/// ```yml
129/// triggers:
130/// my_readarr:
131/// type: readarr
132/// ```
133///
134/// or
135///
136/// ```yml
137/// triggers:
138/// my_readarr:
139/// type: readarr
140/// rewrite:
141/// from: "/downloads/books"
142/// to: "/books"
143/// timer:
144/// wait: 30
145/// excludes: [ "ignored_target" ]
146/// ```
147///
148/// See [`Readarr`] for all options
149pub mod readarr;
150/// Sonarr - Sonarr trigger
151///
152/// This trigger is used to process a file from Sonarr
153///
154/// # Example
155///
156/// ```yml
157/// triggers:
158/// my_sonarr:
159/// type: sonarr
160/// ```
161///
162/// or
163///
164/// ```yml
165/// triggers:
166/// my_sonarr:
167/// type: sonarr
168/// rewrite:
169/// from: "/downloads/shows"
170/// to: "/shows"
171/// timer:
172/// wait: 30
173/// excludes: [ "ignored_target" ]
174/// ```
175///
176/// See [`Sonarr`] for all options
177pub mod sonarr;
178
179use crate::settings::rewrite::Rewrite;
180use crate::settings::timer::Timer;
181use serde::Deserialize;
182use {
183 lidarr::{Lidarr, LidarrRequest},
184 manual::Manual,
185 notify::Notify,
186 radarr::{Radarr, RadarrRequest},
187 readarr::{Readarr, ReadarrRequest},
188 sonarr::{Sonarr, SonarrRequest},
189};
190
191pub trait TriggerRequest {
192 fn from_json(json: serde_json::Value) -> anyhow::Result<Self>
193 where
194 Self: Sized;
195
196 // where the bool represents whether to check found status
197 fn paths(&self) -> Vec<(String, bool)>;
198}
199
200#[derive(Deserialize, Clone)]
201#[serde(tag = "type", rename_all = "lowercase")]
202pub enum Trigger {
203 Manual(Manual),
204 Radarr(Radarr),
205 Sonarr(Sonarr),
206 Lidarr(Lidarr),
207 Readarr(Readarr),
208 Notify(Notify),
209}
210
211impl Trigger {
212 pub const fn get_rewrite(&self) -> Option<&Rewrite> {
213 match &self {
214 Self::Sonarr(trigger) => trigger.rewrite.as_ref(),
215 Self::Radarr(trigger) => trigger.rewrite.as_ref(),
216 Self::Lidarr(trigger) => trigger.rewrite.as_ref(),
217 Self::Readarr(trigger) => trigger.rewrite.as_ref(),
218 Self::Manual(_) | Self::Notify(_) => None,
219 }
220 }
221
222 pub fn get_timer(&self, event_name: Option<String>) -> Timer {
223 let mut base_timer = match self.clone() {
224 Self::Sonarr(trigger) => trigger.timer,
225 Self::Radarr(trigger) => trigger.timer,
226 Self::Lidarr(trigger) => trigger.timer,
227 Self::Readarr(trigger) => trigger.timer,
228 Self::Manual(trigger) => trigger.timer,
229 Self::Notify(trigger) => trigger.timer,
230 };
231
232 let event_specific_timer = match &self {
233 Self::Sonarr(trigger) => event_name
234 .as_ref()
235 .and_then(|event| trigger.event_timers.get(event)),
236 Self::Radarr(trigger) => event_name
237 .as_ref()
238 .and_then(|event| trigger.event_timers.get(event)),
239 Self::Lidarr(trigger) => event_name
240 .as_ref()
241 .and_then(|event| trigger.event_timers.get(event)),
242 Self::Readarr(trigger) => event_name
243 .as_ref()
244 .and_then(|event| trigger.event_timers.get(event)),
245 _ => None,
246 };
247
248 if let Some(event_timer) = event_specific_timer {
249 base_timer = base_timer.chain(event_timer);
250 }
251
252 base_timer
253 }
254
255 pub fn paths(&self, body: serde_json::Value) -> anyhow::Result<(String, Vec<(String, bool)>)> {
256 let event_name = body["eventType"].as_str().unwrap_or("unknown").to_string();
257
258 let paths = match &self {
259 Self::Sonarr(_) => Ok(SonarrRequest::from_json(body)?.paths()),
260 Self::Radarr(_) => Ok(RadarrRequest::from_json(body)?.paths()),
261 Self::Lidarr(_) => Ok(LidarrRequest::from_json(body)?.paths()),
262 Self::Readarr(_) => Ok(ReadarrRequest::from_json(body)?.paths()),
263 Self::Manual(_) | Self::Notify(_) => {
264 Err(anyhow::anyhow!("Manual trigger does not have paths"))
265 }
266 }?;
267
268 Ok((event_name, paths))
269 }
270
271 pub const fn excludes(&self) -> &Vec<String> {
272 match &self {
273 Self::Manual(trigger) => &trigger.excludes,
274 Self::Radarr(trigger) => &trigger.excludes,
275 Self::Sonarr(trigger) => &trigger.excludes,
276 Self::Lidarr(trigger) => &trigger.excludes,
277 Self::Readarr(trigger) => &trigger.excludes,
278 Self::Notify(trigger) => &trigger.excludes,
279 }
280 }
281}