async def darkmode(c, m):
    cb_data = m.data
    if cb_data.startswith("d||"):
        filename = cb_data.split("||")[-1].strip(".png")

        print(cb_data)
        light_button = InlineKeyboardMarkup([
            [
                InlineKeyboardButton("Light Mode ☀️",
                                     callback_data=f"l||{filename}")
            ],
        ])

        darkimage = InputMediaPhoto(media=f"{filename}_dark.png", )
        await m.edit_message_media(media=darkimage, reply_markup=light_button)

    elif cb_data.startswith("l||"):
        filename = cb_data.split("||")[-1].strip("_dark.png")
        dark_button = InlineKeyboardMarkup([
            [
                InlineKeyboardButton("Darkmode 🌜",
                                     callback_data=f"d||{filename}")
            ],
        ])

        darkimage = InputMediaPhoto(media=f"{filename}.png", )
        await m.edit_message_media(media=darkimage, reply_markup=dark_button)
    else:
        raise ContinuePropagation
Exemplo n.º 2
0
async def google_img(message: Message):
    if (GCS_API_KEY and GCS_IMAGE_E_ID) is None:
        await message.edit(REQ_ERR, disable_web_page_preview=True)
        return
    if os.path.exists(PATH):
        shutil.rmtree(PATH, ignore_errors=True)

    fetcher = GIS(GCS_API_KEY, GCS_IMAGE_E_ID)
    query = message.input_str
    search = {
        'q': query,
        'num': 5,
        'safe': "off",
        'fileType': "jpg",
        'imgType': "photo",
        'imgSize': "MEDIUM"
    }
    await message.edit("`Processing...`")
    fetcher.search(search_params=search)
    for image in fetcher.results():
        image.download(PATH)
    if not os.path.exists(PATH):
        await message.edit("Oops, No Results Found")
        return
    ss = []
    for img in os.listdir(PATH):
        imgs = PATH + img
        ss.append(InputMediaPhoto(str(imgs)))
        if len(ss) == 5:
            break
    await message.reply_chat_action("upload_photo")
    await message.reply_media_group(ss, True)
    shutil.rmtree(PATH, ignore_errors=True)
    await message.delete()
Exemplo n.º 3
0
 def edit_post(self, app, chat_id, msg_id, kb):
     app.edit_message_media(chat_id=chat_id,
                            message_id=msg_id,
                            media=InputMediaPhoto(media=self.file_id,
                                                  file_ref=self.file_ref,
                                                  caption=self.text),
                            reply_markup=kb)
Exemplo n.º 4
0
def edit_message_photo(client: Client, cid: int, mid: int, photo: str, file_ref: str = None, caption: str = "",
                       markup: InlineKeyboardMarkup = None) -> Union[bool, Message, None]:
    # Edit the message's photo
    result = None

    try:
        media = InputMediaPhoto(
            media=photo,
            file_ref=file_ref,
            caption=caption,
            parse_mode="html"
        )
        result = client.edit_message_media(
            chat_id=cid,
            message_id=mid,
            media=media,
            reply_markup=markup
        )
    except FloodWait as e:
        raise e
    except ButtonDataInvalid:
        logger.warning(f"Edit message {mid} photo {photo} in {cid} - invalid markup: {markup}")
    except (ChannelInvalid, ChannelPrivate, ChatAdminRequired, PeerIdInvalid):
        return False
    except Exception as e:
        logger.warning(f"Edit message photo error: {e}", exc_info=True)

    return result
Exemplo n.º 5
0
async def generate_screen_shot(bot, update):
    tmp_directory_for_each_user = os.path.join(os.getcwd(), "Screenshots",
                                               str(update.from_user.id))
    if not os.path.isdir(tmp_directory_for_each_user):
        os.makedirs(tmp_directory_for_each_user)
    ss_folder = [f for f in os.listdir(tmp_directory_for_each_user)]
    for f in ss_folder:
        try:
            os.remove(os.path.join(tmp_directory_for_each_user, f))
        except IndexError:
            pass
    saved_file_path = os.getcwd() + "/" + "downloads" + "/" + str(
        update.from_user.id) + "/"
    for file in os.listdir(saved_file_path):
        dir_content = (os.path.join(saved_file_path, file))
        if dir_content is not None:
            images = await generate_screen_shots(dir_content,
                                                 tmp_directory_for_each_user,
                                                 5, 9)
            media_album_p = []
            if images is not None:
                i = 0
                for image in images:
                    if os.path.exists(image):
                        if i == 0:
                            media_album_p.append(
                                InputMediaPhoto(
                                    media=image,
                                    caption=Translation.CAPTION_TEXT,
                                    parse_mode="html"))
                        else:
                            media_album_p.append(InputMediaPhoto(media=image))
                        i = i + 1
            await bot.send_chat_action(chat_id=update.message.chat.id,
                                       action="upload_photo")
            await bot.send_media_group(
                chat_id=update.message.chat.id,
                disable_notification=True,
                reply_to_message_id=update.message.message_id,
                media=media_album_p)
            try:
                shutil.rmtree(tmp_directory_for_each_user)
                await trim(bot, update)
            except IndexError:
                pass
Exemplo n.º 6
0
def img(message):
    query = extract_args(message)
    lim = findall(r"lim=\d+", query)
    try:
        lim = lim[0]
        lim = lim.replace("lim=", "")
        query = query.replace("lim=" + lim[0], "")
        lim = int(lim)
        if lim > 10:
            lim = 10
    except IndexError:
        lim = 5

    if len(query) < 1:
        edit(message, '`Bir arama terimi girmelisiniz.`')
        return
    edit(message, '`İşleniyor...`')

    url = f'https://www.google.com/search?tbm=isch&q={query}&gbv=2&sa=X&biw=1920&bih=1080'
    driver = get_webdriver()
    driver.get(url)
    count = 1
    files = []
    for i in driver.find_elements_by_xpath(
            '//div[contains(@class,"isv-r PNCib MSM1fd BUooTd")]'):
        i.click()
        try_count = 0
        while len(element := driver.find_elements_by_xpath(
                '//img[contains(@class,"n3VNCb") and contains(@src,"http")]')
                  ) < 1 and try_count < 20:
            try_count += 1
            time.sleep(.1)
        if len(element) < 1:
            continue
        link = element[0].get_attribute('src')
        filename = f'result_{count}.jpg'
        try:
            with open(filename, 'wb') as result:
                result.write(get(link).content)
            ftype = guess_type(filename)
            if not ftype[0] or ftype[0].split('/')[1] not in [
                    'png', 'jpg', 'jpeg'
            ]:
                os.remove(filename)
                continue
        except Exception as e:
            continue
        files.append(InputMediaPhoto(filename))
        time.sleep(1)
        driver.find_elements_by_xpath(
            '//a[contains(@class,"hm60ue")]')[0].click()
        count += 1
        if lim < count:
            break
        time.sleep(1)
Exemplo n.º 7
0
async def generate_screen_shot(client, update):
    await client.send_chat_action(chat_id=update.message.chat.id,
                                  action="upload_document")
    tmp_directory_for_each_user = os.path.join(os.getcwd(), "screenshots",
                                               str(update.from_user.id))
    if not os.path.isdir(tmp_directory_for_each_user):
        os.makedirs(tmp_directory_for_each_user)
    saved_file_path = os.path.join(os.getcwd(), "downloads",
                                   str(update.message.chat.id))
    for file in os.listdir(saved_file_path):
        dir_content = (os.path.join(saved_file_path, file))
        if dir_content is not None:
            images = await generate_screen_shots(dir_content,
                                                 tmp_directory_for_each_user,
                                                 5, 9)
            media_album_p = []
            if images is not None:
                i = 0
                caption = str(Config.PRE_FILE_TXT)
                for image in images:
                    if os.path.exists(image):
                        if i == 0:
                            media_album_p.append(
                                InputMediaPhoto(media=image,
                                                caption=caption,
                                                parse_mode="html"))
                        else:
                            media_album_p.append(InputMediaPhoto(media=image))
                        i = i + 1
            await client.send_chat_action(chat_id=update.message.chat.id,
                                          action="upload_photo")
            await client.send_media_group(
                chat_id=update.message.chat.id,
                disable_notification=True,
                reply_to_message_id=update.message.message_id,
                media=media_album_p)
            try:
                shutil.rmtree(tmp_directory_for_each_user)
                await trim(client, update)
            except IndexError:
                pass
