110 lines
3.7 KiB
Python
110 lines
3.7 KiB
Python
"""
|
|
Доставка дайджеста: Telegram (Избранное / бот) или файл.
|
|
"""
|
|
|
|
import logging
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
import httpx
|
|
from telethon import TelegramClient
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
SESSION_DIR = Path("/data")
|
|
|
|
|
|
def _split_message(text: str, max_length: int = 4000) -> list[str]:
|
|
if len(text) <= max_length:
|
|
return [text]
|
|
|
|
parts = []
|
|
current = ""
|
|
for line in text.split("\n"):
|
|
if len(current) + len(line) + 1 > max_length:
|
|
if current:
|
|
parts.append(current.strip())
|
|
current = line + "\n"
|
|
else:
|
|
current += line + "\n"
|
|
if current.strip():
|
|
parts.append(current.strip())
|
|
return parts
|
|
|
|
|
|
class DeliveryManager:
|
|
def __init__(self, config: dict):
|
|
self.cfg = config["delivery"]
|
|
self.tg_cfg = config["telegram"]
|
|
self.method = self.cfg["method"]
|
|
self.max_length = self.cfg.get("max_message_length", 4000)
|
|
|
|
async def deliver(self, digest: str) -> None:
|
|
now = datetime.now().strftime("%d.%m.%Y %H:%M")
|
|
header = f"📰 **Новостной дайджест** — {now}\n\n"
|
|
full_text = header + digest
|
|
|
|
if self.method == "saved_messages":
|
|
await self._send_saved_messages(full_text)
|
|
elif self.method == "bot":
|
|
await self._send_via_bot(full_text)
|
|
elif self.method == "file":
|
|
self._save_to_file(full_text)
|
|
else:
|
|
raise ValueError(f"Неизвестный метод доставки: {self.method}")
|
|
|
|
async def _send_saved_messages(self, text: str):
|
|
session_path = SESSION_DIR / self.tg_cfg["session_name"]
|
|
client = TelegramClient(
|
|
str(session_path),
|
|
self.tg_cfg["api_id"],
|
|
self.tg_cfg["api_hash"],
|
|
)
|
|
await client.connect()
|
|
|
|
if not await client.is_user_authorized():
|
|
raise RuntimeError("Сессия не авторизована")
|
|
|
|
parts = _split_message(text, self.max_length)
|
|
me = await client.get_me()
|
|
for i, part in enumerate(parts, 1):
|
|
await client.send_message(me, part, parse_mode="md")
|
|
logger.info(f"Отправлена часть {i}/{len(parts)} в Избранное")
|
|
|
|
await client.disconnect()
|
|
logger.info("✓ Дайджест отправлен в Избранное")
|
|
|
|
async def _send_via_bot(self, text: str):
|
|
token = self.cfg["bot_token"]
|
|
chat_id = self.cfg["chat_id"]
|
|
url = f"https://api.telegram.org/bot{token}/sendMessage"
|
|
|
|
parts = _split_message(text, self.max_length)
|
|
|
|
async with httpx.AsyncClient(timeout=30) as client:
|
|
for i, part in enumerate(parts, 1):
|
|
resp = await client.post(
|
|
url,
|
|
json={
|
|
"chat_id": chat_id,
|
|
"text": part,
|
|
"parse_mode": "Markdown",
|
|
"disable_web_page_preview": True,
|
|
},
|
|
)
|
|
if resp.status_code != 200:
|
|
logger.error(f"Bot API: {resp.status_code} {resp.text}")
|
|
else:
|
|
logger.info(f"Часть {i}/{len(parts)} через бота")
|
|
|
|
logger.info("✓ Дайджест отправлен через бота")
|
|
|
|
def _save_to_file(self, text: str):
|
|
output_dir = Path("/data/digests")
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
filename = datetime.now().strftime("digest_%Y%m%d_%H%M.md")
|
|
filepath = output_dir / filename
|
|
filepath.write_text(text, encoding="utf-8")
|
|
logger.info(f"✓ Дайджест сохранён: {filepath}")
|