Как создать Telegram-бот для отложенной замены аватарок
Traffic Cardinal Traffic Cardinal  написал 17.05.2025

Как создать Telegram-бот для отложенной замены аватарок

Traffic Cardinal Traffic Cardinal  написал 17.05.2025
11 мин
0
374
Содержание

Наверняка многие помнят, как в начале весны чуть ли не 9 из 10 арбитражных пабликов почти одновременно сменили аву на рекламу одной конфы. Нужно признать — прикольное решение. Вот только ходят слухи, что с тех пор у многих SMMщиков так и не прошло ПТСР. А если серьезно — зачем делать руками то, что можно автоматизировать? Ведь одно дело — сменить аву в 2–3 каналах и другое — в сетке из нескольких десятков. А поможет в этом бот для отложенной замены аватарок в Telegram-каналах, процесс создания которого мы и рассмотрим сегодня.

banner banner

Вообще странно, что отложенной замены авы нет в базовом функционале Телеги
Вообще странно, что отложенной замены авы нет в базовом функционале Телеги

Правда, прежде, чем начать создавать бот, небольшое уточнение: бот должен быть админом канала, в котором вы собираетесь менять аву. Ваш КЭП.

Какие задачи выполняет бот для отложенной замены аватарок

Как очевидно из названия — заменяет авы в указанное время. Это может быть нужно для решения следующих задач:

  • Массовая замена в одно и то же время — например, если это часть РК.

  • Замена авы в неудобное время — например, если вы спите.

  • Минимизация рисков — реклам все равно, почему у вас пропал интернет в оговоренное время. Бот позволяет нивелировать подобные риски.

  • Каруселинг — добавив в текущий код простой цикл, можно создать из аватарок динамическую карусель.

  • Безопасность — если вы не хотите использовать боты для администрирования и вам нужен функционал только для замены аватарок.

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

Принцип работы бота для отложенной замены аватарок

Алгоритмически данный бот очень простой. Суть его функционала сводится к следующему:

  1. Прослушивание эфира и реакция на «не подходящие по формату сообщения» в виде приветствия и описания своего функционала.
  2. Инициация процесса создания задания при получении изображения.
  3. Запоминание изображения, @usernames каналов и времени замены авы в задачу и присвоение ей ID.
  4. Остановка создания задания и вывод просьбы предоставить данные в нужном формате, если @usernames или время указаны некорректно.
  5. Вывод запланированных задач при получении команды /show.
  6. Удаление задачи по ID при получении команды /delete ID (просто номер — без ID).
  7. Создание бэкапа при создании/изменении/удалении задач.
  8. Создание бэкапа для бэкапа перед созданием бэкапа — на случай, если вы «везунчик» и ваш сервер вдруг упадет именно в момент создания резервной копии.
  9. Восстановление бэкапа или бэкапа для бэкапа при получении команды /restore или /restore_old — соответственно.
  10. Автоматическое изменение аватарок согласно списку запланированных задач.

Как видим, ничего сложного.

Бэкапа много не бывает — поэтому держите еще
Бэкапа много не бывает — поэтому держите еще

Пошаговая инструкция, как сделать бот для отложенной замены аватарок

Так как данный бот реализован сугубо на bot_api без использований user_api, то его развертывание пройдет несколько проще, чем в последних наших ботах. Тем не менее ему все равно нужен сервер, где он будет «жить», а потому с него и начнем. Здесь есть два стула: создать свой Python-сервер или же арендовать существующий. Для тестов рекомендуем свой, для полноценной работы — арендный. Затем сервер нужно настроить, введя в консоль:

pip install pyTelegramBotAPI

pip install apscheduler

pip install requests

После загрузки необходимых модулей создаем сам бот, для этого:

1. Находим профиль BotFather — это официальный бот Телеги для создания токенов ботов, пишем ему, следуем его инструкции, получаем токен и сохраняем его.

2. Создаем в корне сервера файла bot.py.

3. Открываем его текстовым редактором и вставляем:

import telebot

import requests

from apscheduler.schedulers.background import BackgroundScheduler

from datetime import datetime

import json

import time

import shutil

BOT_TOKEN = 'ТОКЕН СЮДА'

bot = telebot.TeleBot(BOT_TOKEN)

scheduler = BackgroundScheduler()

scheduler.start()

pending_tasks = {}

user_state = {}

id_counter = 1

BACKUP_FILE = 'tasks_backup.json'

OLD_BACKUP_FILE = 'tasks_backup_old.json'

def save_backup():

