# Seerr — family request portal (watch.nook.family) # Init container ensures Jellyfin connection is always configured from git. # If settings.json has no Jellyfin apiKey (e.g. after reset), it is restored from the ConfigMap. --- apiVersion: v1 kind: ConfigMap metadata: name: seerr-defaults namespace: media data: jellyfin.json: | { "name": "Jellyfin", "ip": "jellyfin.media.svc.cluster.local", "port": 8096, "useSsl": false, "urlBase": "", "externalHostname": "https://jellyfin.nook.family", "jellyfinForgotPasswordUrl": "", "libraries": [], "serverId": "87e202a4e9ad49d1bf73927f714fbce6", "apiKey": "35e87cb67e3a4b908678ba9a257d2571" } restore.js: | const fs = require('fs'); const SETTINGS = '/app/config/settings.json'; const DEFAULTS = '/defaults/jellyfin.json'; let settings = {}; if (fs.existsSync(SETTINGS)) { try { settings = JSON.parse(fs.readFileSync(SETTINGS, 'utf8')); } catch(e) {} } // Seerr's Settings.load runs in raw mode during the overseerrMerge check, // which replaces this.data entirely with the file contents. If settings.main // is absent, it crashes at "this.data.main.apiKey" (settings/index.js:418). // Ensure main exists with mediaServerType=JELLYFIN so the merge check is skipped. if (!settings.main) { settings.main = {}; } if (!settings.main.mediaServerType) { settings.main.mediaServerType = 'JELLYFIN'; console.log('Set main.mediaServerType = JELLYFIN'); } if (!settings.jellyfin || !settings.jellyfin.apiKey) { console.log('Jellyfin apiKey missing — restoring from defaults'); settings.jellyfin = JSON.parse(fs.readFileSync(DEFAULTS, 'utf8')); console.log('Restored Jellyfin config'); } else { console.log('Jellyfin config present, skipping restore'); } fs.writeFileSync(SETTINGS, JSON.stringify(settings, null, 2)); console.log('Settings written successfully'); --- apiVersion: apps/v1 kind: Deployment metadata: name: overseerr namespace: media labels: app: overseerr spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: overseerr template: metadata: labels: app: overseerr spec: initContainers: # Restore Jellyfin connection config if it was cleared (e.g. after pod restart with bad key) - name: restore-jellyfin-config image: node:22-alpine command: - node - /defaults/restore.js volumeMounts: - name: config mountPath: /app/config - name: seerr-defaults mountPath: /defaults containers: - name: overseerr image: seerr/seerr:latest env: - name: TZ value: "America/Chicago" ports: - containerPort: 5055 volumeMounts: - name: config mountPath: /app/config resources: requests: memory: 256Mi cpu: 100m limits: memory: 1Gi cpu: 500m livenessProbe: httpGet: path: /api/v1/status port: 5055 initialDelaySeconds: 30 periodSeconds: 30 readinessProbe: httpGet: path: /api/v1/status port: 5055 initialDelaySeconds: 15 periodSeconds: 10 volumes: - name: config persistentVolumeClaim: claimName: overseerr-config - name: seerr-defaults configMap: name: seerr-defaults --- apiVersion: v1 kind: Service metadata: name: overseerr namespace: media spec: selector: app: overseerr ports: - name: http port: 5055 targetPort: 5055 type: ClusterIP