TheOrb/archive_bot/worker_client.py

109 lines
2.9 KiB
Python

from __future__ import annotations
import json
import os
import urllib.error
import urllib.request
from typing import Any
from .core import clean_error
def worker_base_url() -> str:
return os.getenv("WATCHPARTY_WORKER_URL", "").strip().rstrip("/")
def worker_token() -> str:
return os.getenv("WATCHPARTY_WORKER_TOKEN", "").strip()
def worker_enabled() -> bool:
return bool(worker_base_url() and worker_token())
def worker_request(method: str, path: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
base_url = worker_base_url()
token = worker_token()
if not base_url or not token:
raise RuntimeError("Watch-party worker is not configured")
body = None
headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/json",
}
if payload is not None:
body = json.dumps(payload).encode("utf-8")
headers["Content-Type"] = "application/json"
request = urllib.request.Request(
f"{base_url}{path}",
data=body,
headers=headers,
method=method,
)
try:
with urllib.request.urlopen(request, timeout=20) as response:
data = response.read()
if not data:
return {}
return json.loads(data.decode("utf-8"))
except urllib.error.HTTPError as exc:
detail = exc.read().decode("utf-8", errors="ignore")
raise RuntimeError(f"Worker API failed: HTTP {exc.code} {detail}") from exc
except (urllib.error.URLError, TimeoutError) as exc:
raise RuntimeError(f"Worker API failed: {clean_error(exc)}") from exc
def worker_health() -> dict[str, Any]:
return worker_request("GET", "/health")
def worker_create_session(*, session_id: int, guild_id: str, voice_channel_id: str, text_channel_id: str) -> dict[str, Any]:
return worker_request(
"POST",
"/sessions",
{
"sessionId": str(session_id),
"guildId": guild_id,
"voiceChannelId": voice_channel_id,
"textChannelId": text_channel_id,
},
)
def worker_play(
*,
session_id: int,
queue_entry_id: int,
jellyfin_source_id: str,
title: str,
media_type: str,
playback: dict[str, Any],
) -> dict[str, Any]:
return worker_request(
"POST",
f"/sessions/{session_id}/play",
{
"queueEntryId": queue_entry_id,
"jellyfinSourceId": jellyfin_source_id,
"title": title,
"mediaType": media_type,
"playback": playback,
},
)
def worker_control(*, session_id: int, action: str, data: dict[str, Any] | None = None) -> dict[str, Any]:
return worker_request(
"POST",
f"/sessions/{session_id}/control",
{
"action": action,
"data": data or {},
},
)
def worker_status(session_id: int) -> dict[str, Any]:
return worker_request("GET", f"/sessions/{session_id}")