Files
trilium-bot/main.py

191 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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())