Compare commits
10 Commits
205d9a458c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cfabd27b4 | ||
|
|
60b2c6d568 | ||
|
|
363a76504a | ||
|
|
67cd245a0a | ||
|
|
5f4b02d912 | ||
|
|
95ac12bbe2 | ||
|
|
de728f7c8f | ||
|
|
3d9f700d42 | ||
|
|
9c297ab7b1 | ||
|
|
122b2b3ef7 |
32
.env
Normal file
32
.env
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Minecraft RCON
|
||||||
|
export MC_HOST="mc.techniverse.net"
|
||||||
|
export RCON_PORT="25575"
|
||||||
|
export RCON_PASSWORD=""
|
||||||
|
|
||||||
|
# Polling
|
||||||
|
export POLL_SECONDS="10"
|
||||||
|
export ANNOUNCE_SERVER_UPDOWN="true"
|
||||||
|
|
||||||
|
# Spiel-Adresse:
|
||||||
|
export GAME_HOST="mc.techniverse.net"
|
||||||
|
export GAME_PORT="25573"
|
||||||
|
|
||||||
|
# Anzeigename:
|
||||||
|
SERVER_NAME="[GER] Blockventure | ⌁25573"
|
||||||
|
|
||||||
|
# Optionale Zusatzzeile im Body
|
||||||
|
MESSAGE_EXTRA="Whitelist aktiv"
|
||||||
|
|
||||||
|
# ntfy
|
||||||
|
export NTFY_SERVER="https://ntfy.pushservice.techniverse.net"
|
||||||
|
export NTFY_TOPIC="mc-events"
|
||||||
|
export NTFY_TOKEN=""
|
||||||
|
export NTFY_TITLE_PREFIX="🟩 Minecraft"
|
||||||
|
export NTFY_TAGS_BASE="minecraft"
|
||||||
|
export NTFY_MARKDOWN="false"
|
||||||
|
|
||||||
|
# Optional: Prioritäten (1=hoch, 5=niedrig; ntfy: 5=lowest, 1=urgent)
|
||||||
|
export NTFY_PRIORITY_JOIN="3"
|
||||||
|
export NTFY_PRIORITY_LEAVE="3"
|
||||||
|
export NTFY_PRIORITY_UP="4"
|
||||||
|
export NTFY_PRIORITY_DOWN="5"
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# template_repository
|
Readme kommt nachträglich..
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Wichtig: Link für Lizenz anpassen.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -11,5 +7,5 @@ Wichtig: Link für Lizenz anpassen.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://assets.techniverse.net/f1/logos/small/license.png" alt="License" width="15" height="15"> <a href="./template_repository/src/branch/main/LICENSE">License</a> | <img src="https://assets.techniverse.net/f1/logos/small/matrix2.svg" alt="Matrix" width="15" height="15"> <a href="https://matrix.to/#/#community:techniverse.net">Matrix</a> | <img src="https://assets.techniverse.net/f1/logos/small/mastodon2.svg" alt="Matrix" width="15" height="15"> <a href="https://social.techniverse.net/@donnerwolke">Mastodon</a>
|
<img src="https://assets.techniverse.net/f1/logos/small/license.png" alt="License" width="15" height="15"> <a href="./minecraft-ntfy-notify/src/branch/main/LICENSE">License</a> | <img src="https://assets.techniverse.net/f1/logos/small/matrix2.svg" alt="Matrix" width="15" height="15"> <a href="https://matrix.to/#/#community:techniverse.net">Matrix</a> | <img src="https://assets.techniverse.net/f1/logos/small/mastodon2.svg" alt="Matrix" width="15" height="15"> <a href="https://social.techniverse.net/@donnerwolke">Mastodon</a>
|
||||||
</p>
|
</p>
|
||||||
225
mc-ntfy-notify.v1.sh
Normal file
225
mc-ntfy-notify.v1.sh
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#!/bin/bash
|
||||||
|
# Beschreibung: Minecraft → ntfy Notifier (Join/Leave + optional Up/Down) mit Cron-safe Locking
|
||||||
|
# Autor: Patrick Asmus
|
||||||
|
# Web: https://www.cleveradmin.de
|
||||||
|
# Repository: https://git.techniverse.net/scriptos/minecraft-ntfy-notify
|
||||||
|
# Version: 1.8
|
||||||
|
# Datum: 19.09.2025
|
||||||
|
# Änderungen:
|
||||||
|
# - SERVER_NAME im Titel
|
||||||
|
# - GAME_HOST/GAME_PORT im Body
|
||||||
|
# - MESSAGE_EXTRA als zusätzliche Body-Zeile (optional)
|
||||||
|
# - Body-Layout mehrzeilig: Event, Server, Port, [Extra]
|
||||||
|
#####################################################
|
||||||
|
set -euo pipefail
|
||||||
|
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
|
||||||
|
# .env laden: bevorzugt ENV_FILE, 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 =====
|
||||||
|
# RCON (für Polling)
|
||||||
|
MC_HOST="${MC_HOST:-127.0.0.1}"
|
||||||
|
RCON_PORT="${RCON_PORT:-25575}"
|
||||||
|
RCON_PASSWORD="${RCON_PASSWORD:-changeme}"
|
||||||
|
|
||||||
|
# Spiel-Adresse (DNS:Port zum Joinen, nur Anzeige)
|
||||||
|
GAME_HOST="${GAME_HOST:-${MC_HOST}}"
|
||||||
|
GAME_PORT="${GAME_PORT:-25565}"
|
||||||
|
|
||||||
|
POLL_SECONDS="${POLL_SECONDS:-10}"
|
||||||
|
ANNOUNCE_SERVER_UPDOWN="${ANNOUNCE_SERVER_UPDOWN:-true}"
|
||||||
|
|
||||||
|
# ntfy
|
||||||
|
NTFY_SERVER="${NTFY_SERVER:-}"
|
||||||
|
NTFY_TOPIC="${NTFY_TOPIC:-}"
|
||||||
|
NTFY_TOKEN="${NTFY_TOKEN:-}"
|
||||||
|
NTFY_TITLE_PREFIX="${NTFY_TITLE_PREFIX:-Minecraft}"
|
||||||
|
NTFY_PRIORITY_JOIN="${NTFY_PRIORITY_JOIN:-3}"
|
||||||
|
NTFY_PRIORITY_LEAVE="${NTFY_PRIORITY_LEAVE:-3}"
|
||||||
|
NTFY_PRIORITY_UP="${NTFY_PRIORITY_UP:-4}"
|
||||||
|
NTFY_PRIORITY_DOWN="${NTFY_PRIORITY_DOWN:-5}"
|
||||||
|
NTFY_MARKDOWN="${NTFY_MARKDOWN:-false}"
|
||||||
|
|
||||||
|
# Anzeigename für den Titel
|
||||||
|
SERVER_NAME="${SERVER_NAME:-}"
|
||||||
|
|
||||||
|
# Optionale Zusatzzeile im Body
|
||||||
|
MESSAGE_EXTRA="${MESSAGE_EXTRA:-}"
|
||||||
|
|
||||||
|
# Lock & State je Instanz (Host:Port:Topic)
|
||||||
|
LOCK_KEY="$(printf '%s' "${MC_HOST}_${RCON_PORT}_${NTFY_TOPIC}" | tr -c 'A-Za-z0-9._-' '_')"
|
||||||
|
STATE_DIR="${STATE_DIR:-${SCRIPT_DIR}/state.${LOCK_KEY}}"
|
||||||
|
STATE_PLAYERS="${STATE_DIR}/players.prev"
|
||||||
|
STATE_UP="${STATE_DIR}/server_up.prev"
|
||||||
|
RUN_DIR="${RUN_DIR:-${STATE_DIR}}"
|
||||||
|
LOCK_DIR="${RUN_DIR}/lock.${LOCK_KEY}"
|
||||||
|
PID_FILE="${LOCK_DIR}/pid"
|
||||||
|
RUN_MARK="${RUN_DIR}/running.${LOCK_KEY}"
|
||||||
|
|
||||||
|
DEBUG="${DEBUG:-false}"
|
||||||
|
|
||||||
|
# ===== Helpers =====
|
||||||
|
die() { echo "ERROR: $*" >&2; exit 1; }
|
||||||
|
need_bin() { command -v "$1" >/dev/null 2>&1 || die "Benötigtes Tool fehlt: $1"; }
|
||||||
|
dbg() { [[ "$DEBUG" == "true" ]] && echo "DBG: $*" >&2 || true; }
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -f "$RUN_MARK" "$PID_FILE" 2>/dev/null || true
|
||||||
|
rmdir "$LOCK_DIR" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
acquire_lock() {
|
||||||
|
mkdir -p "$RUN_DIR"
|
||||||
|
if mkdir "$LOCK_DIR" 2>/dev/null; then
|
||||||
|
echo "$$" > "$PID_FILE"
|
||||||
|
trap cleanup EXIT INT TERM
|
||||||
|
else
|
||||||
|
if [[ -f "$PID_FILE" ]]; then
|
||||||
|
oldpid="$(cat "$PID_FILE" 2>/dev/null || true)"
|
||||||
|
if [[ -n "${oldpid:-}" ]] && kill -0 "$oldpid" 2>/dev/null; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_title() {
|
||||||
|
if [[ -n "$SERVER_NAME" ]]; then
|
||||||
|
printf '%s - %s' "$NTFY_TITLE_PREFIX" "$SERVER_NAME"
|
||||||
|
else
|
||||||
|
printf '%s' "$NTFY_TITLE_PREFIX"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Baut den Body in gewünschtem Layout:
|
||||||
|
# <eventline>\nServer: <GAME_HOST>\nPort: <GAME_PORT>\n[<MESSAGE_EXTRA>]
|
||||||
|
build_body() {
|
||||||
|
local event="$1"
|
||||||
|
if [[ -n "$MESSAGE_EXTRA" ]]; then
|
||||||
|
printf '%s\n\nServer: %s\nPort: %s\n%s' \
|
||||||
|
"$event" "$GAME_HOST" "$GAME_PORT" "$MESSAGE_EXTRA"
|
||||||
|
else
|
||||||
|
printf '%s\nServer: %s\nPort: %s' \
|
||||||
|
"$event" "$GAME_HOST" "$GAME_PORT"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ntfy_notify() {
|
||||||
|
# ntfy_notify "Body" PRIORITY
|
||||||
|
local body="$1" priority="$2"
|
||||||
|
[[ -z "$NTFY_SERVER" || -z "$NTFY_TOPIC" ]] && { echo "ntfy Server/Topic fehlt – skip"; return 1; }
|
||||||
|
local url="${NTFY_SERVER%/}/${NTFY_TOPIC}"
|
||||||
|
local title; title="$(build_title)"
|
||||||
|
local args=(-sS -X POST "$url" -H "Title: ${title}" -H "Priority: ${priority}")
|
||||||
|
[[ "$NTFY_MARKDOWN" == "true" ]] && args+=(-H "Markdown: yes")
|
||||||
|
[[ -n "$NTFY_TOKEN" ]] && args+=(-H "Authorization: Bearer ${NTFY_TOKEN}")
|
||||||
|
curl "${args[@]}" --data-raw "$body" >/dev/null 2>&1 || return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_state() {
|
||||||
|
mkdir -p "$STATE_DIR"
|
||||||
|
touch "$STATE_PLAYERS"
|
||||||
|
[[ -f "$STATE_UP" ]] || echo "unknown" >"$STATE_UP"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ANSI- & MC-Farbcodes entfernen
|
||||||
|
sanitize() {
|
||||||
|
sed -E $'s/\x1B\\[[0-9;]*[A-Za-z]//g' \
|
||||||
|
| sed -E 's/§[0-9A-FK-ORa-fk-or]//g' \
|
||||||
|
| tr -d '\r' \
|
||||||
|
| sed -E 's/[\x00-\x1F\x7F]//g'
|
||||||
|
}
|
||||||
|
|
||||||
|
get_players() {
|
||||||
|
local out
|
||||||
|
if ! out=$(mcrcon -H "$MC_HOST" -P "$RCON_PORT" -p "$RCON_PASSWORD" "list" 2>/dev/null); then
|
||||||
|
return 1
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== Checks & Lock =====
|
||||||
|
need_bin curl
|
||||||
|
need_bin mcrcon
|
||||||
|
[[ -n "${NTFY_SERVER}" && -n "${NTFY_TOPIC}" ]] || die "NTFY_SERVER/NTFY_TOPIC nicht gesetzt"
|
||||||
|
ensure_state
|
||||||
|
acquire_lock
|
||||||
|
|
||||||
|
echo "Starte Polling RCON ${MC_HOST}:${RCON_PORT} -> ntfy ${NTFY_SERVER}/${NTFY_TOPIC} (PID $$)"
|
||||||
|
prev_up="$(cat "$STATE_UP")"
|
||||||
|
|
||||||
|
# ===== Main Loop =====
|
||||||
|
while :; do
|
||||||
|
date -Iseconds > "$RUN_MARK"; echo "$$" >> "$RUN_MARK"
|
||||||
|
|
||||||
|
tmp_players="$(mktemp)"
|
||||||
|
if get_players >"$tmp_players"; then
|
||||||
|
server_up="true"
|
||||||
|
else
|
||||||
|
server_up="false"
|
||||||
|
: >"$tmp_players"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$ANNOUNCE_SERVER_UPDOWN" == "true" && "$prev_up" != "unknown" && "$server_up" != "$prev_up" ]]; then
|
||||||
|
if [[ "$server_up" == "true" ]]; then
|
||||||
|
ntfy_notify "$(build_body "Server ist wieder erreichbar.")" "$NTFY_PRIORITY_UP" || true
|
||||||
|
else
|
||||||
|
ntfy_notify "$(build_body "Server ist nicht erreichbar.")" "$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 "$(build_body "Player \"${name}\" hat den Server betreten.")" "$NTFY_PRIORITY_JOIN" || true
|
||||||
|
done <<<"$joined"
|
||||||
|
fi
|
||||||
|
if [[ -n "$left" ]]; then
|
||||||
|
while IFS= read -r name; do
|
||||||
|
[[ -z "$name" ]] && continue
|
||||||
|
ntfy_notify "$(build_body "Player \"${name}\" hat den Server verlassen.")" "$NTFY_PRIORITY_LEAVE" || true
|
||||||
|
done <<<"$left"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv "$tmp_players" "$STATE_PLAYERS"
|
||||||
|
else
|
||||||
|
rm -f "$tmp_players"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "$server_up" >"$STATE_UP"
|
||||||
|
prev_up="$server_up"
|
||||||
|
sleep "$POLL_SECONDS"
|
||||||
|
done
|
||||||
11
stop.sh
Normal file
11
stop.sh
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
cd /home/scripts/minecraft-ntfy-notify
|
||||||
|
|
||||||
|
RUN="state.mc.techniverse.local_25673_minecraft-java-feed/running.mc.techniverse.local_25673_minecraft-java-feed"
|
||||||
|
|
||||||
|
# PID aus der letzten Zeile lesen und sanft beenden
|
||||||
|
PID="$(tail -n1 "$RUN")"
|
||||||
|
kill -TERM "$PID"
|
||||||
|
|
||||||
|
# prüfen
|
||||||
|
sleep 1
|
||||||
|
ps -p "$PID" || echo "gestoppt"
|
||||||
Reference in New Issue
Block a user