How to share your BTT and Mac specs easily

Sharing BTT version and Mac specs is critical to receive help from this community, especially given the recent Sequoia macOS update... but it's annoying to find, copy & paste.

**Device information:**
- Type of Mac:
- macOS version: 
- BetterTouchTool version: (please post the exact version - not just "the latest one")

I made this process easy by writing a script to automatically obtain this information.

Whenever I type /BTTD, it is replaced by:

Device: MacBook Pro (14-inch, 2021)
macOS: 15.0 (24A335)
BTT Version: 4.702 (2024091705)
Alpha: 6 update(s) behind latest Alpha version 4.709 (2024091807).
Regular: Installed version is ahead of latest Regular version 4.701.

After updating BTT to the latest Alpha version, if I type /BTTD, it gets replaced by:

Device: MacBook Pro (14-inch, 2021)
macOS: 15.0 (24A335)
BTT Version: 4.709 (2024091807)
Alpha: 0 update(s) behind latest Alpha version 4.709 (2024091807).
Regular: Installed version is ahead of latest Regular version 4.701.

Note: I use KM text replacement instead of Key Sequences in BTT because I find KM's text replacement more reliable.

Here's the script:
#!/bin/bash

###############################################################################
# BetterTouchTool Version Checker CLI
# A robust command-line interface (CLI) tool to check the installed version of
# BetterTouchTool (BTT) on macOS, compare it with the latest available alpha and
# regular (stable) versions, and provide a status update. It also retrieves
# system information and optionally copies the output to the clipboard.
#
# Usage:
#   ./btt_version_checker.sh [options]
#
# Options:
#   -v, --installed-version VERSION   Manually specify the installed BTT version number (e.g., 4.702)
#   -b, --installed-build BUILD       Manually specify the installed BTT build number (e.g., 2024091705)
#   -l, --log-level LEVEL             Set the logging level (NONE, ERROR, INFO, DEBUG). Default: NONE
#   -o, --output-format FORMAT        Set output format (markdown, plain, json). Default: markdown
#   -c, --copy                        Copy output to clipboard (enabled by default)
#   -n, --no-copy                     Do not copy output to clipboard
#   -h, --help                        Display this help message and exit
#
# Examples:
#   1. Run the script without arguments (auto-detect installed BTT version):
#      ./btt_version_checker.sh
#
#   2. Specify the installed BTT version and build manually:
#      ./btt_version_checker.sh -v 4.702 -b 2024091705
#
#   3. Set log level to DEBUG and output format to plain text:
#      ./btt_version_checker.sh -l DEBUG -o plain
#
#   4. Set output format to JSON and disable copying to clipboard:
#      ./btt_version_checker.sh -o json -n
#
# Notes:
# - The script requires internet access to fetch the latest BTT versions.
# - The output is formatted using Markdown by default.
# - The output is copied to the clipboard by default. Use '-n' to disable.
#
# Author: fortred2 https://community.folivora.ai/u/fortred2/summary
# Date: 2024-09-19
# Version: 1.0.0
###############################################################################

# Default configurations
log_level="NONE"           # Options: NONE, ERROR, INFO, DEBUG
output_format="markdown"   # Options: markdown, plain, json
copy_to_clipboard=true     # Set to false with '-n' or '--no-copy'

# Initialize variables for installed version and build
installed_version=""
installed_build=""

# Required utilities
required_utilities=(
  "curl"
  "grep"
  "awk"
  "sed"
  "ioreg"
  "defaults"
  "/usr/libexec/PlistBuddy"
  "sw_vers"
  "pbcopy"
)

# Function to display usage instructions
usage() {
  cat << EOF
Usage: $0 [options]

Options:
  -v, --installed-version VERSION   Manually specify the installed BTT version number (e.g., 4.702)
  -b, --installed-build BUILD       Manually specify the installed BTT build number (e.g., 2024091705)
  -l, --log-level LEVEL             Set the logging level (NONE, ERROR, INFO, DEBUG). Default: NONE
  -o, --output-format FORMAT        Set output format (markdown, plain, json). Default: markdown
  -c, --copy                        Copy output to clipboard (enabled by default)
  -n, --no-copy                     Do not copy output to clipboard
  -h, --help                        Display this help message and exit

Examples:
  $0                              # Auto-detect installed BTT version
  $0 -v 4.702 -b 2024091705       # Specify installed BTT version and build
  $0 -l DEBUG -o plain            # Set log level to DEBUG and output format to plain text
  $0 -o json -n                   # Set output format to JSON and do not copy to clipboard

EOF
  exit 1
}

