#!/usr/bin/env bash set -euo pipefail # Headless GL: start a virtual framebuffer unless a real DISPLAY is provided # (a GPU node may pass through an X socket). CasparCG's mixer needs a GL context. if [ -z "${DISPLAY:-}" ]; then echo "[entrypoint] starting Xvfb on :99" Xvfb :99 -screen 0 1920x1080x24 -nolisten tcp & export DISPLAY=:99 # Give Xvfb a moment to create the socket. for i in $(seq 1 20); do [ -e /tmp/.X11-unix/X99 ] && break sleep 0.25 done fi # Ensure the HLS preview directory exists before CasparCG attaches its second # FFMPEG consumer (mam-api serves /live//* from the shared volume). if [ -n "${CHANNEL_ID:-}" ]; then mkdir -p "/media/live/${CHANNEL_ID}" fi # Launch CasparCG Server from its install dir (it reads ./casparcg.config and # resolves relative media paths against the configured media folder). cd /opt/casparcg CASPAR_BIN="./casparcg" [ -x "$CASPAR_BIN" ] || CASPAR_BIN="./CasparCG Server" echo "[entrypoint] launching CasparCG: $CASPAR_BIN" "$CASPAR_BIN" & CASPAR_PID=$! # Forward termination to CasparCG so the channel closes cleanly. term() { echo "[entrypoint] terminating CasparCG ($CASPAR_PID)" kill -TERM "$CASPAR_PID" 2>/dev/null || true wait "$CASPAR_PID" 2>/dev/null || true exit 0 } trap term SIGTERM SIGINT # Launch the Node control shim (foreground). If it exits, stop the container. cd /app node src/index.js & NODE_PID=$! wait -n "$CASPAR_PID" "$NODE_PID" term