https://habr.com/ru/post/477178/- Системы обмена сообщениями
- Python
- Социальные сети и сообщества
Задача кажется простой, когда ничего про нее не знаешь и когда решил.
В один “прекрасный” день, я понял, что мне не интересно сидеть на многочисленных форумах, а хочется создать свой канал и делиться “мудростью”.
Мне нравится Телеграм заложенными в него возможностями в том числе и ботами, поэтому канал в виде блога был создан там. Начал искать ботов, помогающих оформлять сообщения…. а так как мне хочется не нашел. Что ж, напишем сами. Умные люди посоветовали писать на Python.
Прочитал первый попавшийся в инете самоучитель на 149 страниц. Я знаком с Pascal, FoxPro, Interbase и даже (ха-ха 3 раза) 20 лет назад продавал свои программы, а потом как-то не сложилось, ушел в торговлю. Работа программистом мне сильно помогла в постановке задач для кодеров кстати. Но вернемся к Python, кажется, ничего сложного, ведь и на BASIC программировать можно было и это не мой институтский диплом с программно-аппаратным комплексом генератора поверки МИГа на Assembler. Одна проблема, всё это было давно, так что возвращаясь к заголовку — кажется что просто, потому что пока ничего не знаю про задачу, но попробовать стоит.
Я решил, что удобнее всего делать проект со смартфона на Андроид, ибо он всегда под рукой. Итак ставим:
- Pydroid 3 — IDE for Python 3 Собственно Питон для Андроид.
- @BotFather, В Телеграм устанавливаем отца всех ботов — он понадобится чтобы получить идентификатор вашего бота и сделать основные настройки.
- Rebootr Приложение для запуска проекта на heroku.
- GIT Приложение для онлайн-хостинга репозиториев.
- Windscribe Без VPN никуда?
- Termux Эмулятор терминала и среды Linux.
И что в сухом остатке? Программировать на смартфоне можно в теории, но невозможно на практике. Максимум проверить код, исправить ошибку, исследовать работоспособность.
Такое длинное вступление, а что я хотел получить от своего бота. Сначала мне показалось достаточным добавлять в конце сообщения Хэштег. Потом пришла мысль “накрыть” его ссылкой на мой канал, так при репосте будет дополнительная завлекуха на канал источник. Потом, добавил автоматизацию ссылки на источник, откуда я беру сообщение. Далее сделаю лирическое отступление. Реклама, конечно двигатель прогресса. Но иногда ее количество зашкаливает. Телеграм был выбран мной в том числе и из-за того, что тут есть возможность бороться с последней. Я уважаю читателей своего канала и поэтому интересные новости, найденные на просторах инета чищу от рекламы и отправляю в канал. В то же время я уважаю авторов и практически всегда даю ссылку на источник в виде “Читать далее...”. По причине нелюбви рекламы я скачиваю контент с Ютуба и выкладываю его в своем канале в виде видеофайла. В один определенный момент бот, который качал видео сошел с ума и стал присылать мне рекламу каждый час. Так в моем боте появилась возможность скачивать видео с ютуба. Недавно кстати познакомился с автором этого бота, он был сильно удивлен, т.к. по его словам отправляет рекламу “всего” 20 раз в месяц. Тоже самое произошло и с ботом, который делает водяной знак — он был отправлен в топку, а у меня появилась возможность делать водяной знак.
Для того, чтобы практически с нуля написать программу пришлось много информации искать в интернете. Надеюсь, что тем, кто пойдет по моим стопам это поможет. Итак откуда я черпал информацию и чем пользовался:
- Мне действительно помогли статьи на Хабре. Поэтому не буду переписывать как и что установить. Тут все есть. Кстати, я обращался в личку к авторам и мне ни разу не отказали в помощи.
- github Сервис онлайн-хостинга репозиториев, обладающий всеми функциями распределенного контроля версий и функциональностью управления исходным кодом. Букварь
- heroku — облачная PaaS-платформа, поддерживающая ряд языков программирования. Очень быстро от него отказался.
- pyTelegramBotAPI — Одна из основных библиотек при написании бота для Телеграм.
- Учебник по написанию ботов
- Python 3 для начинающих
- Боты: информация для разработчиков
- Справочник по HTML
- Без VPN никуда?
Второе лирическое отступление или война план покажет. Когда я начал писать бота, первым делом посмотрел чужие коды. Если нет каментов понять можно с трудом:
Земля тряслась — как наши груди,
Смешались в кучу кони, люди,
И залпы тысячи орудий
Слились в протяжный вой…
Лермонтов писал о коде. В куче лежат функции, декораторы. Нет красоты кода, о ресурсах никто не заботится. Хотя красоту скорее всего может увидеть извращенец мазохист. До меня очень быстро дошел смысл фразы знакомого программиста “Посмотри прогу, может быть разберешься”. Самый главный взрыв мозга у меня был, когда я наконец то осознал, что код событийный, а не последовательный. Это другой уровень.
Вторая проблема отсутствие хорошей документации. Даже на басурманском. Приведу пример. Я отправляю в телеграм картинку, а он ее безбожно жмет. Оказалось что в строке был прописан неверный аргумент:
file_info = bot.get_file(message.photo[-1].file_id)
А что документация? Идем к первоисточнику
Это же массив. Можно по нему пройтись, поизучать, где какой размер возвращается. Спасибо, умные люди подсказали, что прописать.
Хотя о чем я, если даже гуру в недоумении.
Когда писал код водяного знака использовал бесплатный шрифт и чтобы сделать его жирным применил решение вывода сообщения трижды со смещением на пиксель, не знаю насколько красивое решение, но работает.
font = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", width//20)
pos = (width//4, height - height//10)
text = skanal
drawing.text(pos, text, fill=black, font=font)
pos = (1 + width // 4, 1 + height - height // 10)
drawing.text(pos, text, fill=black, font=font)
pos = (2 + width // 4, 2 + height - height // 10)
drawing.text(pos, text, fill=black, font=font)
Позиция как видите выбирается в зависимости от размера картинки, высота шрифта тоже. Тут же столкнулся с интересным моментом: хотя шрифт и является неотъемлемой частью библиотеки PIL, так как в первой строке написано локально работает, а в Docker — нет. Выход скачать его в репозиторий, добавить путь в файл окружения и прописать другой путь в проге.
Еще один непостижимый для меня момент произошел с картинкой после обработки с помощью библиотеки PIL (сразу после водяного знака). Отправляю ее в свой бот:
with open(photo_path, 'rb') as fi:
bot.send_photo(message.chat.id, fi)
Все замечательно, картинка нравится. Затем мне требуется добавить к картинке комментарий и посмотреть, а красиво ли все смотрится вместе? Пишем:
bot.send_photo(message.chat.id, message.photo[-1].file_id, caption='Какая красота')
В бот почему то уходит первоначальная, необработанная картинка. Хорошо, попробуем обмануть: getupdates.offset -1 толку никакого, Телеграм уверен, что это одно и тоже фото. Хорошо, делаем так:
with open(photo_path, 'rb') as fi:
info = bot.send_photo(message.chat.id, fi)
Переписываем:
bot.send_photo(message.chat.id, info.photo[-1].file_id, caption='Какая красота')
Результат тот же — выводится первоначальная картинка. И только замена message в первом аргументе на info дала желаемый результат.
Также тут приведу кусок интересного кода начального уровня загрузки с ютуб (NB: без проверки на ошибки):
elif message.entities: # Работа со ссылками pkanal = 6
for item in message.entities:
if item.type == "url" and message.text.find(' ') == -1:
if 'youtube.com' in message.text or 'youtu.be' in message.text: # Загружаем с Ютуб
ydl_opts = {'outtmpl': '/tmp/f.mp3', 'preferredcodec': 'mp3', 'max_filesize': 60000000}
link_of_the_video = message.text
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
ydl.download([link_of_the_video])
bot.delete_message(message.chat.id, message.message_id)
if os.path.exists('/tmp/f.mp3'): # файл есть
video = open('/tmp/f.mp3', 'rb')
bot.send_video(message.chat.id, video)
os.remove('/tmp/f.mp3')
pkanal = 6
else: # файла нет
bot.send_message(message.chat.id, 'Слишком большой файл', parse_mode='html', disable_web_page_preview=True)
Для меня было камнем преткновения, что entities это массив массивов и надо “пробежаться” по всему массиву чтобы бот понял, что работаем со ссылкой. Еще выяснилось, что пользователи отправляют ссылку в бот как “Поделиться” из Ютуб поэтому в примере прописано еще и “youtu.be”. Как сразу отправить в Телеграм файл я не придумал, поэтому мы его сохраняем, отправляем и затем удаляем. Во время тестирования мне сразу указали на то, что люди начнут качать гигантские файлы — позднее пришлось ввести ограничение.
Перед релизом бота вдруг выяснилось, что у меня нет проверки на права доступа в канал. К примеру зная мой канал любой пользователь бота мог туда отправить сообщение, т.к. бот является Администратором. Пришлось срочно делать проверку:
if message.from_user.id in [adm_obj.user.id for adm_obj in bot.get_chat_administrators(chat_id)]:
Тут получаем от канала список Администраторов и смотрим является ли автор сообщения тоже Администратором.
Пара слов о том, как пришлось воевать с роскомнадзором. Поскольку доступ к API заблокирован, для разработки бота локально нужно как-то пропустить трафик через наших доблестных защитников. Сделать это можно двумя путями — через VPN или через proxy. Самым простым и быстрым и “нормальным” способом можно считать ssh тоннель: устанавливаем соединение между клиентом и proxy сервером, получаем на локальном хосте порт куда можно посылать трафик с нашей стороны, а выйдет он с другой стороны (уже где-то в Германии). Для удобства можно добавить некое подобие автоматизации этого соединения — скрипт и ярлык на рабочем столе, которым его запустим, при необходимости. Под “нормальным” способом здесь я понимаю ситуацию, где входную и выходную точку контролируем мы сами — слева наш ноутбук, справа VPS в Германии. по середине трафик могут перехватывать сколько угодно, он шифрованный, а на выходе мы оказываемся в юрисдикции другого государства, и законы РФ к нему не применимы. Как плюс мы получаем дополнительно гарантию того что proxy сервер не будет изменен или выключен, пока мы не сделаем этого самостоятельно. Т.е. в отличие от всяких дядиных VPN у нас появляется спокойствие и уверенность в завтрашнем дне.
Скрипт
/home/user/proxy.sh
Код скрипта
#!/bin/bash
ssh -f -D 1080 user@12.34.56.78 sleep 72000
После того как у нас соединение с сервером установлено, а порт открыт, нам нужно как-то направить туда трафик. Идя по пути наименьшего сопротивления и чтобы не думать о том как настраивать proxy в IDE\docker\python можно сделать одну настройку на всех, такой настройкой будет выступать proxychains. Если запустить любой софт с помощью этой утилиты, то она перенаправит трафик через цепочку proxy которые прописаны в конфиге.
/etc/proxychains.conf
В нашем случае это одна цепочка и написать ее не составляет никакого труда.
socks5 127.0.0.1 1080
и еще один костыль, который был предпринят, чтобы только не настраивать VPN (сарказм) — это способ запуска питоновского приложения из PyCharm. В простом случае чтобы запустить через proxychains приложение достаточно написать proxychains app.py и всё. Но в IDE обязательно требуется указать интерпретатор. Обойти это просто — создаем новую «run configuration», выбираем shell script. и заполняем поля
После чего запуск с точки зрения IDE приобретает такой вид: proxychains python3 app.py — собственно это нам и надо. Таким образом, когда мы хотим заняться проектом все что нужно сделать — запустить скрипт на рабочем столе, а потом для запуска бота нажать кнопку “play" в ide. Всю остальную магию сделают proxychains и ssh.
Наконец бот написан, оттестирован. Что дальше? С одной стороны хочется заявить о себе, с другой стороны, я думаю, он реально может кому то пригодиться. И тут мы сталкиваемся с еще одной проблемой Телеграм; у него нет единого каталога каналов и ботов. Вполне возможно бот подобный моему существует, но повторюсь я его не нашел. А где то в трамвае сидит и мучается человек, которому хочется красиво оформить сообщение в канал и он все делает ручками.
Если вы уже запустили мой бот, то увидели, что есть хэштег #Реклама. Как же так? — спросите вы. А тут я пошел на поводу у конечных пользователей — многие выкладывают рекламу в своих каналах и быстро привыкнув к оформлению сообщений с помощью бота, попросили добавить. Рекламу можно не любить, бороться с ней, но это суровые и необходимые для пользователей реалии.
Проект некоммерческий, поэтому думаю можно назвать сам бот @SGK_espace_bot.
А тут видео как пользоваться
Буду благодарен за любую конструктивную критику.