nonebot-plugin-parser 2.1.1__tar.gz → 2.1.3__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 (55) hide show
  1. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/PKG-INFO +227 -34
  2. nonebot_plugin_parser-2.1.3/README.md +364 -0
  3. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/pyproject.toml +9 -10
  4. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/config.py +13 -2
  5. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/download/__init__.py +12 -11
  6. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/download/ytdlp.py +3 -3
  7. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/helper.py +2 -2
  8. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/matchers/__init__.py +71 -7
  9. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/bilibili/__init__.py +1 -6
  10. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/bilibili/video.py +1 -1
  11. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/common.py +218 -96
  12. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/utils.py +1 -1
  13. nonebot_plugin_parser-2.1.1/README.md +0 -171
  14. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/__init__.py +0 -0
  15. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/constants.py +0 -0
  16. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/download/task.py +0 -0
  17. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/exception.py +0 -0
  18. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/matchers/filter.py +0 -0
  19. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/matchers/rule.py +0 -0
  20. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/__init__.py +0 -0
  21. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/acfun.py +0 -0
  22. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/base.py +0 -0
  23. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/bilibili/article.py +0 -0
  24. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/bilibili/common.py +0 -0
  25. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/bilibili/dynamic.py +0 -0
  26. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/bilibili/favlist.py +0 -0
  27. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/bilibili/live.py +0 -0
  28. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/bilibili/opus.py +0 -0
  29. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/cookie.py +0 -0
  30. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/data.py +0 -0
  31. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/douyin/__init__.py +0 -0
  32. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/douyin/slides.py +0 -0
  33. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/douyin/video.py +0 -0
  34. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/kuaishou.py +0 -0
  35. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/nga.py +0 -0
  36. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/tiktok.py +0 -0
  37. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/twitter.py +0 -0
  38. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/weibo.py +0 -0
  39. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/xiaohongshu.py +0 -0
  40. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/parsers/youtube.py +0 -0
  41. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/__init__.py +0 -0
  42. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/base.py +0 -0
  43. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/default.py +0 -0
  44. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/resources/HYSongYunLangHeiW-1.ttf +0 -0
  45. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/resources/bilibili.png +0 -0
  46. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/resources/douyin.png +0 -0
  47. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/resources/kuaishou.png +0 -0
  48. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/resources/media_button.png +0 -0
  49. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/resources/tiktok.png +0 -0
  50. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/resources/twitter.png +0 -0
  51. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/resources/weibo.png +0 -0
  52. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/resources/xiaohongshu.png +0 -0
  53. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/resources/youtube.png +0 -0
  54. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/templates/weibo.html.jinja +0 -0
  55. {nonebot_plugin_parser-2.1.1 → nonebot_plugin_parser-2.1.3}/src/nonebot_plugin_parser/renders/weibo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nonebot-plugin-parser
3
- Version: 2.1.1
3
+ Version: 2.1.3
4
4
  Summary: NoneBot2 链接分享解析 Alconna 版, 通用媒体卡片渲染(PIL 实现), 支持 B站/抖音/快手/微博/小红书/youtube/tiktok/twitter/acfun/nga
5
5
  Keywords: acfun,bilibili,douyin,kuaishou,nga,nonebot,nonebot2,tiktok,twitter,video,weibo,xiaohongshu,youtube
6
6
  Author: fllesser
@@ -29,12 +29,12 @@ Requires-Dist: nonebot-plugin-localstore>=0.7.4,<1.0.0
29
29
  Requires-Dist: nonebot-plugin-uninfo>=0.10.0
30
30
  Requires-Dist: nonebot2>=2.4.3,<3.0.0
31
31
  Requires-Dist: pillow>=11.0.0
32
- Requires-Dist: pilmoji-for-parser
32
+ Requires-Dist: pilmoji-for-parser>=0.1.0
33
33
  Requires-Dist: tqdm>=4.67.1,<5.0.0
34
34
  Requires-Dist: nonebot-plugin-htmlkit>=0.1.0rc4 ; extra == 'all'
35
- Requires-Dist: yt-dlp>=2025.10.14 ; extra == 'all'
35
+ Requires-Dist: yt-dlp[default]>=2025.11.12 ; extra == 'all'
36
36
  Requires-Dist: nonebot-plugin-htmlkit>=0.1.0rc4 ; extra == 'htmlkit'
37
- Requires-Dist: yt-dlp>=2025.10.14 ; extra == 'ytdlp'
37
+ Requires-Dist: yt-dlp[default]>=2025.11.12 ; extra == 'ytdlp'
38
38
  Requires-Python: >=3.10
39
39
  Project-URL: IssueTracker, https://github.com/fllesser/nonebot-plugin-parser/issues
40
40
  Project-URL: Release, https://github.com/fllesser/nonebot-plugin-parser/releases
@@ -101,7 +101,7 @@ Description-Content-Type: text/markdown
101
101
  > [!Important]
102
102
  > 插件可选依赖 `htmlkit`, `ytdlp`, `all`,分别用于 htmlkit 渲染和 youtube / tiktok 解析,如果需要使用,请在安装时指定,如 `nb plugin install nonebot-plugin-parser[ytdlp]`
103
103
 
104
- <details open>
104
+ <details>
105
105
  <summary>使用 nb-cli 安装/更新</summary>
106
106
  在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
107
107
 
@@ -117,7 +117,7 @@ Description-Content-Type: text/markdown
117
117
  <details>
118
118
  <summary>使用包管理器安装</summary>
119
119
  在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
120
- <details open>
120
+ <details>
121
121
  <summary>uv</summary>
122
122
  使用 uv 安装
123
123
 
@@ -165,7 +165,7 @@ Description-Content-Type: text/markdown
165
165
 
166
166
  </details>
167
167
 
168
- <details open>
168
+ <details>
169
169
  <summary>安装必要组件</summary>
170
170
  部分解析依赖于 ffmpeg
171
171
 
@@ -180,38 +180,231 @@ Windows 参考(原项目推荐): https://www.jianshu.com/p/5015a477de3c
180
180
 
181
181
  ## ⚙️ 配置
182
182
 
183
- 在 nonebot2 项目的`.env`文件中添加下表中的必填配置
184
-
185
- | 配置项 | 必填 | 默认值 | 说明 |
186
- | :--------------------------: | :---: | :----------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
187
- | NICKNAME | 否 | [""] | nonebot2 内置配置,可作为解析结果消息的前缀 |
188
- | API_TIMEOUT | 否 | 30.0 | nonebot2 内置配置,若服务器上传带宽太低,建议调高,防止超时 |
189
- | parser_bili_ck | 否 | "" | B 站 cookie, 必须含有 SESSDATA 项,可附加 B 站 AI 总结功能, 如果需要长期使用此凭据则不应该在**浏览器登录账户**导致 cookie 被刷新,建议注册个小号获取, 也可以配置 ac_time_value 项,用于凭据的自动刷新,[获取方式](https://github.com/fllesser/nonebot-plugin-parser/issues/177) |
190
- | parser_bili_video_codes | 否 | '["avc", "av01", "hev"]' | 允许的 B 站视频编码,越靠前的编码优先级越高,可选 "avc"(H.264,体积较大), "hev"(HEVC), "av01"(AV1), 后两项在不同设备可能有兼容性问题,如需完全避免,可只填一项,如 '["avc"]' |
191
- | parser_ytb_ck | 否 | "" | Youtube cookie, Youtube 视频因人机检测下载失败,需填 |
192
- | parser_proxy | 否 | None | 仅作用于 youtube, tiktok 解析,推特解析会自动读取环境变量中的 http_proxy / https_proxy(代理软件通常会自动设置) |
193
- | parser_need_upload | 否 | False | 音频解析,是否需要上传群文件 |
194
- | parser_use_base64 | 否 | False | 视频,图片,音频是否使用 base64 发送,注意:编解码和传输 base64 会占用更多的内存,性能和带宽, 甚至可能会使 websocket 连接崩溃,因此该配置项仅推荐 nonebot 和 协议端不在同一机器的用户配置 |
195
- | parser_duration_maximum | 否 | 480 | 视频最大解析时长,单位:_秒_ |
196
- | parser_max_size | 否 | 90 | 音视频下载最大文件大小,单位 MB,超过该配置将阻断下载 |
197
- | parser_disabled_platforms | 否 | [] | 全局禁止的解析,示例 parser_disabled_platforms=["bilibili", "douyin"] 表示禁止了哔哩哔哩和抖, 请根据自己需求填写["bilibili", "douyin", "kuaishou", "twitter", "youtube", "acfun", "tiktok", "weibo", "xiaohongshu"] |
198
- | parser_render_type | 否 | "common" | 渲染器类型,可选 "default"(无图片渲染), "common"(PIL 通用图片渲染), "htmlkit"(htmlkit, 暂不可用) |
199
- | parser_append_url | 否 | False | 是否在解析结果中附加原始URL |
200
- | parser_custom_font | 否 | None | 自定义渲染字体,配置字体文件名,并将字体文件放置于 localstore 生成的插件 data 目录下(如 ./data/nonebot_plugin_parser/) |
201
- | parser_need_forward_contents | 否 | True | 是否需要转发媒体内容(超过 4 项时始终使用合并转发) |
202
- ## 🎉 使用
203
- ### 指令表
204
- | 指令 | 权限 | 需要@ | 范围 | 说明 |
205
- | :------: | :-------------------: | :---: | :---: | :------: |
206
- | 开启解析 | SUPERUSER/OWNER/ADMIN | 是 | 群聊 | 开启解析 |
207
- | 关闭解析 | SUPERUSER/OWNER/ADMIN | 是 | 群聊 | 关闭解析 |
183
+ <details>
184
+ <summary>配置项</summary>
185
+
186
+ ```bash
187
+ # [可选] nonebot2 内置配置,若服务器上传带宽太低,建议调高,防止超时
188
+ API_TIMEOUT=30.0
189
+
190
+ # [可选] B cookie, 必须含有 SESSDATA 项,可附加 B 站 AI 总结功能
191
+ # 如果需要长期使用此凭据则不应该在浏览器登录账户导致 cookie 被刷新,建议注册个小号获取
192
+ # 各项获取方式 https://nemo2011.github.io/bilibili-api/#/get-credential
193
+ # ac_time_value 相对特殊,仅用于刷新 Cookies
194
+ # B站网页打开开发者工具,进入控制台,输入 window.localStorage.ac_time_value 即可获取其值。
195
+ parser_bili_ck="SESSDATA=xxxxxxxxxx;ac_time_value=131231241231241"
196
+
197
+ # [可选] 允许的 B 站视频编码,越靠前的编码优先级越高
198
+ # 可选 "avc"(H.264,体积较大), "hev"(HEVC), "av01"(AV1)
199
+ # 后两项在不同设备可能有兼容性问题,如需完全避免,可只填一项,如 '["avc"]'
200
+ parser_bili_video_codes='["avc", "av01", "hev"]'
201
+
202
+ # B 站视频分辨率
203
+ # 360p(16), 480p(32), 720p(64), 1080p(80), 1080p+(112), 1080p_60(116), 4k(120)
204
+ parser_bili_video_quality= 80
205
+
206
+ # [可选] Youtube Cookie, Youtube 视频因人机检测下载失败,需填
207
+ parser_ytb_ck=""
208
+
209
+ # [可选] 代理, 仅作用于 youtube, tiktok 解析
210
+ # 推特解析会自动读取环境变量中的 http_proxy / https_proxy(代理软件通常会自动设置)
211
+ parser_proxy=None
212
+
213
+ # [可选] 音频解析,是否需要上传群文件
214
+ parser_need_upload=False
215
+
216
+ # [可选] 视频,图片,音频是否使用 base64 发送
217
+ # 注意:编解码和传输 base64 会占用更多的内存,性能和带宽, 甚至可能会使 websocket 连接崩溃
218
+ # 因此该配置项仅推荐 nonebot 和 协议端不在同一机器的用户配置
219
+ parser_use_base64=False
220
+
221
+ # [可选] 视频最大解析时长,单位:秒
222
+ parser_duration_maximum=480
223
+
224
+ # [可选] 音视频下载最大文件大小,单位 MB,超过该配置将阻断下载
225
+ parser_max_size=90
226
+
227
+ # [可选] 全局禁止的解析
228
+ # 示例 parser_disabled_platforms=["bilibili", "douyin"] 表示禁止了哔哩哔哩和抖音
229
+ # 可选值: ["bilibili", "douyin", "kuaishou", "twitter", "youtube", "acfun", "tiktok", "weibo", "xiaohongshu"]
230
+ parser_disabled_platforms='["twitter"]'
231
+
232
+ # [可选] 渲染器类型
233
+ # 可选 "default"(无图片渲染), "common"(PIL 通用图片渲染), "htmlkit"(htmlkit, 暂不可用)
234
+ parser_render_type="common"
235
+
236
+ # [可选] 是否在解析结果中附加原始URL
237
+ parser_append_url=False
238
+
239
+ # [可选] 自定义渲染字体
240
+ # 配置字体文件名,并将字体文件放置于 localstore 生成的插件 data 目录下
241
+ # 例如: ./data/nonebot_plugin_parser/
242
+ parser_custom_font="LXGWZhenKaiGB-Regular.ttf"
243
+
244
+ # [可选] 是否需要转发媒体内容(超过 4 项时始终使用合并转发)
245
+ parser_need_forward_contents=True
246
+ ```
247
+
248
+ </details>
249
+
250
+ <details>
251
+ <summary>推荐的字体</summary>
208
252
 
209
- ### 推荐的字体
210
253
  - [LXGW ZhenKai / 霞鹜臻楷](https://github.com/lxgw/LxgwZhenKai) 效果图使用字体
211
254
  - [LXGW Neo XiHei / 霞鹜新晰黑](https://github.com/lxgw/LxgwNeoXiHei)
212
255
  - [LXGW Neo ZhiSong / 霞鹜新致宋 / 霞鶩新緻宋](https://github.com/lxgw/LxgwNeoZhiSong)
256
+ </details>
257
+
258
+ ## 🎉 使用
259
+ | 指令 | 权限 | 需要@ | 范围 | 说明 |
260
+ | :------: | :-------------------: | :---: | :---: | :---------------: |
261
+ | 开启解析 | SUPERUSER/OWNER/ADMIN | 是 | 群聊 | 开启解析 |
262
+ | 关闭解析 | SUPERUSER/OWNER/ADMIN | 是 | 群聊 | 关闭解析 |
263
+ | bm | - | 否 | 群聊 | 下载 B 站音频 |
264
+ | ym | - | 否 | 群聊 | 下载 youtube 音频 |
265
+
266
+ ## 🧩 扩展
267
+ > [!IMPORTANT]
268
+ > 插件自 `v2.1.1` 版本开始支持自定义解析器,通过继承 `BaseParser` 类并实现 `platform`, `patterns`, `parse` 即可
269
+ <details>
270
+ <summary>完整示例</summary>
271
+
272
+ ```python
273
+ from re import Match
274
+ from typing import ClassVar
275
+
276
+ from httpx import AsyncClient
277
+ from nonebot import require
278
+
279
+ require("nonebot_plugin_parser")
280
+ from nonebot_plugin_parser.parsers import BaseParser, ParseResult
281
+ from nonebot_plugin_parser.parsers.base import Platform
282
+
283
+
284
+ class ExampleParser(BaseParser):
285
+ """示例视频网站解析器"""
286
+
287
+ platform: ClassVar[Platform] = Platform(name="example", display_name="示例网站")
288
+
289
+ patterns: ClassVar[list[tuple[str, str]]] = [
290
+ ("example.com", r"example\.com/video/(?P<video_id>\w+)"),
291
+ ("ex.short", r"ex\.short/(?P<short_id>\w+)"),
292
+ ]
293
+
294
+ async def parse(self, keyword: str, searched: Match[str]) -> ParseResult:
295
+ # 1. 提取视频 ID
296
+ if keyword == "ex.short":
297
+ # 处理短链接
298
+ short_id = searched.group("short_id")
299
+ full_url = await self.get_redirect_url(f"https://ex.short/{short_id}")
300
+ video_id = full_url.split("/")[-1]
301
+ else:
302
+ video_id = searched.group("video_id")
303
+
304
+ # 2. 请求 API 获取视频信息
305
+ async with AsyncClient(headers=self.headers, timeout=self.timeout) as client:
306
+ resp = await client.get(f"https://api.example.com/video/{video_id}")
307
+ resp.raise_for_status()
308
+ data = resp.json()
309
+
310
+ # 3. 提取数据
311
+ title = data["title"]
312
+ author_name = data["author"]["name"]
313
+ avatar_url = data["author"]["avatar"]
314
+ video_url = data["video_url"]
315
+ cover_url = data["cover_url"]
316
+ duration = data["duration"]
317
+ timestamp = data["publish_time"]
318
+ description = data.get("description", "")
319
+
320
+ # 4. 视频内容
321
+ author = self.create_author(author_name, avatar_url)
322
+ video = self.create_video_content(video_url, cover_url, duration)
323
+
324
+ # 5. 图集内容
325
+ image_urls = data.get("images")
326
+ images = self.create_image_contents(image_urls)
327
+
328
+ # 6. 返回解析结果
329
+ return self.result(
330
+ title=title,
331
+ text=description,
332
+ author=author,
333
+ contents=[video, *images],
334
+ timestamp=timestamp,
335
+ url=f"https://example.com/video/{video_id}",
336
+ )
337
+
338
+ ```
339
+ </details>
340
+ <details>
341
+ <summary>辅助函数</summary>
342
+
343
+ > 构建作者信息
344
+
345
+ ```python
346
+ author = self.create_author(
347
+ name="作者名",
348
+ avatar_url="https://example.com/avatar.jpg", # 可选,会自动下载
349
+ description="个性签名" # 可选
350
+ )
351
+ ```
352
+
353
+ > 构建视频内容
354
+ ```python
355
+ # 方式1:传入 URL,自动下载
356
+ video = self.create_video_content(
357
+ url_or_task="https://example.com/video.mp4",
358
+ cover_url="https://example.com/cover.jpg", # 可选
359
+ duration=120.5 # 可选,单位:秒
360
+ )
361
+
362
+ # 方式2:传入已创建的下载任务
363
+ from nonebot_plugin_parser.download import DOWNLOADER
364
+ video_task = DOWNLOADER.download_video(url, ext_headers=self.headers)
365
+ video = self.create_video_content(
366
+ url_or_task=video_task,
367
+ cover_url=cover_url,
368
+ duration=duration
369
+ )
370
+ ```
371
+
372
+ > 构建图集内容
373
+ ```python
374
+ # 并发下载图集内容
375
+ images = self.create_image_contents([
376
+ "https://example.com/img1.jpg",
377
+ "https://example.com/img2.jpg",
378
+ ])
379
+ ```
380
+
381
+ > 构建图文内容(适用于类似 Bilibili 动态图文混排)
382
+ ```python
383
+ graphics = self.create_graphics_content(
384
+ image_url="https://example.com/image.jpg",
385
+ text="图片前的文字说明", # 可选
386
+ alt="图片描述" # 可选,居中显示
387
+ )
388
+ ```
389
+
390
+ > 创建动图内容(GIF),平台一般只提供视频(后续插件会做自动转为 gif 的处理)
391
+ ```python
392
+ dynamics = self.create_dynamic_contents([
393
+ "https://example.com/dynamic1.mp4",
394
+ "https://example.com/dynamic2.mp4",
395
+ ])
396
+ ```
397
+ > 重定向 url
398
+ ```python
399
+ real_url = await self.get_redirect_url(
400
+ url="https://short.url/abc",
401
+ headers=self.headers # 可选
402
+ )
403
+ ```
404
+
405
+ </details>
213
406
 
214
407
 
215
- ## 致谢
408
+ ## 🎉 致谢
216
409
  [nonebot-plugin-resolver](https://github.com/zhiyu1998/nonebot-plugin-resolver)
217
410
  [parse-video-py](https://github.com/wujunwei928/parse-video-py)
@@ -0,0 +1,364 @@
1
+ <div align="center">
2
+ <a href="https://v2.nonebot.dev/store">
3
+ <img src="https://raw.githubusercontent.com/fllesser/nonebot-plugin-template/refs/heads/resource/.docs/NoneBotPlugin.svg" width="310" alt="logo">
4
+ </a>
5
+
6
+ ## ✨ [Nonebot2](https://github.com/nonebot/nonebot2) 链接分享自动解析插件 ✨
7
+ [![LICENSE](https://img.shields.io/github/license/fllesser/nonebot-plugin-parser.svg)](./LICENSE)
8
+ [![pypi](https://img.shields.io/pypi/v/nonebot-plugin-parser.svg)](https://pypi.python.org/pypi/nonebot-plugin-parser)
9
+ [![python](https://img.shields.io/badge/python-3.10|3.11|3.12|3.13-blue.svg)](https://python.org)
10
+ [![uv](https://img.shields.io/badge/package%20manager-uv-black?style=flat-square&logo=uv)](https://github.com/astral-sh/uv)
11
+ [![ruff](https://img.shields.io/badge/code%20style-ruff-black?style=flat-square&logo=ruff)](https://github.com/astral-sh/ruff)
12
+ <br/>
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
+ [![codecov](https://codecov.io/gh/fllesser/nonebot-plugin-parser/graph/badge.svg?token=VCS8IHSO7U)](https://codecov.io/gh/fllesser/nonebot-plugin-parser)
15
+ [![qqgroup](https://img.shields.io/badge/QQ%E7%BE%A4-820082006-orange?style=flat-square)](https://qm.qq.com/q/y4T4CjHimc)
16
+ </div>
17
+
18
+ > [!IMPORTANT]
19
+ > **收藏项目**,你将从 GitHub 上无延迟地接收所有发布通知~⭐️
20
+
21
+ <img width="100%" src="https://starify.komoridevs.icu/api/starify?owner=fllesser&repo=nonebot-plugin-parser" alt="starify" />
22
+
23
+ ## 📖 介绍
24
+
25
+ | 平台 | 触发的消息形态 | 视频 | 图集 | 音频 |
26
+ | ------- | ------------------------------------- | ---- | ---- | ---- |
27
+ | B站 | BV号/链接(包含短链,BV,av)/卡片/小程序 | ✅​ | ✅​ | ✅​ |
28
+ | 抖音 | 链接(分享链接,兼容电脑端链接) | ✅​ | ✅​ | ❌️ |
29
+ | 微博 | 链接(博文,视频,show) | ✅​ | ✅​ | ❌️ |
30
+ | 小红书 | 链接(含短链)/卡片 | ✅​ | ✅​ | ❌️ |
31
+ | 快手 | 链接(包含标准链接和短链) | ✅​ | ✅​ | ❌️ |
32
+ | acfun | 链接 | ✅​ | ❌️ | ❌️ |
33
+ | youtube | 链接(含短链) | ✅​ | ❌️ | ✅​ |
34
+ | tiktok | 链接 | ✅​ | ❌️ | ❌️ |
35
+ | twitter | 链接 | ✅​ | ✅​ | ❌️ |
36
+
37
+ 支持的链接,可参考 [测试链接](https://github.com/fllesser/nonebot-plugin-parser/blob/master/test_url.md)
38
+
39
+ ## 🎨 效果图
40
+ 插件默认启用 PIL 实现的通用媒体卡片渲染,效果图如下
41
+ <div align="center">
42
+
43
+ <img src="https://raw.githubusercontent.com/fllesser/nonebot-plugin-parser/refs/heads/resources/resources/renderdamine/video.png" width="160" />
44
+ <img src="https://raw.githubusercontent.com/fllesser/nonebot-plugin-parser/refs/heads/resources/resources/renderdamine/9_pic.png" width="160" />
45
+ <img src="https://raw.githubusercontent.com/fllesser/nonebot-plugin-parser/refs/heads/resources/resources/renderdamine/4_pic.png" width="160" />
46
+ <img src="https://raw.githubusercontent.com/fllesser/nonebot-plugin-parser/refs/heads/resources/resources/renderdamine/repost_video.png" width="160" />
47
+ <img src="https://raw.githubusercontent.com/fllesser/nonebot-plugin-parser/refs/heads/resources/resources/renderdamine/repost_2_pic.png" width="160" />
48
+
49
+ </div>
50
+
51
+ ## 💿 安装
52
+ > [!Warning]
53
+ > **如果你已经在使用 nonebot-plugin-resolver[2],请在安装此插件前卸载**
54
+
55
+ > [!Important]
56
+ > 插件可选依赖 `htmlkit`, `ytdlp`, `all`,分别用于 htmlkit 渲染和 youtube / tiktok 解析,如果需要使用,请在安装时指定,如 `nb plugin install nonebot-plugin-parser[ytdlp]`
57
+
58
+ <details>
59
+ <summary>使用 nb-cli 安装/更新</summary>
60
+ 在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
61
+
62
+ nb plugin install nonebot-plugin-parser --upgrade
63
+ 使用 pypi 源更新
64
+
65
+ nb plugin install nonebot-plugin-parser --upgrade -i https://pypi.org/simple
66
+ 安装仓库 dev 分支
67
+
68
+ uv pip install git+https://github.com/fllesser/nonebot-plugin-parser.git@dev
69
+ </details>
70
+
71
+ <details>
72
+ <summary>使用包管理器安装</summary>
73
+ 在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
74
+ <details>
75
+ <summary>uv</summary>
76
+ 使用 uv 安装
77
+
78
+ uv add nonebot-plugin-parser
79
+ 安装仓库 dev 分支
80
+
81
+ uv add git+https://github.com/fllesser/nonebot-plugin-parser.git@master
82
+ </details>
83
+
84
+
85
+ <details>
86
+ <summary>pip</summary>
87
+
88
+ pip install --upgrade nonebot-plugin-parser
89
+ </details>
90
+ <details>
91
+ <summary>pdm</summary>
92
+
93
+ pdm add nonebot-plugin-parser
94
+ </details>
95
+ <details>
96
+ <summary>poetry</summary>
97
+
98
+ poetry add nonebot-plugin-parser
99
+ </details>
100
+
101
+ 打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
102
+
103
+ plugins = ["nonebot_plugin_parser"]
104
+
105
+ </details>
106
+
107
+ <details>
108
+ <summary>使用 nbr 安装(使用 uv 管理依赖可用)</summary>
109
+
110
+ [nbr](https://github.com/fllesser/nbr) 是一个基于 uv 的 nb-cli,可以方便地管理 nonebot2
111
+
112
+ nbr plugin install nonebot-plugin-parser
113
+ 使用 **pypi** 源安装
114
+
115
+ nbr plugin install nonebot-plugin-parser -i "https://pypi.org/simple"
116
+ 使用**清华源**安装
117
+
118
+ nbr plugin install nonebot-plugin-parser -i "https://pypi.tuna.tsinghua.edu.cn/simple"
119
+
120
+ </details>
121
+
122
+ <details>
123
+ <summary>安装必要组件</summary>
124
+ 部分解析依赖于 ffmpeg
125
+
126
+ ubuntu/debian
127
+
128
+ sudo apt-get install ffmpeg
129
+
130
+ 其他 linux 参考(原项目推荐): https://gitee.com/baihu433/ffmpeg
131
+
132
+ Windows 参考(原项目推荐): https://www.jianshu.com/p/5015a477de3c
133
+ </details>
134
+
135
+ ## ⚙️ 配置
136
+
137
+ <details>
138
+ <summary>配置项</summary>
139
+
140
+ ```bash
141
+ # [可选] nonebot2 内置配置,若服务器上传带宽太低,建议调高,防止超时
142
+ API_TIMEOUT=30.0
143
+
144
+ # [可选] B 站 cookie, 必须含有 SESSDATA 项,可附加 B 站 AI 总结功能
145
+ # 如果需要长期使用此凭据则不应该在浏览器登录账户导致 cookie 被刷新,建议注册个小号获取
146
+ # 各项获取方式 https://nemo2011.github.io/bilibili-api/#/get-credential
147
+ # ac_time_value 相对特殊,仅用于刷新 Cookies
148
+ # B站网页打开开发者工具,进入控制台,输入 window.localStorage.ac_time_value 即可获取其值。
149
+ parser_bili_ck="SESSDATA=xxxxxxxxxx;ac_time_value=131231241231241"
150
+
151
+ # [可选] 允许的 B 站视频编码,越靠前的编码优先级越高
152
+ # 可选 "avc"(H.264,体积较大), "hev"(HEVC), "av01"(AV1)
153
+ # 后两项在不同设备可能有兼容性问题,如需完全避免,可只填一项,如 '["avc"]'
154
+ parser_bili_video_codes='["avc", "av01", "hev"]'
155
+
156
+ # B 站视频分辨率
157
+ # 360p(16), 480p(32), 720p(64), 1080p(80), 1080p+(112), 1080p_60(116), 4k(120)
158
+ parser_bili_video_quality= 80
159
+
160
+ # [可选] Youtube Cookie, Youtube 视频因人机检测下载失败,需填
161
+ parser_ytb_ck=""
162
+
163
+ # [可选] 代理, 仅作用于 youtube, tiktok 解析
164
+ # 推特解析会自动读取环境变量中的 http_proxy / https_proxy(代理软件通常会自动设置)
165
+ parser_proxy=None
166
+
167
+ # [可选] 音频解析,是否需要上传群文件
168
+ parser_need_upload=False
169
+
170
+ # [可选] 视频,图片,音频是否使用 base64 发送
171
+ # 注意:编解码和传输 base64 会占用更多的内存,性能和带宽, 甚至可能会使 websocket 连接崩溃
172
+ # 因此该配置项仅推荐 nonebot 和 协议端不在同一机器的用户配置
173
+ parser_use_base64=False
174
+
175
+ # [可选] 视频最大解析时长,单位:秒
176
+ parser_duration_maximum=480
177
+
178
+ # [可选] 音视频下载最大文件大小,单位 MB,超过该配置将阻断下载
179
+ parser_max_size=90
180
+
181
+ # [可选] 全局禁止的解析
182
+ # 示例 parser_disabled_platforms=["bilibili", "douyin"] 表示禁止了哔哩哔哩和抖音
183
+ # 可选值: ["bilibili", "douyin", "kuaishou", "twitter", "youtube", "acfun", "tiktok", "weibo", "xiaohongshu"]
184
+ parser_disabled_platforms='["twitter"]'
185
+
186
+ # [可选] 渲染器类型
187
+ # 可选 "default"(无图片渲染), "common"(PIL 通用图片渲染), "htmlkit"(htmlkit, 暂不可用)
188
+ parser_render_type="common"
189
+
190
+ # [可选] 是否在解析结果中附加原始URL
191
+ parser_append_url=False
192
+
193
+ # [可选] 自定义渲染字体
194
+ # 配置字体文件名,并将字体文件放置于 localstore 生成的插件 data 目录下
195
+ # 例如: ./data/nonebot_plugin_parser/
196
+ parser_custom_font="LXGWZhenKaiGB-Regular.ttf"
197
+
198
+ # [可选] 是否需要转发媒体内容(超过 4 项时始终使用合并转发)
199
+ parser_need_forward_contents=True
200
+ ```
201
+
202
+ </details>
203
+
204
+ <details>
205
+ <summary>推荐的字体</summary>
206
+
207
+ - [LXGW ZhenKai / 霞鹜臻楷](https://github.com/lxgw/LxgwZhenKai) 效果图使用字体
208
+ - [LXGW Neo XiHei / 霞鹜新晰黑](https://github.com/lxgw/LxgwNeoXiHei)
209
+ - [LXGW Neo ZhiSong / 霞鹜新致宋 / 霞鶩新緻宋](https://github.com/lxgw/LxgwNeoZhiSong)
210
+ </details>
211
+
212
+ ## 🎉 使用
213
+ | 指令 | 权限 | 需要@ | 范围 | 说明 |
214
+ | :------: | :-------------------: | :---: | :---: | :---------------: |
215
+ | 开启解析 | SUPERUSER/OWNER/ADMIN | 是 | 群聊 | 开启解析 |
216
+ | 关闭解析 | SUPERUSER/OWNER/ADMIN | 是 | 群聊 | 关闭解析 |
217
+ | bm | - | 否 | 群聊 | 下载 B 站音频 |
218
+ | ym | - | 否 | 群聊 | 下载 youtube 音频 |
219
+
220
+ ## 🧩 扩展
221
+ > [!IMPORTANT]
222
+ > 插件自 `v2.1.1` 版本开始支持自定义解析器,通过继承 `BaseParser` 类并实现 `platform`, `patterns`, `parse` 即可
223
+ <details>
224
+ <summary>完整示例</summary>
225
+
226
+ ```python
227
+ from re import Match
228
+ from typing import ClassVar
229
+
230
+ from httpx import AsyncClient
231
+ from nonebot import require
232
+
233
+ require("nonebot_plugin_parser")
234
+ from nonebot_plugin_parser.parsers import BaseParser, ParseResult
235
+ from nonebot_plugin_parser.parsers.base import Platform
236
+
237
+
238
+ class ExampleParser(BaseParser):
239
+ """示例视频网站解析器"""
240
+
241
+ platform: ClassVar[Platform] = Platform(name="example", display_name="示例网站")
242
+
243
+ patterns: ClassVar[list[tuple[str, str]]] = [
244
+ ("example.com", r"example\.com/video/(?P<video_id>\w+)"),
245
+ ("ex.short", r"ex\.short/(?P<short_id>\w+)"),
246
+ ]
247
+
248
+ async def parse(self, keyword: str, searched: Match[str]) -> ParseResult:
249
+ # 1. 提取视频 ID
250
+ if keyword == "ex.short":
251
+ # 处理短链接
252
+ short_id = searched.group("short_id")
253
+ full_url = await self.get_redirect_url(f"https://ex.short/{short_id}")
254
+ video_id = full_url.split("/")[-1]
255
+ else:
256
+ video_id = searched.group("video_id")
257
+
258
+ # 2. 请求 API 获取视频信息
259
+ async with AsyncClient(headers=self.headers, timeout=self.timeout) as client:
260
+ resp = await client.get(f"https://api.example.com/video/{video_id}")
261
+ resp.raise_for_status()
262
+ data = resp.json()
263
+
264
+ # 3. 提取数据
265
+ title = data["title"]
266
+ author_name = data["author"]["name"]
267
+ avatar_url = data["author"]["avatar"]
268
+ video_url = data["video_url"]
269
+ cover_url = data["cover_url"]
270
+ duration = data["duration"]
271
+ timestamp = data["publish_time"]
272
+ description = data.get("description", "")
273
+
274
+ # 4. 视频内容
275
+ author = self.create_author(author_name, avatar_url)
276
+ video = self.create_video_content(video_url, cover_url, duration)
277
+
278
+ # 5. 图集内容
279
+ image_urls = data.get("images")
280
+ images = self.create_image_contents(image_urls)
281
+
282
+ # 6. 返回解析结果
283
+ return self.result(
284
+ title=title,
285
+ text=description,
286
+ author=author,
287
+ contents=[video, *images],
288
+ timestamp=timestamp,
289
+ url=f"https://example.com/video/{video_id}",
290
+ )
291
+
292
+ ```
293
+ </details>
294
+ <details>
295
+ <summary>辅助函数</summary>
296
+
297
+ > 构建作者信息
298
+
299
+ ```python
300
+ author = self.create_author(
301
+ name="作者名",
302
+ avatar_url="https://example.com/avatar.jpg", # 可选,会自动下载
303
+ description="个性签名" # 可选
304
+ )
305
+ ```
306
+
307
+ > 构建视频内容
308
+ ```python
309
+ # 方式1:传入 URL,自动下载
310
+ video = self.create_video_content(
311
+ url_or_task="https://example.com/video.mp4",
312
+ cover_url="https://example.com/cover.jpg", # 可选
313
+ duration=120.5 # 可选,单位:秒
314
+ )
315
+
316
+ # 方式2:传入已创建的下载任务
317
+ from nonebot_plugin_parser.download import DOWNLOADER
318
+ video_task = DOWNLOADER.download_video(url, ext_headers=self.headers)
319
+ video = self.create_video_content(
320
+ url_or_task=video_task,
321
+ cover_url=cover_url,
322
+ duration=duration
323
+ )
324
+ ```
325
+
326
+ > 构建图集内容
327
+ ```python
328
+ # 并发下载图集内容
329
+ images = self.create_image_contents([
330
+ "https://example.com/img1.jpg",
331
+ "https://example.com/img2.jpg",
332
+ ])
333
+ ```
334
+
335
+ > 构建图文内容(适用于类似 Bilibili 动态图文混排)
336
+ ```python
337
+ graphics = self.create_graphics_content(
338
+ image_url="https://example.com/image.jpg",
339
+ text="图片前的文字说明", # 可选
340
+ alt="图片描述" # 可选,居中显示
341
+ )
342
+ ```
343
+
344
+ > 创建动图内容(GIF),平台一般只提供视频(后续插件会做自动转为 gif 的处理)
345
+ ```python
346
+ dynamics = self.create_dynamic_contents([
347
+ "https://example.com/dynamic1.mp4",
348
+ "https://example.com/dynamic2.mp4",
349
+ ])
350
+ ```
351
+ > 重定向 url
352
+ ```python
353
+ real_url = await self.get_redirect_url(
354
+ url="https://short.url/abc",
355
+ headers=self.headers # 可选
356
+ )
357
+ ```
358
+
359
+ </details>
360
+
361
+
362
+ ## 🎉 致谢
363
+ [nonebot-plugin-resolver](https://github.com/zhiyu1998/nonebot-plugin-resolver)
364
+ [parse-video-py](https://github.com/wujunwei928/parse-video-py)