diff --git a/flake.lock b/flake.lock index 8715c9d..ab5461e 100644 --- a/flake.lock +++ b/flake.lock @@ -511,11 +511,11 @@ "secrets": { "flake": false, "locked": { - "lastModified": 1757954517, - "narHash": "sha256-fmcVzq/HGeXbMKsrW/NlLEuBZ+xYiRBTOkwQc80tzGk=", + "lastModified": 1758576944, + "narHash": "sha256-P6fvi2mjyJEUg19BTZ6eb+fRM8V6s2xY1SWQ8gb49U0=", "ref": "refs/heads/main", - "rev": "dab48ad2370acfa732987eef6f647bdd4f4362f8", - "revCount": 46, + "rev": "a9d956a20fc4534fcc7d3da7f0994c499c4ea405", + "revCount": 47, "type": "git", "url": "ssh://git@karaolidis.com/karaolidis/nix-secrets.git" }, 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 627a2ac..f205ece 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix @@ -132,7 +132,6 @@ in "media" "vaultwarden" "nextcloud" - "jellyfin" "gitea" "outline" "shlink" 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 509fd52..4a8e203 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/media/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/media/default.nix @@ -1,5 +1,10 @@ { user, home }: -{ config, inputs, ... }: +{ + config, + inputs, + pkgs, + ... +}: let hmConfig = config.home-manager.users.${user}; @@ -17,7 +22,7 @@ let in { imports = [ - (import ./jellyfin { inherit user home; }) + (import ./plex { inherit user home; }) (import ./jellyseerr { inherit user @@ -58,6 +63,32 @@ in sops.secrets."ntfy/tokens/jupiter/media".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; - virtualisation.quadlet.networks.media = { }; + virtualisation.quadlet = { + networks.media = { }; + + containers.authelia.containerConfig.volumes = + let + mediaConfig = (pkgs.formats.yaml { }).generate "media.yaml" { + access_control.rules = [ + { + domain = "beta.media.karaolidis.com"; + policy = "one_factor"; + resources = [ "^/manage([/?].*)?$" ]; + subject = [ "group:media" ]; + } + { + domain = "beta.media.karaolidis.com"; + policy = "deny"; + resources = [ "^/manage([/?].*)?$" ]; + } + { + domain = "beta.media.karaolidis.com"; + policy = "bypass"; + } + ]; + }; + in + [ "${mediaConfig}:/etc/authelia/conf.d/media.yaml:ro" ]; + }; }; } diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/default.nix b/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/default.nix deleted file mode 100644 index c5f1b3c..0000000 --- a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/default.nix +++ /dev/null @@ -1,152 +0,0 @@ -{ user, home }: -{ - config, - inputs, - pkgs, - ... -}: -let - hmConfig = config.home-manager.users.${user}; - inherit (hmConfig.virtualisation.quadlet) volumes networks; - autheliaClientId = "59TRpNutxEeRRCAZbDsK7rsnrA5NC69HAdAO45CEfc740xl4hgIacDy2u03oiFc89Exb67udBQvmfwxgeAQtJPiNAJxA5OzGmdQf"; -in -{ - home-manager.users.${user} = { - sops = { - secrets = { - "jellyfin/admin".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; - "jellyfin/authelia/password".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; - "jellyfin/authelia/digest".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; - "opensubtitles/username".sopsFile = "${inputs.secrets}/domains/personal/secrets.yaml"; - "opensubtitles/password".sopsFile = "${inputs.secrets}/domains/personal/secrets.yaml"; - }; - - templates = { - jellyfin-env.content = '' - JELLYFIN_ADMIN_PASSWORD=${hmConfig.sops.placeholder."jellyfin/admin"} - JELLYFIN_OIDC_SECRET=${hmConfig.sops.placeholder."jellyfin/authelia/password"} - OPENSUBTITLES_USERNAME=${hmConfig.sops.placeholder."opensubtitles/username"} - OPENSUBTITLES_PASSWORD=${hmConfig.sops.placeholder."opensubtitles/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://beta.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"; - pre_configured_consent_duration = "1 month"; - } - ]; - }; - } - ); - }; - }; - - virtualisation.quadlet = { - networks.jellyfin = { }; - - volumes = { - jellyfin-config = { }; - jellyfin-data = { }; - jellyfin-metadata = { }; - jellyfin-root = { }; - jellyfin-log = { }; - jellyfin-cache = { }; - }; - - containers = { - jellyfin = { - containerConfig = { - image = "docker-archive:${pkgs.dockerImages.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" - # FIXME: https://github.com/9p4/jellyfin-plugin-sso/issues/189#issuecomment-3262794524 - "${./sso-button.js}:/etc/jellyfin/sso-button.js:ro" - "${./libraries}:/etc/jellyfin/libraries:ro" - "${volumes.jellyfin-config.ref}:/etc/jellyfin" - "${volumes.jellyfin-data.ref}:/var/lib/jellyfin/data" - "${volumes.jellyfin-metadata.ref}:/var/lib/jellyfin/metadata" - "${volumes.jellyfin-root.ref}:/var/lib/jellyfin/root" - "${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(`beta.media.karaolidis.com`)" - ]; - podmanArgs = [ "--cdi-spec-dir=/run/cdi" ]; - devices = [ "nvidia.com/gpu=all" ]; - }; - - unitConfig.After = [ "sops-nix.service" ]; - }; - - authelia.containerConfig.volumes = - let - mediaConfig = (pkgs.formats.yaml { }).generate "media.yaml" { - access_control.rules = [ - { - domain = "beta.media.karaolidis.com"; - policy = "one_factor"; - resources = [ "^/manage([/?].*)?$" ]; - subject = [ "group:media" ]; - } - { - domain = "beta.media.karaolidis.com"; - policy = "deny"; - resources = [ "^/manage([/?].*)?$" ]; - } - { - domain = "beta.media.karaolidis.com"; - policy = "bypass"; - } - ]; - }; - in - [ - "${mediaConfig}:/etc/authelia/conf.d/media.yaml:ro" - "${hmConfig.sops.templates.authelia-jellyfin.path}:/etc/authelia/conf.d/jellyfin.yaml:ro" - ]; - }; - }; - }; -} diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/movies/Films (Anime).json b/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/movies/Films (Anime).json deleted file mode 100644 index 58835fd..0000000 --- a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/movies/Films (Anime).json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "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/libraries/anime/films" - } - ] - } -} diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/movies/Films.json b/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/movies/Films.json deleted file mode 100644 index ee81551..0000000 --- a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/movies/Films.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "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/libraries/films" - } - ] - } -} diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/tvshows/Shows (Anime).json b/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/tvshows/Shows (Anime).json deleted file mode 100644 index cbc0c7c..0000000 --- a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/tvshows/Shows (Anime).json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "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/libraries/anime/shows" - } - ] - } -} diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/tvshows/Shows.json b/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/tvshows/Shows.json deleted file mode 100644 index f26f3d6..0000000 --- a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/libraries/tvshows/Shows.json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "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/libraries/shows" - } - ] - } -} diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/setup.sh b/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/setup.sh deleted file mode 100644 index ccf73b2..0000000 --- a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/setup.sh +++ /dev/null @@ -1,222 +0,0 @@ -# shellcheck shell=sh - -JELLYFIN_HOST="${JELLYFIN_HOST:-http://localhost:8096}" -JELLYFIN_ADMIN_USERNAME="${JELLYFIN_ADMIN_USERNAME:-admin}" - -until response="$(curl -sf "$JELLYFIN_HOST/System/Info/Public")"; do - echo "Waiting for Jellyfin to be ready..." - sleep 1 -done - -setup="$(echo "$response" | jq -r '.StartupWizardCompleted')" - -if [ "$setup" = "false" ]; then - 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 -fi - -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" - | .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/4b9ed42f-5185-48b5-9803-6ff2989014c4/Configuration" \ - -H 'Authorization: MediaBrowser Token="'"$token"'"' \ - | jq --arg username "$OPENSUBTITLES_USERNAME" \ - --arg password "$OPENSUBTITLES_PASSWORD" \ - '.Username = $username - | .Password = $password' \ - | curl -sf "$JELLYFIN_HOST/Plugins/4b9ed42f-5185-48b5-9803-6ff2989014c4/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 @- - -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 -) - -curl -sf "$JELLYFIN_HOST/System/Configuration/branding" \ - -H "Authorization: MediaBrowser Token=$token" | - jq --arg custom_css "$custom_css" \ - '.CustomCss = $custom_css' | - curl -sf "$JELLYFIN_HOST/System/Configuration/branding" \ - -X POST \ - -H 'Content-Type: application/json' \ - -H "Authorization: MediaBrowser Token=$token" \ - --data-binary @- - -jq -Rn --rawfile script /etc/jellyfin/sso-button.js ' - { - CustomJavaScripts: [ - { - Name: "SSO Button", - Script: $script, - Enabled: true, - RequiresAuthentication: false - } - ] - } -' \ - | curl -sf "$JELLYFIN_HOST/Plugins/f5a34f7b-2e8a-4e6a-a722-3a216a81b374/Configuration" \ - -X POST \ - -H 'Content-Type: application/json' \ - -H 'Authorization: MediaBrowser Token="'"$token"'"' \ - --data-binary @- - -existing_libraries="$(curl -sf "$JELLYFIN_HOST/Library/VirtualFolders" \ - -H 'Authorization: MediaBrowser Token="'"$token"'"')" - -find /etc/jellyfin/libraries -name "*.json" | sort -V | while IFS= read -r filepath; do - collectionType=$(jq -rn --arg s "$(basename "$(dirname "$filepath")")" '$s|@uri') - name=$(jq -rn --arg s "$(basename "$filepath" .json)" '$s|@uri') - - if echo "$existing_libraries" | jq -e --arg name "$name" 'any(.[]; .Name | @uri == $name)'; then - echo "Skipping existing virtual folder: $name" - continue - fi - - echo "Creating virtual folder: $name" - 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 diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/sso-button.js b/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/sso-button.js deleted file mode 100644 index 99c9b61..0000000 --- a/hosts/jupiter/users/storm/configs/console/podman/media/jellyfin/sso-button.js +++ /dev/null @@ -1,180 +0,0 @@ -const SSO_AUTH_URL = "https://beta.media.karaolidis.com/sso/OID/start/authelia"; - -// SSO provider customization. Available options are: -// generic, authentik, authelia, keycloak, zitadel -const PROVIDER = "authelia"; - -// Self-executing function that waits for the document body to be available -(function waitForBody() { - // If document.body doesn't exist yet, retry in 100ms - if (!document.body) { - return setTimeout(waitForBody, 100); - } - - /** - * Determines if the current page is a login page by checking multiple indicators - * @returns {boolean} True if this appears to be a login page - */ - function isLoginPage() { - const hash = location.hash.toLowerCase(); - const pathname = location.pathname.toLowerCase(); - // Check for URL patterns that typically indicate login pages - const hasLoginUrl = - hash === "" || - hash === "#/" || - hash === "#/home" || - hash === "#/login" || - hash.startsWith("#/login") || - pathname.includes("/login"); - - // Check for DOM elements that indicate a login form is present - const hasLoginElements = - document.querySelector('input[type="password"]') !== null || - document.querySelector(".loginPage") !== null || - document.querySelector("#txtUserName") !== null; - - return hasLoginUrl || hasLoginElements; - } - - /** - * Checks if the current page should be excluded from SSO button insertion - * These are typically pages where users are already authenticated - * @returns {boolean} True if this page should be excluded - */ - function shouldExcludePage() { - const hash = location.hash.toLowerCase(); - // List of page patterns where we don't want to show the SSO button - const excludePatterns = [ - "#/dashboard", - "#/home.html", - "#/movies", - "#/tv", - "#/music", - "#/livetv", - "#/search", - "#/settings", - "#/wizardstart", - "#/wizardfinish", - "#/mypreferencesmenu", - "#/userprofile", - ]; - - return excludePatterns.some((pattern) => hash.startsWith(pattern)); - } - - /** - * Initializes the OAuth device ID in localStorage if it doesn't exist - * This is required for Jellyfin native apps to maintain device identification - */ - function oAuthInitDeviceId() { - // Only set device ID if it's not already set and we're in a native shell environment - if ( - !localStorage.getItem("_deviceId2") && - window.NativeShell?.AppHost?.deviceId - ) { - localStorage.setItem("_deviceId2", window.NativeShell.AppHost.deviceId()); - } - } - - /** - * Creates and inserts the SSO login button into the login page - * Only runs if we're on a valid login page and the button doesn't already exist - */ - function insertSSOButton() { - // Safety check: ensure we're on the right page before proceeding - if (!isLoginPage() || shouldExcludePage()) return; - - // Try to find a suitable container for the SSO button - const loginContainer = - document.querySelector(".readOnlyContent") || - document.querySelector("form")?.parentNode || - document.querySelector(".loginPage") || - document.querySelector("#loginPage"); - - // Exit if no container found or button already exists - if (!loginContainer || document.querySelector("#custom-sso-button")) return; - - switch (PROVIDER.toLowerCase()) { - case "authentik": - SSO_BUTTON_HTML = - 'Login with Authentik'; - break; - - case "authelia": - SSO_BUTTON_HTML = - 'Login with Authelia'; - break; - - case "keycloak": - SSO_BUTTON_HTML = - 'Login with Keycloak'; - break; - - case "zitadel": - SSO_BUTTON_HTML = - 'Login with Zitadel'; - break; - - default: - SSO_BUTTON_HTML = - 'shieldLogin with SSO'; - } - - // Skip insertion for Jellyfin Media Player (JMP) as it may have different auth handling - const isJMP = navigator.userAgent.includes("JellyfinMediaPlayer"); - if (isJMP) return; - - // Create the SSO button element - const button = document.createElement("button"); - button.id = "custom-sso-button"; - button.className = "raised block emby-button button-submit"; - // Style the button to match Jellyfin's design while being visually distinct - button.style = - "display: flex; align-items: center; justify-content: center; gap: 10px; padding: 12px 20px; font-size: 16px; background-color: #3949ab; color: white; margin-top: 16px;"; - // Add icon and text content - button.innerHTML = SSO_BUTTON_HTML; - // Handle button click - prevent form submission and redirect to SSO - button.onclick = function (e) { - e.preventDefault(); - oAuthInitDeviceId(); // Ensure device ID is set before SSO redirect - window.location.href = SSO_AUTH_URL; - }; - - // Add the button to the login container - loginContainer.appendChild(button); - } - - // Initial setup: Check if we should insert the SSO button when script first loads - if (isLoginPage() && !shouldExcludePage()) { - // Delay insertion slightly to ensure all page elements are fully loaded - setTimeout(insertSSOButton, 500); - } - - // Set up a MutationObserver to watch for dynamic page changes - // This handles cases where Jellyfin loads content dynamically via JavaScript - const observer = new MutationObserver(() => { - if (isLoginPage() && !shouldExcludePage()) { - // Check if login elements are ready and button hasn't been inserted yet - const ready = - document.querySelector(".readOnlyContent") || - document.querySelector("form") || - document.querySelector(".loginPage"); - if (ready && !document.querySelector("#custom-sso-button")) { - insertSSOButton(); - } - } - }); - - // Start observing changes to the entire document body and its children - observer.observe(document.body, { childList: true, subtree: true }); - - // Listen for hash changes (when navigating between pages in Jellyfin's SPA) - window.addEventListener("hashchange", () => { - // Small delay to allow page transition to complete - setTimeout(() => { - if (isLoginPage() && !shouldExcludePage()) { - insertSSOButton(); - } - }, 300); - }); -})(); diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/jellyseerr/default.nix b/hosts/jupiter/users/storm/configs/console/podman/media/jellyseerr/default.nix index 96dcded..42f1a80 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/media/jellyseerr/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/media/jellyseerr/default.nix @@ -15,22 +15,13 @@ let hmConfig = config.home-manager.users.${user}; inherit (hmConfig.virtualisation.quadlet) containers volumes networks; arrs = radarrs ++ sonarrs; - autheliaClientId = "s8QyVqBdiEStH5WXeEYNSrEh8ls2xHif0qyTGbC7V8nHNcqHi5NhqHUapCHuVFT4kEtngqgLry2SKOKepQl3AiqCWlhTjlIxr7LI"; in { home-manager.users.${user} = { sops = { - secrets = { - "jellyseerr/smtp".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; - "jellyseerr/authelia/password".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; - "jellyseerr/authelia/digest".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; - }; + secrets."jellyseerr/smtp".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; templates = { - jellyseerr-env.content = '' - JELLYFIN_ADMIN_PASSWORD=${hmConfig.sops.placeholder."jellyfin/admin"} - ''; - jellyseerr.content = builtins.readFile ( (pkgs.formats.json { }).generate "setings.json" { main = { @@ -42,38 +33,51 @@ in # 32 | 4194304 | 67108864 defaultPermissions = 71303200; localLogin = false; - mediaServerLogin = false; - oidcLogin = true; - newPlexLogin = false; - mediaServerType = 2; + mediaServerLogin = true; + oidcLogin = false; + newPlexLogin = true; + mediaServerType = 1; partialRequestsEnabled = true; enableSpecialEpisodes = true; }; - jellyfin = { + plex = { name = "jupiter"; - ip = "jellyfin"; - port = 8096; + ip = "beta.media.karaolidis.com"; + port = 443; + useSsl = true; + libraries = [ + { + id = "1"; + name = "Films"; + enabled = true; + type = "movie"; + } + { + id = "2"; + name = "Shows"; + enabled = true; + type = "show"; + } + { + id = "3"; + name = "Films (Anime)"; + enabled = true; + type = "movie"; + } + { + id = "4"; + name = "Shows (Anime)"; + enabled = true; + type = "show"; + } + ]; externalHostname = "https://beta.media.karaolidis.com"; - jellyfinForgotPasswordUrl = "https://id.karaolidis.com/reset-password/step1"; + webAppUrl = "https://beta.media.karaolidis.com"; + machineId = hmConfig.sops.placeholder."plex/processedMachineIdentifier"; }; - oidc.providers = [ - { - slug = "authelia"; - name = "Authelia"; - issuerUrl = "https://id.karaolidis.com"; - clientId = autheliaClientId; - clientSecret = hmConfig.sops.placeholder."jellyseerr/authelia/password"; - scopes = lib.strings.concatStringsSep " " [ - "openid" - "profile" - "email" - "groups" - ]; - newUserLogin = true; - } - ]; + jellyfin = { }; radarr = [ ]; @@ -111,34 +115,6 @@ in network.trustProxy = true; } ); - - authelia-jellyseerr.content = builtins.readFile ( - (pkgs.formats.yaml { }).generate "jellyseerr.yaml" { - identity_providers.oidc = { - authorization_policies.jellyseerr = { - default_policy = "deny"; - rules = [ - { - policy = "one_factor"; - subject = "group:jellyfin"; - } - ]; - }; - - clients = [ - { - client_id = autheliaClientId; - client_name = "jellyseerr"; - client_secret = hmConfig.sops.placeholder."jellyseerr/authelia/digest"; - redirect_uris = [ "https://request.karaolidis.com/login?provider=authelia&callback=true" ]; - authorization_policy = "jellyseerr"; - token_endpoint_auth_method = "client_secret_post"; - pre_configured_consent_duration = "1 month"; - } - ]; - }; - } - ); } // builtins.listToAttrs ( builtins.map (arr: { @@ -153,57 +129,49 @@ in virtualisation.quadlet = { volumes.jellyseerr = { }; - containers = { - jellyseerr = { - containerConfig = { - image = "docker-archive:${pkgs.dockerImages.jellyseerr}"; - networks = [ - networks.jellyfin.ref - networks.media.ref - networks.traefik.ref - ]; - volumes = - let - preStart = pkgs.writeTextFile { - name = "pre-start.sh"; - executable = true; - text = builtins.readFile ./pre-start.sh; - }; - in - [ - "${preStart}:/etc/jellyseerr/pre-start.sh:ro" - "${hmConfig.sops.templates.jellyseerr.path}:/etc/jellyseerr/settings.default.json:ro" - "${volumes.jellyseerr.ref}:/var/lib/jellyseerr" - ] - ++ builtins.map ( - radarr: - "${ - hmConfig.sops.templates."jellyseerr-${radarr.hostName}".path - }:/etc/jellyseerr/apps/radarr/${radarr.hostName}.json:ro" - ) radarrs - ++ builtins.map ( - sonarr: - "${ - hmConfig.sops.templates."jellyseerr-${sonarr.hostName}".path - }:/etc/jellyseerr/apps/sonarr/${sonarr.hostName}.json:ro" - ) sonarrs; - environmentFiles = [ hmConfig.sops.templates.jellyseerr-env.path ]; - labels = [ - "traefik.enable=true" - "traefik.http.routers.jellyseerr.rule=Host(`request.karaolidis.com`)" - ]; - }; - - unitConfig.After = + containers.jellyseerr = { + containerConfig = { + image = "docker-archive:${pkgs.dockerImages.jellyseerr}"; + networks = [ + networks.media.ref + networks.traefik.ref + ]; + volumes = let - arrServices = builtins.map (arr: "${containers.${arr.hostName}._serviceName}.service") arrs; + preStart = pkgs.writeTextFile { + name = "pre-start.sh"; + executable = true; + text = builtins.readFile ./pre-start.sh; + }; in - [ "sops-nix.service" ] ++ arrServices; + [ + "${preStart}:/etc/jellyseerr/pre-start.sh:ro" + "${hmConfig.sops.templates.jellyseerr.path}:/etc/jellyseerr/settings.default.json:ro" + "${volumes.jellyseerr.ref}:/var/lib/jellyseerr" + ] + ++ builtins.map ( + radarr: + "${ + hmConfig.sops.templates."jellyseerr-${radarr.hostName}".path + }:/etc/jellyseerr/apps/radarr/${radarr.hostName}.json:ro" + ) radarrs + ++ builtins.map ( + sonarr: + "${ + hmConfig.sops.templates."jellyseerr-${sonarr.hostName}".path + }:/etc/jellyseerr/apps/sonarr/${sonarr.hostName}.json:ro" + ) sonarrs; + labels = [ + "traefik.enable=true" + "traefik.http.routers.jellyseerr.rule=Host(`request.karaolidis.com`)" + ]; }; - authelia.containerConfig.volumes = [ - "${hmConfig.sops.templates.authelia-jellyseerr.path}:/etc/authelia/conf.d/jellyseerr.yaml:ro" - ]; + unitConfig.After = + let + arrServices = builtins.map (arr: "${containers.${arr.hostName}._serviceName}.service") arrs; + in + [ "sops-nix.service" ] ++ arrServices; }; }; }; diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/jellyseerr/pre-start.sh b/hosts/jupiter/users/storm/configs/console/podman/media/jellyseerr/pre-start.sh index 9f31a38..acbc4e8 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/media/jellyseerr/pre-start.sh +++ b/hosts/jupiter/users/storm/configs/console/podman/media/jellyseerr/pre-start.sh @@ -1,59 +1,5 @@ # shellcheck shell=sh -JELLYFIN_HOST="${JELLYFIN_HOST:-http://jellyfin:8096}" -JELLYFIN_ADMIN_USERNAME="${JELLYFIN_ADMIN_USERNAME:-admin}" - -until public="$(curl -sf "$JELLYFIN_HOST/System/Info/Public")"; do - echo "Waiting for Jellyfin to be ready..." - sleep 1 -done - -until [ "$(echo "$public" | jq -r '.StartupWizardCompleted')" = "true" ]; do - echo "Waiting for Jellyfin setup wizard to finish..." - sleep 1 - public="$(curl -sf "${JELLYFIN_HOST}/System/Info/Public")" -done - -token="$(curl -sf "$JELLYFIN_HOST/Users/AuthenticateByName" \ - -X POST \ - -H 'Content-Type: application/json' \ - -H 'Authorization: MediaBrowser Client="jellyseerr-init", Device="sh", DeviceId="sh", Version="1.0"' \ - --data-raw '{"Username":"'"$JELLYFIN_ADMIN_USERNAME"'","Pw":"'"$JELLYFIN_ADMIN_PASSWORD"'"}' \ - | jq -r '.AccessToken')" - -keys="$(curl -sf "$JELLYFIN_HOST/Auth/Keys" \ - -H 'Authorization: MediaBrowser Token="'"$token"'"')" - -jellyseerr_key="$(echo "$keys" | jq -r '.Items[] | select(.AppName=="Jellyseerr") | .AccessToken')" - -if [ -z "$jellyseerr_key" ] || [ "$jellyseerr_key" = "null" ]; then - curl -sf "$JELLYFIN_HOST/Auth/Keys?App=Jellyseerr" \ - -X POST \ - -H 'Authorization: MediaBrowser Token="'"$token"'"' - - keys="$(curl -sf "$JELLYFIN_HOST/Auth/Keys" \ - -H 'Authorization: MediaBrowser Token="'"$token"'"')" - - jellyseerr_key="$(echo "$keys" | jq -r '.Items[] | select(.AppName=="Jellyseerr") | .AccessToken')" -fi - -serverId="$(echo "$public" | jq -r '.Id')" - -libraries="$(curl -sf "$JELLYFIN_HOST/Library/VirtualFolders" \ - -H 'Authorization: MediaBrowser Token="'"$token"'"')" - -libraries="$( - echo "$libraries" | jq '[ - .[] - | { - id: .ItemId, - name: .Name, - enabled: .LibraryOptions.Enabled, - type: ( .CollectionType | if . == "movies" then "movie" elif . == "tvshows" then "show" else . end ) - } - ]' -)" - try_forever() { until "$@" 2>&1; do echo "Try failed: $* - retrying in 1s" @@ -129,15 +75,9 @@ done tmpfile=$(mktemp) jq -s \ - --argjson libs "$libraries" \ --argjson radarr "$radarr_json" \ --argjson sonarr "$sonarr_json" \ - --arg serverId "$serverId" \ - --arg apiKey "$jellyseerr_key" \ '.[0] * .[1] - | .jellyfin.serverId = $serverId - | .jellyfin.apiKey = $apiKey - | .jellyfin.libraries = $libs | .radarr = $radarr | .sonarr = $sonarr' \ /var/lib/jellyseerr/settings.json \ diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/plex/default.nix b/hosts/jupiter/users/storm/configs/console/podman/media/plex/default.nix new file mode 100644 index 0000000..f58a435 --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/media/plex/default.nix @@ -0,0 +1,109 @@ +{ user, home }: +{ + config, + inputs, + pkgs, + ... +}: +let + hmConfig = config.home-manager.users.${user}; + inherit (hmConfig.virtualisation.quadlet) volumes networks; +in +{ + networking.firewall.allowedTCPPorts = [ 32400 ]; + + home-manager.users.${user} = { + sops = { + secrets = { + "plex/machineIdentifier".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; + "plex/processedMachineIdentifier".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; + "plex/anonymousMachineIdentifier".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; + "plex/certificateUuid".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; + "plex/plexOnlineToken".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; + }; + + templates.plex.content = '' + + + ''; + }; + + virtualisation.quadlet = { + networks.plex = { }; + + volumes.plex = { }; + + containers.plex = { + containerConfig = { + image = "docker-archive:${pkgs.dockerImages.plex}"; + networks = [ + networks.plex.ref + networks.traefik.ref + ]; + volumes = + let + postStart = pkgs.writeTextFile { + name = "post-start.sh"; + executable = true; + text = builtins.readFile ./post-start.sh; + }; + in + [ + "${hmConfig.sops.templates.plex.path}:/etc/plex/Preferences.xml:ro" + "${postStart}:/etc/plex/post-start.sh:ro" + "/mnt/storage/private/storm/containers/storage/volumes/media/_data:/var/lib/media" + "${volumes.plex.ref}:/var/lib/plex" + ]; + labels = [ + "traefik.enable=true" + "traefik.http.routers.plex.rule=Host(`beta.media.karaolidis.com`)" + ]; + podmanArgs = [ "--cdi-spec-dir=/run/cdi" ]; + devices = [ "nvidia.com/gpu=all" ]; + addCapabilities = [ "SYS_ADMIN" ]; + publishPorts = [ "32400:32400/tcp" ]; + }; + + unitConfig.After = [ "sops-nix.service" ]; + }; + }; + }; +} diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/plex/post-start.sh b/hosts/jupiter/users/storm/configs/console/podman/media/plex/post-start.sh new file mode 100644 index 0000000..67ff467 --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/media/plex/post-start.sh @@ -0,0 +1,112 @@ +# shellcheck shell=sh + +HOST="http://localhost:32400" +TOKEN="$(getPref "PlexOnlineToken")" + +try_forever() { + until "$@" 2>&1; do + echo "Try failed: $* - retrying in 1s" + sleep 1 + done +} + +wait_for_api() { + try_forever curl -sf -H "X-Plex-Token: $TOKEN" "$HOST/identity" + echo "API is up!" +} + +call() { + method="$1" + path="$2" + params="${3:-}" + + curl -sf \ + -X "$method" \ + -H "Accept: application/json" \ + -H "X-Plex-Token: $TOKEN" \ + "$HOST/$path?$params" +} + +get_resources() { + endpoint="$1" + call GET "$endpoint" | jq -r '.MediaContainer.Directory // []' +} + +get_resource_id() { + endpoint="$1" + ident_field="$2" + name="$3" + + get_resources "$endpoint" | jq -r --arg field "$ident_field" --arg name "$name" '.[] | select(.[$field] == $name) | .key // empty' +} + +upsert_resource() { + endpoint="$1" + ident_field="$2" + name="$3" + params="$4" + + id="$(get_resource_id "$endpoint" "$ident_field" "$name")" + + if [ -n "$id" ] && [ "$id" != "null" ]; then + echo "Updating library '$name' (id=$id)" + call PUT "$endpoint/$id" "$params" + else + echo "Creating library '$name'" + call POST "$endpoint" "$params" + fi +} + +prune_resources() { + endpoint="$1" + ident_field="$2" + + shift 2 + + keep_list="$(printf '%s\n' "$@" | jq -R . | jq -s .)" + resources="$(get_resources "$endpoint")" + + printf '%s' "$resources" | jq -c '.[]' | while IFS= read -r library; do + name="$(printf '%s' "$library" | jq -r --arg field "$ident_field" '.[$field]')" + id="$(printf '%s' "$library" | jq -r '.key')" + found="$(printf '%s' "$keep_list" | jq -r --arg name "$name" 'index($name)')" + + if [ "$found" = "null" ]; then + echo "Deleting extra library '$name' (id=$id)" + call DELETE "$endpoint/$id" || echo "failed to delete $name, continuing" + fi + done +} + +build_films_payload() { + cat <<-EOF +name=Films&type=movie&agent=tv.plex.agents.movie&scanner=Plex%20Movie&language=en-US&location=%2Fvar%2Flib%2Fmedia%2Flibraries%2Ffilms&prefs%5BuseRedbandTrailers%5D=1&prefs%5BincludeAdultContent%5D=1&prefs%5BautoCollectionThreshold%5D=2&prefs%5BcollectionMode%5D=1&prefs%5BenableAdMarkerGeneration%5D=2 +EOF +} + +build_shows_payload() { + cat <<-EOF +name=Shows&type=show&agent=tv.plex.agents.series&scanner=Plex%20TV%20Series&language=en-US&location=%2Fvar%2Flib%2Fmedia%2Flibraries%2Fshows&prefs%5BuseSeasonTitles%5D=1&prefs%5BuseRedbandTrailers%5D=1&prefs%5BincludeAdultContent%5D=1&prefs%5BcollectionMode%5D=1&prefs%5BenableAdMarkerGeneration%5D=2 +EOF +} + +build_anime_films_payload() { + cat <<-EOF +name=Films%20%28Anime%29&type=movie&agent=tv.plex.agents.movie&scanner=Plex%20Movie&language=en-US&location=%2Fvar%2Flib%2Fmedia%2Flibraries%2Fanime%2Ffilms&prefs%5Bcountry%5D=JP&prefs%5BuseRedbandTrailers%5D=1&prefs%5BincludeAdultContent%5D=1&prefs%5BautoCollectionThreshold%5D=2&prefs%5BcollectionMode%5D=1&prefs%5BenableAdMarkerGeneration%5D=2 +EOF +} + +build_anime_shows_payload() { + cat <<-EOF +name=Shows%20%28Anime%29&type=show&agent=tv.plex.agents.series&scanner=Plex%20TV%20Series&language=en-US&location=%2Fvar%2Flib%2Fmedia%2Flibraries%2Fanime%2Fshows&prefs%5Bcountry%5D=JP&prefs%5BuseSeasonTitles%5D=1&prefs%5BuseRedbandTrailers%5D=1&prefs%5BincludeAdultContent%5D=1&prefs%5BcollectionMode%5D=1&prefs%5BenableAdMarkerGeneration%5D=2 +EOF +} + +wait_for_api + +try_forever upsert_resource "library/sections" "title" "Films" "$(build_films_payload)" +try_forever upsert_resource "library/sections" "title" "Shows" "$(build_shows_payload)" +try_forever upsert_resource "library/sections" "title" "Films (Anime)" "$(build_anime_films_payload)" +try_forever upsert_resource "library/sections" "title" "Shows (Anime)" "$(build_anime_shows_payload)" + +prune_resources "library/sections" "title" "Films" "Shows" "Films (Anime)" "Shows (Anime)" diff --git a/overlays/default.nix b/overlays/default.nix index 2c89852..a9b795c 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -24,7 +24,6 @@ final: prev: grafana-image-renderer = final.docker-image-grafana-image-renderer; grafana-to-ntfy = final.docker-image-grafana-to-ntfy; grafana = final.docker-image-grafana; - jellyfin = final.docker-image-jellyfin; jellyseerr = final.docker-image-jellyseerr; littlelink-server = final.docker-image-littlelink-server; mariadb = final.docker-image-mariadb; @@ -35,6 +34,7 @@ final: prev: ntfy = final.docker-image-ntfy; oidcwarden = final.docker-image-oidcwarden; outline = final.docker-image-outline; + plex = final.docker-image-plex; postgresql = final.docker-image-postgresql; prometheus = final.docker-image-prometheus; prometheus-fail2ban-exporter = final.docker-image-prometheus-fail2ban-exporter; @@ -53,20 +53,6 @@ final: prev: transmission-protonvpn = final.docker-image-transmission-protonvpn; whoami = final.docker-image-whoami; }; - - jellyfinPlugins = prev.jellyfinPlugins or { } // { - bookshelf = final.jellyfin-plugin-bookshelf-bin; - intro-skipper = final.jellyfin-plugin-intro-skipper-bin; - javascript-injector = final.jellyfin-plugin-javascript-injector-bin; - opensubtitles = final.jellyfin-plugin-opensubtitles-bin; - playbackreporting = final.jellyfin-plugin-playbackreporting-bin; - reports = final.jellyfin-plugin-reports-bin; - sso = final.jellyfin-plugin-sso-bin; - subtitleextract = final.jellyfin-plugin-subtitleextract-bin; - tmdbboxsets = final.jellyfin-plugin-tmdbboxsets-bin; - tvdb = final.jellyfin-plugin-tvdb-bin; - }; - obsidianPlugins = prev.obsidianPlugins or { } // { better-word-count = final.obsidian-plugin-better-word-count; dataview = final.obsidian-plugin-dataview; diff --git a/packages/default.nix b/packages/default.nix index ab07245..7185b54 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -17,7 +17,6 @@ docker-image-grafana-image-renderer = import ./docker/grafana-image-renderer { inherit pkgs; }; docker-image-grafana-to-ntfy = import ./docker/grafana-to-ntfy { inherit pkgs; }; docker-image-grafana = import ./docker/grafana { inherit pkgs; }; - docker-image-jellyfin = import ./docker/jellyfin { inherit pkgs; }; docker-image-jellyseerr = import ./docker/jellyseerr { inherit pkgs; }; docker-image-littlelink-server = import ./docker/littlelink-server { inherit pkgs; }; docker-image-mariadb = import ./docker/mariadb { inherit pkgs; }; @@ -28,6 +27,7 @@ docker-image-ntfy = import ./docker/ntfy { inherit pkgs; }; docker-image-oidcwarden = import ./docker/oidcwarden { inherit pkgs; }; docker-image-outline = import ./docker/outline { inherit pkgs; }; + docker-image-plex = import ./docker/plex { inherit pkgs; }; docker-image-postgresql = import ./docker/postgresql { inherit pkgs; }; docker-image-prometheus = import ./docker/prometheus { inherit pkgs; }; docker-image-prometheus-fail2ban-exporter = import ./docker/prometheus-fail2ban-exporter { @@ -52,21 +52,6 @@ docker-image-transmission-protonvpn = import ./docker/transmission-protonvpn { inherit pkgs; }; docker-image-whoami = import ./docker/whoami { inherit pkgs; }; - jellyfin-plugin-bookshelf-bin = import ./jellyfin/plugins/bookshelf { inherit pkgs; }; - jellyfin-plugin-intro-skipper-bin = import ./jellyfin/plugins/intro-skipper { inherit pkgs; }; - jellyfin-plugin-javascript-injector-bin = import ./jellyfin/plugins/javascript-injector { - inherit pkgs; - }; - jellyfin-plugin-opensubtitles-bin = import ./jellyfin/plugins/opensubtitles { inherit pkgs; }; - jellyfin-plugin-playbackreporting-bin = import ./jellyfin/plugins/playbackreporting { - inherit pkgs; - }; - jellyfin-plugin-reports-bin = import ./jellyfin/plugins/reports { inherit pkgs; }; - jellyfin-plugin-sso-bin = import ./jellyfin/plugins/sso { inherit pkgs; }; - jellyfin-plugin-subtitleextract-bin = import ./jellyfin/plugins/subtitleextract { inherit pkgs; }; - jellyfin-plugin-tmdbboxsets-bin = import ./jellyfin/plugins/tmdbboxsets { inherit pkgs; }; - jellyfin-plugin-tvdb-bin = import ./jellyfin/plugins/tvdb { inherit pkgs; }; - littlelink-server = import ./littlelink-server { inherit pkgs; }; obsidian-plugin-better-word-count = import ./obsidian/plugins/better-word-count { inherit pkgs; }; diff --git a/packages/docker/attic/entrypoint.sh b/packages/docker/attic/entrypoint.sh index ee8c603..9e368c8 100644 --- a/packages/docker/attic/entrypoint.sh +++ b/packages/docker/attic/entrypoint.sh @@ -4,7 +4,7 @@ set -o errexit set -o nounset atticd "$@" & -PID=$! +PID="$!" if [ -f /etc/attic/post-start.sh ]; then # shellcheck disable=SC1091 diff --git a/packages/docker/jellyfin/default.nix b/packages/docker/jellyfin/default.nix deleted file mode 100644 index 27dac58..0000000 --- a/packages/docker/jellyfin/default.nix +++ /dev/null @@ -1,77 +0,0 @@ -{ pkgs, ... }: -let - 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 - ''; - - entrypoint = pkgs.writeTextFile { - name = "entrypoint"; - executable = true; - destination = "/bin/entrypoint"; - text = builtins.readFile ./entrypoint.sh; - }; -in -pkgs.dockerTools.buildImage { - name = "jellyfin"; - fromImage = pkgs.docker-image-base; - - copyToRoot = pkgs.buildEnv { - name = "root"; - paths = - with pkgs; - [ - entrypoint - jellyfin - jellyfin-web - jellyfin-ffmpeg - curl - jq - ] - ++ (with jellyfinPlugins; [ - bookshelf - intro-skipper - javascript-injector - opensubtitles - playbackreporting - reports - sso - subtitleextract - tmdbboxsets - tvdb - ]); - pathsToLink = [ - "/bin" - "/lib" - "/var" - ]; - }; - - config = { - Entrypoint = [ "entrypoint" ]; - ExposedPorts = { - "8096/tcp" = { }; - }; - WorkingDir = "/var/lib/jellyfin"; - Volumes = { - "/etc/jellyfin" = { }; - "/var/lib/jellyfin/data" = { }; - "/var/lib/jellyfin/metadata" = { }; - "/var/lib/jellyfin/root" = { }; - "/var/log/jellyfin" = { }; - "/tmp/jellyfin" = { }; - }; - Env = [ - # FIXME: https://github.com/NixOS/nixpkgs/issues/176081 - "FONTCONFIG_FILE=${pkgs.fontconfig.out}/etc/fonts/fonts.conf" - "FONTCONFIG_PATH=${pkgs.fontconfig.out}/etc/fonts/" - ]; - }; -} diff --git a/packages/docker/jellyfin/entrypoint.sh b/packages/docker/jellyfin/entrypoint.sh deleted file mode 100644 index 8e16edd..0000000 --- a/packages/docker/jellyfin/entrypoint.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/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 "$@" - -if [ -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/mariadb/entrypoint.sh b/packages/docker/mariadb/entrypoint.sh index cf4ef79..8671988 100644 --- a/packages/docker/mariadb/entrypoint.sh +++ b/packages/docker/mariadb/entrypoint.sh @@ -34,6 +34,6 @@ fi trap 'kill -QUIT "$PID"' INT TERM mariadbd --user=root --datadir="$DATADIR" "$@" & -PID=$! +PID="$!" wait "$PID" exit $? diff --git a/packages/docker/mysql/entrypoint.sh b/packages/docker/mysql/entrypoint.sh index 1b62a2b..fb1932c 100644 --- a/packages/docker/mysql/entrypoint.sh +++ b/packages/docker/mysql/entrypoint.sh @@ -34,6 +34,6 @@ fi trap 'kill -QUIT "$PID"' INT TERM mysqld --user=root --datadir="$DATADIR" "$@" & -PID=$! +PID="$!" wait "$PID" exit $? diff --git a/packages/docker/plex/default.nix b/packages/docker/plex/default.nix new file mode 100644 index 0000000..0d1d623 --- /dev/null +++ b/packages/docker/plex/default.nix @@ -0,0 +1,47 @@ +{ pkgs, ... }: +let + entrypoint = pkgs.writeTextFile { + name = "entrypoint"; + executable = true; + destination = "/bin/entrypoint"; + text = builtins.readFile ./entrypoint.sh; + }; +in +pkgs.dockerTools.buildImage { + name = "plex"; + fromImage = pkgs.docker-image-base; + + copyToRoot = pkgs.buildEnv { + name = "root"; + paths = with pkgs; [ + entrypoint + util-linux + plex + xmlstarlet + curl + jq + sqlite + ]; + pathsToLink = [ + "/bin" + "/lib" + "/var" + "/usr" + ]; + }; + + config = { + Entrypoint = [ "entrypoint" ]; + ExposedPorts = { + "32400/tcp" = { }; + }; + WorkingDir = "/var/lib/plex"; + Volumes = { + "/var/lib/plex" = { }; + }; + Env = [ + "LD_LIBRARY_PATH=/run/opengl-driver/lib" + "PLEX_DATADIR=/var/lib/plex" + ]; + }; +} diff --git a/packages/docker/plex/entrypoint.sh b/packages/docker/plex/entrypoint.sh new file mode 100644 index 0000000..ad998e4 --- /dev/null +++ b/packages/docker/plex/entrypoint.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env sh + +set -o errexit +set -o nounset + +PREFERENCES="/var/lib/plex/Plex Media Server/Preferences.xml" +TEMPLATE_PREFERENCES="/etc/plex/Preferences.xml" + +getPref() { + xmlstarlet sel -t -v "/Preferences/@$1" "$PREFERENCES" 2>/dev/null || true +} + +setPref() { + name="$1" + value="$2" + + xmlstarlet ed --inplace \ + -d "/Preferences/@${name}" \ + -i "/Preferences" -t attr -n "${name}" -v "${value}" \ + "$PREFERENCES" +} + +mkdir -p "$(dirname "$PREFERENCES")" +if [ ! -f "$PREFERENCES" ]; then + echo '' > "$PREFERENCES" +fi + +if [ -f "$TEMPLATE_PREFERENCES" ]; then + ATTRS="$(xmlstarlet sel -t -m "/Preferences/@*" -v "concat(name(),'=',.)" -n "$TEMPLATE_PREFERENCES")" + + if [ -n "$ATTRS" ]; then + set -- + + while IFS='=' read -r name value; do + [ -z "$name" ] && continue + set -- "$@" -d "/Preferences/@${name}" + set -- "$@" -i "/Preferences" -t attr -n "${name}" -v "${value}" + done < "$PIPE" 2>&1 & -PID=$! +PID="$!" CAT_PIPE=$(mktemp -u) GREP_PIPE=$(mktemp -u) @@ -108,7 +108,7 @@ rpc_url="http://127.0.0.1:9091${rpc_path}rpc/" sleep 45 done ) & -NATPMP_PID=$! +NATPMP_PID="$!" # shellcheck disable=SC2317 cleanup() { diff --git a/packages/jellyfin/plugins/bookshelf/default.nix b/packages/jellyfin/plugins/bookshelf/default.nix deleted file mode 100644 index 3d007e3..0000000 --- a/packages/jellyfin/plugins/bookshelf/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ pkgs, ... }: -# AUTO-UPDATE: nix-update --flake jellyfin-plugin-bookshelf-bin -pkgs.stdenv.mkDerivation (finalAttrs: { - pname = "bookshelf"; - version = "12"; - - src = pkgs.fetchzip { - url = "https://github.com/jellyfin/jellyfin-plugin-bookshelf/releases/download/v${finalAttrs.version}/bookshelf_${finalAttrs.version}.0.0.0.zip"; - sha256 = "sha256-P85SLXaJuFIv9AmAE6mPbxZDMBhqEt+88dZiPUKu2iQ="; - stripRoot = false; - }; - - installPhase = '' - mkdir -p $out/var/lib/jellyfin/plugins - cp -r $src $out/var/lib/jellyfin/plugins/bookshelf - ''; -}) diff --git a/packages/jellyfin/plugins/intro-skipper/default.nix b/packages/jellyfin/plugins/intro-skipper/default.nix deleted file mode 100644 index c84a743..0000000 --- a/packages/jellyfin/plugins/intro-skipper/default.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ pkgs, ... }: -# AUTO-UPDATE: nix-update --flake jellyfin-plugin-intro-skipper-bin -pkgs.stdenv.mkDerivation (finalAttrs: { - pname = "intro-skipper"; - version = "10.10/v1.10.10.23"; - - src = - let - parts = pkgs.lib.strings.splitString "/" finalAttrs.version; - full = builtins.elemAt parts 1; - in - pkgs.fetchzip { - url = "https://github.com/intro-skipper/intro-skipper/releases/download/${finalAttrs.version}/intro-skipper-${full}.zip"; - sha256 = "sha256-r+syY/AlErws1xVkkiWm51aI+QxtefdLDc/sWC7oVo8="; - stripRoot = false; - }; - - installPhase = '' - mkdir -p $out/var/lib/jellyfin/plugins - cp -r $src $out/var/lib/jellyfin/plugins/intro-skipper - ''; -}) diff --git a/packages/jellyfin/plugins/javascript-injector/default.nix b/packages/jellyfin/plugins/javascript-injector/default.nix deleted file mode 100644 index 9def6a1..0000000 --- a/packages/jellyfin/plugins/javascript-injector/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ pkgs, ... }: -# AUTO-UPDATE: nix-update --flake jellyfin-plugin-javascript-injector-bin -pkgs.stdenv.mkDerivation (finalAttrs: { - pname = "javascript-injector"; - version = "2.0.0.0"; - - src = pkgs.fetchzip { - url = "https://github.com/n00bcodr/Jellyfin-JavaScript-Injector/releases/download/${finalAttrs.version}/javascript-injector-${finalAttrs.version}.zip"; - sha256 = "sha256-BzT4Hk4ulHsnkV9eKyy2oK6su98Am0x6rydfjAY/AWY="; - stripRoot = false; - }; - - installPhase = '' - mkdir -p $out/var/lib/jellyfin/plugins - cp -r $src $out/var/lib/jellyfin/plugins/javascript-injector - ''; -}) diff --git a/packages/jellyfin/plugins/opensubtitles/default.nix b/packages/jellyfin/plugins/opensubtitles/default.nix deleted file mode 100644 index d317b98..0000000 --- a/packages/jellyfin/plugins/opensubtitles/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ pkgs, ... }: -# AUTO-UPDATE: nix-update --flake jellyfin-plugin-opensubtitles-bin -pkgs.stdenv.mkDerivation (finalAttrs: { - pname = "opensubtitles"; - version = "20"; - - src = pkgs.fetchzip { - url = "https://github.com/jellyfin/jellyfin-plugin-opensubtitles/releases/download/v${finalAttrs.version}/open-subtitles_${finalAttrs.version}.0.0.0.zip"; - sha256 = "sha256-U17wQn32GB4nh05ExYJhzRw4nDvYOCB4EJtDoaaUnjI="; - stripRoot = false; - }; - - installPhase = '' - mkdir -p $out/var/lib/jellyfin/plugins - cp -r $src $out/var/lib/jellyfin/plugins/opensubtitles - ''; -}) diff --git a/packages/jellyfin/plugins/playbackreporting/default.nix b/packages/jellyfin/plugins/playbackreporting/default.nix deleted file mode 100644 index 3a8e0cd..0000000 --- a/packages/jellyfin/plugins/playbackreporting/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ pkgs, ... }: -# AUTO-UPDATE: nix-update --flake jellyfin-plugin-playbackreporting-bin -pkgs.stdenv.mkDerivation (finalAttrs: { - pname = "playbackreporting"; - version = "16"; - - src = pkgs.fetchzip { - url = "https://github.com/jellyfin/jellyfin-plugin-playbackreporting/releases/download/v${finalAttrs.version}/playback-reporting_${finalAttrs.version}.0.0.0.zip"; - sha256 = "sha256-UrWxS0CpeeW4nYNyRNxnK0jqiAqXwfLv3YfFokfVH0A="; - stripRoot = false; - }; - - installPhase = '' - mkdir -p $out/var/lib/jellyfin/plugins - cp -r $src $out/var/lib/jellyfin/plugins/playbackreporting - ''; -}) diff --git a/packages/jellyfin/plugins/reports/default.nix b/packages/jellyfin/plugins/reports/default.nix deleted file mode 100644 index 62a3494..0000000 --- a/packages/jellyfin/plugins/reports/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ pkgs, ... }: -# AUTO-UPDATE: nix-update --flake jellyfin-plugin-reports-bin -pkgs.stdenv.mkDerivation (finalAttrs: { - pname = "reports"; - version = "17"; - - src = pkgs.fetchzip { - url = "https://github.com/jellyfin/jellyfin-plugin-reports/releases/download/v${finalAttrs.version}/reports_${finalAttrs.version}.0.0.0.zip"; - sha256 = "sha256-kN1UDhx5/1sw3PO5co2YkfbZNiDj56F2YAT8S/0EdZM="; - stripRoot = false; - }; - - installPhase = '' - mkdir -p $out/var/lib/jellyfin/plugins - cp -r $src $out/var/lib/jellyfin/plugins/reports - ''; -}) diff --git a/packages/jellyfin/plugins/sso/default.nix b/packages/jellyfin/plugins/sso/default.nix deleted file mode 100644 index 1688f78..0000000 --- a/packages/jellyfin/plugins/sso/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ pkgs, ... }: -# AUTO-UPDATE: nix-update --flake jellyfin-plugin-sso-bin -pkgs.stdenv.mkDerivation (finalAttrs: { - pname = "sso"; - version = "3.5.2.4"; - - src = pkgs.fetchzip { - url = "https://github.com/9p4/jellyfin-plugin-sso/releases/download/v${finalAttrs.version}/sso-authentication_${finalAttrs.version}.zip"; - sha256 = "sha256-e+w5m6/7vRAynStDj34eBexfCIEgDJ09huHzi5gQEbo="; - stripRoot = false; - }; - - installPhase = '' - mkdir -p $out/var/lib/jellyfin/plugins - cp -r $src $out/var/lib/jellyfin/plugins/sso - ''; -}) diff --git a/packages/jellyfin/plugins/subtitleextract/default.nix b/packages/jellyfin/plugins/subtitleextract/default.nix deleted file mode 100644 index e0212b7..0000000 --- a/packages/jellyfin/plugins/subtitleextract/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ pkgs, ... }: -# AUTO-UPDATE: nix-update --flake jellyfin-plugin-subtitleextract-bin -pkgs.stdenv.mkDerivation (finalAttrs: { - pname = "subtitleextract"; - version = "4"; - - src = pkgs.fetchzip { - url = "https://github.com/jellyfin/jellyfin-plugin-subtitleextract/releases/download/v${finalAttrs.version}/subtitle-extract_${finalAttrs.version}.0.0.0.zip"; - sha256 = "sha256-FstPWUYsZg416DNshIV4yOvbg6U21cRxKse8hITUyBY="; - stripRoot = false; - }; - - installPhase = '' - mkdir -p $out/var/lib/jellyfin/plugins - cp -r $src $out/var/lib/jellyfin/plugins/subtitleextract - ''; -}) diff --git a/packages/jellyfin/plugins/tmdbboxsets/default.nix b/packages/jellyfin/plugins/tmdbboxsets/default.nix deleted file mode 100644 index 96aae85..0000000 --- a/packages/jellyfin/plugins/tmdbboxsets/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ pkgs, ... }: -# AUTO-UPDATE: nix-update --flake jellyfin-plugin-tmdbboxsets-bin -pkgs.stdenv.mkDerivation (finalAttrs: { - pname = "tmdbboxsets"; - version = "11"; - - src = pkgs.fetchzip { - url = "https://github.com/jellyfin/jellyfin-plugin-tmdbboxsets/releases/download/v${finalAttrs.version}/tmdb-box-sets_${finalAttrs.version}.0.0.0.zip"; - sha256 = "sha256-cO3hpjFacS62kdXn8ebS7oMtFT9LJAt8Q4b36aSxwCQ="; - stripRoot = false; - }; - - installPhase = '' - mkdir -p $out/var/lib/jellyfin/plugins - cp -r $src $out/var/lib/jellyfin/plugins/tmdbboxsets - ''; -}) diff --git a/packages/jellyfin/plugins/tvdb/default.nix b/packages/jellyfin/plugins/tvdb/default.nix deleted file mode 100644 index 60244cc..0000000 --- a/packages/jellyfin/plugins/tvdb/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ pkgs, ... }: -# AUTO-UPDATE: nix-update --flake jellyfin-plugin-tvdb-bin -pkgs.stdenv.mkDerivation (finalAttrs: { - pname = "tvdb"; - version = "19"; - - src = pkgs.fetchzip { - url = "https://github.com/jellyfin/jellyfin-plugin-tvdb/releases/download/v${finalAttrs.version}/thetvdb_${finalAttrs.version}.0.0.0.zip"; - sha256 = "sha256-011wpVwQy562XDAwAQ44GJTbu/ESHcyo5F/wrtNBAcs="; - stripRoot = false; - }; - - installPhase = '' - mkdir -p $out/var/lib/jellyfin/plugins - cp -r $src $out/var/lib/jellyfin/plugins/tvdb - ''; -}) diff --git a/submodules/secrets b/submodules/secrets index dab48ad..a9d956a 160000 --- a/submodules/secrets +++ b/submodules/secrets @@ -1 +1 @@ -Subproject commit dab48ad2370acfa732987eef6f647bdd4f4362f8 +Subproject commit a9d956a20fc4534fcc7d3da7f0994c499c4ea405