diff --git a/install.sh b/install.sh index c62c3c0..8b46e73 100644 --- a/install.sh +++ b/install.sh @@ -5,15 +5,37 @@ set -e +# Cleanup handler for Ctrl+C / unexpected exit +cleanup() { + echo "" + echo "⚠️ Installation interrupted. Cleaning up..." + # Nothing critical to clean, but inform the user + echo "If the script was modifying system files, you may need to re-run." + exit 1 +} +trap cleanup SIGINT SIGTERM + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_DIR="$SCRIPT_DIR/repo" WHEELS_DIR="$REPO_DIR/python-wheels" SYSTEM_DIR="$REPO_DIR/system-packages" DEB_DIR="$SYSTEM_DIR/debs" +# Helper to find the correct boot config file (Raspberry Pi) +find_boot_config() { + if [ -f /boot/firmware/config.txt ]; then + echo "/boot/firmware/config.txt" + elif [ -f /boot/config.txt ]; then + echo "/boot/config.txt" + else + echo "" + fi +} + # Function to detect Raspberry Pi detect_raspberry_pi() { - if grep -qi "raspberry" /proc/cpuinfo 2>/dev/null || [ -f /boot/config.txt ]; then + BOOT_CONFIG=$(find_boot_config) + if grep -qi "raspberry" /proc/cpuinfo 2>/dev/null || [ -n "$BOOT_CONFIG" ]; then return 0 # Is Raspberry Pi else return 1 # Not Raspberry Pi @@ -118,14 +140,13 @@ EOF echo "" echo "Autostart configuration methods:" echo " 1. ✓ XDG Autostart Entry (~/.config/autostart/)" - echo " 2. ✓ systemd User Service (most reliable)" if [ -f "$LXDE_AUTOSTART" ]; then - echo " 3. ✓ LXDE Autostart" + echo " 2. ✓ LXDE Autostart" fi - echo " 4. ✓ Cron Fallback (@reboot)" + echo " 3. ✓ Cron Fallback (@reboot)" echo "" - echo "Status check command:" - echo " systemctl --user status kivy-signage-player.service" + echo "The player will start automatically when the desktop loads via XDG autostart." + echo "To verify: ls -la ~/.config/autostart/kivy-signage-player.desktop" echo "" } @@ -136,38 +157,43 @@ setup_raspberry_pi_power_management() { echo "Raspberry Pi Detected - Configuring Power Management" echo "==========================================" + # Determine the actual user (if running with sudo) + ACTUAL_USER="${SUDO_USER:-$(whoami)}" + ACTUAL_HOME=$(eval echo ~"$ACTUAL_USER") + # Disable HDMI power-saving echo "Disabling HDMI screen power-saving..." - if [ -f /boot/config.txt ]; then + BOOT_CONFIG=$(find_boot_config) + if [ -n "$BOOT_CONFIG" ]; then # Check if hdmi_blanking is already configured - if grep -q "hdmi_blanking" /boot/config.txt; then - sudo sed -i 's/^hdmi_blanking=.*/hdmi_blanking=0/' /boot/config.txt + if grep -q "hdmi_blanking" "$BOOT_CONFIG"; then + sudo sed -i 's/^hdmi_blanking=.*/hdmi_blanking=0/' "$BOOT_CONFIG" else - echo "hdmi_blanking=0" | sudo tee -a /boot/config.txt > /dev/null + echo "hdmi_blanking=0" | sudo tee -a "$BOOT_CONFIG" > /dev/null fi # Disable HDMI CEC (can interfere with power management) - if grep -q "hdmi_ignore_cec_init" /boot/config.txt; then - sudo sed -i 's/^hdmi_ignore_cec_init=.*/hdmi_ignore_cec_init=1/' /boot/config.txt + if grep -q "hdmi_ignore_cec_init" "$BOOT_CONFIG"; then + sudo sed -i 's/^hdmi_ignore_cec_init=.*/hdmi_ignore_cec_init=1/' "$BOOT_CONFIG" else - echo "hdmi_ignore_cec_init=1" | sudo tee -a /boot/config.txt > /dev/null + echo "hdmi_ignore_cec_init=1" | sudo tee -a "$BOOT_CONFIG" > /dev/null fi # Force HDMI mode to always be on - if grep -q "hdmi_force_hotplug" /boot/config.txt; then - sudo sed -i 's/^hdmi_force_hotplug=.*/hdmi_force_hotplug=1/' /boot/config.txt + if grep -q "hdmi_force_hotplug" "$BOOT_CONFIG"; then + sudo sed -i 's/^hdmi_force_hotplug=.*/hdmi_force_hotplug=1/' "$BOOT_CONFIG" else - echo "hdmi_force_hotplug=1" | sudo tee -a /boot/config.txt > /dev/null + echo "hdmi_force_hotplug=1" | sudo tee -a "$BOOT_CONFIG" > /dev/null fi # Disable HDMI sleep mode - if grep -q "hdmi_ignore_edid" /boot/config.txt; then - sudo sed -i 's/^hdmi_ignore_edid=.*/hdmi_ignore_edid=0xa5000080/' /boot/config.txt + if grep -q "hdmi_ignore_edid" "$BOOT_CONFIG"; then + sudo sed -i 's/^hdmi_ignore_edid=.*/hdmi_ignore_edid=0xa5000080/' "$BOOT_CONFIG" else - echo "hdmi_ignore_edid=0xa5000080" | sudo tee -a /boot/config.txt > /dev/null + echo "hdmi_ignore_edid=0xa5000080" | sudo tee -a "$BOOT_CONFIG" > /dev/null fi - echo "✓ HDMI configuration locked in /boot/config.txt" + echo "✓ HDMI configuration locked in $BOOT_CONFIG" echo " - HDMI blanking disabled" echo " - HDMI CEC disabled" echo " - HDMI hotplug forced" @@ -230,8 +256,8 @@ EOF # Disable screensaver via xset (if X11 is running) if command -v xset &> /dev/null; then # Create .xinitrc if it doesn't exist to disable screensaver - if [ ! -f ~/.xinitrc ]; then - cat >> ~/.xinitrc << 'EOF' + if [ ! -f "$ACTUAL_HOME/.xinitrc" ]; then + cat >> "$ACTUAL_HOME/.xinitrc" << 'EOF' # Disable screen blanking and screensaver xset s off xset -dpms @@ -239,8 +265,8 @@ xset s noblank EOF else # Update existing .xinitrc if needed - if ! grep -q "xset s off" ~/.xinitrc; then - cat >> ~/.xinitrc << 'EOF' + if ! grep -q "xset s off" "$ACTUAL_HOME/.xinitrc"; then + cat >> "$ACTUAL_HOME/.xinitrc" << 'EOF' # Disable screen blanking and screensaver xset s off @@ -249,7 +275,8 @@ xset s noblank EOF fi fi - echo "✓ X11 screensaver disabled in .xinitrc" + chown "$ACTUAL_USER:$ACTUAL_USER" "$ACTUAL_HOME/.xinitrc" 2>/dev/null || true + echo "✓ X11 screensaver disabled in $ACTUAL_HOME/.xinitrc" fi # Create screen keep-alive wrapper script @@ -316,6 +343,7 @@ EOF echo "✓ Screen keep-alive service created" # Create systemd service to keep HDMI powered on + # Note: Using 5-minute interval to avoid flickering on some displays echo "Creating HDMI power control service..." sudo tee /etc/systemd/system/hdmi-poweron.service > /dev/null << 'EOF' [Unit] @@ -324,9 +352,9 @@ After=multi-user.target display-manager.service [Service] Type=simple -ExecStart=/bin/bash -c 'while true; do /usr/bin/tvservice -p 2>/dev/null; sleep 30; done' +ExecStart=/bin/bash -c 'while true; do /usr/bin/tvservice -p 2>/dev/null; sleep 300; done' Restart=always -RestartSec=5 +RestartSec=10 [Install] WantedBy=multi-user.target @@ -427,27 +455,17 @@ EOF # Install Wayland tools if using Wayland echo "Checking for Wayland and installing necessary tools..." - if [ -n "$WAYLAND_DISPLAY" ] || pgrep -x "wayfire\|sway\|weston\|mutter" > /dev/null; then + if [ -n "$WAYLAND_DISPLAY" ] || pgrep -x "wayfire\|sway\|weston\|mutter" > /dev/null 2>/dev/null; then echo "Wayland detected - installing Wayland power management tools..." - # Install wlopm for Wayland output power management - if ! command -v wlopm &> /dev/null; then - echo "Installing wlopm..." - # wlopm might need to be compiled from source or installed via package manager - sudo apt-get install -y wlopm 2>/dev/null || echo "Note: wlopm not available in package manager" - fi - - # Install wlr-randr for wlroots compositors - if ! command -v wlr-randr &> /dev/null; then - echo "Installing wlr-randr..." - sudo apt-get install -y wlr-randr 2>/dev/null || echo "Note: wlr-randr not available" - fi - - # Install ydotool (Wayland's xdotool alternative) - if ! command -v ydotool &> /dev/null; then - echo "Installing ydotool..." - sudo apt-get install -y ydotool 2>/dev/null || echo "Note: ydotool not available" - fi + # List of optional Wayland tools (best-effort install) + WAYLAND_TOOLS="wlopm wlr-randr ydotool" + for tool in $WAYLAND_TOOLS; do + if ! command -v "$tool" &> /dev/null; then + echo "Installing $tool (if available)..." + sudo apt-get install -y "$tool" 2>/dev/null || echo "Note: $tool not available in package manager - skipping" + fi + done echo "✓ Wayland tools installation attempted" else @@ -485,21 +503,405 @@ EOF } -# Check for offline mode +# ============================================================ +# Config & Deployment Functions +# ============================================================ + +# Function to write player configuration from CLI parameters +write_player_config() { + local config_dir="$SCRIPT_DIR/config" + local config_file="$config_dir/app_config.json" + + echo "" + echo "==========================================" + echo "Configuring Player Settings" + echo "==========================================" + + mkdir -p "$config_dir" + + # If --provision was given, fetch config from server + if [ -n "$PROVISION_URL" ]; then + echo "Fetching provisioning data from: $PROVISION_URL" + local response + response=$(curl -sSf "$PROVISION_URL" 2>&1 || true) + if [ -z "$response" ]; then + echo "⚠️ WARNING: Failed to fetch provisioning data from $PROVISION_URL" + echo " The player will start with setup screen on first boot." + echo " You can configure it manually via the touchscreen UI." + return 0 + fi + + # Write fetched config + echo "$response" > "$config_file" + echo "✓ Provisioning data saved to $config_file" + + # Extract key fields from response for display + local fetched_name + fetched_name=$(echo "$response" | python3 -c "import sys,json; print(json.load(sys.stdin).get('screen_name',''))" 2>/dev/null || echo "unknown") + echo " Provisioned screen: $fetched_name" + return 0 + fi + + # If --config was given, copy from file + if [ -n "$CONFIG_FILE_PATH" ]; then + if [ -f "$CONFIG_FILE_PATH" ]; then + cp "$CONFIG_FILE_PATH" "$config_file" + echo "✓ Configuration copied from $CONFIG_FILE_PATH" + return 0 + else + echo "⚠️ WARNING: Config file not found: $CONFIG_FILE_PATH" + fi + fi + + # Build config from individual CLI params if any were provided + if [ -n "$SERVER_IP" ] || [ -n "$SCREEN_NAME" ] || [ -n "$QUICKCONNECT_KEY" ]; then + # Export vars so Python subprocess can read them safely + export SERVER_IP SERVER_PORT SCREEN_NAME QUICKCONNECT_KEY + export ORIENTATION TOUCH_ENABLED MAX_RESOLUTION + export USE_HTTPS VERIFY_SSL EDIT_ENABLED + + # Use Python to merge existing config with CLI params (avoids bash quoting issues) + python3 << PYEOF +import json, os + +config_file = "$config_file" + +# Load existing config or start fresh +if os.path.exists(config_file): + with open(config_file) as f: + config = json.load(f) +else: + config = {} + +# CLI parameter values (passed via environment for safety) +cli_params = { + 'server_ip': os.environ.get('SERVER_IP', ''), + 'port': os.environ.get('SERVER_PORT', ''), + 'screen_name': os.environ.get('SCREEN_NAME', ''), + 'quickconnect_key': os.environ.get('QUICKCONNECT_KEY', ''), + 'orientation': os.environ.get('ORIENTATION', ''), + 'touch': os.environ.get('TOUCH_ENABLED', ''), + 'max_resolution': os.environ.get('MAX_RESOLUTION', ''), +} + +# Boolean flags need special handling +https_val = os.environ.get('USE_HTTPS', '') +verify_val = os.environ.get('VERIFY_SSL', '') +edit_val = os.environ.get('EDIT_ENABLED', '') + +for key, val in cli_params.items(): + if val: # Only override if a value was provided + config[key] = val + +# Handle boolean fields +if https_val: + config['use_https'] = https_val.lower() == 'true' +if verify_val: + config['verify_ssl'] = verify_val.lower() == 'false' # --no-verify-ssl sets to "false" +if edit_val: + config['edit_feature_enabled'] = edit_val.lower() == 'true' + +# Ensure defaults for any missing fields +config.setdefault('port', '8080') +config.setdefault('orientation', 'Landscape') +config.setdefault('touch', 'True') +config.setdefault('max_resolution', '1920x1080') +config.setdefault('edit_feature_enabled', False) +config.setdefault('use_https', False) +config.setdefault('verify_ssl', True) + +with open(config_file, 'w') as f: + json.dump(config, f, indent=2) + +print("✓ Configuration written to " + config_file) +PYEOF + fi + + # If no config at all, create a minimal placeholder + if [ ! -f "$config_file" ]; then + cat > "$config_file" << 'EOF' +{ + "server_ip": "", + "port": "8080", + "screen_name": "", + "quickconnect_key": "", + "orientation": "Landscape", + "touch": "True", + "max_resolution": "1920x1080", + "edit_feature_enabled": false, + "use_https": false, + "verify_ssl": true +} +EOF + echo "✓ Default config template created — please configure via touchscreen UI" + fi +} + +# Function to create required player directories +setup_player_directories() { + echo "" + echo "==========================================" + echo "Setting Up Player Directories" + echo "==========================================" + + mkdir -p "$SCRIPT_DIR/media" + mkdir -p "$SCRIPT_DIR/playlists" + mkdir -p "$SCRIPT_DIR/config/resources" + mkdir -p "$SCRIPT_DIR/logs" + + # Create a log rotation mechanism placeholder + cat > "$SCRIPT_DIR/logs/.gitkeep" 2>/dev/null || true + + echo "✓ Player directories created:" + echo " - media/ (downloaded media files)" + echo " - playlists/ (synced playlists)" + echo " - config/resources/ (resource files)" + echo " - logs/ (player log output)" +} + +# Function to initialize player authentication with Digiserver +init_player_auth() { + echo "" + echo "==========================================" + echo "Initializing Player Authentication" + echo "==========================================" + + local config_file="$SCRIPT_DIR/config/app_config.json" + + if [ ! -f "$config_file" ]; then + echo "⚠️ No config file found — skipping authentication" + echo " Authentication will happen on first player run." + return 0 + fi + + # Check if we have enough config to authenticate + local server_ip + local screen_name + local quickconnect_key + server_ip=$(python3 -c "import json; print(json.load(open('$config_file')).get('server_ip',''))" 2>/dev/null || echo "") + screen_name=$(python3 -c "import json; print(json.load(open('$config_file')).get('screen_name',''))" 2>/dev/null || echo "") + quickconnect_key=$(python3 -c "import json; print(json.load(open('$config_file')).get('quickconnect_key',''))" 2>/dev/null || echo "") + + if [ -z "$server_ip" ] || [ -z "$screen_name" ] || [ -z "$quickconnect_key" ]; then + echo "⏸️ Incomplete config (server, name, or key missing)" + echo " Authentication will happen on first player run via the UI." + return 0 + fi + + echo "Attempting to register player with Digiserver..." + echo " Server: $server_ip" + echo " Screen: $screen_name" + + # Activate venv and run auth + ( + source "$SCRIPT_DIR/.venv/bin/activate" 2>/dev/null + cd "$SCRIPT_DIR/src" + python3 -c " +import json, sys, asyncio +sys.path.insert(0, '.') +from get_playlists_v2 import ensure_authenticated + +config_file = '$config_file' +with open(config_file) as f: + config = json.load(f) + +auth = ensure_authenticated(config) +if auth: + print('✅ Player registered with server successfully') + sys.exit(0) +else: + print('⚠️ Authentication pending — will retry on player startup') + sys.exit(1) +" 2>&1 || echo "⚠️ Auth initialization deferred to first player run" + ) +} + +# Function to optimize for background execution +optimize_background_execution() { + echo "" + echo "==========================================" + echo "Optimizing Background Execution" + echo "==========================================" + + # Create a nohup wrapper that ensures the player runs in background + # even if the terminal session ends + NOHUP_WRAPPER="$SCRIPT_DIR/.run-background.sh" + cat > "$NOHUP_WRAPPER" << 'EOF' +#!/bin/bash +# Background runner for Kiwy Signage Player +# Ensures the player keeps running even after SSH logout + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LOG_FILE="$SCRIPT_DIR/logs/player-background.log" + +# Ensure log directory exists +mkdir -p "$(dirname "$LOG_FILE")" + +# Log startup +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting player in background..." >> "$LOG_FILE" + +# Source the virtual environment +cd "$SCRIPT_DIR" || exit 1 +source .venv/bin/activate 2>/dev/null + +# Use nohup to ignore HUP signals +nohup bash start.sh >> "$LOG_FILE" 2>&1 & +PLAYER_PID=$! + +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Player started with PID: $PLAYER_PID" >> "$LOG_FILE" +echo "Player started in background (PID: $PLAYER_PID)" +echo "Logs: $LOG_FILE" +EOF + + chmod +x "$NOHUP_WRAPPER" + echo "✓ Background runner created: .run-background.sh" + echo " Usage: bash .run-background.sh" + + # Also ensure the autostart .desktop file uses the venv + local autostart_file="$ACTUAL_HOME/.config/autostart/kivy-signage-player.desktop" + if [ -f "$autostart_file" ]; then + # The desktop entry already points to start.sh which handles venv + echo "✓ Autostart entry already configured for background execution" + fi + + # Create a status-check alias for convenience + echo "" + echo "Background management commands:" + echo " bash .run-background.sh Start player in background" + echo " bash check_player_status.sh Check if player is running" + echo " bash stop_player.sh Stop the player" + echo "" +} + + +# ============================================================ +# CLI Argument Parsing +# ============================================================ OFFLINE_MODE=false -if [ "$1" == "--offline" ] || [ "$1" == "-o" ]; then +SERVER_IP="" +SERVER_PORT="" +SCREEN_NAME="" +QUICKCONNECT_KEY="" +USE_HTTPS="" +VERIFY_SSL="" +ORIENTATION="" +TOUCH_ENABLED="" +MAX_RESOLUTION="" +EDIT_ENABLED="" +PROVISION_URL="" +CONFIG_FILE_PATH="" + +usage() { + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Installation modes (choose one):" + echo " --provision URL One-time provisioning URL from Digiserver (fetches all config)" + echo " --config FILE Path to pre-made JSON config file" + echo " (individual params) Set each config value manually" + echo "" + echo "Configuration options:" + echo " -s, --server IP Digiserver IP or hostname" + echo " -p, --port PORT Server port (default: 8080)" + echo " -n, --name NAME Screen/player name" + echo " -k, --key KEY Quick-connect / auth key" + echo " --https Enable HTTPS for server communication" + echo " --no-verify-ssl Disable SSL certificate verification" + echo " -o, --orientation Landscape or Portrait (default: Landscape)" + echo " --touch Enable touch input" + echo " -r, --resolution WxH Max resolution (default: 1920x1080)" + echo " --edit Enable on-device edit feature" + echo "" + echo "Installation options:" + echo " --offline Force offline installation from local packages" + echo " -q, --quiet Silent mode (minimal output)" + echo " -h, --help Show this help" + exit 0 +} + +while [ $# -gt 0 ]; do + case "$1" in + --provision) + PROVISION_URL="$2" + shift 2 + ;; + --config) + CONFIG_FILE_PATH="$2" + shift 2 + ;; + -s|--server) + SERVER_IP="$2" + shift 2 + ;; + -p|--port) + SERVER_PORT="$2" + shift 2 + ;; + -n|--name) + SCREEN_NAME="$2" + shift 2 + ;; + -k|--key) + QUICKCONNECT_KEY="$2" + shift 2 + ;; + --https) + USE_HTTPS="true" + shift + ;; + --no-verify-ssl) + VERIFY_SSL="false" + shift + ;; + -o|--orientation) + ORIENTATION="$2" + shift 2 + ;; + --touch) + TOUCH_ENABLED="True" + shift + ;; + -r|--resolution) + MAX_RESOLUTION="$2" + shift 2 + ;; + --edit) + EDIT_ENABLED="true" + shift + ;; + --offline) + OFFLINE_MODE=true + shift + ;; + -q|--quiet) + # Silent mode - redirect stdout to log file + exec > >(tee -a /tmp/kivy-install.log) 2>&1 + shift + ;; + -h|--help) + usage + ;; + *) + echo "Unknown option: $1" + usage + ;; + esac +done + +# Auto-detect offline mode if wheels exist +if [ "$OFFLINE_MODE" = false ] && [ -d "$WHEELS_DIR" ] && [ "$(ls -A "$WHEELS_DIR"/*.whl 2>/dev/null)" ]; then OFFLINE_MODE=true +fi + +# ============================================================ +# Mode Banner +# ============================================================ +if [ "$OFFLINE_MODE" = true ]; then echo "==========================================" - echo "Offline Installation Mode" + echo "📦 Offline Installation Mode" echo "==========================================" -elif [ -d "$WHEELS_DIR" ] && [ "$(ls -A $WHEELS_DIR 2>/dev/null)" ]; then - echo "==========================================" - echo "Offline packages detected - Using repo folder" - echo "==========================================" - OFFLINE_MODE=true else echo "==========================================" - echo "Online Installation Mode" + echo "🌐 Online Installation Mode" echo "==========================================" fi @@ -548,36 +950,52 @@ fi echo "" -# Install Python dependencies -echo "Step 2: Installing Python dependencies..." +# Install Python dependencies into virtual environment +echo "Step 2: Creating virtual environment and installing Python dependencies..." echo "--------------------" -if [ "$OFFLINE_MODE" = true ] && [ -d "$WHEELS_DIR" ] && [ "$(ls -A $WHEELS_DIR/*.whl 2>/dev/null)" ]; then +# Create virtual environment if it doesn't exist +if [ ! -d "$SCRIPT_DIR/.venv" ]; then + echo "Creating Python virtual environment..." + python3 -m venv "$SCRIPT_DIR/.venv" + echo "✓ Virtual environment created at .venv" +else + echo "✓ Virtual environment already exists" +fi + +# Activate the virtual environment +source "$SCRIPT_DIR/.venv/bin/activate" + +# Upgrade pip inside the virtual environment +echo "Upgrading pip..." +pip install --upgrade pip 2>/dev/null || true + +if [ "$OFFLINE_MODE" = true ] && [ -d "$WHEELS_DIR" ] && [ "$(ls -A "$WHEELS_DIR"/*.whl 2>/dev/null)" ]; then # Offline: Install from local wheels echo "Installing from offline Python wheels..." - echo "Wheel files found: $(ls -1 $WHEELS_DIR/*.whl 2>/dev/null | wc -l)" + echo "Wheel files found: $(ls -1 "$WHEELS_DIR"/*.whl 2>/dev/null | wc -l)" - if pip3 install --break-system-packages --no-index --find-links="$WHEELS_DIR" -r requirements.txt 2>&1 | tee /tmp/pip_install.log; then - echo "Python packages installed from offline repository" + if pip install --no-index --find-links="$WHEELS_DIR" -r requirements.txt 2>&1 | tee /tmp/pip_install.log; then + echo "✓ Python packages installed from offline repository" else - echo "Warning: Offline installation failed (possibly due to Python version mismatch)" + echo "⚠️ Warning: Offline installation failed (possibly due to Python version mismatch)" echo "Falling back to online installation..." - pip3 install --break-system-packages -r requirements.txt - echo "Python packages installed from PyPI" + pip install -r requirements.txt + echo "✓ Python packages installed from PyPI" fi else # Online: Use pip from PyPI - echo "Installing from PyPI..." - pip3 install --break-system-packages -r requirements.txt - - echo "Python packages installed successfully" + echo "Installing from PyPI into virtual environment..." + pip install -r requirements.txt + echo "✓ Python packages installed successfully into .venv" fi -echo "" -echo "==========================================" -echo "Installation completed successfully!" -echo "==========================================" -echo "" +# Deactivate the virtual environment (re-activate at runtime) +deactivate + +# ============================================================ +# Post-Installation Setup +# ============================================================ # Setup autostart workflow setup_autostart @@ -600,23 +1018,75 @@ if detect_raspberry_pi; then fi fi -echo "To run the signage player:" -echo " cd src && python3 main.py" +# Create required player directories +setup_player_directories + +# Write player configuration +write_player_config + +# Initialize authentication with Digiserver +init_player_auth + +# Optimize for background execution +optimize_background_execution + +# ============================================================ +# Final Summary +# ============================================================ echo "" -echo "Or use the run script:" -echo " bash run_player.sh" +echo "==========================================" +echo "✅ Kivy Signage Player — Installation Complete!" +echo "==========================================" echo "" -echo "Or start the watchdog (with auto-restart on crash):" -echo " bash start.sh" -echo "" -echo "Autostart has been configured. The player will start automatically when the desktop loads." +echo "📁 Installation directory: $SCRIPT_DIR" +echo "🐍 Virtual environment: .venv/" echo "" -# Check if config exists -if [ ! -d "$SCRIPT_DIR/config" ] || [ ! "$(ls -A $SCRIPT_DIR/config)" ]; then - echo "⚠️ Note: No configuration found." - echo "Please configure the player before running:" - echo " 1. Copy config/app_config.txt.example to config/app_config.txt" - echo " 2. Edit the configuration file with your server details" +# Read back the config to show applied settings +if [ -f "$SCRIPT_DIR/config/app_config.json" ]; then + echo "📋 Player Configuration:" + echo "------------------------" + python3 -c " +import json +with open('$SCRIPT_DIR/config/app_config.json') as f: + c = json.load(f) +print(f' Server: {c.get(\"server_ip\",\"not set\")}') +print(f' Port: {c.get(\"port\",\"8080\")}') +print(f' Screen: {c.get(\"screen_name\",\"not set\")}') +print(f' HTTPS: {c.get(\"use_https\",False)}') +print(f' Resolution: {c.get(\"max_resolution\",\"auto\")}') +" 2>/dev/null || echo " (config present)" echo "" fi + +echo "🚀 Quick Start Commands:" +echo "------------------------" +echo " bash start.sh Start with watchdog (auto-restart)" +echo " bash run_player.sh Run once (no auto-restart)" +echo " bash .run-background.sh Run in background (survives SSH logout)" +echo " bash check_player_status.sh Check if player is running" +echo " bash stop_player.sh Stop the player" +echo "" +echo "🔄 Autostart: The player will launch automatically on next desktop login." +echo "" +echo "📝 Logs: $SCRIPT_DIR/logs/" +echo "" + +# ============================================================ +# Reboot Prompt +# ============================================================ +echo "" +echo "==========================================" +echo "🔄 System Reboot Required" +echo "==========================================" +echo "" +echo "Autostart and power-saving settings are configured." +echo "A reboot is required to apply all changes." +echo "" + +# Auto-reboot with 5-second window to cancel +echo "" +echo "🔄 Rebooting in 5 seconds... Press Ctrl+C to cancel." +sleep 5 +echo "Rebooting now..." +sudo reboot diff --git a/requirements.txt b/requirements.txt index f1d6cf6..a3d47d2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,6 @@ kivy>=2.3.0 ffpyplayer -requests==2.32.4 -bcrypt==4.2.1 -aiohttp==3.9.1 -asyncio==3.4.3 +requests>=2.32.0,<3.0.0 +bcrypt>=4.2.0,<5.0.0 +aiohttp>=3.9.0,<4.0.0 evdev>=1.6.0 \ No newline at end of file diff --git a/start.sh b/start.sh index 2c75697..34b7b6b 100755 --- a/start.sh +++ b/start.sh @@ -292,8 +292,8 @@ while true; do log_message "⏳ Waiting ${RESTART_DELAY}s before restart..." sleep $RESTART_DELAY - # Cleanup any zombie processes - pkill -9 -f "python3 main.py" 2>/dev/null + # Ensure old player process is gone before restarting + kill -9 $PLAYER_PID 2>/dev/null done @@ -301,6 +301,3 @@ log_message "" log_message "==========================================" log_message "Watchdog stopped" log_message "==========================================" - -# Deactivate virtual environment (this line is never reached in watchdog mode) -deactivate