mirror of
https://github.com/Redume/Shirino.git
synced 2025-07-02 02:00:55 +01:00
chore: autoformatting code and sorting import
This commit is contained in:
parent
cd40332ef6
commit
3d1bacf85b
11 changed files with 177 additions and 229 deletions
12
bot.py
12
bot.py
|
@ -1,13 +1,13 @@
|
|||
import yaml
|
||||
from aiogram import Bot
|
||||
from aiogram.client.default import DefaultBotProperties
|
||||
from aiogram.enums import ParseMode
|
||||
import yaml
|
||||
|
||||
from database.server import Database
|
||||
|
||||
db = Database('/data/shirino.db')
|
||||
config = yaml.safe_load(open('../config.yaml', 'r', encoding='utf-8'))
|
||||
db = Database("/data/shirino.db")
|
||||
config = yaml.safe_load(open("../config.yaml", "r", encoding="utf-8"))
|
||||
bot = Bot(
|
||||
token=config['telegram_token'],
|
||||
default=DefaultBotProperties(parse_mode=ParseMode.HTML)
|
||||
)
|
||||
token=config["telegram_token"],
|
||||
default=DefaultBotProperties(parse_mode=ParseMode.HTML),
|
||||
)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import hashlib
|
||||
|
||||
from aiogram import types, Router
|
||||
from aiogram import Router, types
|
||||
from aiogram.filters import Command
|
||||
|
||||
from bot import bot, db
|
||||
from functions.convert import Converter
|
||||
from functions.create_chart import create_chart
|
||||
from i18n.localization import I18n
|
||||
from utils.format_number import format_number
|
||||
from utils.inline_query import reply
|
||||
from i18n.localization import I18n
|
||||
|
||||
router = Router()
|
||||
i18n = I18n()
|
||||
|
@ -21,45 +21,38 @@ async def currency(query: types.InlineQuery) -> None:
|
|||
result_id = hashlib.md5(text.encode()).hexdigest()
|
||||
get_bot = await bot.get_me()
|
||||
|
||||
data = await db.fetch(
|
||||
'SELECT * FROM users WHERE user_id = ?',
|
||||
query.from_user.id
|
||||
)
|
||||
data = await db.fetch("SELECT * FROM users WHERE user_id = ?", query.from_user.id)
|
||||
|
||||
lang = data.get('lang')
|
||||
lang = data.get("lang")
|
||||
locale = i18n.get_locale(lang)
|
||||
|
||||
currency_example = locale["currency_example"].format(
|
||||
bot_username=get_bot.username
|
||||
)
|
||||
currency_example = locale["currency_example"].format(bot_username=get_bot.username)
|
||||
|
||||
if len(args) < 2:
|
||||
await reply(
|
||||
result_id,
|
||||
[(locale["error_not_enough_args"], currency_example, None, None)],
|
||||
query
|
||||
query,
|
||||
)
|
||||
return
|
||||
|
||||
conv = Converter()
|
||||
|
||||
from_currency, conv_currency = '', ''
|
||||
from_currency, conv_currency = "", ""
|
||||
|
||||
if len(args) == 3:
|
||||
try:
|
||||
conv.amount = float(args[0].replace(',', '.'))
|
||||
conv.amount = float(args[0].replace(",", "."))
|
||||
if conv.amount < 0:
|
||||
await reply(
|
||||
result_id,
|
||||
[(locale["error_negative_amount"], None, None)],
|
||||
query
|
||||
result_id, [(locale["error_negative_amount"], None, None)], query
|
||||
)
|
||||
return
|
||||
except ValueError:
|
||||
await reply(
|
||||
result_id,
|
||||
[(locale["error_invalid_number"], currency_example, None, None)],
|
||||
query
|
||||
query,
|
||||
)
|
||||
return
|
||||
from_currency = args[1]
|
||||
|
@ -81,21 +74,17 @@ async def currency(query: types.InlineQuery) -> None:
|
|||
try:
|
||||
await conv.convert()
|
||||
except RuntimeError:
|
||||
await reply(
|
||||
result_id,
|
||||
[(locale["error_currency_rate"], None, None)],
|
||||
query
|
||||
)
|
||||
await reply(result_id, [(locale["error_currency_rate"], None, None)], query)
|
||||
return
|
||||
|
||||
chart = None
|
||||
|
||||
if bool(data.get('chart', 1)):
|
||||
if bool(data.get("chart", 1)):
|
||||
chart = await create_chart(
|
||||
from_currency,
|
||||
conv_currency,
|
||||
data.get('chart_period', 'month'),
|
||||
data.get('chart_backend', 'matplotlib')
|
||||
data.get("chart_period", "month"),
|
||||
data.get("chart_backend", "matplotlib"),
|
||||
)
|
||||
|
||||
message = (
|
||||
|
@ -105,13 +94,6 @@ async def currency(query: types.InlineQuery) -> None:
|
|||
results = [(message, None, None)]
|
||||
|
||||
if chart:
|
||||
results.insert(
|
||||
0,
|
||||
(
|
||||
message,
|
||||
None,
|
||||
chart
|
||||
)
|
||||
)
|
||||
results.insert(0, (message, None, chart))
|
||||
|
||||
await reply(result_id, results, query)
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
from typing import Optional, Tuple, List
|
||||
import json
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from aiogram import Router, types
|
||||
from aiogram.filters import Command
|
||||
from aiogram.types import (
|
||||
InlineKeyboardMarkup,
|
||||
InlineKeyboardButton,
|
||||
CallbackQuery,
|
||||
)
|
||||
import json
|
||||
from aiogram.types import (CallbackQuery, InlineKeyboardButton,
|
||||
InlineKeyboardMarkup)
|
||||
|
||||
from bot import db
|
||||
from i18n.localization import I18n
|
||||
|
@ -31,17 +29,11 @@ PERIOD_OPTIONS: List[PeriodOption] = [
|
|||
|
||||
|
||||
async def get_user_locale(user_id: int) -> dict:
|
||||
data = await db.fetch(
|
||||
'SELECT lang FROM users WHERE user_id = $1', user_id
|
||||
)
|
||||
data = await db.fetch("SELECT lang FROM users WHERE user_id = $1", user_id)
|
||||
if not data:
|
||||
await db.insert(
|
||||
'INSERT INTO users (user_id) VALUES (?)', user_id
|
||||
)
|
||||
data = await db.fetch(
|
||||
'SELECT lang FROM users WHERE user_id = $1', user_id
|
||||
)
|
||||
return i18n.get_locale(data.get('lang', 'en'))
|
||||
await db.insert("INSERT INTO users (user_id) VALUES (?)", user_id)
|
||||
data = await db.fetch("SELECT lang FROM users WHERE user_id = $1", user_id)
|
||||
return i18n.get_locale(data.get("lang", "en"))
|
||||
|
||||
|
||||
def build_options_keyboard(
|
||||
|
@ -57,13 +49,9 @@ def build_options_keyboard(
|
|||
|
||||
for code, label_key in options:
|
||||
label = locale.get(label_key, label_key)
|
||||
text = (
|
||||
f"[X] {label}" if code == current_value else label
|
||||
)
|
||||
text = f"[X] {label}" if code == current_value else label
|
||||
row.append(
|
||||
InlineKeyboardButton(
|
||||
text=text, callback_data=f"{callback_prefix}_{code}"
|
||||
)
|
||||
InlineKeyboardButton(text=text, callback_data=f"{callback_prefix}_{code}")
|
||||
)
|
||||
if len(row) == buttons_per_row:
|
||||
buttons.append(row)
|
||||
|
@ -85,17 +73,11 @@ def build_options_keyboard(
|
|||
def get_chart_toggle_keyboard(
|
||||
chart_enabled: bool, locale: dict
|
||||
) -> InlineKeyboardMarkup:
|
||||
toggle_text = (
|
||||
locale["chart_disable"]
|
||||
if chart_enabled
|
||||
else locale["chart_enable"]
|
||||
)
|
||||
toggle_text = locale["chart_disable"] if chart_enabled else locale["chart_enable"]
|
||||
return InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
InlineKeyboardButton(
|
||||
text=toggle_text, callback_data="chart_toggle"
|
||||
),
|
||||
InlineKeyboardButton(text=toggle_text, callback_data="chart_toggle"),
|
||||
InlineKeyboardButton(
|
||||
text=locale["chart_period"],
|
||||
callback_data="chart_period",
|
||||
|
@ -134,9 +116,8 @@ async def safe_edit_message_text(
|
|||
new_text_clean = new_text.strip()
|
||||
|
||||
is_text_same = current_text == new_text_clean
|
||||
is_markup_same = (
|
||||
markup_to_json(message.reply_markup)
|
||||
== markup_to_json(new_reply_markup)
|
||||
is_markup_same = markup_to_json(message.reply_markup) == markup_to_json(
|
||||
new_reply_markup
|
||||
)
|
||||
|
||||
if is_text_same and is_markup_same:
|
||||
|
@ -168,20 +149,17 @@ async def settings_handler(message: types.Message):
|
|||
]
|
||||
)
|
||||
|
||||
await message.answer(
|
||||
locale["settings_title"],
|
||||
reply_markup=settings_keyboard
|
||||
)
|
||||
await message.answer(locale["settings_title"], reply_markup=settings_keyboard)
|
||||
|
||||
|
||||
@router.callback_query(lambda c: c.data == "setting_lang")
|
||||
async def show_language_menu(callback: CallbackQuery):
|
||||
locale = await get_user_locale(callback.from_user.id)
|
||||
|
||||
data = await db.fetch(
|
||||
'SELECT lang FROM users WHERE user_id = $1',
|
||||
callback.from_user.id
|
||||
"SELECT lang FROM users WHERE user_id = $1", callback.from_user.id
|
||||
)
|
||||
current_lang = data.get('lang', 'en')
|
||||
current_lang = data.get("lang", "en")
|
||||
|
||||
keyboard = build_options_keyboard(
|
||||
options=LANG_OPTIONS,
|
||||
|
@ -191,15 +169,14 @@ async def show_language_menu(callback: CallbackQuery):
|
|||
back_callback="back_to_settings",
|
||||
)
|
||||
|
||||
await safe_edit_message_text(
|
||||
callback, locale["choose_language"], keyboard
|
||||
)
|
||||
await safe_edit_message_text(callback, locale["choose_language"], keyboard)
|
||||
|
||||
|
||||
@router.callback_query(lambda c: c.data and c.data.startswith("lang_"))
|
||||
async def language_selected(callback: CallbackQuery):
|
||||
lang = callback.data.split("_")[1]
|
||||
await db.update(
|
||||
'UPDATE users SET lang = $1 WHERE user_id = $2',
|
||||
"UPDATE users SET lang = $1 WHERE user_id = $2",
|
||||
lang,
|
||||
callback.from_user.id,
|
||||
)
|
||||
|
@ -213,12 +190,8 @@ async def language_selected(callback: CallbackQuery):
|
|||
back_callback="back_to_settings",
|
||||
)
|
||||
|
||||
await safe_edit_message_text(
|
||||
callback, locale["choose_language"], keyboard
|
||||
)
|
||||
await callback.answer(
|
||||
locale["language_set"].format(lang=lang)
|
||||
)
|
||||
await safe_edit_message_text(callback, locale["choose_language"], keyboard)
|
||||
await callback.answer(locale["language_set"].format(lang=lang))
|
||||
|
||||
|
||||
@router.callback_query(lambda c: c.data == "setting_backend")
|
||||
|
@ -226,10 +199,10 @@ async def show_backend_settings(callback: CallbackQuery):
|
|||
locale = await get_user_locale(callback.from_user.id)
|
||||
|
||||
data = await db.fetch(
|
||||
'SELECT chart_backend, lang FROM users WHERE user_id = $1',
|
||||
callback.from_user.id
|
||||
"SELECT chart_backend, lang FROM users WHERE user_id = $1",
|
||||
callback.from_user.id,
|
||||
)
|
||||
current_backend = data['chart_backend']
|
||||
current_backend = data["chart_backend"]
|
||||
backend_label = locale.get(current_backend, current_backend)
|
||||
|
||||
keyboard = build_options_keyboard(
|
||||
|
@ -241,9 +214,7 @@ async def show_backend_settings(callback: CallbackQuery):
|
|||
)
|
||||
|
||||
await safe_edit_message_text(
|
||||
callback,
|
||||
f"{locale['choose_chart_backend']}",
|
||||
keyboard
|
||||
callback, f"{locale['choose_chart_backend']}", keyboard
|
||||
)
|
||||
|
||||
|
||||
|
@ -252,8 +223,9 @@ async def set_backend(callback: CallbackQuery):
|
|||
backend = callback.data.split("_")[1]
|
||||
|
||||
await db.update(
|
||||
'UPDATE users SET chart_backend = $1 WHERE user_id = $2',
|
||||
backend, callback.from_user.id
|
||||
"UPDATE users SET chart_backend = $1 WHERE user_id = $2",
|
||||
backend,
|
||||
callback.from_user.id,
|
||||
)
|
||||
|
||||
locale = await get_user_locale(callback.from_user.id)
|
||||
|
@ -266,11 +238,7 @@ async def set_backend(callback: CallbackQuery):
|
|||
back_callback="back_to_settings",
|
||||
)
|
||||
|
||||
await safe_edit_message_text(
|
||||
callback,
|
||||
locale["choose_chart_backend"],
|
||||
keyboard
|
||||
)
|
||||
await safe_edit_message_text(callback, locale["choose_chart_backend"], keyboard)
|
||||
|
||||
|
||||
@router.callback_query(lambda c: c.data == "back_to_settings")
|
||||
|
@ -304,7 +272,7 @@ async def back_to_settings(callback: CallbackQuery):
|
|||
@router.callback_query(lambda c: c.data == "setting_chart")
|
||||
async def show_chart_settings(callback: CallbackQuery):
|
||||
data = await db.fetch(
|
||||
'SELECT * FROM users WHERE user_id = $1',
|
||||
"SELECT * FROM users WHERE user_id = $1",
|
||||
callback.from_user.id,
|
||||
)
|
||||
lang = data.get("lang", "en")
|
||||
|
@ -313,9 +281,11 @@ async def show_chart_settings(callback: CallbackQuery):
|
|||
chart_status = bool(data.get("chart", 1))
|
||||
period = data.get("chart_period")
|
||||
|
||||
status_text = locale.get("enabled", "Enabled") \
|
||||
if chart_status \
|
||||
else locale.get("disabled", "Disabled")
|
||||
status_text = (
|
||||
locale.get("enabled", "Enabled")
|
||||
if chart_status
|
||||
else locale.get("disabled", "Disabled")
|
||||
)
|
||||
period_text = locale.get(period, period)
|
||||
|
||||
text = (
|
||||
|
@ -332,8 +302,7 @@ async def show_chart_settings(callback: CallbackQuery):
|
|||
@router.callback_query(lambda c: c.data == "chart_toggle")
|
||||
async def toggle_chart(callback: CallbackQuery):
|
||||
data = await db.fetch(
|
||||
'SELECT chart, lang FROM users WHERE user_id = $1',
|
||||
callback.from_user.id
|
||||
"SELECT chart, lang FROM users WHERE user_id = $1", callback.from_user.id
|
||||
)
|
||||
lang = data.get("lang", "en")
|
||||
locale = i18n.get_locale(lang)
|
||||
|
@ -342,8 +311,9 @@ async def toggle_chart(callback: CallbackQuery):
|
|||
new_status = not current_status
|
||||
|
||||
await db.update(
|
||||
'UPDATE users SET chart = $1 WHERE user_id = $2',
|
||||
new_status, callback.from_user.id
|
||||
"UPDATE users SET chart = $1 WHERE user_id = $2",
|
||||
new_status,
|
||||
callback.from_user.id,
|
||||
)
|
||||
|
||||
await show_chart_settings(callback)
|
||||
|
@ -352,8 +322,7 @@ async def toggle_chart(callback: CallbackQuery):
|
|||
@router.callback_query(lambda c: c.data == "chart_period")
|
||||
async def change_chart_period(callback: CallbackQuery):
|
||||
data = await db.fetch(
|
||||
'SELECT chart_period, lang FROM users WHERE user_id = $1',
|
||||
callback.from_user.id
|
||||
"SELECT chart_period, lang FROM users WHERE user_id = $1", callback.from_user.id
|
||||
)
|
||||
lang = data.get("lang", "en")
|
||||
locale = i18n.get_locale(lang)
|
||||
|
@ -368,19 +337,16 @@ async def change_chart_period(callback: CallbackQuery):
|
|||
back_callback="setting_chart",
|
||||
)
|
||||
|
||||
await safe_edit_message_text(
|
||||
callback,
|
||||
locale["choose_period"],
|
||||
keyboard
|
||||
)
|
||||
await safe_edit_message_text(callback, locale["choose_period"], keyboard)
|
||||
|
||||
|
||||
@router.callback_query(lambda c: c.data and c.data.startswith("period_"))
|
||||
async def set_chart_period(callback: CallbackQuery):
|
||||
period = callback.data.split("_")[1]
|
||||
await db.update(
|
||||
'UPDATE users SET chart_period = $1 WHERE user_id = $2',
|
||||
period, callback.from_user.id
|
||||
"UPDATE users SET chart_period = $1 WHERE user_id = $2",
|
||||
period,
|
||||
callback.from_user.id,
|
||||
)
|
||||
|
||||
locale = await get_user_locale(callback.from_user.id)
|
||||
|
@ -393,8 +359,4 @@ async def set_chart_period(callback: CallbackQuery):
|
|||
back_callback="setting_chart",
|
||||
)
|
||||
|
||||
await safe_edit_message_text(
|
||||
callback,
|
||||
locale["choose_period"],
|
||||
keyboard
|
||||
)
|
||||
await safe_edit_message_text(callback, locale["choose_period"], keyboard)
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
from aiogram import types, Router
|
||||
from aiogram.filters import CommandStart
|
||||
import re
|
||||
|
||||
from aiogram import Router, types
|
||||
from aiogram.filters import CommandStart
|
||||
|
||||
from bot import bot, db
|
||||
from i18n.localization import I18n
|
||||
|
||||
router = Router()
|
||||
i18n = I18n()
|
||||
|
||||
|
||||
def escape_md_v2(text: str) -> str:
|
||||
return re.sub(r'([_*\[\]()~#+\-=|{}.!\\])', r'\\\1', text)
|
||||
return re.sub(r"([_*\[\]()~#+\-=|{}.!\\])", r"\\\1", text)
|
||||
|
||||
|
||||
@router.message(CommandStart())
|
||||
async def start(message: types.Message) -> None:
|
||||
get_bot = await bot.get_me()
|
||||
|
||||
data = await db.fetch(
|
||||
'SELECT lang FROM users WHERE user_id = $1',
|
||||
message.from_user.id
|
||||
"SELECT lang FROM users WHERE user_id = $1", message.from_user.id
|
||||
)
|
||||
|
||||
locale = i18n.get_locale(data.get('lang'))
|
||||
locale = i18n.get_locale(data.get("lang"))
|
||||
|
||||
raw_template = locale.get("start_message")
|
||||
raw_text = raw_template.format(bot_username=get_bot.username)
|
||||
|
@ -28,15 +30,14 @@ async def start(message: types.Message) -> None:
|
|||
|
||||
button_text = locale.get("source_code_button")
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
|
||||
[types.InlineKeyboardButton(
|
||||
text=button_text,
|
||||
url="https://github.com/redume/shirino")
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=button_text, url="https://github.com/redume/shirino"
|
||||
)
|
||||
]
|
||||
]
|
||||
])
|
||||
|
||||
await message.reply(
|
||||
text,
|
||||
parse_mode="MarkdownV2",
|
||||
reply_markup=keyboard
|
||||
)
|
||||
|
||||
await message.reply(text, parse_mode="MarkdownV2", reply_markup=keyboard)
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import json
|
||||
from datetime import date, datetime
|
||||
from pathlib import Path
|
||||
from typing import Optional, List, Dict, Any
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import aiosqlite
|
||||
import yaml
|
||||
|
||||
config = yaml.safe_load(open('../config.yaml', 'r', encoding='utf-8'))
|
||||
config = yaml.safe_load(open("../config.yaml", "r", encoding="utf-8"))
|
||||
|
||||
|
||||
def custom_encoder(obj):
|
||||
"""
|
||||
|
@ -19,6 +20,7 @@ def custom_encoder(obj):
|
|||
return obj.isoformat()
|
||||
raise TypeError(f"Object of type {obj.__class__.__name__} is not JSON serializable")
|
||||
|
||||
|
||||
class Database:
|
||||
"""
|
||||
Asynchronous SQLite database handler using aiosqlite.
|
||||
|
@ -65,16 +67,15 @@ class Database:
|
|||
self.db_path = db_path
|
||||
self.conn: Optional[aiosqlite.Connection] = None
|
||||
|
||||
|
||||
async def _create_table(self) -> None:
|
||||
"""
|
||||
Create table from SQL file using aiosqlite.
|
||||
|
||||
Reads SQL commands from 'schemas/data.sql'
|
||||
Reads SQL commands from 'schemas/data.sql'
|
||||
and executes them as a script.
|
||||
"""
|
||||
sql_file = Path(__file__).parent / "schemas" / "data.sql"
|
||||
sql = sql_file.read_text(encoding='utf-8')
|
||||
sql = sql_file.read_text(encoding="utf-8")
|
||||
|
||||
async with self.conn.execute("BEGIN"):
|
||||
await self.conn.executescript(sql)
|
||||
|
@ -139,12 +140,13 @@ class Database:
|
|||
|
||||
async with self.conn.execute(query, args) as cursor:
|
||||
rows = await cursor.fetchall()
|
||||
return json.loads(
|
||||
json.dumps(
|
||||
[dict(row) for row in rows],
|
||||
default=custom_encoder
|
||||
return (
|
||||
json.loads(
|
||||
json.dumps([dict(row) for row in rows], default=custom_encoder)
|
||||
)
|
||||
) if rows else []
|
||||
if rows
|
||||
else []
|
||||
)
|
||||
|
||||
async def insert(self, query: str, *args) -> Dict[str, Any]:
|
||||
"""
|
||||
|
|
|
@ -9,14 +9,15 @@ import yaml
|
|||
|
||||
from utils.format_number import format_number
|
||||
|
||||
config = yaml.safe_load(open('../config.yaml', 'r', encoding='utf-8'))
|
||||
config = yaml.safe_load(open("../config.yaml", "r", encoding="utf-8"))
|
||||
|
||||
|
||||
class Converter:
|
||||
def __init__(self):
|
||||
self.amount: float = 1.0
|
||||
self.conv_amount: float = 0.0
|
||||
self.from_currency: str = ''
|
||||
self.conv_currency: str = ''
|
||||
self.from_currency: str = ""
|
||||
self.conv_currency: str = ""
|
||||
|
||||
async def convert(self) -> None:
|
||||
if not await self.kekkai():
|
||||
|
@ -27,68 +28,66 @@ class Converter:
|
|||
async def get_lastdate(self) -> str:
|
||||
async with aiohttp.ClientSession(
|
||||
timeout=aiohttp.ClientTimeout(total=3)
|
||||
) as session:
|
||||
async with session.get(
|
||||
f"{config['kekkai_instance']}/api/metadata"
|
||||
) as res:
|
||||
) as session:
|
||||
async with session.get(f"{config['kekkai_instance']}/api/metadata") as res:
|
||||
|
||||
if not HTTPStatus(res.status).is_success:
|
||||
return (
|
||||
datetime.now() - timedelta(1)
|
||||
).strftime('%Y-%m-%d')
|
||||
return (datetime.now() - timedelta(1)).strftime("%Y-%m-%d")
|
||||
|
||||
data = await res.json()
|
||||
|
||||
return data.get(
|
||||
'last_date',
|
||||
(datetime.now() - timedelta(1)).strftime('%Y-%m-%d')
|
||||
)
|
||||
"last_date", (datetime.now() - timedelta(1)).strftime("%Y-%m-%d")
|
||||
)
|
||||
|
||||
async def kekkai(self) -> bool:
|
||||
date = await self.get_lastdate()
|
||||
|
||||
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=3)) as session:
|
||||
async with session.get(f'{config['kekkai_instance']}/api/getRate/', params={
|
||||
'from_currency': self.from_currency,
|
||||
'conv_currency': self.conv_currency,
|
||||
'date': date,
|
||||
'conv_amount': self.amount
|
||||
}) as res:
|
||||
async with aiohttp.ClientSession(
|
||||
timeout=aiohttp.ClientTimeout(total=3)
|
||||
) as session:
|
||||
async with session.get(
|
||||
f"{config['kekkai_instance']}/api/getRate/",
|
||||
params={
|
||||
"from_currency": self.from_currency,
|
||||
"conv_currency": self.conv_currency,
|
||||
"date": date,
|
||||
"conv_amount": self.amount,
|
||||
},
|
||||
) as res:
|
||||
if not HTTPStatus(res.status).is_success:
|
||||
return False
|
||||
|
||||
data = await res.json()
|
||||
self.conv_amount = data.get('conv_amount', 0.0)
|
||||
self.conv_amount = data.get("conv_amount", 0.0)
|
||||
|
||||
return True
|
||||
|
||||
async def ddg(self) -> None:
|
||||
async with aiohttp.ClientSession(
|
||||
timeout=aiohttp.ClientTimeout(total=3)
|
||||
) as session:
|
||||
) as session:
|
||||
async with session.get(
|
||||
'https://duckduckgo.com/js/spice/currency/'
|
||||
f'{self.amount}/{self.from_currency}/{self.conv_currency}'
|
||||
) as res:
|
||||
"https://duckduckgo.com/js/spice/currency/"
|
||||
f"{self.amount}/{self.from_currency}/{self.conv_currency}"
|
||||
) as res:
|
||||
|
||||
data_text = await res.text()
|
||||
|
||||
data = json.loads(re.findall(r'\(\s*(.*)\s*\);$', data_text)[0])
|
||||
data = json.loads(re.findall(r"\(\s*(.*)\s*\);$", data_text)[0])
|
||||
|
||||
for key in ['terms', 'privacy', 'timestamp']:
|
||||
for key in ["terms", "privacy", "timestamp"]:
|
||||
data.pop(key, None)
|
||||
|
||||
if not data.get('to'):
|
||||
if not data.get("to"):
|
||||
raise RuntimeError(
|
||||
'Failed to get the exchange rate from DuckDuckGo'
|
||||
)
|
||||
"Failed to get the exchange rate from DuckDuckGo"
|
||||
)
|
||||
|
||||
conv = data.get('to')[0]
|
||||
conv_amount = conv.get('mid')
|
||||
conv = data.get("to")[0]
|
||||
conv_amount = conv.get("mid")
|
||||
|
||||
if conv_amount is None:
|
||||
raise RuntimeError(
|
||||
'Error when converting currency via DuckDuckGo'
|
||||
)
|
||||
raise RuntimeError("Error when converting currency via DuckDuckGo")
|
||||
|
||||
self.conv_amount = float(conv_amount)
|
||||
|
|
|
@ -1,35 +1,34 @@
|
|||
import time
|
||||
from http import HTTPStatus
|
||||
from urllib.parse import urlencode
|
||||
import time
|
||||
|
||||
import yaml
|
||||
import aiohttp
|
||||
import yaml
|
||||
|
||||
config = yaml.safe_load(open("../config.yaml", "r", encoding="utf-8"))
|
||||
|
||||
config = yaml.safe_load(open('../config.yaml', 'r', encoding='utf-8'))
|
||||
|
||||
async def create_chart(
|
||||
from_currency: str,
|
||||
conv_currency: str,
|
||||
period: str,
|
||||
backend: str) -> (str, None):
|
||||
from_currency: str, conv_currency: str, period: str, backend: str
|
||||
) -> (str, None):
|
||||
params = {
|
||||
'from_currency': from_currency,
|
||||
'conv_currency': conv_currency,
|
||||
'period': period,
|
||||
'backend': backend,
|
||||
'time_unique': time.time()
|
||||
"from_currency": from_currency,
|
||||
"conv_currency": conv_currency,
|
||||
"period": period,
|
||||
"backend": backend,
|
||||
"time_unique": time.time(),
|
||||
}
|
||||
|
||||
# Without time_unqiue Telegram does not want to load the image
|
||||
# Without time_unqiue Telegram does not want to load the image
|
||||
# Probably because of some kind of caching, but it's disabled.
|
||||
|
||||
|
||||
base_url = f'{config["kekkai_instance"]}/api/getChart/'
|
||||
query_string = urlencode(params)
|
||||
full_url = f'{base_url}?{query_string}'
|
||||
full_url = f"{base_url}?{query_string}"
|
||||
|
||||
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=3)) as session:
|
||||
async with session.get(full_url) as res:
|
||||
if not HTTPStatus(res.status).is_success:
|
||||
return None
|
||||
|
||||
|
||||
return full_url
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import yaml
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
class I18n:
|
||||
"""Load every YAML file in i18n/locales and let you pull out a single-language dict."""
|
||||
|
@ -21,7 +22,9 @@ class I18n:
|
|||
def get_locale(self, lang: str | None = None) -> dict:
|
||||
"""Return the whole dictionary for one language (fallback → default_lang)."""
|
||||
lang = (lang or self.default_lang).lower()[:2]
|
||||
lang_dict = self.translations.get(lang, self.translations.get(self.default_lang, {}))
|
||||
lang_dict = self.translations.get(
|
||||
lang, self.translations.get(self.default_lang, {})
|
||||
)
|
||||
|
||||
fallback_dict = self.translations.get(self.default_lang, {})
|
||||
merged_dict = {
|
||||
|
@ -29,4 +32,4 @@ class I18n:
|
|||
for key in set(lang_dict) | set(fallback_dict)
|
||||
}
|
||||
|
||||
return merged_dict
|
||||
return merged_dict
|
||||
|
|
28
main.py
28
main.py
|
@ -1,23 +1,23 @@
|
|||
import yaml
|
||||
|
||||
from aiogram import Dispatcher
|
||||
from aiogram.webhook.aiohttp_server import (SimpleRequestHandler,
|
||||
setup_application)
|
||||
from aiohttp import web
|
||||
|
||||
from aiogram import Dispatcher
|
||||
from aiogram.webhook.aiohttp_server import SimpleRequestHandler, setup_application
|
||||
|
||||
from commands import currency, start, settings
|
||||
from bot import bot, db
|
||||
from commands import currency, settings, start
|
||||
|
||||
config = yaml.safe_load(open("../config.yaml", "r", encoding="utf-8"))
|
||||
|
||||
config = yaml.safe_load(open('../config.yaml', 'r', encoding='utf-8'))
|
||||
|
||||
async def on_startup(bot: bot) -> None:
|
||||
await db.connect()
|
||||
await db._create_table()
|
||||
await bot.set_webhook(
|
||||
f"{config['webhook']['base_url']}{config['webhook']['path']}",
|
||||
secret_token=config['webhook']['secret_token'],
|
||||
allowed_updates=['inline_query', 'message', 'callback_query']
|
||||
)
|
||||
secret_token=config["webhook"]["secret_token"],
|
||||
allowed_updates=["inline_query", "message", "callback_query"],
|
||||
)
|
||||
|
||||
|
||||
async def on_shutdown():
|
||||
|
@ -36,16 +36,14 @@ def main() -> None:
|
|||
|
||||
app = web.Application()
|
||||
webhook_requests_handler = SimpleRequestHandler(
|
||||
dispatcher=dp,
|
||||
bot=bot,
|
||||
secret_token=config['webhook']['secret_token']
|
||||
dispatcher=dp, bot=bot, secret_token=config["webhook"]["secret_token"]
|
||||
)
|
||||
webhook_requests_handler.register(app, path=config['webhook']['path'])
|
||||
webhook_requests_handler.register(app, path=config["webhook"]["path"])
|
||||
|
||||
setup_application(app, dp, bot=bot)
|
||||
|
||||
web.run_app(app, host='0.0.0.0', port=443)
|
||||
web.run_app(app, host="0.0.0.0", port=443)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
from decimal import Decimal
|
||||
|
||||
|
||||
def format_number(number):
|
||||
number = Decimal(str(number))
|
||||
integer_part = number // 1
|
||||
fractional_part = number - integer_part
|
||||
|
||||
formatted_integer = '{:,.0f}'.format(integer_part).replace(',', ' ')
|
||||
formatted_integer = "{:,.0f}".format(integer_part).replace(",", " ")
|
||||
|
||||
if fractional_part == 0:
|
||||
return formatted_integer
|
||||
|
||||
fractional_str = f"{fractional_part:.30f}".split('.')[1]
|
||||
fractional_str = f"{fractional_part:.30f}".split(".")[1]
|
||||
first_non_zero = next(
|
||||
(i for i, char in enumerate(fractional_str) if char != '0'),
|
||||
len(fractional_str)
|
||||
)
|
||||
result_fractional = fractional_str[:first_non_zero + 3]
|
||||
result_fractional = result_fractional.rstrip('0')
|
||||
(i for i, char in enumerate(fractional_str) if char != "0"), len(fractional_str)
|
||||
)
|
||||
result_fractional = fractional_str[: first_non_zero + 3]
|
||||
result_fractional = result_fractional.rstrip("0")
|
||||
|
||||
if not result_fractional:
|
||||
return formatted_integer
|
||||
|
|
|
@ -2,8 +2,10 @@ import re
|
|||
|
||||
from aiogram import types
|
||||
|
||||
|
||||
def esc_md(text: str) -> str:
|
||||
return re.sub(r'([_*\[\]()~`>#+\-=|{}.!\\])', r'\\\1', text)
|
||||
return re.sub(r"([_*\[\]()~`>#+\-=|{}.!\\])", r"\\\1", text)
|
||||
|
||||
|
||||
async def reply(result_id: str, args: list, query: types.InlineQuery) -> None:
|
||||
if not args:
|
||||
|
@ -24,7 +26,7 @@ async def reply(result_id: str, args: list, query: types.InlineQuery) -> None:
|
|||
title=title,
|
||||
description=description,
|
||||
caption=esc_md(title),
|
||||
parse_mode="MarkdownV2"
|
||||
parse_mode="MarkdownV2",
|
||||
)
|
||||
else:
|
||||
article = types.InlineQueryResultArticle(
|
||||
|
|
Loading…
Add table
Reference in a new issue