Недавно сидел я в одном сообществе программистов в Telegram и заметил один очень любопытный профиль. Любопытным было следующее — на главном фото у него было изображено нынешнее время. Мне стало жутко интересно как он этого добился, и я решил во что бы то ни стало написать такую же программу.
До этого я часто работал с Telegram-ботами при помощи библиотеки PyTelegramBotAPI, поэтому предположил, что такая функция есть в API ботов. Наверняка, это было глупейшее предположение в моей жизни, т.к. фото было на аватарке профиля именно пользователя, а не бота — и вскоре я в этом убедился, не найдя ни одной предпосылки к возможности изменить фото профиля.
Я начал сёрфить интернет и наткнулся на довольно удобный инструмент — telethon. Он как раз и позволял мне заходить в Telegram как юзер, а не как бот. Что ж, полагаю это был самый первый и самый большой шаг к цели. Далее давайте разберем как же именно воссоздать «часы» на нашей аватарке.
Переходим по ссылке, вводим номер телефона, после чего получаем код подтверждения. Подробнее об этом написано тут. Итак, мы получаем оттуда две важные для нас вещи — это api_id и api_hash. Создаем файл config.py и вводим туда следующий код:
Теперь создаем файл main.py в котором пишем:
Важно, чтобы main.py и config.py были на одном файловом уровне, т.е. в одной папке иначе строка from .config import * даст ошибку. Класс TelegramClient — это именно то, что позволит нам войти в Telegram в качестве обычного пользователя. Далее в этом же файле пишем следующее:
Таким образом, можно считать, мы залогинились в Telegram. ИМЯ СЕССИИ можете выбрать любое, на свое усмотрение (например, «ананас»). Итак, мы подключились к телеграму. Теперь пора думать о фотографиях…
Пожалуй, этот шаг явился самым легким для меня, т.к. я уже долгое время разрабатывал различное ПО, использующее компьютерное зрение, а следовательно, работа с изображениями стала чем-то обыденным. Тут все просто — устанавливаем библиотеку opencv, позволяющую творить чудеса с фотографиями. Создаем файл utils.py и пишем в ней:
Данная функция нам нужна, чтобы на фотографии было указано время в формате Ч: ММ(были и другие способы сделать это, но я предпочел именно этот).
Итак, приступаем к созданию самих фотографий. Создаем файл generate_time_images.py и пишем в нем:
Этих библиотек должно хватить нам для создания фотографий с указанием времени. Далее пишем функцию для получения черного фона, на котором мы будем писать время:
Теперь нужно будет пройтись циклом по каждой минуте в сутках и сгенерировать фотографию с указанием времени. Заранее создайте папку time_images/ куда будете сохранять фотографии. Итак, пишем:
Для создания колеекции фотографий осталось сделать только одно — запустить generate_time_images.py. После запуска мы видим, что в папке time_images/ появилось множество фотографий. Должны получиться примерно такие фотографии:
У telethon есть очень удобная штука — называется UploadProfilePhotoRequest. Импортируем ее в наш ранее написанный main.py:
Разумеется, мы не должны обновлять аватарку в каждый момент времени — достаточно делать это раз в минуту. Для этого мы должны знать момент, когда заканчивается старая минута и начинается новая — именно в этот момент мы и поменяем фотку. Пишем еще одну небольшую функцию в utils.py:
Да, да, мы передаем в нее строку со временем предыдущего обновления аватарки. Конечно, и тут были другие способы реализации, но писал я это все «на скорую руку», поэтому сильно об оптимизации не задумывался. Продолжаем заполнять наш main.py:
DeletePhotosRequest нам нужен для того, чтобы удалить предыдущие аватарки, чтобы создавался эффект, что мы не добавляем новое фото — оно меняется само собой. Для того, чтобы не перегружать процессор, можно добавить time.sleep(1) в конец цикла(разумеется, импортировав сперва time.py).
Готово! Запустите main.py и ваша аватарка превратится в часы. Как более оригинальный вариант, можете попробовать изменить текст на фотках, например, на такой:
До этого я часто работал с Telegram-ботами при помощи библиотеки PyTelegramBotAPI, поэтому предположил, что такая функция есть в API ботов. Наверняка, это было глупейшее предположение в моей жизни, т.к. фото было на аватарке профиля именно пользователя, а не бота — и вскоре я в этом убедился, не найдя ни одной предпосылки к возможности изменить фото профиля.
Я начал сёрфить интернет и наткнулся на довольно удобный инструмент — telethon. Он как раз и позволял мне заходить в Telegram как юзер, а не как бот. Что ж, полагаю это был самый первый и самый большой шаг к цели. Далее давайте разберем как же именно воссоздать «часы» на нашей аватарке.
Шаг первый. Получить доступ к входу в Telegram из кода
Переходим по ссылке, вводим номер телефона, после чего получаем код подтверждения. Подробнее об этом написано тут. Итак, мы получаем оттуда две важные для нас вещи — это api_id и api_hash. Создаем файл config.py и вводим туда следующий код:
api_id = <ВАШ API_ID>
api_hash = <ВАШ API_HASH>
Теперь создаем файл main.py в котором пишем:
from telethon import TelegramClient, sync
from .config import *
Важно, чтобы main.py и config.py были на одном файловом уровне, т.е. в одной папке иначе строка from .config import * даст ошибку. Класс TelegramClient — это именно то, что позволит нам войти в Telegram в качестве обычного пользователя. Далее в этом же файле пишем следующее:
client = TelegramClient(<ИМЯ СЕССИИ>, api_id, api_hash)
client.start()
Таким образом, можно считать, мы залогинились в Telegram. ИМЯ СЕССИИ можете выбрать любое, на свое усмотрение (например, «ананас»). Итак, мы подключились к телеграму. Теперь пора думать о фотографиях…
Шаг второй. Создаем источник фотографий с указанием времени
Пожалуй, этот шаг явился самым легким для меня, т.к. я уже долгое время разрабатывал различное ПО, использующее компьютерное зрение, а следовательно, работа с изображениями стала чем-то обыденным. Тут все просто — устанавливаем библиотеку opencv, позволяющую творить чудеса с фотографиями. Создаем файл utils.py и пишем в ней:
def convert_time_to_string(dt):
return f"{dt.hour}:{dt.minute:02}"
Данная функция нам нужна, чтобы на фотографии было указано время в формате Ч: ММ(были и другие способы сделать это, но я предпочел именно этот).
Итак, приступаем к созданию самих фотографий. Создаем файл generate_time_images.py и пишем в нем:
from .utils import *
import cv2
import numpy as np
from datetime import datetime, timedelta
Этих библиотек должно хватить нам для создания фотографий с указанием времени. Далее пишем функцию для получения черного фона, на котором мы будем писать время:
def get_black_background():
return np.zeros(500, 500)
Теперь нужно будет пройтись циклом по каждой минуте в сутках и сгенерировать фотографию с указанием времени. Заранее создайте папку time_images/ куда будете сохранять фотографии. Итак, пишем:
start_time = datetime.strptime("2019-01-01", "%Y-%m-%d") # Можете выбрать любую дату
end_time = start_time + timedelta(days=1)
def generate_image_with_text(text):
image = get_black_background()
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(image, convert_time_to_string(datetime.now()), (int(image.shape[0]*0.35), int(image.shape[1]*0.5)), font, 1.5, (255, 255, 0), 2, cv2.LINE_AA)
return image
while start_time < end_time:
text = convert_time_to_string(start_time)
image = generate_image_with_text(text)
cv2.imwrite(f"time_images/{text}.jpg", image)
start_time += timedelta(minutes=1)
Для создания колеекции фотографий осталось сделать только одно — запустить generate_time_images.py. После запуска мы видим, что в папке time_images/ появилось множество фотографий. Должны получиться примерно такие фотографии:
Шаг третий. Обновляем фото каждую минуту
У telethon есть очень удобная штука — называется UploadProfilePhotoRequest. Импортируем ее в наш ранее написанный main.py:
from telethon.tl.functions.photos import UploadProfilePhotoRequest, DeletePhotosRequest
from datetime import datetime
from .utils import *
Разумеется, мы не должны обновлять аватарку в каждый момент времени — достаточно делать это раз в минуту. Для этого мы должны знать момент, когда заканчивается старая минута и начинается новая — именно в этот момент мы и поменяем фотку. Пишем еще одну небольшую функцию в utils.py:
def time_has_changed(prev_time):
return convert_time_to_string(datetime.now()) != prev_time
Да, да, мы передаем в нее строку со временем предыдущего обновления аватарки. Конечно, и тут были другие способы реализации, но писал я это все «на скорую руку», поэтому сильно об оптимизации не задумывался. Продолжаем заполнять наш main.py:
prev_update_time = ""
while True:
if time_has_changed(prev_update_time):
prev_update_time = convert_time_to_string(datetime.now())
client(DeletePhotosRequest(client.get_profile_photos('me')))
file = client.upload_file(f"time_images/{prev_update_time}.jpg")
client(UploadProfilePhotoRequest(file))
DeletePhotosRequest нам нужен для того, чтобы удалить предыдущие аватарки, чтобы создавался эффект, что мы не добавляем новое фото — оно меняется само собой. Для того, чтобы не перегружать процессор, можно добавить time.sleep(1) в конец цикла(разумеется, импортировав сперва time.py).
Готово! Запустите main.py и ваша аватарка превратится в часы. Как более оригинальный вариант, можете попробовать изменить текст на фотках, например, на такой: