예제 #1
0
파일: payment.py 프로젝트: kmacprt/pdfbot
def receive_custom_amount(update, context):
    _ = set_lang(update, context)
    if _(CUSTOM_MSG) in update.effective_message.reply_to_message.text:
        try:
            amount = round(float(update.effective_message.text))
            if amount <= 0:
                raise ValueError

            send_payment_invoice(update, context, amount=amount)
        except ValueError:
            _ = set_lang(update, context)
            update.effective_message.reply_text(
                _('The amount you sent is invalid, try again. {}').format(
                    _(CUSTOM_MSG)),
                reply_markup=ForceReply())
예제 #2
0
def send_payment_invoice(
    update: Update,
    context: CallbackContext,
    query: CallbackQuery,
):
    if query is None:
        message = update.effective_message
        label = message.text
    else:
        message = query.message
        label = query.data

    _ = set_lang(update, context)
    chat_id = message.chat_id
    title = _("Support PDF Bot")
    description = _("Say thanks to PDF Bot and help keep it running")

    price = PAYMENT_DICT[label]
    prices = [LabeledPrice(re.sub(r"\s\(.*", "", label), price * 100)]

    context.bot.send_invoice(
        chat_id,
        title,
        description,
        PAYMENT_PAYLOAD,
        STRIPE_TOKEN,
        CURRENCY,
        prices,
        max_tip_amount=1000,
        suggested_tip_amounts=[100, 300, 500, 1000],
    )
예제 #3
0
def check_photo(update: Update, context: CallbackContext) -> int:
    message = update.effective_message
    message.chat.send_action(ChatAction.TYPING)
    photo_file = check_photo_file(update, context)
    user_id = message.from_user.id
    photo_locks[user_id].acquire()

    if photo_file is None:
        if not context.user_data[PHOTO_IDS]:
            result = ask_first_photo(update, context)
        else:
            result = ask_next_photo(update, context)
    else:
        _ = set_lang(update, context)
        try:
            file_name = photo_file.file_name
        except AttributeError:
            file_name = _("File name unavailable")

        context.user_data[PHOTO_IDS].append(photo_file.file_id)
        context.user_data[PHOTO_NAMES].append(file_name)
        result = ask_next_photo(update, context)

    photo_locks[user_id].release()

    return result
예제 #4
0
def process_photo_task(update, context):
    """
    Receive the task and perform the task on the photo
    Args:
        update: the update object
        context: the context object

    Returns:
        The variable indicating the conversation has ended
    """
    if not check_user_data(update, context, PHOTO_ID):
        return ConversationHandler.END

    _ = set_lang(update, context)
    user_data = context.user_data
    file_id = user_data[PHOTO_ID]

    if update.effective_message.text == _(BEAUTIFY):
        process_photo(update, context, [file_id], is_beautify=True)
    else:
        process_photo(update, context, [file_id], is_beautify=False)

    if user_data[PHOTO_ID] == file_id:
        del user_data[PHOTO_ID]

    return ConversationHandler.END
예제 #5
0
def send_result_photos(update, context, dir_name, task):
    _ = set_lang(update, context)
    message = update.effective_message

    if message.text == _(PHOTOS):
        for photo_name in sorted(os.listdir(dir_name)):
            photo_path = os.path.join(dir_name, photo_name)
            if os.path.getsize(photo_path) <= MAX_FILESIZE_UPLOAD:
                try:
                    message.chat.send_action(ChatAction.UPLOAD_PHOTO)
                    message.reply_photo(open(photo_path, "rb"))
                except BadRequest:
                    message.chat.send_action(ChatAction.UPLOAD_DOCUMENT)
                    message.reply_document(open(photo_path, "rb"))

        message.reply_text(
            _("See above for all your photos"),
            reply_markup=get_support_markup(update, context),
        )
        update_stats(update, task)
    else:
        # Compress the directory of photos
        shutil.make_archive(dir_name, "zip", dir_name)

        # Send result file
        send_result_file(update, context, f"{dir_name}.zip", task)
