NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
17.35k stars 13.58k forks source link

jellyfin-web: how to customize config.json? #286503

Open techhazard opened 7 months ago

techhazard commented 7 months ago

Describe the bug

I would like to change the config.json file to customize my jellyfin login page (to add an extra button/link) According to the jellyfin documentation, that should be in the root of the "web root" directory.

It turns out that this "web root" directory is inside the /nix/store (thus readonly), and part of the jellyfin-web package.

How can I overwrite/customize this file?

Steps To Reproduce

1. Install jellyfin on nixos:

#configuration.nix
{ ... }: {
   services.jellyfin.enable = true;
}

2. Take a look at the ExecStart script for jellyfin.service:

systemctl cat jellyfin.service | awk -F= '$1=="ExecStart" {print $2}' | awk '{print $1}' | xargs cat

Which in my case ends with the line

# ...
exec "/nix/store/wdilbmr53p3gnwhnajfsmbazbcla62ga-jellyfin-10.8.13/lib/jellyfin/jellyfin"  --ffmpeg /nix/store/wyfhqh26kssp6735460gm7psk4y5d7nr-jellyfin-ffmpeg-6.0-7-bin/bin/ffmpeg --webdir /nix/store/m2844vmwhz5xykxi66fagcd8nw86j95k-jellyfin-web-10.8.13/share/jellyfin-web "$@"

Which tells me that the webroot is in the nix store: /nix/store/m2844vmwhz5xykxi66fagcd8nw86j95k-jellyfin-web-10.8.13/share/jellyfin-web

Then I can view the used config.json easily:

$ cat /nix/store/m2844vmwhz5xykxi66fagcd8nw86j95k-jellyfin-web-10.8.13/share/jellyfin-web/config.json
{
  "includeCorsCredentials": false,
  "multiserver": false,
  "themes": [
    {
      "name": "Apple TV",
      "id": "appletv",
      "color": "#bcbcbc"
    }, {
      "name": "Blue Radiance",
      "id": "blueradiance",
      "color": "#011432"
    }, {
      "name": "Dark",
      "id": "dark",
      "color": "#202020",
      "default": true
    }, {
      "name": "Light",
      "id": "light",
      "color": "#303030"
    }, {
      "name": "Purple Haze",
      "id": "purplehaze",
      "color": "#000420"
    }, {
      "name": "WMC",
      "id": "wmc",
      "color": "#0c2450"
    }
  ],
  "menuLinks": [],
  "servers": [],
  "plugins": [
    "playAccessValidation/plugin",
    "experimentalWarnings/plugin",
    "htmlAudioPlayer/plugin",
    "htmlVideoPlayer/plugin",
    "photoPlayer/plugin",
    "comicsPlayer/plugin",
    "bookPlayer/plugin",
    "youtubePlayer/plugin",
    "backdropScreensaver/plugin",
    "pdfPlayer/plugin",
    "logoScreensaver/plugin",
    "sessionPlayer/plugin",
    "chromecastPlayer/plugin"
  ]
}

Expected behavior

There is a clear way (in something like service.nixos.webConfig??) to customize this file.

Notify maintainers

@nyanloutre @minijackson @purcell @jojosch

Metadata

[user@system:~]$ nix-shell -p nix-info --run "nix-info -m"
 - system: `"x86_64-linux"`
 - host os: `Linux 6.6.6, NixOS, 23.11 (Tapir), 23.11pre-git`
 - multi-user?: `yes`
 - sandbox: `yes`
 - version: `nix-env (Nix) 2.18.1`
 - nixpkgs: `/nix/var/nix/profiles/per-user/root/channels/nixos`

Add a :+1: reaction to issues you find important.

fsnkty commented 7 months ago

the webdir is given to jellyfin with a wrapper here, moving webdir out of the store seems like a messy move. Is there something wrong with overriding the jellyfin-web package to change that file?

techhazard commented 7 months ago

Thanks for the reply :slightly_smiling_face:

