新增大量WhatsApp适配器相关代码,包括账号管理、会话处理、消息收发、验证授权、媒体处理、互动命令、审批流程、健康检测等完整功能模块,搭建基础的Baileys协议WhatsApp接入能力
133 lines
3.2 KiB
Python
133 lines
3.2 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
|
|
_ALLOWED_TAGS = {
|
|
"b",
|
|
"strong",
|
|
"i",
|
|
"em",
|
|
"u",
|
|
"ins",
|
|
"s",
|
|
"strike",
|
|
"del",
|
|
"code",
|
|
"pre",
|
|
"a",
|
|
}
|
|
|
|
_TAG_PATTERN = re.compile(r"</?(\w+)[^>]*>")
|
|
|
|
_TABLE_ROW_PATTERN = re.compile(r"^\|(.+)\|$", re.MULTILINE)
|
|
_TABLE_SEPARATOR_PATTERN = re.compile(r"^\|[\s\-:|]+\|$", re.MULTILINE)
|
|
|
|
|
|
def text_sanitizer(text: str) -> str:
|
|
if not text:
|
|
return ""
|
|
|
|
text = text.replace(" ", " ")
|
|
|
|
def _replace_tag(m: re.Match) -> str:
|
|
tag = m.group(1).lower()
|
|
if tag in _ALLOWED_TAGS:
|
|
return m.group(0)
|
|
return ""
|
|
|
|
text = _TAG_PATTERN.sub(_replace_tag, text)
|
|
text = text.strip()
|
|
return text
|
|
|
|
|
|
def markdown_to_whatsapp(md_text: str) -> str:
|
|
if not md_text:
|
|
return ""
|
|
|
|
text = md_text
|
|
|
|
text = re.sub(r"```(\w+)?\n(.*?)```", _code_block, text, flags=re.DOTALL)
|
|
text = re.sub(r"`([^`]+)`", r"```\1```", text)
|
|
|
|
text = _convert_tables(text)
|
|
|
|
text = re.sub(r"\*\*\*(.+?)\*\*\*", r"*_\1_*", text)
|
|
text = re.sub(r"___(.+?)___", r"*_\1_*", text)
|
|
|
|
text = re.sub(r"\*\*(.+?)\*\*", r"*\1*", text)
|
|
text = re.sub(r"__(.+?)__", r"*\1*", text)
|
|
|
|
text = re.sub(r"(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)", r"_\1_", text)
|
|
text = re.sub(r"(?<!_)_(?!_)(.+?)(?<!_)_(?!_)", r"_\1_", text)
|
|
|
|
text = re.sub(r"~~(.+?)~~", r"~\1~", text)
|
|
|
|
text = re.sub(r"^### (.+)$", r"*_\1_*", text, flags=re.MULTILINE)
|
|
text = re.sub(r"^## (.+)$", r"*_\1_*", text, flags=re.MULTILINE)
|
|
text = re.sub(r"^# (.+)$", r"*_\1_*", text, flags=re.MULTILINE)
|
|
|
|
text = re.sub(r"\[([^\]]+)\]\(([^)]+)\)", _link, text)
|
|
|
|
text = re.sub(r"^\- (.+)$", r"• \1", text, flags=re.MULTILINE)
|
|
text = re.sub(r"^\d+\. (.+)$", r"• \1", text, flags=re.MULTILINE)
|
|
|
|
text = text.replace("<br>", "\n")
|
|
text = re.sub(r"\n{3,}", "\n\n", text)
|
|
|
|
return text.strip()
|
|
|
|
|
|
def _convert_tables(text: str) -> str:
|
|
|
|
def _replace_table(m: re.Match) -> str:
|
|
table_block = m.group(0)
|
|
lines = table_block.strip().split("\n")
|
|
if len(lines) < 2:
|
|
return table_block
|
|
|
|
data_lines = []
|
|
header = None
|
|
for line in lines:
|
|
stripped = line.strip()
|
|
if not stripped.startswith("|"):
|
|
continue
|
|
if _TABLE_SEPARATOR_PATTERN.match(stripped):
|
|
continue
|
|
cells = [c.strip() for c in stripped[1:-1].split("|")]
|
|
if header is None:
|
|
header = " | ".join(cells)
|
|
else:
|
|
data_lines.append("• " + " | ".join(cells))
|
|
|
|
if header is None:
|
|
return table_block
|
|
|
|
result = [header]
|
|
result.extend(data_lines)
|
|
return "\n".join(result)
|
|
|
|
text = re.sub(
|
|
r"(?:^|\n)(\|.+\|\s*\n){2,}",
|
|
_replace_table,
|
|
text,
|
|
flags=re.MULTILINE,
|
|
)
|
|
return text
|
|
|
|
|
|
def _code_block(m: re.Match) -> str:
|
|
lang = m.group(1) or ""
|
|
code = m.group(2).strip()
|
|
prefix = f"[{lang}]\n" if lang else ""
|
|
return f"```{prefix}{code}```"
|
|
|
|
|
|
def _link(m: re.Match) -> str:
|
|
text = m.group(1)
|
|
url = m.group(2)
|
|
if text == url:
|
|
return url
|
|
if not text.strip():
|
|
return url
|
|
return f"{text}\n({url})"
|