예제 #6
0
def get_pdf_photos(update, context):
    if not check_user_data(update, context, PDF_INFO):
        return ConversationHandler.END

    _ = set_lang(update, context)
    update.effective_message.reply_text(
        _("Extracting all the photos in your PDF file"),
        reply_markup=ReplyKeyboardRemove(),
    )

    with tempfile.NamedTemporaryFile() as tf:
        user_data = context.user_data
        file_id, file_name = user_data[PDF_INFO]
        pdf_file = context.bot.get_file(file_id)
        pdf_file.download(custom_path=tf.name)

        with tempfile.TemporaryDirectory() as tmp_dir_name:
            dir_name = os.path.join(tmp_dir_name, "Photos_In_PDF")
            os.mkdir(dir_name)
            if not write_photos_in_pdf(tf.name, dir_name, file_name):
                update.effective_message.reply_text(
                    _("Something went wrong, try again"))
            else:
                if not os.listdir(dir_name):
                    update.effective_message.reply_text(
                        _("I couldn't find any photos in your PDF file"))
                else:
                    send_result_photos(update, context, dir_name, "get_photos")

    # Clean up memory
    if user_data[PDF_INFO] == file_id:
        del user_data[PDF_INFO]

    return ConversationHandler.END
예제 #7
0
def ask_split_range(update, context):
    _ = set_lang(update, context)
    update.effective_message.reply_text(
        _(
            "Send me the range of pages that you'll like to keep\n\n"
            "<b>General usage</b>\n"
            "<code>:      all pages</code>\n"
            "<code>22     just the 23rd page</code>\n"
            "<code>0:3    the first three pages</code>\n"
            "<code>:3     the first three pages</code>\n"
            "<code>5:     from the 6th page onwards</code>\n"
            "<code>-1     last page only</code>\n"
            "<code>:-1    all pages but the last page</code>\n"
            "<code>-2     second last page only</code>\n"
            "<code>-2:    last two pages</code>\n"
            "<code>-3:-1  third and second last pages only</code>\n\n"
            "<b>Advanced usage</b>\n"
            "<code>::2    pages 0 2 4 ... to the end</code>\n"
            "<code>1:10:2 pages 1 3 5 7 9</code>\n"
            "<code>::-1   all pages in reversed order</code>\n"
            "<code>3:0:-1 pages 3 2 1 but not 0</code>\n"
            "<code>2::-1  pages 2 1 0</code>"
        ),
        parse_mode=ParseMode.HTML,
        reply_markup=get_back_markup(update, context),
    )

    return WAIT_SPLIT_RANGE
예제 #8
0
def url_to_pdf(update: Update, context: CallbackContext):
    _ = set_lang(update, context)
    message = update.effective_message
    url = message.text
    user_data = context.user_data

    if user_data is not None and URLS in user_data and url in user_data[URLS]:
        message.reply_text(
            _("You've sent me this web page already and I'm still converting it")
        )
    else:
        message.reply_text(_("Converting your web page into a PDF file"))
        if URLS in user_data:
            user_data[URLS].add(url)
        else:
            user_data[URLS] = {url}

        with tempfile.TemporaryDirectory() as dir_name:
            out_fn = os.path.join(dir_name, f"{urlparse(url).netloc}.pdf")
            try:
                HTML(url=url).write_pdf(out_fn)
                send_result_file(update, context, out_fn, "url")
            except URLFetchingError:
                message.reply_text(_("Unable to reach your web page"))

        user_data[URLS].remove(url)
