• Как в Telethon обработать список с entities при пересылке группы сообщений?

    EntireMusic
    @EntireMusic Автор вопроса
    (:
    Решил проблему под свои нужды изменением кода в библиотеке. Оказалось, если передаётся список медиа, то он обрабатывается в этом блоке через цикл, с помощью вызова метода _send_album(), который даже не принимает переданные ранее formatting_entities .

    Поэтому, я дописал в аргументы метода _send_album() аргумент formatting_entities:
    async def _send_album(self: 'TelegramClient', entity, files, caption='',
                              formatting_entities=None,
                              progress_callback=None, reply_to=None,
                              parse_mode=(), silent=None, schedule=None,
                              supports_streaming=None, clear_draft=None,
                              force_document=False, background=None, ttl=None):

    И в сам вызов _send_album() тоже дописал передачу наших formatted_entities
    result = []
                while file:
                    result += await self._send_album(
                        entity, file[:10], caption=captions[:10], formatting_entities=formatting_entities,
                        progress_callback=used_callback, reply_to=reply_to,
                        parse_mode=parse_mode, silent=silent, schedule=schedule,
                        supports_streaming=supports_streaming, clear_draft=clear_draft,
                        force_document=force_document, background=background,
                    )
                    file = file[10:]
                    captions = captions[10:]
                    sent_count += 10
    
                return result

    Затем, внутри метода _send_album() после обработки подписей вставил код, чтобы formatted_entities к первому сообщению, если оно содержит текст:
    if captions and captions[0]:
                captions[0] = (captions[0][0], formatting_entities)

    Ну и всё заработало. Теперь группа отправляется с форматированием. Но эти изменения тоже необходимо немного подкорректировать чтобы они универсально работали в разных случаях.
    Ответ написан
  • Почему зависает авторизация Telethon на двухфакторной аутентификации?

    EntireMusic
    @EntireMusic Автор вопроса
    (:
    Основная проблема в файле библиотеки /telethon/client/auth.py в строке 23 - библиотека и метод getpass.getpass() не работает в консоли PyCharm в которой запускается бот, на этом месте программа и зависает.

    Возможное решение проблемы - изменить 23 строку:
    password: typing.Union[typing.Callable[[], str], str] = lambda: getpass.getpass('Please enter your password: '),
    на
    password: typing.Union[typing.Callable[[], str], str] = lambda: input('Please enter your password: '),

    * после переустановки или обновления Telethon нужно будет делать это повторно

    Вторая проблема - если явно передать строку с паролем в метод start(), то он должен работать, НО при проверке кода, внутри того же файла, атрибут password почему-то всеравно остаётся lambda-функцией. Позже попробую найти почему так и как это исправить.
    Ответ написан
    Комментировать
  • При отправки медиагруппы (несколько фото + текст) бот предложки отправляет каждое фото(видео) отдельно. А мне нужно, чтобы вместе) как исправить то?

    Это известная тема. Чтобы отправить медиагруппу, нужно контролировать её начало и конец. Но бот так же ловит каждое сообщение отдельным обновлением, у них разные id. Из общего - mediagrouop_id. Поэтому и отправляются они не группой, а каждое после получения обновления.

    Чтобы собрать группу, нужна либо машина состояний, либо функция для парсинга последних сообщений и проверки у них того же значения mediagroup_id. Но в Telegram Bot API по-моему нет возможности смотреть историю, только работать с обновлениями. Так что задача усложняется работой на лету.

    Как ещё одна альтернатива — использовать какой-нибудь Pyrogram на MTProto, в нём есть метод copy_mediagroup. Но конкретно эта библиотека давно не обновляется, будут проблемы с типизацией. Аналог — Telethon, но я ей не пользуюсь, не знаю есть ли там нужные инструменты.
    Ответ написан
    Комментировать
  • Задача про часы, почему решается именно так?

    hours = n % (60 * 24) // 60
    minutes = n % 60


    Допустим n = 2000 минут

    1. 60 * 24 = 1440
    — это общее количество минут в сутках. Работаем с минутами, т.к. твоё число "n" в минутах.

    2. 2000 % 1440 = 560
    Остаток от деления (%) твоего "n" на общее количества минут в сутках, так как суток может быть несколько, если число "n" велико.

    3. 560 // 60 = 9
    Оставшееся значение минут поделено целочисленным делением на 60 (//60), чтобы узнать значение для часов, поэтому сколько бы минут небыло, у тебя останется только целая часть - часы.

    4. 2000 % 60 = 20
    С минутами наоборот — часы нам не нужны, поэтому просто получаем остаток от деления на 60, сокращая часы. Остаются только минуты.

    Время на часах 9:20
    Ответ написан
    Комментировать
  • Не работает парсинг телеграмм канала. Но код рабочий в чем беда?

    1. Канал ты можешь парсить только свой. Ты не видишь юзеров в чужих каналах.
    2. Даже на своём канале ты видишь 200 юзеров, остальных нужно искать через танцы с бубном в поисковой строке.

    Пирограм к сожалению больше года не обновляется на Гитхаб, походу создатель подзабил. А жаль.
    Ответ написан
    Комментировать
  • Как правильно посчитать длину текста с эмодзи в Python?

    EntireMusic
    @EntireMusic Автор вопроса
    (:
    Готовый редактор постов канала, некорректно работает только если есть группа медиа и описание написано не к первому медиа)) В таком случае ссылки добавятся к первому медиа, но в следующем тоже будет описание, в итоге Телеграм не покажет ни одно. Но это исключение, лень фиксить.

    from aiogram import Router, types, F
    from aiogram.utils import formatting as fmt
    
    
    # Редактор постов канала в отдельном роутере
    router = Router()
    
    # Это понадобится, чтобы в медиагруппе редактировалось только описание первого медиа
    check_mg = set()
    
    #Фильтры: проверим что пост не переслан и что это медиа имеющие caption
    @router.channel_post(~F.forward_from_chat, ~F.forward_from, (F.text | F.photo | F.video | F.animation | F.document))
    async def redactor(message: types.Message):
        # Собираем текстовые данные из поста
        text = message.text or message.caption or ''
    
        # Собираем те entities которые уже есть в посте
        ent = message.entities or message.caption_entities or []
    
        # Удаляем встроенные ссылки если они есть
        ent = [e for e in ent if e.type != 'text_link']
    
       # Через инструмент formatting создаём внешний вид будущего поста
        content = fmt.Text(
            # Старый текст
            text,
            '\n\n',
            # В моём случае я добавляю три ссылки на канал, чат и админа с эмодзи-разделителем
            fmt.as_line(
                fmt.Bold(fmt.TextLink("Канал", url='https://t.me/1')),
                fmt.Bold(fmt.TextLink("Чат", url='https://t.me/2')),
                fmt.Bold(fmt.TextLink("Админ", url='https://t.me/3')),
                # Тут эмодзи который будет между ссылками
                sep='  '
            )
        )
        # Собираем новый текст и новые entities в кучу
        text, new_ent = content.render()
    
        # Тут расписывать не буду, разные проверки и разные варианты отправки отредактированного сообщения
        if message.text is not None:
            if len(text) <= 4096:
                await message.edit_text(text, entities=ent + new_ent, disable_web_page_preview=True)
            else:
                print("Can't edit Text, length exceeded.")
        elif message.media_group_id is None:
            if len(text) <= 1024:
                await message.edit_caption(caption=text, caption_entities=ent + new_ent, disable_web_page_preview=True)
            else:
                print("Can't edit Caption, length exceeded.")
        elif message.media_group_id not in check_mg:
            check_mg.add(message.media_group_id)
            if len(text) <= 1024:
                await message.edit_caption(caption=text, caption_entities=ent + new_ent, disable_web_page_preview=True)
                await asyncio.sleep(1)
                check_mg.remove(message.media_group_id)
            else:
                print("Can't edit Caption, length exceeded.")
    Ответ написан
    Комментировать
  • Существует ли телеграмм бот, который позволяет отключать возможность писать сообщения всем в общем чате в ночное время?

    Чтобы не получать уведомления об "смс круглую ночь" вы можете просто отключить их [уведомления] в данном чате на ночь. Либо, если вы обладаете правами администратора в чате, можно отключить возможность отправки сообщений (Настройки -> Управление группой -> Разрешения)
    Ответ написан
    Комментировать
  • Не импортирует router из другого файла проекта в aiogram 3. В чём ошибка?

    Сделай так в этом месте
    @router.message(Reg.number)
    async def two_three(message: Message, bot: Bot, state: FSMContext):
        await state.update_data(number=message.text)
        data=await state.get_data()
    
        await bot.send_message(chat_id='нужный айди', text=f'Спасибо, регистрация завершена. \n Имя: {data["name"]} \n Номер: {data ["number"]}')
        await state.clear()


    И удали это
    from run import bot
    Ответ написан
    Комментировать
  • Как избавиться от хлама после ботов?

    ПКМ по сообщению -> Удалить -> Удалить всё от <тут будет имя бота>
    Повторить для каждого бота
    Ответ написан
  • Aiogram: почему в Telegram не визуализируется voice сообщение?

    EntireMusic
    @EntireMusic Автор вопроса
    (:
    Из документации:
    For this to work, your audio must be in an .OGG file encoded with OPUS

    То есть, чтобы войс визуализировался, нужно отправлять его в формате .OGG, тогда и продолжительность будет отображаться корректно. А чтобы отображалась продолжительность (duration) при отправке других форматов, нужно явно её указать при отправке.

    Важное дополнение для Windows:
    1. Скачайте ffmpeg и распакуйте
    2. Добавьте путь в Path
    3. Функция на Python:
    import subprocess
    import io
    
    def mp3_to_ogg(filename, path=''):
        with open(f'{path}{filename}.mp3', 'rb') as input_file, open(f'{path}{filename}.ogg', 'wb') as output_file:
            mp3_io = io.BytesIO(input_file.read())
            ffmpeg_command = ['ffmpeg', '-i', 'pipe:0', '-c:a', 'libopus', '-f', 'ogg', 'pipe:1']
            result = subprocess.run(ffmpeg_command, input=mp3_io.read(), capture_output=True)
            ogg_bytes = result.stdout
            output_file.write(ogg_bytes)

    *вы можете изменить функцию, например добавив путь к файлам, использовав временные файлы и т.д.
    Ответ написан
    1 комментарий
  • Как перевести гео координаты в нонрмальный вид?

    EntireMusic
    @EntireMusic Автор вопроса
    (:
    Методом проб, ошибок, консультаций со специалистами ГИС, выяснил что координаты в EPSG 7827 (Pulkovo 1942 / CS63 zone X3). Написал конвертор на python + pyproj. Спасибо всем кто пытался помочь)

    #pip install pyproj
    from pyproj import CRS, Transformer
    
    def sk_to_wgs84(lat: str, lon: str) -> tuple:
        sk = CRS('epsg:7827')
        wgs84 = CRS('epsg:4326')
    
        transformer = Transformer.from_crs(sk, wgs84)
        x_wgs84, y_wgs84 = transformer.transform(lat, lon)
        return x_wgs84, y_wgs84
    Ответ написан
    Комментировать
  • Не работает Ultra Key в Adobe Premiere Pro, как исправить?

    EntireMusic
    @EntireMusic Автор вопроса
    (:
    Всё удивительно просто - Ультра ключ не хотел работать с чёрным фоном. Зелёный удалил без проблем.
    Но если у вас будут проблемы, особенно при использовании внешнего монитора, пробуйте через Shift+Alt сбросить настройки, это должно помочь.
    Ответ написан
    Комментировать
  • Есть ли возможность получить ID юзеров, поставивших реакции в чате Telegram, с реализацией на Python?

    EntireMusic
    @EntireMusic Автор вопроса
    (:
    https://qna.habr.com/q/1249668 ответ с реализацией с помощью библиотеки Pyrogram
    Ответ написан
    Комментировать
  • Как использовать функцию GetMessageReactionsList с помощью юзербота Pyrogram?

    EntireMusic
    @EntireMusic Автор вопроса
    (:
    Благодаря хорошей документации сам нашёл и понял, как правильно пользоваться подобными функциями, может кому пригодится:
    from pyrogram import Client, filters
    from pyrogram.raw.functions.messages import GetMessageReactionsList
    
    @app.on_message(filters.command("get_react"))
    async def get_mess_reactions(client, message):
        mess_id, mess_chat = 12345678, "some_chat" #тут id нужного сообщения и чат (id / username)
        r_peer = await app.resolve_peer(mess_chat) #обязательно использовать этот метод для получения правильного пира
        print(await app.invoke(GetMessageReactionsList(peer=r_peer, id=mess_id, limit=-1))) #обязательно используем именованные параметры
    Ответ написан
    Комментировать
  • Как сделать уведомление в Aiogram?

    https://docs.aiogram.dev/en/latest/telegram/types/...
    await bot.answer_callback_query(callback_query_id=cmd.id, text="Уведомление", show_alert=True)

    либо
    await callback_query.answer("Уведомление", show_alert=True)
    Ответ написан
    4 комментария
  • Как проверять что введен русский язык?

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

    import string
    
    def is_russian(text):
        alpha = "абвгдеёжзиклмнопрстуфхцчшщъыьэюя"
        new_text = text.translate(str.maketrans('', '', string.punctuation)).lower().replace(' ', '')
        
        rulet = 0
        for letter in new_text:
            if letter in alpha:
                rulet += 1
         
        # Если больше или равно 70%       
        if rulet/len(new_text) >= 0.7:
            return(True)
        else:
            return(False)
        
    
    good_text = "Какой-то текст, со знаками препинания, конечно же, sorry!"
    bad_text = "Some english text, isn't russian."
    secret = "Люблю Gucci"
    
    print(is_russian(good_text)) #вернёт True
    print(is_russian(bad_text)) #вернёт False
    print(is_russian(secret)) #вернёт False
    Ответ написан
    4 комментария
  • Как разделить строку по последнему указанному символу?

    s = r"С:\User\Users\Programs\program.py"
    print(s[:s.rindex("\\")+1])


    Для получения "чистой" строки, чтобы обратный слэш не использовался как экранирующий символ, использовал r-строку. А уже для поиска последнего индекса методом .rindex() использовал два слэша: один экранирующий, второй видит программа.

    Вывод сделал обычным срезом от начала до индекса последнего слэша+1, чтобы путь отображался включая его.
    Ответ написан
  • Как извлечь информацию из сайта?

    description в твоём случае это всё ещё список объектов супа. К ним можно/нужно применить метод text, чтобы получить именно текстовую составляющую.

    import requests
    from bs4 import BeautifulSoup
    
    url = "http://www.swhl.ru/page/1018390"
    r = requests.get(url)
    
    soup = BeautifulSoup(r.content, "lxml")
    description = soup.find_all("div", class_="page-text")
    
    for element in description:
        print(element.text)
    Ответ написан
  • Как отделить числа от букв в списке?

    lst = ['4', '10', '4', 'A', 'T']
    new_lst=[]
    
    for element in lst:
        if element.isdigit():
            new_lst.append(int(element))
        else:
            new_lst.append(element)


    С заменой в текущем списке:
    lst = ['4', '10', '4', 'A', 'T']
    
    for i in range(len(lst)):
        if lst[i].isdigit():
            lst[i] = int(lst[i])
            
    print(lst)
    Ответ написан
    4 комментария
  • Как в экселе найти номер заказа и забрать из него состав заказа?

    Искать по номеру можно так и выводить, используя срез:
    orders = [[1, "first", "order"], [2, "second", "order"], [3, "third", "order"], [4, "fourth", "order"]]
    
    order = int(input("Введите номер заказа: "))
    for line in orders:
        if line[0] == order:
            print(*line[1:])


    Обратите внимание, что перед этим, лучше сделать преведение типа номера заказа в строку, тк у вас в некоторых номерах заказов буквенные значения. Тогда и код будет выглядеть немного иначе.

    orders = [["1", "first", "order"], ["2", "second", "order"], ["3", "third", "order"], ["4", "fourth", "order"]] #первый элемент - строка
    
    order = input("Введите номер заказа: ") #не int
    for line in orders:
        if str(line[0]) == order: #если не преобразовывать список, можно здесь
            print(*line[1:])
    Ответ написан
    Комментировать