This commit is contained in:
2026-03-23 21:47:25 -07:00
parent 23a73a94e6
commit 96f327e4dc
6 changed files with 166 additions and 81 deletions

View File

@@ -5993,16 +5993,23 @@ mp.add_timeout(0, function()
_lua_log('lyric-helper auto-start raised: ' .. tostring(lyric_err))
end
-- Try to re-register right-click after UOSC loads (might override its binding)
mp.add_timeout(1.0, function()
_lua_log('[KEY] attempting to re-register mbtn_right after UOSC loaded')
pcall(function()
mp.add_key_binding("mbtn_right", "medios-menu-right-click-late", function()
_lua_log('[KEY] mbtn_right pressed (late registration attempt)')
-- Force-claim mbtn_right so the Medios menu fires reliably regardless of
-- whether uosc has a cursor zone active at the click position.
-- mp.add_forced_key_binding has higher priority than uosc's force-group.
-- Use complex=true to get the event type and fire only on button release.
local ok_rclick, rclick_err = pcall(function()
mp.add_forced_key_binding('mbtn_right', 'medios-mbtn-right-forced', function(e)
if e and e.event == 'up' then
_lua_log('[KEY] mbtn_right up -> show_menu')
M.show_menu()
end, {repeatable=false})
end)
end
end, {complex = true, repeatable = false})
end)
if ok_rclick then
_lua_log('[KEY] registered forced mbtn_right binding')
else
_lua_log('[KEY] forced mbtn_right failed: ' .. tostring(rclick_err) .. ' (falling back to input.conf)')
end
end)
return M

View File

@@ -1166,11 +1166,6 @@ class MPVIPCClient:
rid = request["request_id"]
payload = json.dumps(request) + "\n"
# Debug: log the command being sent
from SYS.logger import debug as _debug
_debug(f"[IPC] Sending: {payload.strip()}")
# Send command
self._write_payload(payload)
@@ -1199,11 +1194,6 @@ class MPVIPCClient:
continue
resp = json.loads(line)
# Debug: log responses
from SYS.logger import debug as _debug
_debug(f"[IPC] Received: {line}")
# Check if this is the response to our request
if resp.get("request_id") == request.get("request_id"):
return resp

View File

@@ -1766,27 +1766,35 @@ def main(argv: Optional[list[str]] = None) -> int:
# Keep trying.
time.sleep(0.10)
command_client = MPVIPCClient(socket_path=str(args.ipc), timeout=0.75, silent=True)
use_shared_ipc_client = platform.system() == "Windows"
command_client = None if use_shared_ipc_client else MPVIPCClient(socket_path=str(args.ipc), timeout=0.75, silent=True)
def _send_helper_command(command: Any, label: str = "") -> bool:
with command_client_lock:
target_client = client if use_shared_ipc_client else command_client
if target_client is None:
return False
try:
if command_client.sock is None:
if not command_client.connect():
if target_client.sock is None:
if use_shared_ipc_client:
if note_ipc_unavailable is not None:
note_ipc_unavailable(f"helper-command-connect:{label or '?'}")
return False
if not target_client.connect():
_append_helper_log(
f"[helper-ipc] connect failed label={label or '?'}"
)
_note_ipc_unavailable(f"helper-command-connect:{label or '?' }")
return False
_mark_ipc_alive(f"helper-command-connect:{label or '?'}")
rid = command_client.send_command_no_wait(command)
rid = target_client.send_command_no_wait(command)
if rid is None:
_append_helper_log(
f"[helper-ipc] send failed label={label or '?'}"
)
_note_ipc_unavailable(f"helper-command-send:{label or '?'}")
try:
command_client.disconnect()
target_client.disconnect()
except Exception:
pass
return False
@@ -1798,7 +1806,7 @@ def main(argv: Optional[list[str]] = None) -> int:
)
_note_ipc_unavailable(f"helper-command-exception:{label or '?'}")
try:
command_client.disconnect()
target_client.disconnect()
except Exception:
pass
return False
@@ -1906,19 +1914,24 @@ def main(argv: Optional[list[str]] = None) -> int:
except Exception:
pass
_start_ready_heartbeat(
str(args.ipc),
stop_event,
_mark_ipc_alive,
_note_ipc_unavailable,
)
_start_request_poll_loop(
str(args.ipc),
stop_event,
_process_request,
_mark_ipc_alive,
_note_ipc_unavailable,
)
if use_shared_ipc_client:
_append_helper_log(
"[helper] Windows single-client IPC mode enabled; auxiliary heartbeat/poll disabled"
)
else:
_start_ready_heartbeat(
str(args.ipc),
stop_event,
_mark_ipc_alive,
_note_ipc_unavailable,
)
_start_request_poll_loop(
str(args.ipc),
stop_event,
_process_request,
_mark_ipc_alive,
_note_ipc_unavailable,
)
# Pre-compute store choices at startup and publish to a cached property so Lua
# can read immediately without waiting for a request/response cycle (which may timeout).
@@ -2075,10 +2088,11 @@ def main(argv: Optional[list[str]] = None) -> int:
_append_helper_log(f"[helper] exiting reason={shutdown_reason}")
except Exception:
pass
try:
command_client.disconnect()
except Exception:
pass
if command_client is not None:
try:
command_client.disconnect()
except Exception:
pass
try:
client.disconnect()
except Exception:

