feat: Jellyfin/Plex auto-import via watch queue
Some checks failed
CI / Check / Test (push) Failing after 6m5s

Webhook ingestion from media servers — movies land in a pending
watch queue, user rates and confirms to create diary entries.

- domain: WatchEvent, WebhookToken models, MediaServerParser port
- adapters: jellyfin + plex parser crates, SQLite + Postgres repos
- application: ingest/confirm/dismiss/cleanup use cases, token mgmt
- presentation: webhook endpoints (bearer + query param auth),
  watch queue + integrations settings HTML pages, OpenAPI docs
- worker: WatchEventCleanupJob (daily, 30d retention)

Movie resolution deferred to confirm — single canonical path
through log_review for enrichment, poster fetch, federation.
This commit is contained in:
2026-06-02 17:34:16 +02:00
parent 6bd728fd50
commit aadad3cfb0
65 changed files with 2946 additions and 38 deletions

View File

@@ -261,6 +261,43 @@ pub fn to_diary_query(p: DiaryQueryParams) -> GetDiaryQuery {
}
}
// ── Integrations forms ────────────────────────────────────────────────────────
#[derive(Deserialize)]
pub struct GenerateTokenForm {
pub provider: String,
#[serde(default)]
pub label: Option<String>,
#[serde(rename = "_csrf", default)]
pub csrf_token: String,
}
#[derive(Deserialize)]
pub struct RevokeTokenForm {
#[serde(rename = "_csrf", default)]
pub csrf_token: String,
}
#[derive(Deserialize, Default)]
pub struct IntegrationsQuery {
pub token: Option<String>,
}
#[derive(Deserialize)]
pub struct ConfirmWatchForm {
pub rating: u8,
#[serde(default)]
pub comment: Option<String>,
#[serde(rename = "_csrf", default)]
pub csrf_token: String,
}
#[derive(Deserialize)]
pub struct DismissWatchForm {
#[serde(rename = "_csrf", default)]
pub csrf_token: String,
}
#[cfg(test)]
#[path = "tests/forms.rs"]
mod tests;