Media

Media Playback — mpv

Configuration adapted from Samillion/mpv-conf, with custom scripts from Sam’s companion repos: ModernZ (OSC fork), mpv-boxtowide, mpv-ytdlautoformat. Adapted for Linux + NVIDIA Pascal (see §Linux Adaptations).

Architecture

config/mpv/
├── mpv.conf              # Main configuration (High Quality profile)
├── input.conf            # Custom keybindings
├── menu.conf             # Right-click context menu
├── fonts/
│   └── modernz-icons.ttf # ModernZ OSC icon font (custom, not in nixpkgs)
├── script-opts/
│   ├── boxtowide.conf
│   ├── modernz.conf
│   ├── pause_indicator_lite.conf
│   ├── pip_lite.conf
│   ├── thumbfast.conf
│   └── ytdlautoformat.conf
└── scripts/
    ├── boxtowide.lua           # Auto-convert 4:3 → 16:9
    ├── pause_indicator_lite.lua # Pause icon overlay
    ├── pip_lite.lua             # Picture-in-Picture toggle
    └── ytdlautoformat.lua      # Auto yt-dlp format for streams

Scripts injected via Nix wrapper (mpv-with-scripts, see modules/desktop/media/video.nix):

ScriptSourcePurpose
modernznixpkgs mpvScripts.modernzModern OSC — clean UI with fluent icons
thumbfastnixpkgs mpvScripts.thumbfastThumbnail preview on seekbar hover
sponsorblock-minimalnixpkgs mpvScripts.sponsorblock-minimalSkip sponsor segments (lightweight)
mprisnixpkgs mpvScripts.mprisDesktop media integration (play/pause/skip)

Scripts built into mpv 0.41 (compiled into the binary):

ScriptKey bindings
select.luaselect/select-playlist, select/menu, select/show-properties
stats.luastats/display-stats, stats/display-stats-toggle
console.luaconsole/enable
context_menu.luaRight-click → menu.conf
positioning.luapositioning/cursor-centric-zoom (image viewer)
commands.luacommands/open (command palette)

Hardware Configuration

SettingValueNotes
profilehigh-qualityDemanding defaults — requires capable GPU
vogpu-nextModern Vulkan-based output
gpu-apivulkanNVIDIA Pascal driver support
hwdecauto-safeNVDEC when available, software fallback otherwise
debandyesReduce color banding
sigmoid-upscalingyesBetter upscaling quality

Auto-Profiles

Profiles apply automatically based on conditions:

ProfileTriggerEffect
[Video]Any video playingTaskbar progress
[Image]Image file openedImage viewer mode (infinite display, no screensaver)
[Stream]URL detected (yt-dlp)Smaller cache, stream title, user-agent
[Media]Path contains /mnt/nas/video/ or /video/Large cache (1.5 GiB), stereo downmix, dialogue normalization
[2K+]Video height >= 1440pDisable subtitle blending for performance
[Window-PiP]Always-on-top + not fullscreenCompact ModernZ for PiP mode
[Minimized]Window minimizedAuto-pause
[Autofit-Small]Manual (F11)50% window size
[Autofit-Normal]Manual (F12)80% window size

Keybindings

input-default-bindings=no is set — all defaults are disabled. The following are the custom bindings.

Mouse

KeyAction
Left double-clickToggle fullscreen
Right-clickContext menu (menu.conf)

Playback

KeyAction
SPACE / KP_INSPlay/Pause
qQuit
QQuit (save position)
ESCExit fullscreen
f / KP5Toggle fullscreen
vToggle ModernZ OSC visibility
OCycle OSD detail level
iShow playback stats
IToggle persistent stats
ENTER / KP_ENTERShow progress bar
KeyAction
RIGHT / LEFT / KP6 / KP4Seek ±2s
HOMESeek to start
. / ,Frame step forward/back
FORWARD / REWIND (media keys)Seek ±10s
b / n / PGDWN / KP9Next file
p / PGUP / KP7Previous file
lToggle A-B loop
BSReset speed to 1.0×

Volume

KeyAction
UP / DOWN / KP8 / KP2Volume ±2
m / MUTEToggle mute
KeyAction
g-mOpen select menu
g-pToggle ModernZ persistent progress
g-cOpen console (type paths, commands)
Ctrl+pSelect playlist entry
F11Apply Autofit-Small (50%)
F12Apply Autofit-Normal (80%)

Image Viewer

KeyAction
WHEEL_UP / WHEEL_DOWNZoom centered on cursor
0Reset position/zoom

Number Pad

KeyAction
KP9 / KP7Next/Prev file
KP6 / KP4Seek ±2s
KP8 / KP2Volume ±2
KP5Fullscreen
KP_INSPlay/Pause
KP_ENTERShow progress
KP_DELQuit

Jellyfin Integration

jellyfin-mpv-shim is configured to use external mpv mode (mpv_ext: true) so the mpv-with-scripts wrapper is spawned instead of bare libmpv. See modules/services/media/jellyfin.nix.

Config mirroring

Six paths from ~/.config/mpv/ are symlinked into ~/.config/jellyfin-mpv-shim/: mpv.conf, input.conf, menu.conf, script-opts/, fonts/, scripts/.

With mpv_ext_no_ovr: true, mpv reads from ~/.config/mpv/ directly — the shim symlinks are a safety net for edge cases:

  • The activation script hasn’t run yet (bootstrap gap: first launch creates conf.json with defaults, next rebuild patches it)
  • mpv_ext_no_ovr has had bugs in past jellyfin-mpv-shim releases
  • User manually sets mpv_ext_no_ovr: false

The two runtime-mutable files (conf.json, cred.json) are NOT managed by Nix.

Fonts

FontSourceUsed by
MontserratSystem package montserratOSD text (osd-font), subtitles (sub-font)
Robotofonts.packages = [pkgs.roboto] in video.nixModernZ OSC text (font=Roboto in modernz.conf)
ModernZ Iconsconfig/mpv/fonts/modernz-icons.ttfOSC fluent icons (play/pause/volume/etc.)

Why modernz-icons.ttf is in config/mpv/fonts/

mpv auto-loads all fonts from <config-dir>/fonts/ (~/.config/mpv/fonts/) at startup. The ModernZ script references icon_font = "modernz-icons" — this matches the font family name embedded in the ttf.

The nixpkgs mpvScripts.modernz package also ships modernz-icons.ttf at share/fonts/truetype/, but mpv’s wrapper fonts.conf does NOT include nix store font paths — only system fontconfig directories. Without the local copy, ModernZ icons would render as tofu (□). Placing it in config/mpv/fonts/ ensures mpv discovers it reliably via the ~~/fonts/ auto-load mechanism.

Linux Adaptations from Sam’s Config

Sam’s (Windows)Ours (Linux)
hwdec=d3d11vahwdec=auto-safe + gpu-api=vulkan
sub-file-paths with ; separator: separator
taskbar-progress=yesRemoved (not available on Linux)
screenshot-template=~/Desktop/...~/pictures/screenshots/mpv/...
[Media] profile: Windows pathsPaths: /mnt/nas/video/, /video/
open_file Lua script (file dialog)Disabled (Windows-only); use console (g-c) or drag-and-drop
thumbnail=D:\...\thumbfast.outDefault cache path (~~/cache/)