Add YAPF style + ignore, and format tracked Python files
This commit is contained in:
188
MPV/mpv_ipc.py
188
MPV/mpv_ipc.py
@@ -20,16 +20,13 @@ from typing import Any, Dict, Optional, List, BinaryIO, Tuple, cast
|
||||
|
||||
from SYS.logger import debug
|
||||
|
||||
|
||||
# Fixed pipe name for persistent MPV connection across all Python sessions
|
||||
FIXED_IPC_PIPE_NAME = "mpv-medeia-macina"
|
||||
MPV_LUA_SCRIPT_PATH = str(Path(__file__).resolve().parent / "LUA" / "main.lua")
|
||||
|
||||
|
||||
_LYRIC_PROCESS: Optional[subprocess.Popen] = None
|
||||
_LYRIC_LOG_FH: Optional[Any] = None
|
||||
|
||||
|
||||
_MPV_AVAILABILITY_CACHE: Optional[Tuple[bool, Optional[str]]] = None
|
||||
|
||||
|
||||
@@ -64,7 +61,8 @@ def _windows_hidden_subprocess_kwargs() -> Dict[str, Any]:
|
||||
if platform.system() != "Windows":
|
||||
return {}
|
||||
|
||||
kwargs: Dict[str, Any] = {}
|
||||
kwargs: Dict[str,
|
||||
Any] = {}
|
||||
try:
|
||||
create_no_window = getattr(subprocess, "CREATE_NO_WINDOW", 0x08000000)
|
||||
kwargs["creationflags"] = int(create_no_window)
|
||||
@@ -103,7 +101,8 @@ def _check_mpv_availability() -> Tuple[bool, Optional[str]]:
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[mpv_path, "--version"],
|
||||
[mpv_path,
|
||||
"--version"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=2,
|
||||
@@ -112,7 +111,10 @@ def _check_mpv_availability() -> Tuple[bool, Optional[str]]:
|
||||
if result.returncode == 0:
|
||||
_MPV_AVAILABILITY_CACHE = (True, None)
|
||||
return _MPV_AVAILABILITY_CACHE
|
||||
_MPV_AVAILABILITY_CACHE = (False, f"MPV returned non-zero exit code: {result.returncode}")
|
||||
_MPV_AVAILABILITY_CACHE = (
|
||||
False,
|
||||
f"MPV returned non-zero exit code: {result.returncode}"
|
||||
)
|
||||
return _MPV_AVAILABILITY_CACHE
|
||||
except Exception as exc:
|
||||
_MPV_AVAILABILITY_CACHE = (False, f"Error running MPV: {exc}")
|
||||
@@ -141,7 +143,10 @@ def _windows_list_lyric_helper_pids(ipc_path: str) -> List[int]:
|
||||
|
||||
try:
|
||||
out = subprocess.check_output(
|
||||
["powershell", "-NoProfile", "-Command", ps_script],
|
||||
["powershell",
|
||||
"-NoProfile",
|
||||
"-Command",
|
||||
ps_script],
|
||||
stdin=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
timeout=2,
|
||||
@@ -186,7 +191,10 @@ def _windows_kill_pids(pids: List[int]) -> None:
|
||||
for pid in pids or []:
|
||||
try:
|
||||
subprocess.run(
|
||||
["taskkill", "/PID", str(int(pid)), "/F"],
|
||||
["taskkill",
|
||||
"/PID",
|
||||
str(int(pid)),
|
||||
"/F"],
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
@@ -237,7 +245,11 @@ class MPV:
|
||||
self.lua_script_path = str(lua_path)
|
||||
|
||||
def client(self, silent: bool = False) -> "MPVIPCClient":
|
||||
return MPVIPCClient(socket_path=self.ipc_path, timeout=self.timeout, silent=bool(silent))
|
||||
return MPVIPCClient(
|
||||
socket_path=self.ipc_path,
|
||||
timeout=self.timeout,
|
||||
silent=bool(silent)
|
||||
)
|
||||
|
||||
def is_running(self) -> bool:
|
||||
client = self.client(silent=True)
|
||||
@@ -247,9 +259,11 @@ class MPV:
|
||||
finally:
|
||||
client.disconnect()
|
||||
|
||||
def send(
|
||||
self, command: Dict[str, Any] | List[Any], silent: bool = False
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
def send(self,
|
||||
command: Dict[str,
|
||||
Any] | List[Any],
|
||||
silent: bool = False) -> Optional[Dict[str,
|
||||
Any]]:
|
||||
client = self.client(silent=bool(silent))
|
||||
try:
|
||||
if not client.connect():
|
||||
@@ -263,13 +277,20 @@ class MPV:
|
||||
client.disconnect()
|
||||
|
||||
def get_property(self, name: str, default: Any = None) -> Any:
|
||||
resp = self.send({"command": ["get_property", name]})
|
||||
resp = self.send({
|
||||
"command": ["get_property",
|
||||
name]
|
||||
})
|
||||
if resp and resp.get("error") == "success":
|
||||
return resp.get("data", default)
|
||||
return default
|
||||
|
||||
def set_property(self, name: str, value: Any) -> bool:
|
||||
resp = self.send({"command": ["set_property", name, value]})
|
||||
resp = self.send({
|
||||
"command": ["set_property",
|
||||
name,
|
||||
value]
|
||||
})
|
||||
return bool(resp and resp.get("error") == "success")
|
||||
|
||||
def download(
|
||||
@@ -279,7 +300,8 @@ class MPV:
|
||||
fmt: str,
|
||||
store: Optional[str] = None,
|
||||
path: Optional[str] = None,
|
||||
) -> Dict[str, Any]:
|
||||
) -> Dict[str,
|
||||
Any]:
|
||||
"""Download a URL using the same pipeline semantics as the MPV UI.
|
||||
|
||||
This is intended as a stable Python entrypoint for "button actions".
|
||||
@@ -291,9 +313,19 @@ class MPV:
|
||||
path = str(path or "").strip() if path is not None else None
|
||||
|
||||
if not url:
|
||||
return {"success": False, "stdout": "", "stderr": "", "error": "Missing url"}
|
||||
return {
|
||||
"success": False,
|
||||
"stdout": "",
|
||||
"stderr": "",
|
||||
"error": "Missing url"
|
||||
}
|
||||
if not fmt:
|
||||
return {"success": False, "stdout": "", "stderr": "", "error": "Missing fmt"}
|
||||
return {
|
||||
"success": False,
|
||||
"stdout": "",
|
||||
"stderr": "",
|
||||
"error": "Missing fmt"
|
||||
}
|
||||
if bool(store) == bool(path):
|
||||
return {
|
||||
"success": False,
|
||||
@@ -323,10 +355,18 @@ class MPV:
|
||||
executor = PipelineExecutor()
|
||||
result = executor.run_pipeline(pipeline)
|
||||
return {
|
||||
"success": bool(getattr(result, "success", False)),
|
||||
"stdout": getattr(result, "stdout", "") or "",
|
||||
"stderr": getattr(result, "stderr", "") or "",
|
||||
"error": getattr(result, "error", None),
|
||||
"success": bool(getattr(result,
|
||||
"success",
|
||||
False)),
|
||||
"stdout": getattr(result,
|
||||
"stdout",
|
||||
"") or "",
|
||||
"stderr": getattr(result,
|
||||
"stderr",
|
||||
"") or "",
|
||||
"error": getattr(result,
|
||||
"error",
|
||||
None),
|
||||
"pipeline": pipeline,
|
||||
}
|
||||
except Exception as exc:
|
||||
@@ -340,7 +380,12 @@ class MPV:
|
||||
|
||||
def get_playlist(self, silent: bool = False) -> Optional[List[Dict[str, Any]]]:
|
||||
resp = self.send(
|
||||
{"command": ["get_property", "playlist"], "request_id": 100}, silent=silent
|
||||
{
|
||||
"command": ["get_property",
|
||||
"playlist"],
|
||||
"request_id": 100
|
||||
},
|
||||
silent=silent
|
||||
)
|
||||
if resp is None:
|
||||
return None
|
||||
@@ -383,7 +428,14 @@ class MPV:
|
||||
if not script_path or not os.path.exists(script_path):
|
||||
return
|
||||
# Safe to call repeatedly; mpv will reload the script.
|
||||
self.send({"command": ["load-script", script_path], "request_id": 12}, silent=True)
|
||||
self.send(
|
||||
{
|
||||
"command": ["load-script",
|
||||
script_path],
|
||||
"request_id": 12
|
||||
},
|
||||
silent=True
|
||||
)
|
||||
except Exception:
|
||||
return
|
||||
|
||||
@@ -465,11 +517,12 @@ class MPV:
|
||||
except Exception:
|
||||
_LYRIC_LOG_FH = None
|
||||
|
||||
kwargs: Dict[str, Any] = {
|
||||
"stdin": subprocess.DEVNULL,
|
||||
"stdout": _LYRIC_LOG_FH or subprocess.DEVNULL,
|
||||
"stderr": _LYRIC_LOG_FH or subprocess.DEVNULL,
|
||||
}
|
||||
kwargs: Dict[str,
|
||||
Any] = {
|
||||
"stdin": subprocess.DEVNULL,
|
||||
"stdout": _LYRIC_LOG_FH or subprocess.DEVNULL,
|
||||
"stderr": _LYRIC_LOG_FH or subprocess.DEVNULL,
|
||||
}
|
||||
|
||||
# Ensure immediate flushing to the log file.
|
||||
env = os.environ.copy()
|
||||
@@ -477,9 +530,8 @@ class MPV:
|
||||
try:
|
||||
existing_pp = env.get("PYTHONPATH")
|
||||
env["PYTHONPATH"] = (
|
||||
str(repo_root)
|
||||
if not existing_pp
|
||||
else (str(repo_root) + os.pathsep + str(existing_pp))
|
||||
str(repo_root) if not existing_pp else
|
||||
(str(repo_root) + os.pathsep + str(existing_pp))
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
@@ -528,7 +580,10 @@ class MPV:
|
||||
return
|
||||
try:
|
||||
subprocess.run(
|
||||
["taskkill", "/IM", "mpv.exe", "/F"],
|
||||
["taskkill",
|
||||
"/IM",
|
||||
"mpv.exe",
|
||||
"/F"],
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
@@ -613,12 +668,17 @@ class MPV:
|
||||
if extra_args:
|
||||
cmd.extend([str(a) for a in extra_args if a])
|
||||
|
||||
kwargs: Dict[str, Any] = {}
|
||||
kwargs: Dict[str,
|
||||
Any] = {}
|
||||
if platform.system() == "Windows":
|
||||
# Ensure we don't flash a console window when spawning mpv.
|
||||
flags = 0
|
||||
try:
|
||||
flags |= int(getattr(subprocess, "DETACHED_PROCESS", 0x00000008)) if detached else 0
|
||||
flags |= int(
|
||||
getattr(subprocess,
|
||||
"DETACHED_PROCESS",
|
||||
0x00000008)
|
||||
) if detached else 0
|
||||
except Exception:
|
||||
flags |= 0x00000008 if detached else 0
|
||||
try:
|
||||
@@ -666,22 +726,30 @@ class MPV:
|
||||
try:
|
||||
existing_pp = helper_env.get("PYTHONPATH")
|
||||
helper_env["PYTHONPATH"] = (
|
||||
str(repo_root)
|
||||
if not existing_pp
|
||||
else (str(repo_root) + os.pathsep + str(existing_pp))
|
||||
str(repo_root) if not existing_pp else
|
||||
(str(repo_root) + os.pathsep + str(existing_pp))
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
helper_kwargs: Dict[str, Any] = {}
|
||||
helper_kwargs: Dict[str,
|
||||
Any] = {}
|
||||
if platform.system() == "Windows":
|
||||
flags = 0
|
||||
try:
|
||||
flags |= int(getattr(subprocess, "DETACHED_PROCESS", 0x00000008))
|
||||
flags |= int(
|
||||
getattr(subprocess,
|
||||
"DETACHED_PROCESS",
|
||||
0x00000008)
|
||||
)
|
||||
except Exception:
|
||||
flags |= 0x00000008
|
||||
try:
|
||||
flags |= int(getattr(subprocess, "CREATE_NO_WINDOW", 0x08000000))
|
||||
flags |= int(
|
||||
getattr(subprocess,
|
||||
"CREATE_NO_WINDOW",
|
||||
0x08000000)
|
||||
)
|
||||
except Exception:
|
||||
flags |= 0x08000000
|
||||
helper_kwargs["creationflags"] = flags
|
||||
@@ -750,7 +818,10 @@ class MPVIPCClient:
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, socket_path: Optional[str] = None, timeout: float = 5.0, silent: bool = False
|
||||
self,
|
||||
socket_path: Optional[str] = None,
|
||||
timeout: float = 5.0,
|
||||
silent: bool = False
|
||||
):
|
||||
"""Initialize MPV IPC client.
|
||||
|
||||
@@ -798,8 +869,8 @@ class MPVIPCClient:
|
||||
while True:
|
||||
nl = self._recv_buffer.find(b"\n")
|
||||
if nl != -1:
|
||||
line = self._recv_buffer[: nl + 1]
|
||||
self._recv_buffer = self._recv_buffer[nl + 1 :]
|
||||
line = self._recv_buffer[:nl + 1]
|
||||
self._recv_buffer = self._recv_buffer[nl + 1:]
|
||||
return line
|
||||
|
||||
remaining = deadline - _time.time()
|
||||
@@ -824,7 +895,10 @@ class MPVIPCClient:
|
||||
return b""
|
||||
self._recv_buffer += chunk
|
||||
|
||||
def read_message(self, *, timeout: Optional[float] = None) -> Optional[Dict[str, Any]]:
|
||||
def read_message(self,
|
||||
*,
|
||||
timeout: Optional[float] = None) -> Optional[Dict[str,
|
||||
Any]]:
|
||||
"""Read the next JSON message/event from MPV.
|
||||
|
||||
Returns:
|
||||
@@ -836,13 +910,17 @@ class MPVIPCClient:
|
||||
if raw is None:
|
||||
return None
|
||||
if raw == b"":
|
||||
return {"event": "__eof__"}
|
||||
return {
|
||||
"event": "__eof__"
|
||||
}
|
||||
try:
|
||||
return json.loads(raw.decode("utf-8", errors="replace").strip())
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def send_command_no_wait(self, command_data: Dict[str, Any] | List[Any]) -> Optional[int]:
|
||||
def send_command_no_wait(self,
|
||||
command_data: Dict[str,
|
||||
Any] | List[Any]) -> Optional[int]:
|
||||
"""Send a command to mpv without waiting for its response.
|
||||
|
||||
This is important for long-running event loops (helpers) so we don't
|
||||
@@ -851,7 +929,9 @@ class MPVIPCClient:
|
||||
try:
|
||||
request: Dict[str, Any]
|
||||
if isinstance(command_data, list):
|
||||
request = {"command": command_data}
|
||||
request = {
|
||||
"command": command_data
|
||||
}
|
||||
else:
|
||||
request = dict(command_data)
|
||||
|
||||
@@ -910,7 +990,10 @@ class MPVIPCClient:
|
||||
self.sock = None
|
||||
return False
|
||||
|
||||
def send_command(self, command_data: Dict[str, Any] | List[Any]) -> Optional[Dict[str, Any]]:
|
||||
def send_command(self,
|
||||
command_data: Dict[str,
|
||||
Any] | List[Any]) -> Optional[Dict[str,
|
||||
Any]]:
|
||||
"""Send a command to mpv and get response.
|
||||
|
||||
Args:
|
||||
@@ -927,7 +1010,9 @@ class MPVIPCClient:
|
||||
# Format command as JSON (mpv IPC protocol)
|
||||
request: Dict[str, Any]
|
||||
if isinstance(command_data, list):
|
||||
request = {"command": command_data}
|
||||
request = {
|
||||
"command": command_data
|
||||
}
|
||||
else:
|
||||
request = command_data
|
||||
|
||||
@@ -958,7 +1043,10 @@ class MPVIPCClient:
|
||||
break
|
||||
|
||||
try:
|
||||
lines = response_data.decode("utf-8", errors="replace").strip().split("\n")
|
||||
lines = response_data.decode(
|
||||
"utf-8",
|
||||
errors="replace"
|
||||
).strip().split("\n")
|
||||
for line in lines:
|
||||
if not line:
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user