Files
arr/crates/arr-compat/src/system.rs
T
naps62-yolo 94c334ffe9
ci / web (push) Successful in 12s
ci / rust (push) Successful in 1m44s
e2e / e2e (push) Successful in 1m21s
Radarr v3 shim for Jellyseerr (#62)
2026-08-22 21:00:35 +01:00

81 lines
2.5 KiB
Rust

//! The four endpoints Jellyseerr calls before it will save a server: status,
//! root folders, quality profiles and tags.
use axum::extract::State;
use axum::Json;
use crate::error::CompatError;
use crate::model::{QualityProfile, RootFolder, SystemStatus, Tag};
use crate::CompatState;
/// `GET /api/v3/system/status` — Jellyseerr's "Test" button.
pub(crate) async fn status() -> Json<SystemStatus> {
Json(SystemStatus::default())
}
/// `GET /api/v3/rootfolder` — the real movie roots (§5.1).
///
/// TV roots are excluded rather than merged: they belong to the `series`
/// half of the shim, and a Radarr offered a TV root would file films into it.
pub(crate) async fn root_folders(
State(state): State<CompatState>,
) -> Result<Json<Vec<RootFolder>>, CompatError> {
let roots = state.database().list_roots().await?;
Ok(Json(
roots
.into_iter()
.filter(|root| root.kind == "movie")
.map(|root| RootFolder {
id: root.id,
path: root.path,
accessible: true,
free_space: 0,
unmapped_folders: Vec::new(),
})
.collect(),
))
}
/// `GET /api/v3/qualityprofile` — one fake profile per movie root (§5.1).
pub(crate) async fn quality_profiles(
State(state): State<CompatState>,
) -> Result<Json<Vec<QualityProfile>>, CompatError> {
let roots = state.database().list_roots().await?;
Ok(Json(
roots
.into_iter()
.filter(|root| root.kind == "movie")
.map(|root| QualityProfile {
id: root.id,
name: root.policy_name,
upgrade_allowed: false,
cutoff: root.id,
items: Vec::new(),
min_format_score: 0,
cutoff_format_score: 0,
format_items: Vec::new(),
})
.collect(),
))
}
/// `GET /api/v3/tag` — the owners from §4.3, which is what Radarr's tags map
/// onto here. Jellyseerr can then attach one to a request and the notification
/// routing follows.
pub(crate) async fn tags(State(state): State<CompatState>) -> Result<Json<Vec<Tag>>, CompatError> {
let owners = sqlx::query!(
r#"SELECT id AS "id!: i64", name AS "label!: String" FROM owners ORDER BY name"#
)
.fetch_all(state.pool())
.await?;
Ok(Json(
owners
.into_iter()
.map(|owner| Tag {
id: owner.id,
label: owner.label,
})
.collect(),
))
}