{ config, lib, pkgs, ... }: with lib; let inherit (builtins) typeOf stringLength; cfg = config.programs.mpv; mpvOption = with types; either str (either int (either bool float)); mpvOptions = with types; attrsOf mpvOption; mpvProfiles = with types; attrsOf mpvOptions; mpvBindings = with types; attrsOf str; renderOption = option: rec { int = toString option; float = int; bool = if option then "yes" else "no"; string = option; }.${typeOf option}; renderOptions = options: concatStringsSep "\n" (mapAttrsToList (name: value: let rendered = renderOption value; length = toString (stringLength rendered); in "${name}=%${length}%${rendered}") options); renderProfiles = profiles: concatStringsSep "\n" (mapAttrsToList (name: value: '' [${name}] ${renderOptions value} '') profiles); renderBindings = bindings: concatStringsSep "\n" (mapAttrsToList (name: value: "${name} ${value}") bindings); in { options = { programs.mpv = { enable = mkEnableOption "mpv"; scripts = mkOption { type = with types; listOf (either package str); default = [ ]; example = literalExample "[ pkgs.mpvScripts.mpris ]"; description = '' List of scripts to use with mpv. ''; }; config = mkOption { description = '' Configuration written to ~/.config/mpv/mpv.conf. See mpv 1 for the full list of options. ''; type = mpvOptions; default = { }; example = literalExample '' { profile = "gpu-hq"; force-window = "yes"; ytdl-format = "bestvideo+bestaudio"; cache-default = 4000000; } ''; }; profiles = mkOption { description = '' Sub-configuration options for specific profiles written to ~/.config/mpv/mpv.conf. See for more information. ''; type = mpvProfiles; default = { }; example = literalExample '' { fast = { vo = "vdpau"; }; "protocol.dvd" = { profile-desc = "profile for dvd:// streams"; alang = "en"; }; } ''; }; bindings = mkOption { description = '' Input configuration written to ~/.config/mpv/input.conf. See mpv 1 for the full list of options. ''; type = mpvBindings; default = { }; example = literalExample '' { WHEEL_UP = "seek 10"; WHEEL_DOWN = "seek -10"; "Alt+0" = "set window-scale 0.5"; } ''; }; }; }; config = mkIf cfg.enable (mkMerge [ { home.packages = [ (if cfg.scripts == [ ] then pkgs.mpv else pkgs.wrapMpv pkgs.mpv-unwrapped { scripts = cfg.scripts; }) ]; } (mkIf (cfg.config != { } || cfg.profiles != { }) { xdg.configFile."mpv/mpv.conf".text = '' ${optionalString (cfg.config != { }) (renderOptions cfg.config)} ${optionalString (cfg.profiles != { }) (renderProfiles cfg.profiles)} ''; }) (mkIf (cfg.bindings != { }) { xdg.configFile."mpv/input.conf".text = renderBindings cfg.bindings; }) ]); meta.maintainers = with maintainers; [ tadeokondrak ]; }