Comments 70
Не в этот раз. Многие узнали про замечательную библиотеку, способную работать в качестве клиента. Кто-то не знал или просто не думал о возможности автоматической замены фото в Телеграме. Короче, это точно не троллейбус, но даже если и трамвай, всё же как пример кулинарного DIY сгодится.

Хорошо, что вы не каждую секунду обновляетесь, а то пришлось бы вам отдельно указывать, на каких файловых системах можно это запускать.
(Подсказка: не влезло бы в fat32, были бы проблемы у ext2/3, про ntfs не помню).


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

Он создает 60 x 24 = 1440 изображений, на каждую минуту в сутках. В случае ежесекундного обновления ему пришлось бы создать 86 с хвостом тысяч файлов, что превышает допустимое количество файлов в директории для fat32 и вызовет большие затруднения для ранних ext'ов.
Думаю, он может запросто удалять предыдущие изображения. Он может их в принципе даже не хранить, а установить аватарку и удалить файл локально.
Да, но на следующий день нужно будет заново генерировать картинку. Другое дело, если выложить фото на сервер телеграма. В таком случае можно будет просто хранить id каждой фотографии и менять аватарку. Думаю, это был бы оптимальный способ.
А потом системные требования с 4 гигами оперативы… Почему нельзя сделать 10 картинок с числами и из них собирать нужную?
Вполне можно так делать) Но я же не генерирую сотни тысяч картинок, чтобы мне было сильно жалко место на диске. К тому же это может быть более ресурсозатратно.
А можно было сделать аналоговые часы с дискретностью 5 минут, к примеру 24 х 12 = 288 изображений
И какие проблемы были бы у ext2/3? Чем они кардинально отличаются от ext4?
Первый пришедший в голову пример — логи, прекрасно пишутся и читаются чаще, чем раз в секунду на всех этих фс.
Насколько я помню, при наличие более десятка тысяч файлов в директрии у ext2 начинались большие проблемы. Что-либо меняли только в четвёртой версии, но лично я эффективность работы с таким количеством файлов не проверял.
Если не ошибаюсь, там проблема в производительность сишных строк типа char*, много времени уходит на обработку всех имён файлов.
В ext2/3 файлы в директории хранятся линейно, в отличие от ext4, где большие директории конвертятся в hash tree. Отсюда проблемы с поиском файла по имени. И да, ситуация сильно зависит от длины имени файла.
Думаю, моей скорости интернета не хватило бы для обновления ежесекундно, иначе, я бы, конечно, постарался. С другой стороны, вполне возможно, что сам Telegram может на время заблокировать мой аккаунт, посчитав это «вялой попыткой спама» — именно так произошло, когда я отправлял десятки фоток за краткий срок из бота.

Создавать изображения на лету — идея неплохая, но их все равно пришлось бы сохранять как файл, чтобы потом передать в метод TelegramClient.upload_file, именно поэтому решил сделать специальную папку с фотографиями. Вероятнее всего, должен быть метод, который принимает массив байтов вместо названия файла для размещения медиа, однако я писал все это больше ради забавы, посему об оптимизации особо не задумывался.
Конкретно в python не знаю, но вообще должна быть возможность отправить набор байт в HTTP POST запросе «сымитировав» отправку файла.
Это не HTTP, и набор байт по этой теме там бывает только от сервера, и то в PhotoCachedSize и thumb документа (например стикера).

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

  • Можно сделать раздел в RAMFS.
  • Можно сделать в обычной файловой системе пайп, куда питоновский скрипт будет выводить байты картинки.
  • Можно, наверно, не имя файла передавать, а открытый и доступный для чтения поток, следовательно можно было обойтись потоком `io.BytesIO`.
  • А ещё нет никакого смысла хранить тысячи файлов, если рендер на лету такой картинки сопоставим по времени с загрузкой её с диска.
  • Можно даже сделать виртуальную файловую систему, которая на запрос открытия любого файла будет генерить на лету и возвращать картинку с нарисованным именем этого файла и в запрошенном формате.


О сколько странных извращений даёт нам Python совершать.

Вполне можно сгенерировать картинку в массив байт в памяти и стримить его.

Но это реально уже мелочи :)
Почему бы не создать три набора картинок:
  1. 00...23
  2. Статическую ":"
  3. 00...59

После чего склеивать их в:
hours[hour] + colon + minutes[minute]

И накладывать на базовое изображение.