예제 #9
0
def add_ocr_to_pdf(update, context):
    if not check_user_data(update, context, PDF_INFO):
        return ConversationHandler.END

    _ = set_lang(update, context)
    update.effective_message.reply_text(
        _("Adding an OCR text layer to your PDF file"),
        reply_markup=ReplyKeyboardRemove(),
    )

    with tempfile.NamedTemporaryFile() as tf:
        user_data = context.user_data
        file_id, file_name = user_data[PDF_INFO]
        pdf_file = context.bot.get_file(file_id)
        pdf_file.download(custom_path=tf.name)

        with tempfile.TemporaryDirectory() as dir_name:
            out_fn = os.path.join(dir_name,
                                  f"OCR_{os.path.splitext(file_name)[0]}.pdf")
            try:
                # logging.getLogger("ocrmypdf").setLevel(logging.WARNING)
                ocrmypdf.ocr(tf.name, out_fn, deskew=True, progress_bar=False)
                send_result_file(update, context, out_fn, "ocr")
            except PriorOcrFoundError:
                update.effective_message.reply_text(
                    _("Your PDF file already has a text layer"))

    # Clean up memory
    if user_data[PDF_INFO] == file_id:
        del user_data[PDF_INFO]

    return ConversationHandler.END
예제 #10
0
파일: utils.py 프로젝트: kmacprt/pdfbot
def check_pdf(update, context, send_msg=True):
    """
    Validate the PDF file
    Args:
        update: the update object
        context: the context object
        send_msg: the bool indicating to send a message or not

    Returns:
        The variable indicating the validation result
    """
    pdf_status = PDF_OK
    message = update.effective_message
    pdf_file = message.document
    _ = set_lang(update, context)

    if not pdf_file.mime_type.endswith("pdf"):
        pdf_status = PDF_INVALID_FORMAT
        if send_msg:
            message.reply_text(
                _("The file you sent is not a PDF file, try again"))
    elif pdf_file.file_size >= MAX_FILESIZE_DOWNLOAD:
        pdf_status = PDF_TOO_LARGE
        if send_msg:
            message.reply_text(
                _("The PDF file you sent is too large for me to download\n\n"
                  "I've cancelled your action"))

    return pdf_status
예제 #11
0
파일: text.py 프로젝트: kmacprt/pdfbot
def send_pdf_text(update, context, pdf_texts, is_file, out_fn):
    _ = set_lang(update, context)
    message = update.effective_message

    if pdf_texts:
        if is_file:
            with open(out_fn, "w") as f:
                f.write("\n".join(pdf_texts))

            send_result_file(update, context, out_fn, "get_text")
        else:
            msg_text = ""
            for pdf_text in pdf_texts:
                if len(msg_text) + len(pdf_text) + 1 > MAX_MESSAGE_LENGTH:
                    message.reply_text(msg_text.strip())
                    msg_text = ""

                msg_text += f" {pdf_text}"

            if msg_text:
                message.reply_text(msg_text.strip())

            message.reply_text(
                _("*See above for all the text in your PDF file*"),
                parse_mode=ParseMode.MARKDOWN,
            )
    else:
        message.reply_text(_("I couldn't find any text in your PDF file"))
예제 #12
0
파일: text.py 프로젝트: kmacprt/pdfbot
def get_pdf_text(update, context, is_file):
    if not check_user_data(update, context, PDF_INFO):
        return ConversationHandler.END

    _ = set_lang(update, context)
    update.effective_message.reply_text(
        _("Extracting text from your PDF file"), reply_markup=ReplyKeyboardRemove()
    )

    with tempfile.NamedTemporaryFile() as tf:
        user_data = context.user_data
        file_id, file_name = user_data[PDF_INFO]
        pdf_file = context.bot.get_file(file_id)
        pdf_file.download(custom_path=tf.name)

        with tempfile.TemporaryDirectory() as dir_name:
            tmp_text = tempfile.TemporaryFile()
            with open(tf.name, "rb") as f:
                extract_text_to_fp(f, tmp_text)

            tmp_text.seek(0)
            pdf_texts = textwrap.wrap(tmp_text.read().decode("utf-8").strip())
            out_fn = os.path.join(dir_name, f"{os.path.splitext(file_name)[0]}.txt")
            send_pdf_text(update, context, pdf_texts, is_file, out_fn)

    # Clean up memory
    if user_data[PDF_INFO] == file_id:
        del user_data[PDF_INFO]

    return ConversationHandler.END
