diff --git a/.player_heartbeat b/.player_heartbeat deleted file mode 100644 index 0ad10fa..0000000 --- a/.player_heartbeat +++ /dev/null @@ -1 +0,0 @@ -1782752485.750587 \ No newline at end of file diff --git a/.player_stop_requested b/.player_stop_requested new file mode 100644 index 0000000..bb64142 --- /dev/null +++ b/.player_stop_requested @@ -0,0 +1 @@ +User requested exit via password \ No newline at end of file diff --git a/.run-background.sh b/.run-background.sh new file mode 100755 index 0000000..9abf796 --- /dev/null +++ b/.run-background.sh @@ -0,0 +1,11 @@ +#\!/bin/bash +SCRIPT_DIR="/home/pi/kiwy-signage" +LOG_FILE="/home/pi/kiwy-signage/logs/player-background.log" +mkdir -p "." +echo "[2026-07-17 10:18:24] Starting player in background..." >> "" +cd "/home/pi/kiwy-signage" || exit 1 +nohup bash start.sh >> "" 2>&1 & +PLAYER_PID=$\! +echo "[2026-07-17 10:18:24] Player started with PID: $PLAYER_PID" >> "" +echo "Player started in background (PID: $PLAYER_PID)" +echo "Logs: $LOG_FILE" diff --git a/.start-player-cron.sh b/.start-player-cron.sh index 0060d02..0fa7745 100755 --- a/.start-player-cron.sh +++ b/.start-player-cron.sh @@ -1,6 +1,3 @@ -#!/bin/bash -# Wait for desktop environment to be ready +#\!/bin/bash sleep 15 - -# Start the player -cd "/home/pi/Desktop/Kiwy-Signage" && bash start.sh +cd /home/pi/kiwy-signage && bash start.sh diff --git a/config/app_config.json b/config/app_config.json index 7ede3d8..d556c16 100644 --- a/config/app_config.json +++ b/config/app_config.json @@ -1,7 +1,7 @@ { - "server_ip": "192.168.0.159", - "port": "8080", - "screen_name": "rpi-Receptie", + "server_ip": "192.168.0.152", + "port": "80", + "screen_name": "rasppberry", "quickconnect_key": "8887779", "orientation": "Landscape", "touch": "True", diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 index 8b46e73..4e9aaa6 --- a/install.sh +++ b/install.sh @@ -1,27 +1,62 @@ -#!/bin/bash +#\!/bin/bash # Kivy Signage Player Installation Script -# Supports both online and offline installation +# Supports both online and offline installation using a Python virtual environment +# +# Usage: +# bash install.sh [OPTIONS] +# +# Options: +# -U, --sudo-user USER Username for sudo (avoids password prompts) +# -W, --sudo-password PASS Password for sudo (use with caution) +# --offline Force offline installation from local packages +# -q, --quiet Silent mode +# -h, --help Show help +# +# Configuration options (for Digiserver): +# -s, --server IP Server IP/hostname +# -p, --port PORT Server port (default: 8080) +# -n, --name NAME Screen/player name +# -k, --key KEY Quick-connect / auth key +# --https Enable HTTPS +# --no-verify-ssl Disable SSL verification +# -o, --orientation Landscape or Portrait +# --touch Enable touch input +# -r, --resolution WxH Max resolution +# --edit Enable on-device edit feature +# --provision URL One-time provisioning URL +# --config FILE Path to pre-made JSON config 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 - +# ============================================================ +# Configuration +# ============================================================ 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" +VENV_DIR="$SCRIPT_DIR/.venv" +REQUIREMENTS_FILE="$SCRIPT_DIR/requirements.txt" +SUDO_USERNAME="" +SUDO_PASSWORD="" +OFFLINE_MODE=false -# Helper to find the correct boot config file (Raspberry Pi) +# ============================================================ +# Helper: Run sudo with optional password +# ============================================================ +run_sudo() { + if [ -n "$SUDO_PASSWORD" ]; then + echo "$SUDO_PASSWORD" | sudo -S "$@" 2>/dev/null + else + sudo "$@" + fi +} + +# ============================================================ +# Helpers +# ============================================================ find_boot_config() { if [ -f /boot/firmware/config.txt ]; then echo "/boot/firmware/config.txt" @@ -32,752 +67,18 @@ find_boot_config() { fi } -# Function to detect Raspberry Pi detect_raspberry_pi() { 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 - 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 (Primary - works with Wayland/GNOME/KDE) - echo "Creating XDG autostart entry for Wayland..." - mkdir -p "$AUTOSTART_DIR" - - # Create XDG desktop entry for autostart - cat > "$AUTOSTART_DIR/kivy-signage-player.desktop" << 'EOF' -[Desktop Entry] -Type=Application -Name=Kivy Signage Player -Comment=Digital Signage Player -Exec=/bin/bash -c "cd $SCRIPT_DIR && exec bash start.sh" -Icon=media-video-display -Categories=Utility; -NoDisplay=false -Terminal=false -StartupNotify=false -Hidden=false -X-GNOME-Autostart-enabled=true -X-GNOME-Autostart-delay=3 -X-XFCE-Autostart-Override=true -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 644 "$AUTOSTART_DIR/kivy-signage-player.desktop" - echo "✓ XDG autostart entry created for Wayland session" - - # Also create Wayland session directory entry (for GNOME/Wayland) - WAYLAND_AUTOSTART_DIR="$ACTUAL_HOME/.config/autostart.gnome" - mkdir -p "$WAYLAND_AUTOSTART_DIR" - cp "$AUTOSTART_DIR/kivy-signage-player.desktop" "$WAYLAND_AUTOSTART_DIR/kivy-signage-player.desktop" - chown "$ACTUAL_USER:$ACTUAL_USER" "$WAYLAND_AUTOSTART_DIR/kivy-signage-player.desktop" - echo "✓ XDG autostart also added to GNOME/Wayland session directory" - - # 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: Disable systemd service (prefer Wayland session management) - # XDG autostart above is sufficient for Wayland/GNOME sessions - echo "Note: Using Wayland session autostart via XDG instead of systemd service" - - # If systemd service exists from previous installation, disable it - if sudo test -f /etc/systemd/system/kiwy-player.service 2>/dev/null; then - echo "Disabling old systemd service in favor of Wayland session..." - sudo systemctl disable kiwy-player.service 2>/dev/null || true - echo "✓ Old systemd service disabled" - fi - - # 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 15 - -# 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 - CRON_ENTRY="@reboot sleep 20 && $CRON_WRAPPER > /tmp/kivy-player-cron.log 2>&1" - 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 '$CRON_ENTRY') | crontab -" 2>/dev/null || true - echo "✓ Cron fallback configured" - fi - - echo "" - echo "Autostart configuration methods:" - echo " 1. ✓ XDG Autostart Entry (~/.config/autostart/)" - if [ -f "$LXDE_AUTOSTART" ]; then - echo " 2. ✓ LXDE Autostart" - fi - echo " 3. ✓ Cron Fallback (@reboot)" - echo "" - 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 "" -} - -# Function to disable power-saving mode on Raspberry Pi -setup_raspberry_pi_power_management() { - echo "" - echo "==========================================" - 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..." - BOOT_CONFIG=$(find_boot_config) - if [ -n "$BOOT_CONFIG" ]; then - # Check if hdmi_blanking is already configured - 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" > /dev/null - fi - - # Disable HDMI CEC (can interfere with power management) - 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" > /dev/null - fi - - # Force HDMI mode to always be on - 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" > /dev/null - fi - - # Disable HDMI sleep mode - 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" > /dev/null - fi - - echo "✓ HDMI configuration locked in $BOOT_CONFIG" - echo " - HDMI blanking disabled" - echo " - HDMI CEC disabled" - echo " - HDMI hotplug forced" - echo " - HDMI sleep mode 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 "$ACTUAL_HOME/.xinitrc" ]; then - cat >> "$ACTUAL_HOME/.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" "$ACTUAL_HOME/.xinitrc"; then - cat >> "$ACTUAL_HOME/.xinitrc" << 'EOF' - -# Disable screen blanking and screensaver -xset s off -xset -dpms -xset s noblank -EOF - fi - fi - 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 - 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 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] -Description=Keep HDMI Display Powered On -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 300; done' -Restart=always -RestartSec=10 - -[Install] -WantedBy=multi-user.target -EOF - - sudo systemctl daemon-reload - sudo systemctl enable hdmi-poweron.service - sudo systemctl start hdmi-poweron.service - echo "✓ HDMI power control service enabled" - - # Create aggressive display keep-alive script - echo "Creating aggressive display keep-alive script..." - DISPLAY_KEEPALIVE="$SCRIPT_DIR/.display-keepalive.sh" - cat > "$DISPLAY_KEEPALIVE" << 'EOF' -#!/bin/bash -# Aggressive display keep-alive for Raspberry Pi -# Supports both X11 and Wayland environments - -DISPLAY_TIMEOUT=30 - -# Detect display server type -detect_display_server() { - if [ -n "$WAYLAND_DISPLAY" ]; then - echo "wayland" - elif [ -n "$DISPLAY" ]; then - echo "x11" - else - echo "unknown" - fi -} - -DISPLAY_SERVER=$(detect_display_server) - -while true; do - # Keep HDMI powered on (works for both X11 and Wayland) - if command -v tvservice &> /dev/null; then - /usr/bin/tvservice -p 2>/dev/null - fi - - if [ "$DISPLAY_SERVER" = "wayland" ]; then - # Wayland-specific power management - - # Method 1: Use wlr-randr for Wayland compositors (if available) - if command -v wlr-randr &> /dev/null; then - wlr-randr --output HDMI-A-1 --on 2>/dev/null || true - fi - - # Method 2: Prevent idle using systemd-inhibit - if command -v systemd-inhibit &> /dev/null; then - # This is already running, but refresh the lock - systemctl --user restart plasma-ksmserver.service 2>/dev/null || true - fi - - # Method 3: Use wlopm (Wayland output power management) - if command -v wlopm &> /dev/null; then - wlopm --on \* 2>/dev/null || true - fi - - # Method 4: Simulate activity via input (works on Wayland) - if command -v ydotool &> /dev/null; then - ydotool mousemove -x 1 -y 1 2>/dev/null || true - ydotool mousemove -x -1 -y -1 2>/dev/null || true - fi - - # Method 5: GNOME/KDE Wayland idle inhibit - if command -v gnome-session-inhibit &> /dev/null; then - # Already inhibited by running process - true - fi - - else - # X11-specific power management (original code) - if command -v xset &> /dev/null; then - DISPLAY=:0 xset s off 2>/dev/null - DISPLAY=:0 xset -dpms 2>/dev/null - DISPLAY=:0 xset dpms force on 2>/dev/null - DISPLAY=:0 xset s reset 2>/dev/null - fi - - # Move mouse to trigger activity - if command -v xdotool &> /dev/null; then - DISPLAY=:0 xdotool mousemove_relative 1 1 2>/dev/null - DISPLAY=:0 xdotool mousemove_relative -1 -1 2>/dev/null - fi - - # Disable monitor power saving - if command -v xrandr &> /dev/null; then - DISPLAY=:0 xrandr --output HDMI-1 --power-profile performance 2>/dev/null || true - fi - fi - - sleep $DISPLAY_TIMEOUT -done -EOF - - chmod +x "$DISPLAY_KEEPALIVE" - echo "✓ Display keep-alive script created" - - # 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 2>/dev/null; then - echo "Wayland detected - installing Wayland power management tools..." - - # 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 - echo "X11 detected - using xset/xdotool/xrandr tools" - fi - - # Update systemd screen keep-alive service to use this script - 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 -User=$ACTUAL_USER -ExecStart=/bin/bash $DISPLAY_KEEPALIVE -Restart=always -RestartSec=5 -Environment="DISPLAY=:0" -Environment="XAUTHORITY=%h/.Xauthority" - -[Install] -WantedBy=graphical-session.target -EOF - - sudo systemctl daemon-reload - sudo systemctl enable screen-keepalive.service - echo "✓ Aggressive 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 "" -} - - -# ============================================================ -# 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" + else + return 1 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 SERVER_IP="" SERVER_PORT="" SCREEN_NAME="" @@ -794,8 +95,12 @@ CONFIG_FILE_PATH="" usage() { echo "Usage: $0 [OPTIONS]" echo "" + echo "Authentication options (avoids sudo password prompts):" + echo " -U, --sudo-user USER Username for sudo commands" + echo " -W, --sudo-password PASS Password for sudo commands" + echo "" echo "Installation modes (choose one):" - echo " --provision URL One-time provisioning URL from Digiserver (fetches all config)" + echo " --provision URL One-time provisioning URL from Digiserver" echo " --config FILE Path to pre-made JSON config file" echo " (individual params) Set each config value manually" echo "" @@ -820,6 +125,14 @@ usage() { while [ $# -gt 0 ]; do case "$1" in + -U|--sudo-user) + SUDO_USERNAME="$2" + shift 2 + ;; + -W|--sudo-password) + SUDO_PASSWORD="$2" + shift 2 + ;; --provision) PROVISION_URL="$2" shift 2 @@ -873,7 +186,6 @@ while [ $# -gt 0 ]; do shift ;; -q|--quiet) - # Silent mode - redirect stdout to log file exec > >(tee -a /tmp/kivy-install.log) 2>&1 shift ;; @@ -895,156 +207,382 @@ fi # ============================================================ # Mode Banner # ============================================================ +echo "==========================================" +echo "Kivy Signage Player v1.2.0 - Installer" +echo "==========================================" if [ "$OFFLINE_MODE" = true ]; then - echo "==========================================" - echo "📦 Offline Installation Mode" - echo "==========================================" + echo "Mode: Offline Installation" else - echo "==========================================" - echo "🌐 Online Installation Mode" - echo "==========================================" + echo "Mode: Online Installation" +fi +if [ -n "$SUDO_USERNAME" ]; then + echo "Sudo user: $SUDO_USERNAME" fi - -echo "" -echo "Installing Kivy Signage Player dependencies..." echo "" -# Install system dependencies -echo "Step 1: Installing system dependencies..." +# ============================================================ +# Step 1: System Dependencies +# ============================================================ +echo "Step 1/6: Installing system dependencies..." echo "--------------------" +echo "Updating package lists..." +run_sudo apt update + +echo "Installing system packages..." + 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 + run_sudo dpkg -i *.deb 2>/dev/null || true + run_sudo apt-get install -f -y || true + cd "$SCRIPT_DIR" +fi + +run_sudo apt install -y \ + python3-pip python3-setuptools python3-dev \ + python3-venv \ + libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev \ + libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev \ + zlib1g-dev ffmpeg libavcodec-extra \ + gstreamer1.0-plugins-base gstreamer1.0-plugins-good + +echo "System dependencies installed" +echo "" + +# ============================================================ +# Step 2: Python Virtual Environment +# ============================================================ +echo "Step 2/6: Setting up Python virtual environment..." +echo "--------------------" + +if [ -d "$VENV_DIR" ]; then + echo "Removing old virtual environment..." + rm -rf "$VENV_DIR" +fi + +echo "Creating virtual environment..." +python3 -m venv "$VENV_DIR" +echo "Virtual environment created at $VENV_DIR" + +source "$VENV_DIR/bin/activate" + +echo "Upgrading pip..." +pip install --upgrade pip --quiet + +echo "" + +# ============================================================ +# Step 3: Install Python Packages +# ============================================================ +echo "Step 3/6: Installing Python packages..." +echo "--------------------" + +PIP_EXTRA_ARGS="" +if [ "$OFFLINE_MODE" = true ]; then + echo "Using offline wheel repository: $WHEELS_DIR" + PIP_EXTRA_ARGS="--no-index --find-links=$WHEELS_DIR" +fi + +if [ -f "$REQUIREMENTS_FILE" ]; then + echo "Installing packages from requirements.txt..." + if [ "$OFFLINE_MODE" = true ]; then + if pip install $PIP_EXTRA_ARGS -r "$REQUIREMENTS_FILE"; then + echo "All packages installed from offline repository" + else + echo "" + echo "Offline installation failed (some wheels may be missing or incompatible)" + echo " Falling back to online installation (requires internet)..." + echo "" + pip install -r "$REQUIREMENTS_FILE" --find-links="$WHEELS_DIR" + echo "Packages installed from PyPI (with local wheel fallback)" + fi 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 + pip install -r "$REQUIREMENTS_FILE" --find-links="$WHEELS_DIR" + echo "Packages installed from PyPI" fi - - echo "System packages installed successfully" +else + echo "requirements.txt not found - skipping pip install" fi echo "" -# Install Python dependencies into virtual environment -echo "Step 2: Creating virtual environment and installing Python dependencies..." -echo "--------------------" - -# 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)" - - 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 "Falling back to online installation..." - pip install -r requirements.txt - echo "✓ Python packages installed from PyPI" - fi -else - # Online: Use pip from PyPI - echo "Installing from PyPI into virtual environment..." - pip install -r requirements.txt - echo "✓ Python packages installed successfully into .venv" -fi - -# Deactivate the virtual environment (re-activate at runtime) deactivate # ============================================================ -# Post-Installation Setup +# Step 4: Autostart Workflow # ============================================================ +echo "Step 4/6: Setting up autostart..." +echo "--------------------" -# Setup autostart workflow -setup_autostart +ACTUAL_USER="${SUDO_USERNAME:-${SUDO_USER:-$(whoami)}}" +ACTUAL_HOME=$(eval echo ~"$ACTUAL_USER") +AUTOSTART_DIR="$ACTUAL_HOME/.config/autostart" -# Check if running on Raspberry Pi and setup power management -if detect_raspberry_pi; then - setup_raspberry_pi_power_management +echo "Configuring autostart for user: $ACTUAL_USER" + +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=/bin/bash -c "cd $SCRIPT_DIR && exec bash start.sh" +Icon=media-video-display +Categories=Utility; +NoDisplay=false +Terminal=false +StartupNotify=false +Hidden=false +X-GNOME-Autostart-enabled=true +X-GNOME-Autostart-delay=3 +X-XFCE-Autostart-Override=true +EOF + +run_sudo chown "$ACTUAL_USER:$ACTUAL_USER" "$AUTOSTART_DIR/kivy-signage-player.desktop" 2>/dev/null || true +chmod 644 "$AUTOSTART_DIR/kivy-signage-player.desktop" 2>/dev/null || true +echo "XDG autostart entry created" + +# Cron fallback +if command -v crontab &>/dev/null; then + CRON_WRAPPER="$SCRIPT_DIR/.start-player-cron.sh" + cat > "$CRON_WRAPPER" << EOF +#\!/bin/bash +sleep 15 +cd $SCRIPT_DIR && bash start.sh +EOF + chmod +x "$CRON_WRAPPER" + + CRON_ENTRY="@reboot sleep 20 && $CRON_WRAPPER > /tmp/kivy-player-cron.log 2>&1" + # Use sudo -u which works when running with sudo (no password prompt) + if sudo -u "$ACTUAL_USER" crontab -l 2>/dev/null | grep -q "kivy-signage-player"; then + true + else + (sudo -u "$ACTUAL_USER" crontab -l 2>/dev/null || true; echo "$CRON_ENTRY") | sudo -u "$ACTUAL_USER" crontab - 2>/dev/null || true + fi + echo "Cron fallback configured" fi -# Optimize video playback for Raspberry Pi +echo "" + +# ============================================================ +# Step 5: Raspberry Pi Optimization +# ============================================================ if detect_raspberry_pi; then - echo "" - echo "==========================================" - echo "Optimizing for Video Playback" - echo "==========================================" + echo "Step 5/6: Optimizing for Raspberry Pi..." + echo "--------------------" + + BOOT_CONFIG=$(find_boot_config) + if [ -n "$BOOT_CONFIG" ]; then + echo "Configuring HDMI settings..." + for setting in "hdmi_blanking=0" "hdmi_ignore_cec_init=1" "hdmi_force_hotplug=1"; do + key="${setting%%=*}" + if grep -q "^$key" "$BOOT_CONFIG" 2>/dev/null; then + run_sudo sed -i "s/^$key=.*/$setting/" "$BOOT_CONFIG" + else + echo "$setting" | run_sudo tee -a "$BOOT_CONFIG" > /dev/null + fi + done + echo "HDMI settings configured" + fi + + echo "Setting CPU to performance mode..." + for cpu in /sys/devices/system/cpu/cpu[0-9]*; do + if [ -f "$cpu/cpufreq/scaling_governor" ]; then + echo performance | run_sudo tee "$cpu/cpufreq/scaling_governor" > /dev/null 2>&1 || true + fi + done + + run_sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target 2>/dev/null || true + echo "System sleep disabled" - # Run video optimization script if [ -f "$SCRIPT_DIR/.video-optimization.sh" ]; then bash "$SCRIPT_DIR/.video-optimization.sh" fi + + echo "" fi -# Create required player directories -setup_player_directories +# ============================================================ +# Step 6: Finalize Player Setup +# ============================================================ +echo "Step 6/6: Finalizing player setup..." +echo "--------------------" + +# Create required directories +echo "Creating player directories..." +mkdir -p "$SCRIPT_DIR/media" +mkdir -p "$SCRIPT_DIR/playlists" +mkdir -p "$SCRIPT_DIR/config/resources" +mkdir -p "$SCRIPT_DIR/logs" +touch "$SCRIPT_DIR/logs/.gitkeep" 2>/dev/null || true +echo "Player directories created" # Write player configuration +write_player_config() { + local config_dir="$SCRIPT_DIR/config" + local config_file="$config_dir/app_config.json" + mkdir -p "$config_dir" + + if [ -n "$PROVISION_URL" ]; then + echo "Fetching provisioning data from: $PROVISION_URL" + local response + response=$(curl -sSf "$PROVISION_URL" 2>&1 || true) + if [ -n "$response" ]; then + echo "$response" > "$config_file" + echo "Provisioning data saved" + return 0 + fi + echo "Failed to fetch provisioning data" + fi + + if [ -n "$CONFIG_FILE_PATH" ] && [ -f "$CONFIG_FILE_PATH" ]; then + cp "$CONFIG_FILE_PATH" "$config_file" + echo "Configuration copied from $CONFIG_FILE_PATH" + return 0 + fi + + if [ -n "$SERVER_IP" ] || [ -n "$SCREEN_NAME" ] || [ -n "$QUICKCONNECT_KEY" ]; then + export SERVER_IP SERVER_PORT SCREEN_NAME QUICKCONNECT_KEY + export ORIENTATION TOUCH_ENABLED MAX_RESOLUTION + export USE_HTTPS VERIFY_SSL EDIT_ENABLED + + python3 << PYEOF +import json, os + +config_file = "$config_file" +config = {} +if os.path.exists(config_file): + with open(config_file) as f: + config = json.load(f) + +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', ''), +} + +for key, val in cli_params.items(): + if val: + config[key] = val + +https_val = os.environ.get('USE_HTTPS', '') +verify_val = os.environ.get('VERIFY_SSL', '') +edit_val = os.environ.get('EDIT_ENABLED', '') + +if https_val: + config['use_https'] = https_val.lower() == 'true' +if verify_val: + config['verify_ssl'] = verify_val.lower() == 'false' +if edit_val: + config['edit_feature_enabled'] = edit_val.lower() == 'true' + +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") +PYEOF + elif [ \! -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" + fi +} write_player_config -# Initialize authentication with Digiserver -init_player_auth +# Initialize authentication +config_file="$SCRIPT_DIR/config/app_config.json" +if [ -f "$config_file" ]; then + if python3 -c " +import json +c = json.load(open('$config_file')) +if c.get('server_ip') and c.get('screen_name') and c.get('quickconnect_key'): + exit(0) +else: + exit(1) +" 2>/dev/null; then + echo "Attempting player registration..." + cd "$SCRIPT_DIR/src" + source "$VENV_DIR/bin/activate" + python3 -c " +import json, sys +sys.path.insert(0, '.') +from get_playlists_v2 import ensure_authenticated -# Optimize for background execution -optimize_background_execution +with open('$config_file') as f: + config = json.load(f) + +auth = ensure_authenticated(config) +if auth: + print('Player registered successfully') + sys.exit(0) +else: + print('Registration deferred') + sys.exit(1) +" 2>&1 || echo "Auth initialization deferred" + deactivate 2>/dev/null || true + cd "$SCRIPT_DIR" + else + echo "Incomplete config - auth will happen on first run" + fi +fi + +# Create background runner +NOHUP_WRAPPER="$SCRIPT_DIR/.run-background.sh" +cat > "$NOHUP_WRAPPER" << EOF +#\!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LOG_FILE="$SCRIPT_DIR/logs/player-background.log" +mkdir -p "$(dirname "$LOG_FILE")" +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting player in background..." >> "$LOG_FILE" +cd "$SCRIPT_DIR" || exit 1 +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" # ============================================================ # Final Summary # ============================================================ echo "" echo "==========================================" -echo "✅ Kivy Signage Player — Installation Complete!" +echo "Installation Complete\!" echo "==========================================" echo "" -echo "📁 Installation directory: $SCRIPT_DIR" -echo "🐍 Virtual environment: .venv/" +echo "Installation: $SCRIPT_DIR" +echo "Virtual Env: $VENV_DIR" echo "" -# Read back the config to show applied settings if [ -f "$SCRIPT_DIR/config/app_config.json" ]; then - echo "📋 Player Configuration:" + echo "Player Configuration:" echo "------------------------" python3 -c " import json @@ -1059,34 +597,28 @@ print(f' Resolution: {c.get(\"max_resolution\",\"auto\")}') echo "" fi -echo "🚀 Quick Start Commands:" +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 .run-background.sh Run in background" +echo " bash check_player_status.sh Check player status" echo " bash stop_player.sh Stop the player" echo "" -echo "🔄 Autostart: The player will launch automatically on next desktop login." +echo "Autostart enabled for user: $ACTUAL_USER" echo "" -echo "📝 Logs: $SCRIPT_DIR/logs/" +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 +if [ -z "$SUDO_PASSWORD" ]; then + echo "==========================================" + echo "System Reboot Recommended" + echo "==========================================" + echo "" + echo "Some changes (HDMI settings, GPU memory) require a reboot." + echo "" + echo "Rebooting in 5 seconds... Press Ctrl+C to cancel." + sleep 5 + echo "Rebooting now..." + run_sudo reboot +fi diff --git a/install.sh.bak b/install.sh.bak new file mode 100755 index 0000000..6ae7924 --- /dev/null +++ b/install.sh.bak @@ -0,0 +1,1056 @@ +#!/bin/bash + +# Kivy Signage Player Installation Script +# Supports both online and offline installation + +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() { + 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 + 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 (Primary - works with Wayland/GNOME/KDE) + echo "Creating XDG autostart entry for Wayland..." + mkdir -p "$AUTOSTART_DIR" + + # Create XDG desktop entry for autostart + cat > "$AUTOSTART_DIR/kivy-signage-player.desktop" << 'EOF' +[Desktop Entry] +Type=Application +Name=Kivy Signage Player +Comment=Digital Signage Player +Exec=/bin/bash -c "cd $SCRIPT_DIR && exec bash start.sh" +Icon=media-video-display +Categories=Utility; +NoDisplay=false +Terminal=false +StartupNotify=false +Hidden=false +X-GNOME-Autostart-enabled=true +X-GNOME-Autostart-delay=3 +X-XFCE-Autostart-Override=true +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 644 "$AUTOSTART_DIR/kivy-signage-player.desktop" + echo "✓ XDG autostart entry created for Wayland session" + + # Also create Wayland session directory entry (for GNOME/Wayland) + WAYLAND_AUTOSTART_DIR="$ACTUAL_HOME/.config/autostart.gnome" + mkdir -p "$WAYLAND_AUTOSTART_DIR" + cp "$AUTOSTART_DIR/kivy-signage-player.desktop" "$WAYLAND_AUTOSTART_DIR/kivy-signage-player.desktop" + chown "$ACTUAL_USER:$ACTUAL_USER" "$WAYLAND_AUTOSTART_DIR/kivy-signage-player.desktop" + echo "✓ XDG autostart also added to GNOME/Wayland session directory" + + # 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: Disable systemd service (prefer Wayland session management) + # XDG autostart above is sufficient for Wayland/GNOME sessions + echo "Note: Using Wayland session autostart via XDG instead of systemd service" + + # If systemd service exists from previous installation, disable it + if sudo test -f /etc/systemd/system/kiwy-player.service 2>/dev/null; then + echo "Disabling old systemd service in favor of Wayland session..." + sudo systemctl disable kiwy-player.service 2>/dev/null || true + echo "✓ Old systemd service disabled" + fi + + # 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 15 + +# 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 + CRON_ENTRY="@reboot sleep 20 && $CRON_WRAPPER > /tmp/kivy-player-cron.log 2>&1" + if ! sudo -u "$ACTUAL_USER" crontab -l 2>/dev/null | grep -q "kivy-signage-player"; then + sudo -u "$ACTUAL_USER" sh -c "(crontab -l 2>/dev/null || true; echo '$CRON_ENTRY') | crontab -" 2>/dev/null || true + echo "✓ Cron fallback configured" + fi + + echo "" + echo "Autostart configuration methods:" + echo " 1. ✓ XDG Autostart Entry (~/.config/autostart/)" + if [ -f "$LXDE_AUTOSTART" ]; then + echo " 2. ✓ LXDE Autostart" + fi + echo " 3. ✓ Cron Fallback (@reboot)" + echo "" + 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 "" +} + +# Function to disable power-saving mode on Raspberry Pi +setup_raspberry_pi_power_management() { + echo "" + echo "==========================================" + 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..." + BOOT_CONFIG=$(find_boot_config) + if [ -n "$BOOT_CONFIG" ]; then + # Check if hdmi_blanking is already configured + 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" > /dev/null + fi + + # Disable HDMI CEC (can interfere with power management) + 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" > /dev/null + fi + + # Force HDMI mode to always be on + 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" > /dev/null + fi + + # Disable HDMI sleep mode + 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" > /dev/null + fi + + echo "✓ HDMI configuration locked in $BOOT_CONFIG" + echo " - HDMI blanking disabled" + echo " - HDMI CEC disabled" + echo " - HDMI hotplug forced" + echo " - HDMI sleep mode 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 "$ACTUAL_HOME/.xinitrc" ]; then + cat >> "$ACTUAL_HOME/.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" "$ACTUAL_HOME/.xinitrc"; then + cat >> "$ACTUAL_HOME/.xinitrc" << 'EOF' + +# Disable screen blanking and screensaver +xset s off +xset -dpms +xset s noblank +EOF + fi + fi + 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 + 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 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] +Description=Keep HDMI Display Powered On +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 300; done' +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOF + + sudo systemctl daemon-reload + sudo systemctl enable hdmi-poweron.service + sudo systemctl start hdmi-poweron.service + echo "✓ HDMI power control service enabled" + + # Create aggressive display keep-alive script + echo "Creating aggressive display keep-alive script..." + DISPLAY_KEEPALIVE="$SCRIPT_DIR/.display-keepalive.sh" + cat > "$DISPLAY_KEEPALIVE" << 'EOF' +#!/bin/bash +# Aggressive display keep-alive for Raspberry Pi +# Supports both X11 and Wayland environments + +DISPLAY_TIMEOUT=30 + +# Detect display server type +detect_display_server() { + if [ -n "$WAYLAND_DISPLAY" ]; then + echo "wayland" + elif [ -n "$DISPLAY" ]; then + echo "x11" + else + echo "unknown" + fi +} + +DISPLAY_SERVER=$(detect_display_server) + +while true; do + # Keep HDMI powered on (works for both X11 and Wayland) + if command -v tvservice &> /dev/null; then + /usr/bin/tvservice -p 2>/dev/null + fi + + if [ "$DISPLAY_SERVER" = "wayland" ]; then + # Wayland-specific power management + + # Method 1: Use wlr-randr for Wayland compositors (if available) + if command -v wlr-randr &> /dev/null; then + wlr-randr --output HDMI-A-1 --on 2>/dev/null || true + fi + + # Method 2: Prevent idle using systemd-inhibit + if command -v systemd-inhibit &> /dev/null; then + # This is already running, but refresh the lock + systemctl --user restart plasma-ksmserver.service 2>/dev/null || true + fi + + # Method 3: Use wlopm (Wayland output power management) + if command -v wlopm &> /dev/null; then + wlopm --on \* 2>/dev/null || true + fi + + # Method 4: Simulate activity via input (works on Wayland) + if command -v ydotool &> /dev/null; then + ydotool mousemove -x 1 -y 1 2>/dev/null || true + ydotool mousemove -x -1 -y -1 2>/dev/null || true + fi + + # Method 5: GNOME/KDE Wayland idle inhibit + if command -v gnome-session-inhibit &> /dev/null; then + # Already inhibited by running process + true + fi + + else + # X11-specific power management (original code) + if command -v xset &> /dev/null; then + DISPLAY=:0 xset s off 2>/dev/null + DISPLAY=:0 xset -dpms 2>/dev/null + DISPLAY=:0 xset dpms force on 2>/dev/null + DISPLAY=:0 xset s reset 2>/dev/null + fi + + # Move mouse to trigger activity + if command -v xdotool &> /dev/null; then + DISPLAY=:0 xdotool mousemove_relative 1 1 2>/dev/null + DISPLAY=:0 xdotool mousemove_relative -1 -1 2>/dev/null + fi + + # Disable monitor power saving + if command -v xrandr &> /dev/null; then + DISPLAY=:0 xrandr --output HDMI-1 --power-profile performance 2>/dev/null || true + fi + fi + + sleep $DISPLAY_TIMEOUT +done +EOF + + chmod +x "$DISPLAY_KEEPALIVE" + echo "✓ Display keep-alive script created" + + # 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 2>/dev/null; then + echo "Wayland detected - installing Wayland power management tools..." + + # 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 + echo "X11 detected - using xset/xdotool/xrandr tools" + fi + + # Update systemd screen keep-alive service to use this script + 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 +User=$ACTUAL_USER +ExecStart=/bin/bash $DISPLAY_KEEPALIVE +Restart=always +RestartSec=5 +Environment="DISPLAY=:0" +Environment="XAUTHORITY=%h/.Xauthority" + +[Install] +WantedBy=graphical-session.target +EOF + + sudo systemctl daemon-reload + sudo systemctl enable screen-keepalive.service + echo "✓ Aggressive 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 "" +} + + +# ============================================================ +# 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 + touch "$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" + + # Run auth using system Python + ( + 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" + +# Navigate to project directory +cd "$SCRIPT_DIR" || exit 1 + +# 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" + + # Verify autostart entry exists + local autostart_file="$ACTUAL_HOME/.config/autostart/kivy-signage-player.desktop" + if [ -f "$autostart_file" ]; then + 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 +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 "==========================================" +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 + + # Also install Python packages via apt (may pull from cache) + sudo apt install -y python3-kivy python3-aiohttp python3-bcrypt python3-requests python3-evdev 2>/dev/null || 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 + + # Install Python packages system-wide via apt (pre-compiled for system Python) + echo "Installing Python packages via apt..." + sudo apt install -y \ + python3-kivy \ + python3-aiohttp \ + python3-bcrypt \ + python3-requests \ + python3-evdev + echo "✓ Python packages installed via apt" + + # Install ffpyplayer via pip (not available in apt) + echo "Installing ffpyplayer via pip..." + pip3 install --user ffpyplayer 2>/dev/null || pip3 install --user ffpyplayer --break-system-packages 2>/dev/null || echo "⚠️ ffpyplayer not available - video may use fallback" + fi + + echo "System packages installed successfully" +fi + +# 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 + +# Optimize video playback for Raspberry Pi +if detect_raspberry_pi; then + echo "" + echo "==========================================" + echo "Optimizing for Video Playback" + echo "==========================================" + + # Run video optimization script + if [ -f "$SCRIPT_DIR/.video-optimization.sh" ]; then + bash "$SCRIPT_DIR/.video-optimization.sh" + fi +fi + +# 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 "==========================================" +echo "✅ Kivy Signage Player — Installation Complete!" +echo "==========================================" +echo "" +echo "📁 Installation directory: $SCRIPT_DIR" +echo "" + +# 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/logs/.gitkeep b/logs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/repo/python-wheels/Kivy-2.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl b/repo/python-wheels/Kivy-2.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl similarity index 72% rename from repo/python-wheels/Kivy-2.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl rename to repo/python-wheels/Kivy-2.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl index 0942fe1..b07278c 100644 Binary files a/repo/python-wheels/Kivy-2.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl and b/repo/python-wheels/Kivy-2.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl differ diff --git a/repo/python-wheels/aiohappyeyeballs-2.7.1-py3-none-any.whl b/repo/python-wheels/aiohappyeyeballs-2.7.1-py3-none-any.whl new file mode 100644 index 0000000..03be6e4 Binary files /dev/null and b/repo/python-wheels/aiohappyeyeballs-2.7.1-py3-none-any.whl differ diff --git a/repo/python-wheels/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl b/repo/python-wheels/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl new file mode 100644 index 0000000..3c0cd02 Binary files /dev/null and b/repo/python-wheels/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl differ diff --git a/repo/python-wheels/aiohttp-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl b/repo/python-wheels/aiohttp-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl deleted file mode 100644 index ccf6c58..0000000 Binary files a/repo/python-wheels/aiohttp-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl and /dev/null differ diff --git a/repo/python-wheels/attrs-26.1.0-py3-none-any.whl b/repo/python-wheels/attrs-26.1.0-py3-none-any.whl new file mode 100644 index 0000000..68e3e96 Binary files /dev/null and b/repo/python-wheels/attrs-26.1.0-py3-none-any.whl differ diff --git a/repo/python-wheels/certifi-2026.6.17-py3-none-any.whl b/repo/python-wheels/certifi-2026.6.17-py3-none-any.whl new file mode 100644 index 0000000..7b4b486 Binary files /dev/null and b/repo/python-wheels/certifi-2026.6.17-py3-none-any.whl differ diff --git a/repo/python-wheels/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl deleted file mode 100644 index 2d58967..0000000 Binary files a/repo/python-wheels/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl and /dev/null differ diff --git a/repo/python-wheels/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl new file mode 100644 index 0000000..9e96513 Binary files /dev/null and b/repo/python-wheels/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl differ diff --git a/repo/python-wheels/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl new file mode 100644 index 0000000..8804b8a Binary files /dev/null and b/repo/python-wheels/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl differ diff --git a/repo/python-wheels/cython-3.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/cython-3.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl deleted file mode 100644 index 8d89e6f..0000000 Binary files a/repo/python-wheels/cython-3.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl and /dev/null differ diff --git a/repo/python-wheels/docutils-0.23-py3-none-any.whl b/repo/python-wheels/docutils-0.23-py3-none-any.whl new file mode 100644 index 0000000..134afb0 Binary files /dev/null and b/repo/python-wheels/docutils-0.23-py3-none-any.whl differ diff --git a/repo/python-wheels/evdev-1.9.1-cp313-cp313-linux_aarch64.whl b/repo/python-wheels/evdev-1.9.1-cp313-cp313-linux_aarch64.whl new file mode 100644 index 0000000..3d20860 Binary files /dev/null and b/repo/python-wheels/evdev-1.9.1-cp313-cp313-linux_aarch64.whl differ diff --git a/repo/python-wheels/ffpyplayer-4.5.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl b/repo/python-wheels/ffpyplayer-4.5.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl new file mode 100644 index 0000000..671c8dd Binary files /dev/null and b/repo/python-wheels/ffpyplayer-4.5.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl differ diff --git a/repo/python-wheels/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl deleted file mode 100644 index ff0f5c5..0000000 Binary files a/repo/python-wheels/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl and /dev/null differ diff --git a/repo/python-wheels/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl new file mode 100644 index 0000000..b6d3db3 Binary files /dev/null and b/repo/python-wheels/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl differ diff --git a/repo/python-wheels/idna-3.18-py3-none-any.whl b/repo/python-wheels/idna-3.18-py3-none-any.whl new file mode 100644 index 0000000..57a9e84 Binary files /dev/null and b/repo/python-wheels/idna-3.18-py3-none-any.whl differ diff --git a/repo/python-wheels/multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl deleted file mode 100644 index 6a5fbbd..0000000 Binary files a/repo/python-wheels/multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl and /dev/null differ diff --git a/repo/python-wheels/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl new file mode 100644 index 0000000..999851f Binary files /dev/null and b/repo/python-wheels/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl differ diff --git a/repo/python-wheels/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl deleted file mode 100644 index 32b2a15..0000000 Binary files a/repo/python-wheels/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl and /dev/null differ diff --git a/repo/python-wheels/propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl new file mode 100644 index 0000000..2b96077 Binary files /dev/null and b/repo/python-wheels/propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl differ diff --git a/repo/python-wheels/pygments-2.20.0-py3-none-any.whl b/repo/python-wheels/pygments-2.20.0-py3-none-any.whl new file mode 100644 index 0000000..2009f93 Binary files /dev/null and b/repo/python-wheels/pygments-2.20.0-py3-none-any.whl differ diff --git a/repo/python-wheels/requests-2.34.2-py3-none-any.whl b/repo/python-wheels/requests-2.34.2-py3-none-any.whl new file mode 100644 index 0000000..e601338 Binary files /dev/null and b/repo/python-wheels/requests-2.34.2-py3-none-any.whl differ diff --git a/repo/python-wheels/typing_extensions-4.16.0-py3-none-any.whl b/repo/python-wheels/typing_extensions-4.16.0-py3-none-any.whl new file mode 100644 index 0000000..9f9aae6 Binary files /dev/null and b/repo/python-wheels/typing_extensions-4.16.0-py3-none-any.whl differ diff --git a/repo/python-wheels/urllib3-2.7.0-py3-none-any.whl b/repo/python-wheels/urllib3-2.7.0-py3-none-any.whl new file mode 100644 index 0000000..9482938 Binary files /dev/null and b/repo/python-wheels/urllib3-2.7.0-py3-none-any.whl differ diff --git a/repo/python-wheels/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl deleted file mode 100644 index 35903c6..0000000 Binary files a/repo/python-wheels/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl and /dev/null differ diff --git a/repo/python-wheels/yarl-1.24.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl b/repo/python-wheels/yarl-1.24.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl new file mode 100644 index 0000000..7832fe2 Binary files /dev/null and b/repo/python-wheels/yarl-1.24.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl differ diff --git a/run_player.sh b/run_player.sh index 90e801e..3991e4f 100644 --- a/run_player.sh +++ b/run_player.sh @@ -1,6 +1,5 @@ #!/bin/bash # Start Kivy Signage Player -cd "$(dirname "$0")" && source .venv/bin/activate cd "$(dirname "$0")/src" python3 main.py \ No newline at end of file diff --git a/src/player_auth.json b/src/player_auth.json deleted file mode 100644 index 7590145..0000000 --- a/src/player_auth.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "hostname": "rpi-Receptie", - "auth_code": "BrJrGzX_IT9oP_Lfke8Qgo4sDjMc49T1EhSnWmKKpDM", - "player_id": 1, - "player_name": "Receptie TV", - "playlist_id": 1, - "orientation": "Landscape", - "authenticated": true, - "server_url": "http://192.168.0.159:8080" -} \ No newline at end of file diff --git a/start.sh b/start.sh index 34b7b6b..12e1a78 100755 --- a/start.sh +++ b/start.sh @@ -218,19 +218,6 @@ 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!" @@ -253,7 +240,6 @@ while true; do # Start the player cd "$SCRIPT_DIR/src" python3 main.py & - PLAYER_PID=$! log_message "Player PID: $PLAYER_PID"