#!/bin/bash # # run_player-afterclone.sh # ============================================================ # ONE-TIME post-clone setup for a cloned Raspberry Pi SD card. # # Problem it solves: # The player identifies itself to DigiServer using the "screen_name" # value in config/app_config.json (NOT the OS hostname). A cloned SD # card carries the ORIGINAL card's screen_name + a cached auth token # (src/player_auth.json). Two devices then fight over the same player # session, so the cloned device never connects. # # What this script does: # 1. Stops the running player/watchdog (so the token is not re-written) # 2. Backs up the current identity/config files # 3. Deletes the cached authentication token(s) -> forces re-auth # 4. Sets a NEW unique screen_name and (optionally) server details # 5. Leaves the player ready to boot and register as a BRAND-NEW player # # Usage: # bash run_player-afterclone.sh [OPTIONS] # # Options: # -n, --name NAME New unique screen/player name # -s, --server IP Server IP / hostname # -p, --port PORT Server port # -k, --key KEY Quick-connect / auth key # --https Enable HTTPS # --no-https Disable HTTPS # --verify-ssl Enable SSL certificate verification # --no-verify-ssl Disable SSL certificate verification # --set-hostname Also set the OS hostname to the new screen name # -y, --yes Non-interactive; use args/defaults, no prompts # --force Run even if this card was already set up # -h, --help Show this help # SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CONFIG_DIR="$SCRIPT_DIR/config" CONFIG_FILE="$CONFIG_DIR/app_config.json" VENV_DIR="$SCRIPT_DIR/.venv" MARKER_FILE="$SCRIPT_DIR/.post-clone-setup.done" BACKUP_ROOT="$SCRIPT_DIR/.post-clone-backups" STAMP="$(date '+%Y%m%d-%H%M%S')" # ---- Defaults / CLI state ---- NEW_NAME="" NEW_SERVER="" NEW_PORT="" NEW_KEY="" NEW_USE_HTTPS="" NEW_VERIFY_SSL="" SET_HOSTNAME=false ASSUME_YES=false FORCE=false # ---- Pretty printing ---- info() { echo " $1"; } ok() { echo " ✓ $1"; } warn() { echo " ⚠️ $1"; } err() { echo " ✗ $1"; } usage() { cat <<'EOF' run_player-afterclone.sh - one-time post-clone setup for a cloned SD card. Deletes the cached authentication token and configures a NEW unique player identity so the card registers on the server as a new player. Usage: bash run_player-afterclone.sh [OPTIONS] Options: -n, --name NAME New unique screen/player name -s, --server IP Server IP / hostname -p, --port PORT Server port -k, --key KEY Quick-connect / auth key --https Enable HTTPS --no-https Disable HTTPS --verify-ssl Enable SSL certificate verification --no-verify-ssl Disable SSL certificate verification --set-hostname Also set the OS hostname to the new screen name -y, --yes Non-interactive; use args/defaults, no prompts --force Run even if this card was already set up -h, --help Show this help EOF exit 0 } # ---- Pick a python interpreter (prefer the venv, fall back to system) ---- pick_python() { if [ -x "$VENV_DIR/bin/python3" ]; then echo "$VENV_DIR/bin/python3" elif command -v python3 >/dev/null 2>&1; then echo "python3" else echo "" fi } # ---- Parse arguments ---- while [ $# -gt 0 ]; do case "$1" in -n|--name) NEW_NAME="$2"; shift 2 ;; -s|--server) NEW_SERVER="$2"; shift 2 ;; -p|--port) NEW_PORT="$2"; shift 2 ;; -k|--key) NEW_KEY="$2"; shift 2 ;; --https) NEW_USE_HTTPS="true"; shift ;; --no-https) NEW_USE_HTTPS="false"; shift ;; --verify-ssl) NEW_VERIFY_SSL="true"; shift ;; --no-verify-ssl) NEW_VERIFY_SSL="false"; shift ;; --set-hostname) SET_HOSTNAME=true; shift ;; -y|--yes) ASSUME_YES=true; shift ;; --force) FORCE=true; shift ;; -h|--help) usage ;; *) err "Unknown option: $1"; echo ""; usage ;; esac done echo "==========================================" echo "Kiwy Signage - Post-Clone Setup" echo "==========================================" echo "" # ---- Safety: only run once per card (unless --force) ---- if [ -f "$MARKER_FILE" ] && [ "$FORCE" != true ]; then warn "This card looks already set up (marker: $(basename "$MARKER_FILE"))." warn "Re-run with --force if you really want to reset it again." echo "" exit 1 fi PYTHON_BIN="$(pick_python)" if [ -z "$PYTHON_BIN" ]; then err "python3 not found. Run install.sh first." exit 1 fi # ============================================================ # 1) Stop the running player + watchdog so nothing re-writes the token # ============================================================ echo "▶ Stopping any running player/watchdog..." pkill -f "bash.*start.sh" 2>/dev/null || true pkill -f "python3 main.py" 2>/dev/null || true sleep 2 pkill -9 -f "bash.*start.sh" 2>/dev/null || true pkill -9 -f "python3 main.py" 2>/dev/null || true ok "Player stopped" echo "" # ============================================================ # 2) Read current config (for defaults / display) # ============================================================ CUR_NAME="" CUR_SERVER="" CUR_PORT="" CUR_KEY="" if [ -f "$CONFIG_FILE" ]; then eval "$("$PYTHON_BIN" - "$CONFIG_FILE" <<'PYEOF' import json, sys try: c = json.load(open(sys.argv[1])) except Exception: c = {} def q(k): v = c.get(k, "") v = "" if v is None else str(v) return v.replace("'", "'\\''") print(f"CUR_NAME='{q('screen_name')}'") print(f"CUR_SERVER='{q('server_ip')}'") print(f"CUR_PORT='{q('port')}'") print(f"CUR_KEY='{q('quickconnect_key')}'") PYEOF )" fi OS_HOSTNAME="$(hostname 2>/dev/null || echo '')" # Sensible defaults: prefer an explicit new name, else the (changed) OS hostname, # else the previous screen name. DEF_NAME="$NEW_NAME" [ -z "$DEF_NAME" ] && DEF_NAME="$OS_HOSTNAME" [ -z "$DEF_NAME" ] && DEF_NAME="$CUR_NAME" [ -z "$DEF_NAME" ] && DEF_NAME="player-$(date +%s | tail -c 5)" # ============================================================ # 3) Prompt (unless -y / non-interactive) for the new identity # ============================================================ prompt_value() { # $1 = prompt text, $2 = default local answer if [ "$ASSUME_YES" = true ] || [ ! -t 0 ]; then echo "$2" return fi read -r -p " $1 [$2]: " answer echo "${answer:-$2}" } echo "▶ New player identity" info "Note: the server identifies this player by 'screen_name', not the OS hostname." if [ -z "$NEW_NAME" ]; then NEW_NAME="$(prompt_value "New unique screen/player name" "$DEF_NAME")" fi if [ -z "$NEW_SERVER" ]; then NEW_SERVER="$(prompt_value "Server IP/hostname" "$CUR_SERVER")" fi if [ -z "$NEW_PORT" ]; then NEW_PORT="$(prompt_value "Server port" "${CUR_PORT:-8080}")" fi if [ -z "$NEW_KEY" ]; then NEW_KEY="$(prompt_value "Quick-connect key" "$CUR_KEY")" fi echo "" # ============================================================ # 4) Back up current identity files # ============================================================ BACKUP_DIR="$BACKUP_ROOT/$STAMP" mkdir -p "$BACKUP_DIR" echo "▶ Backing up current identity files to:" info "$BACKUP_DIR" [ -f "$CONFIG_FILE" ] && cp -p "$CONFIG_FILE" "$BACKUP_DIR/" 2>/dev/null || true [ -f "$SCRIPT_DIR/src/player_auth.json" ] && cp -p "$SCRIPT_DIR/src/player_auth.json" "$BACKUP_DIR/" 2>/dev/null || true ok "Backup complete" echo "" # ============================================================ # 5) Delete cached authentication tokens (force re-authentication) # ============================================================ echo "▶ Removing cached authentication token(s)..." REMOVED=0 while IFS= read -r token; do [ -z "$token" ] && continue rm -f "$token" && REMOVED=$((REMOVED + 1)) && info "deleted: ${token#$SCRIPT_DIR/}" done < <(find "$SCRIPT_DIR" -name 'player_auth.json' -not -path '*/.venv/*' -not -path "$BACKUP_ROOT/*" 2>/dev/null) rm -f /tmp/temp_auth_test.json 2>/dev/null || true rm -f "$SCRIPT_DIR/.player_heartbeat" 2>/dev/null || true rm -f "$SCRIPT_DIR/.player_stop_requested" 2>/dev/null || true if [ "$REMOVED" -eq 0 ]; then ok "No cached token found (already clean)" else ok "Removed $REMOVED token file(s)" fi echo "" # ============================================================ # 6) Write the new config (screen_name + server details) # ============================================================ echo "▶ Writing new player configuration..." mkdir -p "$CONFIG_DIR" CFG_PATH="$CONFIG_FILE" \ NEW_SCREEN_NAME="$NEW_NAME" \ NEW_SERVER_IP="$NEW_SERVER" \ NEW_PORT="$NEW_PORT" \ NEW_KEY="$NEW_KEY" \ NEW_USE_HTTPS="$NEW_USE_HTTPS" \ NEW_VERIFY_SSL="$NEW_VERIFY_SSL" \ "$PYTHON_BIN" <<'PYEOF' import json, os cfg_path = os.environ['CFG_PATH'] try: with open(cfg_path) as f: cfg = json.load(f) except Exception: cfg = {} updates = { 'screen_name': os.environ.get('NEW_SCREEN_NAME', ''), 'server_ip': os.environ.get('NEW_SERVER_IP', ''), 'port': os.environ.get('NEW_PORT', ''), 'quickconnect_key': os.environ.get('NEW_KEY', ''), } for key, val in updates.items(): if val != '': cfg[key] = val if os.environ.get('NEW_USE_HTTPS', '') != '': cfg['use_https'] = os.environ['NEW_USE_HTTPS'].lower() == 'true' if os.environ.get('NEW_VERIFY_SSL', '') != '': cfg['verify_ssl'] = os.environ['NEW_VERIFY_SSL'].lower() == 'true' # Safe defaults for anything missing cfg.setdefault('port', '8080') cfg.setdefault('orientation', 'Landscape') cfg.setdefault('touch', 'True') cfg.setdefault('max_resolution', '1920x1080') cfg.setdefault('edit_feature_enabled', True) cfg.setdefault('use_https', False) cfg.setdefault('verify_ssl', False) with open(cfg_path, 'w') as f: json.dump(cfg, f, indent=2) f.write('\n') print(json.dumps(cfg, indent=2)) PYEOF ok "Configuration updated" echo "" # ============================================================ # 7) Optionally align the OS hostname with the screen name # ============================================================ if [ "$SET_HOSTNAME" = true ] && [ -n "$NEW_NAME" ]; then SAFE_HOST="$(echo "$NEW_NAME" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9-' '-' | sed 's/-\+$//')" echo "▶ Setting OS hostname to '$SAFE_HOST' (player identity is still 'screen_name')..." if command -v hostnamectl >/dev/null 2>&1; then sudo hostnamectl set-hostname "$SAFE_HOST" 2>/dev/null \ && ok "OS hostname set to $SAFE_HOST" \ || warn "Could not set OS hostname (needs sudo)" else echo "$SAFE_HOST" | sudo tee /etc/hostname >/dev/null 2>&1 \ && ok "OS hostname file updated" \ || warn "Could not write /etc/hostname (needs sudo)" fi warn "A reboot is recommended for the hostname change to fully apply." echo "" fi # ============================================================ # 8) Mark the card as set up + summary # ============================================================ { echo "Post-clone setup completed: $(date '+%Y-%m-%d %H:%M:%S')" echo "screen_name: $NEW_NAME" echo "server_ip: $NEW_SERVER" echo "port: $NEW_PORT" echo "backup: $BACKUP_DIR" } > "$MARKER_FILE" echo "==========================================" echo "✓ Card is ready to connect to the server" echo "==========================================" echo "" echo " Player name : $NEW_NAME" echo " Server : $NEW_SERVER:$NEW_PORT" echo " Backup : $BACKUP_DIR" echo "" echo " Next steps:" echo " 1. (Optional) reboot: sudo reboot" echo " 2. Start the player: ./start.sh" echo "" echo " The player will authenticate as a NEW player '$NEW_NAME'" echo " and fetch its own playlist from the server." echo ""