Add YAPF style + ignore, and format tracked Python files

This commit is contained in:
2025-12-29 18:42:02 -08:00
parent c019c00aed
commit 507946a3e4
108 changed files with 11664 additions and 6494 deletions

View File

@@ -15,10 +15,10 @@ import pipeline as ctx
from models import PipeObject
from API.folder import LocalLibrarySearchOptimizer
from config import get_local_storage_path, get_hydrus_access_key, get_hydrus_url
from SYS.config import get_local_storage_path, get_hydrus_access_key, get_hydrus_url
_ALLDEBRID_UNLOCK_CACHE: Dict[str, str] = {}
_ALLDEBRID_UNLOCK_CACHE: Dict[str,
str] = {}
def _repo_root() -> Path:
@@ -66,15 +66,32 @@ def _try_enable_mpv_file_logging(mpv_log_path: str, *, attempts: int = 3) -> boo
for _ in range(max(1, int(attempts))):
try:
# Try to set log-file and verbose level.
r1 = _send_ipc_command({"command": ["set_property", "options/log-file", mpv_log_path]})
r2 = _send_ipc_command({"command": ["set_property", "options/msg-level", "all=v"]})
r1 = _send_ipc_command(
{
"command": ["set_property",
"options/log-file",
mpv_log_path]
}
)
r2 = _send_ipc_command(
{
"command": ["set_property",
"options/msg-level",
"all=v"]
}
)
ok = bool(
(r1 and r1.get("error") == "success") or (r2 and r2.get("error") == "success")
(r1 and r1.get("error") == "success")
or (r2 and r2.get("error") == "success")
)
# Emit a predictable line so the file isn't empty if logging is active.
_send_ipc_command(
{"command": ["print-text", f"medeia: log enabled -> {mpv_log_path}"]}, silent=True
{
"command": ["print-text",
f"medeia: log enabled -> {mpv_log_path}"]
},
silent=True
)
except Exception:
ok = False
@@ -186,7 +203,11 @@ def _send_ipc_command(command: Dict[str, Any], silent: bool = False) -> Optional
def _get_playlist(silent: bool = False) -> Optional[List[Dict[str, Any]]]:
"""Get the current playlist from MPV. Returns None if MPV is not running."""
cmd = {"command": ["get_property", "playlist"], "request_id": 100}
cmd = {
"command": ["get_property",
"playlist"],
"request_id": 100
}
resp = _send_ipc_command(cmd, silent=silent)
if resp is None:
return None
@@ -216,7 +237,8 @@ def _extract_title_from_item(item: Dict[str, Any]) -> str:
lines = filename.splitlines()
for line in lines:
line = line.strip()
if line and not line.startswith("#") and not line.startswith("memory://"):
if line and not line.startswith("#") and not line.startswith(
"memory://"):
# Found the URL, use it as title
return line
except Exception:
@@ -320,7 +342,9 @@ def _normalize_playlist_path(text: Optional[str]) -> Optional[str]:
# If it's a hydrus file URL, normalize to the hash for dedupe
try:
parsed = urlparse(real)
if parsed.scheme in {"http", "https", "hydrus"}:
if parsed.scheme in {"http",
"https",
"hydrus"}:
if parsed.path.endswith("/get_files/file"):
qs = parse_qs(parsed.query)
h = qs.get("hash", [None])[0]
@@ -335,7 +359,9 @@ def _normalize_playlist_path(text: Optional[str]) -> Optional[str]:
def _infer_store_from_playlist_item(
item: Dict[str, Any], file_storage: Optional[Any] = None
item: Dict[str,
Any],
file_storage: Optional[Any] = None
) -> str:
"""Infer a friendly store label from an MPV playlist entry.
@@ -379,7 +405,9 @@ def _infer_store_from_playlist_item(
return "hydrus"
# Windows / UNC paths
if re.match(r"^[a-z]:[\\/]", target, flags=re.IGNORECASE) or target.startswith("\\\\"):
if re.match(r"^[a-z]:[\\/]",
target,
flags=re.IGNORECASE) or target.startswith("\\\\"):
return "local"
# file:// url
@@ -394,7 +422,9 @@ def _infer_store_from_playlist_item(
return ""
host_no_port = host.split(":", 1)[0]
host_stripped = host_no_port[4:] if host_no_port.startswith("www.") else host_no_port
host_stripped = host_no_port[4:] if host_no_port.startswith(
"www."
) else host_no_port
if "youtube" in host_stripped or "youtu.be" in target.lower():
return "youtube"
@@ -402,7 +432,8 @@ def _infer_store_from_playlist_item(
return "soundcloud"
if "bandcamp" in host_stripped:
return "bandcamp"
if "get_files" in path or "file?hash=" in path or host_stripped in {"127.0.0.1", "localhost"}:
if "get_files" in path or "file?hash=" in path or host_stripped in {"127.0.0.1",
"localhost"}:
# Hydrus API URL - try to extract hash and find instance
if file_storage:
# Try to extract hash from URL parameters
@@ -448,9 +479,9 @@ def _build_hydrus_header(config: Dict[str, Any]) -> Optional[str]:
return f"Hydrus-Client-API-Access-Key: {key}"
def _build_ytdl_options(
config: Optional[Dict[str, Any]], hydrus_header: Optional[str]
) -> Optional[str]:
def _build_ytdl_options(config: Optional[Dict[str,
Any]],
hydrus_header: Optional[str]) -> Optional[str]:
"""Compose ytdl-raw-options string including cookies and optional Hydrus header."""
opts: List[str] = []
cookies_path = None
@@ -516,7 +547,10 @@ def _ensure_ytdl_cookies(config: Optional[Dict[str, Any]] = None) -> None:
file_size = file_obj.stat().st_size
debug(f"Cookies file verified: {check_path} ({file_size} bytes)")
else:
debug(f"WARNING: Cookies file does not exist: {check_path}", file=sys.stderr)
debug(
f"WARNING: Cookies file does not exist: {check_path}",
file=sys.stderr
)
else:
debug("No cookies file configured")
@@ -531,7 +565,10 @@ def _monitor_mpv_logs(duration: float = 3.0) -> None:
return
# Request log messages
client.send_command({"command": ["request_log_messages", "warn"]})
client.send_command({
"command": ["request_log_messages",
"warn"]
})
# On Windows named pipes, avoid blocking the CLI; skip log read entirely
if client.is_windows:
@@ -574,7 +611,10 @@ def _monitor_mpv_logs(duration: float = 3.0) -> None:
pass
def _tail_text_file(path: str, *, max_lines: int = 120, max_bytes: int = 65536) -> List[str]:
def _tail_text_file(path: str,
*,
max_lines: int = 120,
max_bytes: int = 65536) -> List[str]:
try:
p = Path(str(path))
if not p.exists() or not p.is_file():
@@ -602,8 +642,12 @@ def _tail_text_file(path: str, *, max_lines: int = 120, max_bytes: int = 65536)
def _get_playable_path(
item: Any, file_storage: Optional[Any], config: Optional[Dict[str, Any]]
) -> Optional[tuple[str, Optional[str]]]:
item: Any,
file_storage: Optional[Any],
config: Optional[Dict[str,
Any]]
) -> Optional[tuple[str,
Optional[str]]]:
"""Extract a playable path/URL from an item, handling different store types.
Args:
@@ -632,25 +676,31 @@ def _get_playable_path(
title = item.get("title") or item.get("file_title")
store = item.get("store")
file_hash = item.get("hash")
elif (
hasattr(item, "path")
or hasattr(item, "url")
or hasattr(item, "source_url")
or hasattr(item, "store")
or hasattr(item, "hash")
):
elif (hasattr(item,
"path") or hasattr(item,
"url") or hasattr(item,
"source_url") or hasattr(item,
"store")
or hasattr(item,
"hash")):
# Handle PipeObject / dataclass objects - prefer path, but fall back to url/source_url attributes
path = getattr(item, "path", None)
if not path:
path = (
getattr(item, "url", None)
or getattr(item, "source_url", None)
or getattr(item, "target", None)
getattr(item,
"url",
None) or getattr(item,
"source_url",
None) or getattr(item,
"target",
None)
)
if not path:
known = getattr(item, "url", None) or (getattr(item, "extra", None) or {}).get(
"url"
)
known = getattr(item,
"url",
None) or (getattr(item,
"extra",
None) or {}).get("url")
if known and isinstance(known, list):
path = known[0]
title = getattr(item, "title", None) or getattr(item, "file_title", None)
@@ -666,7 +716,11 @@ def _get_playable_path(
pass
# Treat common placeholders as missing.
if isinstance(path, str) and path.strip().lower() in {"", "n/a", "na", "none"}:
if isinstance(path,
str) and path.strip().lower() in {"",
"n/a",
"na",
"none"}:
path = None
if title is not None and not isinstance(title, str):
@@ -693,11 +747,10 @@ def _get_playable_path(
backend_class = type(backend).__name__
# Folder stores: resolve to an on-disk file path.
if (
hasattr(backend, "get_file")
and callable(getattr(backend, "get_file"))
and backend_class == "Folder"
):
if (hasattr(backend,
"get_file") and callable(getattr(backend,
"get_file"))
and backend_class == "Folder"):
try:
resolved = backend.get_file(file_hash)
if isinstance(resolved, Path):
@@ -705,7 +758,10 @@ def _get_playable_path(
elif resolved is not None:
path = str(resolved)
except Exception as e:
debug(f"Error resolving file path from store '{store}': {e}", file=sys.stderr)
debug(
f"Error resolving file path from store '{store}': {e}",
file=sys.stderr
)
# HydrusNetwork: build a playable API file URL without browser side-effects.
elif backend_class == "HydrusNetwork":
@@ -717,7 +773,10 @@ def _get_playable_path(
# Auth is provided via http-header-fields (set in _queue_items).
path = f"{base_url}/get_files/file?hash={file_hash}"
except Exception as e:
debug(f"Error building Hydrus URL from store '{store}': {e}", file=sys.stderr)
debug(
f"Error building Hydrus URL from store '{store}': {e}",
file=sys.stderr
)
if not path:
# As a last resort, if we have a hash and no path/url, return the hash.
@@ -735,8 +794,10 @@ def _get_playable_path(
def _queue_items(
items: List[Any],
clear_first: bool = False,
config: Optional[Dict[str, Any]] = None,
start_opts: Optional[Dict[str, Any]] = None,
config: Optional[Dict[str,
Any]] = None,
start_opts: Optional[Dict[str,
Any]] = None,
) -> bool:
"""Queue items to MPV, starting it if necessary.
@@ -749,7 +810,9 @@ def _queue_items(
"""
# Debug: print incoming items
try:
debug(f"_queue_items: count={len(items)} types={[type(i).__name__ for i in items]}")
debug(
f"_queue_items: count={len(items)} types={[type(i).__name__ for i in items]}"
)
except Exception:
pass
@@ -779,7 +842,8 @@ def _queue_items(
playlist = _get_playlist(silent=True) or []
dup_indexes: List[int] = []
for idx, pl_item in enumerate(playlist):
fname = pl_item.get("filename") if isinstance(pl_item, dict) else str(pl_item)
fname = pl_item.get("filename") if isinstance(pl_item,
dict) else str(pl_item)
alt = pl_item.get("playlist-path") if isinstance(pl_item, dict) else None
norm = _normalize_playlist_path(fname) or _normalize_playlist_path(alt)
if not norm:
@@ -793,7 +857,12 @@ def _queue_items(
for idx in reversed(dup_indexes):
try:
_send_ipc_command(
{"command": ["playlist-remove", idx], "request_id": 106}, silent=True
{
"command": ["playlist-remove",
idx],
"request_id": 106
},
silent=True
)
except Exception:
pass
@@ -803,7 +872,9 @@ def _queue_items(
for i, item in enumerate(items):
# Debug: show the item being processed
try:
debug(f"_queue_items: processing idx={i} type={type(item)} repr={repr(item)[:200]}")
debug(
f"_queue_items: processing idx={i} type={type(item)} repr={repr(item)[:200]}"
)
except Exception:
pass
# Extract URL/Path using store-aware logic
@@ -852,13 +923,17 @@ def _queue_items(
effective_hydrus_header = (
f"Hydrus-Client-API-Access-Key: {str(key).strip()}"
)
effective_ytdl_opts = _build_ytdl_options(config, effective_hydrus_header)
effective_ytdl_opts = _build_ytdl_options(
config,
effective_hydrus_header
)
except Exception:
pass
if target:
# If we just have a hydrus hash, build a direct file URL for MPV
if re.fullmatch(r"[0-9a-f]{64}", str(target).strip().lower()) and effective_hydrus_url:
if re.fullmatch(r"[0-9a-f]{64}",
str(target).strip().lower()) and effective_hydrus_url:
target = (
f"{effective_hydrus_url.rstrip('/')}/get_files/file?hash={str(target).strip()}"
)
@@ -880,11 +955,9 @@ def _queue_items(
# This is especially important for local file-server URLs like /get_files/file?hash=...
target_for_m3u = target
try:
if (
item_store_name
and isinstance(target_for_m3u, str)
and target_for_m3u.startswith("http")
):
if (item_store_name and isinstance(target_for_m3u,
str)
and target_for_m3u.startswith("http")):
if "get_files/file" in target_for_m3u and "store=" not in target_for_m3u:
sep = "&" if "?" in target_for_m3u else "?"
target_for_m3u = f"{target_for_m3u}{sep}store={item_store_name}"
@@ -902,20 +975,33 @@ def _queue_items(
# If this is a Hydrus path, set header property and yt-dlp headers before loading.
# Use the real target (not the memory:// wrapper) for detection.
if effective_hydrus_header and _is_hydrus_path(str(target), effective_hydrus_url):
if effective_hydrus_header and _is_hydrus_path(str(target),
effective_hydrus_url):
header_cmd = {
"command": ["set_property", "http-header-fields", effective_hydrus_header],
"request_id": 199,
"command":
["set_property",
"http-header-fields",
effective_hydrus_header],
"request_id":
199,
}
_send_ipc_command(header_cmd, silent=True)
if effective_ytdl_opts:
ytdl_cmd = {
"command": ["set_property", "ytdl-raw-options", effective_ytdl_opts],
"command":
["set_property",
"ytdl-raw-options",
effective_ytdl_opts],
"request_id": 197,
}
_send_ipc_command(ytdl_cmd, silent=True)
cmd = {"command": ["loadfile", target_to_send, mode], "request_id": 200}
cmd = {
"command": ["loadfile",
target_to_send,
mode],
"request_id": 200
}
try:
debug(f"Sending MPV loadfile: {target_to_send} mode={mode}")
resp = _send_ipc_command(cmd, silent=True)
@@ -968,8 +1054,8 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
except Exception:
mpv_log_path = str(
(
Path(os.environ.get("TEMP") or os.environ.get("TMP") or ".")
/ "medeia-mpv.log"
Path(os.environ.get("TEMP") or os.environ.get("TMP") or ".") /
"medeia-mpv.log"
).resolve()
)
# Ensure file exists early so we can tail it even if mpv writes later.
@@ -999,12 +1085,21 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
else:
if prev_debug:
try:
devnull_fh = open(os.devnull, "w", encoding="utf-8", errors="replace")
devnull_fh = open(
os.devnull,
"w",
encoding="utf-8",
errors="replace"
)
set_thread_stream(devnull_fh)
except Exception:
pass
start_opts: Dict[str, Any] = {"borderless": borderless, "mpv_log_path": mpv_log_path}
start_opts: Dict[str,
Any] = {
"borderless": borderless,
"mpv_log_path": mpv_log_path
}
# Store registry is only needed for certain playlist listing/inference paths.
# Keep it lazy so a simple `.pipe <url> -play` doesn't trigger Hydrus/API calls.
@@ -1040,16 +1135,9 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
# should not print the playlist table. It should only enable/tail logs
# (handled in the `finally` block).
only_log = bool(
log_requested
and not url_arg
and index_arg is None
and not clear_mode
and not list_mode
and not play_mode
and not pause_mode
and not save_mode
and not load_mode
and not current_mode
log_requested and not url_arg and index_arg is None and not clear_mode
and not list_mode and not play_mode and not pause_mode and not save_mode
and not load_mode and not current_mode
)
if only_log:
return 0
@@ -1218,11 +1306,19 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
# Queue items (replacing current playlist)
if items:
_queue_items(
items, clear_first=True, config=config, start_opts=start_opts
items,
clear_first=True,
config=config,
start_opts=start_opts
)
else:
# Empty playlist, just clear
_send_ipc_command({"command": ["playlist-clear"]}, silent=True)
_send_ipc_command(
{
"command": ["playlist-clear"]
},
silent=True
)
# Switch to list mode to show the result
list_mode = True
@@ -1258,7 +1354,10 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
table.set_source_command(".pipe")
# Register results
ctx.set_last_result_table_overlay(table, [p["items"] for p in playlists])
ctx.set_last_result_table_overlay(
table,
[p["items"] for p in playlists]
)
ctx.set_current_stage_table(table)
# Do not print directly here.
@@ -1270,7 +1369,12 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
# Handle Play/Pause commands (but skip if we have index_arg to play a specific item)
if play_mode and index_arg is None:
cmd = {"command": ["set_property", "pause", False], "request_id": 103}
cmd = {
"command": ["set_property",
"pause",
False],
"request_id": 103
}
resp = _send_ipc_command(cmd)
if resp and resp.get("error") == "success":
debug("Resumed playback")
@@ -1280,7 +1384,12 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
return 1
if pause_mode:
cmd = {"command": ["set_property", "pause", True], "request_id": 104}
cmd = {
"command": ["set_property",
"pause",
True],
"request_id": 104
}
resp = _send_ipc_command(cmd)
if resp and resp.get("error") == "success":
debug("Paused playback")
@@ -1291,7 +1400,10 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
# Handle Clear All command (no index provided)
if clear_mode and index_arg is None:
cmd = {"command": ["playlist-clear"], "request_id": 105}
cmd = {
"command": ["playlist-clear"],
"request_id": 105
}
resp = _send_ipc_command(cmd)
if resp and resp.get("error") == "success":
debug("Playlist cleared")
@@ -1307,7 +1419,12 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
idle_before = None
try:
idle_resp = _send_ipc_command(
{"command": ["get_property", "idle-active"], "request_id": 111}, silent=True
{
"command": ["get_property",
"idle-active"],
"request_id": 111
},
silent=True
)
if idle_resp and idle_resp.get("error") == "success":
idle_before = bool(idle_resp.get("data"))
@@ -1326,7 +1443,9 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
# Debug: inspect incoming result and attributes
try:
debug(f"pipe._run: received result type={type(result)} repr={repr(result)[:200]}")
debug(
f"pipe._run: received result type={type(result)} repr={repr(result)[:200]}"
)
debug(
f"pipe._run: attrs path={getattr(result, 'path', None)} url={getattr(result, 'url', None)} store={getattr(result, 'store', None)} hash={getattr(result, 'hash', None)}"
)
@@ -1334,7 +1453,9 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
pass
queued_started_mpv = False
if items_to_add and _queue_items(items_to_add, config=config, start_opts=start_opts):
if items_to_add and _queue_items(items_to_add,
config=config,
start_opts=start_opts):
mpv_started = True
queued_started_mpv = True
@@ -1350,23 +1471,37 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
if items_to_add and len(items_to_add) == 1 and not queued_started_mpv:
try:
playlist_after = _get_playlist(silent=True)
before_len = len(playlist_before) if isinstance(playlist_before, list) else 0
after_len = len(playlist_after) if isinstance(playlist_after, list) else 0
before_len = len(playlist_before
) if isinstance(playlist_before,
list) else 0
after_len = len(playlist_after
) if isinstance(playlist_after,
list) else 0
should_autoplay = False
if idle_before is True:
should_autoplay = True
elif isinstance(playlist_before, list) and len(playlist_before) == 0:
elif isinstance(playlist_before,
list) and len(playlist_before) == 0:
should_autoplay = True
if should_autoplay and after_len > 0:
idx_to_play = min(max(0, before_len), after_len - 1)
play_resp = _send_ipc_command(
{"command": ["playlist-play-index", idx_to_play], "request_id": 112},
{
"command": ["playlist-play-index",
idx_to_play],
"request_id": 112
},
silent=True,
)
_send_ipc_command(
{"command": ["set_property", "pause", False], "request_id": 113},
{
"command": ["set_property",
"pause",
False],
"request_id": 113
},
silent=True,
)
if play_resp and play_resp.get("error") == "success":
@@ -1462,7 +1597,11 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
if clear_mode:
# Remove item
cmd = {"command": ["playlist-remove", idx], "request_id": 101}
cmd = {
"command": ["playlist-remove",
idx],
"request_id": 101
}
resp = _send_ipc_command(cmd)
if resp and resp.get("error") == "success":
debug(f"Removed: {title}")
@@ -1479,16 +1618,25 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
# Play item
if hydrus_header and _is_hydrus_path(filename, hydrus_url):
header_cmd = {
"command": ["set_property", "http-header-fields", hydrus_header],
"command":
["set_property",
"http-header-fields",
hydrus_header],
"request_id": 198,
}
_send_ipc_command(header_cmd, silent=True)
cmd = {"command": ["playlist-play-index", idx], "request_id": 102}
cmd = {
"command": ["playlist-play-index",
idx],
"request_id": 102
}
resp = _send_ipc_command(cmd)
if resp and resp.get("error") == "success":
# Ensure playback starts (unpause)
unpause_cmd = {
"command": ["set_property", "pause", False],
"command": ["set_property",
"pause",
False],
"request_id": 103,
}
_send_ipc_command(unpause_cmd)
@@ -1523,7 +1671,10 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
file_storage = Store(config)
except Exception as e:
debug(f"Warning: Could not initialize Store registry: {e}", file=sys.stderr)
debug(
f"Warning: Could not initialize Store registry: {e}",
file=sys.stderr
)
# Use the loaded playlist name if available, otherwise default
# Note: current_playlist_name is defined in the load_mode block if a playlist was loaded
@@ -1556,7 +1707,10 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
file_hash = hash_match.group(1)
# Try to find which Hydrus instance has this file
if file_storage:
store_name = _find_hydrus_instance_for_hash(file_hash, file_storage)
store_name = _find_hydrus_instance_for_hash(
file_hash,
file_storage
)
if not store_name:
store_name = "hydrus"
# Check if it's a hash-based local file
@@ -1564,7 +1718,8 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
# Try to extract hash from filename (e.g., C:\path\1e8c46...a1b2.mp4)
path_obj = Path(real_path)
stem = path_obj.stem # filename without extension
if len(stem) == 64 and all(c in "0123456789abcdef" for c in stem.lower()):
if len(stem) == 64 and all(c in "0123456789abcdef"
for c in stem.lower()):
file_hash = stem.lower()
# Find which folder store has this file
if file_storage:
@@ -1574,7 +1729,8 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
# Check if this backend has the file
try:
result_path = backend.get_file(file_hash)
if isinstance(result_path, Path) and result_path.exists():
if isinstance(result_path,
Path) and result_path.exists():
store_name = backend_name
break
except Exception:
@@ -1582,7 +1738,10 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
# Fallback to inferred store if we couldn't find it
if not store_name:
store_name = _infer_store_from_playlist_item(item, file_storage=file_storage)
store_name = _infer_store_from_playlist_item(
item,
file_storage=file_storage
)
# Build PipeObject with proper metadata
pipe_obj = PipeObject(
@@ -1701,8 +1860,10 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
def _start_mpv(
items: List[Any],
config: Optional[Dict[str, Any]] = None,
start_opts: Optional[Dict[str, Any]] = None,
config: Optional[Dict[str,
Any]] = None,
start_opts: Optional[Dict[str,
Any]] = None,
) -> None:
"""Start MPV with a list of items."""
import time as _time_module
@@ -1772,12 +1933,21 @@ def _start_mpv(
time.sleep(0.3) # Give MPV a moment to process the queued items
# Play the first item (index 0) and unpause
play_cmd = {"command": ["playlist-play-index", 0], "request_id": 102}
play_cmd = {
"command": ["playlist-play-index",
0],
"request_id": 102
}
play_resp = _send_ipc_command(play_cmd, silent=True)
if play_resp and play_resp.get("error") == "success":
# Ensure playback starts (unpause)
unpause_cmd = {"command": ["set_property", "pause", False], "request_id": 103}
unpause_cmd = {
"command": ["set_property",
"pause",
False],
"request_id": 103
}
_send_ipc_command(unpause_cmd, silent=True)
debug("Auto-playing first item")