View File

@@ -68,7 +68,7 @@ loop-file
# Enable the screensaver when images are kept open forever.
[screensaver]
profile-cond=p['current-tracks/video'].image and image_display_duration == math.huge
profile-cond=get('current-tracks/video', {}).image and image_display_duration == math.huge
profile-restore=copy
stop-screensaver=no

View File

@@ -249,7 +249,7 @@ function TopBar:render()
local button_fg = is_hover and (button.hover_fg or bg) or fg
local button_bg = is_hover and (button.hover_bg or fg) or bg
cursor:zone('primary_down', rect, button.command)
cursor:zone('primary_click', rect, button.command)
local bg_size = self.size - margin
local bg_ax, bg_ay = rect.ax + (is_left and margin or 0), rect.ay + margin
@@ -302,7 +302,7 @@ function TopBar:render()
if left_aligned then title_bx = rect.ax - margin else title_ax = rect.bx + margin end
-- Click action
cursor:zone('primary_down', rect, function() mp.command('script-binding uosc/playlist') end)
cursor:zone('primary_click', rect, function() mp.command('script-binding uosc/playlist') end)
end
-- Skip rendering titles if there's not enough horizontal space
@@ -325,7 +325,7 @@ function TopBar:render()
local title_rect = {ax = ax, ay = title_ay, bx = ax + rect_width, by = by}
if options.top_bar_alt_title_place == 'toggle' then
cursor:zone('primary_down', title_rect, function() self:toggle_title() end)
cursor:zone('primary_click', title_rect, function() self:toggle_title() end)
end
ass:rect(title_rect.ax, title_rect.ay, title_rect.bx, title_rect.by, {
@@ -415,7 +415,7 @@ function TopBar:render()
-- Click action
rect.bx = time_bx
cursor:zone('primary_down', rect, function() mp.command('script-binding uosc/chapters') end)
cursor:zone('primary_click', rect, function() mp.command('script-binding uosc/chapters') end)
title_ay = rect.by + self.title_spacing
end

View File

@@ -173,6 +173,89 @@ def _apply_log_filter(lines: Sequence[str], filter_text: Optional[str]) -> List[
return filtered
def _collapse_repeated_log_lines(lines: Sequence[str]) -> List[str]:
collapsed: List[str] = []
last_line: Optional[str] = None
repeat_count = 0
def flush() -> None:
nonlocal last_line, repeat_count
if last_line is None:
return
if repeat_count > 1:
collapsed.append(f"{last_line} [repeated x{repeat_count}]")
else:
collapsed.append(last_line)
last_line = None
repeat_count = 0
for raw in lines:
line = str(raw or "")
if line == last_line:
repeat_count += 1
continue
flush()
last_line = line
repeat_count = 1
flush()
return collapsed
def _is_noisy_mpv_log_line(line: str) -> bool:
text = str(line or "")
lower = text.lower()
noisy_tokens = (
"client connected",
"client disconnected",
"destroying client handle",
"set property: options/log-file",
"set property: options/msg-level",
"run command: script-message-to, flags=64, args=[target=\"console\", args=\"log\"",
"run command: script-message-to, flags=64, args=[target=\"console\", args=\"print\"",
)
if any(token in lower for token in noisy_tokens):
return True
startup_prefixes = (
"mpv v",
" built on ",
"libplacebo version:",
"ffmpeg version:",
"ffmpeg library versions:",
" libavcodec",
" libavdevice",
" libavfilter",
" libavformat",
" libavutil",
" libswresample",
" libswscale",
"configuration:",
"list of enabled features:",
"built with ndebug.",
)
# Log lines look like [timestamp][level][module] content — strip 3 brackets.
stripped = lower.split(']', 3)
payload = stripped[-1].strip() if len(stripped) > 1 else lower.strip()
return any(prefix in payload for prefix in startup_prefixes)
def _focus_mpv_log_lines(lines: Sequence[str]) -> List[str]:
focused = [str(line) for line in lines if not _is_noisy_mpv_log_line(str(line))]
return _collapse_repeated_log_lines(focused)
def _focus_db_log_rows(
rows: Sequence[tuple[Any, Any, Any, Any]],
) -> List[str]:
rendered: List[str] = []
for timestamp, level, _module, message in rows:
ts = str(timestamp or "").strip()
prefix = f"[{ts}] [{level}] " if ts else f"[{level}] "
rendered.append(prefix + str(message or ""))
return _collapse_repeated_log_lines(rendered)
def _slice_mpv_log_to_latest_run(lines: Sequence[str]) -> List[str]:
startup_pattern = re.compile(r"\bmpv v\d", re.IGNORECASE)
collected = list(lines)
@@ -296,7 +379,7 @@ def _try_enable_mpv_file_logging(mpv_log_path: str, *, attempts: int = 3) -> boo
{
"command": ["set_property",
"options/msg-level",
"all=v"]
"cplayer=info,ffmpeg=error,ipc=warn"]
}
)
ok = bool(
@@ -1585,10 +1668,9 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
try:
# Default: keep `.pipe` quiet even if debug is enabled.
# With -log: enable debug and route it to stdout (pipeable), plus enable mpv log-file.
# With -log: keep transport chatter quiet and print an explicit focused
# report later in this function.
if log_requested:
set_debug(True)
set_thread_stream(sys.stdout)
try:
log_dir = _repo_log_dir()
mpv_log_path = str((log_dir / "medeia-mpv.log").resolve())
@@ -1606,8 +1688,6 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
pass
except Exception:
pass
debug(f"MPV log file: {mpv_log_path}")
# Try to enable mpv file logging on the currently running instance.
# (If mpv wasn't started with --log-file, this may not work everywhere.)
try:
@@ -1620,7 +1700,7 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
mpv_live = MPV()
if mpv_live.is_running():
mpv_live.set_property("options/log-file", mpv_log_path)
mpv_live.set_property("options/msg-level", "all=v")
mpv_live.set_property("options/msg-level", "cplayer=info,ffmpeg=error,ipc=warn")
except Exception:
pass
else:
@@ -2319,7 +2399,9 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
break
latest_run_tail = _slice_mpv_log_to_latest_run(tail_lines)
filtered_tail = _apply_log_filter(latest_run_tail, log_filter_text)
filtered_tail = _focus_mpv_log_lines(
_apply_log_filter(latest_run_tail, log_filter_text)
)
helper_heartbeat = _get_mpv_property("user-data/medeia-pipeline-ready")
helper_status = "not running"
@@ -2327,25 +2409,6 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
helper_status = f"running ({helper_heartbeat})"
print(f"Pipeline helper: {helper_status}")
if filtered_tail:
title = "MPV log (latest run tail"
if log_filter_text:
title += f" filtered by '{log_filter_text}'"
title += "):"
print(title)
for ln in filtered_tail:
print(ln)
else:
if log_filter_text:
print(f"MPV log (tail): <no entries match filter '{log_filter_text}'>")
else:
print("MPV log (latest run tail): <empty>")
print(
"Note: On some Windows builds, mpv cannot start writing to --log-file after launch."
)
print(
"If you need full [main2] logs, restart mpv so it starts with --log-file."
)
# Print database logs for mpv module (helper + lua output)
try:
@@ -2367,12 +2430,9 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
if marker_msg:
print(f"Run marker: {marker_msg}")
if mpv_logs:
for timestamp, level, _module, message in mpv_logs:
ts = str(timestamp or "").strip()
if ts:
print(f"[{ts}] [{level}] {message}")
else:
print(f"[{level}] {message}")
print("Medios MPV logs (latest run, focused):")
for line in _focus_db_log_rows(mpv_logs):
print(line)
else:
if log_filter_text:
print(f"(no latest-run mpv logs found matching '{log_filter_text}')")
@@ -2382,6 +2442,20 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
debug(f"Could not fetch database logs: {e}")
pass
if filtered_tail:
title = "MPV core log (latest run, filtered)"
if log_filter_text:
title += f" for '{log_filter_text}'"
title += ":"
print(title)
for ln in filtered_tail:
print(ln)
else:
if log_filter_text:
print(f"MPV core log: <no focused entries match filter '{log_filter_text}'>")
else:
print("MPV core log: <no focused entries>")
fallback_logs = [
("Medeia Lua log file tail", str(_lua_log_file())),
("Medeia helper log file tail", str(_helper_log_file())),
@@ -2391,7 +2465,7 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
lines = _tail_text_file(path, max_lines=120)
except Exception:
lines = []
lines = _apply_log_filter(lines, log_filter_text)
lines = _collapse_repeated_log_lines(_apply_log_filter(lines, log_filter_text))
if not lines:
continue
print(f"{title}:")
@@ -2481,7 +2555,7 @@ def _start_mpv(
mpv_log_path = (start_opts or {}).get("mpv_log_path")
if isinstance(mpv_log_path, str) and mpv_log_path.strip():
extra_args.append(f"--log-file={mpv_log_path}")
extra_args.append("--msg-level=all=v")
extra_args.append("--msg-level=cplayer=info,ffmpeg=error,ipc=warn")
# Always start MPV with the bundled Lua script via MPV class.
mpv.start(