Как стать автором
Обновить

Комментарии 76

<фото про буханку хлеба и троллейбус.png>

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

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


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

А что именно в fat32 не влезло бы?
Он создает 60 x 24 = 1440 изображений, на каждую минуту в сутках. В случае ежесекундного обновления ему пришлось бы создать 86 с хвостом тысяч файлов, что превышает допустимое количество файлов в директории для fat32 и вызовет большие затруднения для ранних ext'ов.
Думаю, он может запросто удалять предыдущие изображения. Он может их в принципе даже не хранить, а установить аватарку и удалить файл локально.
Да, но на следующий день нужно будет заново генерировать картинку. Другое дело, если выложить фото на сервер телеграма. В таком случае можно будет просто хранить id каждой фотографии и менять аватарку. Думаю, это был бы оптимальный способ.
А еще можно создать папки 00,01,02,03...23, и в них уже файлы от 00.jpg до 59.jpg :)
А потом системные требования с 4 гигами оперативы… Почему нельзя сделать 10 картинок с числами и из них собирать нужную?
не ясно, что мешает генерировать картинку раз в минуту?
Почему нельзя сразу собирать нужную и после установки удалять?
Вполне можно так делать) Но я же не генерирую сотни тысяч картинок, чтобы мне было сильно жалко место на диске. К тому же это может быть более ресурсозатратно.
На каждый час по отдельной папке, делов-то.
А можно было сделать аналоговые часы с дискретностью 5 минут, к примеру 24 х 12 = 288 изображений
И какие проблемы были бы у ext2/3? Чем они кардинально отличаются от ext4?
Первый пришедший в голову пример — логи, прекрасно пишутся и читаются чаще, чем раз в секунду на всех этих фс.
Насколько я помню, при наличие более десятка тысяч файлов в директрии у ext2 начинались большие проблемы. Что-либо меняли только в четвёртой версии, но лично я эффективность работы с таким количеством файлов не проверял.
Если не ошибаюсь, там проблема в производительность сишных строк типа char*, много времени уходит на обработку всех имён файлов.
подтверждаю. в районе 10тыс наблюдаемы тормоза(вот прям щас :)
В 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).
Спасибо, понравилась идея динамической аватарки). За основу взял ваш скрипт и сделал то же самое, но для температуры воздуха. Так как cv не дружит с utf-8, использовал PIL:
github.com/plaksivayatryapka/telegram_avatar/blob/master/change_avatar.py
Прикольно! Cледующим шагом можно сделать трансляцию температуры тела с датчика, чтобы все знали, не болеет ли контакт ;)
Актуально, да =)
Когда то на эта библиотека имитировала 150 пользователей у одного товарища. Бот-ферма для телеграм игры.
Я неслабо удивился, когда итоговая картинка в посте совпала с моим временем. Вот это было бы действительно интересно

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

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

нижнее подчеркивание.
(простите, не удержался от маленького замечания)
В ином случае, проверьте меняется ли у вас start_time в generate_time_images.py
Мне подсказали в чем дело, прошу прощения — это была моя ошибка. В функции 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
Там должно быть np.zeros((500, 500)) вместо np.zeros(500, 500).
Все файлы с кодом должны быть в одной папке: utils.py, main.py, generate_time_images.py. Я, наверное, в скором времени залью код в гитхаб. Оттуда можно будет клонировать.
Предлагаю ещё на картинке указывать локальный часовой пояс :)
да тут ваще бы запустить, потом картинки какие хочешь )
«TypeError: data type not understood»
В этой строке «return np.zeros((500, 500))» нужны двойные скобки во всех файлах.
Еще такой вопрос, как сделать цветной текст?
Это (255, 255, 0) не RGB я так понял? Потому что изменения дают мне лишь оттенки серого
В инете написано нужен кортеж для RGB и просто скалярные значения для серого. Попытался даже явно указать tuple((155, 100, 255)) и все равно получил только серые тона
Разобрался.
Точнее нашел немного обходной путь.
Посколько мы создаем черный фон вручную, то он получается в градациях серого. Поэтому и текст можно наносить только в черно-белых тонах. Как тут указать, что созданный фон в цветной шкале я не понял.
Поэтому чтобы этого избежать я просто сам нарисовал черный фон и загрузил его указав в параметре, что это цветное изображение
image = cv2.imread('Black_background.jpg', 1)
Можно вместо np.array((500, 500)) использовать np.array((500, 500, 3)). Тогда он будет в RGB.
подскажи пожалуйста почему создает 24 файл без расширения и пустые
Windows не всегда(а может и никогда, я им не пользуюсь очень давно, точно не могу сказать) позволяет иметь двоеточие в названии файла. Попробуйте сохранять фотографии без двоеточия, заменив его, например, на нижнее подчеркивание.
Возникла проблема, появились файлы от 0 до 23 без расширений и объемом 0 байт. Долго не могу с этим разобраться. Кто знает как решить, помогите пожалуйста.
Windows не всегда(а может и никогда, я им не пользуюсь очень давно, точно не могу сказать) позволяет иметь двоеточие в названии файла. Попробуйте сохранять фотографии без двоеточия, заменив его, например, на нижнее подчеркивание.
Спасибо большое!
Все заработало, в этом и была проблема.
Немного переделал. Огромное количество картинок не требуется. И использовал библиотеку pillow для рисования, мне она показалась удобнее
github.com/aforizm/avatar-change-time
спасибочки, но выдает ошибку
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'
походу телетон надо обновить )
Спасибо! Вот этот скрипт заработал.
Кто-то на heroku это деплоил? Поделитесь опытом)
Для чего этот бесконечный цикл, почему не настроить запуск по расписанию?
Можно и по расписанию, но я писал код чисто как развлечение и решил поделиться результатом. Код далек от идеала почти во всех смыслах.
это не так?

from telethon import TelegramClient, sync
from config import *
client = TelegramClient(vkoncekoncov, api_id, api_hash)
client.start()
from telethon.tl.functions.photos import UploadProfilePhotoRequest, DeletePhotosRequest
from datetime import datetime
from utils import *
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))

Ошибки:
Traceback (most recent call last):
File «main.py», line 3, in from config import *
File "/Users/IlyaMacBook/Desktop/Code/Telegram/config.py", line 3
api_hash = 6156023a483094eb16484ebd781672e3
^
SyntaxError: invalid syntax
Там нужны кавычки.
api_hash="6156..."
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.