I've never had to override a whole package before, so I wouldn't know.
Conceptually it seems a bit overkill to have to override a whole package just to change a config file.

Do you maybe have some pointers to help me get started? I am using flakes (specifically colmena), if that helps.

fsnkty commented 7 months ago

taken me a while to get to this but its become obvious that if this is something people care to change that it should be more easily accessible. my approach was to override the jellyfin packages jellyfin-web to change that file before its copied to $out in the install phase.. that just feels stupid.

winterqt commented 7 months ago

my approach was to override the jellyfin packages jellyfin-web to change that file before its copied to $out in the install phase.. that just feels stupid.

That's a pretty common approach. (If you want to avoid the needless JS bundling and whatnot, make a separate derivation that copies the compiled jellyfin-web as well as your modified config to $out.)

zefrof commented 5 months ago

I'm not sure if this is the best place to mention this, but it seemed more relevant here than in a new issue.

Something that I feel isn't handled well by overriding is Add-ons. Some add-ons, such as this one, dynamically inject code into the web files. For example the linked intro skipper add-on injects at least one script tag into index.html. Overriding index.html seems like bad practice to me since what's injected where could change.

Guess I could override the output of the jellyfin-web package, but as mentioned by @nu-nu-ko above that feels messy. Open to suggestions if anyone has ideas.

fsnkty commented 5 months ago

Something that I feel isn't handled well by overriding is Add-ons. Some add-ons, such as this one, dynamically inject code into the web files. For example the linked intro skipper add-on injects at least one script tag into index.html. Overriding index.html seems like bad practice to me since what's injected where could change.

Unfortunately I don't think we can get very close to a "good" solution to this or plugin management in general, let alone wider jellyfin config/setup issues. It simply isnt currently very friendly to the idea.

Maybe a onetime inital setup process for this service would be nice to have but not sure if that is worth the time to attempt.

Guess I could override the output of the jellyfin-web package, but as mentioned by @nu-nu-ko above that feels messy. Open to suggestions if anyone has ideas.

Imo the only real solution is an upstream change such that modifying this file as a user is pointless anyway, or more impactfully and unfortunately more unrealistically creating some alternative to add-ons needing to change this file either. Sometimes we just have to use jank to get around jank.

zefrof commented 4 months ago

I decided I'd like to override the output of the jellyfin-web package. In my head this requires copying/moving the jellyfin-web files outside of the nix store, and changing jellyfin to use this new location. I've tried overriding installPhase to mimic current behavior and also copy the files elsewhere, but have run into permission issues. Honestly this is outside my current understanding of nix packaging, so any help would be appreciated (Matrix channel wasn't much help unfortunately).

Here's what I've tried thus far:

  jellyfin-web-injectable = pkgs.jellyfin-web.overrideAttrs (oldAttrs: {
    installPhase = ''
      runHook preInstall

      mkdir -p $out/share
      cp -a dist $out/share/jellyfin-web

      mkdir -p /var/lib/jellyfin-web # dies here due to permission issues
      cp $out/share/jellyfin-web /var/lib/jellyfin-web
      chown -R jellyfin:jellyfin /var/lib/jellyfin-web

      runHook postInstall
    '';
  });

  jellfin-injectable = pkgs.jellfin.overrideAttrs (oldAttrs: {
    preInstall = ''
      makeWrapperArgs+=(
        --add-flags "--ffmpeg ${ffmpeg}/bin/ffmpeg" # dies here since ${ffmpeg} can't be found
        --add-flags "--webdir /var/lib/jellyfin-web"
      )
    '';
  });
nixos-discourse commented 2 months ago

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/overriding-jellyfin-package-to-make-addon-usable/48974/1

kevincox commented 2 months ago

Updating the web package to edit the config.json makes sense. But if you are using a reverse proxy an easier option may be to just override that one URL with a hardcoded JSON file.

For nginx it would look something like this. (Not tested)

location = /ui/config.json {
    try_files ${builtins.toFile "jellyfin-config.json" (builtins.toJSON {
        # ...
    })} =500;
}