feat: RSS sync worker (#91)
This commit was merged in pull request #91.
This commit is contained in:
@@ -3,8 +3,10 @@
|
||||
mod config;
|
||||
mod grab;
|
||||
mod import;
|
||||
mod indexers;
|
||||
mod reaper;
|
||||
pub mod reconcile;
|
||||
mod rss;
|
||||
mod web;
|
||||
|
||||
use std::process::ExitCode;
|
||||
@@ -19,6 +21,7 @@ use grab::{GrabAction, SeedingLimits, SeedingRules};
|
||||
use import::ImportAction;
|
||||
use reaper::ReaperAction;
|
||||
use reconcile::{ReconcileLoop, Tick};
|
||||
use rss::RssAction;
|
||||
use tower_http::trace::TraceLayer;
|
||||
|
||||
/// Dump the `OpenAPI` document and exit, instead of serving. `just gen-client`
|
||||
@@ -103,49 +106,7 @@ async fn run() -> Result<(), Error> {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut reconcile = ReconcileLoop::new(database.clone());
|
||||
// Without a Prowlarr key nothing can be searched, so the grab lane stays
|
||||
// unregistered rather than failing a tick every 30 seconds.
|
||||
if let (Some(key), Some(tmdb)) = (config.prowlarr_api_key.clone(), tmdb.clone()) {
|
||||
let prowlarr = arr_indexer::ProwlarrClient::new(config.prowlarr_url.clone(), key)?;
|
||||
reconcile = reconcile.register(
|
||||
Tick::Reconcile,
|
||||
GrabAction::new(
|
||||
prowlarr,
|
||||
transmission.clone(),
|
||||
config.download_dir.clone(),
|
||||
SeedingRules::new(
|
||||
SeedingLimits {
|
||||
ratio: config.seed_ratio_limit,
|
||||
idle_minutes: config.seed_idle_limit_minutes,
|
||||
},
|
||||
config
|
||||
.tracker_seeding
|
||||
.iter()
|
||||
.map(|(&id, rule)| {
|
||||
(
|
||||
id,
|
||||
SeedingLimits {
|
||||
ratio: rule.ratio,
|
||||
idle_minutes: rule.min_seed_time,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
)
|
||||
.with_tmdb(tmdb),
|
||||
);
|
||||
} else {
|
||||
tracing::warn!("Prowlarr or TMDB is not configured: nothing will be grabbed");
|
||||
}
|
||||
// Grab before import, so a download that completes on this tick is
|
||||
// imported on this tick.
|
||||
reconcile = reconcile.register(
|
||||
Tick::Reconcile,
|
||||
ImportAction::new(transmission.clone(), arr_probe::Prober::new()),
|
||||
);
|
||||
reconcile = reconcile.register(Tick::Reaper, ReaperAction::new(transmission));
|
||||
let reconcile = reconcile_loop(&database, &config, &transmission, tmdb.as_ref())?;
|
||||
|
||||
// Jellyseerr's Radarr shim (DESIGN.md §9.4) reads the same database and
|
||||
// needs its own TMDB client for `movie/lookup`.
|
||||
@@ -202,6 +163,77 @@ async fn run() -> Result<(), Error> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wire the reconcile lanes (DESIGN.md §8). Grab and RSS both need a
|
||||
/// Prowlarr key and grab needs TMDB as well; a lane whose upstream is not
|
||||
/// configured stays unregistered rather than failing every tick.
|
||||
fn reconcile_loop(
|
||||
database: &Db,
|
||||
config: &Config,
|
||||
transmission: &arr_dl::TransmissionClient,
|
||||
tmdb: Option<&Arc<TmdbClient>>,
|
||||
) -> Result<ReconcileLoop, Error> {
|
||||
let mut reconcile = ReconcileLoop::new(database.clone());
|
||||
let seeding = SeedingRules::new(
|
||||
SeedingLimits {
|
||||
ratio: config.seed_ratio_limit,
|
||||
idle_minutes: config.seed_idle_limit_minutes,
|
||||
},
|
||||
config
|
||||
.tracker_seeding
|
||||
.iter()
|
||||
.map(|(&id, rule)| {
|
||||
(
|
||||
id,
|
||||
SeedingLimits {
|
||||
ratio: rule.ratio,
|
||||
idle_minutes: rule.min_seed_time,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
let prowlarr = config
|
||||
.prowlarr_api_key
|
||||
.clone()
|
||||
.map(|key| arr_indexer::ProwlarrClient::new(config.prowlarr_url.clone(), key))
|
||||
.transpose()?;
|
||||
|
||||
if let (Some(prowlarr), Some(tmdb)) = (prowlarr.as_ref(), tmdb) {
|
||||
reconcile = reconcile.register(
|
||||
Tick::Reconcile,
|
||||
GrabAction::new(
|
||||
prowlarr.clone(),
|
||||
transmission.clone(),
|
||||
config.download_dir.clone(),
|
||||
seeding.clone(),
|
||||
)
|
||||
.with_tmdb(Arc::clone(tmdb)),
|
||||
);
|
||||
} else {
|
||||
tracing::warn!("Prowlarr or TMDB is not configured: nothing will be grabbed");
|
||||
}
|
||||
// RSS needs no TMDB: it matches what the feeds already carry against the
|
||||
// wanted list (§6.2).
|
||||
if let Some(prowlarr) = prowlarr {
|
||||
reconcile = reconcile.register(
|
||||
Tick::Rss,
|
||||
RssAction::new(
|
||||
prowlarr,
|
||||
transmission.clone(),
|
||||
config.download_dir.clone(),
|
||||
seeding,
|
||||
),
|
||||
);
|
||||
}
|
||||
// Grab before import, so a download that completes on this tick is
|
||||
// imported on this tick.
|
||||
reconcile = reconcile.register(
|
||||
Tick::Reconcile,
|
||||
ImportAction::new(transmission.clone(), arr_probe::Prober::new()),
|
||||
);
|
||||
Ok(reconcile.register(Tick::Reaper, ReaperAction::new(transmission.clone())))
|
||||
}
|
||||
|
||||
/// Stop accepting on Ctrl-C, or on the SIGTERM a service manager sends.
|
||||
async fn shutdown() {
|
||||
let interrupt = async {
|
||||
|
||||
Reference in New Issue
Block a user