dotfiles

My PC Dotfiles & Website

scripts/mods.sh (3575B)


  1#! /usr/bin/env nix
  2#! nix shell nixpkgs#bash nixpkgs#cacert nixpkgs#coreutils nixpkgs#curl nixpkgs#jq nixpkgs#nix -c bash
  3
  4set -euo pipefail
  5
  6# Script to automatically update Minecraft Server Mods from Modrinth #
  7
  8API="https://api.modrinth.com/v2"
  9COMMIT_PREFIX="chore(mc-server): Update"
 10
 11# Locate mod metadata file
 12SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 13DATA="${MODS_FILE:-${SCRIPT_DIR}/../modules/games/mc-server/_mods.nix}"
 14
 15if [[ ! -f "${DATA}" ]]
 16then
 17  echo "Mod metadata file not found: '${DATA}'"
 18  exit 1
 19fi
 20
 21export CURL_CA_BUNDLE="${CURL_CA_BUNDLE:-$(nix eval --raw nixpkgs#cacert)/etc/ssl/certs/ca-bundle.crt}"
 22
 23# Tracking
 24declare -a UNAVAILABLE=()
 25updated=0
 26uptodate=0
 27
 28# Fetch latest version metadata for a project, target loader and game version
 29latest() {
 30  local id="${1}" loader="${2}" version="${3}"
 31  curl -s -G "${API}/project/${id}/version" \
 32    --data-urlencode "loaders=[\"${loader}\"]" \
 33    --data-urlencode "game_versions=[\"${version}\"]" \
 34    | jq -r '
 35        (sort_by(.date_published) | reverse | .[0]) as $v
 36        | if $v == null then empty
 37          else (($v.files | map(select(.primary)) + .)[0]) as $f
 38            | if $f == null then empty else "\($f.url)\t\($f.hashes.sha512)" end
 39          end
 40      ' 2>/dev/null || true
 41}
 42
 43# Update every mod of a loader
 44process_loader() {
 45  local loader="${1}" json version count
 46  json="$(nix eval --json -f "${DATA}" "${loader}" 2>/dev/null || true)"
 47
 48  if [[ -z "${json}" || "${json}" == "null" ]]
 49  then
 50    return 0
 51  fi
 52
 53  version="$(echo "${json}" | jq -r '.version')"
 54  count="$(echo "${json}" | jq -r '.mods | length')"
 55
 56  echo "==> Loader '${loader}' (Minecraft ${version}): ${count} mods"
 57
 58  local i name id oldurl oldhash result newurl sha512 newhash
 59  for ((i = 0; i < count; i++))
 60  do
 61    name="$(echo "${json}" | jq -r ".mods[${i}].name")"
 62    id="$(echo "${json}" | jq -r ".mods[${i}].id")"
 63    oldurl="$(echo "${json}" | jq -r ".mods[${i}].url")"
 64    oldhash="$(echo "${json}" | jq -r ".mods[${i}].hash")"
 65
 66    result="$(latest "${id}" "${loader}" "${version}")"
 67    newurl="$(echo "${result}" | cut -f1)"
 68    sha512="$(echo "${result}" | cut -f2)"
 69
 70    if [[ -z "${result}" || "${newurl}" == "null" || -z "${newurl}" || "${sha512}" == "null" ]]
 71    then
 72      echo "  ✗ ${name}: no build for Minecraft ${version}"
 73      UNAVAILABLE+=("${name} (${loader} ${version})")
 74      continue
 75    fi
 76
 77    if [[ "${newurl}" == "${oldurl}" ]]
 78    then
 79      echo "  = ${name}: up to date"
 80      ((uptodate += 1)) || true
 81      continue
 82    fi
 83
 84    newhash="$(nix hash convert --hash-algo sha512 --to sri "${sha512}")"
 85
 86    sed -i "s|${oldurl}|${newurl}|" "${DATA}"
 87    sed -i "s|${oldhash}|${newhash}|" "${DATA}"
 88
 89    echo "  ↑ ${name}: updated"
 90    ((updated += 1)) || true
 91  done
 92
 93  # Commit per loader
 94  if [[ "${COMMIT:-true}" == "true" ]]
 95  then
 96    git -C "$(dirname "${DATA}")" diff-index --quiet HEAD "${DATA}" 2>/dev/null || \
 97      git -C "$(dirname "${DATA}")" commit -q -n "${DATA}" \
 98        -m "${COMMIT_PREFIX} \`${loader}\` mods" || true
 99  fi
100}
101
102# Execution
103echo "Checking for Mod Updates..."
104
105# Iterate over every defined loader
106mapfile -t LOADERS < <(nix eval --json -f "${DATA}" 2>/dev/null | jq -r 'keys[]')
107for loader in "${LOADERS[@]}"
108do
109  process_loader "${loader}"
110done
111
112# Summary
113echo
114echo "Summary: ${updated} updated, ${uptodate} up to date, ${#UNAVAILABLE[@]} unavailable"
115if (( ${#UNAVAILABLE[@]} > 0 ))
116then
117  echo "Could not update to the target Minecraft version:"
118  for m in "${UNAVAILABLE[@]}"
119  do
120    echo "  - ${m}"
121  done
122fi