diff options
| author | Robert Günzler <r@gnzler.io> | 2025-09-07 17:32:13 +0200 |
|---|---|---|
| committer | Robert Günzler <r@gnzler.io> | 2025-09-07 17:42:42 +0200 |
| commit | 38be6c13f76e893cf47636257071b440dec0c5b2 (patch) | |
| tree | f7ded3235a7e3362cbd1ed3d91523968fe0faf90 /bundles/jellyfin | |
initial commit
Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to 'bundles/jellyfin')
| -rw-r--r-- | bundles/jellyfin/bcast.py | 20 | ||||
| -rw-r--r-- | bundles/jellyfin/files/SSO-Auth.xml | 71 | ||||
| -rw-r--r-- | bundles/jellyfin/files/branding.xml | 17 | ||||
| -rw-r--r-- | bundles/jellyfin/files/kube.yaml | 72 | ||||
| -rw-r--r-- | bundles/jellyfin/files/logging.json | 11 | ||||
| -rw-r--r-- | bundles/jellyfin/files/system.xml | 202 | ||||
| -rw-r--r-- | bundles/jellyfin/items.py | 33 | ||||
| -rw-r--r-- | bundles/jellyfin/metadata.py | 16 |
8 files changed, 442 insertions, 0 deletions
diff --git a/bundles/jellyfin/bcast.py b/bundles/jellyfin/bcast.py new file mode 100644 index 0000000..2318441 --- /dev/null +++ b/bundles/jellyfin/bcast.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +import socket +from time import sleep + +def main(): + msg = b'Who is JellyfinServer?' + + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # UDP + sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + sock.bind(('0.0.0.0',0)) + sock.sendto(msg, ("255.255.255.255", 7359)) + sock.settimeout(10) + recvd, (ip, port) = sock.recvfrom(4096) + sock.close() + print(f"{ip}:{port} says:") + print(recvd.decode('utf-8')) + +main() + diff --git a/bundles/jellyfin/files/SSO-Auth.xml b/bundles/jellyfin/files/SSO-Auth.xml new file mode 100644 index 0000000..50dfdc8 --- /dev/null +++ b/bundles/jellyfin/files/SSO-Auth.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<PluginConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <SamlConfigs /> + <OidConfigs> + <item> + <key> + <string>authelia</string> + </key> + <value> + <PluginConfiguration> + <OidEndpoint>https://login.gzr.im</OidEndpoint> + <OidClientId>jellyfin</OidClientId> + <OidSecret>${repo.vault.cmd(f"rbw get authelia/client/jellyfin")}</OidSecret> + <Enabled>true</Enabled> + <EnableAuthorization>true</EnableAuthorization> + <EnableAllFolders>false</EnableAllFolders> + <EnabledFolders> + <string>f137a2dd21bbc1b99aa5c0f6bf02a805</string> + <string>a656b907eb3a73532e40e44b968d0225</string> + </EnabledFolders> + <AdminRoles> + <string>admins</string> + </AdminRoles> + <Roles> + <string>jellyfin</string> + </Roles> + <EnableFolderRoles>true</EnableFolderRoles> + <EnableLiveTvRoles>false</EnableLiveTvRoles> + <EnableLiveTv>false</EnableLiveTv> + <EnableLiveTvManagement>false</EnableLiveTvManagement> + <LiveTvRoles /> + <LiveTvManagementRoles /> + <FolderRoleMappings> + <FolderRoleMappings> + <Role>jellyfin</Role> + <Folders> + <string>f137a2dd21bbc1b99aa5c0f6bf02a805</string> + <string>a656b907eb3a73532e40e44b968d0225</string> + </Folders> + </FolderRoleMappings> + <FolderRoleMappings> + <Role>jellyfin-anime</Role> + <Folders> + <string>abebc196cc1b8bbf6f8bb5ca7b5ad6f1</string> + <string>29391378c4118b35b77f84980d25f0a6</string> + </Folders> + </FolderRoleMappings> + <FolderRoleMappings> + <Role>jellyfin-misc</Role> + <Folders> + <string>a1bc8a1aac164cd3d91bf3f4252f92f4</string> + </Folders> + </FolderRoleMappings> + </FolderRoleMappings> + <RoleClaim>groups</RoleClaim> + <OidScopes> + <string>groups</string> + </OidScopes> + <DefaultProvider>authelia</DefaultProvider> + <SchemeOverride>https</SchemeOverride> + <NewPath>true</NewPath> + <CanonicalLinks /> + <DisableHttps>false</DisableHttps> + <DisablePushedAuthorization>false</DisablePushedAuthorization> + <DoNotValidateEndpoints>false</DoNotValidateEndpoints> + <DoNotValidateIssuerName>false</DoNotValidateIssuerName> + </PluginConfiguration> + </value> + </item> + </OidConfigs> +</PluginConfiguration> diff --git a/bundles/jellyfin/files/branding.xml b/bundles/jellyfin/files/branding.xml new file mode 100644 index 0000000..487db6e --- /dev/null +++ b/bundles/jellyfin/files/branding.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<BrandingOptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <LoginDisclaimer><form action="https://tv.gzr.im/sso/OID/start/authelia"> + <button class="raised block emby-button button-submit"> + Sign in with SSO + </button> +</form></LoginDisclaimer> + <CustomCss>a.raised.emby-button { + padding: 0.9em 1em; + color: inherit !important; +} + +.disclaimerContainer { + display: block; +}</CustomCss> + <SplashscreenEnabled>false</SplashscreenEnabled> +</BrandingOptions> diff --git a/bundles/jellyfin/files/kube.yaml b/bundles/jellyfin/files/kube.yaml new file mode 100644 index 0000000..fb6897c --- /dev/null +++ b/bundles/jellyfin/files/kube.yaml @@ -0,0 +1,72 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: jellyfin +data: + JELLYFIN_PublishedServerUrl: http://shimakaze:8096 +--- +apiVersion: v1 +kind: Pod +metadata: + name: jellyfin + labels: + traefik.enable: true + traefik.http.routers.jellyfin.tls: true + traefik.http.routers.jellyfin.tls.certresolver: le + traefik.http.routers.jellyfin.entrypoints: http,https + traefik.http.routers.jellyfin.rule: Host(`tv.gzr.im`) + traefik.http.routers.jellyfin.service: jellyfin + traefik.http.services.jellyfin.loadbalancer.server.port: 8096 + # metrics + traefik.http.routers.jellyfin-metrics.entrypoints: metrics + traefik.http.routers.jellyfin-metrics.rule: Path(`/metrics/jellyfin`) + traefik.http.routers.jellyfin-metrics.middlewares: replacepath-metrics +spec: + # NOTE: required to make discovery work + # jellyfin clients use udp broadcast messages on port 7359 + # sending "Who is JellyfinServer?". To receive those requests the + # jellyfin server can't be behind container networking + hostNetwork: true + + restartPolicy: Never + dnsPolicy: Default + containers: + - name: jellyfin + image: ghcr.io/jellyfin/jellyfin:10.10.7 + envFrom: + - configMapRef: + name: jellyfin + ports: + - containerPort: 8096 + protocol: TCP + - containerPort: 1900 + protocol: UDP + - containerPort: 7359 + protocol: UDP + volumeMounts: + - name: data + mountPath: /config + - name: cache + mountPath: /cache + - name: media + mountPath: /media + readOnly: true + resources: + requests: + podman.io/device=/dev/dri/card0: 1 + podman.io/device=/dev/dri/renderD128: 1 + limits: + #cpu: 300m + #memory: 512Mi + + volumes: + - name: data + hostPath: + path: /var/lib/jellyfin + type: DirectoryOrCreate + - name: cache + emptyDir: {} + - name: media + hostPath: + path: /media/hayasui/media + type: Directory diff --git a/bundles/jellyfin/files/logging.json b/bundles/jellyfin/files/logging.json new file mode 100644 index 0000000..b658515 --- /dev/null +++ b/bundles/jellyfin/files/logging.json @@ -0,0 +1,11 @@ +{ + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Warning", + "System": "Warning" + } + } + } +} diff --git a/bundles/jellyfin/files/system.xml b/bundles/jellyfin/files/system.xml new file mode 100644 index 0000000..0696f49 --- /dev/null +++ b/bundles/jellyfin/files/system.xml @@ -0,0 +1,202 @@ +<?xml version="1.0" encoding="utf-8"?> +<ServerConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <LogFileRetentionDays>3</LogFileRetentionDays> + <IsStartupWizardCompleted>true</IsStartupWizardCompleted> + <CachePath>/cache</CachePath> + <EnableMetrics>true</EnableMetrics> + <EnableNormalizedItemByNameIds>true</EnableNormalizedItemByNameIds> + <IsPortAuthorized>true</IsPortAuthorized> + <QuickConnectAvailable>false</QuickConnectAvailable> + <EnableCaseSensitiveItemIds>true</EnableCaseSensitiveItemIds> + <DisableLiveTvChannelUserDataName>true</DisableLiveTvChannelUserDataName> + <MetadataPath>/config/metadata</MetadataPath> + <PreferredMetadataLanguage>en</PreferredMetadataLanguage> + <MetadataCountryCode>DE</MetadataCountryCode> + <SortReplaceCharacters> + <string>.</string> + <string>+</string> + <string>%</string> + </SortReplaceCharacters> + <SortRemoveCharacters> + <string>,</string> + <string>&</string> + <string>-</string> + <string>{</string> + <string>}</string> + <string>'</string> + </SortRemoveCharacters> + <SortRemoveWords> + <string>the</string> + <string>a</string> + <string>an</string> + </SortRemoveWords> + <MinResumePct>5</MinResumePct> + <MaxResumePct>90</MaxResumePct> + <MinResumeDurationSeconds>300</MinResumeDurationSeconds> + <MinAudiobookResume>5</MinAudiobookResume> + <MaxAudiobookResume>5</MaxAudiobookResume> + <InactiveSessionThreshold>0</InactiveSessionThreshold> + <LibraryMonitorDelay>60</LibraryMonitorDelay> + <LibraryUpdateDuration>30</LibraryUpdateDuration> + <ImageSavingConvention>Legacy</ImageSavingConvention> + <MetadataOptions> + <MetadataOptions> + <ItemType>Book</ItemType> + <DisabledMetadataSavers /> + <LocalMetadataReaderOrder /> + <DisabledMetadataFetchers /> + <MetadataFetcherOrder /> + <DisabledImageFetchers /> + <ImageFetcherOrder /> + </MetadataOptions> + <MetadataOptions> + <ItemType>Movie</ItemType> + <DisabledMetadataSavers /> + <LocalMetadataReaderOrder /> + <DisabledMetadataFetchers /> + <MetadataFetcherOrder /> + <DisabledImageFetchers /> + <ImageFetcherOrder /> + </MetadataOptions> + <MetadataOptions> + <ItemType>MusicVideo</ItemType> + <DisabledMetadataSavers /> + <LocalMetadataReaderOrder /> + <DisabledMetadataFetchers> + <string>The Open Movie Database</string> + </DisabledMetadataFetchers> + <MetadataFetcherOrder /> + <DisabledImageFetchers> + <string>The Open Movie Database</string> + </DisabledImageFetchers> + <ImageFetcherOrder /> + </MetadataOptions> + <MetadataOptions> + <ItemType>Series</ItemType> + <DisabledMetadataSavers /> + <LocalMetadataReaderOrder /> + <DisabledMetadataFetchers /> + <MetadataFetcherOrder /> + <DisabledImageFetchers /> + <ImageFetcherOrder /> + </MetadataOptions> + <MetadataOptions> + <ItemType>MusicAlbum</ItemType> + <DisabledMetadataSavers /> + <LocalMetadataReaderOrder /> + <DisabledMetadataFetchers> + <string>TheAudioDB</string> + </DisabledMetadataFetchers> + <MetadataFetcherOrder /> + <DisabledImageFetchers /> + <ImageFetcherOrder /> + </MetadataOptions> + <MetadataOptions> + <ItemType>MusicArtist</ItemType> + <DisabledMetadataSavers /> + <LocalMetadataReaderOrder /> + <DisabledMetadataFetchers> + <string>TheAudioDB</string> + </DisabledMetadataFetchers> + <MetadataFetcherOrder /> + <DisabledImageFetchers /> + <ImageFetcherOrder /> + </MetadataOptions> + <MetadataOptions> + <ItemType>BoxSet</ItemType> + <DisabledMetadataSavers /> + <LocalMetadataReaderOrder /> + <DisabledMetadataFetchers /> + <MetadataFetcherOrder /> + <DisabledImageFetchers /> + <ImageFetcherOrder /> + </MetadataOptions> + <MetadataOptions> + <ItemType>Season</ItemType> + <DisabledMetadataSavers /> + <LocalMetadataReaderOrder /> + <DisabledMetadataFetchers /> + <MetadataFetcherOrder /> + <DisabledImageFetchers /> + <ImageFetcherOrder /> + </MetadataOptions> + <MetadataOptions> + <ItemType>Episode</ItemType> + <DisabledMetadataSavers /> + <LocalMetadataReaderOrder /> + <DisabledMetadataFetchers /> + <MetadataFetcherOrder /> + <DisabledImageFetchers /> + <ImageFetcherOrder /> + </MetadataOptions> + </MetadataOptions> + <SkipDeserializationForBasicTypes>true</SkipDeserializationForBasicTypes> + <ServerName>jellyfin</ServerName> + <UICulture>en-US</UICulture> + <SaveMetadataHidden>false</SaveMetadataHidden> + <ContentTypes /> + <RemoteClientBitrateLimit>0</RemoteClientBitrateLimit> + <EnableFolderView>false</EnableFolderView> + <EnableGroupingIntoCollections>false</EnableGroupingIntoCollections> + <DisplaySpecialsWithinSeasons>true</DisplaySpecialsWithinSeasons> + <CodecsUsed /> + <PluginRepositories> + <RepositoryInfo> + <Name>Jellyfin Stable</Name> + <Url>https://repo.jellyfin.org/files/plugin/manifest.json</Url> + <Enabled>true</Enabled> + </RepositoryInfo> + <RepositoryInfo> + <Name>Jellyfin SSO</Name> + <Url>https://raw.githubusercontent.com/9p4/jellyfin-plugin-sso/manifest-release/manifest.json</Url> + <Enabled>true</Enabled> + </RepositoryInfo> + <RepositoryInfo> + <Name>Intro Skipper</Name> + <Url>https://manifest.intro-skipper.org/manifest.json</Url> + <Enabled>true</Enabled> + </RepositoryInfo> + </PluginRepositories> + <EnableExternalContentInSuggestions>true</EnableExternalContentInSuggestions> + <ImageExtractionTimeoutMs>0</ImageExtractionTimeoutMs> + <PathSubstitutions /> + <EnableSlowResponseWarning>true</EnableSlowResponseWarning> + <SlowResponseThresholdMs>500</SlowResponseThresholdMs> + <CorsHosts> + <string>*</string> + </CorsHosts> + <ActivityLogRetentionDays>30</ActivityLogRetentionDays> + <LibraryScanFanoutConcurrency>0</LibraryScanFanoutConcurrency> + <LibraryMetadataRefreshConcurrency>0</LibraryMetadataRefreshConcurrency> + <RemoveOldPlugins>false</RemoveOldPlugins> + <AllowClientLogUpload>true</AllowClientLogUpload> + <DummyChapterDuration>0</DummyChapterDuration> + <ChapterImageResolution>MatchSource</ChapterImageResolution> + <ParallelImageEncodingLimit>0</ParallelImageEncodingLimit> + <CastReceiverApplications> + <CastReceiverApplication> + <Id>F007D354</Id> + <Name>Stable</Name> + </CastReceiverApplication> + <CastReceiverApplication> + <Id>6F511C87</Id> + <Name>Unstable</Name> + </CastReceiverApplication> + </CastReceiverApplications> + <TrickplayOptions> + <EnableHwAcceleration>false</EnableHwAcceleration> + <EnableHwEncoding>false</EnableHwEncoding> + <EnableKeyFrameOnlyExtraction>false</EnableKeyFrameOnlyExtraction> + <ScanBehavior>NonBlocking</ScanBehavior> + <ProcessPriority>BelowNormal</ProcessPriority> + <Interval>10000</Interval> + <WidthResolutions> + <int>320</int> + </WidthResolutions> + <TileWidth>10</TileWidth> + <TileHeight>10</TileHeight> + <Qscale>4</Qscale> + <JpegQuality>90</JpegQuality> + <ProcessThreads>1</ProcessThreads> + </TrickplayOptions> +</ServerConfiguration> diff --git a/bundles/jellyfin/items.py b/bundles/jellyfin/items.py new file mode 100644 index 0000000..5ed07ef --- /dev/null +++ b/bundles/jellyfin/items.py @@ -0,0 +1,33 @@ +files = { + "/var/lib/jellyfin/plugins/SSO-Auth.zip": { + "content_type": "download", + "source": "https://github.com/9p4/jellyfin-plugin-sso/releases/download/v3.5.2.4/sso-authentication_3.5.2.4.zip", + "content_hash": "a2f00e5acc7adf785202e27fffc969e019cbd9e8", + "triggers": {"action:extract-jellyfin-plugin-sso"}, + }, + "/var/lib/jellyfin/config/branding.xml": { + "content_type": "text", + "triggers": {"svc_s6rc:jellyfin:restart"}, + }, + "/var/lib/jellyfin/config/logging.json": { + "content_type": "mako", + "triggers": {"svc_s6rc:jellyfin:restart"}, + }, + "/var/lib/jellyfin/plugins/configurations/SSO-Auth.xml": { + "content_type": "mako", + "triggers": {"svc_s6rc:jellyfin:restart"}, + }, + + "/etc/deployments/jellyfin/kube.yaml": { + "content_type": "text", + "source": "kube.yaml", + "triggers": {"svc_s6rc:jellyfin:restart"}, + }, +} + +actions = { + "extract-jellyfin-plugin-sso": { + "command": "unzip -d /var/lib/jellyfin/plugins/SSO-Auth /var/lib/jellyfin/plugins/SSO-Auth.zip", + "triggered": True, + }, +} diff --git a/bundles/jellyfin/metadata.py b/bundles/jellyfin/metadata.py new file mode 100644 index 0000000..a614afd --- /dev/null +++ b/bundles/jellyfin/metadata.py @@ -0,0 +1,16 @@ +defaults = { + "backup": { + "includes": { + "/var/lib/jellyfin", + # "/media/hayasui/media/movies", + # "/media/hayasui/media/tvshows", + # "/media/hayasui/media/anime", + } + }, + "containers": { + "jellyfin": {}, + }, + "metrics": { + "jellyfin": {}, + }, +} |