try:

shutil.copy(BACKUP_FILE, OLD_BACKUP_FILE)

print("Старый бэкап сохранен.")

except FileNotFoundError:

pass

with open(BACKUP_FILE, 'w') as f:

json.dump(pending_tasks, f, indent=4)

print("Бэкап сохранен.")

def clear_all_jobs():

for job in scheduler.get_jobs():

scheduler.remove_job(job.id)

def restore_backup():

global pending_tasks

clear_all_jobs()

try:

with open(BACKUP_FILE, 'r') as f:

pending_tasks = json.load(f)

print("Бэкап восстановлен.")

except FileNotFoundError:

print("Бэкап не найден.")

return

for task_id, task in pending_tasks.items():

scheduler.add_job(

change_photo,

'date',

run_date=datetime.strptime(task['time'], "%Y-%m-%d %H:%M"),

args=[task['chat_ids'], task['photo_url'], task['user_id'], task_id],

id=f"task_{task_id}"

)

def restore_old_backup():

global pending_tasks

clear_all_jobs()

try:

with open(OLD_BACKUP_FILE, 'r') as f:

pending_tasks = json.load(f)

print("Старый бэкап восстановлен.")

except FileNotFoundError:

print("Старый бэкап не найден.")

return

for task_id, task in pending_tasks.items():

scheduler.add_job(

change_photo,

'date',

run_date=datetime.strptime(task['time'], "%Y-%m-%d %H:%M"),

args=[task['chat_ids'], task['photo_url'], task['user_id'], task_id],

id=f"task_{task_id}"

)

@bot.message_handler(commands=['start'])

def send_welcome(message):

bot.reply_to(message, "Привет! Отправь мне фото и список каналов, для которых нужно изменить аватарку.")

@bot.message_handler(commands=['show'])

def show_scheduled_tasks(message):

print("Содержимое scheduled_tasks:")

print(pending_tasks)

if not pending_tasks:

bot.reply_to(message, "Нет запланированных задач.")

return

response = "Запланированные задачи:\n"

for task_id, task in pending_tasks.items():

response += f"ID: {task_id}\nКаналы: {', '.join(task['chat_ids'])}\nВремя: {task['time']}\n\n"

bot.reply_to(message, response)

@bot.message_handler(content_types=['photo'])

def handle_photo(message):

file_info = bot.get_file(message.photo[-1].file_id)

file_url = f'https://api.telegram.org/file/bot{BOT_TOKEN}/{file_info.file_path}'

user_state[message.from_user.id] = {'photo_url': file_url, 'step': 'channels'}

bot.reply_to(message, "Отправь мне ID каналов или супергрупп (через пробел), для которых нужно установить аватарку (например, @your_channel).")

@bot.message_handler(func=lambda message: user_state.get(message.from_user.id, {}).get('step') == 'channels')

def get_channels(message):

chat_ids = message.text.split()

if not chat_ids:

bot.reply_to(message, "Пожалуйста, отправь хотя бы один канал. Пример: @your_channel")

return

user_state[message.from_user.id]['chat_ids'] = chat_ids

user_state[message.from_user.id]['step'] = 'datetime'

bot.reply_to(message, "Теперь отправь мне дату и время в формате YYYY-MM-DD HH:MM, когда нужно сменить аватарку.")

@bot.message_handler(func=lambda message: user_state.get(message.from_user.id, {}).get('step') == 'datetime')

def get_datetime(message):

try:

target_time = datetime.strptime(message.text, "%Y-%m-%d %H:%M")

if target_time < datetime.now():

bot.reply_to(message, "Время не может быть в прошлом. Пожалуйста, отправь будущее время.")

return

task = user_state[message.from_user.id]

task['time'] = target_time.strftime("%Y-%m-%d %H:%M")

global id_counter

task_id = id_counter

id_counter += 1

task['id'] = task_id

task['user_id'] = message.from_user.id

scheduler_task_id = f"task_{task_id}"

scheduler.add_job(

change_photo,

'date',

run_date=target_time,

args=[task['chat_ids'], task['photo_url'], message.chat.id, task_id],

id=scheduler_task_id

)

pending_tasks[task_id] = task

save_backup()

del user_state[message.from_user.id]

bot.reply_to(message, f"Задача запланирована на {target_time.strftime('%Y-%m-%d %H:%M')} с ID {task_id}.")

except ValueError:

bot.reply_to(message, "Неверный формат даты и времени. Пожалуйста, используйте формат YYYY-MM-DD HH:MM.")

