Как стать автором
Обновить

Телеграм-бот для заметок и не только

Время на прочтение6 мин
Количество просмотров2.4K

Как часто у вас бывало, что вдруг пришла в голову какая-то идея, или вспомнилось важное дело, или просто надо что-то будет сделать и не забыть - но именно сейчас у вас совершенно нет времени открывать специальную программу, создавать в ней заметку или планировать задачу, раздумывая, куда, как, и главное когда всё это?

Нужно просто быстрее записать задачу, хоть как, а подумать можно и чуть позже.
Главное - не забыть подумать.

Вот для решения этой задачи удалось приспособить телеграм-бота.
Вообще-то изначально он делался совершенно для другого, но какая теперь разница, если использовать можно по разному...

Итак, по порядку:

Создание бота в Телеграм

Допустим, вам нужен бот в Телеграм - неважно зачем.
Для начала - нужно его создать.

Если ничего не поменялось - для этого достаточно написать в Телеграме боту @BotFather сообщение /newbot, ответить на вопросы, дав ему имя и username, в ответ придет API_KEY в виде длинной строки символов.
API_KEY нужно сохранить и никому не показывать - собственно говоря, на этом этапе бот создан.

Общий принцип работы с ботом: к нему отправляются HTTPS-запросы.
POST-запрос - если нужно что-то отправить, и GET-запрос, если нужно что-то получить.
В запросе указывается API_KEY бота, а в URL - желаемый метод, который надо вызвать.

Всё остальное, библиотеки для разных языков программирования, разнообразные модули-плагины - это всё обертка вокруг HTTPS-вызовов.
И если задача не требует интеграции этих запросов с какими-нибудь локальными базами данных или фреймворками - работать с ботом можно хоть из командной строки, а точнее - из шелл-скриптов.

Всё, что для этого понадобится - какая-нибудь программа, умеющая отправлять запросы (например, curl), и какая-нибудь программа, умеющая разбирать JSON - например, jq

apt install curl jq

Теперь всё необходимое есть. Осталось написать скрипты.

Как оно работает

Во-первых, "для целей данной статьи", определим, что бот - это та штука в Телеграме, "виртуальный юзер", который умеет получать сообщения и отправлять их. Он управляется нашими запросами.
Соответственно, "писать бота" не надо, он уже есть, нужно написать программу, работающую с ботом.

Во-вторых, бот умеет отправлять сообщения кому-то конкретному, кого он уже знает - для этого пользователь должен сначала сам написать боту. После того как он написал - бот запоминает его как некоего юзера, с конкретным chat_id, и вот этому chat_id он и сможет отправлять сообщения.
То есть, нельзя отправить сообщение просто Васе Пупкину, даже если нам известен его телефон или юзернейм - сначала сам Вася Пупкин должен написать боту что-нибудь.

И в третьих, бот, получив сообщение, может работать в одном из двух режимов: либо он держит сообщение в себе, и ждет когда мы у него запросим "есть чё?", либо он работает с вебхуками: мы настраиваем свой URL, на который бот отправит сообщение - там мы его примем и обработаем.
Или-или, одно из двух.

Вебхуки хороши, когда есть свой вебсервер, настроенный на прием сообщений - тогда они приходят почти мгновенно, как только дойдут до бота. Но нужен сервер, реальный IP-адрес.

Запросы можно отправлять в любой момент, но если отправлять их слишком часто - в 99.9% случаев ответ будет пустым, а если редко - бот реагирует на сообщения пользователя с задержкой: пока там мы у него запросим обновления, пока обработаем, пока отправим ответ...

И наконец, типы сообщений: из самых распространенных - текст, фото (Телеграм делает для них превью), видео (Телеграм их обрабатывает как видеофайлы), просто файлы (вроде бы ничего не делает с ними).
Есть еще аудио (голосовые сообщения, например), "кружочки" (видеофайл), команды бота (текст с доп. параметрами) и еще что-то там.
Сейчас это все пока не особо важно.

Решаем задачу

