From ad22169efa67448badd870076e441778f4cf7948 Mon Sep 17 00:00:00 2001 From: repparw <45952970+repparw@users.noreply.github.com> Date: Tue, 27 May 2025 21:10:18 -0300 Subject: [PATCH] jellyfin-mpv-shim: add module (#7129) Init of service jellyfin-mpv-shim, emulating plex-mpv-shim already provided. --- modules/lib/maintainers.nix | 6 + modules/modules.nix | 1 + modules/services/jellyfin-mpv-shim.nix | 140 ++++++++++++++++++ .../services/jellyfin-mpv-shim/default.nix | 3 + ...pv-shim-example-settings-expected-bindings | 3 + ...-mpv-shim-example-settings-expected-config | 3 + ...pv-shim-example-settings-expected-settings | 8 + .../jellyfin-mpv-shim-example-settings.nix | 39 +++++ 8 files changed, 203 insertions(+) create mode 100644 modules/services/jellyfin-mpv-shim.nix create mode 100644 tests/modules/services/jellyfin-mpv-shim/default.nix create mode 100644 tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-bindings create mode 100644 tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-config create mode 100644 tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-settings create mode 100644 tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings.nix diff --git a/modules/lib/maintainers.nix b/modules/lib/maintainers.nix index f2657a82c..42020b63b 100644 --- a/modules/lib/maintainers.nix +++ b/modules/lib/maintainers.nix @@ -734,6 +734,12 @@ } ]; }; + repparw = { + name = "repparw"; + email = "ubritos@gmail.com"; + github = "repparw"; + githubId = 45952970; + }; rosuavio = { name = "Rosario Pulella"; email = "RosarioPulella@gmail.com"; diff --git a/modules/modules.nix b/modules/modules.nix index ea2e70c5a..e3e9ac198 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -387,6 +387,7 @@ let ./services/hyprsunset.nix ./services/imapnotify.nix ./services/jankyborders.nix + ./services/jellyfin-mpv-shim.nix ./services/kanshi.nix ./services/kbfs.nix ./services/kdeconnect.nix diff --git a/modules/services/jellyfin-mpv-shim.nix b/modules/services/jellyfin-mpv-shim.nix new file mode 100644 index 000000000..dd4fc5f1d --- /dev/null +++ b/modules/services/jellyfin-mpv-shim.nix @@ -0,0 +1,140 @@ +{ + config, + lib, + pkgs, + ... +}: +let + inherit (builtins) typeOf stringLength; + jsonFormat = pkgs.formats.json { }; + cfg = config.services.jellyfin-mpv-shim; + + renderOption = + option: + rec { + int = toString option; + float = int; + bool = lib.hm.booleans.yesNo option; + string = option; + } + .${typeOf option}; + + renderOptionValue = + value: + let + rendered = renderOption value; + length = toString (stringLength rendered); + in + "%${length}%${rendered}"; + + renderOptions = lib.generators.toKeyValue { + mkKeyValue = lib.generators.mkKeyValueDefault { mkValueString = renderOptionValue; } "="; + listsAsDuplicateKeys = true; + }; + + renderBindings = + bindings: lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "${name} ${value}") bindings); +in +{ + meta.maintainers = [ lib.hm.maintainers.repparw ]; + + options = { + services.jellyfin-mpv-shim = { + enable = lib.mkEnableOption "Jellyfin mpv shim"; + + package = lib.mkPackageOption pkgs "jellyfin-mpv-shim" { }; + + settings = lib.mkOption { + type = jsonFormat.type; + default = { }; + example = lib.literalExpression '' + { + allow_transcode_to_h265 = false; + always_transcode = false; + audio_output = "hdmi"; + auto_play = true; + fullscreen = true; + player_name = "mpv-shim"; + } + ''; + description = '' + Configuration written to + {file}`$XDG_CONFIG_HOME/jellyfin-mpv-shim/conf.json`. See + + for the configuration documentation. + ''; + }; + + mpvConfig = lib.mkOption { + type = lib.types.nullOr ( + lib.types.attrsOf ( + lib.types.either lib.types.str ( + lib.types.either lib.types.int (lib.types.either lib.types.bool lib.types.float) + ) + ) + ); + default = null; + example = lib.literalExpression '' + { + profile = "gpu-hq"; + force-window = true; + }''; + description = '' + mpv configuration options to use for jellyfin-mpv-shim. + If null, jellyfin-mpv-shim will use its default mpv configuration. + ''; + }; + + mpvBindings = lib.mkOption { + type = lib.types.nullOr (lib.types.attrsOf lib.types.str); + default = null; + example = lib.literalExpression '' + { + WHEEL_UP = "seek 10"; + WHEEL_DOWN = "seek -10"; + }''; + description = '' + mpv input bindings to use for jellyfin-mpv-shim. + If null, jellyfin-mpv-shim will use its default input configuration. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "services.jellyfin-mpv-shim" pkgs lib.platforms.linux) + ]; + + xdg.configFile = { + "jellyfin-mpv-shim/conf.json" = lib.mkIf (cfg.settings != { }) { + source = jsonFormat.generate "jellyfin-mpv-shim-conf" cfg.settings; + }; + + "jellyfin-mpv-shim/mpv.conf" = lib.mkIf (cfg.mpvConfig != null) { + text = renderOptions cfg.mpvConfig; + }; + + "jellyfin-mpv-shim/input.conf" = lib.mkIf (cfg.mpvBindings != null) { + text = renderBindings cfg.mpvBindings; + }; + }; + + systemd.user.services.jellyfin-mpv-shim = { + Unit = { + Description = "Jellyfin mpv shim"; + Documentation = "https://github.com/jellyfin/jellyfin-mpv-shim"; + After = [ "graphical-session.target" ]; + PartOf = [ "graphical-session.target" ]; + }; + + Service = { + ExecStart = "${lib.getExe cfg.package}"; + }; + + Install = { + WantedBy = [ "graphical-session.target" ]; + }; + }; + }; +} diff --git a/tests/modules/services/jellyfin-mpv-shim/default.nix b/tests/modules/services/jellyfin-mpv-shim/default.nix new file mode 100644 index 000000000..3b9717c81 --- /dev/null +++ b/tests/modules/services/jellyfin-mpv-shim/default.nix @@ -0,0 +1,3 @@ +{ + jellyfin-mpv-shim-example-settings = ./jellyfin-mpv-shim-example-settings.nix; +} diff --git a/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-bindings b/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-bindings new file mode 100644 index 000000000..7d8633321 --- /dev/null +++ b/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-bindings @@ -0,0 +1,3 @@ +Alt+0 set window-scale 0.5 +WHEEL_DOWN seek -10 +WHEEL_UP seek 10 diff --git a/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-config b/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-config new file mode 100644 index 000000000..dfd8f0dc4 --- /dev/null +++ b/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-config @@ -0,0 +1,3 @@ +cache-default=%7%4000000 +force-window=%3%yes +ytdl-format=%19%bestvideo+bestaudio diff --git a/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-settings b/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-settings new file mode 100644 index 000000000..5b6cebd0a --- /dev/null +++ b/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings-expected-settings @@ -0,0 +1,8 @@ +{ + "allow_transcode_to_h265": false, + "always_transcode": false, + "audio_output": "hdmi", + "auto_play": true, + "fullscreen": true, + "player_name": "mpv-shim" +} diff --git a/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings.nix b/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings.nix new file mode 100644 index 000000000..e9a8e918b --- /dev/null +++ b/tests/modules/services/jellyfin-mpv-shim/jellyfin-mpv-shim-example-settings.nix @@ -0,0 +1,39 @@ +{ ... }: +{ + services.jellyfin-mpv-shim = { + enable = true; + + settings = { + allow_transcode_to_h265 = false; + always_transcode = false; + audio_output = "hdmi"; + auto_play = true; + fullscreen = true; + player_name = "mpv-shim"; + }; + + mpvBindings = { + WHEEL_UP = "seek 10"; + WHEEL_DOWN = "seek -10"; + "Alt+0" = "set window-scale 0.5"; + }; + + mpvConfig = { + force-window = true; + ytdl-format = "bestvideo+bestaudio"; + cache-default = 4000000; + }; + }; + + nmt.script = '' + assertFileContent \ + home-files/.config/jellyfin-mpv-shim/conf.json \ + ${./jellyfin-mpv-shim-example-settings-expected-settings} + assertFileContent \ + home-files/.config/jellyfin-mpv-shim/mpv.conf \ + ${./jellyfin-mpv-shim-example-settings-expected-config} + assertFileContent \ + home-files/.config/jellyfin-mpv-shim/input.conf \ + ${./jellyfin-mpv-shim-example-settings-expected-bindings} + ''; +}