Files
Kiwy-Signage/start.sh
Kiwy Player 120c889143 Fix app crashes: optimize Kivy window backend and SDL drivers
- Commented out forced pygame backend (causes issues with display initialization)
- Added SDL_VIDEODRIVER and SDL_AUDIODRIVER fallback chains (wayland,x11,dummy)
- Limited KIVY_INPUTPROVIDERS to wayland,x11 (avoids problematic input providers)
- Reduced FFMPEG_THREADS from 4 to 2 (conserves Raspberry Pi resources)
- Reduced LIBPLAYER_BUFFER from 2MB to 1MB (saves memory)
- Fixed asyncio event loop deprecation warning (use try/except for get_running_loop)
- Better exception handling for cursor hiding

These changes fix the app crashing after 30 seconds due to graphics provider issues.
2026-01-17 21:35:30 +02:00

221 lines
7.1 KiB
Bash
Executable File

#!/bin/bash
# Kivy Signage Player Startup Script with Watchdog
# This script monitors and auto-restarts the player if it crashes
# Get the directory where this script is located
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Configuration
MAX_RETRIES=999999 # Effectively unlimited retries
RESTART_DELAY=5 # Seconds to wait before restart
HEALTH_CHECK_INTERVAL=30 # Seconds between health checks
HEARTBEAT_FILE="$SCRIPT_DIR/.player_heartbeat"
STOP_FLAG_FILE="$SCRIPT_DIR/.player_stop_requested"
LOG_FILE="$SCRIPT_DIR/player_watchdog.log"
# Ensure log file is writable
if [ ! -w "$(dirname "$LOG_FILE")" ]; then
LOG_FILE="/tmp/kivy-player-watchdog.log"
fi
# Function to log messages (MUST be defined before use)
log_message() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $1"
echo "$msg"
# Try to write to log file, ignore errors if permission denied
echo "$msg" >> "$LOG_FILE" 2>/dev/null || true
}
# Load user's environment from systemd user session (most reliable method)
# This ensures we get the proper DISPLAY/WAYLAND_DISPLAY and session variables
load_user_environment() {
# Try to get environment from active user session via systemctl
local user_env
if command -v systemctl &>/dev/null; then
user_env=$(systemctl --user show-environment 2>/dev/null)
if [ -n "$user_env" ]; then
# Extract display-related variables
echo "$user_env" | grep -E '^(DISPLAY|WAYLAND_DISPLAY|XDG_RUNTIME_DIR|DBUS_SESSION_BUS_ADDRESS)=' | while read -r line; do
export "$line"
done
log_message "Loaded user environment from systemctl --user"
return 0
fi
fi
# Fallback: detect display manually
log_message "Falling back to manual display detection..."
if [ -z "$DISPLAY" ] && [ -z "$WAYLAND_DISPLAY" ]; then
# Try to detect Wayland display
if [ -S "/run/user/$(id -u)/wayland-0" ]; then
export WAYLAND_DISPLAY=wayland-0
log_message "Detected Wayland display: $WAYLAND_DISPLAY"
# Try to detect X11 display
elif [ -S "/tmp/.X11-unix/X0" ]; then
export DISPLAY=:0
log_message "Detected X11 display: $DISPLAY"
else
# Wait for display to come up (useful for systemd or delayed starts)
log_message "Waiting for display server to be ready (up to 30 seconds)..."
for i in {1..30}; do
sleep 1
if [ -S "/run/user/$(id -u)/wayland-0" ] 2>/dev/null; then
export WAYLAND_DISPLAY=wayland-0
log_message "Display server detected on attempt $i: Wayland"
return 0
elif [ -S "/tmp/.X11-unix/X0" ] 2>/dev/null; then
export DISPLAY=:0
log_message "Display server detected on attempt $i: X11"
return 0
fi
done
fi
fi
# Verify we have a display now
if [ -z "$DISPLAY" ] && [ -z "$WAYLAND_DISPLAY" ]; then
log_message "WARNING: No display server detected. This may cause graphics issues."
return 1
fi
log_message "Display environment ready: DISPLAY=$DISPLAY WAYLAND_DISPLAY=$WAYLAND_DISPLAY"
return 0
}
# Load the user environment early
load_user_environment
# Function to check if player is healthy
check_health() {
# Check if heartbeat file exists and is recent (within last 60 seconds)
if [ -f "$HEARTBEAT_FILE" ]; then
local last_update=$(stat -c %Y "$HEARTBEAT_FILE" 2>/dev/null || echo 0)
local current_time=$(date +%s)
local diff=$((current_time - last_update))
if [ $diff -lt 60 ]; then
return 0 # Healthy
else
log_message "⚠️ Player heartbeat stale (${diff}s old)"
return 1 # Unhealthy
fi
else
# If heartbeat file doesn't exist yet, assume player is starting
return 0
fi
}
# Cleanup function
cleanup() {
log_message "🛑 Watchdog received stop signal"
rm -f "$HEARTBEAT_FILE"
rm -f "$STOP_FLAG_FILE"
exit 0
}
# Trap signals for graceful shutdown
trap cleanup SIGINT SIGTERM
log_message "=========================================="
log_message "🚀 Kivy Signage Player Watchdog Started"
log_message "=========================================="
log_message "Project directory: $SCRIPT_DIR"
log_message "Max retries: Unlimited"
log_message "Restart delay: ${RESTART_DELAY}s"
log_message ""
# Remove old stop flag if exists (fresh start)
rm -f "$STOP_FLAG_FILE"
# Change to the project directory
cd "$SCRIPT_DIR"
# Check if virtual environment exists
if [ -d ".venv" ]; then
log_message "✓ Virtual environment found"
source .venv/bin/activate
else
log_message "⚠️ Creating virtual environment..."
python3 -m venv .venv
source .venv/bin/activate
log_message "📦 Installing dependencies..."
pip3 install -r requirements.txt
log_message "✓ Virtual environment ready"
fi
# Check if configuration exists
if [ ! -f "config/app_config.json" ]; then
log_message "⚠️ WARNING: Configuration file not found!"
log_message "Player may not function correctly without configuration"
fi
# Main watchdog loop
retry_count=0
while true; do
retry_count=$((retry_count + 1))
log_message ""
log_message "=========================================="
log_message "▶️ Starting player (attempt #${retry_count})"
log_message "=========================================="
# Clean old heartbeat
rm -f "$HEARTBEAT_FILE"
# Start the player
cd "$SCRIPT_DIR/src"
python3 main.py &
PLAYER_PID=$!
log_message "Player PID: $PLAYER_PID"
# Monitor the player
while true; do
sleep $HEALTH_CHECK_INTERVAL
# Check if process is still running
if ! kill -0 $PLAYER_PID 2>/dev/null; then
log_message "❌ Player process crashed or stopped (PID: $PLAYER_PID)"
break
fi
# Check health via heartbeat
if ! check_health; then
log_message "❌ Player health check failed - may be frozen"
kill $PLAYER_PID 2>/dev/null
sleep 2
kill -9 $PLAYER_PID 2>/dev/null
break
fi
# Player is healthy, continue monitoring
done
# Player stopped or crashed
# Check if user requested intentional exit
if [ -f "$STOP_FLAG_FILE" ]; then
log_message "✋ Stop flag detected - user requested exit via password"
log_message "Watchdog will NOT restart the player"
log_message "To restart, run ./start.sh again"
rm -f "$HEARTBEAT_FILE"
break
fi
log_message "⏳ Waiting ${RESTART_DELAY}s before restart..."
sleep $RESTART_DELAY
# Cleanup any zombie processes
pkill -9 -f "python3 main.py" 2>/dev/null
done
log_message ""
log_message "=========================================="
log_message "Watchdog stopped"
log_message "=========================================="
# Deactivate virtual environment (this line is never reached in watchdog mode)
deactivate