all repos — gif-escarbot @ 527ce6fa9a2f40fdbbe3942582a8ef47f9bb7781

Earthbound Café's custom delivery bot with other cool utilities built-in.

escarbot/replace.py (view raw)

  1from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton
  2from telegram.constants import ParseMode
  3from escarbot.config import INLINE_SEP, FEEDBACK_TIMEOUT
  4import logging, re, json
  5from asyncio import sleep
  6logger = logging.getLogger(__name__)
  7
  8re_flags = re.I | re.M
  9
 10def get_human_readable(input_str: str, indicator: str, offset: int = 0) -> (int, int):
 11    try:
 12        result = int(input_str[offset:].split(indicator, maxsplit=1)[0])
 13        return result, len(str(result)) + len(indicator)
 14    except ValueError:
 15        return 0, 0
 16
 17youtube_timestamp_regex = re.compile(r"(?:&|\?)t=(\d*h?\d*m?\d*s?)", re_flags)
 18def youtube_timestamp(input_str: str) -> str:
 19    result = youtube_timestamp_regex.findall(input_str)
 20    try:
 21        input_string = result[0]
 22        seconds = int(input_string)
 23        hours, remainder = divmod(seconds, 3600)
 24        minutes, seconds = divmod(remainder, 60)
 25    except IndexError: # nothing to parse
 26        return ""
 27    except ValueError: # human-readable number
 28        hours, offset = get_human_readable(input_string, "h")
 29        minutes, offset = get_human_readable(input_string, "m", offset)
 30        seconds, offset = get_human_readable(input_string, "s", offset)
 31
 32    if hours == 0:
 33        return '{}:{:02}'.format(minutes, seconds)
 34    return '{}:{:02}:{:02}'.format(hours, minutes, seconds)
 35
 36replacers = [
 37    {
 38        "regex": re.compile(r"(?:(?:https?:)?\/\/)?(?:(?:www|m)\.)?(?:(?:youtube(?:-nocookie)?\.com|youtu.be))(?:\/(?:[\w\-]+\?v=|embed\/|live\/|v\/)?)([\w\-]+)(\S+)?", re_flags),
 39        "becomes": "https://y.outube.duckdns.org/{}",
 40        "timestamp": youtube_timestamp
 41    },
 42    {
 43        "regex": re.compile(r"(?:https?:\/\/)?(?:www\.)?twitter\.com\/(?:#!\/)?(.*)\/status(?:es)?\/([^\/\?\s]+)", re_flags),
 44        "becomes": "https://fxtwitter.com/{}/status/{}",
 45    },
 46    {
 47        "regex": re.compile(r"(?:https?:\/\/)?(?:www\.)?x\.com\/(?:#!\/)?(.*)\/status(?:es)?\/([^\/\?\s]+)", re_flags),
 48        "becomes": "https://fixupx.com/{}/status/{}",
 49    },
 50    {
 51        "regex": re.compile(r"(?:https?:\/\/)?(?:www\.)?instagram\.com\/((?:reel)|p)\/([A-Za-z0-9_]{11})[\/\?\w=&]*", re_flags),
 52        "becomes": "https://ddinstagram.com/{}/{}",
 53    },
 54]
 55
 56link_message = "Da {}[\.]({}) {}"
 57
 58def get_callback_data(feedback: bool) -> str:
 59    payload = { "feedback": feedback }
 60    return "feedback" + INLINE_SEP + json.dumps(payload)
 61
 62def get_message_markup() -> InlineKeyboardMarkup:
 63    buttons = [
 64        [
 65            InlineKeyboardButton(text="", callback_data=get_callback_data(True)),
 66            InlineKeyboardButton(text="", callback_data=get_callback_data(False)),
 67        ]
 68    ]
 69    return InlineKeyboardMarkup(buttons)
 70
 71def format_template(template: str, regex_result) -> str:
 72    result_type = type(regex_result)
 73    if result_type is str:
 74        return template.format(regex_result)
 75    elif result_type is tuple or result_type is list:
 76        return template.format(*regex_result)
 77    elif result_type is dict:
 78        return template.format(**regex_result)
 79    else:
 80        return ""
 81
 82def parse_text(message: str) -> list:
 83    output = []
 84    for site in replacers:
 85        regex = site["regex"]
 86        res = regex.findall(message)
 87        for r in res:
 88            link = format_template(site["becomes"], r)
 89            
 90            try:
 91                timestamp = site["timestamp"](r[-1])
 92            except KeyError:
 93                timestamp = None
 94
 95            output.append([link, timestamp])
 96    return output
 97
 98async def replace(update: Update, _) -> None:
 99    try:
100        links = parse_text(update.message.text)
101    except TypeError:
102        links = parse_text(update.message.caption)
103
104    for link in links:
105        logger.info(link)
106
107        user = update.effective_user.mention_markdown_v2(update.effective_user.name)
108        text = link_message.format(user, link[0], link[1])
109        message = await update.effective_chat.send_message(text, parse_mode=ParseMode.MARKDOWN_V2)
110        await sleep(FEEDBACK_TIMEOUT)
111        await message.edit_reply_markup(reply_markup=get_message_markup())
112
113async def feedback(update: Update, _, data_json: str) -> None:
114    data = json.loads(data_json)
115
116    if data["feedback"]:
117        await update.callback_query.answer("Bene!")
118        await update.effective_message.edit_reply_markup()
119        return
120
121    await update.callback_query.answer("Ci ho provato...")
122    await update.effective_message.delete()
123    return