Archipelago — open-source initial import
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Start a dedicated X server for the attached kiosk display.
|
||||
/usr/bin/Xorg :0 vt1 -nolisten tcp -keeptty &
|
||||
XPID=$!
|
||||
|
||||
export DISPLAY=:0
|
||||
export HOME=/home/archipelago
|
||||
|
||||
X_READY=false
|
||||
for _ in $(seq 1 30); do
|
||||
if kill -0 "$XPID" 2>/dev/null && xrandr --query >/tmp/archipelago-kiosk-xrandr.txt 2>/dev/null; then
|
||||
X_READY=true
|
||||
break
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
if [ "$X_READY" != "true" ]; then
|
||||
echo 'ERROR: Xorg failed to become ready'
|
||||
kill "$XPID" 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
KIOSK_SAFE_AREA_X_PX=${ARCHIPELAGO_KIOSK_SAFE_AREA_X_PX:-}
|
||||
KIOSK_SAFE_AREA_Y_PX=${ARCHIPELAGO_KIOSK_SAFE_AREA_Y_PX:-}
|
||||
|
||||
# Actual mode of the kiosk output — configure_display overwrites these so
|
||||
# Chromium's window matches the panel instead of assuming 1080p (a 1366x768
|
||||
# laptop panel otherwise gets a clipped oversized window).
|
||||
KIOSK_MODE_W=1920
|
||||
KIOSK_MODE_H=1080
|
||||
|
||||
configure_display() {
|
||||
command -v xrandr >/dev/null 2>&1 || return 0
|
||||
|
||||
local output mode internal width height
|
||||
output=$(awk '/ connected/ && $1 !~ /^eDP|^LVDS/{print $1; exit}' /tmp/archipelago-kiosk-xrandr.txt)
|
||||
[ -n "$output" ] || output=$(awk '/ connected/{print $1; exit}' /tmp/archipelago-kiosk-xrandr.txt)
|
||||
[ -n "$output" ] || return 0
|
||||
|
||||
# Pick the EDID-preferred ("+") mode, falling back to the first-listed
|
||||
# mode (EDID lists native first). Deliberately ignore "*" (currently
|
||||
# active) — trusting "active" lets a bad clone/mirror state from a
|
||||
# previous boot perpetuate itself forever instead of self-healing.
|
||||
mode=$(awk -v out="$output" '
|
||||
$1 == out { active = 1; next }
|
||||
active && /^[[:space:]]+[0-9]+x[0-9]+/ {
|
||||
if ($0 ~ /\+/ && !preferred) { preferred = $1 }
|
||||
if (!first) first = $1
|
||||
}
|
||||
active && /^[^[:space:]]/ { active = 0 }
|
||||
END { if (preferred) print preferred; else if (first) print first }
|
||||
' /tmp/archipelago-kiosk-xrandr.txt)
|
||||
[ -n "$mode" ] || mode=1920x1080
|
||||
|
||||
# Kiosk should use one native output. A spanning desktop makes Chromium land
|
||||
# on the laptop panel or stretch across both outputs.
|
||||
for internal in $(awk '/ connected/ && $1 ~ /^eDP|^LVDS/{print $1}' /tmp/archipelago-kiosk-xrandr.txt); do
|
||||
[ "$internal" = "$output" ] || xrandr --output "$internal" --off 2>/dev/null || true
|
||||
done
|
||||
|
||||
xrandr --output "$output" \
|
||||
--primary \
|
||||
--mode "$mode" \
|
||||
--pos 0x0 \
|
||||
--scale 1x1 \
|
||||
--panning 0x0 \
|
||||
--transform none 2>/dev/null || true
|
||||
|
||||
width=${mode%x*}
|
||||
height=${mode#*x}
|
||||
case "$width:$height" in *[!0-9:]*|:*) width=1920; height=1080 ;; esac
|
||||
KIOSK_MODE_W=$width
|
||||
KIOSK_MODE_H=$height
|
||||
|
||||
# Browser safe-area fallback for TVs that crop edges. Driver underscan is
|
||||
# preferable, but many Intel HDMI outputs do not expose that property.
|
||||
KIOSK_SAFE_AREA_X_PX=${KIOSK_SAFE_AREA_X_PX:-$((width * 3 / 100))}
|
||||
KIOSK_SAFE_AREA_Y_PX=${KIOSK_SAFE_AREA_Y_PX:-$((height * 3 / 100))}
|
||||
}
|
||||
|
||||
configure_display
|
||||
|
||||
xhost +SI:localuser:archipelago 2>/dev/null || true
|
||||
xsetroot -solid black 2>/dev/null || true
|
||||
xset s off 2>/dev/null || true
|
||||
xset -dpms 2>/dev/null || true
|
||||
xset s noblank 2>/dev/null || true
|
||||
|
||||
pkill -u archipelago -f 'chromium.*localhost' 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
# GPU vs headless (#36, choppy-audio incident 2026-06-28). --enable-gpu-rasterization
|
||||
# spins a dedicated GPU process at 55-92% CPU even on real GPU hardware (Intel HD 5500)
|
||||
# because under X11 it falls back to software compositing anyway — that CPU
|
||||
# starvation is what caused choppy HDMI audio. --in-process-gpu avoids the
|
||||
# separate process; GpuRasterization is also disabled via --disable-features below.
|
||||
# On a GPU-less / headless server (no /dev/dri), disable GPU entirely instead.
|
||||
if [ -e /dev/dri/card0 ] || [ -e /dev/dri/renderD128 ]; then
|
||||
GPU_FLAGS="--in-process-gpu --num-raster-threads=1"
|
||||
else
|
||||
GPU_FLAGS="--disable-gpu --num-raster-threads=1"
|
||||
fi
|
||||
|
||||
ARCHIPELAGO_UID=$(id -u archipelago)
|
||||
|
||||
while true; do
|
||||
# XDG_RUNTIME_DIR must be passed explicitly — without it Chromium's audio
|
||||
# backend can't find PipeWire-Pulse's socket at /run/user/<uid>/pulse/native,
|
||||
# falls back to raw ALSA "default", fails to connect, and produces no audio
|
||||
# at all with no visible error (--noerrdialogs suppresses it).
|
||||
sudo -u archipelago env DISPLAY=:0 HOME=/home/archipelago XDG_RUNTIME_DIR=/run/user/$ARCHIPELAGO_UID chromium --kiosk \
|
||||
--app=http://localhost/kiosk?safe_area_x=${KIOSK_SAFE_AREA_X_PX:-0}\&safe_area_y=${KIOSK_SAFE_AREA_Y_PX:-0} \
|
||||
--noerrdialogs \
|
||||
--disable-infobars \
|
||||
--disable-translate \
|
||||
--no-first-run \
|
||||
--check-for-update-interval=31536000 \
|
||||
--disable-features=TranslateUI,MetricsReporting,AutofillServerCommunication,PasswordManagerEnabled,GpuRasterization \
|
||||
--disable-session-crashed-bubble \
|
||||
--disable-save-password-bubble \
|
||||
--disable-suggestions-service \
|
||||
--disable-component-update \
|
||||
$GPU_FLAGS \
|
||||
--renderer-process-limit=2 \
|
||||
--window-size=${KIOSK_MODE_W},${KIOSK_MODE_H} \
|
||||
--window-position=0,0 \
|
||||
--start-fullscreen \
|
||||
--force-device-scale-factor=1 \
|
||||
--disable-background-networking \
|
||||
--disable-background-timer-throttling \
|
||||
--disable-backgrounding-occluded-windows \
|
||||
--disable-breakpad \
|
||||
--disable-metrics \
|
||||
--disable-metrics-reporting \
|
||||
--disable-domain-reliability \
|
||||
--js-flags="--max-old-space-size=128" \
|
||||
--user-data-dir=/var/lib/archipelago/chromium-kiosk
|
||||
sleep 3
|
||||
done
|
||||
|
||||
kill "$XPID" 2>/dev/null || true
|
||||
Reference in New Issue
Block a user