From 69909f5b4c163f1a6afaaa65b30ad2c88af209c3 Mon Sep 17 00:00:00 2001 From: Pierre Kisters <1524059+lhns@users.noreply.github.com> Date: Tue, 29 Sep 2026 00:08:10 +0200 Subject: [PATCH] jellyfin: hardware decoding through a desktop entry, not an override The shim's permissions (devices=all, its store path, LD_PRELOAD, SFN_MPV_HWDEC) were a Flatpak override: through nix-flatpak's services.flatpak.overrides, whose override file outlives the configuration (it left an empty file behind), or a Home Manager link that `flatpak override --user` would replace (hence `force`). Now a desktop entry shadowing the Flatpak's (same ID, same fields and actions; also what the "+" menu sees) passes them as `flatpak run` options (--device=all --filesystem=:ro --env=...), so nothing is written to Flatpak's overrides and they disappear with the entry. jellyfin.hardwareDecoding.command is that command line for a terminal. The entries earlier versions put into the override file are removed by steam-frame-nix-cleanup. Checked with `flatpak run ... --command=sh`: the shim's store path is visible read-only, the environment is set and /dev/video* is there. --- modules/jellyfin.nix | 97 ++++++++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 34 deletions(-) diff --git a/modules/jellyfin.nix b/modules/jellyfin.nix index 47f44cc..815c55f 100644 --- a/modules/jellyfin.nix +++ b/modules/jellyfin.nix @@ -5,31 +5,30 @@ # exists), and Jellyfin hard-sets mpv's hwdec=auto-copy, whose probe list # leaves out V4L2 M2M, without a way to pass mpv options. So: # - an LD_PRELOAD shim (jellyfin/mpv-hwdec-shim.c) rewrites an "auto*" hwdec -# to $SFN_MPV_HWDEC. Preloaded from the store: the override exposes just -# its store path (read-only) to the sandbox. -# - override: devices=all, that filesystem, LD_PRELOAD, SFN_MPV_HWDEC. -# Through nix-flatpak's services.flatpak.overrides if it is imported and -# enabled (merged with the user's own overrides there); else home-manager -# owns the app's override file. -{ config, options, lib, pkgs, ... }: +# to $SFN_MPV_HWDEC. Preloaded from the store: only its store path is +# exposed (read-only) to the sandbox. +# - a desktop entry shadowing the Flatpak's (same ID, also seen by the "+" +# menu) starts it with those permissions as `flatpak run` options +# (--device=all, --filesystem, --env): nothing is written to Flatpak's +# override files, so they apply only to launches from this entry and +# disappear with it. +# Earlier versions used an override file (nix-flatpak or Home Manager); +# steam-frame-nix-cleanup removes their entries. +{ config, lib, pkgs, ... }: let cfg = config.steamFrame.jellyfin.hardwareDecoding; app = "org.jellyfin.JellyfinDesktop"; shim = pkgs.callPackage ./jellyfin/shim.nix { }; - override = { - Context = { devices = [ "all" ]; filesystems = [ "${shim}:ro" ]; }; - Environment = { LD_PRELOAD = "${shim}/lib/mpv-hwdec-shim.so"; SFN_MPV_HWDEC = cfg.hwdec; }; - }; - - useNixFlatpak = options ? services.flatpak.overrides && config.services.flatpak.enable; - - # Flatpak's keyfile format (lists as "a;b;"). - overrideFile = pkgs.writeText "${app}-override" (lib.concatStringsSep "\n" (lib.mapAttrsToList - (section: entries: "[${section}]\n" + lib.concatStrings (lib.mapAttrsToList (key: value: - "${key}=${if lib.isList value then lib.concatMapStrings (v: "${v};") value else value}\n") entries)) - override)); + run = lib.concatStringsSep " " [ + "flatpak run --branch=stable --arch=aarch64 --command=jellyfin-desktop" + "--device=all" + "--filesystem=${shim}:ro" + "--env=LD_PRELOAD=${shim}/lib/mpv-hwdec-shim.so" + "--env=SFN_MPV_HWDEC=${cfg.hwdec}" + app + ]; in { imports = [ ./cleanup.nix ]; @@ -39,10 +38,11 @@ in { default = false; description = '' Hardware video decoding (the Frame's V4L2 decoder) in the Jellyfin - Desktop Flatpak: device access for the sandbox (devices=all) and an - LD_PRELOAD shim that makes mpv try hwdec's value below. Without - nix-flatpak, home-manager owns the app's Flatpak override file. Takes - effect at the next start of Jellyfin. + Desktop Flatpak: a desktop entry (shadowing the Flatpak's) that + starts it with device access (devices=all) and an LD_PRELOAD shim + that makes mpv try hwdec's value below. Only launches from that + entry (menus, the "+" menu) get it; nothing is written to Flatpak's + overrides. Takes effect at the next start of Jellyfin. ''; }; hwdec = lib.mkOption { @@ -55,17 +55,46 @@ in { Set as SFN_MPV_HWDEC in the Flatpak's environment. ''; }; + command = lib.mkOption { + type = lib.types.str; + readOnly = true; + default = run; + defaultText = lib.literalMD "`flatpak run … org.jellyfin.JellyfinDesktop` with the options"; + description = "The command line the desktop entry runs (for a terminal)."; + }; }; - # The shim copy of earlier versions is removed by steam-frame-nix-cleanup. - config = lib.mkMerge [ - (lib.mkIf (cfg.enable && !useNixFlatpak) { - # force: `flatpak override --user` replaces the link with a file. - xdg.dataFile."flatpak/overrides/${app}" = { source = overrideFile; force = true; }; - }) - # Only if nix-flatpak is imported: the option doesn't exist otherwise. - (lib.optionalAttrs (options ? services.flatpak.overrides) { - services.flatpak.overrides = lib.mkIf (cfg.enable && useNixFlatpak) { ${app} = override; }; - }) - ]; + # Fields as in the Flatpak's own entry (1.x), which has no MimeType. + config = lib.mkIf cfg.enable { + xdg.dataFile."applications/${app}.desktop".text = '' + [Desktop Entry] + Version=1.0 + Name=Jellyfin + Comment=Desktop client for Jellyfin + Exec=${run} + Icon=${app} + Terminal=false + Type=Application + StartupWMClass=${app} + Categories=AudioVideo;Video;Player;TV; + Actions=DesktopF;DesktopW;TVF;TVW + X-Flatpak=${app} + + [Desktop Action DesktopF] + Name=Desktop [Fullscreen] + Exec=${run} --fullscreen --desktop + + [Desktop Action DesktopW] + Name=Desktop [Windowed] + Exec=${run} --windowed --desktop + + [Desktop Action TVF] + Name=TV [Fullscreen] + Exec=${run} --fullscreen --tv + + [Desktop Action TVW] + Name=TV [Windowed] + Exec=${run} --windowed --tv + ''; + }; }