Files
infrastructure/servers/legion/k8s/media/overseerr.yaml
T
Will Anderson 4031628f4b fix(seerr): add main.mediaServerType to settings.json to prevent crash
Seerr's checkOverseerrMerge calls Settings.load with raw=true, which
replaces this.data entirely with file contents. If settings.main is
absent (as in our jellyfin-only restore), it crashes at line 418:
'Cannot read properties of undefined (reading apiKey)'.

restore.js now ensures settings.main exists and mediaServerType=JELLYFIN,
which both prevents the crash and causes checkOverseerrMerge to return
early (migration already done).
2026-04-11 01:44:41 -05:00

135 lines
3.8 KiB
YAML

# 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