Add channel search and subscription

This commit is contained in:
sevenhill
2026-07-07 22:09:18 +03:00
parent b2766ebbe9
commit 0a42e6f860
14 changed files with 421 additions and 4 deletions
+85
View File
@@ -752,6 +752,37 @@ def parse_chat_id(value: Any) -> int:
return int(text)
def is_channel_link_query(value: str) -> bool:
text = value.strip()
lower = text.lower()
return (
"://max.ru/" in lower
or "://web.max.ru/" in lower
or "/join/" in lower
or lower.startswith("join/")
or lower.startswith("@")
)
def channel_search_result(
chat: Any,
user_map: dict[str, Any] | None = None,
me_id: int | None = None,
*,
subscribed: bool,
chat_url: str | None = None,
) -> dict[str, Any]:
user_map = user_map or {}
return {
"externalId": clean_id(getattr(chat, "id", None)),
"title": resolve_chat_title(chat, user_map, me_id),
"avatarUrl": resolve_chat_avatar(chat, user_map, me_id),
"chatUrl": chat_url or f"pymax://chat/{chat.id}",
"isSubscribed": subscribed,
"description": first_text(getattr(chat, "description", None), getattr(chat, "about", None)),
}
def validate_send_path(raw: str) -> pathlib.Path:
path = pathlib.Path(raw)
resolved = path.resolve(strict=True)
@@ -877,6 +908,58 @@ async def resolve_chat_url(request: web.Request) -> web.Response:
return json_response({"success": True, "chatUrl": f"pymax://chat/{chat_id}", "error": None})
@route_errors
async def channels_search(request: web.Request) -> web.Response:
data = await read_json(request)
query = str(data.get("query") or "").strip()
if not query:
return json_response([])
client = await runtime.get_client()
lower_query = query.lower()
chats = await fetch_chat_pages(client, CHAT_FETCH_LIMIT)
channel_chats = [chat for chat in chats if normalize_chat_kind(chat) == "Channel"]
me_id = get_me_user_id(client)
user_map = await build_user_map(client, channel_chats)
results = [
channel_search_result(chat, user_map, me_id, subscribed=True)
for chat in channel_chats
if lower_query in resolve_chat_title(chat, user_map, me_id).lower()
]
if is_channel_link_query(query) and not any(result.get("chatUrl") == query for result in results):
try:
resolved = await asyncio.wait_for(client.resolve_group_by_link(query), timeout=10)
except Exception:
resolved = None
if resolved is not None:
results.insert(0, channel_search_result(resolved, subscribed=False, chat_url=query))
elif not any(result.get("externalId") == query for result in results):
results.insert(0, {
"externalId": query,
"title": query,
"avatarUrl": None,
"chatUrl": query,
"isSubscribed": False,
"description": "Канал MAX по ссылке или invite-токену",
})
return json_response(results[:20])
@route_errors
async def channels_join(request: web.Request) -> web.Response:
data = await read_json(request)
link = str(data.get("link") or data.get("chatUrl") or "").strip()
if not link:
return json_response({"success": False, "error": "link is required"}, status=400)
client = await runtime.get_client()
chat = await client.join_channel(link)
result = await normalize_chat_update(client, chat, include_history=True)
return json_response(result)
@route_errors
async def chat_presence(_request: web.Request) -> web.Response:
return json_response({"isTyping": False, "statusText": None, "updatedAt": utc_now()})
@@ -936,6 +1019,8 @@ def create_app() -> web.Application:
app.router.add_get("/updates", updates)
app.router.add_post("/chat/history", chat_history)
app.router.add_post("/chat/resolve-url", resolve_chat_url)
app.router.add_post("/channels/search", channels_search)
app.router.add_post("/channels/join", channels_join)
app.router.add_post("/chat/presence", chat_presence)
app.router.add_post("/chat/clear-history", disabled_action)
app.router.add_post("/chat/delete", disabled_action)