Skip to content

Instantly share code, notes, and snippets.

@hrdtbs
Created November 29, 2025 14:30
Show Gist options
  • Select an option

  • Save hrdtbs/3e3ab8bfa454f3f5999051b12d6bf270 to your computer and use it in GitHub Desktop.

Select an option

Save hrdtbs/3e3ab8bfa454f3f5999051b12d6bf270 to your computer and use it in GitHub Desktop.
XR Animator Auto-Update Launcher
#!/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