Задача следующая: нужен телеграм-бот, который умеет принять от пользователя текстовое или иное сообщение, и сохранить его на компьютере, для последующего разбора в свободное время.

Сценарий использования примерно такой: подписываемся на своего бота, когда в голову приходит очередная гениальная идея или что-нибудь еще, заслуживающее записи - открываем Телегу и пишем. Или говорим. Или отправляем документ из почты, или фотографию чего-нибудь нужного.
Когда бот его сохранит - он сообщит нам об этом. Потом, на компьютере, разберемся.

Реализация: бот, который внутри Телеграм, получит сообщение сразу, и оно уже будет сохранено, там, в Телеграме.
А вот забирать его оттуда на диск сразу не обязательно - немедленная реакция не требуется, достаточно запустить скрипт по крону раз в N минут.
Поэтому вебхуки не используем, используем разовые запросы.

Для начала - попробуем написать что-нибудь своему боту. И да, он не ответит, не умеет еще.
Но зато теперь можно протестировать запрос обновления:

curl https://api.telegram.org/bot<== your API_KEY ==>/getUpdates

В ответ мы должны получить JSON-строку, в которой кроме всего прочего будет указано, от кого получено сообщение, и id для этого пользователя.
(кстати, отправляя разное - фото, видео и т.д. - можно узнать в каком виде приходят сообщения)

Вот теперь уже можно отправлять свои сообщения:

#!/bin/sh

TOKEN='<== your API_KEY ==>'
CHAT_ID=<== your CHAT_ID ==>
MESSAGE="Наш ответ"
URL="https://api.telegram.org/bot${TOKEN}/sendMessage"

curl -s -X POST $URL -d chat_id=$CHAT_ID -d text="$MESSAGE"

Если сообщение пришло - значит, всё работает. Остается написать скрипт, который будет запрашивать обновления и обрабатывать результаты:

#!/bin/sh

PATH=$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin; export PATH

TOKEN='<== your bot API token ==>'
API_URL="https://api.telegram.org/bot$TOKEN"

SAVE_DIR="$HOME/NewInfo"
CONFIG_DIR="$HOME/.config/tlg_bot"
OFFSET_FILE="$CONFIG_DIR/seq"

# functions
send_reply() {
  local chat_id=$1
  local message=$2
  curl -s -X POST $API_URL/sendMessage -d chat_id=$chat_id -d text="$message"
}

get_file() {
  local file_id=$1
  local file_name=$2

  file_path=$(curl -s "$API_URL/getFile?file_id=$file_id" | jq -r '.result.file_path')
  file_url="https://api.telegram.org/file/bot$TOKEN/$file_path"

  curl -s "$file_url" -o "$SAVE_DIR/$file_name"
}
# begin

mkdir -p "$SAVE_DIR"
mkdir -p "$CONFIG_DIR"

# read offset
if [ -f "$OFFSET_FILE" ]; then
    OFFSET=$(cat "$OFFSET_FILE")
else
    OFFSET=0
fi

# get updates
response=$(curl -s "$API_URL/getUpdates?offset=$OFFSET&timeout=10")

