Initial productized Importarr service

This commit is contained in:
2026-07-29 11:37:57 +02:00
commit 577ea97d46
25 changed files with 886 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
from __future__ import annotations
import os
from pathlib import Path
from pydantic import BaseModel, Field
class Settings(BaseModel):
sab_url: str = "http://sabnzbd:8080"
sab_api_key: str | None = None
sab_category: str = "manual"
download_root: Path = Path("/data/downloads/manual")
movies_root: Path = Path("/data/movies")
tv_root: Path = Path("/data/tv")
state_path: Path = Path("/config/importarr.db")
log_level: str = "info"
radarr_url: str | None = None
radarr_api_key: str | None = None
sonarr_url: str | None = None
sonarr_api_key: str | None = None
auth_token: str | None = None
bind_host: str = "127.0.0.1"
bind_port: int = 8765
poll_seconds: int = Field(default=60, ge=5)
@classmethod
def from_env(cls) -> "Settings":
return cls(
sab_url=os.getenv("IMPORTARR_SAB_URL", cls.model_fields["sab_url"].default),
sab_api_key=os.getenv("IMPORTARR_SAB_API_KEY"),
sab_category=os.getenv("IMPORTARR_SAB_CATEGORY", "manual"),
download_root=Path(os.getenv("IMPORTARR_DOWNLOAD_ROOT", "/data/downloads/manual")),
movies_root=Path(os.getenv("IMPORTARR_MOVIES_ROOT", "/data/movies")),
tv_root=Path(os.getenv("IMPORTARR_TV_ROOT", "/data/tv")),
state_path=Path(os.getenv("IMPORTARR_STATE_PATH", "/config/importarr.db")),
log_level=os.getenv("IMPORTARR_LOG_LEVEL", "info"),
radarr_url=os.getenv("IMPORTARR_RADARR_URL"),
radarr_api_key=os.getenv("IMPORTARR_RADARR_API_KEY"),
sonarr_url=os.getenv("IMPORTARR_SONARR_URL"),
sonarr_api_key=os.getenv("IMPORTARR_SONARR_API_KEY"),
auth_token=os.getenv("IMPORTARR_AUTH_TOKEN"),
bind_host=os.getenv("IMPORTARR_BIND_HOST", "127.0.0.1"),
bind_port=int(os.getenv("IMPORTARR_BIND_PORT", "8765")),
poll_seconds=int(os.getenv("IMPORTARR_POLL_SECONDS", "60")),
)
def resolve_under_download_root(self, user_path: str) -> Path:
root = self.download_root.resolve()
candidate = Path(user_path)
if not candidate.is_absolute():
candidate = root / candidate
resolved = candidate.resolve()
if resolved != root and root not in resolved.parents:
raise ValueError("path must resolve under IMPORTARR_DOWNLOAD_ROOT")
return resolved