Exemplo n.º 8
0
async def post_async(client):
    item_store_channel = (await redis_hgetall("fortnite:store:channel"))
    item_store_file, item_store_hash = await parse_item_store()

    item_store_caption = "🛒 Магазин предметов в Фортнайте был обновлен. #магазин"
    item_store_caption_edited = f"{item_store_caption}\n\n__Магазин предметов после оригинальной публикации " \
                                "сообщения был обновлен в {} по московскому времени.__"

    if not item_store_channel or item_store_channel[
            'hash'] != item_store_hash or config.DEVELOPER_MODE:
        logging.info(
            "Магазин предметов в Фортнайте был обновлен. Публикуется его изображение в канал, "
            "указанный в конфигурационном файле.")

        try:
            assert item_store_channel['chat_id']
            assert item_store_channel['message_id']
            assert item_store_channel['time']

            if int(time()) - int(item_store_channel['time']) < 3600:
                logging.info(
                    "Последний пост с магазином предметов был опубликован в канал меньше, "
                    "чем час назад, поэтому сообщение было отредактировано обновленным магазином."
                )

                message = client.edit_message_media(
                    int(item_store_channel['chat_id']),
                    int(item_store_channel['message_id']),
                    media=InputMediaPhoto(
                        item_store_file,
                        caption=item_store_caption_edited.format(
                            convert_to_moscow(
                                datetime.utcnow()).strftime("%H:%M:%S"))))
            else:
                raise AssertionError
        except (AssertionError, TypeError, KeyError):
            message = client.send_photo(config.CHANNEL_ID,
                                        item_store_file,
                                        caption=item_store_caption)

        await Redis.execute("HSET", "fortnite:store:channel", "hash",
                            item_store_hash, "chat_id", message['chat']['id'],
                            "message_id", message['message_id'], "time",
                            int(time()))
        await Redis.execute("EXPIRE", "fortnite:store:channel", 86400)
        """
Exemplo n.º 9
0
async def new_cat_callback_handler(c: bot, cb: CallbackQuery):
    await cb.answer()
    cat_file = await cat().random_cat()

    await c.edit_message_media(chat_id=cb.message.chat.id,
                               message_id=cb.message.message_id,
                               media=InputMediaPhoto(cat_file),
                               reply_markup=InlineKeyboardMarkup([[
                                   InlineKeyboardButton(
                                       text=f"{Emoji.CAT_FACE} New Cat",
                                       callback_data="new_cat_callback")
                               ]]))

    try:
        os.remove(cat_file)
    except Exception as e:
        logging.error(str(e))
Exemplo n.º 10
0
async def post_async(client):
    news_channel = (await redis_hgetall("fortnite:news:channel"))
    news_file, news_hash = await parse_news()

    news_caption = "📰 Новости Королевской Битвы и/или Сражения с Бурей были обновлены. #новости"
    news_caption_edited = f"{news_caption}\n\n__Новости после оригинальной публикации " \
                          "сообщения были обновлены в {} по московскому времени.__"

    if not news_channel or news_channel[
            'hash'] != news_hash or config.DEVELOPER_MODE:
        logging.info(
            "Новости в Фортнайте были обновлены. Публикуется их изображение в канал, "
            "указанный в конфигурационном файле.")

        try:
            assert news_channel['chat_id']
            assert news_channel['message_id']
            assert news_channel['time']

            if int(time()) - int(news_channel['time']) < 3600:
                logging.info(
                    "Последний пост с новостями был опубликован в канал меньше, чем час назад, поэтому "
                    "сообщение было отредактировано обновленными новостями.")

                message = client.edit_message_media(
                    int(news_channel['chat_id']),
                    int(news_channel['message_id']),
                    media=InputMediaPhoto(
                        news_file,
                        caption=news_caption_edited.format(
                            convert_to_moscow(
                                datetime.utcnow()).strftime("%H:%M:%S"))))
            else:
                raise AssertionError
        except (AssertionError, TypeError, KeyError):
            message = client.send_photo(config.CHANNEL_ID,
                                        news_file,
                                        caption=news_caption)

        await Redis.execute("HSET", "fortnite:news:channel", "hash", news_hash,
                            "chat_id", message['chat']['id'], "message_id",
                            message['message_id'], "time", int(time()))
        await Redis.execute("EXPIRE", "fortnite:news:channel", 604800)
Exemplo n.º 11
0
def media_group_worker(cli: Client, msg: Message):
    chat_id = msg.chat.id
    media_group_id = msg.media_group_id
    if media_group_id not in last_media_group_ids:
        last_media_group_ids.append(media_group_id)
        print('Catch media_group')
        for ids in from_to_ids:
            from_id = ids['from_id']
            to_id = ids['to_id']
            if from_id == chat_id:
                photos = []
                for message in app.get_history(chat_id, limit=10):
                    if message.media_group_id == msg.media_group_id:
                        caption = message.caption if message.caption else ''
                        photos.append(
                            InputMediaPhoto(message.photo.file_id,
                                            message.photo.file_ref, caption))
                photos.reverse()
                app.send_media_group(to_id, photos)
Exemplo n.º 12
0
async def cb_(client, callback_query):
    cb_data = callback_query.data
    msg = callback_query.message
    if (cb_data == "render" or cb_data == 'cancel' or cb_data == 'statics'):
        pass
    else:
        # cause @Spechide said so
        await client.answer_callback_query(callback_query.id, )
    if cb_data == "render":
        await client.answer_callback_query(callback_query.id,
                                           text='Processing your request..!')
        random_message = await msg.edit(text='<b><i>Processing...</b></i>')
        link = msg.reply_to_message.text
        # starting to recognize settings
        background, split, resolution = False, False, False
        for_logging = ""
        for settings in msg.reply_markup.inline_keyboard:
            if "Format" in settings[0].text:
                format = settings[0].text.split('-', 1)[1].strip()
            if "Page" in settings[0].text:
                page = settings[0].text.split('-', 1)[1].strip()
                page_value = True if 'Full' in page else False
            if "Split" in settings[0].text:
                split_boolean = settings[0].text.split('-', 1)[1].strip()
                split = True if 'Yes' in split_boolean else False
            if "wait" in settings[0].text:
                timer = settings[0].text.split('|', 1)[1].strip().strip('s')
                background = False if 'default' in timer else True
            if "resolution" in settings[0].text:
                resolution = settings[0].text.split('|', 1)[1].strip()
            for_logging += settings[0].text + '\n'
        # starting folder creartion with message id
        if not os.path.isdir('./FILES'):
            os.mkdir('./FILES')
        location = f"./FILES/{str(msg.chat.id)}/{str(msg.message_id)}"
        if not os.path.isdir(location):
            os.makedirs(location)
        # logging the request into a specific group or channel
        try:
            LOGGING_GROUP = int(os.environ["LOG_GROUP"])
            await client.send_message(chat_id=LOGGING_GROUP,
                                      text=format_for_logging.format(
                                          name=msg.chat.first_name,
                                          user=msg.chat.username,
                                          link=link,
                                          settings=for_logging),
                                      disable_web_page_preview=True)
        except Exception as e:
            print(f'Logging Avoided\nREASON : {e}')
        # opening chrome bin
        try:
            browser = await launch(headless=True, executablePath=EXEC_PATH)
            page = await browser.newPage()
            await page.goto(link, {"waitUtil": 'networkidle0'})
            await asyncio.sleep(2)
            # getting page title
            text = str(await page.title())
            if len(text) > 14:
                text = text[:14]
            text = text.replace(' ', '')
            # implementing the settings
            await random_message.edit(text='<b><i>Rendering</b></i>')
            if format == 'jpeg' or format == 'PNG':
                arguments_for_photo = {}
                # configuring resolution
                if resolution:
                    if '1280' in resolution:
                        res = {'width': 1280, 'height': 720}
                    elif '2560' in resolution:
                        res = {'width': 2560, 'height': 1440}
                    elif '640' in resolution:
                        res = {'width': 640, 'height': 480}
                    else:
                        res = {'width': 800, 'height': 600}
                    await page.setViewport(res)
                # configure btw Partial/fullpage
                if page_value:
                    arguments_for_photo['fullPage'] = True
                await random_message.edit(text='<b><i>Rendering.</b></i>')
                # naming for the output file
                if format == 'jpeg':
                    arguments_for_photo[
                        'path'] = f'{location}/{text.strip()}-webshotbot.jpeg'
                    arguments_for_photo['type'] = 'jpeg'
                if format == 'PNG':
                    arguments_for_photo[
                        'path'] = f'{location}/{text.strip()}-webshotbot.png'
                    arguments_for_photo['type'] = 'png'
                await random_message.edit(text='<b><i>rendering...</b></i>')
                if background:
                    await asyncio.sleep(3)
                # taking screenshot and closing the browser
                await page.screenshot(arguments_for_photo)
                await browser.close()
                # spliting the image
                if split and page_value:
                    await random_message.edit(
                        text='<b><i>Spliting Images...</b></i>')
                    # https://stackoverflow.com/questions/25705773/image-cropping-tool-python
                    Image.MAX_IMAGE_PIXELS = None
                    # https://coderwall.com/p/ovlnwa/use-python-and-pil-to-slice-an-image-vertically
                    location_of_image = []
                    img = Image.open(arguments_for_photo['path'])
                    width, height = img.size
                    upper, left, count, slice_size = 0, 0, 1, 800
                    slices = int(math.ceil(height / slice_size))
                    for _ in range(slices):
                        # if we are at the end, set the lower bound to be the bottom of the image
                        if count == slices:
                            lower = height
                        else:
                            lower = int(count * slice_size)
                        bbox = (left, upper, width, lower)
                        working_slice = img.crop(bbox)
                        upper += slice_size
                        # saving = the slice
                        if 'jpeg' in format:
                            location_to_save_slice = f'{location}/slice_{str(count)}.jpeg'
                        else:
                            location_to_save_slice = f'{location}/slice_{str(count)}.png'
                        location_of_image.append(location_to_save_slice)
                        working_slice.save(location_to_save_slice)
                        count += 1
                    # spliting finished
                    if len(location_of_image) > 20:
                        await random_message.edit(
                            text=
                            '<b>detected images more than 20\n\n<i>Zipping...</i></b>'
                        )
                        await asyncio.sleep(1)
                        # zipping if length is too high
                        zipped_file = f'{location}/webshot.zip'
                        with ZipFile(zipped_file, 'w') as zipper:
                            for files in location_of_image:
                                zipper.write(files)
                        #  finished zipping and sending the zipped file as document
                        await random_message.edit(
                            text='<b><i>uploading...</b></i>')
                        await client.send_chat_action(msg.chat.id,
                                                      "upload_document")
                        await client.send_document(
                            document=zipped_file,
                            chat_id=msg.chat.id,
                            reply_to_message_id=msg.reply_to_message.message_id
                        )
                        # sending as media group if files are not too long
                    else:
                        await random_message.edit(
                            text='<b><i>uploading...</b></i>')
                        location_to_send = []
                        for count, images in enumerate(location_of_image,
                                                       start=1):
                            location_to_send.append(
                                InputMediaPhoto(media=images,
                                                caption=str(count)))
                        sent_so_far = 0
                        # sending 10 at a time
                        while sent_so_far <= len(location_to_send):
                            await client.send_chat_action(
                                msg.chat.id, "upload_photo")
                            await client.send_media_group(
                                media=location_to_send[
                                    sent_so_far:sent_so_far + 10],
                                chat_id=msg.chat.id,
                                reply_to_message_id=msg.reply_to_message.
                                message_id,
                                disable_notification=True)
                            sent_so_far += 10
                            await asyncio.sleep(0.5)
                # if split is not selected
                else:
                    await random_message.edit(text='<b><i>uploading...</b></i>'
                                              )
                    if not page_value:
                        await client.send_chat_action(msg.chat.id,
                                                      "upload_photo")
                        await client.send_photo(
                            photo=arguments_for_photo['path'],
                            chat_id=msg.chat.id,
                            reply_to_message_id=msg.reply_to_message.message_id
                        )
                    else:
                        await client.send_chat_action(msg.chat.id,
                                                      "upload_document")
                        await client.send_document(
                            document=arguments_for_photo['path'],
                            chat_id=msg.chat.id,
                            reply_to_message_id=msg.reply_to_message.message_id
                        )
                await asyncio.sleep(1)
                await random_message.delete()
                shutil.rmtree(location)
            # configuring pdf settings
            else:
                await random_message.edit(text='<b><i>rendering.</b></i>')
                arguments_for_pdf = {}
                if resolution:
                    if '1280' in resolution:
                        arguments_for_pdf = {'width': 1280, 'height': 720}
                    elif '2560' in resolution:
                        # cause asked by <ll>//𝚂𝚊𝚢𝚊𝚗𝚝𝚑//<ll>
                        arguments_for_pdf = {'width': 2560, 'height': 1440}
                        arguments_for_pdf['scale'] = 2
                    elif '640' in resolution:
                        arguments_for_pdf = {'width': 640, 'height': 480}
                    else:
                        arguments_for_pdf = {'width': 800, 'height': 600}
                await page.emulateMedia('screen')
                arguments_for_pdf['path'] = f'{location}/{text}-webshotbot.pdf'
                if not page_value:
                    arguments_for_pdf['pageRanges'] = '1-2'
                if background:
                    await random_message.edit(text='<b><i>Rendering..</b></i>')
                    await asyncio.sleep(3)
                    arguments_for_pdf['printBackground'] = True
                await random_message.edit(text='<b><i>Rendering...</b></i>')
                await page.pdf(arguments_for_pdf)
                await random_message.edit(text='<b><i>Uploading...</b></i>')
                await client.send_chat_action(msg.chat.id, "upload_document")
                await browser.close()
                await client.send_document(
                    document=arguments_for_pdf['path'],
                    chat_id=msg.chat.id,
                    reply_to_message_id=msg.reply_to_message.message_id)
                await asyncio.sleep(1)
                await random_message.delete()
                shutil.rmtree(location)
        except errors.PageError:
            await msg.edit(text='Not a valid link 😓🤔')
            return False
    elif cb_data == "splits":
        if "PDF" not in msg.reply_markup.inline_keyboard[0][0].text:
            index_number = 1
        current_boolean = msg.reply_markup.inline_keyboard[index_number][0]
        boolean_to_change = 'Split - No' if "Yes" in current_boolean.text else 'Split - Yes'
        msg.reply_markup.inline_keyboard[index_number][0][
            'text'] = boolean_to_change
        await msg.edit(text='Choose the prefered settings',
                       reply_markup=msg.reply_markup)

    elif cb_data == "page":
        if 'PDF' in msg.reply_markup.inline_keyboard[0][0].text:
            index_number = 1
        else:
            index_number = 2
        current_page = msg.reply_markup.inline_keyboard[index_number][0]
        page_to_change = "Page - Partial" if "Full" in current_page.text else "Page - Full"
        msg.reply_markup.inline_keyboard[index_number][0][
            'text'] = page_to_change
        await msg.edit(text='Choose the prefered settings',
                       reply_markup=msg.reply_markup)

    elif cb_data == 'timer':
        current_time = msg.reply_markup.inline_keyboard[-4][0].text
        time_to_change = "wait for | BackgroundToLoad" if 'default' in current_time else "wait for | default"
        msg.reply_markup.inline_keyboard[-4][0]['text'] = time_to_change
        await msg.edit(text='Choose the prefered settings',
                       reply_markup=msg.reply_markup)

    elif cb_data == 'options':
        current_option = msg.reply_markup.inline_keyboard[-3][0].text
        options_to_change = "hide additional options ˄" if 'show' in current_option else 'show additional options ˅'
        if 'hide' in options_to_change:
            msg.reply_markup.inline_keyboard.insert(-2, [
                InlineKeyboardButton(text="resolution | 800x600",
                                     callback_data='res')
            ])
            msg.reply_markup.inline_keyboard.insert(
                -2,
                [
                    InlineKeyboardButton(text='wait for | default',
                                         callback_data="timer")
                ],
            )
            msg.reply_markup.inline_keyboard.insert(
                -2,
                [
                    InlineKeyboardButton(text='▫️ site statitics ▫️',
                                         callback_data="statics")
                ],
            )
            if 'PDF' in msg.reply_markup.inline_keyboard[0][0].text:
                index_to_change = 2
            else:
                index_to_change = 3
            msg.reply_markup.inline_keyboard[index_to_change][0][
                'text'] = options_to_change

        else:
            for _ in range(3):
                msg.reply_markup.inline_keyboard.pop(-3)
            msg.reply_markup.inline_keyboard[-3][0]['text'] = options_to_change
        await msg.edit(text='Choose the prefered settings',
                       reply_markup=msg.reply_markup)

    elif cb_data == "res":
        current_res = msg.reply_markup.inline_keyboard[-5][0].text
        if '800' in current_res:
            res_to_change = "resolution | 1280x720"
        elif '1280' in current_res:
            # cause asked by <ll>//𝚂𝚊𝚢𝚊𝚗𝚝𝚑//<ll>
            res_to_change = "resolution | 2560x1440"
        elif '2560' in current_res:
            res_to_change = "resolution | 640x480"
        else:
            res_to_change = "resolution | 800x600"
        msg.reply_markup.inline_keyboard[-5][0]['text'] = res_to_change
        await msg.edit(text='Choose the prefered settings',
                       reply_markup=msg.reply_markup)

    elif cb_data == "format":
        current_format = msg.reply_markup.inline_keyboard[0][0]
        if 'PDF' in current_format.text:
            format_to_change = 'Format - PNG'
        elif 'PNG' in current_format.text:
            format_to_change = 'Format - jpeg'
        elif 'jpeg' in current_format.text:
            format_to_change = 'Format - PDF'
        msg.reply_markup.inline_keyboard[0][0]['text'] = format_to_change
        if "PNG" in format_to_change:
            msg.reply_markup.inline_keyboard.insert(1, [
                InlineKeyboardButton(text="Split - No", callback_data='splits')
            ])
        if 'PDF' in format_to_change:
            if "Split" in msg.reply_markup.inline_keyboard[1][0].text:
                msg.reply_markup.inline_keyboard.pop(1)
        await msg.edit(text='Choose the prefered settings',
                       reply_markup=msg.reply_markup)

    elif cb_data == "cancel":
        await client.answer_callback_query(callback_query.id,
                                           text='Canceled your request..!')
        await msg.delete()
    elif cb_data == 'statics':
        await client.answer_callback_query(
            callback_query.id,
            text='Soory this features is not implemented yet😫😢😬!',
            show_alert=True)
    elif cb_data == 'deleteno' or cb_data == 'deleteyes':
        if cb_data == 'deleteno':
            await msg.edit(text='process canceled')
            await asyncio.sleep(2)
            await msg.delete()
        else:
            await msg.edit(text='deleteing')
            try:
                shutil.rmtree('./FILES/')
            except Exception as e:
                await msg.edit(text=e)
            finally:
                await asyncio.sleep(2)
                await msg.delete()
Exemplo n.º 13
0
async def youtube_dl_call_back(bot, update):
    cb_data = update.data
    # youtube_dl extractors
    tg_send_type, youtube_dl_format, youtube_dl_ext = cb_data.split("|")
    thumb_image_path = DOWNLOAD_LOCATION + \
        "/" + str(update.from_user.id) + ".jpg"
    save_ytdl_json_path = DOWNLOAD_LOCATION + \
        "/" + str(update.from_user.id) + ".json"
    try:
        with open(save_ytdl_json_path, "r", encoding="utf8") as f:
            response_json = json.load(f)
    except FileNotFoundError:
        await update.message.delete()
        return False

    youtube_dl_url, \
        custom_file_name, \
        youtube_dl_username, \
        youtube_dl_password = get_link(
            update.message.reply_to_message
        )
    if not custom_file_name:
        custom_file_name = str(response_json.get("title")) + \
            "_" + youtube_dl_format + "." + youtube_dl_ext
    await update.message.edit_caption(caption=Translation.DOWNLOAD_START)
    description = Translation.CUSTOM_CAPTION_UL_FILE
    if "fulltitle" in response_json:
        description = response_json["fulltitle"][0:1021]
        # escape Markdown and special characters
    tmp_directory_for_each_user = os.path.join(DOWNLOAD_LOCATION,
                                               str(update.from_user.id))
    if not os.path.isdir(tmp_directory_for_each_user):
        os.makedirs(tmp_directory_for_each_user)
    download_directory = os.path.join(tmp_directory_for_each_user,
                                      custom_file_name)
    command_to_exec = []
    if tg_send_type == "audio":
        command_to_exec = [
            "youtube-dl", "-c", "--max-filesize",
            str(TG_MAX_FILE_SIZE), "--prefer-ffmpeg", "--extract-audio",
            "--audio-format", youtube_dl_ext, "--audio-quality",
            youtube_dl_format, youtube_dl_url, "-o", download_directory
        ]
    else:
        minus_f_format = youtube_dl_format
        if "youtu" in youtube_dl_url:
            minus_f_format = youtube_dl_format + "+bestaudio"
        command_to_exec = [
            "youtube-dl", "-c", "--max-filesize",
            str(TG_MAX_FILE_SIZE), "--embed-subs", "-f", minus_f_format,
            "--hls-prefer-ffmpeg", youtube_dl_url, "-o", download_directory
        ]
    if HTTP_PROXY is not None:
        command_to_exec.append("--proxy")
        command_to_exec.append(HTTP_PROXY)
    if youtube_dl_username is not None:
        command_to_exec.append("--username")
        command_to_exec.append(youtube_dl_username)
    if youtube_dl_password is not None:
        command_to_exec.append("--password")
        command_to_exec.append(youtube_dl_password)
    command_to_exec.append("--no-warnings")
    # command_to_exec.append("--quiet")
    command_to_exec.append("--restrict-filenames")
    LOGGER.info(command_to_exec)
    start = datetime.now()
    t_response, e_response = await run_shell_command(command_to_exec)
    LOGGER.info(e_response)
    LOGGER.info(t_response)
    if e_response and Translation.YTDL_ERROR_MESSAGE in e_response:
        error_message = e_response.replace(Translation.YTDL_ERROR_MESSAGE, "")
        await update.message.edit_caption(caption=error_message)
        return False
    if t_response:
        # LOGGER.info(t_response)
        os.remove(save_ytdl_json_path)
        end_one = datetime.now()
        time_taken_for_download = (end_one - start).seconds
        file_size = TG_MAX_FILE_SIZE + 1
        download_directory_dirname = os.path.dirname(download_directory)
        download_directory_contents = os.listdir(download_directory_dirname)
        for download_directory_c in download_directory_contents:
            current_file_name = os.path.join(download_directory_dirname,
                                             download_directory_c)
            file_size = os.stat(current_file_name).st_size

            if file_size > TG_MAX_FILE_SIZE:
                await update.message.edit_caption(
                    caption=Translation.RCHD_TG_API_LIMIT.format(
                        time_taken_for_download, humanbytes(file_size)))

            else:
                is_w_f = False
                images = await generate_screen_shots(
                    current_file_name, tmp_directory_for_each_user, is_w_f, "",
                    300, 9)
                LOGGER.info(images)
                await update.message.edit_caption(
                    caption=Translation.UPLOAD_START)
                # get the correct width, height, and duration
                # for videos greater than 10MB
                # ref: message from @BotSupport
                width = 0
                height = 0
                duration = 0
                if tg_send_type != "file":
                    metadata = extractMetadata(createParser(current_file_name))
                    if metadata is not None:
                        if metadata.has("duration"):
                            duration = metadata.get('duration').seconds
                # get the correct width, height, and duration
                # for videos greater than 10MB
                if os.path.exists(thumb_image_path):
                    # https://stackoverflow.com/a/21669827/4723940
                    Image.open(thumb_image_path).convert("RGB").save(
                        thumb_image_path)
                    metadata = extractMetadata(createParser(thumb_image_path))
                    if metadata.has("width"):
                        width = metadata.get("width")
                    if metadata.has("height"):
                        height = metadata.get("height")
                    if tg_send_type == "vm":
                        height = width
                else:
                    thumb_image_path = None
                start_time = time.time()
                # try to upload file
                if tg_send_type == "audio":
                    await update.message.reply_audio(
                        audio=current_file_name,
                        caption=description,
                        parse_mode="HTML",
                        duration=duration,
                        # performer=response_json["uploader"],
                        # title=response_json["title"],
                        # reply_markup=reply_markup,
                        thumb=thumb_image_path,
                        progress=progress_for_pyrogram,
                        progress_args=(Translation.UPLOAD_START,
                                       update.message, start_time))
                elif tg_send_type == "file":
                    await update.message.reply_document(
                        document=current_file_name,
                        thumb=thumb_image_path,
                        caption=description,
                        parse_mode="HTML",
                        # reply_markup=reply_markup,
                        progress=progress_for_pyrogram,
                        progress_args=(Translation.UPLOAD_START,
                                       update.message, start_time))
                elif tg_send_type == "vm":
                    await update.message.reply_video_note(
                        video_note=current_file_name,
                        duration=duration,
                        length=width,
                        thumb=thumb_image_path,
                        progress=progress_for_pyrogram,
                        progress_args=(Translation.UPLOAD_START,
                                       update.message, start_time))
                elif tg_send_type == "video":
                    await update.message.reply_video(
                        video=current_file_name,
                        caption=description,
                        parse_mode="HTML",
                        duration=duration,
                        width=width,
                        height=height,
                        supports_streaming=True,
                        # reply_markup=reply_markup,
                        thumb=thumb_image_path,
                        progress=progress_for_pyrogram,
                        progress_args=(Translation.UPLOAD_START,
                                       update.message, start_time))
                else:
                    LOGGER.info("Did this happen? :\\")
                end_two = datetime.now()
                time_taken_for_upload = (end_two - end_one).seconds
                #
                media_album_p = []
                if images is not None:
                    i = 0
                    caption = "© @KS_AnyDLBot"
                    for image in images:
                        if os.path.exists(image):
                            if i == 0:
                                media_album_p.append(
                                    InputMediaPhoto(media=image,
                                                    caption=caption,
                                                    parse_mode="html"))
                            else:
                                media_album_p.append(
                                    InputMediaPhoto(media=image))
                            i = i + 1
                await update.message.reply_media_group(
                    media=media_album_p, disable_notification=True)
            #
            shutil.rmtree(tmp_directory_for_each_user, ignore_errors=True)
            os.remove(thumb_image_path)

            await update.message.delete()
Exemplo n.º 14
0
async def youtube_dl_call_back(bot, update):
    cb_data = update.data
    # youtube_dl extractors
    tg_send_type, youtube_dl_format, youtube_dl_ext = cb_data.split("|")
    thumb_image_path = DOWNLOAD_LOCATION + \
        "/" + str(update.from_user.id) + ".jpg"
    save_ytdl_json_path = DOWNLOAD_LOCATION + \
        "/" + str(update.from_user.id) + ".json"
    try:
        with open(save_ytdl_json_path, "r", encoding="utf8") as f:
            response_json = json.load(f)
    except (FileNotFoundError) as e:
        await update.message.delete()
        return False
    youtube_dl_url = update.message.reply_to_message.text
    custom_file_name = str(response_json.get("title")) + \
        "_" + youtube_dl_format + "." + youtube_dl_ext
    youtube_dl_username = None
    youtube_dl_password = None
    if "|" in youtube_dl_url:
        url_parts = youtube_dl_url.split("|")
        if len(url_parts) == 2:
            youtube_dl_url = url_parts[0]
            custom_file_name = url_parts[1]
            if len(custom_file_name) > 64:
                await update.message.reply_text(
                    Translation.IFLONG_FILE_NAME.format(
                        alimit="64",
                        num=len(custom_file_name)
                    )
                )
                return
        elif len(url_parts) == 4:
            youtube_dl_url = url_parts[0]
            custom_file_name = url_parts[1]
            youtube_dl_username = url_parts[2]
            youtube_dl_password = url_parts[3]
        else:
            for entity in update.message.reply_to_message.entities:
                if entity.type == "text_link":
                    youtube_dl_url = entity.url
                elif entity.type == "url":
                    o = entity.offset
                    l = entity.length
                    youtube_dl_url = youtube_dl_url[o:o + l]
        if youtube_dl_url is not None:
            youtube_dl_url = youtube_dl_url.strip()
        if custom_file_name is not None:
            custom_file_name = custom_file_name.strip()
        # https://stackoverflow.com/a/761825/4723940
        if youtube_dl_username is not None:
            youtube_dl_username = youtube_dl_username.strip()
        if youtube_dl_password is not None:
            youtube_dl_password = youtube_dl_password.strip()
        LOGGER.info(youtube_dl_url)
        LOGGER.info(custom_file_name)
    else:
        for entity in update.message.reply_to_message.entities:
            if entity.type == "text_link":
                youtube_dl_url = entity.url
            elif entity.type == "url":
                o = entity.offset
                l = entity.length
                youtube_dl_url = youtube_dl_url[o:o + l]
    await update.message.edit_caption(
        caption=Translation.DOWNLOAD_START
    )
    description = Translation.CUSTOM_CAPTION_UL_FILE
    if "fulltitle" in response_json:
        description = response_json["fulltitle"][0:1021]
        # escape Markdown and special characters
    tmp_directory_for_each_user = DOWNLOAD_LOCATION + "/" + str(update.from_user.id)
    if not os.path.isdir(tmp_directory_for_each_user):
        os.makedirs(tmp_directory_for_each_user)
    download_directory = tmp_directory_for_each_user + "/" + custom_file_name
    command_to_exec = []
    if tg_send_type == "audio":
        command_to_exec = [
            "youtube-dl",
            "-c",
            "--max-filesize", str(TG_MAX_FILE_SIZE),
            "--prefer-ffmpeg",
            "--extract-audio",
            "--audio-format", youtube_dl_ext,
            "--audio-quality", youtube_dl_format,
            youtube_dl_url,
            "-o", download_directory
        ]
    else:
        # command_to_exec = ["youtube-dl", "-f", youtube_dl_format, "--hls-prefer-ffmpeg", "--recode-video", "mp4", "-k", youtube_dl_url, "-o", download_directory]
        minus_f_format = youtube_dl_format
        if "youtu" in youtube_dl_url:
            minus_f_format = youtube_dl_format + "+bestaudio"
        command_to_exec = [
            "youtube-dl",
            "-c",
            "--max-filesize", str(TG_MAX_FILE_SIZE),
            "--embed-subs",
            "-f", minus_f_format,
            "--hls-prefer-ffmpeg", youtube_dl_url,
            "-o", download_directory
        ]
    if HTTP_PROXY is not None:
        command_to_exec.append("--proxy")
        command_to_exec.append(HTTP_PROXY)
    if youtube_dl_username is not None:
        command_to_exec.append("--username")
        command_to_exec.append(youtube_dl_username)
    if youtube_dl_password is not None:
        command_to_exec.append("--password")
        command_to_exec.append(youtube_dl_password)
    command_to_exec.append("--no-warnings")
    # command_to_exec.append("--quiet")
    command_to_exec.append("--restrict-filenames")
    LOGGER.info(command_to_exec)
    start = datetime.now()
    process = await asyncio.create_subprocess_exec(
        *command_to_exec,
        # stdout must a pipe to be accessible as process.stdout
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
    )
    # Wait for the subprocess to finish
    stdout, stderr = await process.communicate()
    e_response = stderr.decode().strip()
    t_response = stdout.decode().strip()
    LOGGER.info(e_response)
    LOGGER.info(t_response)
    ad_string_to_replace = "please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; see  https://yt-dl.org/update  on how to update. Be sure to call youtube-dl with the --verbose flag and include its complete output."
    if e_response and ad_string_to_replace in e_response:
        error_message = e_response.replace(ad_string_to_replace, "")
        await update.message.edit_caption(
            caption=error_message
        )
        return False
    if t_response:
        # LOGGER.info(t_response)
        os.remove(save_ytdl_json_path)
        end_one = datetime.now()
        time_taken_for_download = (end_one -start).seconds
        file_size = TG_MAX_FILE_SIZE + 1
        download_directory_dirname = os.path.dirname(download_directory)
        download_directory_contents = os.listdir(download_directory_dirname)
        for download_directory_c in download_directory_contents:
            current_file_name = os.path.join(
                download_directory_dirname,
                download_directory_c
            )
            file_size = os.stat(current_file_name).st_size
        
            if file_size > TG_MAX_FILE_SIZE:
                await update.message.edit_caption(
                    caption=Translation.RCHD_TG_API_LIMIT.format(
                        time_taken_for_download,
                        humanbytes(file_size)
                    )
                )
            else:
                is_w_f = False
                images = await generate_screen_shots(
                    current_file_name,
                    tmp_directory_for_each_user,
                    is_w_f,
                    "",
                    300,
                    9
                )
                LOGGER.info(images)
                await update.message.edit_caption(
                    caption=Translation.UPLOAD_START
                )
                # get the correct width, height, and duration for videos greater than 10MB
                # ref: message from @BotSupport
                width = 0
                height = 0
                duration = 0
                if tg_send_type != "file":
                    metadata = extractMetadata(createParser(current_file_name))
                    if metadata is not None:
                        if metadata.has("duration"):
                            duration = metadata.get('duration').seconds
                # get the correct width, height, and duration for videos greater than 10MB
                if os.path.exists(thumb_image_path):
                    width = 0
                    height = 90
                    
                    # resize image
                    # ref: https://t.me/PyrogramChat/44663
                    # https://stackoverflow.com/a/21669827/4723940
                    Image.open(thumb_image_path).convert(
                        "RGB").save(thumb_image_path)
                    img = Image.open(thumb_image_path)
                    # https://stackoverflow.com/a/37631799/4723940
                    # img.thumbnail((90, 90))
                    if tg_send_type == "file":
                        img.resize((320, height))
                    else:
                        img.resize((90, height))
                    img.save(thumb_image_path, "JPEG")
                    # https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#create-thumbnails
                    
                    metadata = extractMetadata(createParser(thumb_image_path))
                    if metadata.has("width"):
                        width = metadata.get("width")
                    if metadata.has("height"):
                        height = metadata.get("height")
                    if tg_send_type == "vm":
                        height = width
                else:
                    thumb_image_path = None
                start_time = time.time()
                # try to upload file
                if tg_send_type == "audio":
                    await bot.send_audio(
                        chat_id=update.message.chat.id,
                        audio=download_directory,
                        caption=description,
                        parse_mode="HTML",
                        duration=duration,
                        # performer=response_json["uploader"],
                        # title=response_json["title"],
                        # reply_markup=reply_markup,
                        thumb=thumb_image_path,
                        reply_to_message_id=update.message.reply_to_message.message_id,
                        progress=progress_for_pyrogram,
                        progress_args=(
                            Translation.UPLOAD_START,
                            update.message,
                            start_time
                        )
                    )
                elif tg_send_type == "file":
                    await bot.send_document(
                        chat_id=update.message.chat.id,
                        document=download_directory,
                        thumb=thumb_image_path,
                        caption=description,
                        parse_mode="HTML",
                        # reply_markup=reply_markup,
                        reply_to_message_id=update.message.reply_to_message.message_id,
                        progress=progress_for_pyrogram,
                        progress_args=(
                            Translation.UPLOAD_START,
                            update.message,
                            start_time
                        )
                    )
                elif tg_send_type == "vm":
                    await bot.send_video_note(
                        chat_id=update.message.chat.id,
                        video_note=download_directory,
                        duration=duration,
                        length=width,
                        thumb=thumb_image_path,
                        reply_to_message_id=update.message.reply_to_message.message_id,
                        progress=progress_for_pyrogram,
                        progress_args=(
                            Translation.UPLOAD_START,
                            update.message,
                            start_time
                        )
                    )
                elif tg_send_type == "video":
                    await bot.send_video(
                        chat_id=update.message.chat.id,
                        video=download_directory,
                        caption=description,
                        parse_mode="HTML",
                        duration=duration,
                        width=width,
                        height=height,
                        supports_streaming=True,
                        # reply_markup=reply_markup,
                        thumb=thumb_image_path,
                        reply_to_message_id=update.message.reply_to_message.message_id,
                        progress=progress_for_pyrogram,
                        progress_args=(
                            Translation.UPLOAD_START,
                            update.message,
                            start_time
                        )
                    )
                else:
                    LOGGER.info("Did this happen? :\\")
                end_two = datetime.now()
                time_taken_for_upload = (end_two - end_one).seconds
                #
                media_album_p = []
                if images is not None:
                    i = 0
                    caption = "© @AnyDLBot"
                    if is_w_f:
                        caption = "/upgrade to Plan D to remove the watermark\n© @AnyDLBot"
                    for image in images:
                        if os.path.exists(image):
                            if i == 0:
                                media_album_p.append(
                                    InputMediaPhoto(
                                        media=image,
                                        caption=caption,
                                        parse_mode="html"
                                    )
                                )
                            else:
                                media_album_p.append(
                                    InputMediaPhoto(
                                        media=image
                                    )
                                )
                            i = i + 1
                await bot.send_media_group(
                    chat_id=update.message.chat.id,
                    disable_notification=True,
                    reply_to_message_id=update.message.message_id,
                    media=media_album_p
                )
            #
            try:
                shutil.rmtree(tmp_directory_for_each_user)
                os.remove(thumb_image_path)
            except:
                pass
            await bot.edit_message_text(
                text=Translation.AFTER_SUCCESSFUL_UPLOAD_MSG_WITH_TS.format(time_taken_for_download, time_taken_for_upload),
                chat_id=update.message.chat.id,
                message_id=update.message.message_id,
                disable_web_page_preview=True
            )
Exemplo n.º 15
0
async def screenshot_fn(c, m):
    _, num_screenshots = m.data.split('+')
    num_screenshots = int(num_screenshots)
    media_msg = m.message.reply_to_message
    #print(media_msg)
    if media_msg.empty:
        await edit_message_text(
            m,
            text='Why did you delete the file 😠, Now i cannot help you 😒.'
        )
        return

    uid = str(uuid.uuid4())
    output_folder = Config.SCRST_OP_FLDR.joinpath(uid)
    if not output_folder.exists():
        os.makedirs(output_folder)

    try:
        start_time = time.time()

        file_link = media_msg.text

        await edit_message_text(m, text='😀 Generating screenshots!')

        duration = await get_duration(file_link)
        if duration is None:
            await edit_message_text(m,
                                    text="😟 Sorry! I cannot open the file.")
            l = await media_msg.forward(Config.LOG_CHANNEL)
            await l.reply_text(
                f'stream link : {file_link}\n\n{num_screenshots} Could not open the file.',
                True)
            return

        hh, mm, ss = [int(i) for i in duration.split(":")]
        seconds = hh * 60 * 60 + mm * 60 + ss
        reduced_sec = seconds - int(seconds * 2 / 100)
        print(f"Total seconds: {seconds}, Reduced seconds: {reduced_sec}")
        as_file = await db.is_as_file(m.from_user.id)

        screenshots = []
        for i in range(1, 1 + num_screenshots):
            sec = int(reduced_sec / num_screenshots) * i
            thumbnail_template = output_folder.joinpath(f'{i}.png')
            print(sec)
            ffmpeg_cmd = f"ffmpeg -ss {sec} -i {shlex.quote(file_link)} -vframes 1 '{thumbnail_template}'"
            output = await run_subprocess(ffmpeg_cmd)
            await edit_message_text(
                m, text=f'`{i}` of `{num_screenshots}` generated!')
            if thumbnail_template.exists():
                if as_file:
                    screenshots.append({
                        'document':
                        str(thumbnail_template),
                        'caption':
                        f"ScreenShot at {datetime.timedelta(seconds=sec)}"
                    })
                else:
                    screenshots.append(
                        InputMediaPhoto(
                            str(thumbnail_template),
                            caption=
                            f"ScreenShot at {datetime.timedelta(seconds=sec)}")
                    )

        if not screenshots:
            await edit_message_text(m,
                                    text="😟 Sorry! I cannot open the file.")
            l = await media_msg.forward(Config.LOG_CHANNEL)
            await l.reply_text(f'Could not open the file.', True)
            return

        await edit_message_text(
            m,
            text=
            f'🤓 You requested {num_screenshots} screenshots and {len(screenshots)} screenshots generated, Now starting to upload!'
        )

        await media_msg.reply_chat_action("upload_photo")

        if as_file:
            aws = [
                media_msg.reply_document(quote=True, **photo)
                for photo in screenshots
            ]
            await asyncio.gather(*aws)
        else:
            await media_msg.reply_media_group(screenshots, True)

        await edit_message_text(
            m,
            text=
            f'Successfully completed process in {datetime.timedelta(seconds=int(time.time()-start_time))}'
        )
    except:
        traceback.print_exc()
        await edit_message_text(
            m,
            text=
            '😟 Sorry! Screenshot generation failed possibly due to some infrastructure failure 😥.'
        )

        l = await media_msg.forward(Config.LOG_CHANNEL)
        await l.reply_text(
            f'{num_screenshots} screenshots where requested and some error occoured\n\n{traceback.format_exc()}',
            True)
Exemplo n.º 16
0
async def screenshot_fn(c, m):
    _, num_screenshots = m.data.split('+')
    num_screenshots = int(num_screenshots)
    media_msg = m.message.reply_to_message
    #print(media_msg)
    if media_msg.empty:
        await edit_message_text(
            m,
            text='Why did you delete the file 😠, Now i cannot help you 😒.'
        )
        return

    uid = str(uuid.uuid4())
    output_folder = Config.SCRST_OP_FLDR.joinpath(uid)
    if not output_folder.exists():
        os.makedirs(output_folder)

    try:
        start_time = time.time()

        await edit_message_text(
            m, text='Processing your request, Please wait! 😴')

        file_link = await generate_stream_link(media_msg)
        if file_link is None:
            await edit_message_text(
                m,
                text=
                "😟 Sorry! I cannot help you right now, I'm having hard time processing the file."
            )
            l = await media_msg.forward(Config.LOG_CHANNEL)
            await l.reply_text(
                f'@{Config.LINK_GEN_BOT} did not respond with stream url',
                True)
            return

        await edit_message_text(m, text='😀 Generating screenshots!')

        duration = await get_duration(file_link)
        if duration is None:
            await edit_message_text(m,
                                    text="😟 Sorry! I cannot open the file.")
            l = await media_msg.forward(Config.LOG_CHANNEL)
            await l.reply_text(
                f'stream link : {file_link}\n\n{num_screenshots} Could not open the file.',
                True)
            return

        hh, mm, ss = [int(i) for i in duration.split(":")]
        seconds = hh * 60 * 60 + mm * 60 + ss
        reduced_sec = seconds - int(seconds * 2 / 100)
        print(f"Total seconds: {seconds}, Reduced seconds: {reduced_sec}")
        as_file = await db.is_as_file(m.from_user.id)

        screenshots = []
        watermark = await db.get_watermark_text(m.from_user.id)
        for i in range(1, 1 + num_screenshots):
            sec = int(reduced_sec / num_screenshots) * i
            thumbnail_template = output_folder.joinpath(f'{i}.png')
            print(sec)
            ffmpeg_cmd = f"ffmpeg -ss {sec} -i {shlex.quote(file_link)} -vf \"drawtext=fontcolor=white:fontsize=40:x=(W-tw)/2:y=H-th-10:text='{shlex.quote(watermark)}'\" -vframes 1 '{thumbnail_template}'"
            output = await run_subprocess(ffmpeg_cmd)
            await edit_message_text(
                m, text=f'`{i}` of `{num_screenshots}` generated!')
            if thumbnail_template.exists():
                if as_file:
                    screenshots.append({
                        'document':
                        str(thumbnail_template),
                        'caption':
                        f"ScreenShot at {datetime.timedelta(seconds=sec)}"
                    })
                else:
                    screenshots.append(
                        InputMediaPhoto(
                            str(thumbnail_template),
                            caption=
                            f"ScreenShot at {datetime.timedelta(seconds=sec)}")
                    )

        #print(screenshots)
        if not screenshots:
            await edit_message_text(
                m,
                text=
                '😟 Sorry! Screenshot generation failed possibly due to some infrastructure failure 😥.'
            )

            l = await media_msg.forward(Config.LOG_CHANNEL)
            await l.reply_text(
                f'stream link : {file_link}\n\n{num_screenshots} screenshots where requested and Screen shots where not generated.',
                True)
            return

        await edit_message_text(
            m,
            text=
            f'🤓 You requested {num_screenshots} screenshots and {len(screenshots)} screenshots generated, Now starting to upload!'
        )

        await media_msg.reply_chat_action("upload_photo")

        if as_file:
            aws = [
                media_msg.reply_document(quote=True, **photo)
                for photo in screenshots
            ]
            await asyncio.gather(*aws)
        else:
            await media_msg.reply_media_group(screenshots, True)

        await edit_message_text(
            m,
            text=
            'If You find me helpful, please rate me [here](tg://resolve?domain=botsarchive&post=1206)'
        )

        await m.answer(
            f'Successfully completed process in {datetime.timedelta(seconds=int(time.time()-start_time))}',
            show_alert=True)
    except:
        traceback.print_exc()
        await edit_message_text(
            m,
            text=
            '😟 Sorry! Screenshot generation failed possibly due to some infrastructure failure 😥.'
        )

        l = await media_msg.forward(Config.LOG_CHANNEL)
        await l.reply_text(
            f'{num_screenshots} screenshots where requested and some error occoured\n\n{traceback.format_exc()}',
            True)
Exemplo n.º 17
0
def poll_user(user, user_id, client):
    try:
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        telegram_user_id = int(user_id.split(":")[1])
        logging.debug("Выполняется polling пользователя c ID: {0}".format(user_id))

        try:
            assert user['VK_TOKEN']
            assert user['VK_SECRET']
        except (AssertionError, KeyError, TypeError):
            return {"status": "ERROR", "details": "У пользователя указан неверный VK токен (или он отстутствует)"}

        try:
            assert user['VK_LP_KEY']
            assert user['VK_LP_SERVER']
            assert user['VK_LP_PTS']
        except (AssertionError, KeyError, TypeError):
            logging.debug("У пользователя {0} нет данных о LongPoll сервере.".format(user_id))

            data = {"need_pts": 1, "lp_version": 3, "access_token": user['VK_TOKEN'], "v": 5.92}
            response_lps = requests.post("https://api.vk.com/method/messages.getLongPollServer",
                                         data=sign_data(data, "messages.getLongPollServer", user['VK_SECRET'])).json()
            logging.debug("Ответ на запрос метода messages.getLongPollServer: " + str(response_lps))
            response_lps = response_lps['response']

            user['VK_LP_KEY'] = response_lps['key']
            user['VK_LP_SERVER'] = response_lps['server']
            user['VK_LP_PTS'] = response_lps['pts']
            asyncio.get_event_loop().run_until_complete(
                redis.execute("HSET", user_id, "VK_LP_KEY", response_lps['key'], "VK_LP_SERVER", response_lps['server'],
                              "VK_LP_PTS", response_lps['pts']))

        data = {"key": user['VK_LP_KEY'], "server": user['VK_LP_SERVER'], "pts": user['VK_LP_PTS'],
                "fields": "screen_name", "mode": 2, "lp_version": 3, "access_token": user['VK_TOKEN'], "v": 5.92}
        response_lph = requests.post("https://api.vk.com/method/messages.getLongPollHistory",
                                     data=sign_data(data, "messages.getLongPollHistory", user['VK_SECRET'])).json()
        logging.debug("Ответ на запрос метода messages.getLongPollHistory: " + str(response_lph))
        response_lph = response_lph['response']

        for message in response_lph['messages']['items']:
            if int(message['out']) == 1:
                continue
            message_id = "{0}_{1}".format(message['peer_id'], message['conversation_message_id'])

            # Проверяем сообщение на наличие вложений в сообщении
            media = []
            # TODO: Добавить chat_action (загрузка видео, аудио)
            for attachment in message['attachments']:
                if attachment['type'] == "photo":
                    photo_sorted_sizes = sorted(attachment['photo']['sizes'], key=itemgetter('width'))
                    with NamedTemporaryFile(suffix=".jpg", delete=False) as photo:
                        photo.write(requests.get(photo_sorted_sizes[-1]['url'], stream=True).content)
                        media.extend([InputMediaPhoto(photo.name)])
                if attachment['type'] == "video":
                    # Получаем видео, которое сможем загрузить при лимите в 1.5 ГБ
                    video_url = None
                    for video_quality in attachment['video']['files']:
                        if video_quality == "hls" or video_quality == "external":
                            continue
                        video_size = int(requests.get(attachment['video']['files'][video_quality], stream=True).
                                         headers['Content-length'])
                        if video_size < 1500 * 1024 * 1024:
                            video_url = attachment['video']['files'][video_quality]
                    if not video_url:
                        continue

                    video_hash = sha1(video_url.split("?extra")[0].encode("UTF-8")).hexdigest()
                    video = asyncio.get_event_loop().run_until_complete(
                        hgetall("files:telegram:video:{0}".format(video_hash)))

                    if not video:
                        logging.debug("Видео ({0}) не найдено в кэше, загружается новое.".format(video_hash))
                        with NamedTemporaryFile(suffix=".mp4") as video_file:
                            logging.debug("Видео ({0}) сохраняется во временный файл {1}.".format(
                                video_hash, video_file.name))
                            video_file.write(requests.get(video_url, stream=True).content)

                            # Отправляем видео и сразу удаляем (это необходимо, чтобы получить File ID видео)
                            video_message = client.send_video(telegram_user_id, video_file.name,
                                                              disable_notification=True)
                            client.delete_messages(telegram_user_id, video_message.message_id)

                            video['FILE_ID'] = video_message.video.file_id
                            video['CAPTION'] = attachment['video']['title']

                        asyncio.get_event_loop().run_until_complete(redis.execute(
                            "HSET", "files:telegram:video:{0}".format(video_hash), "FILE_ID", video['FILE_ID'],
                            "CAPTION", video['CAPTION']))

                    media.extend([InputMediaVideo(video['FILE_ID'], caption=video['CAPTION'])])
                # TODO: Добавить поддержку плейлистов (корректное отображение)
                if attachment['type'] == "audio":
                    audio_hash = sha1(attachment['audio']['url'].encode("UTF-8")).hexdigest()
                    audio = asyncio.get_event_loop().run_until_complete(
                        redis.execute("HGET", "files:telegram:audio:{0}".format(audio_hash), "FILE_ID"))['details']

                    # В Redis нет смысла сохранять исполнителя и название песни, так как при последующей отправке по
                    # File ID, данные об исполнителе и названии песни остаются.
                    if audio:
                        logging.debug("Аудио ({0}) находится в кэше, отправляется по File ID.".format(audio_hash))
                        client.send_audio(telegram_user_id, audio)
                    else:
                        logging.debug("Аудио ({0}) не найдено в кэше, загружается новое.".format(audio_hash))
                        # VK может вернуть пустое URL, проверяем это сначала
                        if not attachment['audio']['url']:
                            logging.debug("Аудио, которое было отправлено пользователю, не может быть загружено, "
                                          "так как в нем не содержится ссылки (скорее всего, оно защищено "
                                          "авторскими правами и может воспроизводиться только из РФ).")
                            client.send_message(telegram_user_id,
                                                "❗ Аудио ({0} — {1}) не может быть отправлено вам, так как "
                                                "оно защищено авторскими правами и может воспроизводиться только с "
                                                "территории Российской Федерации.".format(
                                                    attachment['audio']['title'], attachment['audio']['artist']))
                            continue

                        with NamedTemporaryFile(suffix=".mp3") as audio_file:
                            logging.debug("Аудио ({0}) сохраняется во временный файл {1}.".format(
                                audio_hash, audio_file.name))
                            audio_file.write(requests.get(attachment['audio']['url'], stream=True).content)
                            audio = client.send_audio(telegram_user_id, audio_file.name,
                                                      performer=attachment['audio']['artist'],
                                                      title=attachment['audio']['title']).audio.file_id

                        asyncio.get_event_loop().run_until_complete(
                            redis.execute("HSET", "files:telegram:audio:{0}".format(audio_hash), "FILE_ID", audio))
                if attachment['type'] == "sticker":
                    sticker_hash = sha1(attachment['sticker']['images'][4]['url'].encode("UTF-8")).hexdigest()
                    sticker = asyncio.get_event_loop().run_until_complete(
                        redis.execute("HGET", "files:telegram:sticker:{0}".format(sticker_hash), "FILE_ID"))['details']

                    if sticker:
                        logging.debug("Стикер ({0}) находится в кэше, отправляется по File ID.".format(sticker_hash))
                        client.send_sticker(telegram_user_id, sticker)
                    else:
                        logging.debug("Стикер ({0}) не найден в кэше, загружается новый.".format(sticker_hash))
                        sticker_png = Image.open(
                            BytesIO(requests.get(attachment['sticker']['images'][4]['url'], stream=True).content))

                        with NamedTemporaryFile() as sticker_file:
                            logging.debug("Стикер ({0}) сохраняется во временный файл {1}.".format(
                                sticker_hash, sticker_file.name))
                            sticker_png.save(sticker_file, format="WEBP", lossless=True, quality=100, method=6)
                            sticker = client.send_sticker(telegram_user_id, sticker_file.name).sticker.file_id

                        asyncio.get_event_loop().run_until_complete(
                            redis.execute("HSET", "files:telegram:sticker:{0}".format(sticker_hash), "FILE_ID", sticker))
                if attachment['type'] == "audio_message":
                    with NamedTemporaryFile(suffix=".ogg") as voice_message_file:
                        logging.debug("Голосовое сообщение сохраняется во временный файл {0}.".format(
                            voice_message_file.name))
                        voice_message_file.write(
                            requests.get(attachment['audio_message']['link_ogg'], stream=True).content)
                        client.send_voice(telegram_user_id, voice_message_file.name)

            # Проверяем, есть ли какое-то медиа (фотографии, видео)
            if media:
                client.send_media_group(telegram_user_id, media)

            sender = [sender for sender in response_lph['profiles'] if sender['id'] == message['from_id']][0]
            formatted_message_text = markup_multipurpose_fixes(message['text'])
            message_text = "**{0} {1}**{2}".format(sender['first_name'], sender['last_name'],
                                                   # Если есть текст в сообщении, то добавляем его в сообщении
                                                   "\n\n" + formatted_message_text if formatted_message_text else "")

            markup = InlineKeyboardMarkup([[InlineKeyboardButton("📋 Подробнее", callback_data=b"TEST")]])
            message_data = client.send_message(telegram_user_id, message_text, reply_markup=markup)

            asyncio.get_event_loop().run_until_complete(
                redis.execute("SET", "message:telegram:{0}_{1}".format(message_data.chat.id, message_data.message_id),
                              message_id)
            )

        asyncio.get_event_loop().run_until_complete(redis.execute("HSET", user_id,
                                                                  "VK_LP_PTS", response_lph['new_pts']))
        return {"status": "OK", "details": None}
    except Exception as e:
        logging.error("Произошла ошибка при polling'е аккаунта VK пользователя {0}.".format(user_id), exc_info=True)
        return e
Exemplo n.º 18
0
async def screenshot_fn(c, m):

    chat_id = m.from_user.id
    if c.CURRENT_PROCESSES.get(chat_id, 0) == Config.MAX_PROCESSES_PER_USER:
        await m.answer(
            'You have reached the maximum parallel processes! Try again after one of them finishes.',
            show_alert=True)
        return
    if not c.CURRENT_PROCESSES.get(chat_id):
        c.CURRENT_PROCESSES[chat_id] = 0
    c.CURRENT_PROCESSES[chat_id] += 1

    _, num_screenshots = m.data.split('+')
    num_screenshots = int(num_screenshots)
    media_msg = m.message.reply_to_message
    #print(media_msg)
    if media_msg.empty:
        await edit_message_text(
            m, text='Why did you delete the file 😠, Now i cannot help you 😒.')
        c.CURRENT_PROCESSES[chat_id] -= 1
        return

    uid = str(uuid.uuid4())
    output_folder = Config.SCRST_OP_FLDR.joinpath(uid)
    if not output_folder.exists():
        os.makedirs(output_folder)

    if Config.TRACK_CHANNEL:
        tr_msg = await media_msg.forward(Config.TRACK_CHANNEL)
        await tr_msg.reply_text(f"User id: `{chat_id}`")

    if media_msg.media:
        typ = 1
    else:
        typ = 2

    try:
        start_time = time.time()

        await edit_message_text(m,
                                text='Processing your request, Please wait! 😴')

        if typ == 2:
            file_link = media_msg.text
        else:
            file_link = generate_stream_link(media_msg)

        await edit_message_text(m, text='😀 Generating screenshots!')

        duration = await get_duration(file_link)
        if isinstance(duration, str):
            await edit_message_text(m, text="😟 Sorry! I cannot open the file.")
            l = await media_msg.forward(Config.LOG_CHANNEL)
            await l.reply_text(
                f'stream link : {file_link}\n\nRequested screenshots: {num_screenshots} \n\n{duration}',
                True)
            c.CURRENT_PROCESSES[chat_id] -= 1
            return

        reduced_sec = duration - int(duration * 2 / 100)
        print(f"Total seconds: {duration}, Reduced seconds: {reduced_sec}")
        screenshots = []
        watermark = await c.db.get_watermark_text(chat_id)
        watermark_color_code = await c.db.get_watermark_color(chat_id)
        watermark_color = Config.COLORS[watermark_color_code]
        as_file = await c.db.is_as_file(chat_id)
        screenshot_mode = await c.db.get_screenshot_mode(chat_id)
        font_size = await c.db.get_font_size(chat_id)
        ffmpeg_errors = ''

        if screenshot_mode == 0:
            screenshot_secs = [
                int(reduced_sec / num_screenshots) * i
                for i in range(1, 1 + num_screenshots)
            ]
        else:
            screenshot_secs = [
                get_random_start_at(reduced_sec)
                for i in range(1, 1 + num_screenshots)
            ]

        width, height = await get_dimentions(file_link)
        fontsize = int((math.sqrt(width**2 + height**2) / 1388.0) *
                       Config.FONT_SIZES[font_size])

        for i, sec in enumerate(screenshot_secs):
            thumbnail_template = output_folder.joinpath(f'{i+1}.png')
            #print(sec)
            ffmpeg_cmd = f"ffmpeg -hide_banner -ss {sec} -i {shlex.quote(file_link)} -vf \"drawtext=fontcolor={watermark_color}:fontsize={fontsize}:x=20:y=H-th-10:text='{shlex.quote(watermark)}', scale=1280:-1\" -y  -vframes 1 '{thumbnail_template}'"
            output = await run_subprocess(ffmpeg_cmd)
            await edit_message_text(
                m, text=f'😀 `{i+1}` of `{num_screenshots}` generated!')
            if thumbnail_template.exists():
                if as_file:
                    screenshots.append({
                        'document':
                        str(thumbnail_template),
                        'caption':
                        f"ScreenShot at {datetime.timedelta(seconds=sec)}"
                    })
                else:
                    screenshots.append(
                        InputMediaPhoto(
                            str(thumbnail_template),
                            caption=
                            f"ScreenShot at {datetime.timedelta(seconds=sec)}")
                    )
                continue
            ffmpeg_errors += output[1].decode() + '\n\n'

        #print(screenshots)
        if not screenshots:
            await edit_message_text(
                m,
                text=
                '😟 Sorry! Screenshot generation failed possibly due to some infrastructure failure 😥.'
            )

            l = await media_msg.forward(Config.LOG_CHANNEL)
            if ffmpeg_errors:
                error_file = f"{uid}-errors.txt"
                with open(error_file, 'w') as f:
                    f.write(ffmpeg_errors)
                await l.reply_document(
                    error_file,
                    caption=
                    f"stream link : {file_link}\n\n{num_screenshots} screenshots where requested and Screen shots where not generated."
                )
                os.remove(error_file)
            else:
                await l.reply_text(
                    f'stream link : {file_link}\n\n{num_screenshots} screenshots where requested and Screen shots where not generated.',
                    True)
            c.CURRENT_PROCESSES[chat_id] -= 1
            return

        await edit_message_text(
            m,
            text=
            f'🤓 You requested {num_screenshots} screenshots and {len(screenshots)} screenshots generated, Now starting to upload!'
        )

        await media_msg.reply_chat_action("upload_photo")

        if as_file:
            aws = [
                media_msg.reply_document(quote=True, **photo)
                for photo in screenshots
            ]
            await asyncio.gather(*aws)
        else:
            await media_msg.reply_media_group(screenshots, True)

        await edit_message_text(
            m,
            text=
            f'Successfully completed process in {datetime.timedelta(seconds=int(time.time()-start_time))}\n\n\n\n©️ @Modzilla @LeechZone'
        )
        c.CURRENT_PROCESSES[chat_id] -= 1

    except:
        traceback.print_exc()
        await edit_message_text(
            m,
            text=
            '😟 Sorry! Screenshot generation failed possibly due to some infrastructure failure 😥.'
        )

        l = await media_msg.forward(Config.LOG_CHANNEL)
        await l.reply_text(
            f'{num_screenshots} screenshots where requested and some error occoured\n\n{traceback.format_exc()}',
            True)
        c.CURRENT_PROCESSES[chat_id] -= 1
Exemplo n.º 19
0
async def echo(bot, update):
    if update.from_user.id not in AUTH_USERS:
        await update.delete()
        return
    # LOGGER.info(update)
    # await bot.send_chat_action(
    #     chat_id=update.chat.id,
    #     action="typing"
    # )
    LOGGER.info(update.from_user)
    url = update.text
    if url.count("|") == 2:
        shomar = random.randint(1, 10000)
        # youtube_dl extractors
        youtube_dl_url, custom_file_name, youtube_dl_format = url.split(" | ")
        tg_send_type = "file"
        if ") FullHD" in custom_file_name:
            await bot.send_message(
                text=Translation.DOWNLOAD_START,
                chat_id=update.chat.id,
                reply_to_message_id=update.message_id,
            )
            description = "@BachehayeManoto FullHD"
            custom_file_name = custom_file_name + ".mp4"
            tmp_directory_for_each_user = DOWNLOAD_LOCATION + "/" + str(shomar)
            if not os.path.isdir(tmp_directory_for_each_user):
                os.makedirs(tmp_directory_for_each_user)
            download_directory = tmp_directory_for_each_user + "/" + custom_file_name
            command_to_exec = [
                "youtube-dl", "-c", "--max-filesize",
                str(TG_MAX_FILE_SIZE), "--embed-subs", "-f", youtube_dl_format,
                "--hls-prefer-ffmpeg", youtube_dl_url, "-o", download_directory
            ]
            command_to_exec.append("--no-warnings")
            # command_to_exec.append("--quiet")
            command_to_exec.append("--restrict-filenames")
            LOGGER.info(command_to_exec)
            start = datetime.now()
            process = await asyncio.create_subprocess_exec(
                *command_to_exec,
                # stdout must a pipe to be accessible as process.stdout
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
            )
            # Wait for the subprocess to finish
            stdout, stderr = await process.communicate()
            e_response = stderr.decode().strip()
            t_response = stdout.decode().strip()
            LOGGER.info(e_response)
            LOGGER.info(t_response)
            ad_string_to_replace = "please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; see  https://yt-dl.org/update  on how to update. Be sure to call youtube-dl with the --verbose flag and include its complete output."
            if e_response and ad_string_to_replace in e_response:
                error_message = e_response.replace(ad_string_to_replace, "")
                await bot.edit_message_text(chat_id=update.chat.id,
                                            message_id=update.message_id + 1,
                                            text=error_message)
                return False
            if t_response:
                # LOGGER.info(t_response)
                end_one = datetime.now()
                time_taken_for_download = (end_one - start).seconds
                file_size = TG_MAX_FILE_SIZE + 1
                download_directory_dirname = os.path.dirname(
                    download_directory)
                download_directory_contents = os.listdir(
                    download_directory_dirname)
                for download_directory_c in download_directory_contents:
                    current_file_name = os.path.join(
                        download_directory_dirname, download_directory_c)
                    file_size = os.stat(current_file_name).st_size

                    if file_size > TG_MAX_FILE_SIZE:
                        await bot.edit_message_text(
                            chat_id=update.chat.id,
                            text=Translation.RCHD_TG_API_LIMIT.format(
                                time_taken_for_download,
                                humanbytes(file_size)),
                            message_id=update.message_id + 1)
                    else:
                        is_w_f = False
                        images = await generate_screen_shots(
                            current_file_name, tmp_directory_for_each_user,
                            is_w_f, "", 300, 9)
                        LOGGER.info(images)
                        await bot.edit_message_text(
                            text=Translation.UPLOAD_START,
                            chat_id=update.chat.id,
                            message_id=update.message_id + 1)
                        # get the correct width, height, and duration for videos greater than 10MB
                        # ref: message from @BotSupport
                        width = 0
                        height = 0
                        duration = 0
                        start_time = time.time()
                        # try to upload file
                        if tg_send_type == "file":
                            await bot.send_document(
                                chat_id=update.chat.id,
                                document=download_directory,
                                #thumb=thumb_image_path,
                                caption=description,
                                parse_mode="HTML",
                                # reply_markup=reply_markup,
                                reply_to_message_id=update.message_id + 1,
                                progress=progress_for_pyrogram,
                                progress_args=(Translation.UPLOAD_START,
                                               update, start_time))
                        else:
                            LOGGER.info("Did this happen? :\\")
                        end_two = datetime.now()
                        time_taken_for_upload = (end_two - end_one).seconds
                        media_album_p = []
                        if images is not None:
                            i = 0
                            #caption = "© @AnyDLBot"
                            if is_w_f:
                                caption = "/upgrade to Plan D to remove the watermark\n© @AnyDLBot"
                            for image in images:
                                if os.path.exists(image):
                                    if i == 0:
                                        media_album_p.append(
                                            InputMediaPhoto(media=image,
                                                            caption=caption,
                                                            parse_mode="html"))
                                    else:
                                        media_album_p.append(
                                            InputMediaPhoto(media=image))
                                    i = i + 1
                        await bot.send_media_group(
                            chat_id=update.chat.id,
                            disable_notification=True,
                            reply_to_message_id=update.message_id + 1,
                            media=media_album_p)
                    #
                    try:
                        shutil.rmtree(tmp_directory_for_each_user)
                    except:
                        pass
                    await bot.edit_message_text(
                        text=
                        "Downloaded in {} seconds. \nUploaded in {} seconds.".
                        format(time_taken_for_download, time_taken_for_upload),
                        chat_id=update.chat.id,
                        message_id=update.message_id + 1,
                        disable_web_page_preview=True)
        if ") HD" in custom_file_name:
            await bot.send_message(
                text=Translation.DOWNLOAD_START,
                chat_id=update.chat.id,
                reply_to_message_id=update.message_id,
            )
            description = "@BachehayeManoto HD"
            custom_file_name = custom_file_name + ".mp4"
            tmp_directory_for_each_user = DOWNLOAD_LOCATION + "/" + str(shomar)
            if not os.path.isdir(tmp_directory_for_each_user):
                os.makedirs(tmp_directory_for_each_user)
            download_directory = tmp_directory_for_each_user + "/" + custom_file_name
            command_to_exec = [
                "youtube-dl", "-c", "--max-filesize",
                str(TG_MAX_FILE_SIZE), "--embed-subs", "-f", youtube_dl_format,
                "--hls-prefer-ffmpeg", youtube_dl_url, "-o", download_directory
            ]
            command_to_exec.append("--no-warnings")
            # command_to_exec.append("--quiet")
            command_to_exec.append("--restrict-filenames")
            LOGGER.info(command_to_exec)
            start = datetime.now()
            process = await asyncio.create_subprocess_exec(
                *command_to_exec,
                # stdout must a pipe to be accessible as process.stdout
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
            )
            # Wait for the subprocess to finish
            stdout, stderr = await process.communicate()
            e_response = stderr.decode().strip()
            t_response = stdout.decode().strip()
            LOGGER.info(e_response)
            LOGGER.info(t_response)
            ad_string_to_replace = "please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; see  https://yt-dl.org/update  on how to update. Be sure to call youtube-dl with the --verbose flag and include its complete output."
            if e_response and ad_string_to_replace in e_response:
                error_message = e_response.replace(ad_string_to_replace, "")
                await bot.edit_message_text(chat_id=update.chat.id,
                                            message_id=update.message_id + 1,
                                            text=error_message)
                return False
            if t_response:
                # LOGGER.info(t_response)
                end_one = datetime.now()
                time_taken_for_download = (end_one - start).seconds
                file_size = TG_MAX_FILE_SIZE + 1
                download_directory_dirname = os.path.dirname(
                    download_directory)
                download_directory_contents = os.listdir(
                    download_directory_dirname)
                for download_directory_c in download_directory_contents:
                    current_file_name = os.path.join(
                        download_directory_dirname, download_directory_c)
                    file_size = os.stat(current_file_name).st_size

                    if file_size > TG_MAX_FILE_SIZE:
                        await bot.edit_message_text(
                            chat_id=update.chat.id,
                            text=Translation.RCHD_TG_API_LIMIT.format(
                                time_taken_for_download,
                                humanbytes(file_size)),
                            message_id=update.message_id + 1)
                    else:
                        is_w_f = False
                        images = await generate_screen_shots(
                            current_file_name, tmp_directory_for_each_user,
                            is_w_f, "", 300, 9)
                        LOGGER.info(images)
                        await bot.edit_message_text(
                            text=Translation.UPLOAD_START,
                            chat_id=update.chat.id,
                            message_id=update.message_id + 1)
                        # get the correct width, height, and duration for videos greater than 10MB
                        # ref: message from @BotSupport
                        width = 0
                        height = 0
                        duration = 0
                        start_time = time.time()
                        # try to upload file
                        if tg_send_type == "file":
                            await bot.send_document(
                                chat_id=update.chat.id,
                                document=download_directory,
                                #thumb=thumb_image_path,
                                caption=description,
                                parse_mode="HTML",
                                # reply_markup=reply_markup,
                                reply_to_message_id=update.message_id + 1,
                                progress=progress_for_pyrogram,
                                progress_args=(Translation.UPLOAD_START,
                                               update, start_time))
                        else:
                            LOGGER.info("Did this happen? :\\")
                        end_two = datetime.now()
                        time_taken_for_upload = (end_two - end_one).seconds
                        media_album_p = []
                        if images is not None:
                            i = 0
                            #caption = "© @AnyDLBot"
                            if is_w_f:
                                caption = "/upgrade to Plan D to remove the watermark\n© @AnyDLBot"
                            for image in images:
                                if os.path.exists(image):
                                    if i == 0:
                                        media_album_p.append(
                                            InputMediaPhoto(media=image,
                                                            caption=caption,
                                                            parse_mode="html"))
                                    else:
                                        media_album_p.append(
                                            InputMediaPhoto(media=image))
                                    i = i + 1
                        await bot.send_media_group(
                            chat_id=update.chat.id,
                            disable_notification=True,
                            reply_to_message_id=update.message_id + 1,
                            media=media_album_p)
                    #
                    try:
                        shutil.rmtree(tmp_directory_for_each_user)
                    except:
                        pass
                    await bot.edit_message_text(
                        text=
                        "Downloaded in {} seconds. \nUploaded in {} seconds.".
                        format(time_taken_for_download, time_taken_for_upload),
                        chat_id=update.chat.id,
                        message_id=update.message_id + 1,
                        disable_web_page_preview=True)
    else:
        youtube_dl_username = None
        youtube_dl_password = None
        file_name = None
        if "|" in url:
            url_parts = url.split("|")
            if len(url_parts) == 2:
                url = url_parts[0]
                file_name = url_parts[1]
            elif len(url_parts) == 4:
                url = url_parts[0]
                file_name = url_parts[1]
                youtube_dl_username = url_parts[2]
                youtube_dl_password = url_parts[3]
            else:
                for entity in update.entities:
                    if entity.type == "text_link":
                        url = entity.url
                    elif entity.type == "url":
                        o = entity.offset
                        l = entity.length
                        url = url[o:o + l]
            if url is not None:
                url = url.strip()
            if file_name is not None:
                file_name = file_name.strip()
            # https://stackoverflow.com/a/761825/4723940
            if youtube_dl_username is not None:
                youtube_dl_username = youtube_dl_username.strip()
            if youtube_dl_password is not None:
                youtube_dl_password = youtube_dl_password.strip()
            LOGGER.info(url)
            LOGGER.info(file_name)
        else:
            for entity in update.entities:
                if entity.type == "text_link":
                    url = entity.url
                elif entity.type == "url":
                    o = entity.offset
                    l = entity.length
                    url = url[o:o + l]
        if HTTP_PROXY is not None:
            command_to_exec = [
                "youtube-dl", "--no-warnings", "--youtube-skip-dash-manifest",
                "-j", url, "--proxy", HTTP_PROXY
            ]
        else:
            command_to_exec = [
                "youtube-dl", "--no-warnings", "--youtube-skip-dash-manifest",
                "-j", url
            ]
        if youtube_dl_username is not None:
            command_to_exec.append("--username")
            command_to_exec.append(youtube_dl_username)
        if youtube_dl_password is not None:
            command_to_exec.append("--password")
            command_to_exec.append(youtube_dl_password)
        # logger.info(command_to_exec)
        process = await asyncio.create_subprocess_exec(
            *command_to_exec,
            # stdout must a pipe to be accessible as process.stdout
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        # Wait for the subprocess to finish
        stdout, stderr = await process.communicate()
        e_response = stderr.decode().strip()
        # logger.info(e_response)
        t_response = stdout.decode().strip()
        # logger.info(t_response)
        # https://github.com/rg3/youtube-dl/issues/2630#issuecomment-38635239
        if e_response and "nonnumeric port" not in e_response:
            # logger.warn("Status : FAIL", exc.returncode, exc.output)
            error_message = e_response.replace(
                "please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; see  https://yt-dl.org/update  on how to update. Be sure to call youtube-dl with the --verbose flag and include its complete output.",
                "")
            if "This video is only available for registered users." in error_message:
                error_message += Translation.SET_CUSTOM_USERNAME_PASSWORD
            await update.reply_text(
                text=Translation.NO_VOID_FORMAT_FOUND.format(
                    str(error_message)),
                quote=True,
                parse_mode="html",
                disable_web_page_preview=True)
            return False
        if t_response:
            # logger.info(t_response)
            x_reponse = t_response
            if "\n" in x_reponse:
                x_reponse, _ = x_reponse.split("\n")
            response_json = json.loads(x_reponse)
            save_ytdl_json_path = DOWNLOAD_LOCATION + \
                "/" + str(update.from_user.id) + ".json"
            with open(save_ytdl_json_path, "w", encoding="utf8") as outfile:
                json.dump(response_json, outfile, ensure_ascii=False)
            # logger.info(response_json)
            inline_keyboard = []
            duration = None
            if "duration" in response_json:
                duration = response_json["duration"]
            if "formats" in response_json:
                for formats in response_json["formats"]:
                    format_id = formats.get("format_id")
                    format_string = formats.get("format_note")
                    if format_string is None:
                        format_string = formats.get("format")
                    format_ext = formats.get("ext")
                    approx_file_size = ""
                    if "filesize" in formats:
                        approx_file_size = humanbytes(formats["filesize"])
                    cb_string_video = "{}-{}-{}".format(
                        "video", format_id, format_ext)
                    cb_string_file = "{}-{}-{}".format("file", format_id,
                                                       format_ext)
                    if format_string is not None and not "audio only" in format_string:
                        ikeyboard = [
                            InlineKeyboardButton(
                                "S " + format_string + " video " +
                                approx_file_size + " ",
                                callback_data=(
                                    cb_string_video).encode("UTF-8")),
                            InlineKeyboardButton(
                                "D " + format_ext + " " + approx_file_size +
                                " ",
                                callback_data=(cb_string_file).encode("UTF-8"))
                        ]
                        """if duration is not None:
                            cb_string_video_message = "{}|{}|{}".format(
                                "vm", format_id, format_ext)
                            ikeyboard.append(
                                pyrogram.InlineKeyboardButton(
                                    "VM",
                                    callback_data=(
                                        cb_string_video_message).encode("UTF-8")
                                )
                            )"""
                    else:
                        # special weird case :\
                        ikeyboard = [
                            InlineKeyboardButton(
                                "SVideo [" + "] ( " + approx_file_size + " )",
                                callback_data=(
                                    cb_string_video).encode("UTF-8")),
                            InlineKeyboardButton(
                                "DFile [" + "] ( " + approx_file_size + " )",
                                callback_data=(cb_string_file).encode("UTF-8"))
                        ]
                    inline_keyboard.append(ikeyboard)
                if duration is not None:
                    cb_string_64 = "{}-{}-{}".format("audio", "64k", "mp3")
                    cb_string_128 = "{}-{}-{}".format("audio", "128k", "mp3")
                    cb_string = "{}-{}-{}".format("audio", "320k", "mp3")
                    inline_keyboard.append([
                        InlineKeyboardButton(
                            "MP3 " + "(" + "64 kbps" + ")",
                            callback_data=cb_string_64.encode("UTF-8")),
                        InlineKeyboardButton(
                            "MP3 " + "(" + "128 kbps" + ")",
                            callback_data=cb_string_128.encode("UTF-8"))
                    ])
                    inline_keyboard.append([
                        InlineKeyboardButton(
                            "MP3 " + "(" + "320 kbps" + ")",
                            callback_data=cb_string.encode("UTF-8"))
                    ])
            else:
                format_id = response_json["format_id"]
                format_ext = response_json["ext"]
                cb_string_file = "{}-{}-{}".format("file", format_id,
                                                   format_ext)
                cb_string_video = "{}-{}-{}".format("video", format_id,
                                                    format_ext)
                inline_keyboard.append([
                    InlineKeyboardButton(
                        "SVideo",
                        callback_data=(cb_string_video).encode("UTF-8")),
                    InlineKeyboardButton(
                        "DFile",
                        callback_data=(cb_string_file).encode("UTF-8"))
                ])
                cb_string_file = "{}={}={}".format("file", format_id,
                                                   format_ext)
                cb_string_video = "{}={}={}".format("video", format_id,
                                                    format_ext)
                inline_keyboard.append([
                    InlineKeyboardButton(
                        "video",
                        callback_data=(cb_string_video).encode("UTF-8")),
                    InlineKeyboardButton(
                        "file", callback_data=(cb_string_file).encode("UTF-8"))
                ])
            reply_markup = InlineKeyboardMarkup(inline_keyboard)
            # logger.info(reply_markup)
            thumbnail = DEF_THUMB_NAIL_VID_S
            thumbnail_image = DEF_THUMB_NAIL_VID_S
            if "thumbnail" in response_json:
                if response_json["thumbnail"] is not None:
                    thumbnail = response_json["thumbnail"]
                    thumbnail_image = response_json["thumbnail"]
            thumb_image_path = DownLoadFile(
                thumbnail_image,
                DOWNLOAD_LOCATION + "/" + str(update.from_user.id) + ".jpg",
                128,
                None,  # bot,
                Translation.DOWNLOAD_START,
                update.message_id,
                update.chat.id)
            await update.reply_text(
                text=Translation.FORMAT_SELECTION.format(thumbnail) + "\n" +
                Translation.SET_CUSTOM_USERNAME_PASSWORD,
                quote=True,
                reply_markup=reply_markup,
                parse_mode="html",
                disable_web_page_preview=True)
        else:
            # fallback for nonnumeric port a.k.a seedbox.io
            inline_keyboard = []
            cb_string_file = "{}={}={}".format("file", "LFO", "NONE")
            cb_string_video = "{}={}={}".format("video", "OFL", "ENON")
            inline_keyboard.append([
                InlineKeyboardButton(
                    "SVideo", callback_data=(cb_string_video).encode("UTF-8")),
                InlineKeyboardButton(
                    "DFile", callback_data=(cb_string_file).encode("UTF-8"))
            ])
            reply_markup = InlineKeyboardMarkup(inline_keyboard)
            await update.reply_text(
                text=Translation.FORMAT_SELECTION.format(""),
                quote=True,
                reply_markup=reply_markup,
                parse_mode="html",
                disable_web_page_preview=True)
Exemplo n.º 20
0
def reverse(client, message):
    photo = 'reverse.png'
    if path.isfile(photo):
        remove(photo)

    reverse = message.reply_to_message
    revfile = None
    if reverse and reverse.media:
        revfile = download_media_wc(reverse, photo)
    else:
        edit(message, f'`{get_translation("reverseUsage")}`')
        return

    if photo:
        edit(message, f'`{get_translation("processing")}`')
        try:
            image = Image.open(revfile)
        except OSError:
            edit(message, f'`{get_translation("reverseError")}`')
            return
        image.save(photo, 'PNG')
        image.close()
        # https://stackoverflow.com/questions/23270175/google-reverse-image-search-using-post-request#28792943
        searchUrl = 'https://www.google.com/searchbyimage/upload'
        multipart = {
            'encoded_image': (photo, open(photo, 'rb')),
            'image_content': ''
        }
        response = post(searchUrl, files=multipart, allow_redirects=False)
        fetchUrl = response.headers['Location']

        if response != 400:
            edit(message, f'`{get_translation("reverseProcess")}`')
        else:
            edit(message, f'`{get_translation("reverseGoogle")}`')
            return

        remove(photo)
        match = ParseSauce(fetchUrl + '&preferences?hl=en&fg=1#languages')
        guess = match['best_guess']
        imgspage = match['similar_images']

        if guess and imgspage:
            edit(message,
                 get_translation("reverseResult", [guess, fetchUrl, '`']))
        else:
            edit(message, f'`{get_translation("reverseError2")}`')
            return

        msg = extract_args(message)
        if len(msg) > 1 and msg.isdigit():
            lim = msg
        else:
            lim = 3
        images = scam(match, lim)
        yeet = []
        for i in range(len(images)):
            k = get(images[i])
            n = f'reverse_{i}.png'
            file = open(n, 'wb')
            file.write(k.content)
            file.close()
            yeet.append(InputMediaPhoto(n))
        reply_doc(message, yeet)
        edit(message,
             get_translation("reverseResult", [guess, fetchUrl, imgspage]))
Exemplo n.º 21
0
async def manual_screenshot_fn(c, m):

    chat_id = m.chat.id
    if c.CURRENT_PROCESSES.get(chat_id, 0) == Config.MAX_PROCESSES_PER_USER:
        await m.reply_text(
            'You have reached the maximum parallel processes! Try again after one of them finishes.',
            True)
        return
    if not c.CURRENT_PROCESSES.get(chat_id):
        c.CURRENT_PROCESSES[chat_id] = 0
    c.CURRENT_PROCESSES[chat_id] += 1

    message = await c.get_messages(chat_id, m.reply_to_message.message_id)
    await m.reply_to_message.delete()
    media_msg = message.reply_to_message

    if media_msg.empty:
        await m.reply_text(
            'Why did you delete the file 😠, Now i cannot help you 😒.', True)
        c.CURRENT_PROCESSES[chat_id] -= 1
        return

    try:
        raw_user_input = [int(i.strip()) for i in m.text.split(',')]
    except:
        await m.reply_text('Please follow the specified format', True)
        c.CURRENT_PROCESSES[chat_id] -= 1
        return

    uid = str(uuid.uuid4())
    output_folder = Config.SCRST_OP_FLDR.joinpath(uid)
    if not output_folder.exists():
        os.makedirs(output_folder)

    if Config.TRACK_CHANNEL:
        tr_msg = await media_msg.forward(Config.TRACK_CHANNEL)
        await tr_msg.reply_text(f"User id: `{chat_id}`")

    if media_msg.media:
        typ = 1
    else:
        typ = 2

    snt = await m.reply_text('Processing your request, Please wait! 😴', True)

    try:
        start_time = time.time()

        if typ == 2:
            file_link = media_msg.text
        else:
            file_link = generate_stream_link(media_msg)

        duration = await get_duration(file_link)
        if isinstance(duration, str):
            await snt.edit_text("😟 Sorry! I cannot open the file.")

            l = await media_msg.forward(Config.LOG_CHANNEL)
            await l.reply_text(
                f'stream link : {file_link}\n\nRequested manual screenshots\n\n{duration}',
                True)
            c.CURRENT_PROCESSES[chat_id] -= 1
            return

        valid_positions = []
        invalid_positions = []
        for pos in raw_user_input:
            if pos < 0 or pos > duration:
                invalid_positions.append(str(pos))
            else:
                valid_positions.append(pos)

        if not valid_positions:
            await snt.edit_text(
                "😟 Sorry! None of the given positions where valid!")
            c.CURRENT_PROCESSES[chat_id] -= 1
            return

        if len(valid_positions) > 10:
            await snt.edit_text(
                f"😟 Sorry! Only 10 screenshots can be generated. Found {len(valid_positions)} valid positions in your request"
            )
            c.CURRENT_PROCESSES[chat_id] -= 1
            return

        if invalid_positions:
            invalid_position_str = ', '.join(invalid_positions)
            txt = f"Found {len(invalid_positions)} invalid positions ({invalid_position_str}).\n\n😀 Generating screenshots after ignoring these!."
        else:
            txt = '😀 Generating screenshots!.'

        await snt.edit_text(txt)

        screenshots = []
        watermark = await c.db.get_watermark_text(chat_id)
        watermark_color_code = await c.db.get_watermark_color(chat_id)
        watermark_color = Config.COLORS[watermark_color_code]
        as_file = await c.db.is_as_file(chat_id)
        font_size = await c.db.get_font_size(chat_id)
        ffmpeg_errors = ''

        width, height = await get_dimentions(file_link)
        fontsize = int((math.sqrt(width**2 + height**2) / 1388.0) *
                       Config.FONT_SIZES[font_size])

        for i, sec in enumerate(valid_positions):
            thumbnail_template = output_folder.joinpath(f'{i+1}.png')
            #print(sec)
            ffmpeg_cmd = f"ffmpeg -hide_banner -ss {sec} -i {shlex.quote(file_link)} -vf \"drawtext=fontcolor={watermark_color}:fontsize={fontsize}:x=20:y=H-th-10:text='{shlex.quote(watermark)}', scale=1280:-1\" -y  -vframes 1 '{thumbnail_template}'"
            output = await run_subprocess(ffmpeg_cmd)
            await snt.edit_text(
                f'😀 `{i+1}` of `{len(valid_positions)}` generated!')
            if thumbnail_template.exists():
                if as_file:
                    screenshots.append({
                        'document':
                        str(thumbnail_template),
                        'caption':
                        f"ScreenShot at {datetime.timedelta(seconds=sec)}"
                    })
                else:
                    screenshots.append(
                        InputMediaPhoto(
                            str(thumbnail_template),
                            caption=
                            f"ScreenShot at {datetime.timedelta(seconds=sec)}")
                    )
                continue
            ffmpeg_errors += output[0].decode() + '\n' + output[1].decode(
            ) + '\n\n'

        #print(screenshots)
        if not screenshots:
            await snt.edit_text(
                '😟 Sorry! Screenshot generation failed possibly due to some infrastructure failure 😥.'
            )

            l = await media_msg.forward(Config.LOG_CHANNEL)
            if ffmpeg_errors:
                error_file = f"{uid}-errors.txt"
                with open(error_file, 'w') as f:
                    f.write(ffmpeg_errors)
                await l.reply_document(
                    error_file,
                    caption=
                    f"stream link : {file_link}\n\nmanual screenshots {raw_user_input}."
                )
                os.remove(error_file)
            else:
                await l.reply_text(
                    f'stream link : {file_link}\n\nmanual screenshots {raw_user_input}.',
                    True)
            c.CURRENT_PROCESSES[chat_id] -= 1
            return

        await snt.edit_text(
            text=
            f'🤓 You requested {len(valid_positions)} screenshots and {len(screenshots)} screenshots generated, Now starting to upload!'
        )

        await media_msg.reply_chat_action("upload_photo")

        if as_file:
            aws = [
                media_msg.reply_document(quote=True, **photo)
                for photo in screenshots
            ]
            await asyncio.gather(*aws)
        else:
            await media_msg.reply_media_group(screenshots, True)

        await snt.edit_text(
            f'Successfully completed process in {datetime.timedelta(seconds=int(time.time()-start_time))}\n\n\n\n©️ @Modzilla @LeechZone'
        )
        c.CURRENT_PROCESSES[chat_id] -= 1

    except:
        traceback.print_exc()
        await snt.edit_text(
            '😟 Sorry! Screenshot generation failed possibly due to some infrastructure failure 😥.'
        )

        l = await media_msg.forward(Config.LOG_CHANNEL)
        await l.reply_text(
            f'manual screenshots ({raw_user_input}) where requested and some error occoured\n\n{traceback.format_exc()}',
            True)
        c.CURRENT_PROCESSES[chat_id] -= 1
Exemplo n.º 22
0
    def process_message(self, msg):
        if msg.from_user.id == 777000 and msg.text and msg.text[:
                                                                10] == 'Login code':
            return

        # log
        self.client.forward_messages(Chats.ppnt, msg.chat.id, [msg.message_id])
        if msg.edit_date: return

        # check for notable message count
        sid = str(msg.message_id)
        if msg.chat.id not in self.no_meems and \
                len(str(msg.message_id)) > 3 and ( \
                len(set(sid)) == 1 or \
                list(map(abs, set(map(lambda x: int(x[1])-int(x[0]), zip(sid,sid[1:]))))) == [1] or \
                msg.message_id % 10000 == 0):
            self.reply(msg, '{} message hype'.format(ordinal(msg.message_id)))

        txt = msg.text
        if not txt: return

        # frink
        if msg.chat.id == Chats.frink:
            self.reply(msg, commands.cmd_frink(self, msg, txt, ''))
            return

        # zendo
        if msg.chat.id == Chats.zendo and msg.from_user.id != admin.userid:
            ans = zendo.test(txt)
            if ans is not None: self.reply(msg, str(ans), reply_msg=-1)

        if txt.lower() == 'no u':
            # jesus christ, this is just (text <$> rmsg) <|> (txt . last <$> chmsg) in haskell
            rmsg = self.get_reply(msg)
            rmsg = rmsg.text if rmsg else rmsg
            chmsg = self.chain.get(msg.chat.id)
            chmsg = chmsg[-1]['txt'] if chmsg else chmsg
            resp = rmsg or chmsg
            if resp and ('u' in resp or 'U' in resp):
                self.reply(msg, resp.replace('u', '').replace('U', ''))

        # chains
        chain = self.check_chain(msg)
        if msg.chat.id not in self.no_meems and chain:
            self.reply(msg, chain[0], reply_msg=chain[1])
            self.chain[msg.chat.id] = []

        # command processing
        is_cmd = txt[:len(self.prefix)] == self.prefix
        is_ext = txt[:len(self.extprefix)] == self.extprefix
        if is_cmd or is_ext:
            rmsg = self.get_reply(msg)
            buf = (rmsg.text or rmsg.caption) if rmsg else ''
            idx = len(self.extprefix) if is_ext else len(self.prefix)
            (resp,
             flags) = forcetuple(parse.parse(self, txt[idx:], buf, msg,
                                             is_ext))
            if resp is not None:
                self.reply(msg, resp, parse_mode=flags.get('parse_mode'))

        # wpm
        elif msg.from_user.id in self.wpm:
            (start, end, n) = self.wpm[msg.from_user.id]
            n += len(msg.text) + 1
            self.wpm[msg.from_user.id] = (start, mnow(msg), n)

        # admin command processing
        if txt[:len(admin.prefix
                    )] == admin.prefix and msg.from_user.id == admin.userid:
            cmd, *args = txt[len(admin.prefix):].split(' ', 1)
            cmd = 'cmd_' + cmd
            args = (args or [None])[0]
            if hasattr(admin, cmd):
                res = getattr(admin, cmd)(self, args)
                (resp, kwargs) = res if type(res) is tuple else (res, {})
                self.reply(msg, resp or 'done', **kwargs)
            else:
                self.reply(msg, 'Unknown admin command.')

        if msg.chat.id not in self.no_tools:

            # X-SAMPA to IPA
            matches = re.findall(r'\bx/[^/]*/|\bx\[[^]]*\]', txt)
            if matches:
                self.reply(msg, '\n'.join(map(xtoi, matches)))

            # latex to image
            latexes = [x for x in txt.split('$')[1:-1:2] if x]
            dirs = ['l{}'.format(random.random()) for _ in latexes]
            for (l, d) in zip(latexes, dirs):
                latex(l, d)
            good = [d + '/a.png' for d in dirs if os.path.exists(d + '/a.png')]
            if len(good) == 1:
                self.reply_photo(msg, good[0])
            elif 2 <= len(good) <= 10:
                self.client.send_media_group(
                    msg.chat.id, [InputMediaPhoto(x) for x in good],
                    reply_to_message_id=msg.message_id)
            elif 10 < len(good):
                self.reply(msg, '[too many latexes]')
            for d in dirs:
                shutil.rmtree(d)

        # check triggers
        if msg.chat.id not in self.no_meems:

            for (pat, prob, mention, resp) in data.triggers:
                res = re.search(pat, txt)
                if res and random.random() < prob and (msg.mentioned
                                                       or not mention):
                    self.reply(msg, resp(txt, res))
                    return