# Deploy guard check for Jellyfin. # # Contract (deploy-guard-check plug-in): # - exit 0: Jellyfin has no active playback sessions (or is unreachable, which # also means no users can be watching). # - exit 1: at least one session is actively playing back media; stdout lists # user / title / client so the operator sees who they'd disrupt. # # A paused session counts as "active" — the user is at the keyboard and will # notice a restart. { config, lib, pkgs, service_configs, ... }: let apiKeyPath = config.age.secrets.jellyfin-api-key.path; jellyfinPort = service_configs.ports.private.jellyfin.port; check = pkgs.writeShellApplication { name = "deploy-guard-check-jellyfin"; runtimeInputs = with pkgs; [ curl jq coreutils ]; text = '' api_key_path=${lib.escapeShellArg apiKeyPath} if [[ ! -r "$api_key_path" ]]; then echo "jellyfin: api key not readable at $api_key_path; skipping" >&2 exit 0 fi key=$(cat "$api_key_path") if ! resp=$(curl -sf --max-time 5 \ -H "Authorization: MediaBrowser Token=$key" \ "http://127.0.0.1:${toString jellyfinPort}/Sessions" 2>/dev/null); then echo "jellyfin: unreachable; assuming safe to deploy" >&2 exit 0 fi # Parse defensively — if Jellyfin returns something we can't understand # we prefer allowing the deploy over blocking it (the worst case is we # restart jellyfin while nobody is watching). if ! active=$(printf '%s' "$resp" | jq '[.[] | select(.NowPlayingItem)] | length' 2>/dev/null); then echo "jellyfin: /Sessions response not parsable; assuming safe" >&2 exit 0 fi if [[ "$active" -eq 0 ]]; then exit 0 fi echo "Jellyfin: $active active playback session(s):" printf '%s' "$resp" | jq -r ' .[] | select(.NowPlayingItem) | " - \(.UserName // "?") \(if (.PlayState.IsPaused // false) then "paused" else "playing" end) \(.NowPlayingItem.Type // "item") \"\(.NowPlayingItem.Name // "?")\" on \(.Client // "?") / \(.DeviceName // "?")" ' exit 1 ''; }; in { imports = [ ../../modules/server-deploy-guard.nix ]; config = lib.mkIf config.services.jellyfin.enable { services.deployGuard.checks.jellyfin = { description = "Active Jellyfin playback sessions"; command = check; }; }; }