Тогда картинок в кеше понадобится только 24 + 60 + 1 = 85
Можно просто 00...59, для часов юзать те-же картинки что и для минут, они ведь ничем не отличаются, просто для минут картинок с изображением численно больше?)
Профдеформация (:
Часы могут иметь другой шрифт, другой формат (например бразильский 6h 45min etc.).

А не проще взять моноширинный шрифт и использовать "0".."9" и ":" — 11 картинок?

Если все равно склеивать, то почему бы тогда не генерить картинку на лету, даже не сохраняя в файл?
Можно и генерить, но это может быть более ресурсозатратно. Хотя конечно же зависит от железа автора, нужны бенчмарки (:

Почему бы для этих целей не заливать файлы в Сохранённые сообщения и сохранять id файлов в конфиг файле или БД?

Зачем каждый раз загружать новую картинку, если можно загрузить все разом для каждого час/минута и потом переключаться между ними (хотя вроде есть ограничение на 100 аватаров, но это не точно)? Не знаю как в telethon, но такое есть в tglib (не знаю есть ли прямая обертка под python).
Прикольно! Cледующим шагом можно сделать трансляцию температуры тела с датчика, чтобы все знали, не болеет ли контакт ;)
Когда то на эта библиотека имитировала 150 пользователей у одного товарища. Бот-ферма для телеграм игры.
Я неслабо удивился, когда итоговая картинка в посте совпала с моим временем. Вот это было бы действительно интересно

Подскажите, а это можно сделать только на аву юзера или можно сделать на канал и сообщество?

Если у вас есть доступ администратора группы или канала — то запросто. Для этого используете telethon.tl.functions.channels.EditPhotoRequest. Подробнее тут.
Не подскажите, в чем может быть проблема: на втором шаге вместо 1440 картинок с разным временем получаю 1440 картинок локального времени в момент которого запустил код
С такой же проблемой столкнулся один мой знакомый. Полагаю это из-за спецификации ОС или ФС. В первую очередь, проверьте пожалуйста папку с фотографиями time_images на наличие в ней множества изображений(их должно быть 1440). Вероятнее всего вы там не найдете такого числа файлов. Это из-за того, что Windows не всегда(а может и никогда, я им не пользуюсь очень давно, точно не могу сказать) позволяет иметь двоеточие в названии файла. Попробуйте сохранять фотографии без двоеточия, заменив его, например, на нижний пробел.
нижний пробел

нижнее подчеркивание.
(простите, не удержался от маленького замечания)
Мне подсказали в чем дело, прошу прощения — это была моя ошибка. В функции generate_image_with_text было использовано datetime.now() как аргумент для текста в картинке. Исправил ошибку. Думаю, теперь все должно пойти хорошо)
В приведенном в статье коде ошибка в функции
generate_image_with_text(text)


Правильно
def generate_image_with_text(text):
    image = get_black_background()
    font = cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(image, text, (int(image.shape[0]*0.35), int(image.shape[1]*0.5)), font, 1.5, (255, 255, 0), 2, cv2.LINE_AA)
    return image

какие библиотеки импортровать? ниче не написано толком!!! гдет скопипастили и все :(
Насколько я знаю, такой статьи нигде не было, поэтому про копипаст речи идти не может. Если вы используете современный IDE, то он сам предложит импортировать те или иные библиотеки. В целом, достаточно установить telthon и opencv. Все остальное есть в стандартном наборе библиотек питона.

хорошо, с библиотеками разобрались, выдает такую ошибку:
ModuleNotFoundError: No module named 'main.utils'; 'main' is not a package


Python 3.7.3
установлены 3 библиотеки: telthon, opencv, utils
можно же как то сделать типа такого:


utils.py:


def convert_time_to_string(dt):
return f"{dt.hour}:{dt.minute:02}"
def time_has_changed(prev_time):
return convert_time_to_string(datetime.now()) != prev_time

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)
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, text, (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)

и так все 3 файла чтобы не собирать по всему посту )


меня вот это смущает from .utils import * а именно звездочка, что она означает?

* — астериск. В импортировании это означает «все, что имеется». То есть «из .utils импортируй все».
Traceback (most recent call last):
File «C:/Users/Public/Downloads/clock/generate_time_images.py», line 1, in from .utils import *
ModuleNotFoundError: No module named '__main__.utils'; '__main__' is not a package

Process finished with exit code 1
Просто удали в этой строке точку перед utils в обоих файлах «from utils import *»
После удаления точки
Traceback (most recent call last):
File «C:/Users/Public/Downloads/clock/generate_time_images.py», line 21, in image = generate_image_with_text(text)
File «C:/Users/Public/Downloads/clock/generate_time_images.py», line 14, in generate_image_with_text
image = get_black_background()
File «C:/Users/Public/Downloads/clock/generate_time_images.py», line 11, in get_black_background
return np.zeros(500, 500)
TypeError: data type not understood

Process finished with exit code 1
Все файлы с кодом должны быть в одной папке: utils.py, main.py, generate_time_images.py. Я, наверное, в скором времени залью код в гитхаб. Оттуда можно будет клонировать.
Предлагаю ещё на картинке указывать локальный часовой пояс :)
«TypeError: data type not understood»
В этой строке «return np.zeros((500, 500))» нужны двойные скобки во всех файлах.
спасибо, помогло. появились файлы от 0 до 23 без расширений и обьемом 0 байт.
ковыряю дальше ))
Еще такой вопрос, как сделать цветной текст?
Это (255, 255, 0) не RGB я так понял? Потому что изменения дают мне лишь оттенки серого
В инете написано нужен кортеж для RGB и просто скалярные значения для серого. Попытался даже явно указать tuple((155, 100, 255)) и все равно получил только серые тона
Разобрался.
Точнее нашел немного обходной путь.
Посколько мы создаем черный фон вручную, то он получается в градациях серого. Поэтому и текст можно наносить только в черно-белых тонах. Как тут указать, что созданный фон в цветной шкале я не понял.
Поэтому чтобы этого избежать я просто сам нарисовал черный фон и загрузил его указав в параметре, что это цветное изображение
image = cv2.imread('Black_background.jpg', 1)
Windows не всегда(а может и никогда, я им не пользуюсь очень давно, точно не могу сказать) позволяет иметь двоеточие в названии файла. Попробуйте сохранять фотографии без двоеточия, заменив его, например, на нижнее подчеркивание.
Возникла проблема, появились файлы от 0 до 23 без расширений и объемом 0 байт. Долго не могу с этим разобраться. Кто знает как решить, помогите пожалуйста.
Windows не всегда(а может и никогда, я им не пользуюсь очень давно, точно не могу сказать) позволяет иметь двоеточие в названии файла. Попробуйте сохранять фотографии без двоеточия, заменив его, например, на нижнее подчеркивание.
спасибочки, но выдает ошибку
Traceback (most recent call last):
File «main.py», line 18, in client(DeletePhotosRequest(client.get_profile_photos('me')))
AttributeError: 'TelegramClient' object has no attribute 'get_profile_photos'
походу телетон надо обновить )
Only those users with full accounts are able to leave comments. Log in, please.