Created
November 29, 2025 14:30
-
-
Save hrdtbs/3e3ab8bfa454f3f5999051b12d6bf270 to your computer and use it in GitHub Desktop.
XR Animator Auto-Update Launcher
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -euo pipefail | |
| # Constants | |
| readonly BASE_DIR="${XR_ANIMATOR_DIR:-./XR-Animator}" | |
| readonly API_URL="https://api.github.com/repos/ButzYung/SystemAnimatorOnline/releases/latest" | |
| readonly VERSION_FILE="${BASE_DIR}/.version" | |
| readonly CONFIG_FILE_NAME="XR Animator.js" | |
| # Global variables | |
| PLATFORM="" | |
| RELEASE_JSON="" | |
| LATEST_TAG="" | |
| LATEST_VERSION="" | |
| # Cleanup on error | |
| cleanup() { | |
| local exit_code=$? | |
| if [ -n "${TEMP_DIR:-}" ] && [ -d "${TEMP_DIR:-}" ]; then | |
| rm -rf "${TEMP_DIR}" 2>/dev/null || true | |
| fi | |
| if [ -n "${ZIP_FILE:-}" ] && [ -f "${ZIP_FILE:-}" ]; then | |
| rm -f "${ZIP_FILE}" 2>/dev/null || true | |
| fi | |
| exit "${exit_code}" | |
| } | |
| trap cleanup EXIT INT TERM | |
| # Detect platform | |
| detect_platform() { | |
| case "$(uname -s)" in | |
| MINGW*|MSYS*|CYGWIN*) | |
| PLATFORM="windows" | |
| ;; | |
| Linux*) | |
| PLATFORM="linux" | |
| ;; | |
| Darwin*) | |
| PLATFORM="macOS" | |
| ;; | |
| *) | |
| echo "Error: Unsupported OS" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| } | |
| # Extract version number from tag name | |
| extract_version_from_tag() { | |
| local tag="$1" | |
| echo "${tag}" | sed -n 's/.*v\([0-9.]*\)/\1/p' | sed 's/^/v/' | |
| } | |
| # Fetch latest release information | |
| fetch_latest_release() { | |
| if [ -z "${RELEASE_JSON:-}" ]; then | |
| RELEASE_JSON=$(curl -sf "${API_URL}" || { | |
| echo "Error: Failed to fetch release information from GitHub API" >&2 | |
| exit 1 | |
| }) | |
| LATEST_TAG=$(echo "${RELEASE_JSON}" | jq -r '.tag_name // empty') | |
| if [ -z "${LATEST_TAG}" ]; then | |
| echo "Error: Failed to get release tag" >&2 | |
| exit 1 | |
| fi | |
| LATEST_VERSION=$(extract_version_from_tag "${LATEST_TAG}") | |
| fi | |
| } | |
| # Get current version | |
| get_current_version() { | |
| if [ -f "${VERSION_FILE}" ]; then | |
| cat "${VERSION_FILE}" | tr -d '[:space:]' | |
| fi | |
| } | |
| # Check if existing installation exists | |
| check_existing_installation() { | |
| find "${BASE_DIR}" -maxdepth 1 -type d -name "XR Animator - electron-*" 2>/dev/null | head -n 1 | |
| } | |
| # Check if update is needed | |
| check_update_needed() { | |
| local current_version | |
| current_version=$(get_current_version) | |
| local electron_dir | |
| electron_dir=$(check_existing_installation) | |
| if [ -z "${current_version}" ]; then | |
| # .version file does not exist | |
| fetch_latest_release | |
| if [ -n "${electron_dir}" ]; then | |
| # Existing installation found, assume it matches latest version | |
| echo "${LATEST_VERSION}" > "${VERSION_FILE}" | |
| return 1 # No update needed | |
| else | |
| return 0 # Update needed | |
| fi | |
| else | |
| # Current version exists, compare with latest tag | |
| fetch_latest_release | |
| if [ "${current_version}" != "${LATEST_VERSION}" ]; then | |
| return 0 # Update needed | |
| else | |
| return 1 # No update needed | |
| fi | |
| fi | |
| } | |
| # Get download URL | |
| get_download_url() { | |
| fetch_latest_release | |
| echo "${RELEASE_JSON}" | jq -r ".assets[] | select(.name | contains(\"${PLATFORM}\")) | .browser_download_url" | head -n 1 | |
| } | |
| # Copy config file | |
| copy_config_file() { | |
| local old_gadget="$1" | |
| local new_gadget="$2" | |
| if [ -z "${old_gadget}" ] || [ -z "${new_gadget}" ] || [ "${old_gadget}" = "${new_gadget}" ]; then | |
| return 0 | |
| fi | |
| local old_config="${old_gadget}/TEMP/_config_local/${CONFIG_FILE_NAME}" | |
| local new_config="${new_gadget}/TEMP/_config_local/${CONFIG_FILE_NAME}" | |
| if [ -f "${old_config}" ] && [ ! -f "${new_config}" ]; then | |
| mkdir -p "$(dirname "${new_config}")" | |
| cp "${old_config}" "${new_config}" | |
| fi | |
| } | |
| # Perform update | |
| perform_update() { | |
| local download_url="$1" | |
| if [ -z "${download_url}" ]; then | |
| echo "Error: Failed to get download URL" >&2 | |
| exit 1 | |
| fi | |
| fetch_latest_release | |
| # Temporary directory and ZIP file paths | |
| ZIP_FILE="${BASE_DIR}/update.zip" | |
| TEMP_DIR="${BASE_DIR}/.update_temp" | |
| # Download | |
| echo "Downloading latest version..." | |
| curl -sfSL -o "${ZIP_FILE}" "${download_url}" || { | |
| echo "Error: Download failed" >&2 | |
| exit 1 | |
| } | |
| # Extract to temporary directory | |
| rm -rf "${TEMP_DIR}" | |
| mkdir -p "${TEMP_DIR}" | |
| unzip -q "${ZIP_FILE}" -d "${TEMP_DIR}" || { | |
| echo "Error: Failed to extract ZIP file" >&2 | |
| exit 1 | |
| } | |
| rm -f "${ZIP_FILE}" | |
| # Backup config file (before update) | |
| local old_gadget | |
| old_gadget=$(find "${BASE_DIR}" -maxdepth 1 -type d -name "AT_SystemAnimator_*" 2>/dev/null | sort | head -n 1) | |
| # Remove old directories | |
| echo "Removing old files..." | |
| find "${BASE_DIR}" -maxdepth 1 -type d -name "XR Animator - electron-*" -exec rm -rf {} \; 2>/dev/null || true | |
| find "${BASE_DIR}" -maxdepth 1 -type d -name "AT_SystemAnimator_*" -exec rm -rf {} \; 2>/dev/null || true | |
| find "${BASE_DIR}" -maxdepth 1 -type d -name "accessories" -exec rm -rf {} \; 2>/dev/null || true | |
| # Move new files | |
| echo "Installing new files..." | |
| find "${TEMP_DIR}" -maxdepth 1 -type d -name "XR Animator - electron-*" -exec mv {} "${BASE_DIR}/" \; 2>/dev/null || true | |
| find "${TEMP_DIR}" -maxdepth 1 -type d -name "AT_SystemAnimator_*" -exec mv {} "${BASE_DIR}/" \; 2>/dev/null || true | |
| if [ -d "${TEMP_DIR}/accessories" ]; then | |
| [ -d "${BASE_DIR}/accessories" ] && rm -rf "${BASE_DIR}/accessories" | |
| mv "${TEMP_DIR}/accessories" "${BASE_DIR}/" | |
| fi | |
| if [ -f "${TEMP_DIR}/readme.txt" ]; then | |
| mv "${TEMP_DIR}/readme.txt" "${BASE_DIR}/" 2>/dev/null || true | |
| fi | |
| # Remove temporary directory | |
| rm -rf "${TEMP_DIR}" | |
| # Copy config file (after update) | |
| local new_gadget | |
| new_gadget=$(find "${BASE_DIR}" -maxdepth 1 -type d -name "AT_SystemAnimator_*" 2>/dev/null | sort | tail -n 1) | |
| if [ -n "${old_gadget}" ] && [ -n "${new_gadget}" ]; then | |
| copy_config_file "${old_gadget}" "${new_gadget}" | |
| fi | |
| # Update .version file | |
| echo "${LATEST_VERSION}" > "${VERSION_FILE}" | |
| echo "Update completed: ${LATEST_VERSION}" | |
| } | |
| # Find Electron executable | |
| find_electron_executable() { | |
| local electron_dir="$1" | |
| local exe_path="${electron_dir}/electron.exe" | |
| if [ ! -f "${exe_path}" ]; then | |
| exe_path=$(find "${electron_dir}" -maxdepth 1 -type f \( -name "electron" -o -name "electron.exe" \) 2>/dev/null | head -n 1) | |
| fi | |
| if [ -z "${exe_path}" ] || [ ! -f "${exe_path}" ]; then | |
| echo "Error: Electron executable not found" >&2 | |
| exit 1 | |
| fi | |
| echo "${exe_path}" | |
| } | |
| # Main function | |
| main() { | |
| # Check required commands | |
| for cmd in curl jq unzip find; do | |
| if ! command -v "${cmd}" >/dev/null 2>&1; then | |
| echo "Error: Command '${cmd}' not found" >&2 | |
| exit 1 | |
| fi | |
| done | |
| detect_platform | |
| # Check for updates | |
| if check_update_needed; then | |
| local download_url | |
| download_url=$(get_download_url) | |
| if [ -z "${download_url}" ]; then | |
| echo "Error: Download URL for ${PLATFORM} not found" >&2 | |
| exit 1 | |
| fi | |
| perform_update "${download_url}" | |
| else | |
| echo "No update needed" | |
| fi | |
| # Launch Electron | |
| local electron_dir | |
| electron_dir=$(find "${BASE_DIR}" -maxdepth 1 -type d -name "XR Animator - electron-*" 2>/dev/null | sort | tail -n 1) | |
| if [ -z "${electron_dir}" ]; then | |
| echo "Error: Electron directory not found" >&2 | |
| exit 1 | |
| fi | |
| local electron_exe | |
| electron_exe=$(find_electron_executable "${electron_dir}") | |
| exec "${electron_exe}" "$@" | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment