nonebot-plugin-parser 2.0.1__tar.gz → 2.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/PKG-INFO +2 -3
  2. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/README.md +1 -2
  3. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/pyproject.toml +2 -2
  4. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/exception.py +9 -0
  5. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/helper.py +1 -2
  6. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/matchers/__init__.py +19 -17
  7. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/data.py +2 -45
  8. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/twitter.py +21 -24
  9. nonebot_plugin_parser-2.0.2/src/nonebot_plugin_parser/renders/base.py +73 -0
  10. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/renders/default.py +7 -1
  11. nonebot_plugin_parser-2.0.1/src/nonebot_plugin_parser/renders/base.py +0 -54
  12. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/__init__.py +0 -0
  13. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/config.py +0 -0
  14. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/constants.py +0 -0
  15. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/download/__init__.py +0 -0
  16. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/download/task.py +0 -0
  17. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/download/ytdlp.py +0 -0
  18. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/matchers/filter.py +0 -0
  19. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/matchers/preprocess.py +0 -0
  20. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/__init__.py +0 -0
  21. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/acfun.py +0 -0
  22. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/base.py +0 -0
  23. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/bilibili/__init__.py +0 -0
  24. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/bilibili/opus.py +0 -0
  25. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/bilibili/video.py +0 -0
  26. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/cookie.py +0 -0
  27. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/douyin/__init__.py +0 -0
  28. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/douyin/slides.py +0 -0
  29. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/douyin/video.py +0 -0
  30. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/kuaishou.py +0 -0
  31. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/nga.py +0 -0
  32. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/tiktok.py +0 -0
  33. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/weibo.py +0 -0
  34. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/xiaohongshu.py +0 -0
  35. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/parsers/youtube.py +0 -0
  36. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/renders/__init__.py +0 -0
  37. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/renders/common.py +0 -0
  38. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/renders/fonts/HYSongYunLangHeiW-1.ttf +0 -0
  39. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/renders/templates/weibo.html.jinja +0 -0
  40. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/renders/weibo.py +0 -0
  41. {nonebot_plugin_parser-2.0.1 → nonebot_plugin_parser-2.0.2}/src/nonebot_plugin_parser/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nonebot-plugin-parser
3
- Version: 2.0.1
3
+ Version: 2.0.2
4
4
  Summary: NoneBot2 链接分享解析器自动解析, BV号/链接/小程序/卡片 | B站/抖音/快手/微博/小红书/youtube/tiktok/twitter/acfun
5
5
  Keywords: nonebot,nonebot2,video,bilibili,youtube,tiktok,twitter,kuaishou,acfun,weibo,xiaohongshu,nga,douyin
6
6
  Author: fllesser
@@ -42,8 +42,7 @@ Description-Content-Type: text/markdown
42
42
  <br/>