예제 #13
0
def check_user_data(
    update: Update, context: CallbackContext, key: str, lock: Lock = None
) -> bool:
    """
    Check if the specified key exists in user_data
    Args:
        update: the update object
        context: the context object
        key: the string of key

    Returns:
        The boolean indicating if the key exists or not
    """
    data_ok = True
    if lock is not None:
        lock.acquire()

    if key not in context.user_data:
        data_ok = False
        _ = set_lang(update, context)
        update.effective_message.reply_text(_("Something went wrong, start over again"))

    if lock is not None:
        lock.release()

    return data_ok
예제 #14
0
def cancel(update, context):
    _ = set_lang(update, context)
    update.effective_message.reply_text(
        _("Action cancelled"), reply_markup=ReplyKeyboardRemove()
    )

    return ConversationHandler.END
예제 #15
0
def check_text(update: Update, context: CallbackContext) -> int:
    update.effective_message.chat.send_action(ChatAction.TYPING)
    _ = set_lang(update, context)
    if update.effective_message.text == _(CANCEL):
        return cancel(update, context)
    else:
        return receive_feedback(update, context)
예제 #16
0
def check_doc_task(update, context):
    _ = set_lang(update, context)
    text = update.effective_message.text

    if text == _(CROP):
        return ask_crop_type(update, context)
    elif text == _(DECRYPT):
        return ask_decrypt_pw(update, context)
    elif text == _(ENCRYPT):
        return ask_encrypt_pw(update, context)
    elif text in [_(EXTRACT_PHOTO), _(TO_PHOTO)]:
        return ask_photo_results_type(update, context)
    elif text == _(PREVIEW):
        return get_pdf_preview(update, context)
    elif text == _(RENAME):
        return ask_pdf_new_name(update, context)
    elif text == _(ROTATE):
        return ask_rotate_degree(update, context)
    elif text in [_(SCALE)]:
        return ask_scale_type(update, context)
    elif text == _(SPLIT):
        return ask_split_range(update, context)
    elif text == _(EXTRACT_TEXT):
        return ask_text_type(update, context)
    elif text == OCR:
        return add_ocr_to_pdf(update, context)
    elif text == COMPRESS:
        return compress_pdf(update, context)
    elif text == _(CANCEL):
        return cancel_without_async(update, context)
