home-manager/modules/programs/mpv.nix
polykernel c7592b747b
treewide: prefer XDG variables over dot directories
Currently, dot directories and XDG base directories are used
inconsistently in the Home Manager option declarations. This creates
ambiguity for the user as to where the location of the file should be
albeit this is rarely encountered in practice as it is sufficient to
read upstream documentation. The rationale is to make declarations
consistent and make a clear distinction between hardcoded and modular
specifications.

References to ~/.config in relevant nixpkgs modules were untouched as
the location is hardcoded upstream[1]. Furthermore, modules of
programs which do not follow XDG specifications were also untouched.

Generalization of tilde(~) expansions to $HOME were also considered,
however there isn't sufficient rationale despite the use of $HOME
being more universal. The expansion is standardized in POSIX[2] and is
essentially portable across all shells, thus there is no pragmatic
value to introducing the change.

[1] https://github.com/nixos/nixpkgs/blob/master/pkgs/top-level/impure.nix
[2] https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_01
2021-12-10 23:51:44 +01:00

193 lines
5.3 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
inherit (builtins) typeOf stringLength;
cfg = config.programs.mpv;
mpvOption = with types; either str (either int (either bool float));
mpvOptionDup = with types; either mpvOption (listOf mpvOption);
mpvOptions = with types; attrsOf mpvOptionDup;
mpvProfiles = with types; attrsOf mpvOptions;
mpvBindings = with types; attrsOf str;
mpvDefaultProfiles = with types; listOf str;
renderOption = option:
rec {
int = toString option;
float = int;
bool = if option then "yes" else "no";
string = option;
}.${typeOf option};
renderOptionValue = value:
let
rendered = renderOption value;
length = toString (stringLength rendered);
in "%${length}%${rendered}";
renderOptions = generators.toKeyValue {
mkKeyValue =
generators.mkKeyValueDefault { mkValueString = renderOptionValue; } "=";
listsAsDuplicateKeys = true;
};
renderProfiles = generators.toINI {
mkKeyValue =
generators.mkKeyValueDefault { mkValueString = renderOptionValue; } "=";
listsAsDuplicateKeys = true;
};
renderBindings = bindings:
concatStringsSep "\n"
(mapAttrsToList (name: value: "${name} ${value}") bindings);
renderDefaultProfiles = profiles:
renderOptions { profile = concatStringsSep "," profiles; };
mpvPackage = if cfg.scripts == [ ] then
cfg.package
else
pkgs.wrapMpv pkgs.mpv-unwrapped { scripts = cfg.scripts; };
in {
options = {
programs.mpv = {
enable = mkEnableOption "mpv";
package = mkOption {
type = types.package;
default = pkgs.mpv;
example = literalExpression
"pkgs.wrapMpv (pkgs.mpv-unwrapped.override { vapoursynthSupport = true; }) { youtubeSupport = true; }";
description = ''
Package providing mpv.
'';
};
finalPackage = mkOption {
type = types.package;
readOnly = true;
visible = false;
description = ''
Resulting mpv package.
'';
};
scripts = mkOption {
type = with types; listOf (either package str);
default = [ ];
example = literalExpression "[ pkgs.mpvScripts.mpris ]";
description = ''
List of scripts to use with mpv.
'';
};
config = mkOption {
description = ''
Configuration written to
<filename>$XDG_CONFIG_HOME/mpv/mpv.conf</filename>. See
<citerefentry>
<refentrytitle>mpv</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
for the full list of options.
'';
type = mpvOptions;
default = { };
example = literalExpression ''
{
profile = "gpu-hq";
force-window = true;
ytdl-format = "bestvideo+bestaudio";
cache-default = 4000000;
}
'';
};
profiles = mkOption {
description = ''
Sub-configuration options for specific profiles written to
<filename>$XDG_CONFIG_HOME/mpv/mpv.conf</filename>. See
<option>programs.mpv.config</option> for more information.
'';
type = mpvProfiles;
default = { };
example = literalExpression ''
{
fast = {
vo = "vdpau";
};
"protocol.dvd" = {
profile-desc = "profile for dvd:// streams";
alang = "en";
};
}
'';
};
defaultProfiles = mkOption {
description = ''
Profiles to be applied by default. Options set by them are overridden
by options set in <xref linkend="opt-programs.mpv.config"/>.
'';
type = mpvDefaultProfiles;
default = [ ];
example = [ "gpu-hq" ];
};
bindings = mkOption {
description = ''
Input configuration written to
<filename>$XDG_CONFIG_HOME/mpv/input.conf</filename>. See
<citerefentry>
<refentrytitle>mpv</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
for the full list of options.
'';
type = mpvBindings;
default = { };
example = literalExpression ''
{
WHEEL_UP = "seek 10";
WHEEL_DOWN = "seek -10";
"Alt+0" = "set window-scale 0.5";
}
'';
};
};
};
config = mkIf cfg.enable (mkMerge [
{
assertions = [{
assertion = (cfg.scripts == [ ]) || (cfg.package == pkgs.mpv);
message = ''
The programs.mpv "package" option is mutually exclusive with "scripts" option.'';
}];
}
{
home.packages = [ mpvPackage ];
programs.mpv.finalPackage = mpvPackage;
}
(mkIf (cfg.config != { } || cfg.profiles != { }) {
xdg.configFile."mpv/mpv.conf".text = ''
${optionalString (cfg.defaultProfiles != [ ])
(renderDefaultProfiles cfg.defaultProfiles)}
${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 thiagokokada ];
}