Skip to content

Commit 1eaf54b

Browse files
thepiratebaepartycheese
andauthored
feat(jellyseerr): support remote Jellyfin instances (#125)
Add adminUsername and adminPassword options to jellyseerr.jellyfin with computed defaults that auto-derive from nixflix.jellyfin.users when Jellyfin is co-located. When Jellyfin runs on a separate host, these can be set explicitly. - Add credential options with computed defaults in options/jellyfin.nix - Replace jellyfin.enable assertion with credential null check - Remove jellyfinCfg parameter from authUtil.nix - Make jellyfin-related systemd deps conditional on nixflix.jellyfin.enable - Remove nixflix.jellyfin.enable gates from service mkIf conditions Co-authored-by: partycheese <partycheese@riseup.net>
1 parent 558411b commit 1eaf54b

10 files changed

Lines changed: 83 additions & 43 deletions

File tree

modules/jellyseerr/authUtil.nix

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,15 @@
22
lib,
33
pkgs,
44
cfg,
5-
jellyfinCfg,
65
}:
76
with lib;
87
let
98
secrets = import ../../lib/secrets { inherit lib; };
109
mkSecureCurl = import ../../lib/mk-secure-curl.nix { inherit lib pkgs; };
11-
adminUsers = filterAttrs (_: user: user.policy.isAdministrator) jellyfinCfg.users;
12-
sortedAdminNames = sort (a: b: a < b) (attrNames adminUsers);
13-
firstAdminName = head sortedAdminNames;
14-
firstAdminUser = adminUsers.${firstAdminName};
10+
inherit (cfg.jellyfin) adminUsername;
1511

1612
jqAuthSecrets = secrets.mkJqSecretArgs {
17-
inherit (firstAdminUser) password;
13+
password = cfg.jellyfin.adminPassword;
1814
};
1915

