import os import logging import httpx from aiogram import Bot, Dispatcher, types, F from aiogram.filters import Command from aiogram.utils.markdown import hbold, hlink # Настройки TOKEN = os.getenv("TELEGRAM_TOKEN") API_URL = os.getenv("VNDB_API_URL", "https://api.vndb.org/kana") # Логирование logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) bot = Bot(token=TOKEN, parse_mode="HTML") dp = Dispatcher() # Хелпер для запросов к VNDB async def fetch_vndb(endpoint: str, filters: list, fields: str): payload = {"filters": filters, "fields": fields} async with httpx.AsyncClient(timeout=10.0) as client: try: response = await client.post(f"{API_URL}/{endpoint}", json=payload) if response.status_code != 200: logger.error(f"VNDB Error {response.status_code}: {response.text}") return None return response.json().get("results", []) except Exception as e: logger.error(f"Connection error: {e}") return None # Команды /start и /help @dp.message(Command("start", "help")) async def cmd_start(message: types.Message): help_text = ( "🤖 VNDB Bot\n\n" "Поиск:\n" "/search [name] - поиск новеллы\n" "/char [name] - поиск персонажа\n" "/release [name] - поиск релизов\n\n" "Инфо по ID:\n" "/vn [id] (напр. v17)\n" "/char_id [id] (напр. c1)\n" "/rel_id [id] (напр. r1)" ) await message.answer(help_text) # Обработчик поиска VN @dp.message(Command("search")) async def search_vn(message: types.Message): query = message.extract_args() if not query: return await message.answer("Введите название для поиска. Пример: /search Steins;Gate") res = await fetch_vndb("vn", ["search", "=", query], "title, released, rating") if not res: return await message.answer("❌ Ничего не найдено или ошибка API") out = [f"🔍 Результаты поиска:"] for item in res[:10]: rating = f"⭐ {item['rating']/10}" if item.get('rating') else "No rating" out.append(f"• {item['title']} (ID: {item['id']}) | {rating}") await message.answer("\n".join(out)) # Обработчик деталей VN @dp.message(Command("vn")) async def details_vn(message: types.Message): vn_id = message.extract_args() if not vn_id: return await message.answer("Укажите ID. Пример: /vn v11") res = await fetch_vndb("vn", ["id", "=", vn_id], "id, title, original, released, rating, votecount") if not res: return await message.answer("❌ VN не найдена") v = res[0] text = ( f"📖 {v['title']}\n" f"Original: {v.get('original', 'N/A')}\n" f"Released: {v.get('released', 'N/A')}\n" f"Rating: {v.get('rating', 'N/A') if v.get('rating') else 'N/A'} ({v.get('votecount', 0)} votes)\n" f"Link: https://vndb.org/{v['id']}" ) await message.answer(text) # Обработчик персонажей @dp.message(Command("char")) async def search_char(message: types.Message): query = message.extract_args() if not query: return await message.answer("Пример: /char Kurisu") res = await fetch_vndb("character", ["search", "=", query], "id, name, original") if not res: return await message.answer("❌ Персонаж не найден") out = [f"👤 Персонажи:"] for c in res[:10]: out.append(f"• {c['name']} ({c['id']})") await message.answer("\n".join(out)) # Запуск if __name__ == "__main__": if not TOKEN: print("Error: TELEGRAM_TOKEN not set!") else: dp.run_polling(bot)