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