Skip to content

Commit 2b70570

Browse files
committed
add other xml config options
1 parent 631f0ed commit 2b70570

6 files changed

Lines changed: 1262 additions & 257 deletions

File tree

modules/jellyfin/default.nix

Lines changed: 24 additions & 257 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@ with lib; let
88
inherit (config) nixflix;
99
inherit (config.nixflix) globals;
1010
cfg = config.nixflix.jellyfin;
11-
stateDir = "${nixflix.stateDir}/jellyfin";
1211

13-
# Convert camelCase to PascalCase
1412
toPascalCase = str: let
1513
firstChar = substring 0 1 str;
1614
rest = substring 1 (-1) str;
1715
in
1816
(toUpper firstChar) + rest;
1917

20-
# Recursive function to convert Nix attrs to XML
2118
attrsToXml = indent: attrs:
2219
concatStringsSep "\n" (
2320
mapAttrsToList (name: value: let
@@ -44,251 +41,21 @@ with lib; let
4441
attrs
4542
);
4643

47-
networkXmlContent = ''
44+
mkXmlContent = tagName: attrs: ''
4845
<?xml version="1.0" encoding="utf-8"?>
49-
<NetworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
50-
${attrsToXml " " cfg.network}
51-
</NetworkConfiguration>
46+
<${tagName} xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
47+
${attrsToXml " " attrs}
48+
</${tagName}>
5249
'';
53-
in {
54-
options.nixflix.jellyfin = {
55-
enable = mkOption {
56-
type = types.bool;
57-
default = false;
58-
description = "Whether to enable Jellyfin media server";
59-
};
60-
61-
package = mkOption {
62-
type = types.package;
63-
default = pkgs.jellyfin;
64-
defaultText = literalExpression "pkgs.jellyfin";
65-
description = "Jellyfin package to use";
66-
};
67-
68-
user = mkOption {
69-
type = types.str;
70-
default = "jellyfin";
71-
description = "User under which the service runs";
72-
};
73-
74-
group = mkOption {
75-
type = types.str;
76-
default = globals.libraryOwner.group;
77-
defaultText = literalExpression "config.nixflix.globals.libraryOwner.group";
78-
description = "Group under which the service runs";
79-
};
80-
81-
dataDir = mkOption {
82-
type = types.path;
83-
default = stateDir;
84-
defaultText = literalExpression ''"''${config.nixflix.stateDir}/jellyfin"'';
85-
description = "Directory containing the Jellyfin data files";
86-
};
87-
88-
configDir = mkOption {
89-
type = types.path;
90-
default = "${stateDir}/config";
91-
defaultText = literalExpression ''"''${config.nixflix.stateDir}/jellyfin/config"'';
92-
description = ''
93-
Directory containing the server configuration files,
94-
passed with `--configdir` see [configuration-directory](https://jellyfin.org/docs/general/administration/configuration/#configuration-directory)
95-
'';
96-
};
97-
98-
cacheDir = mkOption {
99-
type = types.path;
100-
default = "/var/cache/jellyfin";
101-
description = ''
102-
Directory containing the jellyfin server cache,
103-
passed with `--cachedir` see [#cache-directory](https://jellyfin.org/docs/general/administration/configuration/#cache-directory)
104-
'';
105-
};
106-
107-
logDir = mkOption {
108-
type = types.path;
109-
default = "${stateDir}/log";
110-
defaultText = literalExpression ''"''${config.nixflix.stateDir}/jellyfin/log"'';
111-
description = ''
112-
Directory where the Jellyfin logs will be stored,
113-
passed with `--logdir` see [#log-directory](https://jellyfin.org/docs/general/administration/configuration/#log-directory)
114-
'';
115-
};
116-
117-
apiKeyPath = mkOption {
118-
type = types.nullOr types.path;
119-
default = null;
120-
description = ''
121-
Path to file containing the Jellyfin API key.
122-
This is optional and currently not used for configuration,
123-
but available for future API-based configuration enhancements.
124-
'';
125-
};
126-
127-
openFirewall = mkOption {
128-
type = types.bool;
129-
default = false;
130-
description = ''
131-
Open ports in the firewall for Jellyfin.
132-
TCP ports 8096 and 8920, UDP ports 1900 and 7359.
133-
'';
134-
};
135-
136-
vpn = {
137-
enable = mkOption {
138-
type = types.bool;
139-
default = false;
140-
description = ''
141-
Whether to route Jellyfin traffic through the VPN.
142-
When false (default), Jellyfin bypasses the VPN.
143-
When true, Jellyfin routes through the VPN (requires nixflix.mullvad.enable = true).
144-
'';
145-
};
146-
};
147-
148-
network = {
149-
autoDiscovery = mkOption {
150-
type = types.bool;
151-
default = true;
152-
description = "Enable auto-discovery";
153-
};
154-
155-
baseUrl = mkOption {
156-
type = types.str;
157-
default =
158-
if nixflix.nginx.enable
159-
then "/jellyfin"
160-
else "";
161-
defaultText = literalExpression ''if config.nixflix.serviceNameIsUrlBase then "/jellyfin" else ""'';
162-
description = "Base URL for Jellyfin (URL prefix)";
163-
};
164-
165-
certificatePassword = mkOption {
166-
type = types.str;
167-
default = "";
168-
description = "Certificate password";
169-
};
17050

171-
certificatePath = mkOption {
172-
type = types.str;
173-
default = "";
174-
description = "Path to certificate file";
175-
};
176-
177-
enableHttps = mkOption {
178-
type = types.bool;
179-
default = false;
180-
description = "Enable HTTPS";
181-
};
182-
183-
enableIPv4 = mkOption {
184-
type = types.bool;
185-
default = true;
186-
description = "Enable IPv4";
187-
};
188-
189-
enableIPv6 = mkOption {
190-
type = types.bool;
191-
default = false;
192-
description = "Enable IPv6";
193-
};
194-
195-
enablePublishedServerUriByRequest = mkOption {
196-
type = types.bool;
197-
default = false;
198-
description = "Enable published server URI by request";
199-
};
200-
201-
enableRemoteAccess = mkOption {
202-
type = types.bool;
203-
default = true;
204-
description = "Enable remote access";
205-
};
206-
207-
enableUPnP = mkOption {
208-
type = types.bool;
209-
default = false;
210-
description = "Enable UPnP";
211-
};
212-
213-
ignoreVirtualInterfaces = mkOption {
214-
type = types.bool;
215-
default = true;
216-
description = "Ignore virtual interfaces";
217-
};
218-
219-
internalHttpPort = mkOption {
220-
type = types.ints.between 0 65535;
221-
default = 8096;
222-
description = "Internal HTTP port";
223-
};
224-
225-
internalHttpsPort = mkOption {
226-
type = types.ints.between 0 65535;
227-
default = 8920;
228-
description = "Internal HTTPS port";
229-
};
230-
231-
isRemoteIPFilterBlacklist = mkOption {
232-
type = types.bool;
233-
default = false;
234-
description = "Is remote IP filter a blacklist";
235-
};
236-
237-
knownProxies = mkOption {
238-
type = types.listOf types.str;
239-
default = [];
240-
description = "List of known proxies";
241-
};
242-
243-
localNetworkAddresses = mkOption {
244-
type = types.bool;
245-
default = false;
246-
description = "Local network addresses";
247-
};
248-
249-
localNetworkSubnets = mkOption {
250-
type = types.listOf types.str;
251-
default = [];
252-
description = "List of local network subnets";
253-
};
254-
255-
publicHttpPort = mkOption {
256-
type = types.ints.between 0 65535;
257-
default = 8096;
258-
description = "Public HTTP port";
259-
};
260-
261-
publicHttpsPort = mkOption {
262-
type = types.ints.between 0 65535;
263-
default = 8920;
264-
description = "Public HTTPS port";
265-
};
266-
267-
publishedServerUriBySubnet = mkOption {
268-
type = types.listOf types.str;
269-
default = [];
270-
description = "List of published server URIs by subnet";
271-
};
272-
273-
remoteIpFilter = mkOption {
274-
type = types.listOf types.str;
275-
default = [];
276-
description = "Remote IP filter list";
277-
};
278-
279-
requireHttps = mkOption {
280-
type = types.bool;
281-
default = false;
282-
description = "Require HTTPS";
283-
};
284-
285-
virtualInterfaceNames = mkOption {
286-
type = types.listOf types.str;
287-
default = ["veth"];
288-
description = "List of virtual interface names";
289-
};
290-
};
291-
};
51+
networkXmlContent = mkXmlContent "NetworkConfiguration" cfg.network;
52+
brandingXmlContent = mkXmlContent "BrandingOptions" cfg.branding;
53+
encodingXmlContent = mkXmlContent "EncodingOptions" cfg.encoding;
54+
systemXmlContent = mkXmlContent "ServerConfiguration" cfg.system;
55+
in {
56+
imports = [
57+
./options
58+
];
29259

29360
config = mkIf (nixflix.enable && cfg.enable) {
29461
assertions = [
@@ -316,7 +83,12 @@ in {
31683
"d '${cfg.logDir}' 0750 ${cfg.user} ${cfg.group} - -"
31784
];
31885

319-
environment.etc."jellyfin/network.xml.template".text = networkXmlContent;
86+
environment.etc = {
87+
"jellyfin/network.xml.template".text = networkXmlContent;
88+
"jellyfin/branding.xml.template".text = brandingXmlContent;
89+
"jellyfin/encoding.xml.template".text = encodingXmlContent;
90+
"jellyfin/system.xml.template".text = systemXmlContent;
91+
};
32092

32193
systemd.services.jellyfin = {
32294
description = "Jellyfin Media Server";
@@ -334,7 +106,12 @@ in {
334106
TimeoutSec = 15;
335107
SuccessExitStatus = "0 143";
336108

337-
ExecStartPre = "${pkgs.coreutils}/bin/install -m 640 /etc/jellyfin/network.xml.template '${cfg.configDir}/network.xml'";
109+
ExecStartPre = pkgs.writeShellScript "jellyfin-setup-config" ''
110+
${pkgs.coreutils}/bin/install -m 640 /etc/jellyfin/network.xml.template '${cfg.configDir}/network.xml'
111+
${pkgs.coreutils}/bin/install -m 640 /etc/jellyfin/branding.xml.template '${cfg.configDir}/branding.xml'
112+
${pkgs.coreutils}/bin/install -m 640 /etc/jellyfin/encoding.xml.template '${cfg.configDir}/encoding.xml'
113+
${pkgs.coreutils}/bin/install -m 640 /etc/jellyfin/system.xml.template '${cfg.configDir}/system.xml'
114+
'';
338115

339116
ExecStart =
340117
if (config.nixflix.mullvad.enable && !cfg.vpn.enable)
@@ -412,16 +189,6 @@ in {
412189
413190
proxy_set_header X-Real-IP $remote_addr;
414191
proxy_buffering off;
415-
416-
${
417-
if nixflix.theme.enable
418-
then ''
419-
proxy_set_header Accept-Encoding "";
420-
sub_filter '</body>' '<style>@import url("https://theme-park.dev/css/base/jellyfin/${nixflix.theme.name}.css");</style></body>';
421-
sub_filter_once on;
422-
''
423-
else ""
424-
}
425192
'';
426193
};
427194
"${cfg.network.baseUrl}/socket" = {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
config,
3+
lib,
4+
...
5+
}:
6+
with lib; {
7+
options.nixflix.jellyfin.branding = {
8+
customCss = mkOption {
9+
type = types.lines;
10+
default =
11+
if config.nixflix.theme.enable
12+
then ''@import url("https://theme-park.dev/css/base/jellyfin/${config.nixflix.theme.name}.css");''
13+
else "";
14+
defaultText = literalExpression ''
15+
if config.nixflix.theme.enable
16+
then '''@import url("https://theme-park.dev/css/base/jellyfin/${config.nixflix.theme.name}.css");'''
17+
else "";'';
18+
description = "Custom CSS to be injected into the web client";
19+
};
20+
21+
loginDisclaimer = mkOption {
22+
type = types.lines;
23+
default = "";
24+
description = "Sets the text shown during login underneath the form";
25+
};
26+
27+
splashscreenEnabled = mkOption {
28+
type = types.bool;
29+
default = false;
30+
description = "Enables a splashscreen to be shown during loading";
31+
};
32+
33+
splashscreenLocation = mkOption {
34+
type = with types; either path str;
35+
default = "";
36+
description = "Location of the splashscreen image";
37+
};
38+
};
39+
}

0 commit comments

Comments
 (0)