import os from datetime import datetime from dotenv import load_dotenv from aiogram import Bot, Dispatcher from aiogram.client.default import DefaultBotProperties from aiogram.enums import ParseMode from aiogram.filters import Command, CommandStart from aiogram.types import Message from trilium_py.client import ETAPI load_dotenv() TELEGRAM_TOKEN = os.getenv("TELEGRAM_TOKEN") TRILIUM_URL = os.getenv("TRILIUM_URL") TRILIUM_TOKEN = os.getenv("TRILIUM_TOKEN") INBOX_NOTE_ID = os.getenv("INBOX_NOTE_ID") DAILY_NOTE_ID = os.getenv("DAILY_NOTE_ID") # ID папки для ежедневных заметок # создаем Trilium API клиент ea = ETAPI(server_url=TRILIUM_URL, token=TRILIUM_TOKEN) bot = Bot(token=TELEGRAM_TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML)) dp = Dispatcher() pending_daily_chats = set() # chat_ids ожидающих текст для /daily @dp.message(CommandStart()) async def start(msg: Message): await msg.answer("Отправь мне текст — я создам заметку в Trilium.") def _get_id(obj): if isinstance(obj, dict): return obj.get("noteId") or obj.get("id") return getattr(obj, "noteId", None) or getattr(obj, "id", None) def _get_title(obj): return obj.get("title") if isinstance(obj, dict) else getattr(obj, "title", "") def _get_content(obj): return obj.get("content") if isinstance(obj, dict) else getattr(obj, "content", "") def _children(obj): if isinstance(obj, dict): return obj.get("children") or [] return getattr(obj, "children", []) or [] def _translate_month_en_ru(name: str) -> str: mapping = { "January": "Январь", "February": "Февраль", "March": "Март", "April": "Апрель", "May": "Май", "June": "Июнь", "July": "Июль", "August": "Август", "September": "Сентябрь", "October": "Октябрь", "November": "Ноябрь", "December": "Декабрь", } return mapping.get(name, name) def _translate_weekday_en_ru(name: str) -> str: mapping = { "Monday": "Понедельник", "Tuesday": "Вторник", "Wednesday": "Среда", "Thursday": "Четверг", "Friday": "Пятница", "Saturday": "Суббота", "Sunday": "Воскресенье", } return mapping.get(name, name) def save_inbox(text: str): # разделяем на заголовок и тело lines = text.split("\n", 1) title = lines[0][:100] content = lines[1] if len(lines) > 1 else "" ea.create_note( parentNoteId=INBOX_NOTE_ID, title=title, content=content, type="text" ) def save_daily(text: str) -> str: today = datetime.now() month_name = ( f"{today.strftime('%m')} - {_translate_month_en_ru(today.strftime('%B'))}" ) day_name = ( f"{today.strftime('%d')} - {_translate_weekday_en_ru(today.strftime('%A'))}" ) today_date = today.strftime("%Y-%m-%d") # Корень daily daily_root = ea.get_note(DAILY_NOTE_ID) # Ищем/создаём месяц month_folder = None for child in _children(daily_root): if _get_title(child) == month_name: month_folder = child break if not month_folder: month_folder = ea.create_note( parentNoteId=DAILY_NOTE_ID, title=month_name, type="text" ) month_id = _get_id(month_folder) month_folder = ea.get_note(month_id) # Ищем/создаём день day_folder = None for child in _children(month_folder): if _get_title(child) == day_name: day_folder = child break if not day_folder: day_folder = ea.create_note(parentNoteId=month_id, title=day_name, type="text") day_id = _get_id(day_folder) day_folder = ea.get_note(day_id) # Ищем заметку по дате existing_note = None for child in _children(day_folder): if _get_title(child) == today_date: existing_note = child break if existing_note: existing_content = _get_content(existing_note) new_content = f"{existing_content}\n\n---\n{text}" if existing_content else text ea.update_note(noteId=_get_id(existing_note), content=new_content) return f"Добавлено в ежедневную заметку за {today_date}." ea.create_note(parentNoteId=day_id, title=today_date, content=text, type="text") return f"Создана ежедневная заметка за {today_date}." @dp.message(Command("daily")) async def daily_command(msg: Message): pending_daily_chats.add(msg.chat.id) await msg.answer( "Жду текст для ежедневной заметки. Следующее сообщение запишу в текущий день." ) @dp.message() async def handler(msg: Message): text = (msg.text or "").strip() # Если ожидаем daily — пишем туда if msg.chat.id in pending_daily_chats: pending_daily_chats.discard(msg.chat.id) try: result = save_daily(text) await msg.answer(result) except Exception as e: await msg.answer(f"Ошибка при работе с ежедневной заметкой: {str(e)}") return # Обычная заметка в Inbox try: save_inbox(text) await msg.answer("Заметка сохранена в Trilium.") except Exception as e: await msg.answer(f"Ошибка при сохранении в Inbox: {str(e)}") async def main(): await dp.start_polling(bot) if __name__ == "__main__": import asyncio asyncio.run(main())