diff --git a/.env b/.env index 4d47841..5b8532f 100644 --- a/.env +++ b/.env @@ -7,11 +7,15 @@ export RCON_PASSWORD="" export POLL_SECONDS="10" export ANNOUNCE_SERVER_UPDOWN="true" +# Anzeigename/Tag +SERVER_NAME="[GER] Blockventure | ⌁25573" +SERVER_TAG="blockventure-25573" + # ntfy export NTFY_SERVER="https://ntfy.pushservice.techniverse.net" export NTFY_TOPIC="mc-events" export NTFY_TOKEN="" -export NTFY_TITLE_PREFIX="Minecraft" +export NTFY_TITLE_PREFIX="🟩 Minecraft" export NTFY_TAGS_BASE="minecraft" export NTFY_MARKDOWN="false" diff --git a/mc-ntfy-notify.v1.sh b/mc-ntfy-notify.v1.sh index 1bc4e88..558789e 100644 --- a/mc-ntfy-notify.v1.sh +++ b/mc-ntfy-notify.v1.sh @@ -4,20 +4,23 @@ # Autor: Patrick Asmus # Web: https://www.cleveradmin.de # Repository: https://git.techniverse.net/scriptos/minecraft-ntfy-notify -# Version: 1.3 +# Version: 1.4 # Datum: 18.09.2025 -# Modifikation: Cron-sicheres Locking (Lockdir+PID), Running-Mark, Cleanup via trap +# Modifikation: +# - Serverlabel/Tags (SERVER_NAME/SERVER_TAG) in Titel & ntfy-Tags +# - State-Verzeichnis per Instanz (Host:Port:Topic) +# - Optionales ENV_FILE zum Laden einer spezifischen .env ##################################################### set -euo pipefail - -# Robustes PATH für Cron export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -if [[ -f "${SCRIPT_DIR}/.env" ]]; then - set -a - . "${SCRIPT_DIR}/.env" - set +a + +# --- .env laden: zuerst ENV_FILE (falls gesetzt), sonst ./.env --- +if [[ -n "${ENV_FILE:-}" && -f "${ENV_FILE}" ]]; then + set -a; . "${ENV_FILE}"; set +a +elif [[ -f "${SCRIPT_DIR}/.env" ]]; then + set -a; . "${SCRIPT_DIR}/.env"; set +a fi # ===== Konfiguration via ENV ===== @@ -40,14 +43,20 @@ NTFY_PRIORITY_UP="${NTFY_PRIORITY_UP:-4}" NTFY_PRIORITY_DOWN="${NTFY_PRIORITY_DOWN:-5}" NTFY_MARKDOWN="${NTFY_MARKDOWN:-false}" -# State (standardmäßig im Script-Ordner, root-frei) -STATE_DIR="${STATE_DIR:-${SCRIPT_DIR}/state}" +# Server-Label/Tag +SERVER_NAME="${SERVER_NAME:-}" # z. B. "[GER] Blockventure | ⌁25573" +SERVER_LABEL="${SERVER_NAME:-${MC_HOST}:${RCON_PORT}}" +# Maschinenfreundlicher Tag, wenn nicht gesetzt: aus Name oder Host:Port ableiten +SERVER_TAG="${SERVER_TAG:-$(printf '%s' "${SERVER_NAME:-${MC_HOST}-${RCON_PORT}}" \ + | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g;s/^-+|-+$//g')}" + +# ==== Lock & State (pro Instanz eindeutig nach Host:Port:Topic) ==== +LOCK_KEY="$(printf '%s' "${MC_HOST}_${RCON_PORT}_${NTFY_TOPIC}" | tr -c 'A-Za-z0-9._-' '_')" +# eigenes State-Verzeichnis je Instanz (damit mehrere Server parallel sauber laufen) +STATE_DIR="${STATE_DIR:-${SCRIPT_DIR}/state.${LOCK_KEY}}" STATE_PLAYERS="${STATE_DIR}/players.prev" STATE_UP="${STATE_DIR}/server_up.prev" -# Lock & Running-Mark (pro MC_HOST:RCON_PORT:NTFY_TOPIC eindeutig) -# -> erlaubt mehrere parallele Instanzen für verschiedene Server/Topics -LOCK_KEY="$(printf '%s' "${MC_HOST}_${RCON_PORT}_${NTFY_TOPIC}" | tr -c 'A-Za-z0-9._-' '_')" RUN_DIR="${RUN_DIR:-${STATE_DIR}}" LOCK_DIR="${RUN_DIR}/lock.${LOCK_KEY}" PID_FILE="${LOCK_DIR}/pid" @@ -62,41 +71,28 @@ need_bin() { command -v "$1" >/dev/null 2>&1 || die "Benötigtes Tool fehlt: $1" dbg() { [[ "$DEBUG" == "true" ]] && echo "DBG: $*" >&2 || true; } cleanup() { - # Lauf-Mark und Lock sauber entfernen - rm -f "$RUN_MARK" 2>/dev/null || true - rm -f "$PID_FILE" 2>/dev/null || true + rm -f "$RUN_MARK" "$PID_FILE" 2>/dev/null || true rmdir "$LOCK_DIR" 2>/dev/null || true } acquire_lock() { mkdir -p "$RUN_DIR" - # Atomarer Lock-Versuch if mkdir "$LOCK_DIR" 2>/dev/null; then echo "$$" > "$PID_FILE" trap cleanup EXIT INT TERM - return 0 - fi - - # Lock existiert -> prüfen, ob Prozess noch lebt - if [[ -f "$PID_FILE" ]]; then - oldpid="$(cat "$PID_FILE" 2>/dev/null || true)" - if [[ -n "${oldpid:-}" ]] && kill -0 "$oldpid" 2>/dev/null; then - # Schon aktiv → leise beenden (Cron-safe) - dbg "Bereits laufend (PID $oldpid), beende." - exit 0 + else + if [[ -f "$PID_FILE" ]]; then + oldpid="$(cat "$PID_FILE" 2>/dev/null || true)" + if [[ -n "${oldpid:-}" ]] && kill -0 "$oldpid" 2>/dev/null; then + dbg "Bereits laufend (PID $oldpid), beende." + exit 0 + fi fi - fi - - # Stale Lock entfernen und erneut versuchen - rm -rf "$LOCK_DIR" 2>/dev/null || true - if mkdir "$LOCK_DIR" 2>/dev/null; then + rm -rf "$LOCK_DIR" 2>/dev/null || true + mkdir "$LOCK_DIR" 2>/dev/null || die "Konnte Lock nicht übernehmen: ${LOCK_DIR}" echo "$$" > "$PID_FILE" trap cleanup EXIT INT TERM - return 0 fi - - # Falls wir hier landen, ist wirklich etwas schief - die "Konnte Lock nicht übernehmen: ${LOCK_DIR}" } ntfy_notify() { @@ -131,23 +127,19 @@ get_players() { fi dbg "RAW: $out" out="$(printf '%s' "$out" | sanitize)" - if ! grep -q "players online:" <<<"$out"; then return 0 fi - local names="${out#*:}" names="$(echo "$names" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" if [[ -z "$names" ]]; then return 0 fi - printf '%s\n' "$names" \ | tr ',' '\n' \ | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' \ | sed '/^$/d' \ | LC_ALL=C sort -u - return 0 } @@ -158,14 +150,12 @@ need_bin mcrcon ensure_state acquire_lock -echo "Starte Polling ${MC_HOST}:${RCON_PORT} → ntfy ${NTFY_SERVER}/${NTFY_TOPIC} (PID $$)" +echo "Starte Polling ${MC_HOST}:${RCON_PORT} → ntfy ${NTFY_SERVER}/${NTFY_TOPIC} (PID $$) [${SERVER_LABEL}]" prev_up="$(cat "$STATE_UP")" # ===== Main Loop ===== while :; do - # Running-Mark aktualisieren (für Monitoring/„läuft“-Check) - date -Iseconds > "$RUN_MARK" - echo "$$" >> "$RUN_MARK" + date -Iseconds > "$RUN_MARK"; echo "$$" >> "$RUN_MARK" tmp_players="$(mktemp)" if get_players >"$tmp_players"; then @@ -177,36 +167,35 @@ while :; do if [[ "$ANNOUNCE_SERVER_UPDOWN" == "true" && "$prev_up" != "unknown" && "$server_up" != "$prev_up" ]]; then if [[ "$server_up" == "true" ]]; then - ntfy_notify "${NTFY_TITLE_PREFIX}: Server up" \ + ntfy_notify "${NTFY_TITLE_PREFIX}: Server up — ${SERVER_LABEL}" \ "Server ist wieder erreichbar (${MC_HOST}:${RCON_PORT})." \ - "${NTFY_TAGS_BASE},up" "$NTFY_PRIORITY_UP" || true + "${NTFY_TAGS_BASE},${SERVER_TAG},up" "$NTFY_PRIORITY_UP" || true else - ntfy_notify "${NTFY_TITLE_PREFIX}: Server down" \ + ntfy_notify "${NTFY_TITLE_PREFIX}: Server down — ${SERVER_LABEL}" \ "Server ist nicht erreichbar (${MC_HOST}:${RCON_PORT})." \ - "${NTFY_TAGS_BASE},down" "$NTFY_PRIORITY_DOWN" || true + "${NTFY_TAGS_BASE},${SERVER_TAG},down" "$NTFY_PRIORITY_DOWN" || true fi fi if [[ "$server_up" == "true" ]]; then LC_ALL=C sort -u "$STATE_PLAYERS" -o "$STATE_PLAYERS" - joined="$(comm -13 "$STATE_PLAYERS" "$tmp_players" || true)" left="$(comm -23 "$STATE_PLAYERS" "$tmp_players" || true)" if [[ -n "$joined" ]]; then while IFS= read -r name; do [[ -z "$name" ]] && continue - ntfy_notify "${NTFY_TITLE_PREFIX}: Join" \ + ntfy_notify "${NTFY_TITLE_PREFIX}: Join — ${SERVER_LABEL}" \ "Player \"${name}\" ist beigetreten." \ - "${NTFY_TAGS_BASE},join" "$NTFY_PRIORITY_JOIN" || true + "${NTFY_TAGS_BASE},${SERVER_TAG},join" "$NTFY_PRIORITY_JOIN" || true done <<<"$joined" fi if [[ -n "$left" ]]; then while IFS= read -r name; do [[ -z "$name" ]] && continue - ntfy_notify "${NTFY_TITLE_PREFIX}: Leave" \ + ntfy_notify "${NTFY_TITLE_PREFIX}: Leave — ${SERVER_LABEL}" \ "Player \"${name}\" hat den Server verlassen." \ - "${NTFY_TAGS_BASE},leave" "$NTFY_PRIORITY_LEAVE" || true + "${NTFY_TAGS_BASE},${SERVER_TAG},leave" "$NTFY_PRIORITY_LEAVE" || true done <<<"$left" fi