Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64fe9c466e | ||
|
|
8bba0d9dd5 |
+50
-5
@@ -204,11 +204,7 @@ class TelegramToMaxBridge:
|
|||||||
|
|
||||||
chat_title = _telegram_chat_title(chat)
|
chat_title = _telegram_chat_title(chat)
|
||||||
normalized = _normalize_title(chat_title)
|
normalized = _normalize_title(chat_title)
|
||||||
if not normalized:
|
max_chat_id = self._resolve_max_chat_id(message=message, normalized_title=normalized, chat=chat)
|
||||||
logger.error("Telegram chat without title/username, skip (chat=%s)", chat)
|
|
||||||
return
|
|
||||||
|
|
||||||
max_chat_id = self._resolve_max_chat_id_by_title(normalized)
|
|
||||||
if max_chat_id is None:
|
if max_chat_id is None:
|
||||||
# требование: если в MAX нет канала/группы — ошибка и не пересылать
|
# требование: если в MAX нет канала/группы — ошибка и не пересылать
|
||||||
logger.error("MAX чат с названием '%s' не найден — сообщение не пересылаю", chat_title)
|
logger.error("MAX чат с названием '%s' не найден — сообщение не пересылаю", chat_title)
|
||||||
@@ -441,6 +437,55 @@ class TelegramToMaxBridge:
|
|||||||
# reply_to в MAX — это id сообщения; если не нашли, просто отправляем без reply
|
# reply_to в MAX — это id сообщения; если не нашли, просто отправляем без reply
|
||||||
return mapped
|
return mapped
|
||||||
|
|
||||||
|
def _resolve_max_chat_id(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
message: dict[str, Any],
|
||||||
|
normalized_title: str,
|
||||||
|
chat: dict[str, Any],
|
||||||
|
) -> int | None:
|
||||||
|
# При reply маршрутизируем по исходному сообщению (контекст диалога),
|
||||||
|
# чтобы не зависеть от username/title Telegram-чата.
|
||||||
|
from_reply = self._resolve_max_chat_id_from_reply(message)
|
||||||
|
if from_reply is not None:
|
||||||
|
return from_reply
|
||||||
|
|
||||||
|
if not normalized_title:
|
||||||
|
logger.error("Telegram chat without title/username, skip (chat=%s)", chat)
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self._resolve_max_chat_id_by_title(normalized_title)
|
||||||
|
|
||||||
|
def _resolve_max_chat_id_from_reply(self, message: dict[str, Any]) -> int | None:
|
||||||
|
reply = message.get("reply_to_message")
|
||||||
|
if not isinstance(reply, dict):
|
||||||
|
return None
|
||||||
|
reply_mid = reply.get("message_id")
|
||||||
|
if reply_mid is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
chat = message.get("chat")
|
||||||
|
if not isinstance(chat, dict):
|
||||||
|
return None
|
||||||
|
telegram_chat_id = str(chat.get("id"))
|
||||||
|
|
||||||
|
max_chat_id = self._storage.get_max_chat_id_for_telegram(
|
||||||
|
telegram_chat_id=telegram_chat_id,
|
||||||
|
telegram_message_id=str(reply_mid),
|
||||||
|
)
|
||||||
|
if not max_chat_id:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return int(max_chat_id)
|
||||||
|
except ValueError:
|
||||||
|
logger.warning(
|
||||||
|
"Invalid max_chat_id '%s' in mapping for Telegram %s/%s",
|
||||||
|
max_chat_id,
|
||||||
|
telegram_chat_id,
|
||||||
|
reply_mid,
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
async def _extract_attachments(self, message: dict[str, Any]) -> tuple[list[Any], list[str]]:
|
async def _extract_attachments(self, message: dict[str, Any]) -> tuple[list[Any], list[str]]:
|
||||||
attachments: list[Any] = []
|
attachments: list[Any] = []
|
||||||
file_links: list[str] = []
|
file_links: list[str] = []
|
||||||
|
|||||||
@@ -105,6 +105,22 @@ class BridgeStorage:
|
|||||||
return None
|
return None
|
||||||
return str(row[0])
|
return str(row[0])
|
||||||
|
|
||||||
|
def get_max_chat_id_for_telegram(
|
||||||
|
self, *, telegram_chat_id: str, telegram_message_id: str
|
||||||
|
) -> str | None:
|
||||||
|
with closing(self._connect()) as conn:
|
||||||
|
row = conn.execute(
|
||||||
|
"""
|
||||||
|
SELECT max_chat_id
|
||||||
|
FROM message_mapping
|
||||||
|
WHERE telegram_chat_id = ? AND telegram_message_id = ?
|
||||||
|
""",
|
||||||
|
(telegram_chat_id, telegram_message_id),
|
||||||
|
).fetchone()
|
||||||
|
if not row:
|
||||||
|
return None
|
||||||
|
return str(row[0])
|
||||||
|
|
||||||
def get_telegram_message_id_for_max(
|
def get_telegram_message_id_for_max(
|
||||||
self, *, telegram_chat_id: str, max_chat_id: str, max_message_id: str
|
self, *, telegram_chat_id: str, max_chat_id: str, max_message_id: str
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
- при неизвестных вложениях добавить уведомление в конец.
|
- при неизвестных вложениях добавить уведомление в конец.
|
||||||
6. Обработать reply:
|
6. Обработать reply:
|
||||||
- попытаться найти Telegram `reply_to_message_id` через mapping;
|
- попытаться найти Telegram `reply_to_message_id` через mapping;
|
||||||
|
- не дублировать вложения из исходного сообщения, на которое отвечают;
|
||||||
- если mapping не найден — добавить текстовый контекст ответа.
|
- если mapping не найден — добавить текстовый контекст ответа.
|
||||||
7. Отправить контент:
|
7. Отправить контент:
|
||||||
- при `image+video > 1` — отправить единым альбомом (`sendMediaGroup`);
|
- при `image+video > 1` — отправить единым альбомом (`sendMediaGroup`);
|
||||||
@@ -300,6 +301,7 @@
|
|||||||
- если найден, отправлять `reply_to` в MAX.
|
- если найден, отправлять `reply_to` в MAX.
|
||||||
- Для MAX->Telegram:
|
- Для MAX->Telegram:
|
||||||
- если MAX message является reply, искать `telegram_message_id` в mapping;
|
- если MAX message является reply, искать `telegram_message_id` в mapping;
|
||||||
|
- если MAX message является reply, не копировать медиа из `link.message` (исходного сообщения);
|
||||||
- если найден, отправлять `reply_to_message_id`;
|
- если найден, отправлять `reply_to_message_id`;
|
||||||
- если не найден, добавлять текстовую пометку с превью исходного сообщения.
|
- если не найден, добавлять текстовую пометку с превью исходного сообщения.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user