#!/bin/bash TELEGRAM_TOKEN="" PARSE_MODE="MarkdownV2" ESCAPE_ALL=false API_URL="https://api.telegram.org" # _escape_text(input_text) function _escape() { sed -E 's/[`~!@#$%^&*():<>.,?\|{}=+_-]/\\&/g' <<< "$1" } # _unescape_text(input_text) function _unescape_text() { sed -E 's/\\/&�Meow�/g;s/\\�Meow�\\�Meow�\\�Meow�/\\/;s/\\�Meow�//g' <<< "$1" } # tg_send(chat, text, file, type, [id]) function tg_send() { if [[ $ESCAPE_ALL == true ]]; then text="$(_escape "$2")" echo "$2" echo "$text" else text="$2" fi if [[ $3 != '' ]]; then local type_snake=$4 [[ $4 == '' ]] && local type_snake='document' [[ $4 == '' || $4 == 'document' ]] && local type="Document" [[ $4 == 'photo' ]] && local type="Photo" [[ $4 == 'audio' ]] && local type="Audio" [[ $4 == 'video' ]] && local type="Video" [[ $4 == 'animation' ]] && local type="Animation" [[ $4 == 'voice' ]] && local type="Voice" [[ $4 == 'video_note' ]] && local type="VideoNote" [[ $4 == 'sticker' ]] && local type="Sticker" if [[ $3 == "remoteFileId" ]]; then curl -s \ --form-string chat_id=$1 \ --form-string caption="$text" \ -F parse_mode=$PARSE_MODE \ -F $type_snake=$5 \ "${API_URL}/bot${TELEGRAM_TOKEN}/send${type}" else curl -s \ --form-string chat_id=$1 \ --form-string caption="$text" \ -F parse_mode=$PARSE_MODE \ -F $type_snake=@$3 \ "${API_URL}/bot${TELEGRAM_TOKEN}/send${type}" fi else curl -s \ --form-string chat_id=$1 \ --form-string text="$text" \ -F parse_mode=$PARSE_MODE \ "${API_URL}/bot${TELEGRAM_TOKEN}/sendMessage" fi } # tg_get_me() function tg_get_me() { curl -s "${API_URL}/bot${TELEGRAM_TOKEN}/getMe" } # tg_get_file(id) function tg_get_file() { curl -s "${API_URL}/file/bot${TELEGRAM_TOKEN}/$(curl -s "${API_URL}/bot${TELEGRAM_TOKEN}/getFile?file_id=$1" | jq -r '.result.file_path')" } # tg_get_messages(offset, timeout) function _tg_get_updates() { curl -s "${API_URL}/bot${TELEGRAM_TOKEN}/getUpdates?offset=$1&timeout=p" | jq -c '.result[]' } function _on_msg() { echo "[msg] ${event[from_username]}: ${event[text]}" } function _on_edit() { echo "[edit] ${event[json]}" } function _on_animation() { echo "[animation] ${event[json]}" } function _on_audio() { echo "[audio] ${event[json]}" } function _on_document() { echo "[document] ${event[json]}" } function _on_photo() { echo "[photo] ${event[json]}" } function _on_sticker() { echo "[sticker] ${event[json]}" } function _on_video() { echo "[video] ${event[json]}" } function _on_video_note() { echo "[video_note] ${event[json]}" } function _on_voice() { echo "[voice] ${event[json]}" } #jq_to_array(jq_expression) function _jq_to_array() { declare -ga "_tmp=($(jq -r "$1" | sed 's/[][`~!@#$%^&*():;<>.,?\|{}=+-]/\\&/g;'"s@\\\'@\\'@g" ))" } function tg_start() { _offset=0 while true; do IFS=$'\n' _events=($(_tg_get_updates $_offset 10)) unset IFS for (( i=0; i<${#_events[@]}; i++ )); do declare -A event _msg_type="$(jq -r '(select(.message) | if .message.forward_date then "forwarded_message" else "message" end ), (select(.edited_message) | "edited_message")' <<< "${_events[$i]}")" _event_type="$(jq -r '(select(.message) | .message), (select(.edited_message) | .edited_message) | ( (select(.animation) | "animation"), (select(.audio) | "audio"), (select(.animation == null) | select(.document) | "document"), (select(.photo) | "photo"), (select(.sticker) | "sticker"), (select(.video) | "video"), (select(.video_note) | "video_note"), (select(.voice) | "voice"))' <<< "${_events[$i]}")" _jq_to_array '(select(.message) | .message), (select(.edited_message) | .edited_message) | [.message_id, .from.id, .from.is_bot, .from.first_name, .from.last_name, .from.username, .chat.id, (if .chat.type == "private" then .chat.username else .chat.title end), .chat.type, .date, (select(.text) | .text), (select(.caption) | .caption), (if .reply_to_message then .reply_to_message | ( "true", .message_id, .from.id, .from.is_bot, .from.first_name, .from.last_name, .from.username, .date, .text ) else "false" end)] | @sh' <<< "${_events[$i]}" event[message_id]="${_tmp[0]}" event[from_id]="${_tmp[1]}" event[from_is_bot]="${_tmp[2]}" event[from_first_name]="$(_unescape_text "${_tmp[3]}")" event[from_last_name]="$(_unescape_text "${_tmp[4]}")" event[from_username]="${_tmp[5]}" event[chat_id]="${_tmp[6]}" event[chat_title]="$(_unescape_text "${_tmp[7]}")" event[chat_type]="${_tmp[8]}" event[date]="${_tmp[9]}" event[text]="$(_unescape_text "${_tmp[10]}")" if [[ "${_tmp[11]}" == "true" ]]; then event[reply]=true event[reply_message_id]="${_tmp[12]}" event[reply_from_id]="${_tmp[13]}" event[reply_from_is_bot]="${_tmp[14]}" event[reply_from_first_name]="$(_unescape_text "${_tmp[15]}")" event[reply_from_last_name]="$(_unescape_text "${_tmp[16]}")" event[reply_from_username]="${_tmp[17]}" event[reply_date]="${_tmp[18]}" event[reply_text]="$(_unescape_text "${_tmp[19]}")" else event[reply]=false fi unset _tmp if [[ "$_msg_type" == forwarded_message ]]; then _jq_to_array '.message | [.forward_from.id, .forward_from.is_bot, .forward_from.first_name, .forward_from.last_name, .forward_from.username, .forward_date] | @sh' <<< "${_events[$i]}" event[forward_id]="${_tmp[0]}" event[forward_is_bot]="${_tmp[1]}" event[forward_first_name]="$(_unescape_text "${_tmp[2]}")" event[forward_last_name]="$(_unescape_text "${_tmp[3]}")" event[forward_username]="${_tmp[4]}" event[forward_date]="${_tmp[5]}" unset _tmp fi event[type]="$_msg_type" event[json]="${_events[$i]}" if [[ "$_msg_type" == edited_message ]]; then _on_edit elif [[ "$_event_type" == animation ]]; then _jq_to_array '(select(.message) | .message), (select(.edited_message) | .edited_message) | .animation | [.file_name, .mime_type, .duration, .width, .height, .thumb.file_id, .thumb.file_unique_id, .thumb.height, .thumb.width, .file_id, .file_unique_id, .file_size] | @sh' <<< "${_events[$i]}" event[animation_file_name]="${_tmp[0]}" event[animation_mime_type]="${_tmp[1]}" event[animation_duration]="${_tmp[2]}" event[animation_width]="${_tmp[3]}" event[animation_height]="${_tmp[4]}" event[animation_thumb_file_id]="${_tmp[5]}" event[animation_thumb_file_unique_id]="${_tmp[6]}" event[animation_thumb_height]="${_tmp[7]}" event[animation_thumb_width]="${_tmp[8]}" event[animation_file_id]="${_tmp[9]}" event[animation_file_unique_id]="${_tmp[10]}" event[animation_file_size]="${_tmp[11]}" unset _tmp _on_animation elif [[ "$_event_type" == audio ]]; then _jq_to_array '(select(.message) | .message), (select(.edited_message) | .edited_message) | .audio | [.duration, .file_name, .mime_type, .title, .performer, .thumb.file_id, .thumb.file_unique_id, .thumb.width, .thumb.height, .file_id, .file_unique_id, .file_size] | @sh' <<< "${_events[$i]}" event[audio_duration]="${_tmp[0]}" event[file_name]="${_tmp[1]}" event[mime_type]="${_tmp[2]}" event[title]="$(_unescape_text "${_tmp[3]}")" event[performer]="$(_unescape_text "${_tmp[4]}")" event[thumb_file_id]="${_tmp[5]}" event[thumb_file_unique_id]="${_tmp[6]}" event[thumb_width]="${_tmp[7]}" event[thumb_height]="${_tmp[8]}" event[file_id]="${_tmp[9]}" event[file_unique_id]="${_tmp[10]}" event[file_size]="${_tmp[11]}" unset _tmp _on_audio elif [[ "$_event_type" == document ]]; then _jq_to_array '(select(.message) | .message), (select(.edited_message) | .edited_message) | .document | [.file_name, .mime_type, .file_id, .file_unique_id, .file_size] | @sh' <<< "${_events[$i]}" event[document_file_name]="${_tmp[0]}" event[document_mime_type]="${_tmp[1]}" event[document_file_id]="${_tmp[2]}" event[document_file_unique_id]="${_tmp[3]}" event[document_file_size]="${_tmp[4]}" unset _tmp _on_document elif [[ "$_event_type" == photo ]]; then _jq_to_array '(select(.message) | .message), (select(.edited_message) | .edited_message) | .photo[-1] | [.file_id, .file_unique_id, .file_size, .width, .height] | @sh' <<< "${_events[$i]}" # stub - add more things to me! event[photo_file_id]="${_tmp[0]}" event[photo_file_unique_id]="${_tmp[1]}" event[photo_file_size]="${_tmp[2]}" event[photo_height]="${_tmp[3]}" event[photo_width]="${_tmp[4]}" unset _tmp _on_photo elif [[ "$_event_type" == sticker ]]; then _jq_to_array '(select(.message) | .message), (select(.edited_message) | .edited_message) | .sticker | [.width, .height, .emoji, .set_name, .is_animated, .file_id, .file_unique_id, .file_size] | @sh' <<< "${_events[$i]}" event[sticker_width]="${_tmp[0]}" event[sticker_height]="${_tmp[1]}" event[sticker_emoji]="${_tmp[2]}" event[sticker_set_name]="${_tmp[3]}" event[sticker_is_animated]="${_tmp[4]}" event[sticker_file_id]="${_tmp[5]}" event[sticker_file_unique_id]="${_tmp[6]}" event[sticker_file_size]="${_tmp[7]}" unset _tmp _on_sticker elif [[ "$_event_type" == video ]]; then _jq_to_array '(select(.message) | .message), (select(.edited_message) | .edited_message) | .video | [.duration, .width, .height, .file_name, .mime_type, .thumb.file_id, .thumb.file_unique_id, .thumb.width, .thumb.height, .file_id, .file_unique_id, .file_size] | @sh' <<< "${_events[$i]}" event[video_duration]="${_tmp[0]}" event[video_width]="${_tmp[1]}" event[video_height]="${_tmp[2]}" event[video_file_name]="${_tmp[3]}" event[video_mime_type]="${_tmp[4]}" event[video_thumb_file_id]="${_tmp[5]}" event[video_thumb_file_unique_id]="${_tmp[6]}" event[video_thumb_width]="${_tmp[7]}" event[video_thumb_height]="${_tmp[8]}" event[video_file_id]="${_tmp[9]}" event[video_file_unique_id]="${_tmp[10]}" event[video_file_size]="${_tmp[11]}" unset _tmp _on_video elif [[ "$_event_type" == video_note ]]; then # implement it yourself or use raw JSON # I don't consider video_note to be a valid way of messaging _on_video_note elif [[ "$_event_type" == voice ]]; then _jq_to_array '(select(.message) | .message), (select(.edited_message) | .edited_message) | .voice | [.duration, .mime_type, .file_id, .file_unique_id, .file_size] | @sh' <<< "${_events[$i]}" event[voice_duration]="${_tmp[0]}" event[voice_mime_type]="${_tmp[1]}" event[voice_file_id]="${_tmp[2]}" event[voice_file_unique_id]="${_tmp[3]}" event[voice_file_size]="${_tmp[4]}" unset _tmp _on_voice else _on_msg fi declare -p event unset event done [[ ${#_events[@]} -gt 0 ]] && _update_id=$(jq 'select(.update_id != null) | .update_id' <<< "${_events[-1]}") [[ $_update_id != '' ]] && _offset=$((_update_id+1)) done }