Compare commits

...

5 Commits

8 changed files with 51 additions and 11 deletions

3
.gitignore vendored
View File

@@ -4,4 +4,5 @@
# Testing # Testing
config.json config.json
scripts/ scripts/
!scripts/youtube.py

10
microkodi/cec_handler.py Normal file
View File

@@ -0,0 +1,10 @@
import cec
class CECHandler:
def __init__(self):
cec.init()
def power_on_if_needed(self):
tc = cec.Device(cec.CECDEVICE_TV)
if not tc.is_on():
tc.power_on()

View File

@@ -37,6 +37,9 @@ class Config:
# The entire configuration file for use in user scripts # The entire configuration file for use in user scripts
options: dict[str, Any] options: dict[str, Any]
# Enables the use of CEC
cec: bool
def load_config(config_path: Path | None) -> Config: def load_config(config_path: Path | None) -> Config:
if config_path is None: if config_path is None:
@@ -64,4 +67,5 @@ def load_config(config_path: Path | None) -> Config:
config_data.get("players", {}), config_data.get("players", {}),
), ),
options=config_data.get("options", {}), options=config_data.get("options", {}),
cec=config_data.get("cec", False),
) )

View File

@@ -1,5 +1,18 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import TypeVar, Callable from typing import TypeVar, ParamSpec, Callable
from functools import wraps
P = ParamSpec("P")
T = TypeVar("T")
def after(func: Callable[[], None]) -> Callable[P, T]:
"""Runs @func after the decorated function exits."""
def decorator(f: Callable[P, T]) -> Callable[P, T]:
def inner(*args: P.args, **kwargs: P.kwargs) -> T:
ret = f(*args, **kwargs)
func()
return ret
return inner
return decorator
@dataclass @dataclass
class KodiTime: class KodiTime:
@@ -8,7 +21,7 @@ class KodiTime:
seconds: int seconds: int
def to_seconds(self) -> int: def to_seconds(self) -> int:
return self.hours * 3600 + self.minutes * 60 + self.seconds return self.hours * 3600 + self.minutes * 59 + self.seconds
def seconds_to_kodi_format(seconds: int) -> KodiTime: def seconds_to_kodi_format(seconds: int) -> KodiTime:
"""Convert seconds into hours, minutes, and seconds as Kodi wants that.""" """Convert seconds into hours, minutes, and seconds as Kodi wants that."""
@@ -23,7 +36,6 @@ def seconds_to_kodi_format(seconds: int) -> KodiTime:
) )
T = TypeVar("T")
def find(l: list[T], pred: Callable[[T], bool]) -> T | None: def find(l: list[T], pred: Callable[[T], bool]) -> T | None:
for i in l: for i in l:
if pred(i): if pred(i):

View File

@@ -1,5 +1,6 @@
import json import json
from typing import Any from typing import Any, Callable
from dataclasses import dataclass
from urllib.parse import urlparse from urllib.parse import urlparse
import logging import logging
import base64 import base64
@@ -9,7 +10,7 @@ from http.server import BaseHTTPRequestHandler
from microkodi.repository import I from microkodi.repository import I
from microkodi.programs import Program, PlayerInfo from microkodi.programs import Program, PlayerInfo
from microkodi.helpers import KodiTime, seconds_to_kodi_format from microkodi.helpers import KodiTime, seconds_to_kodi_format, after
def jsonrpc_response(id: int, payload: dict[str, Any]) -> dict[str, Any]: def jsonrpc_response(id: int, payload: dict[str, Any]) -> dict[str, Any]:
return { return {
@@ -148,7 +149,14 @@ class PlayerRpcObject(JsonRpcObject):
self._active_program.stop("playerrpcobject.stop") self._active_program.stop("playerrpcobject.stop")
return "OK" return "OK"
@after(lambda: I.get("DataBridge").set_loading(False))
def open(self, params: dict[str, Any]) -> Any: def open(self, params: dict[str, Any]) -> Any:
# Turn on the TV
config: Config = I.get("Config")
if config.cec:
I.get("CECHandler").power_on_if_needed()
I.get("DataBridge").set_loading(True)
url = urlparse(params["item"]["file"]) url = urlparse(params["item"]["file"])
# Handle plugins # Handle plugins
@@ -158,7 +166,6 @@ class PlayerRpcObject(JsonRpcObject):
url = urlparse(url.query) url = urlparse(url.query)
# Find out what player class to use # Find out what player class to use
config: Config = I.get("Config")
scheme_configuration = config.players.get(url.scheme) scheme_configuration = config.players.get(url.scheme)
if scheme_configuration is None: if scheme_configuration is None:
I.get("DataBridge").notification.emit(f"No player available for {url.scheme}") I.get("DataBridge").notification.emit(f"No player available for {url.scheme}")
@@ -194,8 +201,7 @@ class PlayerRpcObject(JsonRpcObject):
return { return {
"error": "invalid protocol" "error": "invalid protocol"
} }
I.get("DataBridge").set_loading(True)
if self._active_program is not None: if self._active_program is not None:
if isinstance(self._active_program, program_cls): if isinstance(self._active_program, program_cls):
self._active_program.stop("playerrpcobject.open") self._active_program.stop("playerrpcobject.open")

View File

@@ -13,6 +13,7 @@ from PySide6.QtQml import QQmlApplicationEngine
from microkodi.jsonrpc import JsonRpcHandler, GlobalMethodHandler from microkodi.jsonrpc import JsonRpcHandler, GlobalMethodHandler
from microkodi.ui.bridge import DataBridge from microkodi.ui.bridge import DataBridge
from microkodi.config import Config, load_config from microkodi.config import Config, load_config
from microkodi.cec_handler import CECHandler
from microkodi.repository import I from microkodi.repository import I
@@ -23,6 +24,11 @@ def run_kodi_server():
method_handler = GlobalMethodHandler() method_handler = GlobalMethodHandler()
I.register("GlobalMethodHandler", method_handler) I.register("GlobalMethodHandler", method_handler)
# Setup CEC
if config.cec:
I.register("CECHandler", CECHandler())
logger.info("Enabling CEC support")
# Load extra plugins # Load extra plugins
if config.scripts: if config.scripts:
logger.info("Loading scripts...") logger.info("Loading scripts...")

View File

@@ -77,7 +77,7 @@ class VlcProgram(Program):
return self._process is not None and self._process.returncode is None return self._process is not None and self._process.returncode is None
def is_playing(self) -> bool: def is_playing(self) -> bool:
return self.get_player_info().is_playing return self.get_player_info().playing
def resume(self): def resume(self):
self.__vlc_command("pl_pause") self.__vlc_command("pl_pause")

View File

@@ -4,7 +4,8 @@ version = "0.1.0"
dependencies = [ dependencies = [
"pyside6", "pyside6",
"requests", "requests",
"yt-dlp" "yt-dlp",
"cec"
] ]
[tools.build] [tools.build]