From 9c308cef90b7689e539495ad28fe8af94ed464cc Mon Sep 17 00:00:00 2001 From: Yigid BALABAN Date: Sun, 22 Mar 2026 22:47:51 +0300 Subject: [PATCH] add whisper --- whisper/example.env | 2 + whisper/install.sh | 89 +++++++++++++++++++++++++++++++++++++++++++++ whisper/test.sh | 16 ++++++++ whisper/whisper | 82 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 whisper/example.env create mode 100755 whisper/install.sh create mode 100755 whisper/test.sh create mode 100755 whisper/whisper diff --git a/whisper/example.env b/whisper/example.env new file mode 100644 index 0000000..b60b650 --- /dev/null +++ b/whisper/example.env @@ -0,0 +1,2 @@ +TELEGRAM_BOT_TOKEN= +TELEGRAM_CHAT_ID= diff --git a/whisper/install.sh b/whisper/install.sh new file mode 100755 index 0000000..78f7d55 --- /dev/null +++ b/whisper/install.sh @@ -0,0 +1,89 @@ +#!/bin/sh +set -e + +BIN_SRC="./whisper" +BIN_DST="/usr/bin/whisper" +CONF_DIR="/etc/whisper" +CONF_DST="$CONF_DIR/.env" +CONF_SRC="./example.env" + +die() { + printf '%s\n' "$1" >&2 + exit 1 +} + +usage() { + printf 'Usage: install.sh [-i|--install] [-u|--uninstall] [-h|--help]\n' + printf ' -i, --install Install whisper (default)\n' + printf ' -u, --uninstall Remove whisper\n' + printf ' -h, --help Show this help\n' + exit 0 +} + +do_install() { + printf 'This will:\n' + printf ' - Copy whisper to %s\n' "$BIN_DST" + printf ' - Create %s/ with config\n\n' "$CONF_DIR" + + printf 'Proceed? [Y/n] ' + read -r answer + case "$answer" in + [nN]) printf 'Aborted.\n'; exit 0 ;; + esac + + [ -f "$BIN_SRC" ] || die "Cannot find $BIN_SRC in current directory" + [ -f "$CONF_SRC" ] || die "Cannot find $CONF_SRC in current directory" + + cp "$BIN_SRC" "$BIN_DST" + chown root:root "$BIN_DST" + chmod 755 "$BIN_DST" + + mkdir -p "$CONF_DIR" + + if [ ! -f "$CONF_DST" ]; then + cp "$CONF_SRC" "$CONF_DST" + else + printf 'Keeping existing %s\n' "$CONF_DST" + fi + + chown root:root "$CONF_DST" + chmod 600 "$CONF_DST" + + printf '\nInstalled. Edit %s and set your values.\n' "$CONF_DST" +} + +do_uninstall() { + printf 'This will remove:\n' + printf ' - %s\n' "$BIN_DST" + printf ' - %s/\n\n' "$CONF_DIR" + + printf 'Proceed? [y/N] ' + read -r answer + case "$answer" in + [yY]) ;; + *) printf 'Aborted.\n'; exit 0 ;; + esac + + rm -f "$BIN_DST" + rm -rf "$CONF_DIR" + + printf 'Done.\n' +} + +# --- main --- +[ "$(id -u)" -eq 0 ] || die "Must be run as root" + +ACTION="install" +while [ $# -gt 0 ]; do + case "$1" in + -i|--install) ACTION="install"; shift ;; + -u|--uninstall) ACTION="uninstall"; shift ;; + -h|--help) usage ;; + *) die "Unknown option: $1" ;; + esac +done + +case "$ACTION" in + install) do_install ;; + uninstall) do_uninstall ;; +esac diff --git a/whisper/test.sh b/whisper/test.sh new file mode 100755 index 0000000..8d525f9 --- /dev/null +++ b/whisper/test.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# manual smoke tests for whisper via telegram + +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) + +echo '--- test 1: plain text ---\n' +"$SCRIPT_DIR/whisper" -t telegram -m "Hello from whisper test" || true + +echo '\n--- test 2: HTML formatting ---\n' +"$SCRIPT_DIR/whisper" -t telegram -m "bold italic code" || true + +echo '\n--- test 3: multiline ---\n' +MSG=$(printf 'Line one\nLine two\nLine three') +"$SCRIPT_DIR/whisper" -t telegram -m "$MSG" || true + +echo '\nAll tests done.\n' diff --git a/whisper/whisper b/whisper/whisper new file mode 100755 index 0000000..e68592d --- /dev/null +++ b/whisper/whisper @@ -0,0 +1,82 @@ +#!/bin/sh +# whisper - send messages via transport (telegram) +set -e + +die() { + printf 'whisper: %s\n' "$1" >&2 + exit "${2:-1}" +} + +usage() { + printf 'Usage: whisper -m MESSAGE [-t TRANSPORT]\n\n' + printf ' -m, --message Message to send (required)\n' + printf ' -t, --transport Transport to use (default: telegram)\n' + printf ' -h, --help Show this help\n' + exit 0 +} + +# --- config loading --- +# source .env files if they exist (later file wins, env vars win over both) +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) +for _envfile in /etc/whisper/.env "$SCRIPT_DIR/.env"; do + [ -f "$_envfile" ] && . "$_envfile" +done +unset _envfile + +# --- dependency check --- +command -v curl >/dev/null 2>&1 || die "curl is required but not found" 1 + +# --- arg parsing --- +TRANSPORT="telegram" +MESSAGE="" + +while [ $# -gt 0 ]; do + case "$1" in + -m|--message) + [ -n "${2+x}" ] || die "missing value for $1" 1 + MESSAGE="$2"; shift 2 ;; + -t|--transport) + [ -n "${2+x}" ] || die "missing value for $1" 1 + TRANSPORT="$2"; shift 2 ;; + -h|--help) + usage ;; + *) + die "unknown option: $1" 1 ;; + esac +done + +[ -n "$MESSAGE" ] || die "message is required (-m)" 1 + +# --- env validation --- +validate_telegram_env() { + [ -n "$TELEGRAM_BOT_TOKEN" ] || die "TELEGRAM_BOT_TOKEN is not set" 1 + [ -n "$TELEGRAM_CHAT_ID" ] || die "TELEGRAM_CHAT_ID is not set" 1 +} + +# --- transports --- +send_telegram() { + validate_telegram_env + local url="https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" + + local response + response=$(curl -s -X POST "$url" \ + -d chat_id="$TELEGRAM_CHAT_ID" \ + --data-urlencode text="$MESSAGE" \ + -d parse_mode="HTML") + + if echo "$response" | grep -q '"ok":true'; then + printf 'whisper: message sent\n' >&2 + return 0 + else + local err + err=$(echo "$response" | sed -n 's/.*"description":"\([^"]*\)".*/\1/p') + printf 'whisper: send failed: %s\n' "${err:-unknown error}" >&2 + exit 2 + fi +} + +# --- dispatch --- +case "$TRANSPORT" in + telegram) send_telegram ;; + *) die "unknown transport: $TRANSPORT" 1 ;; +esac