diff --git a/flake.lock b/flake.lock index fd776ad..8267763 100644 --- a/flake.lock +++ b/flake.lock @@ -173,11 +173,11 @@ ] }, "locked": { - "lastModified": 1751647666, - "narHash": "sha256-7hqxvyEVdObjo+4KaGEvfdwjdXnrM29H0amu5pwhlpM=", + "lastModified": 1751668458, + "narHash": "sha256-GKNMo5gVuAuwTIkHD7b9abm1TvSv+gYNo4MSnekmg1g=", "owner": "nix-community", "repo": "NUR", - "rev": "998983fdb616a1bd83fb178fd16730160473672a", + "rev": "7bdd7e68584498bb1a8304454067d1bd95a9ecae", "type": "github" }, "original": { @@ -187,6 +187,28 @@ "type": "github" } }, + "nvidia-patch": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "utils": "utils" + }, + "locked": { + "lastModified": 1751055357, + "narHash": "sha256-F3BW9LVnFK378ztxXty5NJmSOxhgpc0LH0QHrrThBOA=", + "owner": "icewind1991", + "repo": "nvidia-patch-nixos", + "rev": "d5947772bf136484712f5d560df161990d427687", + "type": "github" + }, + "original": { + "owner": "icewind1991", + "ref": "main", + "repo": "nvidia-patch-nixos", + "type": "github" + } + }, "quadlet-nix": { "locked": { "lastModified": 1751500838, @@ -212,10 +234,11 @@ "home-manager": "home-manager", "nixpkgs": "nixpkgs", "nur": "nur", + "nvidia-patch": "nvidia-patch", "quadlet-nix": "quadlet-nix", "sops-nix": "sops-nix", "spicetify-nix": "spicetify-nix", - "systems": "systems", + "systems": "systems_2", "treefmt-nix": "treefmt-nix" } }, @@ -265,6 +288,21 @@ } }, "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", @@ -300,6 +338,24 @@ "repo": "treefmt-nix", "type": "github" } + }, + "utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index a188bb7..29798b9 100644 --- a/flake.nix +++ b/flake.nix @@ -125,6 +125,15 @@ systems.follows = "systems"; }; }; + + nvidia-patch = { + type = "github"; + owner = "icewind1991"; + repo = "nvidia-patch-nixos"; + ref = "main"; + + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = diff --git a/hosts/common/configs/system/podman/default.nix b/hosts/common/configs/system/podman/default.nix index aa4108f..0974d21 100644 --- a/hosts/common/configs/system/podman/default.nix +++ b/hosts/common/configs/system/podman/default.nix @@ -10,7 +10,10 @@ storage.settings.storage.driver = "btrfs"; }; - quadlet.autoEscape = true; + quadlet = { + enable = true; + autoEscape = true; + }; }; environment = { diff --git a/hosts/common/configs/user/console/podman/default.nix b/hosts/common/configs/user/console/podman/default.nix index c00c619..d469616 100644 --- a/hosts/common/configs/user/console/podman/default.nix +++ b/hosts/common/configs/user/console/podman/default.nix @@ -19,7 +19,10 @@ settings.storage.storage.driver = "btrfs"; }; - virtualisation.quadlet.autoEscape = true; + virtualisation.quadlet = { + enable = true; + autoEscape = true; + }; home = { packages = with pkgs; [ diff --git a/hosts/jupiter/default.nix b/hosts/jupiter/default.nix index 716540a..7c64eff 100644 --- a/hosts/jupiter/default.nix +++ b/hosts/jupiter/default.nix @@ -52,7 +52,8 @@ ''; }; - users.groups.storage = { }; + # echo $(( (0x$(echo -n "storage" | sha256sum | cut -c1-8) % 999 ) + 1 )) + users.groups.storage.gid = 694; systemd.tmpfiles.rules = [ "v /mnt/storage/public 2770 root storage - -" diff --git a/hosts/jupiter/hardware/default.nix b/hosts/jupiter/hardware/default.nix index 902816c..3f77de9 100644 --- a/hosts/jupiter/hardware/default.nix +++ b/hosts/jupiter/hardware/default.nix @@ -2,11 +2,14 @@ config, pkgs, lib, + inputs, ... }: { imports = [ ./display.nix ]; + nixpkgs.overlays = [ inputs.nvidia-patch.overlays.default ]; + hardware = { enableAllFirmware = true; @@ -17,6 +20,11 @@ }; nvidia = { + # TODO: Enable + # package = pkgs.nvidia-patch.patch-nvenc ( + # pkgs.nvidia-patch.patch-fbc config.boot.kernelPackages.nvidiaPackages.stable + # ); + open = true; powerManagement.enable = true; dynamicBoost.enable = true; @@ -42,7 +50,7 @@ }; nvidia-container-toolkit.enable = - config.virtualisation.containerd.enable || config.virtualisation.docker.enable; + config.virtualisation.containerd.enable || config.virtualisation.podman.enable; }; boot = { 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 67c0faa..8345ac1 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix @@ -68,7 +68,7 @@ in identity_validation.reset_password.jwt_secret = hmConfig.sops.placeholder."authelia/resetPasswordJwt"; - definitions.user_attributes.is_admin.expression = "\"admins\" in groups"; + definitions.user_attributes.is_admin.expression = "\"admin\" in groups"; identity_providers.oidc = { hmac_secret = hmConfig.sops.placeholder."authelia/oidcHmac"; @@ -81,7 +81,7 @@ in rules = [ { policy = "two_factor"; - subject = [ "group:admins" ]; + subject = [ "group:admin" ]; } ]; }; @@ -91,7 +91,7 @@ in rules = [ { policy = "one_factor"; - subject = [ "group:admins" ]; + subject = [ "group:admin" ]; } ]; }; @@ -134,10 +134,11 @@ in password = hmConfig.sops.placeholder."authelia/users/karaolidis"; email = "nick@karaolidis.com"; groups = [ - "admins" + "admin" + "media" "vaultwarden" "nextcloud" - "media" + "jellyfin" "gitea" "outline" "shlink" @@ -149,7 +150,7 @@ in }; virtualisation.quadlet = { - networks.authelia.networkConfig.internal = true; + networks.authelia = { }; volumes = { authelia-redis = { }; @@ -159,24 +160,24 @@ in containers = { authelia-init = { - containerConfig = - let - entrypoint = pkgs.writeTextFile { - name = "entrypoint.sh"; - executable = true; - text = builtins.readFile ./init-entrypoint.sh; - }; - in - { - image = "docker-archive:${selfPkgs.docker-yq}"; - volumes = [ + containerConfig = { + image = "docker-archive:${selfPkgs.docker-yq}"; + volumes = + let + entrypoint = pkgs.writeTextFile { + name = "entrypoint.sh"; + executable = true; + text = builtins.readFile ./init-entrypoint.sh; + }; + in + [ "${volumes.authelia.ref}:/etc/authelia" "${hmConfig.sops.templates.authelia-users.path}:/etc/authelia/users.yaml.default:ro" "${hmConfig.sops.templates.authelia.path}:/etc/authelia/conf.d/authelia.yaml:ro" "${entrypoint}:/entrypoint.sh:ro" ]; - entrypoint = "/entrypoint.sh"; - }; + entrypoint = "/entrypoint.sh"; + }; serviceConfig = { Type = "oneshot"; diff --git a/hosts/jupiter/users/storm/configs/console/podman/authelia/init-entrypoint.sh b/hosts/jupiter/users/storm/configs/console/podman/authelia/init-entrypoint.sh index a8798a3..725a9ab 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/authelia/init-entrypoint.sh +++ b/hosts/jupiter/users/storm/configs/console/podman/authelia/init-entrypoint.sh @@ -1,5 +1,8 @@ #!/bin/sh +set -o errexit +set -o nounset + touch /etc/authelia/users.yaml # shellcheck disable=SC2016 yq eval-all '. as $item ireduce ({}; . * $item)' /etc/authelia/users.yaml /etc/authelia/users.yaml.default -i diff --git a/hosts/jupiter/users/storm/configs/console/podman/default.nix b/hosts/jupiter/users/storm/configs/console/podman/default.nix index 26bf44a..c7d51f8 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/default.nix @@ -11,6 +11,7 @@ in (import ./authelia { inherit user home; }) (import ./gitea { inherit user home; }) (import ./grafana { inherit user home; }) + (import ./jellyfin { inherit user home; }) (import ./nextcloud { inherit user home; }) (import ./ntfy { inherit user home; }) (import ./outline { inherit user home; }) 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 29d8804..090fce8 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/gitea/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/gitea/default.nix @@ -199,7 +199,7 @@ in ]; virtualisation.quadlet = { - networks.gitea.networkConfig.internal = true; + networks.gitea = { }; volumes = { gitea-postgresql = { }; diff --git a/hosts/jupiter/users/storm/configs/console/podman/gitea/entrypoint.sh b/hosts/jupiter/users/storm/configs/console/podman/gitea/entrypoint.sh index 9d2b4ab..d489939 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/gitea/entrypoint.sh +++ b/hosts/jupiter/users/storm/configs/console/podman/gitea/entrypoint.sh @@ -12,6 +12,6 @@ gitea admin auth add-oauth \ --scopes='openid email profile groups' \ --skip-local-2fa \ --group-claim-name=groups \ - --admin-group=admins 2>&1 || true + --admin-group=admin 2>&1 || true exec gitea web -c /etc/gitea/app.ini 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 104a47f..338f53b 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/grafana/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/grafana/default.nix @@ -87,9 +87,9 @@ in groups_attribute_path = "groups"; allow_assign_grafana_admin = true; role_attribute_strict = true; - role_attribute_path = "contains(groups, 'admins') && 'GrafanaAdmin' || 'Viewer'"; + role_attribute_path = "contains(groups, 'admin') && 'GrafanaAdmin' || 'Viewer'"; org_attribute_path = "groups"; - org_mapping = "admins:1:Admin *:1:Viewer"; + org_mapping = "admin:1:Admin *:1:Viewer"; }; smtp = { @@ -122,7 +122,7 @@ in }; virtualisation.quadlet = { - networks.grafana.networkConfig.internal = true; + networks.grafana = { }; containers = { grafana = { diff --git a/hosts/jupiter/users/storm/configs/console/podman/jellyfin/default.nix b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/default.nix new file mode 100644 index 0000000..2836ce4 --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/default.nix @@ -0,0 +1,132 @@ +{ + user ? throw "user argument is required", + home ? throw "home argument is required", +}: +{ + config, + inputs, + pkgs, + system, + ... +}: +let + selfPkgs = inputs.self.packages.${system}; + hmConfig = config.home-manager.users.${user}; + inherit (hmConfig.virtualisation.quadlet) volumes networks; + autheliaClientId = "59TRpNutxEeRRCAZbDsK7rsnrA5NC69HAdAO45CEfc740xl4hgIacDy2u03oiFc89Exb67udBQvmfwxgeAQtJPiNAJxA5OzGmdQf"; +in +{ + home-manager.users.${user} = { + sops = { + secrets = { + "jellyfin/admin".sopsFile = ../../../../../../secrets/secrets.yaml; + "jellyfin/authelia/password".sopsFile = ../../../../../../secrets/secrets.yaml; + "jellyfin/authelia/digest".sopsFile = ../../../../../../secrets/secrets.yaml; + }; + + templates = { + jellyfin-env.content = '' + JELLYFIN_ADMIN_PASSWORD=${hmConfig.sops.placeholder."jellyfin/admin"} + JELLYFIN_OIDC_SECRET=${hmConfig.sops.placeholder."jellyfin/authelia/password"} + ''; + + authelia-jellyfin.content = builtins.readFile ( + (pkgs.formats.yaml { }).generate "jellyfin.yaml" { + identity_providers.oidc = { + authorization_policies.jellyfin = { + default_policy = "deny"; + rules = [ + { + policy = "one_factor"; + subject = "group:jellyfin"; + } + ]; + }; + + clients = [ + { + client_id = autheliaClientId; + client_name = "Jellyfin"; + client_secret = hmConfig.sops.placeholder."jellyfin/authelia/digest"; + redirect_uris = [ "https://media.karaolidis.com/sso/OID/redirect/authelia" ]; + authorization_policy = "jellyfin"; + require_pkce = true; + pkce_challenge_method = "S256"; + scopes = [ + "openid" + "profile" + "groups" + ]; + token_endpoint_auth_method = "client_secret_post"; + } + ]; + }; + } + ); + }; + }; + + systemd.user.tmpfiles.rules = [ + "d /mnt/storage/private/storm/containers/storage/volumes/media/_data 700 storm storm" + "d /mnt/storage/private/storm/containers/storage/volumes/media/_data/films 755 storm storm" + "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" + ]; + + virtualisation.quadlet = { + networks.jellyfin = { }; + + volumes = { + jellyfin-config = { }; + jellyfin-data = { }; + jellyfin-log = { }; + jellyfin-cache = { }; + }; + + containers = { + jellyfin = { + containerConfig = { + image = "docker-archive:${selfPkgs.docker-jellyfin}"; + networks = [ + networks.jellyfin.ref + networks.traefik.ref + ]; + volumes = + let + setup = pkgs.writeTextFile { + name = "setup.sh"; + executable = true; + text = builtins.readFile ./setup.sh; + }; + in + [ + "/mnt/storage/private/storm/containers/storage/volumes/media/_data:/var/lib/media" + "${setup}:/etc/jellyfin/setup.sh:ro" + "${./libraries}:/etc/jellyfin/libraries:ro" + "${volumes.jellyfin-config.ref}:/etc/jellyfin" + "${volumes.jellyfin-data.ref}:/var/lib/jellyfin" + "${volumes.jellyfin-log.ref}:/var/log/jellyfin" + "${volumes.jellyfin-cache.ref}:/tmp/jellyfin" + ]; + environments.JELLYFIN_OIDC_CLIENT_ID = autheliaClientId; + environmentFiles = [ hmConfig.sops.templates.jellyfin-env.path ]; + labels = [ + "traefik.enable=true" + "traefik.http.routers.jellyfin.rule=Host(`media.karaolidis.com`)" + ]; + podmanArgs = [ "--cdi-spec-dir=/run/cdi" ]; + devices = [ "nvidia.com/gpu=all" ]; + }; + + unitConfig.After = [ "sops-nix.service" ]; + }; + + authelia-init.containerConfig.volumes = [ + "${hmConfig.sops.templates.authelia-jellyfin.path}:/etc/authelia/conf.d/jellyfin.yaml:ro" + ]; + }; + }; + }; +} diff --git a/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/movies/Anime Films.json b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/movies/Anime Films.json new file mode 100644 index 0000000..6202525 --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/movies/Anime Films.json @@ -0,0 +1,128 @@ +{ + "LibraryOptions": { + "Enabled": true, + "EnableArchiveMediaFiles": false, + "EnablePhotos": true, + "EnableRealtimeMonitor": true, + "EnableLUFSScan": true, + "ExtractTrickplayImagesDuringLibraryScan": false, + "SaveTrickplayWithMedia": true, + "EnableTrickplayImageExtraction": true, + "ExtractChapterImagesDuringLibraryScan": false, + "EnableChapterImageExtraction": true, + "EnableInternetProviders": true, + "SaveLocalMetadata": true, + "EnableAutomaticSeriesGrouping": false, + "PreferredMetadataLanguage": "en", + "MetadataCountryCode": "JP", + "SeasonZeroDisplayName": "Specials", + "AutomaticRefreshIntervalDays": 30, + "EnableEmbeddedTitles": false, + "EnableEmbeddedExtrasTitles": false, + "EnableEmbeddedEpisodeInfos": false, + "AllowEmbeddedSubtitles": "AllowAll", + "SkipSubtitlesIfEmbeddedSubtitlesPresent": false, + "SkipSubtitlesIfAudioTrackMatches": false, + "SaveSubtitlesWithMedia": true, + "SaveLyricsWithMedia": false, + "RequirePerfectSubtitleMatch": true, + "AutomaticallyAddToCollection": true, + "PreferNonstandardArtistsTag": false, + "UseCustomTagDelimiters": false, + "MetadataSavers": ["Nfo"], + "TypeOptions": [ + { + "Type": "Movie", + "MetadataFetchers": [ + "TheMovieDb", + "The Open Movie Database", + "TheTVDB" + ], + "MetadataFetcherOrder": [ + "TheMovieDb", + "The Open Movie Database", + "TheTVDB" + ], + "ImageFetchers": [ + "TheMovieDb", + "The Open Movie Database", + "TheTVDB", + "Embedded Image Extractor", + "Screen Grabber" + ], + "ImageFetcherOrder": [ + "TheMovieDb", + "The Open Movie Database", + "TheTVDB", + "Embedded Image Extractor", + "Screen Grabber" + ], + "ImageOptions": [ + { + "Type": "Primary", + "Limit": 1, + "MinWidth": 0 + }, + { + "Type": "Art", + "Limit": 1, + "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": 1, + "MinWidth": 0 + }, + { + "Type": "Backdrop", + "Limit": "1", + "MinWidth": "1280" + } + ] + } + ], + "LocalMetadataReaderOrder": ["Nfo"], + "SubtitleDownloadLanguages": [], + "CustomTagDelimiters": ["/", "|", ";", "\\"], + "DelimiterWhitelist": [], + "DisabledSubtitleFetchers": [], + "SubtitleFetcherOrder": [], + "DisabledLyricFetchers": [], + "LyricFetcherOrder": [], + "PathInfos": [ + { + "Path": "/var/lib/media/anime-films" + } + ] + } +} diff --git a/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/movies/Films.json b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/movies/Films.json new file mode 100644 index 0000000..cdb9345 --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/movies/Films.json @@ -0,0 +1,128 @@ +{ + "LibraryOptions": { + "Enabled": true, + "EnableArchiveMediaFiles": false, + "EnablePhotos": true, + "EnableRealtimeMonitor": true, + "EnableLUFSScan": true, + "ExtractTrickplayImagesDuringLibraryScan": false, + "SaveTrickplayWithMedia": true, + "EnableTrickplayImageExtraction": true, + "ExtractChapterImagesDuringLibraryScan": false, + "EnableChapterImageExtraction": true, + "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": false, + "RequirePerfectSubtitleMatch": true, + "AutomaticallyAddToCollection": true, + "PreferNonstandardArtistsTag": false, + "UseCustomTagDelimiters": false, + "MetadataSavers": ["Nfo"], + "TypeOptions": [ + { + "Type": "Movie", + "MetadataFetchers": [ + "TheMovieDb", + "The Open Movie Database", + "TheTVDB" + ], + "MetadataFetcherOrder": [ + "TheMovieDb", + "The Open Movie Database", + "TheTVDB" + ], + "ImageFetchers": [ + "TheMovieDb", + "The Open Movie Database", + "TheTVDB", + "Embedded Image Extractor", + "Screen Grabber" + ], + "ImageFetcherOrder": [ + "TheMovieDb", + "The Open Movie Database", + "TheTVDB", + "Embedded Image Extractor", + "Screen Grabber" + ], + "ImageOptions": [ + { + "Type": "Primary", + "Limit": 1, + "MinWidth": 0 + }, + { + "Type": "Art", + "Limit": 1, + "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": 1, + "MinWidth": 0 + }, + { + "Type": "Backdrop", + "Limit": "1", + "MinWidth": "1280" + } + ] + } + ], + "LocalMetadataReaderOrder": ["Nfo"], + "SubtitleDownloadLanguages": [], + "CustomTagDelimiters": ["/", "|", ";", "\\"], + "DelimiterWhitelist": [], + "DisabledSubtitleFetchers": [], + "SubtitleFetcherOrder": [], + "DisabledLyricFetchers": [], + "LyricFetcherOrder": [], + "PathInfos": [ + { + "Path": "/var/lib/media/films" + } + ] + } +} diff --git a/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/music/Music.json b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/music/Music.json new file mode 100644 index 0000000..9d1ffeb --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/music/Music.json @@ -0,0 +1,229 @@ +{ + "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/jellyfin/libraries/tvshows/Anime Shows.json b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/tvshows/Anime Shows.json new file mode 100644 index 0000000..f5d3b03 --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/tvshows/Anime Shows.json @@ -0,0 +1,204 @@ +{ + "LibraryOptions": { + "Enabled": true, + "EnableArchiveMediaFiles": false, + "EnablePhotos": true, + "EnableRealtimeMonitor": true, + "EnableLUFSScan": true, + "ExtractTrickplayImagesDuringLibraryScan": false, + "SaveTrickplayWithMedia": true, + "EnableTrickplayImageExtraction": true, + "ExtractChapterImagesDuringLibraryScan": false, + "EnableChapterImageExtraction": true, + "EnableInternetProviders": true, + "SaveLocalMetadata": true, + "EnableAutomaticSeriesGrouping": true, + "PreferredMetadataLanguage": "en", + "MetadataCountryCode": "JP", + "SeasonZeroDisplayName": "Specials", + "AutomaticRefreshIntervalDays": 30, + "EnableEmbeddedTitles": false, + "EnableEmbeddedExtrasTitles": false, + "EnableEmbeddedEpisodeInfos": false, + "AllowEmbeddedSubtitles": "AllowAll", + "SkipSubtitlesIfEmbeddedSubtitlesPresent": false, + "SkipSubtitlesIfAudioTrackMatches": false, + "SaveSubtitlesWithMedia": true, + "SaveLyricsWithMedia": false, + "RequirePerfectSubtitleMatch": true, + "AutomaticallyAddToCollection": false, + "PreferNonstandardArtistsTag": false, + "UseCustomTagDelimiters": false, + "MetadataSavers": ["Nfo"], + "TypeOptions": [ + { + "Type": "Series", + "MetadataFetchers": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database", + "Missing Episode Fetcher" + ], + "MetadataFetcherOrder": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database", + "Missing Episode Fetcher" + ], + "ImageFetchers": ["TheTVDB", "TheMovieDb"], + "ImageFetcherOrder": ["TheTVDB", "TheMovieDb"], + "ImageOptions": [ + { + "Type": "Primary", + "Limit": 1, + "MinWidth": 0 + }, + { + "Type": "Art", + "Limit": 1, + "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": 1, + "MinWidth": 0 + }, + { + "Type": "Backdrop", + "Limit": "1", + "MinWidth": "1280" + } + ] + }, + { + "Type": "Season", + "MetadataFetchers": ["TheTVDB", "TheMovieDb"], + "MetadataFetcherOrder": ["TheTVDB", "TheMovieDb"], + "ImageFetchers": ["TheTVDB", "TheMovieDb"], + "ImageFetcherOrder": ["TheTVDB", "TheMovieDb"], + "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": 0, + "MinWidth": 0 + }, + { + "Type": "Menu", + "Limit": 0, + "MinWidth": 0 + }, + { + "Type": "Thumb", + "Limit": 0, + "MinWidth": 0 + }, + { + "Type": "Backdrop", + "Limit": "0", + "MinWidth": "1280" + } + ] + }, + { + "Type": "Episode", + "MetadataFetchers": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database" + ], + "MetadataFetcherOrder": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database" + ], + "ImageFetchers": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database", + "Embedded Image Extractor", + "Screen Grabber" + ], + "ImageFetcherOrder": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database", + "Embedded Image Extractor", + "Screen Grabber" + ] + } + ], + "LocalMetadataReaderOrder": ["Nfo"], + "SubtitleDownloadLanguages": [], + "CustomTagDelimiters": ["/", "|", ";", "\\"], + "DelimiterWhitelist": [], + "DisabledSubtitleFetchers": [], + "SubtitleFetcherOrder": [], + "DisabledLyricFetchers": [], + "LyricFetcherOrder": [], + "PathInfos": [ + { + "Path": "/var/lib/media/anime-shows" + } + ] + } +} diff --git a/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/tvshows/Shows.json b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/tvshows/Shows.json new file mode 100644 index 0000000..7f24020 --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/libraries/tvshows/Shows.json @@ -0,0 +1,204 @@ +{ + "LibraryOptions": { + "Enabled": true, + "EnableArchiveMediaFiles": false, + "EnablePhotos": true, + "EnableRealtimeMonitor": true, + "EnableLUFSScan": true, + "ExtractTrickplayImagesDuringLibraryScan": false, + "SaveTrickplayWithMedia": true, + "EnableTrickplayImageExtraction": true, + "ExtractChapterImagesDuringLibraryScan": false, + "EnableChapterImageExtraction": true, + "EnableInternetProviders": true, + "SaveLocalMetadata": true, + "EnableAutomaticSeriesGrouping": true, + "PreferredMetadataLanguage": "en", + "MetadataCountryCode": "US", + "SeasonZeroDisplayName": "Specials", + "AutomaticRefreshIntervalDays": 30, + "EnableEmbeddedTitles": false, + "EnableEmbeddedExtrasTitles": false, + "EnableEmbeddedEpisodeInfos": false, + "AllowEmbeddedSubtitles": "AllowAll", + "SkipSubtitlesIfEmbeddedSubtitlesPresent": false, + "SkipSubtitlesIfAudioTrackMatches": false, + "SaveSubtitlesWithMedia": true, + "SaveLyricsWithMedia": false, + "RequirePerfectSubtitleMatch": true, + "AutomaticallyAddToCollection": false, + "PreferNonstandardArtistsTag": false, + "UseCustomTagDelimiters": false, + "MetadataSavers": ["Nfo"], + "TypeOptions": [ + { + "Type": "Series", + "MetadataFetchers": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database", + "Missing Episode Fetcher" + ], + "MetadataFetcherOrder": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database", + "Missing Episode Fetcher" + ], + "ImageFetchers": ["TheTVDB", "TheMovieDb"], + "ImageFetcherOrder": ["TheTVDB", "TheMovieDb"], + "ImageOptions": [ + { + "Type": "Primary", + "Limit": 1, + "MinWidth": 0 + }, + { + "Type": "Art", + "Limit": 1, + "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": 1, + "MinWidth": 0 + }, + { + "Type": "Backdrop", + "Limit": "1", + "MinWidth": "1280" + } + ] + }, + { + "Type": "Season", + "MetadataFetchers": ["TheTVDB", "TheMovieDb"], + "MetadataFetcherOrder": ["TheTVDB", "TheMovieDb"], + "ImageFetchers": ["TheTVDB", "TheMovieDb"], + "ImageFetcherOrder": ["TheTVDB", "TheMovieDb"], + "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": 0, + "MinWidth": 0 + }, + { + "Type": "Menu", + "Limit": 0, + "MinWidth": 0 + }, + { + "Type": "Thumb", + "Limit": 0, + "MinWidth": 0 + }, + { + "Type": "Backdrop", + "Limit": "0", + "MinWidth": "1280" + } + ] + }, + { + "Type": "Episode", + "MetadataFetchers": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database" + ], + "MetadataFetcherOrder": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database" + ], + "ImageFetchers": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database", + "Embedded Image Extractor", + "Screen Grabber" + ], + "ImageFetcherOrder": [ + "TheTVDB", + "TheMovieDb", + "The Open Movie Database", + "Embedded Image Extractor", + "Screen Grabber" + ] + } + ], + "LocalMetadataReaderOrder": ["Nfo"], + "SubtitleDownloadLanguages": [], + "CustomTagDelimiters": ["/", "|", ";", "\\"], + "DelimiterWhitelist": [], + "DisabledSubtitleFetchers": [], + "SubtitleFetcherOrder": [], + "DisabledLyricFetchers": [], + "LyricFetcherOrder": [], + "PathInfos": [ + { + "Path": "/var/lib/media/shows" + } + ] + } +} diff --git a/hosts/jupiter/users/storm/configs/console/podman/jellyfin/setup.sh b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/setup.sh new file mode 100644 index 0000000..feb51fc --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/jellyfin/setup.sh @@ -0,0 +1,182 @@ +# shellcheck shell=sh + +curl -sf "$JELLYFIN_HOST/Startup/Configuration" \ + -X POST \ + -H 'Content-Type: application/json' \ + --data-raw '{"UICulture":"en-US","MetadataCountryCode":"US","PreferredMetadataLanguage":"en"}' + +curl -sf "$JELLYFIN_HOST/Startup/User" + +curl -sf "$JELLYFIN_HOST/Startup/User" \ + -X POST \ + -H 'Content-Type: application/json' \ + --data-raw '{"Name":"'"$JELLYFIN_ADMIN_USERNAME"'","Password":"'"$JELLYFIN_ADMIN_PASSWORD"'"}' + +curl -sf "$JELLYFIN_HOST/Startup/RemoteAccess" \ + -X POST \ + -H 'Content-Type: application/json' \ + --data-raw '{"EnableRemoteAccess":true,"EnableAutomaticPortMapping":false}' + +curl -sf "$JELLYFIN_HOST/Startup/Complete" \ + -X POST + +token="$(curl -sf "$JELLYFIN_HOST/Users/AuthenticateByName" \ + -X POST \ + -H 'Content-Type: application/json' \ + -H 'Authorization: MediaBrowser Client="jellyfin-init", Device="sh", DeviceId="sh", Version="1.0"' \ + --data-raw '{"Username":"'"$JELLYFIN_ADMIN_USERNAME"'","Pw":"'"$JELLYFIN_ADMIN_PASSWORD"'"}' \ + | jq -r '.AccessToken')" + +curl -sf "$JELLYFIN_HOST/System/Configuration" \ + -H 'Authorization: MediaBrowser Token="'"$token"'"' \ + | jq '.EnableMetrics = true + | .ServerName = "jupiter" + | .EnableGroupingIntoCollections = true + | .RemoteClientBitrateLimit = 1024000000 + | .TrickplayOptions.EnableHwAcceleration = true + | .TrickplayOptions.EnableHwEncoding = true' \ + | curl -sf "$JELLYFIN_HOST/System/Configuration" \ + -X POST \ + -H 'Content-Type: application/json' \ + -H 'Authorization: MediaBrowser Token="'"$token"'"' \ + --data-binary @- + +curl -sf "$JELLYFIN_HOST/System/Configuration/encoding" \ + -H 'Authorization: MediaBrowser Token="'"$token"'"' \ + | jq '.EnableThrottling = true + | .HardwareAccelerationType = "nvenc" + | .EnableTonemapping = true + | .EnableDecodingColorDepth12HevcRext = true + | .AllowHevcEncoding = true + | .HardwareDecodingCodecs = ["h264", "hevc", "mpeg2video", "mpeg4", "vc1", "vp8", "vp9", "av1"]' \ + | curl -sf "$JELLYFIN_HOST/System/Configuration/encoding" \ + -X POST \ + -H 'Content-Type: application/json' \ + -H 'Authorization: MediaBrowser Token="'"$token"'"' \ + --data-binary @- + +curl -sf "$JELLYFIN_HOST/Plugins/c83d86bb-a1e0-4c35-a113-e2101cf4ee6b/Configuration" \ + -H 'Authorization: MediaBrowser Token="'"$token"'"' \ + | jq '.AnalyzeSeasonZero = true + | .AnalyzeMovies = true' \ + | curl -sf "$JELLYFIN_HOST/Plugins/c83d86bb-a1e0-4c35-a113-e2101cf4ee6b/Configuration" \ + -X POST \ + -H 'Content-Type: application/json' \ + -H 'Authorization: MediaBrowser Token="'"$token"'"' \ + --data-binary @- + +curl -sf "$JELLYFIN_HOST/Plugins/b8715ed1-6c47-4528-9ad3-f72deb539cd4/Configuration" \ + -H 'Authorization: MediaBrowser Token="'"$token"'"' \ + | jq '.IncludeAdult = true' \ + | curl -sf "$JELLYFIN_HOST/Plugins/b8715ed1-6c47-4528-9ad3-f72deb539cd4/Configuration" \ + -X POST \ + -H 'Content-Type: application/json' \ + -H 'Authorization: MediaBrowser Token="'"$token"'"' \ + --data-binary @- + +for filepath in /etc/jellyfin/libraries/*/*.json; do + collectionType=$(jq -rn --arg s "$(basename "$(dirname "$filepath")")" '$s|@uri') + name=$(jq -rn --arg s "$(basename "$filepath" .json)" '$s|@uri') + + curl -sf "${JELLYFIN_HOST}/Library/VirtualFolders?collectionType=${collectionType}&name=${name}" \ + -X POST \ + -H "Content-Type: application/json" \ + -H 'Authorization: MediaBrowser Token="'"$token"'"' \ + --data-binary @"${filepath}" +done + +curl -sf "${JELLYFIN_HOST}/Plugins/505ce9d1-d916-42fa-86ca-673ef241d7df/Configuration" \ + -X POST \ + -H 'Content-Type: application/json' \ + -H 'Authorization: MediaBrowser Token="'"$token"'"' \ + --data-binary @- < :not(:first-child) { + display: none !important; +} +EOF +) + +login_disclaimer=$(cat < + + +EOF +) + +curl -sf "$JELLYFIN_HOST/System/Configuration/branding" \ + -H "Authorization: MediaBrowser Token=$token" | + jq --arg custom_css "$custom_css" \ + --arg login_disclaimer "$login_disclaimer" \ + '.CustomCss = $custom_css | .LoginDisclaimer = $login_disclaimer' | + curl -sf "$JELLYFIN_HOST/System/Configuration/branding" \ + -X POST \ + -H 'Content-Type: application/json' \ + -H "Authorization: MediaBrowser Token=$token" \ + --data-binary @- diff --git a/hosts/jupiter/users/storm/configs/console/podman/nextcloud/default.nix b/hosts/jupiter/users/storm/configs/console/podman/nextcloud/default.nix index dd6b098..13625ad 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/nextcloud/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/nextcloud/default.nix @@ -156,7 +156,7 @@ in ]; virtualisation.quadlet = { - networks.nextcloud.networkConfig.internal = true; + networks.nextcloud = { }; volumes = { nextcloud-postgresql = { }; @@ -173,21 +173,26 @@ in networks.nextcloud.ref networks.traefik.ref ]; - volumes = [ - "/mnt/storage/private/storm/containers/storage/volumes/nextcloud-data/_data:/var/lib/nextcloud" - "${volumes.nextcloud-log.ref}:/var/log/nextcloud" - "${volumes.nextcloud-config.ref}:/var/www/nextcloud/config" - "${volumes.nextcloud-apps.ref}:/var/www/nextcloud/apps" - "${hmConfig.sops.templates.nextcloud.path}:/var/www/nextcloud/config/override.config.php:ro" - ]; + volumes = + let + post-setup = pkgs.writeTextFile { + name = "post-setup.sh"; + executable = true; + text = builtins.readFile ./post-setup.sh; + }; + in + [ + "${post-setup}:/etc/nextcloud/post-setup.sh:ro" + "/mnt/storage/private/storm/containers/storage/volumes/nextcloud-data/_data:/var/lib/nextcloud" + "${volumes.nextcloud-log.ref}:/var/log/nextcloud" + "${volumes.nextcloud-config.ref}:/var/www/nextcloud/config" + "${volumes.nextcloud-apps.ref}:/var/www/nextcloud/apps" + "${hmConfig.sops.templates.nextcloud.path}:/var/www/nextcloud/config/override.config.php:ro" + ]; environments = { POSTGRES_HOST = "nextcloud-postgresql"; POSTGRES_DB = "nextcloud"; POSTGRES_USER = "nextcloud"; - EXTRA_INIT = '' - occ config:app:set core shareapi_allow_custom_tokens --value true --type boolean --no-interaction - occ theming:config url https://cloud.karaolidis.com - ''; }; environmentFiles = [ hmConfig.sops.templates.nextcloud-env.path ]; labels = [ diff --git a/hosts/jupiter/users/storm/configs/console/podman/nextcloud/post-setup.sh b/hosts/jupiter/users/storm/configs/console/podman/nextcloud/post-setup.sh new file mode 100644 index 0000000..8dd77df --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/nextcloud/post-setup.sh @@ -0,0 +1,26 @@ +# shellcheck shell=bash + +occ user:delete admin + +occ app:disable \ + app_api \ + contactsinteraction \ + dashboard \ + federation \ + firstrunwizard \ + photos \ + recommendations \ + sharebymail \ + support \ + survey_client \ + user_status \ + weather_status + +occ app:install \ + oidc_login + +occ config:app:set \ + core shareapi_allow_custom_tokens --value true --type boolean --no-interaction + +occ theming:config \ + url https://cloud.karaolidis.com diff --git a/hosts/jupiter/users/storm/configs/console/podman/ntfy/default.nix b/hosts/jupiter/users/storm/configs/console/podman/ntfy/default.nix index 611b4a1..ac548e6 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/ntfy/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/ntfy/default.nix @@ -84,7 +84,7 @@ in }; virtualisation.quadlet = { - networks.ntfy.networkConfig.internal = true; + networks.ntfy = { }; volumes.ntfy = { }; diff --git a/hosts/jupiter/users/storm/configs/console/podman/outline/default.nix b/hosts/jupiter/users/storm/configs/console/podman/outline/default.nix index f1852bf..a0c04b7 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/outline/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/outline/default.nix @@ -68,6 +68,7 @@ in "email" "offline_access" ]; + response_types = [ "code" ]; token_endpoint_auth_method = "client_secret_post"; } ]; @@ -82,7 +83,7 @@ in ]; virtualisation.quadlet = { - networks.outline.networkConfig.internal = true; + networks.outline = { }; volumes = { outline-redis = { }; diff --git a/hosts/jupiter/users/storm/configs/console/podman/prometheus/default.nix b/hosts/jupiter/users/storm/configs/console/podman/prometheus/default.nix index 3ef1959..96c9e41 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/prometheus/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/prometheus/default.nix @@ -84,10 +84,7 @@ in in { virtualisation.quadlet = { - networks = { - prometheus.networkConfig.internal = true; - prometheus-ext = { }; - }; + networks.prometheus = { }; volumes = { prometheus-data = { }; @@ -269,10 +266,8 @@ in "${volumes.prometheus-data.ref}:/var/lib/prometheus" ]; networks = [ - networks.grafana.ref networks.prometheus.ref - # Access to root exporters - networks.prometheus-ext.ref + networks.grafana.ref ]; exec = [ "--log.level=warn" diff --git a/hosts/jupiter/users/storm/configs/console/podman/shlink/default.nix b/hosts/jupiter/users/storm/configs/console/podman/shlink/default.nix index cbe457a..cd330e6 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/shlink/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/shlink/default.nix @@ -41,7 +41,7 @@ in }; virtualisation.quadlet = { - networks.shlink.networkConfig.internal = true; + networks.shlink = { }; volumes = { shlink-postgresql = { }; diff --git a/hosts/jupiter/users/storm/configs/console/podman/sish/default.nix b/hosts/jupiter/users/storm/configs/console/podman/sish/default.nix index 869f582..285f29d 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/sish/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/sish/default.nix @@ -21,7 +21,7 @@ in sops.secrets."sish/ssh/key".sopsFile = ../../../../../../secrets/secrets.yaml; virtualisation.quadlet = { - networks.sish.networkConfig.internal = true; + networks.sish = { }; containers.sish = { containerConfig = { diff --git a/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix b/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix index 5991079..650de1a 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix @@ -140,7 +140,7 @@ in { domain = "proxy.karaolidis.com"; policy = "two_factor"; - subject = [ "group:admins" ]; + subject = [ "group:admin" ]; } ]; }; diff --git a/hosts/jupiter/users/storm/configs/console/podman/transmission/default.nix b/hosts/jupiter/users/storm/configs/console/podman/transmission/default.nix index 173a11f..12f155b 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/transmission/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/transmission/default.nix @@ -24,7 +24,7 @@ in virtualisation.quadlet = { # Not internal, we need network access for obvious reasons - networks.transmission = { }; + networks.transmission-ext = { }; volumes.transmission-config = { }; @@ -33,7 +33,7 @@ in containerConfig = { image = "docker-archive:${selfPkgs.docker-transmission-protonvpn}"; networks = [ - networks.transmission.ref + networks.transmission-ext.ref networks.traefik.ref ]; addCapabilities = [ "NET_ADMIN" ]; diff --git a/hosts/jupiter/users/storm/configs/console/podman/vaultwarden/default.nix b/hosts/jupiter/users/storm/configs/console/podman/vaultwarden/default.nix index a62ddf5..72b68a4 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/vaultwarden/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/vaultwarden/default.nix @@ -71,6 +71,7 @@ in "profile" "offline_access" ]; + response_types = [ "code" ]; } ]; }; @@ -80,7 +81,7 @@ in }; virtualisation.quadlet = { - networks.vaultwarden.networkConfig.internal = true; + networks.vaultwarden = { }; volumes = { vaultwarden-postgresql = { }; diff --git a/hosts/jupiter/users/storm/configs/console/podman/whoami/default.nix b/hosts/jupiter/users/storm/configs/console/podman/whoami/default.nix index f824642..ffebad5 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/whoami/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/whoami/default.nix @@ -15,7 +15,7 @@ let in { home-manager.users.${user}.virtualisation.quadlet = { - networks.whoami.networkConfig.internal = true; + networks.whoami = { }; containers.whoami.containerConfig = { image = "docker-archive:${selfPkgs.docker-whoami}"; diff --git a/packages/default.nix b/packages/default.nix index 13352ff..a5dea48 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -14,6 +14,7 @@ docker-gitea = import ./docker/gitea { inherit pkgs; }; docker-grafana = import ./docker/grafana { inherit pkgs; }; docker-grafana-image-renderer = import ./docker/grafana-image-renderer { inherit pkgs; }; + docker-jellyfin = import ./docker/jellyfin { inherit pkgs inputs system; }; docker-mariadb = import ./docker/mariadb { inherit pkgs; }; docker-nextcloud = import ./docker/nextcloud { inherit pkgs; }; docker-ntfy = import ./docker/ntfy { inherit pkgs; }; @@ -40,6 +41,14 @@ docker-whoami = import ./docker/whoami { inherit pkgs; }; docker-yq = import ./docker/yq { inherit pkgs; }; + jellyfin-plugin-bookshelf = import ./jellyfin/plugins/bookshelf { inherit pkgs; }; + jellyfin-plugin-intro-skipper = import ./jellyfin/plugins/intro-skipper { inherit pkgs; }; + jellyfin-plugin-playbackreporting = import ./jellyfin/plugins/playbackreporting { inherit pkgs; }; + jellyfin-plugin-reports = import ./jellyfin/plugins/reports { inherit pkgs; }; + jellyfin-plugin-sso = import ./jellyfin/plugins/sso { inherit pkgs; }; + jellyfin-plugin-subtitleextract = import ./jellyfin/plugins/subtitleextract { inherit pkgs; }; + jellyfin-plugin-tvdb = import ./jellyfin/plugins/tvdb { inherit pkgs; }; + linux-firmware-latest = import ./linux-firmware-latest { inherit pkgs; }; obsidian-plugin-better-word-count = import ./obsidian/plugins/better-word-count { inherit pkgs; }; diff --git a/packages/docker/jellyfin/default.nix b/packages/docker/jellyfin/default.nix new file mode 100644 index 0000000..19ed3ca --- /dev/null +++ b/packages/docker/jellyfin/default.nix @@ -0,0 +1,108 @@ +{ + pkgs, + inputs, + system, + ... +}: +let + selfPkgs = inputs.self.packages.${system}; + + jellyfin = pkgs.jellyfin.overrideAttrs (_: { + makeWrapperArgs = [ + "--add-flags" + "--ffmpeg=${pkgs.jellyfin-ffmpeg}/bin/ffmpeg" + ]; + }); + + jellyfin-web = pkgs.runCommandLocal "jellyfin-web" { } '' + mkdir -p $out/var/www + cp -r ${pkgs.jellyfin-web}/share/jellyfin-web $out/var/www/jellyfin + ''; + + jellyfin-plugin-bookshelf = pkgs.runCommandLocal "jellyfin-plugin-bookshelf" { } '' + mkdir -p $out/var/lib/jellyfin/plugins + cp -r ${selfPkgs.jellyfin-plugin-bookshelf} $out/var/lib/jellyfin/plugins/bookshelf + ''; + + jellyfin-plugin-intro-skipper = pkgs.runCommandLocal "jellyfin-plugin-intro-skipper" { } '' + mkdir -p $out/var/lib/jellyfin/plugins + cp -r ${selfPkgs.jellyfin-plugin-intro-skipper} $out/var/lib/jellyfin/plugins/intro-skipper + ''; + + jellyfin-plugin-playbackreporting = pkgs.runCommandLocal "jellyfin-plugin-playbackreporting" { } '' + mkdir -p $out/var/lib/jellyfin/plugins + cp -r ${selfPkgs.jellyfin-plugin-playbackreporting} $out/var/lib/jellyfin/plugins/playbackreporting + ''; + + jellyfin-plugin-reports = pkgs.runCommandLocal "jellyfin-plugin-reports" { } '' + mkdir -p $out/var/lib/jellyfin/plugins + cp -r ${selfPkgs.jellyfin-plugin-reports} $out/var/lib/jellyfin/plugins/reports + ''; + + jellyfin-plugin-sso = pkgs.runCommandLocal "jellyfin-plugin-sso" { } '' + mkdir -p $out/var/lib/jellyfin/plugins + cp -r ${selfPkgs.jellyfin-plugin-sso} $out/var/lib/jellyfin/plugins/sso + ''; + + jellyfin-plugin-subtitleextract = pkgs.runCommandLocal "jellyfin-plugin-subtitleextract" { } '' + mkdir -p $out/var/lib/jellyfin/plugins + cp -r ${selfPkgs.jellyfin-plugin-subtitleextract} $out/var/lib/jellyfin/plugins/subtitleextract + ''; + + jellyfin-plugin-tvdb = pkgs.runCommandLocal "jellyfin-plugin-tvdb" { } '' + mkdir -p $out/var/lib/jellyfin/plugins + cp -r ${selfPkgs.jellyfin-plugin-tvdb} $out/var/lib/jellyfin/plugins/tvdb + ''; + + entrypoint = pkgs.writeTextFile { + name = "entrypoint"; + executable = true; + destination = "/bin/entrypoint"; + text = builtins.readFile ./entrypoint.sh; + }; +in +pkgs.dockerTools.buildImage { + name = "jellyfin"; + fromImage = import ../base { inherit pkgs; }; + + copyToRoot = pkgs.buildEnv { + name = "root"; + paths = [ + entrypoint + jellyfin + jellyfin-web + jellyfin-plugin-bookshelf + jellyfin-plugin-intro-skipper + jellyfin-plugin-playbackreporting + jellyfin-plugin-reports + jellyfin-plugin-sso + jellyfin-plugin-subtitleextract + jellyfin-plugin-tvdb + pkgs.jellyfin-ffmpeg + pkgs.curl + pkgs.jq + ]; + pathsToLink = [ + "/bin" + "/lib" + "/var" + ]; + }; + + runAsRoot = '' + ${pkgs.dockerTools.shadowSetup} + ''; + + config = { + Entrypoint = [ "entrypoint" ]; + ExposedPorts = { + "8096/tcp" = { }; + }; + Volumes = { + "/etc/jellyfin" = { }; + "/var/lib/jellyfin" = { }; + "/var/log/jellyfin" = { }; + "/tmp/jellyfin" = { }; + }; + }; +} diff --git a/packages/docker/jellyfin/entrypoint.sh b/packages/docker/jellyfin/entrypoint.sh new file mode 100644 index 0000000..c8feb49 --- /dev/null +++ b/packages/docker/jellyfin/entrypoint.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env sh + +set -o errexit +set -o nounset + +start() { + jellyfin \ + -w /var/www/jellyfin \ + -c /etc/jellyfin \ + -d /var/lib/jellyfin \ + -l /var/log/jellyfin \ + -C /tmp/jellyfin \ + "$@" & + + PID=$! +} + +start "$@" + +JELLYFIN_HOST="${JELLYFIN_HOST:-http://localhost:8096}" +JELLYFIN_ADMIN_USERNAME="${JELLYFIN_ADMIN_USERNAME:-admin}" + +until setup="$(curl -sf --retry 10 --retry-connrefused "$JELLYFIN_HOST/System/Info/Public" | jq -r '.StartupWizardCompleted' 2>/dev/null)"; do + echo "Waiting for Jellyfin to be ready..." + sleep 1 +done + +if [ "$setup" = "false" ] && [ -f /etc/jellyfin/setup.sh ]; then + # shellcheck disable=SC1091 + . /etc/jellyfin/setup.sh + + kill "$PID" + wait "$PID" 2>/dev/null || true + start "$@" +fi + +trap 'kill -INT "$PID"' INT TERM +wait "$PID" +exit $? diff --git a/packages/docker/nextcloud/entrypoint.sh b/packages/docker/nextcloud/entrypoint.sh index af7dacb..5c30649 100644 --- a/packages/docker/nextcloud/entrypoint.sh +++ b/packages/docker/nextcloud/entrypoint.sh @@ -26,24 +26,10 @@ if [ ! -f "/var/www/nextcloud/config/config.php" ]; then --admin-pass "$ADMIN_PASS" \ --data-dir "/var/lib/nextcloud" - occ user:delete admin - - occ app:disable \ - app_api \ - contactsinteraction \ - dashboard \ - federation \ - firstrunwizard \ - photos \ - recommendations \ - sharebymail \ - support \ - survey_client \ - user_status \ - weather_status - - occ app:install \ - oidc_login + if [ -f /etc/nextcloud/post-setup.sh ]; then + # shellcheck disable=SC1091 + . /etc/nextcloud/post-setup.sh + fi fi occ upgrade @@ -58,8 +44,6 @@ occ maintenance:repair --include-expensive occ background:cron occ maintenance:update:htaccess -[ -n "${EXTRA_INIT:-}" ] && eval "$EXTRA_INIT" - cron PHPRC="$(dirname "$(readlink -f "$(which php)")")/../lib/php.ini" diff --git a/packages/docker/shlink-web-client/entrypoint.sh b/packages/docker/shlink-web-client/entrypoint.sh index 23c5ed3..89f31f2 100644 --- a/packages/docker/shlink-web-client/entrypoint.sh +++ b/packages/docker/shlink-web-client/entrypoint.sh @@ -1,8 +1,9 @@ #!/usr/bin/env sh set -o errexit +set -o nounset -if [ -n "$SHLINK_SERVER_URL" ] && [ -n "$SHLINK_SERVER_API_KEY" ]; then +if [ -n "${SHLINK_SERVER_URL:-}" ] && [ -n "${SHLINK_SERVER_API_KEY:-}" ]; then SHLINK_SERVER_NAME="${SHLINK_SERVER_NAME:-Shlink}" SHLINK_SERVER_FORWARD_CREDENTIALS="${SHLINK_SERVER_FORWARD_CREDENTIALS:-false}" echo "[{\"name\":\"${SHLINK_SERVER_NAME}\",\"url\":\"${SHLINK_SERVER_URL}\",\"apiKey\":\"${SHLINK_SERVER_API_KEY}\",\"forwardCredentials\":${SHLINK_SERVER_FORWARD_CREDENTIALS}}]" > /var/www/shlink-web-client/servers.json diff --git a/packages/docker/shlink/entrypoint.sh b/packages/docker/shlink/entrypoint.sh index 38aa5f9..ef23fe1 100644 --- a/packages/docker/shlink/entrypoint.sh +++ b/packages/docker/shlink/entrypoint.sh @@ -1,6 +1,7 @@ #!/usr/bin/env sh set -o errexit +set -o nounset mkdir -p \ /var/www/shlink/data/cache \ @@ -14,15 +15,15 @@ INITIAL_API_KEY=$(/var/www/shlink/bin/cli env-var:read INITIAL_API_KEY) init_flags="--no-interaction --clear-db-cache" -if [ -z "${GEOLITE_LICENSE_KEY}" ] || [ "${SKIP_INITIAL_GEOLITE_DOWNLOAD}" = "true" ]; then - init_flags="${init_flags} --skip-download-geolite" +if [ -z "${GEOLITE_LICENSE_KEY:-}" ] || [ "${SKIP_INITIAL_GEOLITE_DOWNLOAD:-}" = "true" ]; then + init_flags="$init_flags --skip-download-geolite" fi -if [ -n "${INITIAL_API_KEY}" ]; then - init_flags="${init_flags} --initial-api-key=${INITIAL_API_KEY}" +if [ -n "${INITIAL_API_KEY:-}" ]; then + init_flags="$init_flags --initial-api-key=$INITIAL_API_KEY" fi # shellcheck disable=SC2086 -php /var/www/shlink/vendor/bin/shlink-installer init ${init_flags} +php /var/www/shlink/vendor/bin/shlink-installer init $init_flags exec rr serve -c /var/www/shlink/config/roadrunner/.rr.yml "$@" diff --git a/packages/jellyfin/plugins/bookshelf/default.nix b/packages/jellyfin/plugins/bookshelf/default.nix new file mode 100644 index 0000000..aa667d2 --- /dev/null +++ b/packages/jellyfin/plugins/bookshelf/default.nix @@ -0,0 +1,16 @@ +{ pkgs, ... }: +# AUTO-UPDATE: nix-update --flake jellyfin-plugin-bookshelf +pkgs.stdenv.mkDerivation rec { + pname = "bookshelf"; + version = "12"; + + src = pkgs.fetchzip { + url = "https://github.com/jellyfin/jellyfin-plugin-bookshelf/releases/download/v${version}/bookshelf_${version}.0.0.0.zip"; + sha256 = "sha256-P85SLXaJuFIv9AmAE6mPbxZDMBhqEt+88dZiPUKu2iQ="; + stripRoot = false; + }; + + installPhase = '' + cp -r $src $out + ''; +} diff --git a/packages/jellyfin/plugins/intro-skipper/default.nix b/packages/jellyfin/plugins/intro-skipper/default.nix new file mode 100644 index 0000000..5f71003 --- /dev/null +++ b/packages/jellyfin/plugins/intro-skipper/default.nix @@ -0,0 +1,22 @@ +{ pkgs, ... }: +# AUTO-UPDATE: nix-update --flake jellyfin-plugin-intro-skipper +pkgs.stdenv.mkDerivation rec { + pname = "intro-skipper"; + version = "1.10.10.20"; + + src = + let + parts = pkgs.lib.strings.splitString "." version; + major = pkgs.lib.lists.take 2 (pkgs.lib.lists.drop 1 parts); + merged = pkgs.lib.strings.concatStringsSep "." major; + in + pkgs.fetchzip { + url = "https://github.com/intro-skipper/intro-skipper/releases/download/${merged}/v${version}/intro-skipper-v${version}.zip"; + sha256 = "sha256-RlrZkE8108Uj5V90+jw2o5fXb+K+9/hoDcEaSkKLDGg="; + stripRoot = false; + }; + + installPhase = '' + cp -r $src $out + ''; +} diff --git a/packages/jellyfin/plugins/playbackreporting/default.nix b/packages/jellyfin/plugins/playbackreporting/default.nix new file mode 100644 index 0000000..49e93bd --- /dev/null +++ b/packages/jellyfin/plugins/playbackreporting/default.nix @@ -0,0 +1,16 @@ +{ pkgs, ... }: +# AUTO-UPDATE: nix-update --flake jellyfin-plugin-playbackreporting +pkgs.stdenv.mkDerivation rec { + pname = "playbackreporting"; + version = "16"; + + src = pkgs.fetchzip { + url = "https://github.com/jellyfin/jellyfin-plugin-playbackreporting/releases/download/v${version}/playback-reporting_${version}.0.0.0.zip"; + sha256 = "sha256-UrWxS0CpeeW4nYNyRNxnK0jqiAqXwfLv3YfFokfVH0A="; + stripRoot = false; + }; + + installPhase = '' + cp -r $src $out + ''; +} diff --git a/packages/jellyfin/plugins/reports/default.nix b/packages/jellyfin/plugins/reports/default.nix new file mode 100644 index 0000000..b7c5c8a --- /dev/null +++ b/packages/jellyfin/plugins/reports/default.nix @@ -0,0 +1,16 @@ +{ pkgs, ... }: +# AUTO-UPDATE: nix-update --flake jellyfin-plugin-reports +pkgs.stdenv.mkDerivation rec { + pname = "reports"; + version = "17"; + + src = pkgs.fetchzip { + url = "https://github.com/jellyfin/jellyfin-plugin-reports/releases/download/v${version}/reports_${version}.0.0.0.zip"; + sha256 = "sha256-kN1UDhx5/1sw3PO5co2YkfbZNiDj56F2YAT8S/0EdZM="; + stripRoot = false; + }; + + installPhase = '' + cp -r $src $out + ''; +} diff --git a/packages/jellyfin/plugins/sso/default.nix b/packages/jellyfin/plugins/sso/default.nix new file mode 100644 index 0000000..20aff3f --- /dev/null +++ b/packages/jellyfin/plugins/sso/default.nix @@ -0,0 +1,16 @@ +{ pkgs, ... }: +# AUTO-UPDATE: nix-update --flake jellyfin-plugin-sso +pkgs.stdenv.mkDerivation rec { + pname = "sso"; + version = "3.5.2.4"; + + src = pkgs.fetchzip { + url = "https://github.com/9p4/jellyfin-plugin-sso/releases/download/v${version}/sso-authentication_${version}.zip"; + sha256 = "sha256-e+w5m6/7vRAynStDj34eBexfCIEgDJ09huHzi5gQEbo="; + stripRoot = false; + }; + + installPhase = '' + cp -r $src $out + ''; +} diff --git a/packages/jellyfin/plugins/subtitleextract/default.nix b/packages/jellyfin/plugins/subtitleextract/default.nix new file mode 100644 index 0000000..9b0b960 --- /dev/null +++ b/packages/jellyfin/plugins/subtitleextract/default.nix @@ -0,0 +1,16 @@ +{ pkgs, ... }: +# AUTO-UPDATE: nix-update --flake jellyfin-plugin-subtitleextract +pkgs.stdenv.mkDerivation rec { + pname = "subtitleextract"; + version = "4"; + + src = pkgs.fetchzip { + url = "https://github.com/jellyfin/jellyfin-plugin-subtitleextract/releases/download/v${version}/subtitle-extract_${version}.0.0.0.zip"; + sha256 = "sha256-FstPWUYsZg416DNshIV4yOvbg6U21cRxKse8hITUyBY="; + stripRoot = false; + }; + + installPhase = '' + cp -r $src $out + ''; +} diff --git a/packages/jellyfin/plugins/tvdb/default.nix b/packages/jellyfin/plugins/tvdb/default.nix new file mode 100644 index 0000000..33cbf4f --- /dev/null +++ b/packages/jellyfin/plugins/tvdb/default.nix @@ -0,0 +1,16 @@ +{ pkgs, ... }: +# AUTO-UPDATE: nix-update --flake jellyfin-plugin-tvdb +pkgs.stdenv.mkDerivation rec { + pname = "tvdb"; + version = "19"; + + src = pkgs.fetchzip { + url = "https://github.com/jellyfin/jellyfin-plugin-tvdb/releases/download/v${version}/thetvdb_${version}.0.0.0.zip"; + sha256 = "sha256-011wpVwQy562XDAwAQ44GJTbu/ESHcyo5F/wrtNBAcs="; + stripRoot = false; + }; + + installPhase = '' + cp -r $src $out + ''; +}