pinned channel info

This commit is contained in:
kislovdm
2026-06-12 01:31:01 +03:00
parent aecfe4dedf
commit 2b5260049b
8 changed files with 277 additions and 18 deletions
+65 -7
View File
@@ -3,7 +3,7 @@ from typing import Any
import structlog
from pymax.types.domain.message import Message as MaxMessage
from app.models.domain import MaxIncomingMessage
from app.models.domain import MaxChatMeta, MaxIncomingMessage
logger = structlog.get_logger(__name__)
@@ -211,14 +211,72 @@ async def resolve_media(client, message: MaxMessage) -> list[dict]:
return items
def build_chat_title(chat, ls_prefix: str) -> tuple[str, bool]:
def _pick_image_url(*values: str | None) -> str | None:
for value in values:
if value and value.strip():
return value.strip()
return None
def _chat_icon_url(chat) -> str | None:
return _pick_image_url(
getattr(chat, "base_icon_url", None),
getattr(chat, "base_raw_icon_url", None),
)
def _user_icon_url(user) -> str | None:
return _pick_image_url(
getattr(user, "base_url", None),
getattr(user, "base_raw_url", None),
)
async def resolve_chat_icon_url(
client,
chat,
my_user_id: int | None,
) -> str | None:
is_dm = bool(getattr(chat, "is_dialog", False) or chat.type == "DIALOG")
if is_dm:
title = chat.title or "Контакт"
if not title.startswith(ls_prefix.strip()):
title = f"{ls_prefix}{title}"
return title, True
return chat.title or f"Чат {chat.id}", False
for user_id in chat.participants or {}:
if my_user_id and user_id == my_user_id:
continue
try:
user = await client.get_user(user_id)
icon_url = _user_icon_url(user)
if icon_url:
return icon_url
except Exception:
logger.debug(
"max_dm_icon_lookup_failed",
chat_id=chat.id,
user_id=user_id,
)
return None
return _chat_icon_url(chat)
def extract_chat_meta(chat, ls_prefix: str) -> MaxChatMeta:
is_dm = bool(getattr(chat, "is_dialog", False) or chat.type == "DIALOG")
chat_name = chat.title or ("Контакт" if is_dm else f"Чат {chat.id}")
topic_title = chat_name
if is_dm and not topic_title.startswith(ls_prefix.strip()):
topic_title = f"{ls_prefix}{topic_title}"
return MaxChatMeta(
topic_title=topic_title,
chat_name=chat_name,
is_dm=is_dm,
icon_url=_chat_icon_url(chat),
participants_count=getattr(chat, "participants_count", 0) or 0,
link=getattr(chat, "link", None),
)
def build_chat_title(chat, ls_prefix: str) -> tuple[str, bool]:
meta = extract_chat_meta(chat, ls_prefix)
return meta.topic_title, meta.is_dm
def resolve_sender_name(user) -> str:
+35 -10
View File
@@ -1,16 +1,18 @@
import asyncio
from pathlib import Path
from uuid import uuid4
import aiohttp
import structlog
from pymax import ExtraConfig, Message, WebClient
from pymax.types.domain.enums import ChatType
from app.config import Settings
from app.media_transfer import download_max_media, tmp_dir
from app.media_transfer import download_max_image_url, download_max_media, tmp_dir
from app.max_layer.client_holder import MaxClientHolder
from app.max_layer.formatter import (
build_chat_title,
extract_chat_meta,
extract_forwarded_content,
resolve_chat_icon_url,
format_forwarded_text,
get_reply_target,
resolve_media,
@@ -86,6 +88,21 @@ class MaxListener:
message_id=message.id,
)
async def _download_chat_icon(self, icon_url: str | None) -> str | None:
if not icon_url:
return None
dest = self._tmp_dir / f"chat_icon_{uuid4().hex}.jpg"
try:
async with aiohttp.ClientSession() as session:
if not await download_max_image_url(session, icon_url, dest):
logger.warning("max_chat_icon_download_failed", url=icon_url)
return None
return str(dest)
except Exception:
logger.exception("max_chat_icon_download_failed", url=icon_url)
dest.unlink(missing_ok=True)
return None
async def run(self) -> None:
self._client = self.build_client()
await self._client.start()
@@ -169,11 +186,14 @@ class MaxListener:
logger.exception("max_chat_fetch_failed", chat_id=message.chat_id)
return
is_dm = chat.type == ChatType.DIALOG or getattr(chat, "is_dialog", False)
chat_title, _ = build_chat_title(chat, self._settings.ls_topic_prefix)
chat_meta = extract_chat_meta(chat, self._settings.ls_topic_prefix)
chat_icon_url = await resolve_chat_icon_url(
client, chat, self._holder.my_user_id
)
chat_icon_local_path = await self._download_chat_icon(chat_icon_url)
sender_name: str | None = None
if not is_dm and message.sender:
if not chat_meta.is_dm and message.sender:
try:
user = await client.get_user(message.sender)
sender_name = resolve_sender_name(user)
@@ -207,7 +227,7 @@ class MaxListener:
is_forward=forwarded is not None,
text_len=len(effective_text),
media_count=len(media),
is_dm=is_dm,
is_dm=chat_meta.is_dm,
reply_to=reply_to,
)
@@ -217,8 +237,13 @@ class MaxListener:
text=effective_text,
sender_id=message.sender,
sender_name=sender_name,
is_dm=is_dm,
chat_title=chat_title,
is_dm=chat_meta.is_dm,
chat_title=chat_meta.topic_title,
chat_name=chat_meta.chat_name,
chat_icon_url=chat_icon_url,
chat_icon_local_path=chat_icon_local_path,
participants_count=chat_meta.participants_count,
max_chat_link=chat_meta.link,
reply_to_max_message_id=reply_to,
media=media,
)