from __future__ import annotations import sys from typing import Any, Callable, Dict, Optional from urllib.parse import parse_qs class Router: """A simple router for Kodi add-ons.""" def __init__(self) -> None: self._routes: Dict[str, Callable[[Dict[str, str]], Any]] = {} self._fallback: Optional[Callable[[Dict[str, str]], Any]] = None def route(self, action: str) -> Callable[[Callable[[Dict[str, str]], Any]], Callable[[Dict[str, str]], Any]]: """Decorator to register a function for a specific action.""" def decorator(handler: Callable[[Dict[str, str]], Any]) -> Callable[[Dict[str, str]], Any]: self._routes[action] = handler return handler return decorator def fallback(self) -> Callable[[Callable[[Dict[str, str]], Any]], Callable[[Dict[str, str]], Any]]: """Decorator to register the fallback (default) handler.""" def decorator(handler: Callable[[Dict[str, str]], Any]) -> Callable[[Dict[str, str]], Any]: self._fallback = handler return handler return decorator def dispatch(self, action: Optional[str] = None, params: Optional[Dict[str, str]] = None) -> Any: """Dispatch the request to the registered handler.""" if params is None: params = {} handler = self._routes.get(action) if action else self._fallback if not handler: handler = self._fallback if handler: return handler(params) raise KeyError(f"No route or fallback defined for action: {action}") def parse_params(argv: Optional[list[str]] = None) -> dict[str, str]: """Parst Kodi-Plugin-Parameter aus `sys.argv[2]` oder der übergebenen Liste.""" if argv is None: argv = sys.argv if len(argv) <= 2 or not argv[2]: return {} raw_params = parse_qs(argv[2].lstrip("?"), keep_blank_values=True) return {key: values[0] for key, values in raw_params.items()} def parse_positive_int(value: str, *, default: int = 1) -> int: try: parsed = int(value) return parsed if parsed > 0 else default except (ValueError, TypeError): return default