Simple server jar updater (bash)

Tau

New member
Jan 12, 2022
26
8
3
I just updated it to v3, thought I'd share this rather than keep it to myself.
Don't expect support for this.

Code:
#!/usr/bin/env bash

#
# A simple jar updater script you can run on every startup.
# By default, it only attempts an update if the server jar is missing or 
# more than half a day has passed since the last update.
#
# Requirements: curl, jq, bash, sha256sum, stat
#
# Usage: -h
#
# Author: Tau ([email protected], [email protected])
#

# Check we have all dependencies
for cmd in curl jq sha256sum stat; do
  command -v $cmd >/dev/null 2>&1 || { echo "$cmd is required but not installed."; exit 1; }
done

PROJECT="paper"

# Defaults
MINECRAFT_VERSION_DEF="1.21.6"
STABLE_ONLY_DEF="false"
SERVER_JAR_PATH_DEF="server.jar"
JAR_AGE_DEF=43200 # Half a day

# Do not change
MINECRAFT_VERSION="$MINECRAFT_VERSION_DEF"
STABLE_ONLY="$STABLE_ONLY_DEF"
SERVER_JAR_PATH="$SERVER_JAR_PATH_DEF"
JAR_AGE="$JAR_AGE_DEF"

USER_AGENT="User-Agent: taucu-jar-updater/1.0.0"

while getopts "v:s:j:a:h" opt; do
  case $opt in
    v) MINECRAFT_VERSION="$OPTARG" ;;
    s) STABLE_ONLY="$OPTARG" ;;
    j) SERVER_JAR_PATH="$OPTARG" ;;
    a) JAR_AGE="$OPTARG" ;;
    h)
      echo "Usage: $0 [-v version] [-s true|false] [-j path] [-a seconds]"
      echo "  -v <version>     Target Minecraft version             def: $MINECRAFT_VERSION_DEF"
      echo "  -s <true|false>  Only update to stable releases       def: $STABLE_ONLY_DEF"
      echo "  -j <path>        Path of the jar to update            def: $SERVER_JAR_PATH_DEF"
      echo "  -a <seconds|-1>  Only update if jar is older than -a  def: $JAR_AGE_DEF"
      exit 0
      ;;
    \?)
      echo "Invalid option: -$OPTARG"
      exit 1
      ;;
  esac
done

# Parse/check variables
if ! [[ "$JAR_AGE" =~ ^-?[0-9]+$ ]]; then
  echo "Error: -a must be a number. Got: $JAR_AGE"
  exit 1
fi
STABLE_ONLY="${STABLE_ONLY,,}"
if [[ "$STABLE_ONLY" != "true" && "$STABLE_ONLY" != "false" ]]; then
  echo "Error: -s must be a true or false. Got: $STABLE_ONLY"
  exit 1
fi

# Only update if the jar doesn't exist or is older than JAR_AGE
if (( JAR_AGE > -1 )); then
    CURTIME=$(date +%s)
    if [ -f "$SERVER_JAR_PATH" ]; then
        FILETIME=$(stat -c %Y "$SERVER_JAR_PATH")
        TIMEDIFF=$((CURTIME - FILETIME))
        if (( TIMEDIFF < JAR_AGE )); then
            echo "Server jar updated recently: $TIMEDIFF seconds ago; Skipping update."
            exit 0
        fi
    fi
fi

# Get available builds
AVAILABLE_BUILDS=$(curl -sSf --retry 3 --retry-delay 5 -H "${USER_AGENT}" "https://fill.papermc.io/v3/projects/${PROJECT}/versions/${MINECRAFT_VERSION}/builds") || {
    echo "Error: Failed to fetch builds from PaperMC API"
    exit 1
}

# Parse/check response
if ! echo "$AVAILABLE_BUILDS" | jq empty 2>/dev/null; then
    echo "Error: Received invalid JSON"
    echo "Got: $AVAILABLE_BUILDS"
    exit 1
fi

# Get latest build
if [ "$STABLE_ONLY" = "true" ]; then
    echo "Checking for updates... (stable only)"
    LATEST_BUILD=$(echo "$AVAILABLE_BUILDS" | jq 'first(.[] | map(select(.channel == "STABLE")))')
else
    echo "Checking for updates..."
    LATEST_BUILD=$(echo "$AVAILABLE_BUILDS" | jq 'first(.[])')
fi

# Parse/check response
if [ "$LATEST_BUILD" = "null" ] || [ -z "$LATEST_BUILD" ]; then
  echo "Couldn't find a build for: [$MINECRAFT_VERSION, stable: $STABLE_ONLY]"
  exit 1
fi

# Resolve build number, hash and download url
LATEST_BUILD_NUM=$(echo "$LATEST_BUILD" | jq -r '.id')
EXPECTED_HASH=$(echo "$LATEST_BUILD" | jq -r '.downloads."server:default".checksums.sha256')
LATEST_BUILD_DL_URL=$(echo "$LATEST_BUILD" | jq -r '.downloads."server:default".url')

# Download jar
echo "Downloading: $LATEST_BUILD_DL_URL"
curl -Sf --retry 3 --retry-delay 5 -H "${USER_AGENT}" -o "$SERVER_JAR_PATH.tmp" "$LATEST_BUILD_DL_URL"

# Compute the hash
FILE_HASH=$(sha256sum "$SERVER_JAR_PATH.tmp" | awk '{print $1}')

# Verify the hash and move the jar
if [ "$EXPECTED_HASH" = "$FILE_HASH" ]; then
    if [ -f "$SERVER_JAR_PATH" ]; then
        mv -f "$SERVER_JAR_PATH" "$SERVER_JAR_PATH.old"
    fi
    mv -f "$SERVER_JAR_PATH.tmp" "$SERVER_JAR_PATH"
    echo "Server jar updated to: ${MINECRAFT_VERSION}-$LATEST_BUILD_NUM"
else
    echo "Hash mismatch! Update failed."
    echo "Expected: $EXPECTED_HASH"
    echo "Actual:   $FILE_HASH"
    exit 1
fi

exit 0