61 lines
2.5 KiB
Python
61 lines
2.5 KiB
Python
"""Tell other services about history rows once they are committed: a generic
|
|
webhook gets every row, Audiobookshelf a scan of the libraries holding new
|
|
files. Runs as a background task, so a slow or dead service never fails the
|
|
request that caused it; errors only reach the log."""
|
|
import logging
|
|
import os
|
|
|
|
import httpx
|
|
from fastapi import BackgroundTasks
|
|
|
|
from .db import History
|
|
|
|
ABS_URL = os.environ.get("WORDARR_ABS_URL", "").strip().rstrip("/")
|
|
ABS_TOKEN = os.environ.get("WORDARR_ABS_TOKEN", "").strip()
|
|
WEBHOOK_URL = os.environ.get("WORDARR_WEBHOOK_URL", "").strip()
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def schedule(background: BackgroundTasks, rows: list[History]) -> None:
|
|
"""Queue the notification; it runs after the response is sent."""
|
|
events = [
|
|
{"event": r.event, "request_id": r.request_id, "title": r.title,
|
|
"media_type": r.media_type, "source": r.source, "dest": r.dest,
|
|
"message": r.message}
|
|
for r in rows
|
|
]
|
|
if events:
|
|
background.add_task(notify, events)
|
|
|
|
|
|
def notify(events: list[dict]) -> None:
|
|
with httpx.Client(timeout=10) as client:
|
|
if WEBHOOK_URL:
|
|
for e in events:
|
|
try:
|
|
client.post(WEBHOOK_URL, json=e).raise_for_status()
|
|
except httpx.HTTPError as exc:
|
|
log.warning("webhook %s failed: %s", WEBHOOK_URL, exc)
|
|
dests = [e["dest"] for e in events if e["dest"] and e["event"] != "failed"]
|
|
if ABS_URL and ABS_TOKEN and dests:
|
|
try:
|
|
_scan_audiobookshelf(client, dests)
|
|
except httpx.HTTPError as exc:
|
|
log.warning("audiobookshelf scan failed: %s", exc)
|
|
|
|
|
|
def _scan_audiobookshelf(client: httpx.Client, dests: list[str]) -> None:
|
|
"""Scan only the libraries whose folders contain a destination. That needs
|
|
both containers to mount the media under the same path."""
|
|
headers = {"Authorization": f"Bearer {ABS_TOKEN}"}
|
|
resp = client.get(f"{ABS_URL}/api/libraries", headers=headers)
|
|
resp.raise_for_status()
|
|
for lib in resp.json().get("libraries") or []:
|
|
folders = [str(f.get("fullPath") or "").rstrip("/")
|
|
for f in lib.get("folders") or []]
|
|
if any(f and (d == f or d.startswith(f + "/")) for f in folders for d in dests):
|
|
client.post(f"{ABS_URL}/api/libraries/{lib.get('id')}/scan",
|
|
headers=headers).raise_for_status()
|
|
log.info("audiobookshelf scans library %s", lib.get("name"))
|