#!/bin/bash # Kivy Signage Player Installation Script # Supports both online and offline installation set -e 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" # Function to detect Raspberry Pi detect_raspberry_pi() { if grep -qi "raspberry" /proc/cpuinfo 2>/dev/null || [ -f /boot/config.txt ]; then return 0 # Is Raspberry Pi else return 1 # Not Raspberry Pi fi } # Function to setup autostart workflow setup_autostart() { echo "" echo "==========================================" echo "Setting up Autostart Workflow" echo "==========================================" # Determine the actual user (if running with sudo) ACTUAL_USER="${SUDO_USER:-$(whoami)}" ACTUAL_HOME=$(eval echo ~"$ACTUAL_USER") AUTOSTART_DIR="$ACTUAL_HOME/.config/autostart" SYSTEMD_DIR="$ACTUAL_HOME/.config/systemd/user" LXDE_AUTOSTART="$ACTUAL_HOME/.config/lxsession/LXDE-pi/autostart" # Method 1: XDG Autostart (works with most desktop environments) echo "Creating XDG autostart entry..." mkdir -p "$AUTOSTART_DIR" cat > "$AUTOSTART_DIR/kivy-signage-player.desktop" << 'EOF' [Desktop Entry] Type=Application Name=Kivy Signage Player Comment=Digital Signage Player Exec=bash -c "cd $SCRIPT_DIR && bash start.sh" Icon=media-video-display Categories=Utility; NoDisplay=false Terminal=true StartupNotify=false Hidden=false EOF # Replace $SCRIPT_DIR with actual path in the file sed -i "s|\$SCRIPT_DIR|$SCRIPT_DIR|g" "$AUTOSTART_DIR/kivy-signage-player.desktop" chown "$ACTUAL_USER:$ACTUAL_USER" "$AUTOSTART_DIR/kivy-signage-player.desktop" chmod +x "$AUTOSTART_DIR/kivy-signage-player.desktop" echo "✓ XDG autostart entry created for user: $ACTUAL_USER" # Method 2: LXDE Autostart (for Raspberry Pi OS with LXDE) if [ -f "$LXDE_AUTOSTART" ]; then echo "Configuring LXDE autostart..." if ! grep -q "kivy-signage-player" "$LXDE_AUTOSTART"; then echo "" >> "$LXDE_AUTOSTART" echo "# Kivy Signage Player autostart" >> "$LXDE_AUTOSTART" echo "@bash -c 'cd $SCRIPT_DIR && bash start.sh'" >> "$LXDE_AUTOSTART" chown "$ACTUAL_USER:$ACTUAL_USER" "$LXDE_AUTOSTART" echo "✓ Added to LXDE autostart" fi fi # Method 3: systemd user service (more reliable) echo "Creating systemd user service..." mkdir -p "$SYSTEMD_DIR" cat > "$SYSTEMD_DIR/kivy-signage-player.service" << EOF [Unit] Description=Kivy Signage Player After=graphical-session-started.target PartOf=graphical-session.target [Service] Type=simple ExecStart=/usr/bin/bash -c 'source $SCRIPT_DIR/.venv/bin/activate && cd $SCRIPT_DIR && bash start.sh' Restart=on-failure RestartSec=10 Environment="DISPLAY=:0" Environment="XAUTHORITY=%h/.Xauthority" StandardOutput=journal StandardError=journal [Install] WantedBy=graphical-session.target EOF chown "$ACTUAL_USER:$ACTUAL_USER" "$SYSTEMD_DIR/kivy-signage-player.service" chmod 644 "$SYSTEMD_DIR/kivy-signage-player.service" # Reload and enable the service as the actual user su - "$ACTUAL_USER" -c "systemctl --user daemon-reload" 2>/dev/null || true su - "$ACTUAL_USER" -c "systemctl --user enable kivy-signage-player.service" 2>/dev/null || true echo "✓ systemd user service created and enabled" # Method 4: Cron job for fallback (starts at reboot) echo "Setting up cron fallback..." # Create a wrapper script that waits for desktop to be ready CRON_WRAPPER="$SCRIPT_DIR/.start-player-cron.sh" cat > "$CRON_WRAPPER" << 'EOF' #!/bin/bash # Wait for desktop environment to be ready sleep 10 # Start the player cd "$SCRIPT_DIR" && bash start.sh EOF sed -i "s|\$SCRIPT_DIR|$SCRIPT_DIR|g" "$CRON_WRAPPER" chmod +x "$CRON_WRAPPER" # Add to crontab for the actual user if ! su - "$ACTUAL_USER" -c "crontab -l 2>/dev/null" | grep -q "kivy-signage-player"; then su - "$ACTUAL_USER" -c "(crontab -l 2>/dev/null || true; echo '@reboot $CRON_WRAPPER') | crontab -" 2>/dev/null || true echo "✓ Cron fallback configured" fi 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" fi echo " 4. ✓ Cron Fallback (@reboot)" echo "" } # Function to disable power-saving mode on Raspberry Pi setup_raspberry_pi_power_management() { echo "" echo "==========================================" echo "Raspberry Pi Detected - Configuring Power Management" echo "==========================================" # Disable HDMI power-saving echo "Disabling HDMI screen power-saving..." if [ -f /boot/config.txt ]; 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 else echo "hdmi_blanking=0" | sudo tee -a /boot/config.txt > /dev/null fi echo "✓ HDMI screen blanking disabled" fi # Disable screensaver and screen blanking in X11 echo "Configuring display blanking settings..." # Create/update display configuration in home directory XORG_DIR="/etc/X11/xorg.conf.d" if [ -d "$XORG_DIR" ]; then # Create display power management configuration sudo tee "$XORG_DIR/99-no-blanking.conf" > /dev/null << 'EOF' Section "ServerFlags" Option "BlankTime" "0" Option "StandbyTime" "0" Option "SuspendTime" "0" Option "OffTime" "0" EndSection Section "InputClass" Identifier "Disable DPMS" MatchClass "DPMS" Option "DPMS" "false" EndSection EOF echo "✓ X11 display blanking disabled" fi # Disable CPU power scaling (keep at max performance) echo "Configuring CPU power management..." # Create systemd service to keep CPU at max frequency sudo tee /etc/systemd/system/disable-cpu-powersave.service > /dev/null << 'EOF' [Unit] Description=Disable CPU Power Saving for Signage Player After=network.target [Service] Type=oneshot ExecStart=/usr/bin/bash -c 'for cpu in /sys/devices/system/cpu/cpu[0-9]*; do echo performance > "$cpu/cpufreq/scaling_governor" 2>/dev/null; done' RemainAfterExit=yes [Install] WantedBy=multi-user.target EOF # Enable and start the service sudo systemctl daemon-reload sudo systemctl enable disable-cpu-powersave.service sudo systemctl start disable-cpu-powersave.service echo "✓ CPU power saving disabled (performance mode enabled)" # Disable sleep/suspend echo "Disabling system sleep and suspend..." sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target 2>/dev/null || true echo "✓ System sleep/suspend disabled" # 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' # Disable screen blanking and screensaver xset s off xset -dpms xset s noblank EOF else # Update existing .xinitrc if needed if ! grep -q "xset s off" ~/.xinitrc; then cat >> ~/.xinitrc << 'EOF' # Disable screen blanking and screensaver xset s off xset -dpms xset s noblank EOF fi fi echo "✓ X11 screensaver disabled in .xinitrc" fi # Create screen keep-alive wrapper script echo "Creating screen keep-alive service..." KEEPALIVE_SCRIPT="$SCRIPT_DIR/.keep-screen-alive.sh" cat > "$KEEPALIVE_SCRIPT" << 'EOF' #!/bin/bash # Keep-screen-alive wrapper for player # Prevents screen from locking/turning off while player is running SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Function to keep screen awake keep_screen_awake() { while true; do # Move mouse slightly to prevent idle if command -v xdotool &> /dev/null; then xdotool mousemove_relative 1 1 xdotool mousemove_relative -1 -1 fi # Disable DPMS and screensaver periodically if command -v xset &> /dev/null; then xset s reset xset dpms force on fi sleep 30 done } # Function to inhibit systemd sleep (if available) inhibit_sleep() { if command -v systemd-inhibit &> /dev/null; then # Run player under systemd inhibit to prevent sleep systemd-inhibit --what=sleep --why="Signage player running" \ bash "$SCRIPT_DIR/start.sh" return $? fi return 1 } # Try systemd inhibit first (most reliable) if inhibit_sleep; then exit 0 fi # Fallback: Start keep-alive in background keep_screen_awake & KEEPALIVE_PID=$! # Start the player cd "$SCRIPT_DIR" bash start.sh PLAYER_EXIT=$? # Kill keep-alive when player exits kill $KEEPALIVE_PID 2>/dev/null || true exit $PLAYER_EXIT EOF chmod +x "$KEEPALIVE_SCRIPT" echo "✓ Screen keep-alive service created" # Create systemd service to run keep-alive service sudo tee /etc/systemd/system/screen-keepalive.service > /dev/null << EOF [Unit] Description=Keep Screen Awake During Signage Player After=display-manager.service PartOf=graphical-session.target [Service] Type=simple ExecStart=/bin/bash -c 'while true; do xset s reset 2>/dev/null; sleep 30; done' Restart=always RestartSec=5 [Install] WantedBy=graphical-session.target EOF sudo systemctl daemon-reload sudo systemctl enable screen-keepalive.service echo "✓ Systemd screen keep-alive service enabled" echo "" echo "⚠️ Note: Some changes require a system reboot to take effect." echo "Please rerun this script after rebooting if power management issues persist." echo "" } # Check for offline mode OFFLINE_MODE=false if [ "$1" == "--offline" ] || [ "$1" == "-o" ]; then OFFLINE_MODE=true echo "==========================================" 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 "==========================================" fi echo "" echo "Installing Kivy Signage Player dependencies..." echo "" # Install system dependencies echo "Step 1: Installing system dependencies..." echo "--------------------" if [ "$OFFLINE_MODE" = true ] && [ -d "$DEB_DIR" ] && [ "$(ls -A $DEB_DIR/*.deb 2>/dev/null)" ]; then # Offline: Install from local .deb files echo "Installing from offline .deb packages..." cd "$DEB_DIR" # Install all .deb files with dependencies sudo dpkg -i *.deb 2>/dev/null || true # Fix any broken dependencies sudo apt-get install -f -y || true echo "System packages installed from offline repository" else # Online: Use apt-get echo "Updating package lists..." sudo apt update echo "Installing system packages..." # Read packages from file if available, otherwise use default list if [ -f "$SYSTEM_DIR/apt-packages.txt" ]; then PACKAGES=$(grep -v '^#' "$SYSTEM_DIR/apt-packages.txt" | grep -v '^$' | tr '\n' ' ') sudo apt install -y $PACKAGES else # Default package list sudo apt install -y python3-pip python3-setuptools python3-dev sudo apt install -y libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev sudo apt install -y libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev sudo apt install -y zlib1g-dev ffmpeg libavcodec-extra sudo apt install -y gstreamer1.0-plugins-base gstreamer1.0-plugins-good fi echo "System packages installed successfully" fi echo "" # Install Python dependencies echo "Step 2: Installing Python dependencies..." echo "--------------------" 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)" 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" else 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" fi else # Online: Use pip from PyPI echo "Installing from PyPI..." pip3 install --break-system-packages -r requirements.txt echo "Python packages installed successfully" fi echo "" echo "==========================================" echo "Installation completed successfully!" echo "==========================================" echo "" # Setup autostart workflow setup_autostart # Check if running on Raspberry Pi and setup power management if detect_raspberry_pi; then setup_raspberry_pi_power_management fi echo "To run the signage player:" echo " cd src && python3 main.py" echo "" echo "Or use the run script:" echo " bash run_player.sh" 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 "" # 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" echo "" fi