echo "$response" | jq -c '.result[]' |\
  while read -r item; do
    update_id=$(echo "$item" | jq '.update_id')
    message=$(echo "$item" | jq '.message')

    # save offset
    new_offset=$((update_id + 1))
    echo "$new_offset" > "$OFFSET_FILE"

    message_id=$(echo "$message" | jq '.message_id')
   chat_id=$(echo "$message" | jq '.chat.id')
    date=$(echo "$message" | jq -r '.date')

    if echo "$message" | jq 'has("text")' | grep -q true; then
      text=$(echo "$message" | jq -r '.text')
      filename="$SAVE_DIR/message_${chat_id}_${date}.txt"
      echo "$text" > "$filename"
    fi

    if echo "$message" | jq 'has("document")' | grep -q true; then
      file_id=$(echo "$message" | jq -r '.document.file_id')
      file_name=$(echo "$message" | jq -r '.document.file_name')
      get_file "$file_id" "$file_name"
    fi

    if echo "$message" | jq 'has("video")' | grep -q true; then
      file_id=$(echo "$message" | jq -r '.video.file_id')
      file_name="video_${chat_id}_${message_id}.mp4"
      get_file "$file_id" "$file_name"
    fi

    if echo "$message" | jq 'has("voice")' | grep -q true; then
      file_id=$(echo "$message" | jq -r '.voice.file_id')
      file_name="voice_${chat_id}_${message_id}.ogg"
      get_file "$file_id" "$file_name"
   fi

    if echo "$message" | jq 'has("video_note")' | grep -q true; then
      file_id=$(echo "$message" | jq -r '.video_note.file_id')
      file_name="video_note_${chat_id}_${message_id}.mp4"
      get_file "$file_id" "$file_name"
    fi

    if echo "$message" | jq 'has("photo")' | grep -q true; then
      file_id=$(echo "$message" | jq -r '.photo[-1].file_id')
      file_name="photo_${chat_id}_${message_id}.jpg"
      get_file "$file_id" "$file_name"
    fi

    send_reply "$chat_id" "Copied"
  done

С помощью curl получаем информацию, с помощью jq вытаскиваем из JSON нужные поля, остальное всё стандартные утилиты ОС.

Текстовые сообщения приходят сразу, и сразу же сохраняются.
Файлы, видео и прочие картинки - требуется дополнительно запросить, какой URL им соответствует, а потом запросить сам файл по этому URL.

Настроим запуск этого скрипта из крона и отправим сообщение боту в Телеграм: через некоторое время оно появится в виде файла в заданном каталоге, а бот пришлет ответ.

И заодно, раз уж бот есть, можно сделать простые скрипты для автоматической отправки разного-нужного:

Отправка текста (send-tlg):

#!/bin/sh

PATH=$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin; export PATH

TOKEN='<== your bot API token ==>'
CHAT_ID='<== your chat ID ==>'

URL="https://api.telegram.org/bot${TOKEN}/sendMessage"

read MESSAGE

if [ "x$MESSAGE" != "x" ]; then
  curl -s -X POST $URL -d chat_id=$CHAT_ID -d text="$MESSAGE"
  sleep 2
fi

Отправка фото (send-tlg-photo):

#!/bin/sh

PATH=$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin; export PATH

TOKEN='<== your bot API token ==>'
CHAT_ID='<== your chat ID ==>'

URL="https://api.telegram.org/bot${TOKEN}/sendPhoto"

if [ "x$1" != "x" ] && [ -f "$1" ] ; then
  curl -s -X POST $URL -F "chat_id=$CHAT_ID" -F "photo=@$1"
  sleep 2
fi

Отправка видео:

#!/bin/sh

PATH=$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin; export PATH

TOKEN='<== your bot API token ==>'
CHAT_ID='<== your chat ID ==>'

URL="https://api.telegram.org/bot${TOKEN}/sendVideo"

if [ "x$1" != "x" ] && [ -f $1 ] ; then
  curl -s -X POST $URL -F "chat_id=$CHAT_ID" -F "video=@$1"
  sleep 2
fi

В комментариях уже говорили "а у меня Неразобранное - куча файлов, я забываю их разбирать!" - что же, эту проблему тоже можно решить:
Еще один скрипт, проверяющий наличие неразобранных файлов: если они есть - будет ругаться об этом в Телеграм, как та надоедливая зеленая сова.

Насколько надоедливым он будет - зависит от того, как вы настроите его запуск по крону.

#!/bin/sh

PATH=$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin; export PATH

SAVE_DIR="$HOME/NewInfo"

if [ -d "$SAVE_DIR" ]; then
  files=$(ls $SAVE_DIR | wc -l)

  if [ $files -gt 1 ]; then
    echo "You have $files unsorted files!" | send-tlg
  elif [ $files -eq 1 ]; then
    echo "You have $files unsorted file!" | send-tlg
  fi
fi

Закинул на Гитхаб: https://github.com/JBFW/Telebot

Теги:
Хабы:
+1
Комментарии18

Публикации

Ближайшие события