++
Docker Hub / build-and-push (push) Failing after 13s

This commit is contained in:
kislovdm
2026-04-20 19:19:45 +03:00
parent d019e884b6
commit 2d32bf4807
2 changed files with 148 additions and 72 deletions
+148 -24
View File
@@ -5,7 +5,7 @@ from typing import Any
from max_parser import parse_message
from models import ParsedMessage
from pymax import MaxClient
from pymax.types import PhotoAttach, VideoAttach
from pymax.types import AudioAttach, FileAttach, Message, PhotoAttach, StickerAttach, VideoAttach
from storage import BridgeStorage
from telegram_api import TelegramApiError, TelegramClient
@@ -340,29 +340,24 @@ class MaxToTelegramBridge:
except Exception:
logger.debug("Cannot resolve chat title", exc_info=True)
attaches = getattr(max_message, "attaches", None) or []
for attach in attaches:
if isinstance(attach, PhotoAttach):
parsed.image_urls.extend(self._extract_photo_urls(attach))
elif isinstance(attach, VideoAttach):
try:
video = await self._max_client.get_video_by_id(
chat_id=max_message.chat_id,
message_id=max_message.id,
video_id=attach.video_id,
)
video_url = getattr(video, "url", None)
if video_url:
parsed.video_urls.append(str(video_url))
except Exception:
logger.exception("Cannot resolve video URL from Max")
else:
urls = self._extract_any_urls(attach)
if urls:
parsed.file_urls.extend(urls)
else:
if not self._is_forward_attach_like(attach):
parsed.unknown_attachments.append(type(attach).__name__)
await self._collect_message_attachments(
message=max_message,
parsed=parsed,
source_tag="root",
)
link = getattr(max_message, "link", None)
linked_message = getattr(link, "message", None)
if linked_message is not None:
if not (parsed.text or "").strip():
linked_text = str(getattr(linked_message, "text", "") or "").strip()
if linked_text:
parsed.text = linked_text
await self._collect_message_attachments(
message=linked_message,
parsed=parsed,
source_tag="forward",
)
# Убираем дубли URL, если парсер и enrich нашли одинаковые вложения.
parsed.image_urls = list(dict.fromkeys(parsed.image_urls))
@@ -371,6 +366,127 @@ class MaxToTelegramBridge:
parsed.unknown_attachments = list(dict.fromkeys(parsed.unknown_attachments))
return parsed
async def _collect_message_attachments(
self,
*,
message: Any,
parsed: ParsedMessage,
source_tag: str,
) -> None:
attaches = getattr(message, "attaches", None) or []
message_chat_id = getattr(message, "chat_id", None)
message_id = getattr(message, "id", None)
if message_chat_id is None:
message_chat_id = parsed.chat_id
for attach in attaches:
if isinstance(attach, PhotoAttach):
parsed.image_urls.extend(self._extract_photo_urls(attach))
continue
if isinstance(attach, VideoAttach):
try:
video = await self._max_client.get_video_by_id(
chat_id=message_chat_id,
message_id=message_id,
video_id=attach.video_id,
)
video_url = getattr(video, "url", None)
if video_url:
parsed.video_urls.append(str(video_url))
except Exception:
logger.exception("Cannot resolve video URL from Max (%s)", source_tag)
continue
if isinstance(attach, FileAttach):
resolved = await self._resolve_file_attach_url(
message_chat_id=message_chat_id,
message_id=message_id,
attach=attach,
)
if resolved:
parsed.file_urls.append(resolved)
else:
fallback = str(getattr(attach, "name", "") or "").strip()
if fallback:
parsed.text = self._append_missing_file_note(parsed.text, fallback)
else:
parsed.unknown_attachments.append(type(attach).__name__)
continue
if isinstance(attach, AudioAttach):
audio_url = str(getattr(attach, "url", "") or "").strip()
if audio_url:
parsed.file_urls.append(audio_url)
else:
parsed.unknown_attachments.append(type(attach).__name__)
continue
if isinstance(attach, StickerAttach):
sticker_url = str(getattr(attach, "url", "") or "").strip()
if sticker_url:
parsed.image_urls.append(sticker_url)
else:
parsed.unknown_attachments.append(type(attach).__name__)
continue
# Fallback на случай сырого Attach/нестандартного типа:
if await self._resolve_generic_file_attach(
message_chat_id=message_chat_id,
message_id=message_id,
attach=attach,
parsed=parsed,
):
continue
urls = self._extract_any_urls(attach)
if urls:
parsed.file_urls.extend(urls)
continue
parsed.unknown_attachments.append(type(attach).__name__)
async def _resolve_file_attach_url(self, *, message_chat_id: Any, message_id: Any, attach: FileAttach) -> str | None:
file_id = getattr(attach, "file_id", None)
if file_id is None or message_id is None:
return None
try:
file_info = await self._max_client.get_file_by_id(
chat_id=message_chat_id,
message_id=message_id,
file_id=file_id,
)
url = getattr(file_info, "url", None)
return str(url) if url else None
except Exception:
logger.exception("Cannot resolve file URL from Max (file_id=%s)", file_id)
return None
async def _resolve_generic_file_attach(
self,
*,
message_chat_id: Any,
message_id: Any,
attach: Any,
parsed: ParsedMessage,
) -> bool:
file_id = getattr(attach, "file_id", None)
if file_id is None or message_id is None:
return False
try:
file_info = await self._max_client.get_file_by_id(
chat_id=message_chat_id,
message_id=message_id,
file_id=file_id,
)
url = getattr(file_info, "url", None)
if url:
parsed.file_urls.append(str(url))
return True
except Exception:
logger.debug("Cannot resolve generic file attach from Max", exc_info=True)
return False
def _is_self_message(self, max_message: Any) -> bool:
sender = getattr(max_message, "sender", None)
me = getattr(self._max_client, "me", None)
@@ -459,6 +575,14 @@ class MaxToTelegramBridge:
return True
return False
@staticmethod
def _append_missing_file_note(current_text: str, file_name: str) -> str:
text = (current_text or "").strip()
note = f"[MAX forwarded file without direct URL] {file_name}"
if not text:
return note
return f"{text}\n{note}"
@staticmethod
def _append_unknown_attachment_notice(*, parsed: ParsedMessage, text: str) -> str:
if not parsed.unknown_attachments:
-48
View File
@@ -94,49 +94,6 @@ def _collect_urls(node: Any) -> list[str]:
return list(dict.fromkeys(urls))
def _extract_forwarded_text(message: Any) -> str:
candidates: list[str] = []
seen_ids: set[int] = set()
forward_keys = {"forward", "forwarded", "forwards", "link", "message", "messages", "payload", "quote", "origin"}
text_keys = {"text", "message", "body", "caption"}
def walk(value: Any, inside_forward: bool) -> None:
if value is None:
return
obj_id = id(value)
if obj_id in seen_ids:
return
seen_ids.add(obj_id)
if isinstance(value, str):
if inside_forward:
text = value.strip()
if text and not (text.startswith("http://") or text.startswith("https://")):
candidates.append(text)
return
if isinstance(value, (list, tuple, set)):
for item in value:
walk(item, inside_forward)
return
if isinstance(value, dict):
current_is_forward = inside_forward or any(key in value for key in forward_keys)
for key, nested in value.items():
if key in text_keys and current_is_forward and isinstance(nested, str):
text = nested.strip()
if text and not (text.startswith("http://") or text.startswith("https://")):
candidates.append(text)
walk(nested, current_is_forward)
return
if hasattr(value, "__dict__"):
walk(vars(value), inside_forward)
walk(message, False)
uniq = list(dict.fromkeys(candidates))
if not uniq:
return ""
return "\n\n".join(uniq[:5])
def _extract_media_urls(message: Any) -> tuple[list[str], list[str], list[str], list[str]]:
image_urls: list[str] = []
video_urls: list[str] = []
@@ -239,11 +196,6 @@ def parse_message(message: Any) -> ParsedMessage:
message_id = _stringify(_get_attr(message, ["id", "message_id", "mid"])) or "unknown-id"
chat_id = _stringify(_get_attr(message, ["chat_id", "dialog_id", "peer_id"])) or "unknown-chat"
text = _stringify(_get_attr(message, ["text", "message", "body"]))
forwarded_text = _extract_forwarded_text(message)
if text and forwarded_text and forwarded_text != text:
text = f"{text}\n\n[forwarded]\n{forwarded_text}"
elif not text and forwarded_text:
text = forwarded_text
image_urls, video_urls, file_urls, unknown_attachments = _extract_media_urls(message)
reply_mid, reply_preview = _extract_max_reply(message)