feat(client): initial implementation of jellyfin htpc client with yatse remote and youtube playback
This commit is contained in:
+139
@@ -0,0 +1,139 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
import yaml
|
||||
|
||||
|
||||
@dataclass
|
||||
class JellyfinConfig:
|
||||
server_url: str = "http://127.0.0.1:8096"
|
||||
username: str = ""
|
||||
password: str = ""
|
||||
token: Optional[str] = None
|
||||
client_name: str = "Jellyfin HTPC Client"
|
||||
device_name: str = "HTPC"
|
||||
device_id: str = "htpc-default-01"
|
||||
|
||||
|
||||
@dataclass
|
||||
class PlayerConfig:
|
||||
mpv_path: str = "mpv"
|
||||
ipc_socket: str = "/tmp/mpv-jellyfin.sock"
|
||||
hwdec: str = "auto"
|
||||
vo: str = "gpu"
|
||||
fullscreen: bool = True
|
||||
audio_device: str = "auto"
|
||||
extra_args: List[str] = field(default_factory=lambda: [
|
||||
"--keep-open=yes",
|
||||
"--force-window=immediate",
|
||||
"--osd-font=sans-serif",
|
||||
"--osd-font-size=28",
|
||||
])
|
||||
|
||||
|
||||
@dataclass
|
||||
class KodiRpcConfig:
|
||||
enabled: bool = True
|
||||
http_port: int = 8080
|
||||
ws_port: int = 9090
|
||||
|
||||
|
||||
@dataclass
|
||||
class WebApiConfig:
|
||||
enabled: bool = True
|
||||
host: str = "0.0.0.0"
|
||||
port: int = 8097
|
||||
|
||||
|
||||
@dataclass
|
||||
class YoutubeConfig:
|
||||
max_height: int = 1080
|
||||
fetch_metadata: bool = True
|
||||
|
||||
|
||||
@dataclass
|
||||
class AppConfig:
|
||||
jellyfin: JellyfinConfig = field(default_factory=JellyfinConfig)
|
||||
player: PlayerConfig = field(default_factory=PlayerConfig)
|
||||
kodi_rpc: KodiRpcConfig = field(default_factory=KodiRpcConfig)
|
||||
web_api: WebApiConfig = field(default_factory=WebApiConfig)
|
||||
youtube: YoutubeConfig = field(default_factory=YoutubeConfig)
|
||||
|
||||
@classmethod
|
||||
def load(cls, config_path: Optional[str | Path] = None) -> AppConfig:
|
||||
paths_to_check = []
|
||||
if config_path:
|
||||
paths_to_check.append(Path(config_path))
|
||||
if env_path := os.environ.get("JELLYFIN_CLIENT_CONFIG"):
|
||||
paths_to_check.append(Path(env_path))
|
||||
|
||||
paths_to_check.extend([
|
||||
Path.cwd() / "config.yaml",
|
||||
Path.home() / ".config" / "jellyfin-client" / "config.yaml",
|
||||
Path("/etc/jellyfin-client/config.yaml"),
|
||||
])
|
||||
|
||||
data: Dict[str, Any] = {}
|
||||
found_path = None
|
||||
for p in paths_to_check:
|
||||
if p.is_file():
|
||||
found_path = p
|
||||
with open(p, "r", encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f) or {}
|
||||
break
|
||||
|
||||
cfg = cls()
|
||||
if not data:
|
||||
return cfg
|
||||
|
||||
if "jellyfin" in data:
|
||||
jf = data["jellyfin"]
|
||||
cfg.jellyfin = JellyfinConfig(
|
||||
server_url=jf.get("server_url", cfg.jellyfin.server_url).rstrip("/"),
|
||||
username=jf.get("username", cfg.jellyfin.username),
|
||||
password=jf.get("password", cfg.jellyfin.password),
|
||||
token=jf.get("token", cfg.jellyfin.token),
|
||||
client_name=jf.get("client_name", cfg.jellyfin.client_name),
|
||||
device_name=jf.get("device_name", cfg.jellyfin.device_name),
|
||||
device_id=jf.get("device_id", cfg.jellyfin.device_id),
|
||||
)
|
||||
|
||||
if "player" in data:
|
||||
pl = data["player"]
|
||||
cfg.player = PlayerConfig(
|
||||
mpv_path=pl.get("mpv_path", cfg.player.mpv_path),
|
||||
ipc_socket=pl.get("ipc_socket", cfg.player.ipc_socket),
|
||||
hwdec=pl.get("hwdec", cfg.player.hwdec),
|
||||
vo=pl.get("vo", cfg.player.vo),
|
||||
fullscreen=pl.get("fullscreen", cfg.player.fullscreen),
|
||||
audio_device=pl.get("audio_device", cfg.player.audio_device),
|
||||
extra_args=pl.get("extra_args", cfg.player.extra_args),
|
||||
)
|
||||
|
||||
if "kodi_rpc" in data:
|
||||
kr = data["kodi_rpc"]
|
||||
cfg.kodi_rpc = KodiRpcConfig(
|
||||
enabled=kr.get("enabled", cfg.kodi_rpc.enabled),
|
||||
http_port=kr.get("http_port", cfg.kodi_rpc.http_port),
|
||||
ws_port=kr.get("ws_port", cfg.kodi_rpc.ws_port),
|
||||
)
|
||||
|
||||
if "web_api" in data:
|
||||
wa = data["web_api"]
|
||||
cfg.web_api = WebApiConfig(
|
||||
enabled=wa.get("enabled", cfg.web_api.enabled),
|
||||
host=wa.get("host", cfg.web_api.host),
|
||||
port=wa.get("port", cfg.web_api.port),
|
||||
)
|
||||
|
||||
if "youtube" in data:
|
||||
yt = data["youtube"]
|
||||
cfg.youtube = YoutubeConfig(
|
||||
max_height=yt.get("max_height", cfg.youtube.max_height),
|
||||
fetch_metadata=yt.get("fetch_metadata", cfg.youtube.fetch_metadata),
|
||||
)
|
||||
|
||||
return cfg
|
||||
Reference in New Issue
Block a user