43
43
  [![pre-commit](https://results.pre-commit.ci/badge/github/fllesser/nonebot-plugin-parser/master.svg)](https://results.pre-commit.ci/latest/github/fllesser/nonebot-plugin-parser/master)
44
44
  [![codecov](https://codecov.io/gh/fllesser/nonebot-plugin-parser/graph/badge.svg?token=VCS8IHSO7U)](https://codecov.io/gh/fllesser/nonebot-plugin-parser)
45
- [![pepy](https://static.pepy.tech/badge/nonebot-plugin-parser)](https://pepy.tech/projects/nonebot-plugin-parser)
46
-
45
+ [![qqgroup](https://img.shields.io/badge/QQ%E7%BE%A4-820082006-orange?style=flat-square)](https://qm.qq.com/q/y4T4CjHimc)
47
46
  </div>
48
47
 
49
48
  > [!IMPORTANT]
@@ -12,8 +12,7 @@
12
12
  <br/>
13
13
  [![pre-commit](https://results.pre-commit.ci/badge/github/fllesser/nonebot-plugin-parser/master.svg)](https://results.pre-commit.ci/latest/github/fllesser/nonebot-plugin-parser/master)
14
14
  [![codecov](https://codecov.io/gh/fllesser/nonebot-plugin-parser/graph/badge.svg?token=VCS8IHSO7U)](https://codecov.io/gh/fllesser/nonebot-plugin-parser)
15
- [![pepy](https://static.pepy.tech/badge/nonebot-plugin-parser)](https://pepy.tech/projects/nonebot-plugin-parser)
16
-
15
+ [![qqgroup](https://img.shields.io/badge/QQ%E7%BE%A4-820082006-orange?style=flat-square)](https://qm.qq.com/q/y4T4CjHimc)
17
16
  </div>
18
17
 
19
18
  > [!IMPORTANT]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nonebot-plugin-parser"
3
- version = "2.0.1"
3
+ version = "2.0.2"
4
4
  description = "NoneBot2 链接分享解析器自动解析, BV号/链接/小程序/卡片 | B站/抖音/快手/微博/小红书/youtube/tiktok/twitter/acfun"
5
5
  authors = [{ "name" = "fllesser", "email" = "fllessive@gmail.com" }]
6
6
  readme = "README.md"
@@ -185,7 +185,7 @@ build-backend = "uv_build"
185
185
 
186
186
 
187
187
  [tool.bumpversion]
188
- current_version = "2.0.1"
188
+ current_version = "2.0.2"
189
189
  commit = true
190
190
  message = "🔖 release: bump vesion from {current_version} to {new_version}"
191
191
  tag = true
@@ -18,3 +18,12 @@ class DownloadSizeLimitException(DownloadException):
18
18
  def __init__(self):
19
19
  self.message = "媒体大小超过配置限制,取消下载"
20
20
  super().__init__(self.message)
21
+
22
+
23
+ class MultiException(ParseException):
24
+ """多个异常"""
25
+
26
+ def __init__(self, exceptions: list[ParseException]):
27
+ self.exceptions = exceptions
28
+ message = ",".join([e.message for e in exceptions])
29
+ super().__init__(f"[{message}]")
@@ -7,7 +7,6 @@ from nonebot_plugin_alconna.uniseg import Segment, UniMessage, Voice
7
7
  from nonebot_plugin_alconna.uniseg.segment import CustomNode, Reference
8
8
 
9
9
  from .config import pconfig
10
- from .exception import ParseException
11
10
 
12
11
 
13
12
  class UniHelper:
@@ -103,7 +102,7 @@ class UniHelper:
103
102
  # 检测文件大小
104
103
  file_size_byte_count = int(video_path.stat().st_size)
105
104
  if file_size_byte_count == 0:
106
- raise ParseException("视频文件大小为 0")
105
+ return Text("视频文件大小为 0")
107
106
  elif file_size_byte_count > 100 * 1024 * 1024:
108
107
  # 转为文件 Seg
109
108
  return cls.file_seg(video_path, display_name=video_path.name)
@@ -62,15 +62,11 @@ async def _(
62
62
  await _message_reaction(event, "resolving")
63
63
 
64
64
  cache_key = matched.group(0)
65
- if result := RESULT_CACHE.get(cache_key):
66
- logger.debug(f"命中缓存: {cache_key}")
67
- else:
68
- # 获取对应平台 parser
69
- parser = KEYWORD_PARSER_MAP.get(keyword)
70
-
71
- if parser is None:
72
- logger.warning("没有找到对应平台的 Parser")
73
- return
65
+ # 1. 获取缓存结果
66
+ result = RESULT_CACHE.get(cache_key)
67
+ if result is None:
68
+ # 2. 获取对应平台 parser
69
+ parser = KEYWORD_PARSER_MAP[keyword]
74
70
 
75
71
  try:
76
72
  result = await parser.parse(matched)
@@ -78,16 +74,22 @@ async def _(
78
74
  # await UniMessage(str(e)).send()
79
75
  await _message_reaction(event, "fail")
80
76
  raise
81
-
82
- # 缓存解析结果
83
- RESULT_CACHE[cache_key] = result
77
+ else:
78
+ logger.debug(f"命中缓存: {cache_key}, 结果: {result}")
84
79
 
85
80
  # 3. 渲染内容消息并发送
86
- renderer = get_renderer(result.platform.name)
87
- async for message in renderer.render_messages(result):
88
- await message.send()
89
-
90
- # 4. 添加成功的消息响应
81
+ try:
82
+ renderer = get_renderer(result.platform.name)
83
+ async for message in renderer.render_messages(result):
84
+ await message.send()
85
+ except Exception:
86
+ await _message_reaction(event, "fail")
87
+ raise
88
+
89
+ # 4. 无 raise 再缓存解析结果
90
+ RESULT_CACHE[cache_key] = result
91
+
92
+ # 5. 添加成功的消息响应
91
93
  await _message_reaction(event, "done")
92
94
 
93
95
 
@@ -1,13 +1,9 @@
1
1
  from asyncio import Task
2
2
  from dataclasses import dataclass, field
3
3
  from datetime import datetime
4
- from itertools import chain
5
4
  from pathlib import Path
6
5
  from typing import Any
7
6
 
8
- from ..exception import ParseException
9
- from ..helper import Segment, UniHelper, UniMessage
10
-
11
7
 
12
8
  @dataclass(repr=False)
13
9
  class MediaContent:
@@ -137,15 +133,6 @@ class ParseResult:
137
133
  repost: "ParseResult | None" = None
138
134
  """转发的内容"""
139
135
 
140
- def __hash__(self) -> int:
141
- return hash(
142
- (
143
- self.platform.name,
144
- self.timestamp,
145
- self.url,
146
- )
147
- )
148
-
149
136
  @property
150
137
  def header(self) -> str:
151
138
  header = self.platform.display_name
@@ -167,9 +154,6 @@ class ParseResult:
167
154
  def extra_info(self) -> str:
168
155
  return self.extra.get("info", "")
169
156
 
170
- def formart_datetime(self, fmt: str = "%Y-%m-%d %H:%M:%S") -> str:
171
- return datetime.fromtimestamp(self.timestamp).strftime(fmt) if self.timestamp else ""
172
-
173
157
  @property
174
158
  def video_contents(self) -> list[VideoContent]:
175
159
  return [cont for cont in self.contents if isinstance(cont, VideoContent)]
@@ -197,35 +181,8 @@ class ParseResult:
197
181
  return await cont.get_cover_path()
198
182
  return None
199
183
 
200
- async def contents_to_segs(self):
201
- """将内容列表转换为消息段
202
-
203
- Returns:
204
- tuple[list[Segment], list[str | Segment | UniMessage]]: 消息段
205
- separate_segs: 必须单独发送的消息段(视频、语音、文件)
206
- forwardable_segs: 可以合并转发的消息段(文本和图片)
207
- """
208
- separate_segs: list[Segment] = []
209
- forwardable_segs: list[str | Segment | UniMessage] = []
210
-
211
- for cont in chain(self.contents, self.repost.contents if self.repost else ()):
212
- try:
213
- path = await cont.get_path()
214
- match cont:
215
- case VideoContent():
216
- separate_segs.append(UniHelper.video_seg(path))
217
- case ImageContent():
218
- forwardable_segs.append(UniHelper.img_seg(path))
219
- case AudioContent():
220
- separate_segs.append(UniHelper.record_seg(path))
221
- case DynamicContent():
222
- forwardable_segs.append(UniHelper.video_seg(path))
223
- case GraphicsContent(_, text):
224
- forwardable_segs.append(text + UniHelper.img_seg(path))
225
- except ParseException as e:
226
- forwardable_segs.append(e.message)
227
-
228
- return separate_segs, forwardable_segs
184
+ def formart_datetime(self, fmt: str = "%Y-%m-%d %H:%M:%S") -> str:
185
+ return datetime.fromtimestamp(self.timestamp).strftime(fmt) if self.timestamp else ""
229
186
 
230
187
  def __str__(self) -> str:
231
188
  return f"title: {self.title}\nplatform: {self.platform}\nauthor: {self.author}\ncontents: {self.contents}"
@@ -1,3 +1,4 @@
1
+ from itertools import chain
1
2
  import re
2
3
  from typing import Any, ClassVar
3
4
 
@@ -73,41 +74,40 @@ class TwitterParser(BaseParser):
73
74
  from .data import ParseData
74
75
 
75
76
  soup = BeautifulSoup(html_content, "html.parser")
76
- data = ParseData()
77
+ data = ParseData(name="无用户名")
77
78
 
78
79
  # 1. 提取缩略图链接
79
- img_tag = soup.find("img")
80
- if img_tag and isinstance(img_tag, Tag):
81
- src = img_tag.get("src")
82
- if src and isinstance(src, str):
83
- data.cover_url = src
80
+ thumb_tag = soup.find("img")
81
+ if isinstance(thumb_tag, Tag):
82
+ if cover := thumb_tag.get("src"):
83
+ data.cover_url = str(cover)
84
84
 
85
85
  # 2. 提取下载链接
86
- download_links = soup.find_all("a", class_="tw-button-dl")
87
- # class="abutton is-success is-fullwidth btn-premium mt-3"
88
- download_items = soup.find_all("a", class_="abutton")
89
- for link in download_links + download_items:
90
- if isinstance(link, Tag) and (href := link.get("href")) and isinstance(href, str):
91
- href = href
92
- else:
86
+ tw_button_tags = soup.find_all("a", class_="tw-button-dl")
87
+ abutton_tags = soup.find_all("a", class_="abutton")
88
+ for tag in chain(tw_button_tags, abutton_tags):
89
+ if not isinstance(tag, Tag):
90
+ continue
91
+ href = tag.get("href")
92
+ if href is None:
93
93
  continue
94
- text = link.get_text(strip=True)
95
94
 
96
- if "下载图片" in text:
97
- # 从图片下载链接中提取原始图片URL
98
- data.images_urls.append(href)
99
- elif "下载 gif" in text:
100
- data.dynamic_urls.append(href) # GIF和MP4是同一个文件
101
- elif "下载 MP4" in text:
102
- # 从GIF/MP4下载链接中提取原始视频URL
95
+ href = str(href)
96
+ text = tag.get_text(strip=True)
97
+ if "下载 MP4" in text:
103
98
  data.video_url = href
104
99
  break
100
+ elif "下载图片" in text:
101
+ data.images_urls.append(href)
102
+ elif "下载 gif" in text:
103
+ data.dynamic_urls.append(href)
105
104
 
106
105
  # 3. 提取标题
107
106
  title_tag = soup.find("h3")
108
107
  if title_tag:
109
108
  data.title = title_tag.get_text(strip=True)
110
109
 
110
+ return data
111
111
  # # 4. 提取Twitter ID
112
112
  # twitter_id_input = soup.find("input", {"id": "TwitterId"})
113
113
  # if (
@@ -116,6 +116,3 @@ class TwitterParser(BaseParser):
116
116
  # and (value := twitter_id_input.get("value"))
117
117
  # and isinstance(value, str)
118
118
  # ):
119
- data.name = "暂时无法获取用户名"
120
-
121
- return data
@@ -0,0 +1,73 @@
1
+ from abc import ABC, abstractmethod
2
+ from collections.abc import AsyncGenerator
3
+ from itertools import chain
4
+ from pathlib import Path
5
+ from typing import Any, ClassVar
6
+
7
+ from ..exception import MultiException, ParseException
8
+ from ..helper import Segment, UniHelper, UniMessage
9
+ from ..parsers import ParseResult
10
+ from ..parsers.data import AudioContent, DynamicContent, GraphicsContent, ImageContent, VideoContent
11
+
12
+
13
+ class BaseRenderer(ABC):
14
+ """统一的渲染器,将解析结果转换为消息"""
15
+
16
+ templates_dir: ClassVar[Path] = Path(__file__).parent / "templates"
17
+ """模板目录"""
18
+
19
+ @abstractmethod
20
+ async def render_messages(self, result: ParseResult) -> AsyncGenerator[UniMessage[Any], None]:
21
+ """消息生成器
22
+
23
+ Args:
24
+ result (ParseResult): 解析结果
25
+
26
+ Returns:
27
+ AsyncGenerator[UniMessage[Any], None]: 消息生成器
28
+ """
29
+ if False:
30
+ yield
31
+ raise NotImplementedError
32
+
33
+ async def render_contents(self, result: ParseResult) -> AsyncGenerator[UniMessage[Any], None]:
34
+ """渲染媒体内容消息
35
+
36
+ Args:
37
+ result (ParseResult): 解析结果
38
+
39
+ Returns:
40
+ AsyncGenerator[UniMessage[Any], None]: 消息生成器
41
+ """
42
+ raises: list[ParseException] = []
43
+ forwardable_segs: list[str | Segment | UniMessage] = []
44
+ for cont in chain(result.contents, result.repost.contents if result.repost else ()):
45
+ try:
46
+ path = await cont.get_path()
47
+ except ParseException as e:
48
+ forwardable_segs.append(e.message)
49
+ raises.append(e)
50
+ # 继续渲染其他内容
51
+ continue
52
+
53
+ match cont:
54
+ case VideoContent():
55
+ yield UniMessage(UniHelper.video_seg(path))
56
+ case AudioContent():
57
+ yield UniMessage(UniHelper.record_seg(path))
58
+ case ImageContent():
59
+ forwardable_segs.append(UniHelper.img_seg(path))
60
+ case DynamicContent():
61
+ forwardable_segs.append(UniHelper.video_seg(path))
62
+ case GraphicsContent(_, text):
63
+ forwardable_segs.append(text + UniHelper.img_seg(path))
64
+
65
+ if forwardable_segs:
66
+ if all(isinstance(seg, str) for seg in forwardable_segs):
67
+ yield UniMessage(forwardable_segs)
68
+ else:
69
+ forward_msg = UniHelper.construct_forward_message(forwardable_segs)
70
+ yield UniMessage(forward_msg)
71
+
72
+ if raises:
73
+ raise MultiException(raises)
@@ -19,7 +19,13 @@ class DefaultRenderer(BaseRenderer):
19
19
  Generator[UniMessage[Any], None, None]: 消息生成器
20
20
  """
21
21
 
22
- texts: list[str] = [result.header, result.text, result.extra_info, result.display_url]
22
+ texts: list[str] = [
23
+ result.header,
24
+ result.text,
25
+ result.extra_info,
26
+ result.display_url,
27
+ result.repost_display_url,
28
+ ]
23
29
  texts = [text for text in texts if text]
24
30
  texts[:-1] = [seg + "\n" for seg in texts[:-1]]
25
31
 
@@ -1,54 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from collections.abc import AsyncGenerator
3
- from pathlib import Path
4
- from typing import Any, ClassVar
5
-
6
- from ..helper import UniHelper as UniHelper
7
- from ..helper import UniMessage as UniMessage
8
- from ..parsers import ParseResult as ParseResult
9
-
10
-
11
- class BaseRenderer(ABC):
12
- """统一的渲染器,将解析结果转换为消息"""
13
-
14
- templates_dir: ClassVar[Path] = Path(__file__).parent / "templates"
15
- """模板目录"""
16
-
17
- @abstractmethod
18
- async def render_messages(self, result: ParseResult) -> AsyncGenerator[UniMessage[Any], None]:
19
- """消息生成器
20
-
21
- Args:
22
- result (ParseResult): 解析结果
23
-
24
- Returns:
25
- AsyncGenerator[UniMessage[Any], None]: 消息生成器
26
- """
27
- if False:
28
- yield
29
- raise NotImplementedError
30
-
31
- async def render_contents(self, result: ParseResult) -> AsyncGenerator[UniMessage[Any], None]:
32
- """渲染内容消息
33
-
34
- Args:
35
- result (ParseResult): 解析结果
36
-
37
- Returns:
38
- AsyncGenerator[UniMessage[Any], None]: 消息生成器
39
- """
40
- separate_segs, forwardable_segs = await result.contents_to_segs()
41
-
42
- # 处理可以合并转发的消息段
43
- if forwardable_segs:
44
- # 如果只有 str 类型, 则不使用转发消息
45
- if all(isinstance(seg, str) for seg in forwardable_segs):
46
- yield UniMessage(forwardable_segs)
47
- else:
48
- forward_msg = UniHelper.construct_forward_message(forwardable_segs)
49
- yield UniMessage(forward_msg)
50
-
51
- # 处理必须单独发送的消息段
52
- if separate_segs:
53
- for seg in separate_segs:
54
- yield UniMessage(seg)