From 122b2b3ef7f90d031fce9b8441e307a0c4eaddd3 Mon Sep 17 00:00:00 2001 From: scriptos Date: Thu, 18 Sep 2025 21:53:53 +0200 Subject: [PATCH] Initial --- .env | 22 +++++++ mc-ntfy-notify.v1.sh | 143 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 .env create mode 100644 mc-ntfy-notify.v1.sh diff --git a/.env b/.env new file mode 100644 index 0000000..4d47841 --- /dev/null +++ b/.env @@ -0,0 +1,22 @@ +# 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" + +# 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" diff --git a/mc-ntfy-notify.v1.sh b/mc-ntfy-notify.v1.sh new file mode 100644 index 0000000..0b5b96e --- /dev/null +++ b/mc-ntfy-notify.v1.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash +#!/bin/bash +# Beschreibung: Minecraft → ntfy Notifier (Join/Leave + optional Up/Down) +# Autor: Patrick Asmus +# Web: https://www.cleveradmin.de +# Repository: https://git.techniverse.net/scriptos/minecraft-ntfy-notify +# Version: 1.0 +# Datum: 18.09.2025 +# Modifikation: Initial +##################################################### +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +if [[ -f "${SCRIPT_DIR}/.env" ]]; then + set -a + . "${SCRIPT_DIR}/.env" + set +a +fi + +# ===== Konfiguration via ENV ===== +MC_HOST="${MC_HOST:-127.0.0.1}" +RCON_PORT="${RCON_PORT:-25575}" +RCON_PASSWORD="${RCON_PASSWORD:-changeme}" + +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_TAGS_BASE="${NTFY_TAGS_BASE:-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}" + +# State (standardmäßig im Script-Ordner, root-frei) +STATE_DIR="${STATE_DIR:-${SCRIPT_DIR}/state}" +STATE_PLAYERS="${STATE_DIR}/players.prev" +STATE_UP="${STATE_DIR}/server_up.prev" + +# ===== Helpers ===== +die() { echo "ERROR: $*" >&2; exit 1; } +need_bin() { command -v "$1" >/dev/null 2>&1 || die "Benötigtes Tool fehlt: $1"; } + +ntfy_notify() { + local title="$1" body="$2" tags="$3" priority="$4" + [[ -z "$NTFY_SERVER" || -z "$NTFY_TOPIC" ]] && { echo "ntfy Server/Topic fehlt – skip"; return 1; } + local url="${NTFY_SERVER%/}/${NTFY_TOPIC}" + local args=(-sS -X POST "$url" -H "Title: ${title}" -H "Priority: ${priority}" -H "Tags: ${tags}") + [[ "$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" +} + +get_players() { + local out + if ! out=$(mcrcon -H "$MC_HOST" -P "$RCON_PORT" -p "$RCON_PASSWORD" "list" 2>/dev/null); then + return 1 + fi + if grep -q "players online:" <<<"$out"; then + local names="${out#*:}" + names="$(echo "$names" | sed 's/^ *//;s/ *$//')" + if [[ -n "$names" ]]; then + tr ',' '\n' <<<"$names" | sed 's/^ *//;s/ *$//' | sed '/^$/d' | sort -u + return 0 + fi + fi + return 0 +} + +# ===== Checks ===== +need_bin curl +need_bin mcrcon +[[ -n "${NTFY_SERVER}" && -n "${NTFY_TOPIC}" ]] || die "NTFY_SERVER/NTFY_TOPIC nicht gesetzt" +ensure_state + +echo "Starte Polling ${MC_HOST}:${RCON_PORT} → ntfy ${NTFY_SERVER}/${NTFY_TOPIC}" +prev_up="$(cat "$STATE_UP")" + +while :; do + tmp_players="$(mktemp)" + if players=$(get_players); then + server_up="true" + printf "%s\n" $players 2>/dev/null | sed '/^$/d' | sort -u >"$tmp_players" + 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 "${NTFY_TITLE_PREFIX}: Server up" \ + "Server ist wieder erreichbar (${MC_HOST}:${RCON_PORT})." \ + "${NTFY_TAGS_BASE},up" "$NTFY_PRIORITY_UP" || true + else + ntfy_notify "${NTFY_TITLE_PREFIX}: Server down" \ + "Server ist nicht erreichbar (${MC_HOST}:${RCON_PORT})." \ + "${NTFY_TAGS_BASE},down" "$NTFY_PRIORITY_DOWN" || true + fi + fi + + if [[ "$server_up" == "true" ]]; then + 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" \ + "Player ${name} ist beigetreten." \ + "${NTFY_TAGS_BASE},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" \ + "Player ${name} hat den Server verlassen." \ + "${NTFY_TAGS_BASE},leave" "$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 \ No newline at end of file