# configuration options (today only a *subset* of the config is done in nix)
# - jellyfin-web can be statically configured (result/share/jellyfin-web/config.json)
#   - <https://jellyfin.org/docs/general/clients/web-config>
#   - configure server list, plugins, "menuLinks", colors
#
# - jellfyin server is configured in /var/lib/jellfin/
#   - root/default/<LibraryType>/
#     - <LibraryName>.mblink: contains the directory name where this library lives
#     - options.xml: contains preferences which were defined in the web UI during import
#       - e.g. `EnablePhotos`, `EnableChapterImageExtraction`, etc.
#   - config/encoding.xml: transcoder settings
#   - config/system.xml: misc preferences like log file duration, audiobook resume settings, etc.
#   - data/jellyfin.db: maybe account definitions? internal state?
#
# N.B.: default install DOES NOT SUPPORT DLNA out of the box.
#       one must install it as a "plugin", which can be done through the UI.
{ lib, ... }:

# lib.mkIf false  #< XXX(2024-11-17): disabled because it hasn't been working for months; web UI hangs on load, TVs see no files
{
  # https://jellyfin.org/docs/general/networking/index.html
  sane.ports.ports."1900" = {
    protocol = [ "udp" ];
    visibleTo.lan = true;
    description = "colin-upnp-for-jellyfin";
  };
  sane.ports.ports."7359" = {
    protocol = [ "udp" ];
    visibleTo.lan = true;
    description = "colin-jellyfin-specific-client-discovery";
    # ^ not sure if this is necessary: copied this port from nixos jellyfin.openFirewall
  };
  # not sure if 8096/8920 get used either:
  sane.ports.ports."8096" = {
    protocol = [ "tcp" ];
    visibleTo.lan = true;
    description = "colin-jellyfin-http-lan";
  };
  sane.ports.ports."8920" = {
    protocol = [ "tcp" ];
    visibleTo.lan = true;
    description = "colin-jellyfin-https-lan";
  };

  sane.persist.sys.byStore.plaintext = [
    { user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/data"; method = "bind"; }
    { user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/metadata"; method = "bind"; }
    # TODO: ship plugins statically, via nix. that'll be less fragile
    { user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/plugins/DLNA_5.0.0.0"; method = "bind"; }
    { user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/root"; method = "bind"; }
  ];
  sane.persist.sys.byStore.ephemeral = [
    { user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/log"; method = "bind"; }
    { user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/transcodes"; method = "bind"; }
  ];

  services.jellyfin.enable = true;
  users.users.jellyfin.extraGroups = [ "media" ];

  sane.fs."/var/lib/jellyfin".dir.acl = {
    user = "jellyfin";
    group = "jellyfin";
    mode = "0700";
  };

  # `"Jellyfin.Plugin.Dlna": "Debug"` logging: <https://jellyfin.org/docs/general/networking/dlna>
  # TODO: switch Dlna back to 'Information' once satisfied with stability
  sane.fs."/var/lib/jellyfin/config/logging.json".symlink.text = ''
    {
      "Serilog": {
        "MinimumLevel": {
          "Default": "Information",
          "Override": {
            "Microsoft": "Warning",
            "System": "Warning",
            "Jellyfin.Plugin.Dlna": "Debug"
          }
        },
        "WriteTo": [
          {
            "Name": "Console",
            "Args": {
              "outputTemplate": "[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}"
            }
          }
        ],
        "Enrich": [ "FromLogContext", "WithThreadId" ]
      }
    }
  '';

  sane.fs."/var/lib/jellyfin/config/network.xml".file.text = ''
    <?xml version="1.0" encoding="utf-8"?>
    <NetworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <BaseUrl />
      <EnableHttps>false</EnableHttps>
      <RequireHttps>false</RequireHttps>
      <InternalHttpPort>8096</InternalHttpPort>
      <InternalHttpsPort>8920</InternalHttpsPort>
      <PublicHttpPort>8096</PublicHttpPort>
      <PublicHttpsPort>8920</PublicHttpsPort>
      <AutoDiscovery>true</AutoDiscovery>
      <EnableUPnP>false</EnableUPnP>
      <EnableIPv4>true</EnableIPv4>
      <EnableIPv6>false</EnableIPv6>
      <EnableRemoteAccess>true</EnableRemoteAccess>
      <LocalNetworkSubnets>
        <string>10.78.76.0/22</string>
      </LocalNetworkSubnets>
      <KnownProxies>
        <string>127.0.0.1</string>
        <string>localhost</string>
        <string>10.78.79.1</string>
      </KnownProxies>
      <IgnoreVirtualInterfaces>false</IgnoreVirtualInterfaces>
      <VirtualInterfaceNames />
      <EnablePublishedServerUriByRequest>false</EnablePublishedServerUriByRequest>
      <PublishedServerUriBySubnet />
      <RemoteIPFilter />
      <IsRemoteIPFilterBlacklist>false</IsRemoteIPFilterBlacklist>
    </NetworkConfiguration>
  '';

  # guest user id is `5ad194d60dca41de84b332950ffc4308`
  sane.fs."/var/lib/jellyfin/plugins/configurations/Jellyfin.Plugin.Dlna.xml".file.text = ''
    <?xml version="1.0" encoding="utf-8"?>
    <DlnaPluginConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <EnablePlayTo>true</EnablePlayTo>
      <ClientDiscoveryIntervalSeconds>60</ClientDiscoveryIntervalSeconds>
      <BlastAliveMessages>true</BlastAliveMessages>
      <AliveMessageIntervalSeconds>180</AliveMessageIntervalSeconds>
      <SendOnlyMatchedHost>true</SendOnlyMatchedHost>
      <DefaultUserId>5ad194d6-0dca-41de-84b3-32950ffc4308</DefaultUserId>
    </DlnaPluginConfiguration>
  '';

  # fix LG TV to play more files.
  # there are certain files for which it only supports Direct Play (not even "Direct Stream" -- but "Direct Play").
  # this isn't a 100% fix: patching the profile allows e.g. Azumanga Daioh to play,
  # but A Place Further Than the Universe still fails as before.
  #
  # profile is based on upstream: <https://github.com/jellyfin/jellyfin-plugin-dlna>
  sane.fs."/var/lib/jellyfin/plugins/DLNA_5.0.0.0/profiles/LG Smart TV.xml".symlink.target = ./dlna/user/LG_Smart_TV.xml;
  # XXX(2024-11-17): old method, but the file referenced seems not to be used and setting just it causes failures:
  # > [DBG] Jellyfin.Plugin.Dlna.ContentDirectory.ContentDirectoryService: Not eligible for DirectPlay due to unsupported subtitles
  # sane.fs."/var/lib/jellyfin/plugins/configurations/dlna/user/LG Smart TV.xml".symlink.target = ./dlna/user/LG_Smart_TV.xml;

  systemd.services.jellyfin.unitConfig.RequiresMountsFor = [
    "/var/media"
  ];

  # Jellyfin multimedia server
  # this is mostly taken from the official jellfin.org docs
  services.nginx.virtualHosts."jelly.uninsane.org" = {
    forceSSL = true;
    enableACME = true;
    # inherit kTLS;

    locations."/" = {
      proxyPass = "http://127.0.0.1:8096";
      proxyWebsockets = true;
      recommendedProxySettings = true;
      # extraConfig = ''
      #   # Disable buffering when the nginx proxy gets very resource heavy upon streaming
      #   proxy_buffering off;
      # '';
    };
  };

  sane.dns.zones."uninsane.org".inet.CNAME."jelly" = "native";
}