2016
baseUrl = "http://127.0.0.1:${toString cfg.port}";
@@ -63,14 +59,14 @@ in
6359
6460
# Authenticate if needed
6561
if [ "$NEED_AUTH" = "true" ]; then
66-
echo "Authenticating to Jellyseerr as ${firstAdminName}..."
62+
echo "Authenticating to Jellyseerr as ${adminUsername}..."
6763
6864
BACKOFF=1
6965
for attempt in {1..10}; do
7066
AUTH_PAYLOAD_FILE=$(mktemp)
7167
${pkgs.jq}/bin/jq -n \
7268
${jqAuthSecrets.flagsString} \
73-
--arg username "${firstAdminName}" \
69+
--arg username "${adminUsername}" \
7470
'{username: $username, password: ${jqAuthSecrets.refs.password}}' > "$AUTH_PAYLOAD_FILE"
7571
7672
AUTH_RESPONSE=$(${

modules/jellyseerr/default.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ in
3636
in
3737
[
3838
{
39-
assertion = config.nixflix.jellyfin.enable;
40-
message = "Jellyseerr requires Jellyfin to be enabled. Please set nixflix.jellyfin.enable = true.";
39+
assertion = cfg.jellyfin.adminUsername != null && cfg.jellyfin.adminPassword != null;
40+
message = "Jellyseerr requires Jellyfin admin credentials. Either enable nixflix.jellyfin with an admin user, or set nixflix.jellyseerr.jellyfin.adminUsername and nixflix.jellyseerr.jellyfin.adminPassword.";
4141
}
4242
{
4343
assertion = cfg.vpn.enable -> config.nixflix.mullvad.enable;

modules/jellyseerr/jellyfinService.nix

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,17 @@ with lib;
88
let
99
inherit (config) nixflix;
1010
cfg = nixflix.jellyseerr;
11-
jellyfinCfg = nixflix.jellyfin;
1211
authUtil = import ./authUtil.nix {
1312
inherit
1413
lib
1514
pkgs
1615
cfg
17-
jellyfinCfg
1816
;
1917
};
2018
baseUrl = "http://127.0.0.1:${toString cfg.port}";
2119
in
2220
{
23-
config = mkIf (nixflix.enable && cfg.enable && nixflix.jellyfin.enable) {
21+
config = mkIf (nixflix.enable && cfg.enable) {
2422
systemd.services.jellyseerr-jellyfin = {
2523
description = "Configure Jellyfin settings in Jellyseerr";
2624
after = [

modules/jellyseerr/librarySyncService.nix

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,29 @@ with lib;
88
let
99
inherit (config) nixflix;
1010
cfg = nixflix.jellyseerr;
11-
jellyfinCfg = nixflix.jellyfin;
1211
authUtil = import ./authUtil.nix {
1312
inherit
1413
lib
1514
pkgs
1615
cfg
17-
jellyfinCfg
1816
;
1917
};
2018
baseUrl = "http://127.0.0.1:${toString cfg.port}";
2119
in
2220
{
23-
config = mkIf (nixflix.enable && cfg.enable && nixflix.jellyfin.enable) {
21+
config = mkIf (nixflix.enable && cfg.enable) {
2422
systemd.services.jellyseerr-libraries = {
2523
description = "Sync Jellyseerr library selections";
2624
after = [
2725
"jellyseerr-setup.service"
2826
"jellyseerr-jellyfin.service"
29-
"jellyfin-libraries.service"
30-
];
27+
]
28+
++ optional nixflix.jellyfin.enable "jellyfin-libraries.service";
3129
requires = [
3230
"jellyseerr-setup.service"
3331
"jellyseerr-jellyfin.service"
34-
"jellyfin-libraries.service"
35-
];
32+
]
33+
++ optional nixflix.jellyfin.enable "jellyfin-libraries.service";
3634
wantedBy = [ "multi-user.target" ];
3735

3836
serviceConfig = {

modules/jellyseerr/options/jellyfin.nix

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,40 @@
44
...
55
}:
66
with lib;
7+
let
8+
secrets = import ../../../lib/secrets { inherit lib; };
9+
jellyfinCfg = config.nixflix.jellyfin;
10+
adminUsers = filterAttrs (_: user: user.policy.isAdministrator) jellyfinCfg.users;
11+
sortedAdminNames = sort (a: b: a < b) (attrNames adminUsers);
12+
hasLocalAdmin = jellyfinCfg.enable && sortedAdminNames != [ ];
13+
firstAdminName = if hasLocalAdmin then head sortedAdminNames else null;
14+
firstAdminUser = if hasLocalAdmin then adminUsers.${firstAdminName} else null;
15+
in
716
{
817
options.nixflix.jellyseerr.jellyfin = {
18+
adminUsername = mkOption {
19+
type = types.nullOr types.str;
20+
default = firstAdminName;
21+
defaultText = literalExpression "first admin username from nixflix.jellyfin.users, or null";
22+
description = ''
23+
Jellyfin admin username for Jellyseerr authentication.
24+
25+
Auto-derived from `nixflix.jellyfin.users` when Jellyfin is enabled locally.
26+
Must be set explicitly when using a remote Jellyfin instance.
27+
'';
28+
};
29+
30+
adminPassword = secrets.mkSecretOption {
31+
default = if hasLocalAdmin then firstAdminUser.password else null;
32+
defaultText = literalExpression "password of first admin from nixflix.jellyfin.users, or null";
33+
description = ''
34+
Jellyfin admin password for Jellyseerr authentication.
35+
36+
Auto-derived from `nixflix.jellyfin.users` when Jellyfin is enabled locally.
37+
Must be set explicitly when using a remote Jellyfin instance.
38+
'';
39+
};
40+
941
hostname = mkOption {
1042
type = types.str;
1143
default = "127.0.0.1";

modules/jellyseerr/radarrService.nix

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@ let
99
secrets = import ../../lib/secrets { inherit lib; };
1010
inherit (config) nixflix;
1111
cfg = nixflix.jellyseerr;
12-
jellyfinCfg = nixflix.jellyfin;
1312
authUtil = import ./authUtil.nix {
1413
inherit
1514
lib
1615
pkgs
1716
cfg
18-
jellyfinCfg
1917
;
2018
};
2119
baseUrl = "http://127.0.0.1:${toString cfg.port}";

modules/jellyseerr/setupService.nix

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,31 @@ let
99
secrets = import ../../lib/secrets { inherit lib; };
1010
inherit (config) nixflix;
1111
cfg = nixflix.jellyseerr;
12-
jellyfinCfg = nixflix.jellyfin;
13-
14-
adminUsers = filterAttrs (_: user: user.policy.isAdministrator) jellyfinCfg.users;
15-
sortedAdminNames = sort (a: b: a < b) (attrNames adminUsers);
16-
firstAdminName = head sortedAdminNames;
17-
firstAdminUser = adminUsers.${firstAdminName};
1812

1913
authUtil = import ./authUtil.nix {
2014
inherit
2115
lib
2216
pkgs
2317
cfg
24-
jellyfinCfg
2518
;
2619
};
2720
baseUrl = "http://127.0.0.1:${toString cfg.port}";
2821
jqSetupSecrets = secrets.mkJqSecretArgs {
29-
inherit (firstAdminUser) password;
22+
password = cfg.jellyfin.adminPassword;
3023
};
3124
in
3225
{
33-
config = mkIf (nixflix.enable && cfg.enable && nixflix.jellyfin.enable) {
26+
config = mkIf (nixflix.enable && cfg.enable) {
3427
systemd.services.jellyseerr-setup = {
3528
description = "Complete Jellyseerr initial setup with Jellyfin";
3629
after = [
3730
"jellyseerr.service"
38-
"jellyfin-setup-wizard.service"
39-
];
31+
]
32+
++ optional nixflix.jellyfin.enable "jellyfin-setup-wizard.service";
4033
requires = [
4134
"jellyseerr.service"
42-
"jellyfin-setup-wizard.service"
43-
];
35+
]
36+
++ optional nixflix.jellyfin.enable "jellyfin-setup-wizard.service";
4437
wantedBy = [ "multi-user.target" ];
4538

4639
serviceConfig = {
@@ -75,15 +68,14 @@ in
7568
echo "Running initial setup..."
7669
7770
# Step 1: Connect to Jellyfin (this creates the session cookie)
78-
# Use Jellyfin's first admin credentials
7971
SETUP_PAYLOAD=$(${pkgs.jq}/bin/jq -n \
8072
${jqSetupSecrets.flagsString} \
81-
--arg username "${firstAdminName}" \
73+
--arg username "${cfg.jellyfin.adminUsername}" \
8274
--arg hostname "${cfg.jellyfin.hostname}" \
8375
--arg port "${toString cfg.jellyfin.port}" \
8476
--arg useSsl "${boolToString cfg.jellyfin.useSsl}" \
8577
--arg urlBase "${cfg.jellyfin.urlBase}" \
86-
--arg email "${firstAdminUser.email or firstAdminName}" \
78+
--arg email "${cfg.jellyfin.adminUsername}" \
8779
--arg serverType "${toString cfg.jellyfin.serverType}" \
8880
'{
8981
username: $username,

modules/jellyseerr/sonarrService.nix

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@ let
99
secrets = import ../../lib/secrets { inherit lib; };
1010
inherit (config) nixflix;
1111
cfg = nixflix.jellyseerr;
12-
jellyfinCfg = nixflix.jellyfin;
1312
authUtil = import ./authUtil.nix {
1413
inherit
1514
lib
1615
pkgs
1716
cfg
18-
jellyfinCfg
1917
;
2018
};
2119
baseUrl = "http://127.0.0.1:${toString cfg.port}";

modules/jellyseerr/userSettingsService.nix

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,18 @@ with lib;
88
let
99
inherit (config) nixflix;
1010
cfg = nixflix.jellyseerr;
11-
jellyfinCfg = nixflix.jellyfin;
1211
authUtil = import ./authUtil.nix {
1312
inherit
1413
lib
1514
pkgs
1615
cfg
17-
jellyfinCfg
1816
;
1917
};
2018
baseUrl = "http://127.0.0.1:${toString cfg.port}";
2119
userSettings = cfg.settings.users;
2220
in
2321
{
24-
config = mkIf (nixflix.enable && cfg.enable && nixflix.jellyfin.enable) {
22+
config = mkIf (nixflix.enable && cfg.enable) {
2523
systemd.services.jellyseerr-user-settings = {
2624
description = "Configure Jellyseerr default user settings";
2725
after = [ "jellyseerr-setup.service" ];

tests/unit-tests/default.nix

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,36 @@ in
242242
in
243243
assertTest "sabnzbd-service-generation" hasAllServices;
244244

245+
# Test that jellyseerr generates services with a remote Jellyfin (no local jellyfin)
246+
jellyseerr-remote-jellyfin =
247+
let
248+
config = evalConfig [
249+
{
250+
nixflix = {
251+
enable = true;
252+
jellyseerr = {
253+
enable = true;
254+
apiKey = {
255+
_secret = "/run/secrets/jellyseerr-api";
256+
};
257+
jellyfin = {
258+
adminUsername = "remoteadmin";
259+
adminPassword = "remotepassword";
260+
};
261+
};
262+
};
263+
}
264+
];
265+
systemdUnits = config.config.systemd.services;
266+
in
267+
assertTest "jellyseerr-remote-jellyfin" (
268+
systemdUnits ? jellyseerr
269+
&& systemdUnits ? jellyseerr-setup
270+
&& systemdUnits ? jellyseerr-jellyfin
271+
&& systemdUnits ? jellyseerr-libraries
272+
&& systemdUnits ? jellyseerr-user-settings
273+
);
274+
245275
jellyfin-integration =
246276
let
247277
config = evalConfig [

0 commit comments

Comments
 (0)