#!/usr/bin/env bash # Stormux Installation Helper # Provides automatic installation with speech feedback and progress indicators # Configuration GAMES_REGISTRY="/usr/share/stormux/downloadable_games.json" PACKAGES_REGISTRY="/usr/share/stormux/installable_packages.json" LOG_DIR="$HOME/Logs" LOG_FILE="$LOG_DIR/installer.log" INSTALL_BASE="$HOME/.local/games" NVDA_DLL_SOURCE="$HOME/.local/games/nvda" # Initialize logging init_logging() { mkdir -p "$LOG_DIR" # Clear previous log and start fresh echo "=== Installation started at $(date) ===" > "$LOG_FILE" } # Speech output speak() { local message="$1" echo "$message" >> "$LOG_FILE" spd-say "$message" 2>/dev/null || echo "$message" } # Progress beep progress_beep() { # Simple beep using speaker-test or paplay if command -v paplay &> /dev/null && [[ -f /usr/share/sounds/freedesktop/stereo/message.oga ]]; then paplay /usr/share/sounds/freedesktop/stereo/message.oga 2>/dev/null & fi } # Download with progress feedback download_with_progress() { local url="$1" local output="$2" local name="$3" speak "Downloading $name" echo "Downloading from: $url" >> "$LOG_FILE" # Start background process for progress beeps ( while kill -0 $$ 2>/dev/null; do sleep 5 progress_beep done ) & local beep_pid=$! # Download with curl if curl -L -f --progress-bar -o "$output" "$url" 2>> "$LOG_FILE"; then kill $beep_pid 2>/dev/null wait $beep_pid 2>/dev/null echo "Download successful" >> "$LOG_FILE" return 0 else kill $beep_pid 2>/dev/null wait $beep_pid 2>/dev/null echo "Download failed" >> "$LOG_FILE" return 1 fi } # Replace NVDA DLLs in game directory replace_nvda_dlls() { local game_dir="$1" if [[ ! -d "$NVDA_DLL_SOURCE" ]]; then echo "Warning: NVDA DLL source directory not found" >> "$LOG_FILE" return 0 fi # Replace all NVDA DLLs { find "$game_dir" -type f -name "nvdaControllerClient32.dll" -exec cp -v "$NVDA_DLL_SOURCE/nvdaControllerClient32.dll" '{}' \; find "$game_dir" -type f -name "nvdaControllerClient64.dll" -exec cp -v "$NVDA_DLL_SOURCE/nvdaControllerClient64.dll" '{}' \; find "$game_dir" -type f -name "nvdaControllerClient.dll" -exec cp -v "$NVDA_DLL_SOURCE/nvdaControllerClient64.dll" '{}' \; } >> "$LOG_FILE" 2>&1 } # Extract and setup game from ZIP setup_game_zip() { local zipfile="$1" local game_dir="$2" local game_name="$3" speak "Installing $game_name" echo "Extracting to: $game_dir" >> "$LOG_FILE" # Remove old installation rm -rf "$game_dir" mkdir -p "$game_dir" # Extract to temp location first to handle any ZIP structure local temp_extract="/tmp/stormux_install_$$" mkdir -p "$temp_extract" if ! unzip -q "$zipfile" -d "$temp_extract" 2>> "$LOG_FILE"; then echo "Extraction failed" >> "$LOG_FILE" rm -rf "$temp_extract" return 2 fi # Check if everything extracted into a single subdirectory local extracted_items extracted_items=("$temp_extract"/*) if [[ ${#extracted_items[@]} -eq 1 ]] && [[ -d "${extracted_items[0]}" ]]; then # Single directory - move its contents to game_dir echo "Single directory extracted, moving contents" >> "$LOG_FILE" mv "${extracted_items[0]}"/* "$game_dir/" 2>> "$LOG_FILE" else # Multiple items or single file - move everything echo "Multiple items extracted, moving all" >> "$LOG_FILE" mv "$temp_extract"/* "$game_dir/" 2>> "$LOG_FILE" fi rm -rf "$temp_extract" # Replace NVDA DLLs replace_nvda_dlls "$game_dir" # Clean up temp file rm -f "$zipfile" echo "Installation complete" >> "$LOG_FILE" return 0 } # Install system package via yay install_system_package() { local package="$1" local name="$2" speak "Installing $name" echo "Installing package: $package" >> "$LOG_FILE" if yay -Sy --noconfirm "$package" >> "$LOG_FILE" 2>&1; then echo "Package installation successful" >> "$LOG_FILE" return 0 else echo "Package installation failed" >> "$LOG_FILE" speak "Installation of $name failed. Check logs." return 1 fi } # Check if game is installed is_game_installed() { local game_dir="$1" local executable="$2" [[ -e "$game_dir/$executable" ]] } # Check if package is installed is_package_installed() { local verify_command="$1" eval "$verify_command" &>/dev/null } # Auto-install: Main function # Usage: auto_install # Returns: 0 if ready to launch, non-zero on failure auto_install() { local item_id="$1" init_logging # Try to find in games registry if [[ -f "$GAMES_REGISTRY" ]]; then echo "Reading games registry: $GAMES_REGISTRY" >> "$LOG_FILE" local game_info game_info=$(jq -r ".downloadable_games[\"$item_id\"] // empty" "$GAMES_REGISTRY" 2>> "$LOG_FILE") echo "Game info result: ${game_info:-empty}" >> "$LOG_FILE" if [[ -n "$game_info" ]]; then local name url directory executable game_dir name=$(echo "$game_info" | jq -r '.name') url=$(echo "$game_info" | jq -r '.url') directory=$(echo "$game_info" | jq -r '.directory') executable=$(echo "$game_info" | jq -r '.executable') game_dir="$INSTALL_BASE/$directory" # Check if already installed if is_game_installed "$game_dir" "$executable"; then echo "Game already installed: $name" >> "$LOG_FILE" return 0 fi # Download and install local temp_zip="/tmp/${directory}_download.zip" if download_with_progress "$url" "$temp_zip" "$name"; then if setup_game_zip "$temp_zip" "$game_dir" "$name"; then # Verify installation if is_game_installed "$game_dir" "$executable"; then speak "Installation complete" return 0 else speak "Installation failed. Executable not found." echo "Error: Executable not found after installation: $executable" >> "$LOG_FILE" return 3 fi else speak "Installation failed. Could not extract game." return 2 fi else speak "Download failed. Check your internet connection." return 1 fi fi fi # Try to find in packages registry if [[ -f "$PACKAGES_REGISTRY" ]]; then local package_info package_info=$(jq -r ".installable_packages[\"$item_id\"] // empty" "$PACKAGES_REGISTRY" 2>/dev/null) if [[ -n "$package_info" ]]; then local name package verify_command name=$(echo "$package_info" | jq -r '.name') package=$(echo "$package_info" | jq -r '.package') verify_command=$(echo "$package_info" | jq -r '.verify_command') # Check if already installed if is_package_installed "$verify_command"; then echo "Package already installed: $name" >> "$LOG_FILE" return 0 fi # Install package if install_system_package "$package" "$name"; then speak "Installation complete" return 0 else return 1 fi fi fi # Item not found in any registry if [[ ! -f "$GAMES_REGISTRY" ]] && [[ ! -f "$PACKAGES_REGISTRY" ]]; then echo "Error: Registry files not found!" >> "$LOG_FILE" echo " Expected: $GAMES_REGISTRY" >> "$LOG_FILE" echo " Expected: $PACKAGES_REGISTRY" >> "$LOG_FILE" speak "Error: Installation registry files not found. This may be a development system." else echo "Error: Item not found in registries: $item_id" >> "$LOG_FILE" speak "Error: $item_id not found in installation registry" fi return 4 }