#!/bin/bash # --------------------------------------------------- # Send notification to a telegram account thru a bot account # Configuration is stored in /etc/telegram-notify.conf # Depends on curl # # Revision history : # 10/01/2016, v1.0 - Creation by N. Bernaerts # 22/01/2016, v1.1 - Handle emoticons # 06/08/2016, v1.2 - Add API key and User ID parameters # Remove dependency to PERL # 08/08/2016, v1.3 - Add --document, --html and --silent options # 10/11/2016, v1.4 - Add --icon option # 11/01/2018, v1.5 - Add possibility of piped text, idea from Yasir Atabani # 19/05/2018, v1.6 - Add socks5 proxy option, idea from RangerRU # 28/06/2018, v1.7 - Add --warning and --config options, idea from Markus Hof # 08/08/2019, v1.8 - Add --file option (file holding text to display) # 23/09/2019, v1.9 - Add --quiet option, thanks to Alberto Panu # 06/02/2020, v2.0 - Add --disable_preview option, thanks to Alex P. # 30/01/2022, v2.1 - Add --code option and --protect # 03/05/2022, v2.2 - Bug fixes, thanks to Radius17 # 31/01/2023, v2.3 - Fix for image and document sending, thanks to jacklul # 01/02/2023, v2.4 - Add --debug and --position option, idea from z3r0l1nk # 03/02/2023, v2.5 - Add --audio option and code rewrite # --------------------------------------------------- # initialise variables TEXT="" ICON="" TYPE="text" MODE="markdown" DISABLE_PREVIEW="false" PROTECT="false" SILENT="false" QUIET="false" LINE_BREAK=$'\n' # Configuration file FILE_CONF="/etc/telegram-notify.conf" # ------------------------------------------------------- # Check tools availability # ------------------------------------------------------- command -v curl >/dev/null 2>&1 || { echo "[Error] Please install curl"; exit 1; } # ------------------------------------------------------- # Loop to load arguments # ------------------------------------------------------- # if no argument, display help if [ $# -eq 0 ] then echo "Tool to send a message to a Telegram User or Channel." echo "Message is sent from a Telegram Bot and can contain icon, text, image and/or document." echo "Main parameters are :" echo " --text Text of the message (use - for piped text)" echo " --file File holding the text of the message" echo " --photo Image to display" echo " --document Document to transfer" echo " --position GPS position" echo " --audio Audio file (converted to opus if needed)" echo "Options are :" echo " --title Title of the message (if text message)" echo " --html Use HTML mode for text content (markdown by default)" echo " --disable_preview Don't create previews for links, image and/or document" echo " --protect Protects the contents of the sent message from forwarding and saving" echo " --silent Send message in silent mode (no user notification on the client)" echo " --quiet Don't print message to stdout" echo " --config <file> use alternate config file, instead of default ${FILE_CONF}" echo " --user <user-id> Recipient User or Channel ID (replaces user-id= in ${FILE_CONF})" echo " --key <api-key> API Key of your Telegram bot (replaces api-key= in ${FILE_CONF})" echo "Optional icons are :" echo " --success Add a success icon" echo " --warning Add a warning icon" echo " --error Add an error icon" echo " --question Add a question mark icon" echo " --icon <code> Add an icon by UTF code (ex 1F355)" echo "Other options are :" echo " --debug Display JSON answer for debug" echo "Here is an example of piped text :" echo " echo 'text to be displayed' | telegram-notify --success --text -" exit fi # loop to retrieve arguments while test $# -gt 0 do case "$1" in "--text") shift; TEXT="$1"; shift; ;; "--file") shift; FILE="$1"; shift; ;; "--photo") shift; TYPE="pict"; FILE="$1"; shift; ;; "--document") shift; TYPE="doc"; FILE="$1"; shift; ;; "--audio") shift; TYPE="audio"; FILE="$1"; shift; ;; "--position") shift; TYPE="pos"; POSITION="$1"; shift; ;; "--title") shift; TITLE="$1"; shift; ;; "--html") MODE="html"; shift; ;; "--disable_preview") DISABLE_PREVIEW="true"; shift; ;; "--protect") PROTECT="true"; shift; ;; "--silent") SILENT="true"; shift; ;; "--quiet") QUIET="true"; shift; ;; "--config") shift; FILE_CONF="$1"; shift; ;; "--user") shift; USER_ID="$1"; shift; ;; "--key") shift; API_KEY="$1"; shift; ;; "--success") ICON=$(echo -e "\U2705"); shift; ;; "--warning") ICON=$(echo -e "\U26A0"); shift; ;; "--error") ICON=$(echo -e "\U1F6A8"); shift; ;; "--question") ICON=$(echo -e "\U2753"); shift; ;; "--icon") shift; ICON=$(echo -e "\U$1"); shift; ;; "--debug") DEBUG="ok"; shift; ;; *) shift; ;; esac done # ------------------------------------------------------- # Read configuration # ------------------------------------------------------- # if configuration file is present if [ -f "${FILE_CONF}" ] then # display used config file unless --quiet parameter is used [ "${QUIET}" = "false" ] && echo "[Info] Using configuration file ${FILE_CONF}" # if needed, load from configuration file [ "${API_KEY}" = "" ] && API_KEY=$(cat "${FILE_CONF}" | grep "api-key=" | cut -d'=' -f2) [ "${USER_ID}" = "" ] && USER_ID=$(cat "${FILE_CONF}" | grep "user-id=" | cut -d'=' -f2) # load socks proxy from configuration file SOCKS_PROXY=$(cat "${FILE_CONF}" | grep "socks-proxy=" | cut -d'=' -f2) else # display warning unless --quiet parameter is used [ "${QUIET}" = "false" ] && echo "[Warning] Configuration file missing ${FILE_CONF}" fi # check API key and User ID [ "${API_KEY}" = "" ] && { echo "[Error] Please provide API key or set it in ${FILE_CONF}"; exit 1; } [ "${USER_ID}" = "" ] && { echo "[Error] Please provide User ID or set it in ${FILE_CONF}"; exit 1; } # Check for file existence [ "${FILE}" != "" -a ! -f "${FILE}" ] && { echo "[error] File ${FILE} doesn't exist"; exit 1; } # generate temporary directory TMP_DIR=$(mktemp -t -d "telegram-XXXXXXXX") TMP_AUDIO="${TMP_DIR}/audio.ogg" # ------------------------------------------------------- # Text : space, line break, title and icon # ------------------------------------------------------- # if text is a file, get its content [ "${TYPE}" = "text" -a "${FILE}" != "" ] && TEXT=$(cat "${FILE}") # if text is to be read from pipe, get it [ ! -t 0 -a "${TEXT}" = "-" ] && TEXT=$(cat) # convert \n to LF TEXT=$(echo "${TEXT}" | sed 's:\\n:\n:g') # if title defined, add it with line break [ "${TITLE}" != "" -a "${MODE}" = "html" ] && TEXT="<b>${TITLE}</b>${LINE_BREAK}${LINE_BREAK}${TEXT}" [ "${TITLE}" != "" -a "${MODE}" = "markdown" ] && TEXT="*${TITLE}*${LINE_BREAK}${LINE_BREAK}${TEXT}" # if icon defined, include ahead of notification [ "${ICON}" != "" ] && TEXT="${ICON} ${TEXT}" # ----------------- # Notification # ----------------- # default option ARR_OPTIONS=( "--silent" "--insecure" ) # if needed, socks5 option [ "${SOCKS_PROXY}" != "" ] && ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--socks5-hostname" "${SOCKS_PROXY}" ) case "${TYPE}" in # text "text") ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--data" "chat_id=${USER_ID}" "--data" "disable_notification=${SILENT}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--data" "protect_content=${PROTECT}" "--data" "disable_web_page_preview=${DISABLE_PREVIEW}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--data" "parse_mode=${MODE}" "--data" "text=${TEXT}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "https://api.telegram.org/bot${API_KEY}/sendMessage" ) ;; # image "pict") ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--form" "chat_id=${USER_ID}" "--form" "disable_notification=${SILENT}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--form" "protect_content=${PROTECT}" "--form" "disable_web_page_preview=${DISABLE_PREVIEW}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--form" "parse_mode=${MODE}" "--form" "photo=@${FILE}" "--form" "caption=${TEXT}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "https://api.telegram.org/bot${API_KEY}/sendPhoto" ) ;; # document "doc") ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--form" "chat_id=${USER_ID}" "--form" "disable_notification=${SILENT}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--form" "protect_content=${PROTECT}" "--form" "disable_web_page_preview=${DISABLE_PREVIEW}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--form" "parse_mode=${MODE}" "--form" "document=@${FILE}" "--form" "caption=${TEXT}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "https://api.telegram.org/bot${API_KEY}/sendDocument" ) ;; # position "pos") # extract coordonates LATITUDE=$(echo "${POSITION}" | cut -d',' -f1) LONGITUDE=$(echo "${POSITION}" | cut -d',' -f2) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--form" "chat_id=${USER_ID}" "--form" "disable_notification=${SILENT}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--form" "parse_mode=${MODE}" "--form" "caption=${TEXT}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--form" "latitude=${LATITUDE}" "--form" "longitude=${LONGITUDE}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "https://api.telegram.org/bot${API_KEY}/sendLocation" ) ;; # audio "audio") # if needed, convert audio file IS_OPUS=$(file "${FILE}" | grep "Opus audio") command -v ffmpeg >/dev/null 2>&1 && IS_FFMPEG="ok" [ "${IS_OPUS}" != "" ] && TMP_AUDIO="${FILE}" [ "${IS_OPUS}" = "" -a "${IS_FFMPEG}" = "ok" ] && ffmpeg -i "${FILE}" -loglevel quiet -c libopus -ab 64k "${TMP_AUDIO}" # if proper audio file if [ -f "${TMP_AUDIO}" ] then ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--form" "chat_id=${USER_ID}" "--form" "disable_notification=${SILENT}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "--form" "parse_mode=${MODE}" "--form" "voice=@${TMP_AUDIO}" "--form" "caption=${TEXT}" ) ARR_OPTIONS=( "${ARR_OPTIONS[@]}" "https://api.telegram.org/bot${API_KEY}/sendVoice" ) else ARR_OPTIONS=( ) [ "${QUIET}" = "false" ] && echo "[Error] FFmpeg absent, Opus conversion impossible" fi ;; *) ARR_OPTIONS=( ) ;; esac # if there is a message to send if [ ${#ARR_OPTIONS[@]} -gt 0 ] then # send message RESULT=$(curl "${ARR_OPTIONS[@]}") # if debug mode, display bot answer if [ "${DEBUG}" = "ok" ] then echo "option : ${ARR_OPTIONS[@]}" echo "answer : ${RESULT}" fi # else, nothing, error else # display error message unless --quiet parameter is used [ "${QUIET}" = "false" ] && echo "[Error] Nothing to notify" fi # remove temporary directory rm -r "${TMP_DIR}"