def change_photo(chat_ids, file_url, user_id, task_id):

photo = requests.get(file_url).content

url = f'https://api.telegram.org/bot{BOT_TOKEN}/setChatPhoto'

success_count = 0

for chat_id in chat_ids:

response = requests.post(url, data={'chat_id': chat_id}, files={'photo': photo})

if response.status_code == 200:

success_count += 1

if success_count > 0:

bot.send_message(user_id, f"Фото успешно обновлено для {success_count} каналов!")

else:

bot.send_message(user_id, "Произошла ошибка при изменении аватарки. Проверьте ID каналов и попробуйте снова.")

if task_id in pending_tasks:

del pending_tasks[task_id]

scheduler.remove_job(f"task_{task_id}")

save_backup()

@bot.message_handler(commands=['delete'])

def delete_task(message):

try:

task_id = int(message.text.split()[1])

if task_id in pending_tasks:

scheduler.remove_job(f"task_{task_id}")

del pending_tasks[task_id]

save_backup()

bot.reply_to(message, f"Задача с ID {task_id} была удалена.")

else:

bot.reply_to(message, f"Задача с ID {task_id} не найдена.")

except (IndexError, ValueError):

bot.reply_to(message, "Пожалуйста, укажите корректный ID задачи.")

@bot.message_handler(commands=['restore'])

def restore_task(message):

restore_backup()

bot.reply_to(message, "Бэкап успешно восстановлен.")

@bot.message_handler(commands=['restore_old'])

def restore_old(message):

restore_old_backup()

bot.reply_to(message, "Старый бэкап успешно восстановлен.")

bot.polling()

4. Вместо «ТОКЕН СЮДА» вставляем токен, который мы ранее сохраняли в шаге 1.

5. Сохраняем bot.py.

6. Запускаем бот, вводя в консоль:

python bot.py

7. Тестируем работоспособность.

Демонстрация работы

Создаем тестовые каналы, в которых будем менять аву
Создаем тестовые каналы, в которых будем менять аву

Забрасываем в бот пикчу, которая станет авой, указываем @names каналов и задаем время замены авы
Забрасываем в бот пикчу, которая станет авой, указываем @names каналов и задаем время замены авы

Видим, что в заданное время бот сменил каналам аватарки, — тестим дальше
Видим, что в заданное время бот сменил каналам аватарки, — тестим дальше

А вот что было у бота в «голове» пока задача была активной
А вот что было у бота в «голове» пока задача была активной

В этот раз создаем две задачи: замену авы в каналах 1, 2, 3 и чуть позже — еще одну замену, но в этот раз уже только в каналах 1 и 3.
В этот раз создаем две задачи: замену авы в каналах 1, 2, 3 и чуть позже — еще одну замену, но в этот раз уже только в каналах 1 и 3.

Видим, что в этот раз в «голове» у бота уже 2 задачи
Видим, что в этот раз в «голове» у бота уже 2 задачи

Пока часики тикают, быстренько проверяем функционал удаления задач и функционал восстановления резервных копий
Пока часики тикают, быстренько проверяем функционал удаления задач и функционал восстановления резервных копий

Как видно, в «голове» у бота удаленная задача пропала
Как видно, в «голове» у бота удаленная задача пропала

А после — была восстановлена из резервной копии
А после — была восстановлена из резервной копии

Несмотря на удаление/восстановление, в назначенное время все сработало, как и должно было, ждем дальше
Несмотря на удаление/восстановление, в назначенное время все сработало, как и должно было, ждем дальше

Видим, что задача для двух каналов также корректно обработана: ава сменилась лишь там, где и должна была. Параллельно создаем задачу с ID 3, которую тут же удалим на скрине ниже
Видим, что задача для двух каналов также корректно обработана: ава сменилась лишь там, где и должна была. Параллельно создаем задачу с ID 3, которую тут же удалим на скрине ниже

Удаляем задачу с ID 3 — чтоб продемонстрировать, что удаленные задачи реально удалены. И, как видим, в 11:43 авы не менялись
Удаляем задачу с ID 3 — чтоб продемонстрировать, что удаленные задачи реально удалены. И, как видим, в 11:43 авы не менялись

Подводя итоги

Чтобы автоматически сменить аватарку во всей сетке пабликов, вовсе не обязательно кошмарить SMM-отдел или использовать непонятные админ-боты — ведь можно сделать свой. И теперь вы знаете как.

Здравствуйте! У вас включен блокировщик рекламы, часть сайта не будет работать!