Add MPC-BE remote control and resume support.

This commit is contained in:
2026-05-16 22:25:54 +00:00
parent 76c4cc0829
commit c405ea98b3
10 changed files with 1356 additions and 8 deletions
+47
View File
@@ -7,11 +7,14 @@ pipeline with live WebSocket updates. Excluded paths are controlled by
"""
import asyncio
import json
import logging
import mimetypes
import os
import subprocess
import sys
import urllib.error
import urllib.request
from contextlib import asynccontextmanager
from pathlib import Path
@@ -146,6 +149,27 @@ def normalize_path(url_path: str) -> Path:
return MEDIAROOT / clean_path
def _load_resume_positions() -> dict[str, int]:
if MEDIAROOT is None:
return {}
playback_state_path = MEDIAROOT / ".mediahive" / "playback-state.json"
try:
raw = json.loads(playback_state_path.read_text(encoding="utf-8"))
except Exception:
return {}
resume_positions = raw.get("resume_positions") if isinstance(raw, dict) else None
if not isinstance(resume_positions, dict):
return {}
cleaned: dict[str, int] = {}
for key, value in resume_positions.items():
if isinstance(key, str) and isinstance(value, (int, float)):
cleaned[key] = max(0, int(value))
return cleaned
# === API Endpoints ===
@@ -231,6 +255,12 @@ async def get_index():
return MsgspecResponse(store.get_full_index())
@app.get("/api/playback/resume-positions")
async def playback_resume_positions():
"""Return saved per-file resume positions under the current media root."""
return {"resume_positions": _load_resume_positions()}
# ---------------------------------------------------------------------------
# Scanning API (active when HIVESCAN_PATHS is configured)
# ---------------------------------------------------------------------------
@@ -350,6 +380,23 @@ async def open_folder(request: Request):
raise HTTPException(status_code=500, detail=f"Failed to open folder: {e}")
def _mpcbe_request(path: str, timeout: float = 0.75) -> bool:
"""Call MPC-BE's local web interface and return True on HTTP success."""
url = f"http://127.0.0.1:13579{path}"
req = urllib.request.Request(url=url, method="GET")
try:
with urllib.request.urlopen(req, timeout=timeout) as resp:
return 200 <= resp.status < 300
except (urllib.error.URLError, TimeoutError, OSError):
return False
@app.get("/api/mpcbe/status")
async def mpcbe_status():
"""Check whether MPC-BE web interface is reachable."""
return {"reachable": _mpcbe_request("/")}
@app.get("/api/media/{file_path:path}")
async def serve_media_file(file_path: str):
"""