import os import asyncio from datetime import datetime from zoneinfo import ZoneInfo from dotenv import load_dotenv from aiogram.client.default import DefaultBotProperties from aiogram.enums import ParseMode from aiogram.filters import CommandStart, Command from aiogram.types import ( Message, ReplyKeyboardMarkup, KeyboardButton, ReplyKeyboardRemove, ) from trilium_py.client import ETAPI from aiogram import Bot, Dispatcher, F from aiogram.fsm.context import FSMContext from aiogram.fsm.state import State, StatesGroup from aiogram.fsm.storage.memory import MemoryStorage 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") TIMEZONE = os.getenv("TIMEZONE", "UTC") # Переменная окружения для timezone # Получаем объект timezone tz = ZoneInfo(TIMEZONE) # создаем Trilium API клиент ea = ETAPI(server_url=TRILIUM_URL, token=TRILIUM_TOKEN) bot = Bot(token=TELEGRAM_TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML)) storage = MemoryStorage() dp = Dispatcher(storage=storage) class DailyStates(StatesGroup): waiting_for_text = State() # Клавиатуры main_keyboard = ReplyKeyboardMarkup( keyboard=[ [KeyboardButton(text="📅 Daily"), KeyboardButton(text="📥 Inbox")], [KeyboardButton(text="❌ Отмена")], ], resize_keyboard=True, ) cancel_keyboard = ReplyKeyboardMarkup( keyboard=[[KeyboardButton(text="❌ Отмена")]], resize_keyboard=True ) @dp.message(Command("start")) async def cmd_start(message: Message): """Команда /start - показываем главное меню""" await message.answer( "Выбери действие:\n" "📅 Daily - добавить в дневную заметку\n" "📥 Inbox - создать заметку в Inbox (по умолчанию)", reply_markup=main_keyboard, ) @dp.message(F.text == "📅 Daily") async def btn_daily(message: Message, state: FSMContext): """Кнопка Daily""" await message.answer( "Отправь текст для сегодняшней заметки:", reply_markup=cancel_keyboard ) await state.set_state(DailyStates.waiting_for_text) @dp.message(Command("daily")) async def cmd_daily(message: Message, state: FSMContext): """Команда /daily - альтернативный способ""" await message.answer( "Отправь текст для сегодняшней заметки:", reply_markup=cancel_keyboard ) await state.set_state(DailyStates.waiting_for_text) @dp.message(DailyStates.waiting_for_text, F.text != "❌ Отмена") async def process_daily_text(message: Message, state: FSMContext): """Обработка текста для дневной заметки""" text = message.text today = datetime.now(tz).strftime("%Y-%m-%d") try: existing_content = ea.get_day_note(today) timestamp = datetime.now(tz).strftime("%H:%M") new_content = f"{existing_content}
{timestamp}: {text}
" ea.set_day_note(today, new_content) await message.answer( f"✅ Добавлено в дневную заметку", reply_markup=main_keyboard ) except Exception as e: await message.answer(f"❌ Ошибка: {e}", reply_markup=main_keyboard) await state.clear() @dp.message(F.text == "❌ Отмена") async def btn_cancel(message: Message, state: FSMContext): """Кнопка отмены""" await state.clear() await message.answer("Отменено", reply_markup=main_keyboard) @dp.message(Command("cancel")) async def cmd_cancel(message: Message, state: FSMContext): """Команда отмены""" await state.clear() await message.answer("Отменено", reply_markup=main_keyboard) @dp.message(F.text == "📥 Inbox") async def btn_inbox(message: Message): """Информация о режиме Inbox""" await message.answer( "Просто отправь любой текст - он автоматически создаст заметку в Inbox", reply_markup=main_keyboard, ) @dp.message(F.text & ~F.text.startswith("/")) async def handle_text_to_inbox(message: Message, state: FSMContext): """Обработка обычного текста -> создаём новую заметку в Inbox""" current_state = await state.get_state() if current_state is not None: # Если в состоянии daily - пропускаем return # Игнорируем текст кнопок if message.text in ["📅 Daily", "📥 Inbox", "❌ Отмена"]: return text = message.text lines = text.split("\n", 1) title = lines[0][:100] # заголовок = первая строка content = lines[1] if len(lines) > 1 else "" # остальное — тело заметки timestamp = datetime.now(tz).strftime("%Y-%m-%d %H:%M") # title = text[:50] + "..." if len(text) > 50 else text try: res = ea.create_note( parentNoteId=INBOX_NOTE_ID, title=title, type="text", content=f"{timestamp}
{content}
", ) await message.answer(f"✅ Создана заметка в Inbox", reply_markup=main_keyboard) except Exception as e: await message.answer(f"❌ Ошибка: {e}", reply_markup=main_keyboard) async def main(): await dp.start_polling(bot) if __name__ == "__main__": asyncio.run(main())