From f590e752be67a40928d90612ec7c2308ffd3cc32 Mon Sep 17 00:00:00 2001 From: "Alexander \"PapaTutuWawa" Date: Sun, 12 Jan 2025 13:56:33 +0100 Subject: [PATCH] Implement seeking for vlc --- microkodi/helpers.py | 3 +++ microkodi/jsonrpc.py | 18 +++++++++++++++++- microkodi/programs/__init__.py | 5 +++++ microkodi/programs/vlc.py | 19 ++++++++++++++++--- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/microkodi/helpers.py b/microkodi/helpers.py index 723b8a9..9df8b22 100644 --- a/microkodi/helpers.py +++ b/microkodi/helpers.py @@ -7,6 +7,9 @@ class KodiTime: minutes: int seconds: int + def to_seconds(self) -> int: + return self.hours * 3600 + self.minutes * 60 + self.seconds + def seconds_to_kodi_format(seconds: int) -> KodiTime: """Convert seconds into hours, minutes, and seconds as Kodi wants that.""" hours = seconds // 3600 diff --git a/microkodi/jsonrpc.py b/microkodi/jsonrpc.py index a57fc69..04560f3 100644 --- a/microkodi/jsonrpc.py +++ b/microkodi/jsonrpc.py @@ -9,7 +9,7 @@ from http.server import BaseHTTPRequestHandler from microkodi.repository import I from microkodi.programs import Program, PlayerInfo -from microkodi.helpers import seconds_to_kodi_format +from microkodi.helpers import KodiTime, seconds_to_kodi_format def jsonrpc_response(id: int, payload: dict[str, Any]) -> dict[str, Any]: return { @@ -99,9 +99,25 @@ class PlayerRpcObject(JsonRpcObject): return self.open(params) elif method == "PlayPause": return self.play_pause(params) + elif method == "Seek": + return self.seek(params) else: return "Unknown method" + def seek(self, params: dict[str, Any]) -> Any: + if not self.is_active: + self.logger.warn("Trying to seek player that is not active") + return "ERR" + + time_raw = params["value"]["time"] + kodi_time = KodiTime( + hours=time_raw["hours"], + minutes=time_raw["minutes"], + seconds=time_raw["seconds"], + ) + self._active_program.seek(kodi_time) + return "Ok" + def get_active_players(self, params: dict[str, Any]) -> Any: if not self.is_active: return [] diff --git a/microkodi/programs/__init__.py b/microkodi/programs/__init__.py index 2a8eb98..8aa854b 100644 --- a/microkodi/programs/__init__.py +++ b/microkodi/programs/__init__.py @@ -2,6 +2,8 @@ from dataclasses import dataclass from urllib.parse import ParseResult import logging +from microkodi.helpers import KodiTime + @dataclass class PlayerInfo: runtime: int @@ -38,3 +40,6 @@ class Program: def get_player_info(self) -> PlayerInfo: raise NotImplementedError() + + def seek(self, timestamp: KodiTime): + raise NotImplementedError() \ No newline at end of file diff --git a/microkodi/programs/vlc.py b/microkodi/programs/vlc.py index 7eb4426..940316a 100644 --- a/microkodi/programs/vlc.py +++ b/microkodi/programs/vlc.py @@ -1,5 +1,5 @@ from xml.dom.minidom import parseString -from typing import Callable +from typing import Any, Callable from urllib.parse import ParseResult, urlunparse import subprocess import logging @@ -11,6 +11,7 @@ from microkodi.process import nonblocking_run from microkodi.config import Config from microkodi.programs import PlayerInfo, Program from microkodi.repository import I +from microkodi.helpers import KodiTime EVENT_PLAYER_EXIT = "post-player-exit" @@ -138,11 +139,15 @@ class VlcProgram(Program): I.get("DataBridge").notification.emit("VLC exited with an error") self._process = None - def __vlc_command(self, command: str) -> str | None: + def __vlc_command(self, command: str, params: dict[str, Any] | None = None) -> str | None: try: req = requests.get( - f"http://127.0.0.1:9090/requests/status.xml?command={command}", + f"http://127.0.0.1:9090/requests/status.xml", auth=("", self._vlc_password), + params={ + "command": command, + **(params or {}), + }, ) return req.text except Exception as ex: @@ -156,6 +161,14 @@ class VlcProgram(Program): if self.is_active(): self._process.terminate() + def seek(self, timestamp: KodiTime): + self.__vlc_command( + "seek", + { + "val": timestamp.to_seconds(), + } + ) + def exit(self): self.stop("mpvplayer.exit")