86 lines
2.3 KiB
Python
86 lines
2.3 KiB
Python
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
from yuxi.channels.models import ChatType
|
|||
|
|
|
|||
|
|
TARGET_PREFIX_MAP: dict[str, str] = {
|
|||
|
|
"chat_id:": "chat_id",
|
|||
|
|
"chat_guid:": "chat_guid",
|
|||
|
|
"chat_identifier:": "chat_identifier",
|
|||
|
|
"handle:": "handle",
|
|||
|
|
"phone:": "phone",
|
|||
|
|
"email:": "email",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
EXPLICIT_TARGET_RE_PREFIXES = (
|
|||
|
|
"chat_id:",
|
|||
|
|
"chat_guid:",
|
|||
|
|
"chat_identifier:",
|
|||
|
|
"iMessage;",
|
|||
|
|
"iMessage",
|
|||
|
|
"handle:",
|
|||
|
|
"phone:",
|
|||
|
|
"email:",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
IMESSAGE_TARGET_PREFIXES = (
|
|||
|
|
"chat_id:",
|
|||
|
|
"chat_guid:",
|
|||
|
|
"chat_identifier:",
|
|||
|
|
"iMessage;",
|
|||
|
|
"iMessage",
|
|||
|
|
"handle:",
|
|||
|
|
"phone:",
|
|||
|
|
"email:",
|
|||
|
|
"tel:",
|
|||
|
|
"mailto:",
|
|||
|
|
"+",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def parse_target(raw_target: str) -> dict[str, str]:
|
|||
|
|
"""解析目标字符串,返回 {type, value}。
|
|||
|
|
|
|||
|
|
支持的类型:
|
|||
|
|
- chat_id:<value> → chat_id
|
|||
|
|
- chat_guid:<value> → chat_guid
|
|||
|
|
- chat_identifier:<value> → chat_identifier (chat_id 或 chat_guid)
|
|||
|
|
- handle:<value> → handle
|
|||
|
|
- phone:<value> → phone (E.164)
|
|||
|
|
- email:<value> → email
|
|||
|
|
- 其他:自动推断为 handle
|
|||
|
|
"""
|
|||
|
|
if not raw_target:
|
|||
|
|
return {"type": "unknown", "value": ""}
|
|||
|
|
|
|||
|
|
raw_lower = raw_target.lower()
|
|||
|
|
for prefix, type_name in TARGET_PREFIX_MAP.items():
|
|||
|
|
if raw_lower.startswith(prefix):
|
|||
|
|
return {"type": type_name, "value": raw_target[len(prefix) :]}
|
|||
|
|
|
|||
|
|
if looks_like_explicit_target_id(raw_target):
|
|||
|
|
if ";-;" in raw_target or "@chat" in raw_target:
|
|||
|
|
return {"type": "chat_guid", "value": raw_target}
|
|||
|
|
if raw_target.startswith("iMessage;"):
|
|||
|
|
return {"type": "chat_id", "value": raw_target}
|
|||
|
|
|
|||
|
|
if "@" in raw_target and "." in raw_target.split("@")[-1]:
|
|||
|
|
return {"type": "email", "value": raw_target}
|
|||
|
|
|
|||
|
|
return {"type": "handle", "value": raw_target}
|
|||
|
|
|
|||
|
|
|
|||
|
|
def looks_like_explicit_target_id(target: str) -> bool:
|
|||
|
|
return any(target.lower().startswith(p.lower()) for p in EXPLICIT_TARGET_RE_PREFIXES)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def looks_like_imessage_target_id(target: str) -> bool:
|
|||
|
|
return any(target.lower().startswith(p.lower()) for p in IMESSAGE_TARGET_PREFIXES)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def resolve_chat_type_from_target(target: str) -> ChatType:
|
|||
|
|
parsed = parse_target(target)
|
|||
|
|
value = parsed["value"]
|
|||
|
|
if ";-;" in value or "@chat" in value:
|
|||
|
|
return ChatType.GROUP
|
|||
|
|
return ChatType.DIRECT
|