#!/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" # Function to log messages log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" } # 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