diff --git a/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix b/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix
index aeeeb55..fb015d0 100644
--- a/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix
+++ b/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix
@@ -182,11 +182,18 @@ in
];
};
- unitConfig.After = [
- "${containers.authelia-postgresql._serviceName}.service"
- "${containers.authelia-redis._serviceName}.service"
- "sops-nix.service"
- ];
+ unitConfig =
+ let
+ dependencies = [
+ "${containers.authelia-postgresql._serviceName}.service"
+ "${containers.authelia-redis._serviceName}.service"
+ "sops-nix.service"
+ ];
+ in
+ {
+ After = dependencies;
+ Requires = dependencies;
+ };
};
authelia-postgresql = {
@@ -201,7 +208,14 @@ in
environmentFiles = [ hmConfig.sops.templates.authelia-postgresql-env.path ];
};
- unitConfig.After = [ "sops-nix.service" ];
+ unitConfig =
+ let
+ dependencies = [ "sops-nix.service" ];
+ in
+ {
+ After = dependencies;
+ Requires = dependencies;
+ };
};
authelia-redis.containerConfig = {
diff --git a/hosts/jupiter/users/storm/configs/console/podman/gitea/default.nix b/hosts/jupiter/users/storm/configs/console/podman/gitea/default.nix
index d6244bb..520b07d 100644
--- a/hosts/jupiter/users/storm/configs/console/podman/gitea/default.nix
+++ b/hosts/jupiter/users/storm/configs/console/podman/gitea/default.nix
@@ -237,10 +237,17 @@ in
];
};
- unitConfig.After = [
- "${containers.gitea-postgresql._serviceName}.service"
- "sops-nix.service"
- ];
+ unitConfig =
+ let
+ dependencies = [
+ "${containers.gitea-postgresql._serviceName}.service"
+ "sops-nix.service"
+ ];
+ in
+ {
+ After = dependencies;
+ Requires = dependencies;
+ };
};
gitea-postgresql = {
@@ -255,7 +262,14 @@ in
environmentFiles = [ hmConfig.sops.templates.gitea-postgresql-env.path ];
};
- unitConfig.After = [ "sops-nix.service" ];
+ unitConfig =
+ let
+ dependencies = [ "sops-nix.service" ];
+ in
+ {
+ After = dependencies;
+ Requires = dependencies;
+ };
};
authelia.containerConfig.volumes = [
diff --git a/hosts/jupiter/users/storm/configs/console/podman/grafana/default.nix b/hosts/jupiter/users/storm/configs/console/podman/grafana/default.nix
index 479960e..9afdd18 100644
--- a/hosts/jupiter/users/storm/configs/console/podman/grafana/default.nix
+++ b/hosts/jupiter/users/storm/configs/console/podman/grafana/default.nix
@@ -139,7 +139,14 @@ in
];
};
- unitConfig.After = [ "sops-nix.service" ];
+ unitConfig =
+ let
+ dependencies = [ "sops-nix.service" ];
+ in
+ {
+ After = dependencies;
+ Requires = dependencies;
+ };
};
grafana-image-renderer.containerConfig = {
diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/default.nix b/hosts/jupiter/users/storm/configs/console/podman/media/default.nix
index 09b33c3..d68e21b 100644
--- a/hosts/jupiter/users/storm/configs/console/podman/media/default.nix
+++ b/hosts/jupiter/users/storm/configs/console/podman/media/default.nix
@@ -12,7 +12,7 @@
let
selfPkgs = inputs.self.packages.${system};
hmConfig = config.home-manager.users.${user};
- inherit (hmConfig.virtualisation.quadlet) volumes networks;
+ inherit (hmConfig.virtualisation.quadlet) containers volumes networks;
jellyfinAutheliaClientId = "59TRpNutxEeRRCAZbDsK7rsnrA5NC69HAdAO45CEfc740xl4hgIacDy2u03oiFc89Exb67udBQvmfwxgeAQtJPiNAJxA5OzGmdQf";
in
@@ -24,7 +24,6 @@ in
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/shows 755 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/anime-films 755 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/anime-shows 755 storm storm"
- "d /mnt/storage/private/storm/containers/storage/volumes/media/_data/music 755 storm storm"
];
sops = {
@@ -34,6 +33,11 @@ in
"jellyfin/authelia/digest".sopsFile = ../../../../../../secrets/secrets.yaml;
"prowlarr/apiKey".sopsFile = ../../../../../../secrets/secrets.yaml;
+
+ "radarr-films/apiKey".sopsFile = ../../../../../../secrets/secrets.yaml;
+ "radarr-anime-films/apiKey".sopsFile = ../../../../../../secrets/secrets.yaml;
+ "sonarr-shows/apiKey".sopsFile = ../../../../../../secrets/secrets.yaml;
+ "sonarr-anime-shows/apiKey".sopsFile = ../../../../../../secrets/secrets.yaml;
};
templates = {
@@ -79,6 +83,118 @@ in
prowlarr-env.content = ''
PROWLARR_API_KEY=${hmConfig.sops.placeholder."prowlarr/apiKey"}
'';
+
+ prowlarr-radarr-films.content = builtins.readFile (
+ (pkgs.formats.json { }).generate "radarr-films.json" {
+ enable = true;
+ name = "Radarr (Films)";
+ implementation = "Radarr";
+ configContract = "RadarrSettings";
+ syncLevel = "fullSync";
+ fields = [
+ {
+ name = "prowlarrUrl";
+ value = "http://prowlarr:9696";
+ }
+ {
+ name = "baseUrl";
+ value = "http://radarr-films:7878";
+ }
+ {
+ name = "apiKey";
+ value = hmConfig.sops.placeholder."radarr-films/apiKey";
+ }
+ ];
+ }
+ );
+
+ prowlarr-radarr-anime-films.content = builtins.readFile (
+ (pkgs.formats.json { }).generate "radarr-anime-films.json" {
+ enable = true;
+ name = "Radarr (Anime Films)";
+ implementation = "Radarr";
+ configContract = "RadarrSettings";
+ syncLevel = "fullSync";
+ fields = [
+ {
+ name = "prowlarrUrl";
+ value = "http://prowlarr:9696";
+ }
+ {
+ name = "baseUrl";
+ value = "http://radarr-anime-films:7878";
+ }
+ {
+ name = "apiKey";
+ value = hmConfig.sops.placeholder."radarr-anime-films/apiKey";
+ }
+ ];
+ }
+ );
+
+ prowlarr-sonarr-shows.content = builtins.readFile (
+ (pkgs.formats.json { }).generate "sonarr-shows.json" {
+ enable = true;
+ name = "Sonarr (Shows)";
+ implementation = "Sonarr";
+ configContract = "SonarrSettings";
+ syncLevel = "fullSync";
+ fields = [
+ {
+ name = "prowlarrUrl";
+ value = "http://prowlarr:9696";
+ }
+ {
+ name = "baseUrl";
+ value = "http://sonarr-shows:8989";
+ }
+ {
+ name = "apiKey";
+ value = hmConfig.sops.placeholder."sonarr-shows/apiKey";
+ }
+ ];
+ }
+ );
+
+ prowlarr-sonarr-anime-shows.content = builtins.readFile (
+ (pkgs.formats.json { }).generate "sonarr-anime-shows.json" {
+ enable = true;
+ name = "Sonarr (Anime Shows)";
+ implementation = "Sonarr";
+ configContract = "SonarrSettings";
+ syncLevel = "fullSync";
+ fields = [
+ {
+ name = "prowlarrUrl";
+ value = "http://prowlarr:9696";
+ }
+ {
+ name = "baseUrl";
+ value = "http://sonarr-anime-shows:8989";
+ }
+ {
+ name = "apiKey";
+ value = hmConfig.sops.placeholder."sonarr-anime-shows/apiKey";
+ }
+ ];
+ }
+ );
+
+ radarr-films-env.content = ''
+ RADARR_API_KEY=${hmConfig.sops.placeholder."radarr-films/apiKey"}
+ '';
+
+ radarr-anime-films-env.content = ''
+ RADARR_API_KEY=${hmConfig.sops.placeholder."radarr-anime-films/apiKey"}
+ '';
+
+ sonarr-shows-env.content = ''
+ SONARR_API_KEY=${hmConfig.sops.placeholder."sonarr-shows/apiKey"}
+ '';
+
+ sonarr-anime-shows-env.content = ''
+ SONARR_API_KEY=${hmConfig.sops.placeholder."sonarr-anime-shows/apiKey"}
+ '';
};
};
@@ -96,6 +212,11 @@ in
jellyfin-cache = { };
prowlarr = { };
+
+ radarr-films = { };
+ radarr-anime-films = { };
+ sonarr-shows = { };
+ sonarr-anime-shows = { };
};
containers = {
@@ -133,7 +254,14 @@ in
devices = [ "nvidia.com/gpu=all" ];
};
- unitConfig.After = [ "sops-nix.service" ];
+ unitConfig =
+ let
+ dependencies = [ "sops-nix.service" ];
+ in
+ {
+ After = dependencies;
+ Requires = dependencies;
+ };
};
flaresolverr.containerConfig = {
@@ -168,18 +296,205 @@ in
"${setup}:/etc/prowlarr/setup.sh:ro"
"${postStart}:/etc/prowlarr/post-start.sh:ro"
"${./prowlarr/indexers}:/etc/prowlarr/indexers:ro"
+ "${hmConfig.sops.templates.prowlarr-radarr-films.path}:/etc/prowlarr/apps/radarr-films.json:ro"
+ "${hmConfig.sops.templates.prowlarr-radarr-anime-films.path}:/etc/prowlarr/apps/radarr-anime-films.json:ro"
+ "${hmConfig.sops.templates.prowlarr-sonarr-shows.path}:/etc/prowlarr/apps/sonarr-shows.json:ro"
+ "${hmConfig.sops.templates.prowlarr-sonarr-anime-shows.path}:/etc/prowlarr/apps/sonarr-anime-shows.json:ro"
"${volumes.prowlarr.ref}:/var/lib/prowlarr"
];
- environments.PROWLARR_URL_BASE = "/indexers";
+ environments.PROWLARR_URL_BASE = "/manage/indexers";
environmentFiles = [ hmConfig.sops.templates.prowlarr-env.path ];
labels = [
"traefik.enable=true"
- "traefik.http.routers.prowlarr.rule=Host(`media.karaolidis.com`) && PathPrefix(`/indexers`)"
+ "traefik.http.routers.prowlarr.rule=Host(`media.karaolidis.com`) && PathPrefix(`/manage/indexers`)"
"traefik.http.routers.prowlarr.middlewares=authelia@docker"
];
};
- unitConfig.After = [ "sops-nix.service" ];
+ unitConfig =
+ let
+ dependencies = [
+ "sops-nix.service"
+ "${containers.transmission._serviceName}.service"
+ "${containers.flaresolverr._serviceName}.service"
+ "${containers.radarr-films._serviceName}.service"
+ "${containers.radarr-anime-films._serviceName}.service"
+ "${containers.sonarr-shows._serviceName}.service"
+ "${containers.sonarr-anime-shows._serviceName}.service"
+ ];
+ in
+ {
+ After = dependencies;
+ Requires = dependencies;
+ };
+ };
+
+ radarr-films = {
+ containerConfig = {
+ image = "docker-archive:${selfPkgs.docker-radarr}";
+ networks = [
+ networks.media.ref
+ networks.transmission.ref
+ networks.traefik.ref
+ ];
+ volumes =
+ let
+ setup = pkgs.writeTextFile {
+ name = "setup.sh";
+ executable = true;
+ text = builtins.readFile ./radarr/setup.sh;
+ };
+ in
+ [
+ "${setup}:/etc/radarr/setup.sh:ro"
+ "${volumes.radarr-films.ref}:/var/lib/radarr"
+ ];
+ environments.RADARR_URL_BASE = "/manage/films";
+ environmentFiles = [ hmConfig.sops.templates.radarr-films-env.path ];
+ labels = [
+ "traefik.enable=true"
+ "traefik.http.routers.radarr-films.rule=Host(`media.karaolidis.com`) && PathPrefix(`/manage/films`)"
+ "traefik.http.routers.radarr-films.middlewares=authelia@docker"
+ ];
+ };
+
+ unitConfig =
+ let
+ dependencies = [
+ "${containers.transmission._serviceName}.service"
+ "sops-nix.service"
+ ];
+ in
+ {
+ After = dependencies;
+ Requires = dependencies;
+ };
+ };
+
+ radarr-anime-films = {
+ containerConfig = {
+ image = "docker-archive:${selfPkgs.docker-radarr}";
+ networks = [
+ networks.media.ref
+ networks.transmission.ref
+ networks.traefik.ref
+ ];
+ volumes =
+ let
+ setup = pkgs.writeTextFile {
+ name = "setup.sh";
+ executable = true;
+ text = builtins.readFile ./radarr/setup.sh;
+ };
+ in
+ [
+ "${setup}:/etc/radarr/setup.sh:ro"
+ "${volumes.radarr-anime-films.ref}:/var/lib/radarr"
+ ];
+ environments.RADARR_URL_BASE = "/manage/anime-films";
+ environmentFiles = [ hmConfig.sops.templates.radarr-anime-films-env.path ];
+ labels = [
+ "traefik.enable=true"
+ "traefik.http.routers.radarr-anime-films.rule=Host(`media.karaolidis.com`) && PathPrefix(`/manage/anime-films`)"
+ "traefik.http.routers.radarr-anime-films.middlewares=authelia@docker"
+ ];
+ };
+
+ unitConfig =
+ let
+ dependencies = [
+ "${containers.transmission._serviceName}.service"
+ "sops-nix.service"
+ ];
+ in
+ {
+ After = dependencies;
+ Requires = dependencies;
+ };
+ };
+
+ sonarr-shows = {
+ containerConfig = {
+ image = "docker-archive:${selfPkgs.docker-sonarr}";
+ networks = [
+ networks.media.ref
+ networks.transmission.ref
+ networks.traefik.ref
+ ];
+ volumes =
+ let
+ setup = pkgs.writeTextFile {
+ name = "setup.sh";
+ executable = true;
+ text = builtins.readFile ./sonarr/setup.sh;
+ };
+ in
+ [
+ "${setup}:/etc/sonarr/setup.sh:ro"
+ "${volumes.sonarr-shows.ref}:/var/lib/sonarr"
+ ];
+ environments.SONARR_URL_BASE = "/manage/shows";
+ environmentFiles = [ hmConfig.sops.templates.sonarr-shows-env.path ];
+ labels = [
+ "traefik.enable=true"
+ "traefik.http.routers.sonarr-shows.rule=Host(`media.karaolidis.com`) && PathPrefix(`/manage/shows`)"
+ "traefik.http.routers.sonarr-shows.middlewares=authelia@docker"
+ ];
+ };
+
+ unitConfig =
+ let
+ dependencies = [
+ "${containers.transmission._serviceName}.service"
+ "sops-nix.service"
+ ];
+ in
+ {
+ After = dependencies;
+ Requires = dependencies;
+ };
+ };
+
+ sonarr-anime-shows = {
+ containerConfig = {
+ image = "docker-archive:${selfPkgs.docker-sonarr}";
+ networks = [
+ networks.media.ref
+ networks.transmission.ref
+ networks.traefik.ref
+ ];
+ volumes =
+ let
+ setup = pkgs.writeTextFile {
+ name = "setup.sh";
+ executable = true;
+ text = builtins.readFile ./sonarr/setup.sh;
+ };
+ in
+ [
+ "${setup}:/etc/sonarr/setup.sh:ro"
+ "${volumes.sonarr-anime-shows.ref}:/var/lib/sonarr"
+ ];
+ environments.SONARR_URL_BASE = "/manage/anime-shows";
+ environmentFiles = [ hmConfig.sops.templates.sonarr-anime-shows-env.path ];
+ labels = [
+ "traefik.enable=true"
+ "traefik.http.routers.sonarr-anime-shows.rule=Host(`media.karaolidis.com`) && PathPrefix(`/manage/anime-shows`)"
+ "traefik.http.routers.sonarr-anime-shows.middlewares=authelia@docker"
+ ];
+ };
+
+ unitConfig =
+ let
+ dependencies = [
+ "${containers.transmission._serviceName}.service"
+ "sops-nix.service"
+ ];
+ in
+ {
+ After = dependencies;
+ Requires = dependencies;
+ };
};
authelia.containerConfig.volumes =
@@ -189,13 +504,13 @@ in
{
domain = "media.karaolidis.com";
policy = "one_factor";
- resources = [ "^/(indexers|films|shows|anime-films|anime-shows)([/?].*)?$" ];
+ resources = [ "^/manage([/?].*)?$" ];
subject = [ "group:media" ];
}
{
domain = "media.karaolidis.com";
policy = "deny";
- resources = [ "^/(indexers|films|shows|anime-films|anime-shows)([/?].*)?$" ];
+ resources = [ "^/manage([/?].*)?$" ];
}
{
domain = "media.karaolidis.com";
diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/music/Music.json b/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/music/Music.json
deleted file mode 100644
index 9d1ffeb..0000000
--- a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/music/Music.json
+++ /dev/null
@@ -1,229 +0,0 @@
-{
- "LibraryOptions": {
- "Enabled": true,
- "EnableArchiveMediaFiles": false,
- "EnablePhotos": true,
- "EnableRealtimeMonitor": true,
- "EnableLUFSScan": true,
- "ExtractTrickplayImagesDuringLibraryScan": false,
- "SaveTrickplayWithMedia": false,
- "EnableTrickplayImageExtraction": false,
- "ExtractChapterImagesDuringLibraryScan": false,
- "EnableChapterImageExtraction": false,
- "EnableInternetProviders": true,
- "SaveLocalMetadata": true,
- "EnableAutomaticSeriesGrouping": false,
- "PreferredMetadataLanguage": "en",
- "MetadataCountryCode": "US",
- "SeasonZeroDisplayName": "Specials",
- "AutomaticRefreshIntervalDays": 30,
- "EnableEmbeddedTitles": false,
- "EnableEmbeddedExtrasTitles": false,
- "EnableEmbeddedEpisodeInfos": false,
- "AllowEmbeddedSubtitles": "AllowAll",
- "SkipSubtitlesIfEmbeddedSubtitlesPresent": false,
- "SkipSubtitlesIfAudioTrackMatches": false,
- "SaveSubtitlesWithMedia": true,
- "SaveLyricsWithMedia": true,
- "RequirePerfectSubtitleMatch": true,
- "AutomaticallyAddToCollection": false,
- "PreferNonstandardArtistsTag": false,
- "UseCustomTagDelimiters": false,
- "MetadataSavers": ["Nfo"],
- "TypeOptions": [
- {
- "Type": "MusicArtist",
- "MetadataFetchers": ["MusicBrainz", "TheAudioDB"],
- "MetadataFetcherOrder": ["MusicBrainz", "TheAudioDB"],
- "ImageFetchers": ["TheAudioDB"],
- "ImageFetcherOrder": ["TheAudioDB"],
- "ImageOptions": [
- {
- "Type": "Primary",
- "Limit": 1,
- "MinWidth": 0
- },
- {
- "Type": "Art",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "BoxRear",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Banner",
- "Limit": 1,
- "MinWidth": 0
- },
- {
- "Type": "Box",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Disc",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Logo",
- "Limit": 1,
- "MinWidth": 0
- },
- {
- "Type": "Menu",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Thumb",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Backdrop",
- "Limit": "1",
- "MinWidth": "1280"
- }
- ]
- },
- {
- "Type": "MusicAlbum",
- "MetadataFetchers": ["MusicBrainz", "TheAudioDB"],
- "MetadataFetcherOrder": ["MusicBrainz", "TheAudioDB"],
- "ImageFetchers": ["TheAudioDB"],
- "ImageFetcherOrder": ["TheAudioDB"],
- "ImageOptions": [
- {
- "Type": "Primary",
- "Limit": 1,
- "MinWidth": 0
- },
- {
- "Type": "Art",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "BoxRear",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Banner",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Box",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Disc",
- "Limit": 1,
- "MinWidth": 0
- },
- {
- "Type": "Logo",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Menu",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Thumb",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Backdrop",
- "Limit": "0",
- "MinWidth": "1280"
- }
- ]
- },
- {
- "Type": "Audio",
- "ImageFetchers": ["Image Extractor"],
- "ImageFetcherOrder": ["Image Extractor"]
- },
- {
- "Type": "MusicVideo",
- "ImageFetchers": ["Embedded Image Extractor", "Screen Grabber"],
- "ImageFetcherOrder": ["Embedded Image Extractor", "Screen Grabber"],
- "ImageOptions": [
- {
- "Type": "Primary",
- "Limit": 1,
- "MinWidth": 0
- },
- {
- "Type": "Art",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "BoxRear",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Banner",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Box",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Disc",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Logo",
- "Limit": 1,
- "MinWidth": 0
- },
- {
- "Type": "Menu",
- "Limit": 0,
- "MinWidth": 0
- },
- {
- "Type": "Thumb",
- "Limit": 1,
- "MinWidth": 0
- },
- {
- "Type": "Backdrop",
- "Limit": "1",
- "MinWidth": "1280"
- }
- ]
- }
- ],
- "LocalMetadataReaderOrder": ["Nfo"],
- "SubtitleDownloadLanguages": [],
- "CustomTagDelimiters": ["/", "|", ";", "\\"],
- "DelimiterWhitelist": [],
- "DisabledSubtitleFetchers": [],
- "SubtitleFetcherOrder": [],
- "DisabledLyricFetchers": [],
- "LyricFetcherOrder": [],
- "PathInfos": [
- {
- "Path": "/var/lib/media/music"
- }
- ]
- }
-}
diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/prowlarr/setup.sh b/hosts/jupiter/users/storm/configs/console/podman/media/prowlarr/setup.sh
index 3066b15..c31d561 100644
--- a/hosts/jupiter/users/storm/configs/console/podman/media/prowlarr/setup.sh
+++ b/hosts/jupiter/users/storm/configs/console/podman/media/prowlarr/setup.sh
@@ -5,13 +5,14 @@ curl -sf "$PROWLARR_HOST/api/v1/tag" \
-X POST \
-H 'Content-Type: application/json' \
-H "X-Api-Key: $PROWLARR_API_KEY" \
- --data-raw '{"label": "flaresolverr"}'
+ --data-raw '{"label": "flaresolverr"}' || true
-curl -sf "$PROWLARR_HOST/api/v1/indexerProxy?forceSave=true" \
- -X POST \
- -H 'Content-Type: application/json' \
- -H "X-Api-Key: $PROWLARR_API_KEY" \
- --data-binary @- <' > /var/lib/radarr/config.xml
+
+ xmlstarlet ed -L \
+ -s /Config -t elem -n LaunchBrowser -v "False" \
+ -s /Config -t elem -n ApiKey -v "$RADARR_API_KEY" \
+ -s /Config -t elem -n AuthenticationMethod -v "External" \
+ -s /Config -t elem -n AuthenticationRequired -v "DisabledForLocalAddresses" \
+ -s /Config -t elem -n LogLevel -v "info" \
+ -s /Config -t elem -n UrlBase -v "${RADARR_URL_BASE:-}" \
+ -s /Config -t elem -n InstanceName -v "${RADARR_INSTANCE_NAME:-radarr}" \
+ -s /Config -t elem -n AnalyticsEnabled -v "False" \
+ /var/lib/radarr/config.xml
+fi
+
+Radarr -data=/var/lib/radarr -nobrowser "$@" &
+PID=$!
+
+RADARR_HOST="http://localhost:7878${RADARR_URL_BASE:-}"
+
+if [ ! -f /var/lib/radarr/init ]; then
+ curl -sf --retry 10 --retry-connrefused \
+ -H "X-Api-Key: $RADARR_API_KEY" \
+ "$RADARR_HOST/api/v1/health"
+
+ if [ -f /etc/radarr/setup.sh ]; then
+ # shellcheck disable=SC1091
+ . /etc/radarr/setup.sh
+ fi
+
+ touch /var/lib/radarr/init
+fi
+
+trap 'kill -INT "$PID"' INT TERM
+wait "$PID"
+exit $?
diff --git a/packages/docker/sonarr/default.nix b/packages/docker/sonarr/default.nix
new file mode 100644
index 0000000..854e8d2
--- /dev/null
+++ b/packages/docker/sonarr/default.nix
@@ -0,0 +1,43 @@
+{ pkgs, ... }:
+let
+ entrypoint = pkgs.writeTextFile {
+ name = "entrypoint";
+ executable = true;
+ destination = "/bin/entrypoint";
+ text = builtins.readFile ./entrypoint.sh;
+ };
+in
+pkgs.dockerTools.buildImage {
+ name = "sonarr";
+ fromImage = import ../base { inherit pkgs; };
+
+ copyToRoot = pkgs.buildEnv {
+ name = "root";
+ paths = with pkgs; [
+ entrypoint
+ sonarr
+ xmlstarlet
+ curl
+ jq
+ ];
+ pathsToLink = [
+ "/bin"
+ "/lib"
+ ];
+ };
+
+ runAsRoot = ''
+ ${pkgs.dockerTools.shadowSetup}
+ '';
+
+ config = {
+ Entrypoint = [ "entrypoint" ];
+ ExposedPorts = {
+ "8989/tcp" = { };
+ };
+ WorkingDir = "/var/lib/sonarr";
+ Volumes = {
+ "/var/lib/sonarr" = { };
+ };
+ };
+}
diff --git a/packages/docker/sonarr/entrypoint.sh b/packages/docker/sonarr/entrypoint.sh
new file mode 100644
index 0000000..86f0bad
--- /dev/null
+++ b/packages/docker/sonarr/entrypoint.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env sh
+
+set -o errexit
+set -o nounset
+
+if [ ! -f /var/lib/sonarr/init ]; then
+ echo '' > /var/lib/sonarr/config.xml
+
+ xmlstarlet ed -L \
+ -s /Config -t elem -n LaunchBrowser -v "False" \
+ -s /Config -t elem -n ApiKey -v "$SONARR_API_KEY" \
+ -s /Config -t elem -n AuthenticationMethod -v "External" \
+ -s /Config -t elem -n AuthenticationRequired -v "DisabledForLocalAddresses" \
+ -s /Config -t elem -n LogLevel -v "info" \
+ -s /Config -t elem -n UrlBase -v "${SONARR_URL_BASE:-}" \
+ -s /Config -t elem -n InstanceName -v "${SONARR_INSTANCE_NAME:-sonarr}" \
+ -s /Config -t elem -n AnalyticsEnabled -v "False" \
+ /var/lib/sonarr/config.xml
+fi
+
+Sonarr -data=/var/lib/sonarr -nobrowser "$@" &
+PID=$!
+
+SONARR_HOST="http://localhost:8989${SONARR_URL_BASE:-}"
+
+if [ ! -f /var/lib/sonarr/init ]; then
+ curl -sf --retry 10 --retry-connrefused \
+ -H "X-Api-Key: $SONARR_API_KEY" \
+ "$SONARR_HOST/api/v1/health"
+
+ if [ -f /etc/sonarr/setup.sh ]; then
+ # shellcheck disable=SC1091
+ . /etc/sonarr/setup.sh
+ fi
+
+ touch /var/lib/sonarr/init
+fi
+
+trap 'kill -INT "$PID"' INT TERM
+wait "$PID"
+exit $?