예제 #17
0
def send_support_options(update: Update,
                         context: CallbackContext,
                         query: CallbackQuery = None):
    update.effective_message.reply_chat_action(ChatAction.TYPING)
    _ = set_lang(update, context, query)
    keyboard = [
        [
            InlineKeyboardButton(_(THANKS), callback_data=THANKS),
            InlineKeyboardButton(_(COFFEE), callback_data=COFFEE),
        ],
        [
            InlineKeyboardButton(_(BEER), callback_data=BEER),
            InlineKeyboardButton(_(MEAL), callback_data=MEAL),
        ],
        [InlineKeyboardButton(_("Developer"), "https://t.me/Amani_m_h_d")],
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    text = _("Select how you want to support PDF Bot")

    if query is None:
        user_id = update.effective_message.from_user.id
    else:
        user_id = query.from_user.id

    context.bot.send_message(user_id, text, reply_markup=reply_markup)
예제 #18
0
def send_payment_invoice(update, context, query=None, amount=None):
    if query is None:
        message = update.effective_message
        label = message.text
    else:
        message = query.message
        label = query.data

    _ = set_lang(update, context)
    chat_id = message.chat_id
    title = _("Support PDF Bot")
    description = _("Say thanks to PDF Bot and help keep it running")

    if amount is None:
        price = PAYMENT_DICT[label]
    else:
        label = CUSTOM
        price = amount

    prices = [LabeledPrice(re.sub(r"\s\(.*", "", label), price * 100)]

    context.bot.send_invoice(
        chat_id,
        title,
        description,
        PAYMENT_PAYLOAD,
        STRIPE_TOKEN,
        PAYMENT_PARA,
        CURRENCY,
        prices,
    )
예제 #19
0
def compare_pdf(update, context):
    _ = set_lang(update, context)
    message = update.effective_message
    message.reply_text(_("Comparing your PDF files"),
                       reply_markup=ReplyKeyboardRemove())

    with tempfile.NamedTemporaryFile() as tf1, tempfile.NamedTemporaryFile(
    ) as tf2:
        # Download PDF files
        user_data = context.user_data
        first_file_id = user_data[COMPARE_ID]
        first_file = context.bot.get_file(first_file_id)
        first_file.download(custom_path=tf1.name)
        second_file = message.document.get_file()
        second_file.download(custom_path=tf2.name)

        try:
            with tempfile.TemporaryDirectory() as dir_name:
                out_fn = os.path.join(dir_name, "Differences.png")
                pdf_diff.main(files=[tf1.name, tf2.name], out_file=out_fn)
                send_result_file(update, context, out_fn, "compare")
        except NoDifferenceError:
            message.reply_text(
                _("There are no differences in text between your PDF files"))

    # Clean up memory and files
    if user_data[COMPARE_ID] == first_file_id:
        del user_data[COMPARE_ID]

    return ConversationHandler.END
예제 #20
0
def send_support_options(update, context, query=None):
    _ = set_lang(update, context, query)
    keyboard = [
        [
            InlineKeyboardButton(_(THANKS), callback_data=THANKS),
            InlineKeyboardButton(_(COFFEE), callback_data=COFFEE),
        ],
        [
            InlineKeyboardButton(_(BEER), callback_data=BEER),
            InlineKeyboardButton(_(MEAL), callback_data=MEAL),
        ],
        [InlineKeyboardButton(_(CUSTOM), callback_data=CUSTOM)],
        [
            InlineKeyboardButton(_("Help translate PDF Bot"),
                                 "https://crwd.in/telegram-pdf-bot")
        ],
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    text = _("Select how you want to support PDF Bot")

    if query is None:
        user_id = update.effective_message.from_user.id
    else:
        user_id = query.from_user.id

    context.bot.send_message(user_id, text, reply_markup=reply_markup)
예제 #21
0
def ask_scale_value(update, context, ask_percent=True):
    _ = set_lang(update, context)
    message = update.effective_message
    reply_markup = get_back_markup(update, context)

    if message.text == _(BY_PERCENT) or ask_percent:
        message.reply_text(
            _("Send me the scaling factors for the horizontal and vertical axes\n\n"
              "2 will double the axis and 0.5 will halve the axis\n\n"
              "*Example: 2 0.5* (this will double the horizontal axis and halve the vertical axis)"
              ),
            reply_markup=reply_markup,
            parse_mode=ParseMode.MARKDOWN,
        )

        return WAIT_SCALE_PERCENT
    else:
        message.reply_text(
            _("Send me the width and height\n\n"
              "*Example: 150 200* (this will set the width to 150 and height to 200)"
              ),
            reply_markup=reply_markup,
            parse_mode=ParseMode.MARKDOWN,
        )

        return WAIT_SCALE_DIMENSION
예제 #22
0
def ask_crop_value(update, context):
    _ = set_lang(update, context)
    message = update.effective_message
    reply_markup = ReplyKeyboardMarkup([[_(BACK)]],
                                       one_time_keyboard=True,
                                       resize_keyboard=True)

    if message.text == _(BY_PERCENT):
        message.reply_text(
            _("Send me a number between {} and {}. This is the percentage of margin space to "
              "retain between the content in your PDF file and the page").
            format(MIN_PERCENT, MAX_PERCENT),
            reply_markup=reply_markup,
        )

        return WAIT_CROP_PERCENT
    else:
        message.reply_text(
            _("Send me a number that you'll like to adjust the margin size. "
              "Positive numbers will decrease the margin size and negative numbers will increase it"
              ),
            reply_markup=reply_markup,
        )

        return WAIT_CROP_OFFSET
예제 #23
0
def crop_pdf(update, context, percent=None, offset=None):
    _ = set_lang(update, context)
    update.effective_message.reply_text(_("Cropping your PDF file"),
                                        reply_markup=ReplyKeyboardRemove())

    with tempfile.NamedTemporaryFile(suffix=".pdf") as tf:
        user_data = context.user_data
        file_id, file_name = user_data[PDF_INFO]
        pdf_file = context.bot.get_file(file_id)
        pdf_file.download(custom_path=tf.name)

        with tempfile.TemporaryDirectory() as dir_name:
            out_fn = os.path.join(dir_name, f"Cropped_{file_name}")
            command = f'pdf-crop-margins -o "{out_fn}" "{tf.name}"'

            if percent is not None:
                command += f" -p {percent}"
            else:
                command += f" -a {offset}"

            if run_cmd(command):
                send_result_file(update, context, out_fn, "crop")
            else:
                update.effective_message.reply_text(
                    _("Something went wrong, try again"))

    # Clean up memory
    if user_data[PDF_INFO] == file_id:
        del user_data[PDF_INFO]

    return ConversationHandler.END
예제 #24
0
def precheckout_check(update, context):
    _ = set_lang(update, context)
    query = update.pre_checkout_query

    if query.invoice_payload != PAYMENT_PAYLOAD:
        query.answer(ok=False, error_message=_("Something went wrong"))
    else:
        query.answer(ok=True)
예제 #25
0
def check_crop_task(update, context):
    _ = set_lang(update, context)
    text = update.effective_message.text

    if text in [_(BY_PERCENT), _(BY_SIZE)]:
        return ask_crop_value(update, context)
    elif text == _(BACK):
        return ask_doc_task(update, context)
예제 #26
0
def check_text(update, context):
    _ = set_lang(update, context)
    text = update.effective_message.text

    if text == _(BACK):
        return ask_first_doc(update, context)
    elif text == _(CANCEL):
        return cancel(update, context)
예제 #27
0
파일: watermark.py 프로젝트: kmacprt/pdfbot
def check_text(update, context):
    _ = set_lang(update, context)
    text = update.effective_message.text

    if text == _(BACK):
        return ask_src_doc(update, context)
    elif text == _(CANCEL):
        return cancel_without_async(update, context)
예제 #28
0
def check_crop_size(update, context):
    _ = set_lang(update, context)
    message = update.effective_message

    if message.text == _(BACK):
        return ask_crop_type(update, context)

    try:
        offset = float(update.effective_message.text)
    except ValueError:
        _ = set_lang(update, context)
        update.effective_message.reply_text(
            _("The number is invalid, try again"))

        return WAIT_CROP_OFFSET

    return crop_pdf(update, context, offset=offset)
예제 #29
0
def check_to_photos_task(update, context):
    _ = set_lang(update, context)
    text = update.effective_message.text

    if text in [_(PHOTOS), _(COMPRESSED)]:
        return pdf_to_photos(update, context)
    elif text == _(BACK):
        return ask_doc_task(update, context)
예제 #30
0
def check_scale_task(update, context):
    _ = set_lang(update, context)
    text = update.effective_message.text

    if text in [_(BY_PERCENT), _(TO_DIMENSIONS)]:
        return ask_scale_value(update, context)
    elif text == _(BACK):
        return ask_doc_task(update, context)