# Function to map log levels to numeric values
log_level_num() {
  case "$1" in
    "NONE") echo -1 ;;
    "ERROR") echo 0 ;;
    "INFO") echo 1 ;;
    "DEBUG") echo 2 ;;
    *) echo -1 ;;  # Default to NONE
  esac
}

# Logging function
log() {
  local level=$1
  local message=$2
  local current_level
  current_level=$(log_level_num "$log_level")
  local message_level
  message_level=$(log_level_num "$level")

  if [ "$current_level" -ge "$message_level" ]; then
    echo "[$level] $message" >&2
  fi
}

# Function to check for required utilities and log their paths
check_requirements() {
  local missing_utilities=()
  for util in "${required_utilities[@]}"; do
    local util_path
    util_path=$(command -v "$util")
    if [ -x "$util_path" ]; then
      log "DEBUG" "Found utility '$util' at '$util_path'"
    else
      echo "ERROR" "Required utility '$util' not found in PATH."
      missing_utilities+=("$util")
    fi
  done

  if [ "${#missing_utilities[@]}" -ne 0 ]; then
    echo "ERROR" "The following required utilities are missing: ${missing_utilities[*]}"
    exit 1
  fi
}

# Function to compare version numbers
version_compare() {
  # Returns 1 if $1 > $2, 0 if equal, -1 if $1 < $2
  local ver1="$1"
  local ver2="$2"

  IFS='.' read -ra ver1_parts <<< "$ver1"
  IFS='.' read -ra ver2_parts <<< "$ver2"

  local max_index=$(( ${#ver1_parts[@]} > ${#ver2_parts[@]} ? ${#ver1_parts[@]} : ${#ver2_parts[@]} ))

  for ((i=0; i<max_index; i++)); do
    local part1=${ver1_parts[i]:-0}
    local part2=${ver2_parts[i]:-0}

    if ((10#$part1 > 10#$part2)); then
      echo 1
      return
    elif ((10#$part1 < 10#$part2)); then
      echo -1
      return
    fi
  done

  echo 0
}

# Function to fetch the installed BTT version
get_installed_version() {
  if [ -z "$installed_version" ] || [ -z "$installed_build" ]; then
    # Attempt to read the installed version from BTT's Info.plist
    installed_version=$(defaults read "/Applications/BetterTouchTool.app/Contents/Info.plist" CFBundleShortVersionString 2>/dev/null)
    installed_build=$(defaults read "/Applications/BetterTouchTool.app/Contents/Info.plist" CFBundleVersion 2>/dev/null)
  fi

  # Check if installed version and build are available
  if [ -z "$installed_version" ] || [ -z "$installed_build" ]; then
    echo "ERROR" "BetterTouchTool is not installed, Info.plist is inaccessible, or installed version/build not specified."
    exit 1
  fi

  installed_version_full="$installed_version ($installed_build)"
  installed_version_number="$installed_version"

  log "DEBUG" "Installed version is $installed_version_full"
}

# Function to fetch available alpha versions
fetch_alpha_versions() {
  log "INFO" "Fetching available alpha versions..."
  available_versions=$(curl -s https://folivora.ai/releases/ | grep -o 'btt[0-9]\+\.[0-9]\+-[0-9]\+\.zip' | sort -V | tail -r | uniq)
  formatted_versions=$(echo "$available_versions" | sed -E 's/btt([0-9]+\.[0-9]+)-([0-9]+)\.zip/\1 (\2)/')

  # Get the latest alpha version
  latest_alpha_version=$(echo "$formatted_versions" | head -n 1)

  log "DEBUG" "Available alpha versions: $(echo "$formatted_versions" | head -n 10 | tr '\n' ' ')"
}

# Function to determine alpha version status
determine_alpha_status() {
  # Find the index of the installed version in the list of available alpha versions
  installed_index=$(echo "$formatted_versions" | awk -v installed="$installed_version_full" '
  {
      if ($0 == installed) {
          print NR;
          exit
      }
  }')

  # Determine the alpha version status message
  if [ -z "$installed_index" ]; then
    echo "ERROR" "Installed version not found in available alpha versions."
    alpha_version_message="Installed alpha version not found."
  else
    log "DEBUG" "Installed version found at index $installed_index"
    alpha_updates_behind=$((installed_index - 1))
    alpha_version_message="$alpha_updates_behind update(s) behind latest Alpha version $latest_alpha_version."
  fi
}

# Function to fetch the latest regular version
fetch_regular_version() {
  log "INFO" "Fetching latest regular version..."
  regular_versions=$(curl -s https://updates.folivora.ai/bettertouchtool_release_notes.html | grep -Eo 'BetterTouchTool >= [0-9]+\.[0-9]+' | sed -E 's/BetterTouchTool >= //g' | sort -V)
  latest_regular_version=$(echo "$regular_versions" | tail -n 1)

  log "INFO" "Latest regular version: $latest_regular_version"
}

# Function to determine regular version status
determine_regular_status() {
  # Compare the installed version with the latest regular version
  comparison_result=$(version_compare "$installed_version_number" "$latest_regular_version")

  # Determine the regular version status message
  if [ "$comparison_result" -eq 0 ]; then
    regular_version_message="Up to date with latest Regular version $latest_regular_version."
  elif [ "$comparison_result" -eq 1 ]; then
    regular_version_message="Installed version is ahead of latest Regular version $latest_regular_version."
  else
    regular_version_message="Installed version is behind latest Regular version $latest_regular_version."
  fi

  log "INFO" "$regular_version_message"
}

# Function to retrieve system information
get_system_info() {
  device_info="$(/usr/libexec/PlistBuddy -c 'Print :0:product-name' /dev/stdin <<< "$(ioreg -arc IOPlatformDevice -k product-name)")"
  macos_version="$(sw_vers -productVersion) ($(sw_vers -buildVersion))"
}

# Function to generate output
generate_output() {
  if [ "$output_format" == "markdown" ]; then
    # Markdown format
    output_content=$(cat << EOF
- **Device**: $device_info
- **macOS**: $macos_version
- **BTT Version**: $installed_version_full
- **Alpha**: $alpha_version_message
- **Regular**: $regular_version_message
EOF
)
  elif [ "$output_format" == "plain" ]; then
    # Plain text format
    output_content=$(cat << EOF
Device: $device_info
macOS: $macos_version
BTT Version: $installed_version_full
Alpha: $alpha_version_message
Regular: $regular_version_message
EOF
)
  elif [ "$output_format" == "json" ]; then
    # JSON format
    # Use printf with double quotes and escape inner double quotes
    output_content=$(printf "{\n  \"Device\": \"%s\",\n  \"macOS\": \"%s\",\n  \"BTT_Version\": \"%s\",\n  \"Alpha\": \"%s\",\n  \"Regular\": \"%s\"\n}" \
      "$device_info" \
      "$macos_version" \
      "$installed_version_full" \
      "$alpha_version_message" \
      "$regular_version_message")
  else
    echo "ERROR" "Unsupported output format: $output_format"
    exit 1
  fi

  # Output the result
  echo "$output_content"

  # Copy to clipboard if enabled
  if [ "$copy_to_clipboard" = true ]; then
    echo "$output_content" | pbcopy
    log "INFO" "Output copied to clipboard."
  fi
}

# Parse command-line arguments
while [[ "$#" -gt 0 ]]; do
  case $1 in
    -v|--installed-version)
      installed_version="$2"
      shift 2
      ;;
    -b|--installed-build)
      installed_build="$2"
      shift 2
      ;;
    -l|--log-level)
      log_level="$2"
      shift 2
      ;;
    -o|--output-format)
      output_format="$2"
      shift 2
      ;;
    -c|--copy)
      copy_to_clipboard=true
      shift
      ;;
    -n|--no-copy)
      copy_to_clipboard=false
      shift
      ;;
    -h|--help)
      usage
      ;;
    *)
      echo "Unknown parameter passed: $1"
      usage
      ;;
  esac
done

# Validate log level
case "$log_level" in
  NONE|ERROR|INFO|DEBUG)
    # Valid log level
    ;;
  *)
    echo "Invalid log level: $log_level"
    usage
    ;;
esac

# Validate output format
case "$output_format" in
  markdown|plain|json)
    # Valid output format
    ;;
  *)
    echo "Invalid output format: $output_format"
    usage
    ;;
esac

# Check for required utilities and log their paths
check_requirements

# Main script execution
get_installed_version
fetch_alpha_versions
determine_alpha_status
fetch_regular_version
determine_regular_status
get_system_info
generate_output


Link to preset: BetterTouchTool Preset Sharing Platform

Test...

  • Device: MacBook Pro (14-inch, 2021)
  • macOS: 15.0 (24A335)
  • BTT Version: 4.709 (2024091807)
  • Alpha: 0 update(s) behind latest Alpha version 4.709 (2024091807).
  • Regular: Installed version is ahead of latest Regular version 4.701.