Merge pull request #5289 from HankunYu/v2

This commit is contained in:
jxxghp
2025-12-28 12:50:40 +08:00
committed by GitHub
+79 -9
View File
@@ -1,7 +1,7 @@
import asyncio import asyncio
import re import re
import threading import threading
from typing import Optional, List, Dict, Any, Union from typing import Optional, List, Dict, Any, Tuple, Union
import discord import discord
from discord import app_commands from discord import app_commands
@@ -40,7 +40,10 @@ class Discord:
intents.messages = True intents.messages = True
intents.guilds = True intents.guilds = True
self._client: Optional[discord.Client] = discord.Client(intents=intents) self._client: Optional[discord.Client] = discord.Client(
intents=intents,
proxy=settings.PROXY_HOST
)
self._tree: Optional[app_commands.CommandTree] = None self._tree: Optional[app_commands.CommandTree] = None
self._loop: asyncio.AbstractEventLoop = asyncio.new_event_loop() self._loop: asyncio.AbstractEventLoop = asyncio.new_event_loop()
self._thread: Optional[threading.Thread] = None self._thread: Optional[threading.Thread] = None
@@ -316,20 +319,87 @@ class Discord:
@staticmethod @staticmethod
def _build_embed(title: str, text: Optional[str], image: Optional[str], def _build_embed(title: str, text: Optional[str], image: Optional[str],
link: Optional[str]) -> discord.Embed: link: Optional[str]) -> discord.Embed:
description = ""
fields: List[Dict[str, str]] = [] fields: List[Dict[str, str]] = []
desc_lines: List[str] = []
def _collect_spans(s: str, left: str, right: str) -> List[Tuple[int, int]]:
spans: List[Tuple[int, int]] = []
start = 0
while True:
l_idx = s.find(left, start)
if l_idx == -1:
break
r_idx = s.find(right, l_idx + 1)
if r_idx == -1:
break
spans.append((l_idx, r_idx))
start = r_idx + 1
return spans
def _find_colon_index(s: str, m: re.Match) -> Optional[int]:
segment = s[m.start():m.end()]
for i, ch in enumerate(segment):
if ch in (":", ""):
return m.start() + i
return None
if text: if text:
# 处理上游未反序列化的 "\n" 等转义换行,避免被当成普通字符
if "\\n" in text or "\\r" in text:
text = text.replace("\\r\\n", "\n").replace("\\n", "\n").replace("\\r", "\n")
# 匹配形如 "字段:值" 的片段,字段名不允许包含常见分隔符;
# 下一个字段需以顿号/逗号/分号等分隔开,且不能是 URL 协议开头,避免值里出现 URL 的":" 被误拆
name_re = r"[A-Za-z0-9\u4e00-\u9fa5_\-&]+"
pair_pattern = re.compile(
rf"({name_re})[:](.*?)(?=(?:[,。;;、]+\s*(?!https?://|ftp://|ftps://|magnet:){name_re}[:])|$)",
re.IGNORECASE,
)
for line in text.splitlines(): for line in text.splitlines():
if "" in line: line = line.strip()
name, value = line.split("", 1) if not line:
fields.append({"name": name.strip(), "value": value.strip() or "-", "inline": False}) continue
matches = list(pair_pattern.finditer(line))
if matches:
book_spans = _collect_spans(line, "", "") + _collect_spans(line, "", "")
if book_spans:
has_book_colon = False
for m in matches:
colon_idx = _find_colon_index(line, m)
if colon_idx is not None and any(l < colon_idx < r for l, r in book_spans):
has_book_colon = True
break
if has_book_colon:
desc_lines.append(line)
continue
# 若整行只是 URL/时间等自然包含":"的内容,则不当作字段
url_like_names = {"http", "https", "ftp", "ftps", "magnet"}
if all(m.group(1).lower() in url_like_names or m.group(1).isdigit() for m in matches):
desc_lines.append(line)
continue
last_end = 0
for m in matches:
# 追加匹配前的非空文本到描述
prefix = line[last_end:m.start()].strip(" ,;;。、")
# 仅当前缀不全是分隔符/空白时才记录
if prefix and prefix.strip(" ,;;。、"):
desc_lines.append(prefix)
name = m.group(1).strip()
value = m.group(2).strip(" ,;;。、\t") or "-"
if name:
fields.append({"name": name, "value": value, "inline": False})
last_end = m.end()
# 匹配末尾后的文本
suffix = line[last_end:].strip(" ,;;。、")
if suffix and suffix.strip(" ,;;。、"):
desc_lines.append(suffix)
else: else:
description += f"{line}\n" desc_lines.append(line)
description = description.strip() description = "\n".join(desc_lines).strip()
if not description and not fields and text:
description = text.strip()
embed = discord.Embed( embed = discord.Embed(
title=title, title=title,
url=link or "https://github.com/jxxghp/MoviePilot", url=link or "https://github.com/jxxghp/MoviePilot",
description=description if description else (text or None), description=description if description else None,
color=0xE67E22 color=0xE67E22
) )
for field in fields: for field in fields: