# Apply: kubectl apply -f manifests/media/jellyfin-header-debug.yaml # Delete: kubectl delete -f manifests/media/jellyfin-header-debug.yaml # Description: TEMPORARY compat shim + diagnostic proxy in front of the real # jellyfin Service. The Filebar iOS app (<=1.4.13) sends its auth header only # on the legacy X-Emby-Authorization header, unquoted (e.g. Client=Filebar # instead of Client="Filebar"), and never sends the modern Authorization # header Jellyfin 12.0 requires to identify the client -- so every login # gets a 400 (ArgumentNullException on request.App). This proxy rewrites # just Filebar's requests into the header format Jellyfin expects (matching # what SenPlayer already sends correctly) and forwards everything else # unchanged. All requests are also logged to stdout for visibility. # # TODO: DELETE this file and revert the jellyfin Ingress backend to # `jellyfin` once Filebar ships a fixed release that sends a correct # Authorization header on its own -- this is a workaround for their bug, # not something to keep around permanently. apiVersion: v1 kind: ConfigMap metadata: name: jellyfin-debug-proxy-conf namespace: jellyfin data: default.conf: | map $http_upgrade $connection_upgrade { default upgrade; '' close; } log_format jf_debug '$time_iso8601 client=$remote_addr method=$request_method uri="$request_uri" ' 'status=$status ' 'user_agent="$http_user_agent" ' 'authorization="$http_authorization" ' 'x_emby_authorization="$http_x_emby_authorization" ' 'x_emby_token="$http_x_emby_token" ' 'x_mediabrowser_token="$http_x_mediabrowser_token"'; server { listen 8080; access_log /dev/stdout jf_debug; # TEMPORARY Filebar compat shim -- see TODO in this file's header. # Only touches requests from Filebar's broken auth header; everything # else (SenPlayer, web UI, etc.) passes through untouched. access_by_lua_block { local ua = ngx.var.http_user_agent or "" local authorization = ngx.var.http_authorization local legacy = ngx.var.http_x_emby_authorization if ua:find("^Filebar") and (not authorization or authorization == "") and legacy then local client = legacy:match("Client=([^,]+)") local device = legacy:match("Device=([^,]+)") local deviceid = legacy:match("DeviceId=([^,]+)") local version = legacy:match("Version=([^,]+)") local token = legacy:match("Token=([^,]+)") if client then local fixed = string.format('MediaBrowser Client="%s", Device="%s", DeviceId="%s", Version="%s"', client, device or "", deviceid or "", version or "") if token and token ~= "" then fixed = fixed .. string.format(', Token="%s"', token) end ngx.req.set_header("Authorization", fixed) ngx.req.set_header("X-Emby-Authorization", fixed) end end } location / { proxy_pass http://jellyfin.jellyfin.svc.cluster.local:80; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_read_timeout 3600s; } } --- apiVersion: apps/v1 kind: Deployment metadata: name: jellyfin-debug-proxy namespace: jellyfin spec: replicas: 1 selector: matchLabels: app: jellyfin-debug-proxy template: metadata: labels: app: jellyfin-debug-proxy spec: containers: - name: nginx image: openresty/openresty:1.31.1.1-alpine ports: - containerPort: 8080 volumeMounts: - name: conf mountPath: /etc/nginx/conf.d volumes: - name: conf configMap: name: jellyfin-debug-proxy-conf --- apiVersion: v1 kind: Service metadata: name: jellyfin-debug-proxy namespace: jellyfin spec: selector: app: jellyfin-debug-proxy ports: - port: 80 targetPort: 8080