diff --git a/clockblocker_bot/actions/__init__.py b/clockblocker_bot/actions/__init__.py index efbca514d88f20424b149ab8c3ed51dc8bb4996c..f8e9a89dcccca87e9de3d8e9dcd9fa230fb8ee5b 100644 --- a/clockblocker_bot/actions/__init__.py +++ b/clockblocker_bot/actions/__init__.py @@ -4,4 +4,5 @@ import logging def finish(): importlib.import_module("clockblocker_bot.actions.basic") + importlib.import_module("clockblocker_bot.actions.converters") logging.info("All actions loaded") diff --git a/clockblocker_bot/actions/basic.py b/clockblocker_bot/actions/basic.py index d59240fb83a18e9454f6ccbed53eb87e3ce49bcb..39ac5011a21a65152bdd91584e1ad9a7b115c83a 100644 --- a/clockblocker_bot/actions/basic.py +++ b/clockblocker_bot/actions/basic.py @@ -79,17 +79,17 @@ async def reboot_advice(event: events.NewMessage.Event): async def smile_back(event: events.NewMessage.Event): return await event.respond(event.message.message) -@config.telegram_client.on(events.NewMessage(pattern=r".*(З|зумеры).*")) -@mark_unread -@clean_up_policy -async def zoomers(event: events.NewMessage.Event): - return await event.respond("уууу тиктокеры") +# @config.telegram_client.on(events.NewMessage(pattern=r".*(З|зумеры).*")) +# @mark_unread +# @clean_up_policy +# async def zoomers(event: events.NewMessage.Event): +# return await event.respond("уууу тиктокеры") -@config.telegram_client.on(events.NewMessage(pattern=r".*(З|зумер).*")) -@mark_unread -@clean_up_policy -async def zoomer(event: events.NewMessage.Event): - return await event.respond("уууу тиктокер") +# @config.telegram_client.on(events.NewMessage(pattern=r".*(З|зумер).*")) +# @mark_unread +# @clean_up_policy +# async def zoomer(event: events.NewMessage.Event): +# return await event.respond("уууу тиктокер") @config.telegram_client.on(events.NewMessage(pattern=".*@all.*", forwards=False)) @@ -111,12 +111,12 @@ async def mention_all(event: events.NewMessage.Event): await event.respond(" ".join(participants)) -@config.telegram_client.on(events.NewMessage(pattern=r".*(З|зумер).*")) -@mark_unread -@clean_up_policy -@beware_the_croud_policy(config.telegram_client) -async def zoomer(event: events.NewMessage.Event): - return await event.respond("уууу тиктокер") +# @config.telegram_client.on(events.NewMessage(pattern=r".*(З|зумер).*")) +# @mark_unread +# @clean_up_policy +# @beware_the_croud_policy(config.telegram_client) +# async def zoomer(event: events.NewMessage.Event): +# return await event.respond("уууу тиктокер") @config.telegram_client.on(events.NewMessage(pattern=r"@chat_id")) @@ -129,8 +129,8 @@ async def get_chat_id(event: events.NewMessage.Event): return await event.respond(f'{chat.id}') -@config.telegram_client.on(events.NewMessage(pattern=r"eval(.*)")) +@config.telegram_client.on(events.NewMessage(pattern=r"eval .*")) @only_clockblocker async def custom_eval(event: events.NewMessage.Event): - content = event.message.message[5:-1] - return await event.respond(str(eval(content))) \ No newline at end of file + content = event.message.message[5:] + return await event.respond(f"`{str(eval(content))}`") \ No newline at end of file diff --git a/clockblocker_bot/actions/converters/__init__.py b/clockblocker_bot/actions/converters/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..07f0d20f0d52b372669cb56d7bfa2dd525cf3b28 --- /dev/null +++ b/clockblocker_bot/actions/converters/__init__.py @@ -0,0 +1,3 @@ +from . import crypto, currency + +__all__ = ["currency", "crypto"] diff --git a/clockblocker_bot/actions/converters/crypto.py b/clockblocker_bot/actions/converters/crypto.py new file mode 100644 index 0000000000000000000000000000000000000000..0b87d3e973cc8308b93dc3f0d2b2fc83709a0a81 --- /dev/null +++ b/clockblocker_bot/actions/converters/crypto.py @@ -0,0 +1,103 @@ +import logging +import re +import urllib.parse +from decimal import Decimal + +import httpx +from telethon import events + +from clockblocker_bot.config import config +from clockblocker_bot.utils.converters import get_info_from_group +from clockblocker_bot.utils.decorators import mark_unread + +logger = logging.getLogger(__name__) + +TARGET_CURRENCY = "rub" + +CURRENCY_MAPPING = { + "btc": "bitcoin", + "биткоин": "bitcoin", + "биткоина": "bitcoin", + "биткоинов": "bitcoin", + "биток": "bitcoin", + "битка": "bitcoin", + "битков": "bitcoin", + "etc": "ethereum", + "ефир": "ethereum", + "Ñфир": "ethereum", + "Ñфира": "ethereum", + "b5k": "bitcoin-5000", + "bvk": "bitcoin-5000", + "ltc": "litecoin", + "лайт": "litecoin", +} + +SUPPORTED_CURRENCIES = ["bitcoin", "ethereum", "litecoin", "bitcoin-5000"] + +CANONICAL_NAME = { + "bitcoin": "BTC", + "ethereum": "ETH", + "litecoin": "LTC", + "bitcoin-5000": "BVK", +} + +CURRENCY_PATTERN = ( + rf"\s*((\d+)([\.,]\d+)?)\s+(" + rf"{'|'.join(SUPPORTED_CURRENCIES + list(CURRENCY_MAPPING.keys()))})" +) + + +@config.telegram_client.on( + events.NewMessage( + pattern=re.compile(f".*{CURRENCY_PATTERN}.*", re.IGNORECASE | re.DOTALL) + ) +) +@mark_unread +async def replace_crypto_currency(event: events.NewMessage.Event): + groups = re.findall(CURRENCY_PATTERN, event.message.message, re.IGNORECASE) + response = "**ПолагаÑÑÑŒ на текущий ÐºÑƒÑ€Ñ Ð²Ð°Ð»ÑŽÑ‚ могу Ñказать Ñледующее:**\n\n" + currency_mapper = [] + groups_info = list(map(lambda x: get_info_from_group(x, CURRENCY_MAPPING), groups)) + names = ",".join(set([x.name for x in groups_info])) + query_params = {"ids": names, "vs_currencies": TARGET_CURRENCY} + async with httpx.AsyncClient() as client: + query = urllib.parse.urlencode(query_params) + resp = await client.get( + f"https://api.coingecko.com/api/v3/simple/price?{query}" + ) + currency_exchange = resp.json() + logger.debug(currency_exchange) + for currency in groups_info: + val_id = f"{currency.val} {currency.name}" + logger.debug(val_id) + new_val = ( + Decimal(currency_exchange[currency.name][TARGET_CURRENCY]) * currency.val + ) + if val_id not in currency_mapper: + canon_name = CANONICAL_NAME[currency.name] + if currency.sci: + response += ( + f"`{currency.source_val} {canon_name}" + f" = {new_val.to_eng_string()} RUB`\n" + ) + else: + response += ( + f"`{currency.source_val} {canon_name} = {new_val:.2f} RUB`\n" + ) + currency_mapper.append(val_id) + + await event.reply(response) + + +@config.telegram_client.on(events.NewMessage(pattern="^.scc$")) +@mark_unread +async def supported_currencies(event): + async with httpx.AsyncClient() as client: + response = await client.get("https://api.coingecko.com/api/v3/coins/list") + raw_json = response.json() + currencies = {x["id"]: x for x in raw_json} + response = "**Поддерживаемые курÑÑ‹ криптовалют**:\n\n" + for curr in SUPPORTED_CURRENCIES: + response += f"{CANONICAL_NAME[curr]} ({currencies[curr.lower()]['name']})\n" + + await event.reply(response) diff --git a/clockblocker_bot/actions/converters/currency.py b/clockblocker_bot/actions/converters/currency.py new file mode 100644 index 0000000000000000000000000000000000000000..241dba00e07b6921afe017d9c1c96b56664f64b0 --- /dev/null +++ b/clockblocker_bot/actions/converters/currency.py @@ -0,0 +1,126 @@ +import logging +import re +from decimal import Decimal + +import httpx +from telethon import events + +from clockblocker_bot.config import config +from clockblocker_bot.utils.converters import get_info_from_group +from clockblocker_bot.utils.decorators import mark_unread + +logger = logging.getLogger(__name__) + +CURRENCY_MAPPING = { + "фунт": "GBP", + "фунта": "GBP", + "фунтов": "GBP", + "бакÑ": "USD", + "бакÑа": "USD", + "бакÑов": "USD", + "доллар": "USD", + "доллара": "USD", + "долларов": "USD", + "евро": "EUR", + "иена": "JPY", + "иены": "JPY", + "иен": "JPY", + "йена": "JPY", + "йены": "JPY", + "йен": "JPY", + "вон": "KRW", + "воны": "KRW", + "франк": "CHF", + "франка": "CHF", + "франков": "CHF", + "крона": "SEK", + "кроны": "SEK", + "крон": "SEK", + "юань": "CNY", + "юанÑ": "CNY", + "юаней": "CNY", + "гривна": "UAH", + "гривны": "UAH", + "гривен": "UAH", + "грiвен": "UAH", +} + +SUPPORTED_CURRENCIES = [ + "GBP", + "HUF", + "USD", + "EUR", + "CNY", + "NOK", + "UAH", + "SEK", + "CHF", + "KRW", + "JPY", +] + +MEMES = { + (40, "UAH"): "штанi", + (300, "USD"): "один поход в Dungeon", + (20, "USD"): "boy next door", +} + +CURRENCY_PATTERN = ( + rf"\s*((\d+)([\.,]\d+)?)\s+(" + rf"{'|'.join(SUPPORTED_CURRENCIES + list(CURRENCY_MAPPING.keys()))})" +) + + +@config.telegram_client.on( + events.NewMessage( + pattern=re.compile(f".*{CURRENCY_PATTERN}.*", re.IGNORECASE | re.DOTALL) + ) +) +@mark_unread +async def replace_currency(event): + async with httpx.AsyncClient() as f: + current_currency = await f.get("https://www.cbr-xml-daily.ru/daily_json.js") + chat = await event.get_chat() + memes_allowed = str(chat.id) not in set(config.excluded_chats) + response_json = current_currency.json() + currencies = response_json["Valute"] + groups = re.findall(CURRENCY_PATTERN, event.message.message, re.IGNORECASE) + response = "**ПолагаÑÑÑŒ на текущий ÐºÑƒÑ€Ñ Ð²Ð°Ð»ÑŽÑ‚ могу Ñказать Ñледующее:**\n\n" + currency_mapper = [] + for group in groups: + c_info = get_info_from_group(group, CURRENCY_MAPPING) + val_id = f"{c_info.val} {c_info.name}" + meme_extra = MEMES.get((int(c_info.val), c_info.name)) + new_val = ( + c_info.val + * Decimal(currencies[c_info.name]["Value"]) + / Decimal(currencies[c_info.name]["Nominal"]) + ) + meme = "" + if meme_extra and memes_allowed: + meme = f"{meme_extra} или " + + if val_id not in currency_mapper: + if c_info.sci: + response += ( + f"`{c_info.val} {c_info.name} = " + f"{meme}{new_val.to_eng_string()} RUB`\n" + ) + else: + response += f"`{c_info.val} {c_info.name} = {meme}{new_val:.2f} RUB`\n" + currency_mapper.append(val_id) + await event.reply(response) + + +@config.telegram_client.on(events.NewMessage(pattern="^.sc$")) +@mark_unread +async def supported_currencies(event): + async with httpx.AsyncClient() as f: + current_currency = await f.get("https://www.cbr-xml-daily.ru/daily_json.js") + response_json = current_currency.json() + currencies = response_json["Valute"] + response = "**Поддерживаемые курÑÑ‹ валют**:\n\n" + for curr in SUPPORTED_CURRENCIES: + response += f"{curr} ({currencies[curr]['Name']})\n" + + await event.reply(response) diff --git a/clockblocker_bot/config.py b/clockblocker_bot/config.py index b44d0d43fe4df49f42aebf69814dda987a5f5023..ca92432a148a992dfd6e4ea312c0514cd67c2b4f 100644 --- a/clockblocker_bot/config.py +++ b/clockblocker_bot/config.py @@ -1,6 +1,7 @@ from pydantic import BaseSettings from pydantic.fields import Field from telethon import TelegramClient +from typing import List __all__ = ["config"] @@ -21,6 +22,8 @@ class Config(BaseSettings): flask_port: str = Field(name="flask_port", default="8080", env="FLASK_PORT") telegram_client: TelegramClient = None + + excluded_chats: List[str] = Field([], env="BOT_EXCLUDED_CHATS") class Config: env_file = '.env'