diff --git a/src/actions/__init__.py b/src/actions/__init__.py index f348dddaf45ecb5db17972cd1a3067fcce910278..b21f0d4bc6088e4705286ba1eca0669bac92b4ff 100644 --- a/src/actions/__init__.py +++ b/src/actions/__init__.py @@ -6,7 +6,7 @@ def finish(): importlib.import_module("src.actions.basic") importlib.import_module("src.actions.fun") importlib.import_module("src.actions.replies") - importlib.import_module("src.actions.converter") + importlib.import_module("src.actions.converters") importlib.import_module("src.actions.package_indexes") importlib.import_module("src.actions.search_engines") importlib.import_module("src.actions.speller") diff --git a/src/actions/converters/__init__.py b/src/actions/converters/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d58e0ded53e30b2bba5c597cf6d5c9655f851607 --- /dev/null +++ b/src/actions/converters/__init__.py @@ -0,0 +1,3 @@ +from . import crypto_currency, currency + +__all__ = ["currency", "crypto_currency"] diff --git a/src/actions/converters/crypto_currency.py b/src/actions/converters/crypto_currency.py new file mode 100644 index 0000000000000000000000000000000000000000..eb3c74d4838d5d2e0ed9545b364964090831ec4c --- /dev/null +++ b/src/actions/converters/crypto_currency.py @@ -0,0 +1,101 @@ +import logging +import re +import urllib.parse +from decimal import Decimal + +import httpx +from src.config import config +from src.utils.converters import get_info_from_group +from src.utils.responses import mark_unread +from telethon import events + +logger = logging.getLogger(__name__) + +TARGET_CURRENCY = "rub" + +CURRENCY_MAPPING = { + "btc": "bitcoin", + "биткоин": "bitcoin", + "биткоина": "bitcoin", + "биткоинов": "bitcoin", + "биток": "bitcoin", + "битка": "bitcoin", + "битков": "bitcoin", + "etc": "ethereum-classic", + "ефир": "ethereum-classic", + "Ñфир": "ethereum-classic", + "b5k": "bitcoin-5000", + "bvk": "bitcoin-5000", + "ltc": "litecoin", + "лайт": "litecoin", +} + +SUPPORTED_CURRENCIES = ["bitcoin", "ethereum-classic", "litecoin", "bitcoin-5000"] + +CANONICAL_NAME = { + "bitcoin": "BTC", + "ethereum-classic": "ETC", + "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/src/actions/converter.py b/src/actions/converters/currency.py similarity index 76% rename from src/actions/converter.py rename to src/actions/converters/currency.py index 745b26f43539251524b09f5111518d6783b87aec..b3b12aabe7006ab77661601495d8e8bf31be7259 100644 --- a/src/actions/converter.py +++ b/src/actions/converters/currency.py @@ -4,6 +4,7 @@ from decimal import Decimal import httpx from src.config import config +from src.utils.converters import get_info_from_group from src.utils.responses import mark_unread from telethon import events @@ -27,6 +28,7 @@ CURRENCY_MAPPING = { "йены": "JPY", "йен": "JPY", "вон": "KRW", + "воны": "KRW", "франк": "CHF", "франка": "CHF", "франков": "CHF", @@ -63,7 +65,9 @@ CURRENCY_PATTERN = ( @config.telegram_client.on( - events.NewMessage(pattern=re.compile(f".*{CURRENCY_PATTERN}.*", re.IGNORECASE)) + events.NewMessage( + pattern=re.compile(f".*{CURRENCY_PATTERN}.*", re.IGNORECASE | re.DOTALL) + ) ) @mark_unread async def replace_currency(event): @@ -71,28 +75,24 @@ async def replace_currency(event): current_currency = await f.get("https://www.cbr-xml-daily.ru/daily_json.js") response_json = current_currency.json() currencies = response_json["Valute"] - groups = re.findall(CURRENCY_PATTERN, event.message.message) + groups = re.findall(CURRENCY_PATTERN, event.message.message, re.IGNORECASE) response = "**ПолагаÑÑÑŒ на текущий ÐºÑƒÑ€Ñ Ð²Ð°Ð»ÑŽÑ‚ могу Ñказать Ñледующее:**\n\n" currency_mapper = [] for group in groups: - scientific = False - name = group[3] - if name in CURRENCY_MAPPING: - name = CURRENCY_MAPPING[name] - val = Decimal(str(group[0]).replace(",", ".")) - val_id = f"{val} {name}" - if len(f"{val:.2f}") > 30: - scientific = True + c_info = get_info_from_group(group, CURRENCY_MAPPING) + val_id = f"{c_info.val} {c_info.name}" new_val = ( - val - * Decimal(currencies[name]["Value"]) - / Decimal(currencies[name]["Nominal"]) + c_info.val + * Decimal(currencies[c_info.name]["Value"]) + / Decimal(currencies[c_info.name]["Nominal"]) ) if val_id not in currency_mapper: - if scientific: - response += f"`{val} {name} = {new_val.to_eng_string()} RUB`\n" + if c_info.sci: + response += ( + f"`{c_info.val} {c_info.name} = {new_val.to_eng_string()} RUB`\n" + ) else: - response += f"`{val} {name} = {new_val:.2f} RUB`\n" + response += f"`{c_info.val} {c_info.name} = {new_val:.2f} RUB`\n" currency_mapper.append(val_id) await event.reply(response) diff --git a/src/utils/converters.py b/src/utils/converters.py new file mode 100644 index 0000000000000000000000000000000000000000..a6b2096f289ecd7901d82dc1677faef67331fc1a --- /dev/null +++ b/src/utils/converters.py @@ -0,0 +1,15 @@ +import logging +from collections import namedtuple +from decimal import Decimal + +CapturedCurrency = namedtuple("CapturedCurrency", ("name", "source_val", "val", "sci")) + + +def get_info_from_group(capture_group, mapping): + logging.debug(f"Parsing group: {capture_group}") + name = capture_group[3] + if name.lower() in mapping: + name = mapping[name.lower()] + str_val = capture_group[0].replace(",", ".") + val = Decimal(str_val) + return CapturedCurrency(name, str_val, val, len(f"{val:.2f}") > 30)