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}")