Add media-server auto-detection — pick Emby or Jellyfin by actual running state

This commit is contained in:
Gmer4Lfe
2026-07-18 22:26:07 -04:00
parent 43716a2c74
commit e528d23c68
+81
View File
@@ -439,6 +439,9 @@ is_in_list() {
# EMBY_CONTAINER ← HOST*_EMBY_CONTAINER
# EMBY_URL ← HOST*_EMBY_URL
# EMBY_API_KEY ← HOST*_EMBY_API_KEY
# JELLYFIN_CONTAINER ← HOST*_JELLYFIN_CONTAINER
# JELLYFIN_URL ← HOST*_JELLYFIN_URL
# JELLYFIN_API_KEY ← HOST*_JELLYFIN_API_KEY
# GITEA_API_TOKEN ← HOST*_GITEA_API_TOKEN
#
# Arr-specific vars set by detect_hosts() when needed by arr scripts:
@@ -531,6 +534,13 @@ detect_hosts() {
EMBY_API_KEY_VAR="${MY_ID}_EMBY_API_KEY"
EMBY_API_KEY="${!EMBY_API_KEY_VAR:-}"
JELLYFIN_CONTAINER_VAR="${MY_ID}_JELLYFIN_CONTAINER"
JELLYFIN_CONTAINER="${!JELLYFIN_CONTAINER_VAR:-}"
JELLYFIN_URL_VAR="${MY_ID}_JELLYFIN_URL"
JELLYFIN_URL="${!JELLYFIN_URL_VAR:-}"
JELLYFIN_API_KEY_VAR="${MY_ID}_JELLYFIN_API_KEY"
JELLYFIN_API_KEY="${!JELLYFIN_API_KEY_VAR:-}"
GITEA_API_TOKEN_VAR="${MY_ID}_GITEA_API_TOKEN"
GITEA_API_TOKEN="${!GITEA_API_TOKEN_VAR:-}"
@@ -1363,6 +1373,77 @@ emby_api() {
echo "$body"
}
# ── Media Server Detection ────────────────────────────────────────────────────
# Picks whichever media server is actually running right now, so callers don't have to
# hardcode Emby or Jellyfin. Emby is preferred when both are up (it's the primary player on
# every host; Jellyfin is mainly kept around for its working ffprobe binary — see
# HOST*_FFPROBE_CONTAINER). Either container being merely *configured* in host*.conf doesn't
# count — this checks Docker's actual running state, so a host with Jellyfin installed but
# stopped correctly falls through to Emby (or to nothing, if neither is up).
#
# Requires detect_hosts() to have already run (needs EMBY_*/JELLYFIN_* aliases).
# Sets: MEDIA_SERVER ("Emby"|"Jellyfin"|""), MEDIA_SERVER_URL, MEDIA_SERVER_API_KEY.
# Returns 1 and leaves MEDIA_SERVER="" if neither configured container is running.
# Usage: detect_media_server [docker_timeout_seconds]
detect_media_server() {
local docker_timeout="${1:-10}"
MEDIA_SERVER="" MEDIA_SERVER_URL="" MEDIA_SERVER_API_KEY=""
local emby_up=false jellyfin_up=false
if [[ -n "${EMBY_CONTAINER:-}" ]]; then
[[ "$(timeout "$docker_timeout" docker inspect -f '{{.State.Running}}' \
"$EMBY_CONTAINER" 2>/dev/null)" == "true" ]] && emby_up=true
fi
if [[ -n "${JELLYFIN_CONTAINER:-}" ]]; then
[[ "$(timeout "$docker_timeout" docker inspect -f '{{.State.Running}}' \
"$JELLYFIN_CONTAINER" 2>/dev/null)" == "true" ]] && jellyfin_up=true
fi
if [[ "$emby_up" == true && "$jellyfin_up" == true ]]; then
log "Both Emby and Jellyfin are running — using Emby (primary)"
elif [[ "$emby_up" == true ]]; then
log "Emby is running, Jellyfin is not — using Emby"
elif [[ "$jellyfin_up" == true ]]; then
log "Jellyfin is running, Emby is not — using Jellyfin"
else
warn "Neither Emby nor Jellyfin is running — no media server available"
return 1
fi
if [[ "$emby_up" == true ]]; then
MEDIA_SERVER="Emby"
MEDIA_SERVER_URL="$EMBY_URL"
MEDIA_SERVER_API_KEY="$EMBY_API_KEY"
else
MEDIA_SERVER="Jellyfin"
MEDIA_SERVER_URL="$JELLYFIN_URL"
MEDIA_SERVER_API_KEY="$JELLYFIN_API_KEY"
fi
}
# General REST call against whichever server detect_media_server() picked. Jellyfin accepts
# the same X-Emby-Token header Emby uses (inherited from its Emby-fork lineage — confirmed
# live 2026-07-19), so one call shape covers both backends.
# Usage: detect_media_server && media_server_api <endpoint> [timeout_seconds]
# Prints response body on 200; returns 1 on HTTP error, curl failure, or no server detected.
media_server_api() {
local endpoint="$1" max_time="${2:-30}"
if [[ -z "${MEDIA_SERVER:-}" ]]; then
error "media_server_api called with no MEDIA_SERVER set — call detect_media_server first"
return 1
fi
local response http_code body
response=$(curl -sf --max-time "$max_time" \
-H "X-Emby-Token: $MEDIA_SERVER_API_KEY" \
-w "\n%{http_code}" \
"${MEDIA_SERVER_URL}/${endpoint}" 2>/dev/null)
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | head -n -1)
[[ "$http_code" != "200" ]] && { error "$MEDIA_SERVER API HTTP $http_code: $endpoint"; return 1; }
echo "$body"
}
# Stop containers on the REMOTE server via SSH.
# Reads CRITICAL_CONTAINER_NAMES — set from profile arrays by rsync.sh.
# Tracks running state in RUNNING_CONTAINERS for restart after sync.