/
TetroReks
/
GnomeBot2.0
Обзор
Документация
Войти
/
TetroReks
/
GnomeBot2.0
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
reference.py
190 строк
8 KB
TetroReks
create: parsers.py, update: advisor.py, reference.py, requirements.txt
19 фев 2026, 01:25
Верифицирован
19 фев 2026, 01:25
9b55b34
Код
Авторство
О чём код?
import aiohttp import asyncio from telegram import Update from telegram.ext import ContextTypes from config import OPEN5E_BASE, OPEN5E_HEADERS from utils import translate_text, transliterate # Кэш для результатов API CACHE = {} async def fetch_from_dnd_su(search: str, category: str): """Парсинг next.dnd.su (категории: spells, monsters, items)""" # Транслитерация русского названия в английское en_name = transliterate(search) url = f"https://next.dnd.su/{category}/{en_name}/" async with aiohttp.ClientSession() as session: async with session.get(url, headers={"User-Agent": "Mozilla/5.0"}) as resp: if resp.status != 200: return None html = await resp.text() # Тут нужен парсинг BeautifulSoup # ... async def fetch_api(endpoint: str, search: str): """Универсальный запрос к Open5e API""" cache_key = f"{endpoint}:{search}" if cache_key in CACHE: return CACHE[cache_key] # Преобразуем русский запрос в английский (транслит) en_search = transliterate(search) url = f"{OPEN5E_BASE}{endpoint}/?search={en_search}&document__key=srd-2024" async with aiohttp.ClientSession() as sess: async with sess.get(url, headers=OPEN5E_HEADERS) as resp: if resp.status != 200: return None data = await resp.json() results = data.get('results', []) if not results: # Попробуем без транслита (оригинальный запрос, если латиница) if search != en_search: url2 = f"{OPEN5E_BASE}{endpoint}/?search={search}&document__key=srd-2024" async with sess.get(url2, headers=OPEN5E_HEADERS) as resp2: if resp2.status == 200: data2 = await resp2.json() results = data2.get('results', []) # Возвращаем первый результат, если он есть if results: CACHE[cache_key] = results[0] return results[0] else: CACHE[cache_key] = None return None async def spell_lookup(update: Update, context: ContextTypes.DEFAULT_TYPE): """Поиск заклинания: /spell [название]""" if not context.args: await update.message.reply_text("🔮 Пример: /spell огненный шар") return query = " ".join(context.args) spell_data = await fetch_api("spells", query) if not spell_data: await update.message.reply_text(f"Заклинание «{query}» не найдено в SRD 2024.") return # Извлекаем поля name_en = spell_data['name'] level = spell_data['level'] school = spell_data['school']['name'] casting_time = spell_data['casting_time'] duration = spell_data['duration'] range_text = spell_data['range_text'] components = [] if spell_data.get('verbal'): components.append('В') if spell_data.get('somatic'): components.append('С') if spell_data.get('material'): components.append('М') components_str = ', '.join(components) if components else '—' desc = spell_data.get('desc', '') higher_level = spell_data.get('higher_level', '') # Переводим name_ru = await translate_text(name_en) school_ru = await translate_text(school) casting_time_ru = await translate_text(casting_time) duration_ru = await translate_text(duration) range_ru = await translate_text(range_text) desc_ru = await translate_text(desc[:1000]) # лимит higher_ru = await translate_text(higher_level[:500]) if higher_level else '' level_text = 'заговор' if level == 0 else f'{level} уровень' response = ( f"🔮 *{name_ru}* ({level_text}, {school_ru})\n" f"⏱ Время: {casting_time_ru}\n" f"⏳ Длительность: {duration_ru}\n" f"📏 Дистанция: {range_ru}\n" f"🧪 Компоненты: {components_str}\n\n" f"{desc_ru}\n" ) if higher_ru: response += f"\n*На больших уровнях:* {higher_ru}\n" response += "\n_Источник: SRD 2024_" await update.message.reply_text(response, parse_mode='Markdown') async def monster_lookup(update: Update, context: ContextTypes.DEFAULT_TYPE): if not context.args: await update.message.reply_text("👹 Пример: /monster дракон") return query = " ".join(context.args) monster = await fetch_api("creatures", query) if not monster: await update.message.reply_text(f"Монстр «{query}» не найден.") return # Проверяем наличие всех нужных полей, если чего-то нет — сообщаем required_keys = ['name', 'size', 'type', 'alignment', 'armor_class', 'hit_points', 'strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma'] missing = [key for key in required_keys if key not in monster] if missing: await update.message.reply_text(f"По запросу «{query}» получены неполные данные. Попробуйте уточнить название (например, на английском).") return name_en = monster['name'] size = monster['size'] type_ = monster['type'] alignment = monster['alignment'] ac = monster['armor_class'] hp = monster['hit_points'] speed = monster.get('speed', {}) if isinstance(speed, dict): speed = speed.get('walk', '—') else: speed = speed if speed else '—' str_ = monster['strength'] dex = monster['dexterity'] con = monster['constitution'] int_ = monster['intelligence'] wis = monster['wisdom'] cha = monster['charisma'] # Переводим name_ru = await translate_text(name_en) size_ru = await translate_text(size) type_ru = await translate_text(type_) alignment_ru = await translate_text(alignment) response = ( f"👹 *{name_ru}* ({size_ru}, {type_ru})\n" f"⚖️ Мировоззрение: {alignment_ru}\n" f"🛡️ КД: {ac} | ❤️ ХП: {hp}\n" f"🏃 Скорость: {speed}\n\n" f"Сила: {str_} | Лов: {dex} | Вын: {con}\n" f"Инт: {int_} | Мдр: {wis} | Хар: {cha}\n" ) await update.message.reply_text(response, parse_mode='Markdown') async def item_lookup(update: Update, context: ContextTypes.DEFAULT_TYPE): if not context.args: await update.message.reply_text("⚔️ Пример: /item длинный меч") return query = " ".join(context.args) item = await fetch_api("items", query) if not item: await update.message.reply_text(f"Предмет «{query}» не найден.") return # Проверяем наличие обязательных полей if 'name' not in item or 'type' not in item: await update.message.reply_text(f"По запросу «{query}» получены неполные данные. Попробуйте уточнить название.") return name_en = item['name'] type_ = item['type'] cost = item.get('cost', '—') weight = item.get('weight', '—') desc = item.get('desc', '') name_ru = await translate_text(name_en) type_ru = await translate_text(type_) desc_ru = await translate_text(desc[:500]) response = ( f"⚔️ *{name_ru}* ({type_ru})\n" f"💰 Стоимость: {cost} | ⚖️ Вес: {weight}\n\n" f"{desc_ru}\n" )