The cache_pause=yes change (ac3939e) broke first-click popout playback — mpv paused indefinitely waiting for cache fill on uncached videos. Reverted to cache_pause=no. Kept the demuxer_max_bytes bump (50→150MiB) which reduces stutter on network streams by giving mpv more buffer headroom without changing the pause/play behavior. behavior change
90 lines
3.6 KiB
Python
90 lines
3.6 KiB
Python
"""Pure helpers that build the kwargs dict passed to ``mpv.MPV`` and
|
|
the post-construction options dict applied via the property API.
|
|
|
|
Kept free of any Qt or mpv imports so the options can be audited from
|
|
a CI test that only installs the stdlib.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
# FFmpeg ``protocol_whitelist`` value applied via mpv's
|
|
# ``demuxer-lavf-o`` option (audit finding #2). ``file`` must stay so
|
|
# cached local clips and ``.part`` files keep playing; ``http``/
|
|
# ``https``/``tls``/``tcp`` are needed for fresh network video.
|
|
# ``crypto`` is intentionally omitted — it's an FFmpeg pseudo-protocol
|
|
# for AES-decrypted streams that boorus do not legitimately serve.
|
|
LAVF_PROTOCOL_WHITELIST = "file,http,https,tls,tcp"
|
|
|
|
|
|
def lavf_options() -> dict[str, str]:
|
|
"""Return the FFmpeg lavf demuxer options to apply post-construction.
|
|
|
|
These cannot be set via ``mpv.MPV(**kwargs)`` because python-mpv's
|
|
init path uses ``mpv_set_option_string``, which routes through
|
|
mpv's keyvalue list parser. That parser splits on ``,`` to find
|
|
entries, so the comma-laden ``protocol_whitelist`` value gets
|
|
shredded into orphan tokens and mpv rejects the option with
|
|
-7 OPT_FORMAT. mpv's documented backslash escape (``\\,``) is
|
|
not unescaped on this code path either.
|
|
|
|
The post-construction property API DOES accept dict values for
|
|
keyvalue-list options via the node API, so we set them after
|
|
``mpv.MPV()`` returns. Caller pattern:
|
|
|
|
m = mpv.MPV(**build_mpv_kwargs(is_windows=...))
|
|
for k, v in lavf_options().items():
|
|
m["demuxer-lavf-o"] = {k: v}
|
|
"""
|
|
return {"protocol_whitelist": LAVF_PROTOCOL_WHITELIST}
|
|
|
|
|
|
def build_mpv_kwargs(is_windows: bool) -> dict[str, object]:
|
|
"""Return the kwargs dict for constructing ``mpv.MPV``.
|
|
|
|
The playback, audio, and network options are unchanged from
|
|
pre-audit v0.2.5. The security hardening added by SECURITY_AUDIT.md
|
|
finding #2 is:
|
|
|
|
- ``ytdl="no"``: refuse to delegate URL handling to yt-dlp. mpv's
|
|
default enables a yt-dlp hook script that matches ~1500 hosts
|
|
and shells out to ``yt-dlp`` on any URL it recognizes. A
|
|
compromised booru returning ``file_url: "https://youtube.com/..."``
|
|
would pull the user through whatever extractor CVE is current.
|
|
|
|
- ``load_scripts="no"``: do not auto-load Lua scripts from
|
|
``~/.config/mpv/scripts``. These scripts run in mpv's context
|
|
every time the widget is created.
|
|
|
|
- ``input_conf="/dev/null"`` (POSIX only): skip loading
|
|
``~/.config/mpv/input.conf``. The existing
|
|
``input_default_bindings=False`` + ``input_vo_keyboard=False``
|
|
are the primary lockdown; this is defense-in-depth. Windows
|
|
uses a different null-device path and the load behavior varies
|
|
by mpv build, so it is skipped there.
|
|
|
|
The ffmpeg protocol whitelist (also part of finding #2) is NOT
|
|
in this dict — see ``lavf_options`` for the explanation.
|
|
"""
|
|
kwargs: dict[str, object] = {
|
|
"vo": "libmpv",
|
|
"hwdec": "auto",
|
|
"keep_open": "yes",
|
|
"ao": "pulse,wasapi,",
|
|
"audio_client_name": "booru-viewer",
|
|
"input_default_bindings": False,
|
|
"input_vo_keyboard": False,
|
|
"osc": False,
|
|
"vd_lavc_fast": "yes",
|
|
"vd_lavc_skiploopfilter": "nonkey",
|
|
"cache": "yes",
|
|
"cache_pause": "no",
|
|
"demuxer_max_bytes": "150MiB",
|
|
"demuxer_readahead_secs": "20",
|
|
"network_timeout": "10",
|
|
"ytdl": "no",
|
|
"load_scripts": "no",
|
|
}
|
|
if not is_windows:
|
|
kwargs["input_conf"] = "/dev/null"
|
|
return kwargs
|