Задача кажется простой, когда ничего про нее не знаешь и когда решил.
В один “прекрасный” день, я понял, что мне не интересно сидеть на многочисленных форумах, а хочется создать свой канал и делиться “мудростью”.
Мне нравится Телеграм заложенными в него возможностями в том числе и ботами, поэтому канал в виде блога был создан там. Начал искать ботов, помогающих оформлять сообщения…. а так как мне хочется не нашел. Что ж, напишем сами. Умные люди посоветовали писать на 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 сервером, получаем на локальном хосте порт куда можно посылать трафик с нашей стороны, а выйдет он с другой стороны (уже где-то в Германии). Для удобства можно добавить некое подобие автоматизации этого соединения — скрипт и ярлык на рабочем столе, которым его запустим, при необходимости. Под “нормальным” способом здесь я понимаю ситуацию, где входную и выходную точку контролируем мы сами — слева наш ноутбук, справа
Скрипт
/home/user/proxy.sh
Код скрипта
#!/bin/bash
ssh -f -D 1080 user@12.34.56.78 sleep 72000
После того как у нас соединение с сервером установлено, а порт открыт, нам нужно как-то направить туда трафик. Идя по пути наименьшего сопротивления и чтобы не думать о том как настраивать proxy в IDEdockerpython можно сделать одну настройку на всех, такой настройкой будет выступать 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.
А тут видео как пользоваться
Буду благодарен за любую конструктивную критику.
Автор: SGKond