nonebot-plugin-parser 2.1.0__tar.gz → 2.1.1__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.
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/PKG-INFO +35 -15
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/README.md +4 -1
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/pyproject.toml +123 -121
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/config.py +4 -8
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/constants.py +17 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/download/__init__.py +12 -8
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/download/task.py +2 -2
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/download/ytdlp.py +2 -3
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/matchers/__init__.py +25 -29
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/matchers/filter.py +1 -1
- nonebot_plugin_parser-2.1.0/src/nonebot_plugin_parser/matchers/preprocess.py → nonebot_plugin_parser-2.1.1/src/nonebot_plugin_parser/matchers/rule.py +37 -46
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/__init__.py +6 -2
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/acfun.py +4 -18
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/base.py +55 -19
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/bilibili/__init__.py +22 -32
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/bilibili/dynamic.py +5 -6
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/douyin/__init__.py +12 -13
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/douyin/video.py +1 -1
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/kuaishou.py +9 -21
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/nga.py +7 -18
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/tiktok.py +5 -16
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/twitter.py +6 -17
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/weibo.py +16 -28
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/xiaohongshu.py +12 -25
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/youtube.py +8 -8
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/__init__.py +6 -9
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/common.py +288 -231
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/__init__.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/exception.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/helper.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/bilibili/article.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/bilibili/common.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/bilibili/favlist.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/bilibili/live.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/bilibili/opus.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/bilibili/video.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/cookie.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/data.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/parsers/douyin/slides.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/base.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/default.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/resources/HYSongYunLangHeiW-1.ttf +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/resources/bilibili.png +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/resources/douyin.png +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/resources/kuaishou.png +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/resources/media_button.png +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/resources/tiktok.png +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/resources/twitter.png +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/resources/weibo.png +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/resources/xiaohongshu.png +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/resources/youtube.png +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/templates/weibo.html.jinja +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/renders/weibo.py +0 -0
- {nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/utils.py +0 -0
|
@@ -1,30 +1,47 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: nonebot-plugin-parser
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.1
|
|
4
4
|
Summary: NoneBot2 链接分享解析 Alconna 版, 通用媒体卡片渲染(PIL 实现), 支持 B站/抖音/快手/微博/小红书/youtube/tiktok/twitter/acfun/nga
|
|
5
|
-
Keywords:
|
|
5
|
+
Keywords: acfun,bilibili,douyin,kuaishou,nga,nonebot,nonebot2,tiktok,twitter,video,weibo,xiaohongshu,youtube
|
|
6
6
|
Author: fllesser
|
|
7
7
|
Author-email: fllesser <fllessive@gmail.com>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Framework :: AsyncIO
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Communications :: Chat
|
|
18
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
19
|
+
Classifier: Topic :: Multimedia :: Video
|
|
11
20
|
Requires-Dist: aiofiles>=25.1.0
|
|
12
|
-
Requires-Dist: pillow>=11.0.0
|
|
13
|
-
Requires-Dist: curl-cffi>=0.13.0,<1.0.0
|
|
14
|
-
Requires-Dist: bilibili-api-python>=17.4.0,<18.0.0
|
|
15
21
|
Requires-Dist: beautifulsoup4>=4.12.0,<5.0.0
|
|
16
|
-
Requires-Dist:
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist:
|
|
19
|
-
Requires-Dist:
|
|
22
|
+
Requires-Dist: bilibili-api-python>=17.4.0,<18.0.0
|
|
23
|
+
Requires-Dist: curl-cffi>=0.13.0,<1.0.0
|
|
24
|
+
Requires-Dist: httpx>=0.27.2,<1.0.0
|
|
25
|
+
Requires-Dist: msgspec>=0.19.0,<1.0.0
|
|
20
26
|
Requires-Dist: nonebot-plugin-alconna>=0.59.4
|
|
21
|
-
Requires-Dist: nonebot-plugin-
|
|
22
|
-
Requires-Dist: nonebot-plugin-
|
|
27
|
+
Requires-Dist: nonebot-plugin-apscheduler>=0.5.0,<1.0.0
|
|
28
|
+
Requires-Dist: nonebot-plugin-localstore>=0.7.4,<1.0.0
|
|
29
|
+
Requires-Dist: nonebot-plugin-uninfo>=0.10.0
|
|
30
|
+
Requires-Dist: nonebot2>=2.4.3,<3.0.0
|
|
31
|
+
Requires-Dist: pillow>=11.0.0
|
|
32
|
+
Requires-Dist: pilmoji-for-parser
|
|
33
|
+
Requires-Dist: tqdm>=4.67.1,<5.0.0
|
|
34
|
+
Requires-Dist: nonebot-plugin-htmlkit>=0.1.0rc4 ; extra == 'all'
|
|
35
|
+
Requires-Dist: yt-dlp>=2025.10.14 ; extra == 'all'
|
|
36
|
+
Requires-Dist: nonebot-plugin-htmlkit>=0.1.0rc4 ; extra == 'htmlkit'
|
|
37
|
+
Requires-Dist: yt-dlp>=2025.10.14 ; extra == 'ytdlp'
|
|
23
38
|
Requires-Python: >=3.10
|
|
24
39
|
Project-URL: IssueTracker, https://github.com/fllesser/nonebot-plugin-parser/issues
|
|
25
40
|
Project-URL: Release, https://github.com/fllesser/nonebot-plugin-parser/releases
|
|
26
41
|
Project-URL: Repository, https://github.com/fllesser/nonebot-plugin-parser
|
|
42
|
+
Provides-Extra: all
|
|
27
43
|
Provides-Extra: htmlkit
|
|
44
|
+
Provides-Extra: ytdlp
|
|
28
45
|
Description-Content-Type: text/markdown
|
|
29
46
|
|
|
30
47
|
<div align="center">
|
|
@@ -80,7 +97,10 @@ Description-Content-Type: text/markdown
|
|
|
80
97
|
## 💿 安装
|
|
81
98
|
> [!Warning]
|
|
82
99
|
> **如果你已经在使用 nonebot-plugin-resolver[2],请在安装此插件前卸载**
|
|
83
|
-
|
|
100
|
+
|
|
101
|
+
> [!Important]
|
|
102
|
+
> 插件可选依赖 `htmlkit`, `ytdlp`, `all`,分别用于 htmlkit 渲染和 youtube / tiktok 解析,如果需要使用,请在安装时指定,如 `nb plugin install nonebot-plugin-parser[ytdlp]`
|
|
103
|
+
|
|
84
104
|
<details open>
|
|
85
105
|
<summary>使用 nb-cli 安装/更新</summary>
|
|
86
106
|
在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
|
|
@@ -51,7 +51,10 @@
|
|
|
51
51
|
## 💿 安装
|
|
52
52
|
> [!Warning]
|
|
53
53
|
> **如果你已经在使用 nonebot-plugin-resolver[2],请在安装此插件前卸载**
|
|
54
|
-
|
|
54
|
+
|
|
55
|
+
> [!Important]
|
|
56
|
+
> 插件可选依赖 `htmlkit`, `ytdlp`, `all`,分别用于 htmlkit 渲染和 youtube / tiktok 解析,如果需要使用,请在安装时指定,如 `nb plugin install nonebot-plugin-parser[ytdlp]`
|
|
57
|
+
|
|
55
58
|
<details open>
|
|
56
59
|
<summary>使用 nb-cli 安装/更新</summary>
|
|
57
60
|
在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
|
|
@@ -1,87 +1,112 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "nonebot-plugin-parser"
|
|
3
|
-
version = "2.1.
|
|
3
|
+
version = "2.1.1"
|
|
4
4
|
description = "NoneBot2 链接分享解析 Alconna 版, 通用媒体卡片渲染(PIL 实现), 支持 B站/抖音/快手/微博/小红书/youtube/tiktok/twitter/acfun/nga"
|
|
5
|
-
authors = [{ "name" = "fllesser", "email" = "fllessive@gmail.com" }]
|
|
6
5
|
readme = "README.md"
|
|
7
6
|
requires-python = ">=3.10"
|
|
7
|
+
authors = [{ "name" = "fllesser", "email" = "fllessive@gmail.com" }]
|
|
8
8
|
keywords = [
|
|
9
|
+
"acfun",
|
|
10
|
+
"bilibili",
|
|
11
|
+
"douyin",
|
|
12
|
+
"kuaishou",
|
|
13
|
+
"nga",
|
|
9
14
|
"nonebot",
|
|
10
15
|
"nonebot2",
|
|
11
|
-
"video",
|
|
12
|
-
"bilibili",
|
|
13
|
-
"youtube",
|
|
14
16
|
"tiktok",
|
|
15
17
|
"twitter",
|
|
16
|
-
"
|
|
17
|
-
"acfun",
|
|
18
|
+
"video",
|
|
18
19
|
"weibo",
|
|
19
20
|
"xiaohongshu",
|
|
20
|
-
"
|
|
21
|
-
|
|
21
|
+
"youtube"
|
|
22
|
+
]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 5 - Production/Stable",
|
|
25
|
+
"Framework :: AsyncIO",
|
|
26
|
+
"License :: OSI Approved :: MIT License",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Topic :: Communications :: Chat",
|
|
34
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
35
|
+
"Topic :: Multimedia :: Video",
|
|
22
36
|
]
|
|
23
37
|
dependencies = [
|
|
24
|
-
"msgspec>=0.19.0,<1.0.0",
|
|
25
|
-
"httpx>=0.27.2,<1.0.0",
|
|
26
|
-
"tqdm>=4.67.1,<5.0.0",
|
|
27
38
|
"aiofiles>=25.1.0",
|
|
28
|
-
"pillow>=11.0.0",
|
|
29
|
-
|
|
30
|
-
# 后续改为可选依赖
|
|
31
|
-
"curl_cffi>=0.13.0,<1.0.0",
|
|
32
|
-
"bilibili-api-python>=17.4.0,<18.0.0",
|
|
33
39
|
"beautifulsoup4>=4.12.0,<5.0.0",
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"nonebot-plugin-apscheduler>=0.5.0,<1.0.0",
|
|
40
|
+
"bilibili-api-python>=17.4.0,<18.0.0",
|
|
41
|
+
"curl_cffi>=0.13.0,<1.0.0",
|
|
42
|
+
"httpx>=0.27.2,<1.0.0",
|
|
43
|
+
"msgspec>=0.19.0,<1.0.0",
|
|
39
44
|
"nonebot-plugin-alconna>=0.59.4",
|
|
40
|
-
"nonebot-plugin-
|
|
45
|
+
"nonebot-plugin-apscheduler>=0.5.0,<1.0.0",
|
|
46
|
+
"nonebot-plugin-localstore>=0.7.4,<1.0.0",
|
|
47
|
+
"nonebot-plugin-uninfo>=0.10.0",
|
|
48
|
+
"nonebot2>=2.4.3,<3.0.0",
|
|
49
|
+
"pillow>=11.0.0",
|
|
50
|
+
"pilmoji-for-parser",
|
|
51
|
+
"tqdm>=4.67.1,<5.0.0",
|
|
41
52
|
]
|
|
42
53
|
|
|
43
|
-
[project.optional-dependencies]
|
|
44
|
-
htmlkit = ["nonebot-plugin-htmlkit>=0.1.0rc3"]
|
|
45
|
-
|
|
46
54
|
[project.urls]
|
|
47
|
-
Repository = "https://github.com/fllesser/nonebot-plugin-parser"
|
|
48
55
|
IssueTracker = "https://github.com/fllesser/nonebot-plugin-parser/issues"
|
|
49
56
|
Release = "https://github.com/fllesser/nonebot-plugin-parser/releases"
|
|
57
|
+
Repository = "https://github.com/fllesser/nonebot-plugin-parser"
|
|
58
|
+
|
|
59
|
+
[project.optional-dependencies]
|
|
60
|
+
all = ["nonebot-plugin-htmlkit>=0.1.0rc4", "yt-dlp>=2025.10.14"]
|
|
61
|
+
htmlkit = ["nonebot-plugin-htmlkit>=0.1.0rc4"]
|
|
62
|
+
ytdlp = ["yt-dlp>=2025.10.14"]
|
|
50
63
|
|
|
51
64
|
[dependency-groups]
|
|
52
65
|
dev = [
|
|
53
|
-
"nb-cli>=1.4.2",
|
|
54
66
|
"nonebot2[fastapi]>=2.4.3,<3.0.0",
|
|
55
67
|
"pre-commit>=4.3.0",
|
|
56
|
-
"ruff>=0.14.
|
|
68
|
+
"ruff>=0.14.3,<1.0.0",
|
|
57
69
|
]
|
|
58
|
-
|
|
70
|
+
extras = ["nonebot-plugin-htmlkit>=0.1.0rc4", "yt-dlp>=2025.10.14"]
|
|
71
|
+
pydantic-v1 = ["pydantic<2.0.0"] # renovate:ignore
|
|
72
|
+
pydantic-v2 = ["pydantic>=2.0.0"]
|
|
73
|
+
telegram = ["nonebot-adapter-telegram>=0.1.0b20"]
|
|
59
74
|
test = [
|
|
60
|
-
"nonebot2[fastapi]>=2.4.3,<3.0.0",
|
|
61
75
|
"nonebot-adapter-onebot>=2.4.6",
|
|
76
|
+
"nonebot2[fastapi]>=2.4.3,<3.0.0",
|
|
62
77
|
"nonebug>=0.4.3,<1.0.0",
|
|
63
|
-
"
|
|
78
|
+
"poethepoet>=0.37.0",
|
|
64
79
|
"pytest-asyncio>=1.2.0,<1.3.0",
|
|
65
80
|
"pytest-cov>=7.0.0",
|
|
66
|
-
"
|
|
81
|
+
"pytest-xdist>=3.8.0,<4.0.0",
|
|
67
82
|
"respx>=0.22.0",
|
|
68
83
|
]
|
|
69
84
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
85
|
+
[build-system]
|
|
86
|
+
requires = ["uv_build>=0.9.0,<0.10.0"]
|
|
87
|
+
build-backend = "uv_build"
|
|
88
|
+
|
|
89
|
+
[tool.bumpversion]
|
|
90
|
+
current_version = "2.1.1"
|
|
91
|
+
commit = true
|
|
92
|
+
message = "🔖 release: bump vesion from {current_version} to {new_version}"
|
|
93
|
+
tag = true
|
|
73
94
|
|
|
74
|
-
|
|
95
|
+
[[tool.bumpversion.files]]
|
|
96
|
+
filename = "uv.lock"
|
|
97
|
+
search = "name = \"nonebot-plugin-parser\"\nversion = \"{current_version}\""
|
|
98
|
+
replace = "name = \"nonebot-plugin-parser\"\nversion = \"{new_version}\""
|
|
75
99
|
|
|
76
|
-
[tool.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
100
|
+
[tool.coverage.report]
|
|
101
|
+
show_missing = true # 相当于 --cov-report=term-missing:cite[1]
|
|
102
|
+
# omit = [ # 排除不需要统计的文件
|
|
103
|
+
# ]
|
|
104
|
+
exclude_lines = [
|
|
105
|
+
"raise NotImplementedError",
|
|
106
|
+
"if TYPE_CHECKING:",
|
|
107
|
+
"@overload",
|
|
108
|
+
"except",
|
|
109
|
+
"raise",
|
|
85
110
|
]
|
|
86
111
|
|
|
87
112
|
[tool.nonebot]
|
|
@@ -91,20 +116,6 @@ adapters = [
|
|
|
91
116
|
]
|
|
92
117
|
plugins = ["nonebot_plugin_parser"]
|
|
93
118
|
|
|
94
|
-
|
|
95
|
-
[tool.pytest.ini_options]
|
|
96
|
-
asyncio_mode = "auto"
|
|
97
|
-
asyncio_default_fixture_loop_scope = "session"
|
|
98
|
-
pythonpath = ["src"]
|
|
99
|
-
addopts = [
|
|
100
|
-
"-v", # 详细输出
|
|
101
|
-
"-s", # 显示打印信息
|
|
102
|
-
"--tb=short", # 简短的错误回溯
|
|
103
|
-
"-ra", # 显示所有测试结果摘要
|
|
104
|
-
"--strict-markers", # 严格标记模式
|
|
105
|
-
"--import-mode=prepend", # 导入模式
|
|
106
|
-
]
|
|
107
|
-
|
|
108
119
|
[tool.poe.tasks]
|
|
109
120
|
test_others = "pytest tests/others --cov=src --cov-report=xml:coverage1.xml --junitxml=junit1.xml -n auto"
|
|
110
121
|
test_parsers = "pytest tests/parsers --cov=src --cov-report=xml:coverage2.xml --junitxml=junit2.xml -n auto"
|
|
@@ -112,19 +123,31 @@ test_render = "pytest tests/render --cov=src --cov-report=xml:coverage3.xml --ju
|
|
|
112
123
|
bump = "bump-my-version bump"
|
|
113
124
|
show-bump = "bump-my-version show-bump"
|
|
114
125
|
|
|
126
|
+
[tool.pyright]
|
|
127
|
+
pythonVersion = "3.10"
|
|
128
|
+
pythonPlatform = "All"
|
|
129
|
+
defineConstant = { PYDANTIC_V2 = true }
|
|
130
|
+
executionEnvironments = [
|
|
131
|
+
{ root = "./tests", extraPaths = [
|
|
132
|
+
"./src",
|
|
133
|
+
] },
|
|
134
|
+
{ root = "./src" },
|
|
135
|
+
]
|
|
136
|
+
typeCheckingMode = "standard"
|
|
137
|
+
disableBytesTypePromotions = true
|
|
115
138
|
|
|
116
|
-
[tool.
|
|
117
|
-
|
|
118
|
-
#
|
|
119
|
-
|
|
120
|
-
#
|
|
121
|
-
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"@overload",
|
|
125
|
-
"except",
|
|
126
|
-
"raise",
|
|
139
|
+
[tool.pytest.ini_options]
|
|
140
|
+
addopts = [
|
|
141
|
+
"-v", # 详细输出
|
|
142
|
+
"-s", # 显示打印信息
|
|
143
|
+
"--tb=short", # 简短的错误回溯
|
|
144
|
+
"-ra", # 显示所有测试结果摘要
|
|
145
|
+
"--strict-markers", # 严格标记模式
|
|
146
|
+
"--import-mode=prepend", # 导入模式
|
|
127
147
|
]
|
|
148
|
+
pythonpath = ["src"]
|
|
149
|
+
asyncio_mode = "auto"
|
|
150
|
+
asyncio_default_fixture_loop_scope = "session"
|
|
128
151
|
|
|
129
152
|
[tool.ruff]
|
|
130
153
|
line-length = 120
|
|
@@ -135,33 +158,32 @@ line-ending = "lf"
|
|
|
135
158
|
|
|
136
159
|
[tool.ruff.lint]
|
|
137
160
|
select = [
|
|
138
|
-
"F",
|
|
139
|
-
"W",
|
|
140
|
-
"E",
|
|
141
|
-
"I",
|
|
142
|
-
"UP",
|
|
143
|
-
"ASYNC",
|
|
144
|
-
"C4",
|
|
145
|
-
"T10",
|
|
146
|
-
"T20",
|
|
147
|
-
"PYI",
|
|
148
|
-
"PT",
|
|
149
|
-
"Q",
|
|
150
|
-
"TID",
|
|
151
|
-
"RUF",
|
|
161
|
+
"F", # Pyflakes
|
|
162
|
+
"W", # pycodestyle warnings
|
|
163
|
+
"E", # pycodestyle errors
|
|
164
|
+
"I", # isort
|
|
165
|
+
"UP", # pyupgrade
|
|
166
|
+
"ASYNC", # flake8-async
|
|
167
|
+
"C4", # flake8-comprehensions
|
|
168
|
+
"T10", # flake8-debugger
|
|
169
|
+
"T20", # flake8-print
|
|
170
|
+
"PYI", # flake8-pyi
|
|
171
|
+
"PT", # flake8-pytest-style
|
|
172
|
+
"Q", # flake8-quotes
|
|
173
|
+
"TID", # flake8-tidy-imports
|
|
174
|
+
"RUF", # Ruff-specific rules
|
|
152
175
|
]
|
|
153
176
|
ignore = [
|
|
154
|
-
"E402",
|
|
177
|
+
"E402", # module-import-not-at-top-of-file
|
|
155
178
|
"UP037", # quoted-annotation
|
|
156
|
-
"RUF001",
|
|
157
|
-
"RUF002",
|
|
158
|
-
"RUF003",
|
|
159
|
-
"W191",
|
|
179
|
+
"RUF001", # ambiguous-unicode-character-string
|
|
180
|
+
"RUF002", # ambiguous-unicode-character-docstring
|
|
181
|
+
"RUF003", # ambiguous-unicode-character-comment
|
|
182
|
+
"W191", # indentation contains tabs
|
|
160
183
|
# "I001", # isort: imports are incorrectly sorted
|
|
161
|
-
"TID252",
|
|
184
|
+
"TID252", # 相对导入
|
|
162
185
|
]
|
|
163
186
|
|
|
164
|
-
|
|
165
187
|
[tool.ruff.lint.isort]
|
|
166
188
|
force-sort-within-sections = true
|
|
167
189
|
known-first-party = ["tests/*"]
|
|
@@ -174,33 +196,13 @@ mark-parentheses = false
|
|
|
174
196
|
[tool.ruff.lint.pyupgrade]
|
|
175
197
|
keep-runtime-typing = true
|
|
176
198
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
"
|
|
185
|
-
]
|
|
186
|
-
{ root = "./src" },
|
|
199
|
+
[tool.uv]
|
|
200
|
+
required-version = ">=0.9.7"
|
|
201
|
+
default-groups = ["test", "dev", "extras"]
|
|
202
|
+
conflicts = [
|
|
203
|
+
[
|
|
204
|
+
{ group = "pydantic-v1" },
|
|
205
|
+
{ group = "pydantic-v2" },
|
|
206
|
+
{ group = "telegram" },
|
|
207
|
+
],
|
|
187
208
|
]
|
|
188
|
-
typeCheckingMode = "standard"
|
|
189
|
-
reportShadowedImports = false
|
|
190
|
-
disableBytesTypePromotions = true
|
|
191
|
-
|
|
192
|
-
[build-system]
|
|
193
|
-
requires = ["uv_build>=0.9.0,<0.10.0"]
|
|
194
|
-
build-backend = "uv_build"
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
[tool.bumpversion]
|
|
198
|
-
current_version = "2.1.0"
|
|
199
|
-
commit = true
|
|
200
|
-
message = "🔖 release: bump vesion from {current_version} to {new_version}"
|
|
201
|
-
tag = true
|
|
202
|
-
|
|
203
|
-
[[tool.bumpversion.files]]
|
|
204
|
-
filename = "uv.lock"
|
|
205
|
-
search = "name = \"nonebot-plugin-parser\"\nversion = \"{current_version}\""
|
|
206
|
-
replace = "name = \"nonebot-plugin-parser\"\nversion = \"{new_version}\""
|
{nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/config.py
RENAMED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import Literal
|
|
4
3
|
|
|
5
4
|
from bilibili_api.video import VideoCodecs
|
|
6
5
|
from nonebot import get_driver, get_plugin_config, require
|
|
7
6
|
from pydantic import BaseModel
|
|
8
7
|
|
|
8
|
+
from .constants import PlatformEnum
|
|
9
|
+
|
|
9
10
|
_nickname: str = next(iter(get_driver().config.nickname), "")
|
|
10
11
|
"""全局名称"""
|
|
11
12
|
|
|
@@ -17,11 +18,6 @@ _config_dir: Path = _store.get_plugin_config_dir()
|
|
|
17
18
|
_data_dir: Path = _store.get_plugin_data_dir()
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
PlatformNames = Literal[
|
|
21
|
-
"bilibili", "acfun", "douyin", "youtube", "kuaishou", "twitter", "tiktok", "weibo", "xiaohongshu", "nga"
|
|
22
|
-
]
|
|
23
|
-
|
|
24
|
-
|
|
25
21
|
class RenderType(str, Enum):
|
|
26
22
|
default = "default"
|
|
27
23
|
common = "common"
|
|
@@ -45,7 +41,7 @@ class Config(BaseModel):
|
|
|
45
41
|
"""视频/音频最大时长"""
|
|
46
42
|
parser_append_url: bool = False
|
|
47
43
|
"""是否在解析结果中附加原始URL"""
|
|
48
|
-
parser_disabled_platforms: list[
|
|
44
|
+
parser_disabled_platforms: list[PlatformEnum] = []
|
|
49
45
|
"""禁止的解析器"""
|
|
50
46
|
parser_bili_video_codes: list[VideoCodecs] = [VideoCodecs.AVC, VideoCodecs.AV1, VideoCodecs.HEV]
|
|
51
47
|
"""B站视频编码"""
|
|
@@ -87,7 +83,7 @@ class Config(BaseModel):
|
|
|
87
83
|
return self.parser_duration_maximum
|
|
88
84
|
|
|
89
85
|
@property
|
|
90
|
-
def disabled_platforms(self) -> list[
|
|
86
|
+
def disabled_platforms(self) -> list[PlatformEnum]:
|
|
91
87
|
"""禁止的解析器"""
|
|
92
88
|
return self.parser_disabled_platforms
|
|
93
89
|
|
{nonebot_plugin_parser-2.1.0 → nonebot_plugin_parser-2.1.1}/src/nonebot_plugin_parser/constants.py
RENAMED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from enum import Enum
|
|
1
2
|
from typing import Final
|
|
2
3
|
|
|
3
4
|
from httpx import Timeout
|
|
@@ -20,3 +21,19 @@ ANDROID_HEADER: Final[dict[str, str]] = {
|
|
|
20
21
|
COMMON_TIMEOUT: Final[Timeout] = Timeout(connect=15.0, read=20.0, write=10.0, pool=10.0)
|
|
21
22
|
|
|
22
23
|
DOWNLOAD_TIMEOUT: Final[Timeout] = Timeout(connect=15.0, read=240.0, write=10.0, pool=10.0)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class PlatformEnum(str, Enum):
|
|
27
|
+
ACFUN = "acfun"
|
|
28
|
+
BILIBILI = "bilibili"
|
|
29
|
+
DOUYIN = "douyin"
|
|
30
|
+
KUAISHOU = "kuaishou"
|
|
31
|
+
NGA = "nga"
|
|
32
|
+
TIKTOK = "tiktok"
|
|
33
|
+
TWITTER = "twitter"
|
|
34
|
+
WEIBO = "weibo"
|
|
35
|
+
XIAOHONGSHU = "xiaohongshu"
|
|
36
|
+
YOUTUBE = "youtube"
|
|
37
|
+
|
|
38
|
+
def __str__(self) -> str:
|
|
39
|
+
return self.value
|
|
@@ -2,7 +2,7 @@ import asyncio
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
4
|
import aiofiles
|
|
5
|
-
import
|
|
5
|
+
from httpx import AsyncClient, HTTPError
|
|
6
6
|
from nonebot import logger
|
|
7
7
|
from tqdm.asyncio import tqdm
|
|
8
8
|
|
|
@@ -11,7 +11,6 @@ from ..constants import COMMON_HEADER, DOWNLOAD_TIMEOUT
|
|
|
11
11
|
from ..exception import DownloadException, SizeLimitException, ZeroSizeException
|
|
12
12
|
from ..utils import generate_file_name, merge_av, safe_unlink
|
|
13
13
|
from .task import auto_task
|
|
14
|
-
from .ytdlp import YtdlpDownloader
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
class StreamDownloader:
|
|
@@ -20,10 +19,7 @@ class StreamDownloader:
|
|
|
20
19
|
def __init__(self):
|
|
21
20
|
self.headers: dict[str, str] = COMMON_HEADER.copy()
|
|
22
21
|
self.cache_dir: Path = pconfig.cache_dir
|
|
23
|
-
self.client:
|
|
24
|
-
timeout=DOWNLOAD_TIMEOUT,
|
|
25
|
-
verify=False,
|
|
26
|
-
)
|
|
22
|
+
self.client: AsyncClient = AsyncClient(timeout=DOWNLOAD_TIMEOUT, verify=False)
|
|
27
23
|
|
|
28
24
|
@auto_task
|
|
29
25
|
async def streamd(
|
|
@@ -76,7 +72,7 @@ class StreamDownloader:
|
|
|
76
72
|
await file.write(chunk)
|
|
77
73
|
bar.update(len(chunk))
|
|
78
74
|
|
|
79
|
-
except
|
|
75
|
+
except HTTPError:
|
|
80
76
|
await safe_unlink(file_path)
|
|
81
77
|
logger.exception(f"下载失败 | url: {url}, file_path: {file_path}")
|
|
82
78
|
raise DownloadException("媒体下载失败")
|
|
@@ -217,4 +213,12 @@ class StreamDownloader:
|
|
|
217
213
|
|
|
218
214
|
|
|
219
215
|
DOWNLOADER: StreamDownloader = StreamDownloader()
|
|
220
|
-
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
import yt_dlp as yt_dlp
|
|
219
|
+
|
|
220
|
+
from .ytdlp import YtdlpDownloader
|
|
221
|
+
|
|
222
|
+
YTDLP_DOWNLOADER = YtdlpDownloader()
|
|
223
|
+
except ImportError:
|
|
224
|
+
YTDLP_DOWNLOADER = None
|
|
@@ -3,8 +3,8 @@ from collections.abc import Callable, Coroutine
|
|
|
3
3
|
from functools import wraps
|
|
4
4
|
from typing import Any, ParamSpec, TypeVar
|
|
5
5
|
|
|
6
|
-
P = ParamSpec("P")
|
|
7
|
-
T = TypeVar("T")
|
|
6
|
+
P = ParamSpec("P")
|
|
7
|
+
T = TypeVar("T")
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def auto_task(func: Callable[P, Coroutine[Any, Any, T]]) -> Callable[P, Task[T]]:
|
|
@@ -2,8 +2,7 @@ import asyncio
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
from msgspec import Struct
|
|
5
|
+
from msgspec import Struct, convert
|
|
7
6
|
import yt_dlp
|
|
8
7
|
|
|
9
8
|
from ..config import pconfig
|
|
@@ -73,7 +72,7 @@ class YtdlpDownloader:
|
|
|
73
72
|
if not info_dict:
|
|
74
73
|
raise ParseException("获取视频信息失败")
|
|
75
74
|
|
|
76
|
-
video_info =
|
|
75
|
+
video_info = convert(info_dict, VideoInfo)
|
|
77
76
|
self._video_info_mapping[url] = video_info
|
|
78
77
|
return video_info
|
|
79
78
|
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
"""统一的解析器 matcher"""
|
|
2
2
|
|
|
3
|
-
import re
|
|
4
3
|
from typing import Literal
|
|
5
4
|
|
|
6
5
|
from nonebot import get_driver, logger
|
|
7
6
|
from nonebot.adapters import Event
|
|
8
7
|
from nonebot_plugin_alconna import SupportAdapter
|
|
9
|
-
from nonebot_plugin_alconna.uniseg import get_message_id, get_target, message_reaction
|
|
10
8
|
|
|
11
9
|
from ..config import pconfig
|
|
12
10
|
from ..parsers import BaseParser, ParseResult
|
|
13
11
|
from ..renders import get_renderer
|
|
14
12
|
from ..utils import LimitedSizeDict
|
|
15
|
-
from .
|
|
13
|
+
from .rule import Searched, SearchResult, on_keyword_regex
|
|
16
14
|
|
|
17
15
|
|
|
18
16
|
def _get_enabled_parser_classes() -> list[type[BaseParser]]:
|
|
@@ -21,28 +19,24 @@ def _get_enabled_parser_classes() -> list[type[BaseParser]]:
|
|
|
21
19
|
return [_cls for _cls in all_subclass if _cls.platform.name not in disabled_platforms]
|
|
22
20
|
|
|
23
21
|
|
|
24
|
-
ENABLED_PARSER_CLASSES = _get_enabled_parser_classes()
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def _get_enabled_patterns() -> list[tuple[str, str]]:
|
|
28
|
-
"""根据配置获取启用的平台正则表达式列表"""
|
|
29
|
-
|
|
30
|
-
return [pattern for _cls in ENABLED_PARSER_CLASSES for pattern in _cls.patterns]
|
|
31
|
-
|
|
32
|
-
|
|
33
22
|
# 关键词 Parser 映射
|
|
34
23
|
KEYWORD_PARSER_MAP: dict[str, BaseParser] = {}
|
|
35
24
|
|
|
36
25
|
|
|
37
26
|
@get_driver().on_startup
|
|
38
|
-
def
|
|
27
|
+
def register_parser_matcher():
|
|
28
|
+
enabled_parser_classes = _get_enabled_parser_classes()
|
|
29
|
+
|
|
39
30
|
enabled_platform_names = []
|
|
40
|
-
for _cls in
|
|
31
|
+
for _cls in enabled_parser_classes:
|
|
41
32
|
parser = _cls()
|
|
42
33
|
enabled_platform_names.append(parser.platform.display_name)
|
|
43
34
|
for keyword, _ in _cls.patterns:
|
|
44
35
|
KEYWORD_PARSER_MAP[keyword] = parser
|
|
45
|
-
logger.info(f"
|
|
36
|
+
logger.info(f"启用平台: {', '.join(sorted(enabled_platform_names))}")
|
|
37
|
+
|
|
38
|
+
parser_matcher = on_keyword_regex(*[pattern for _cls in enabled_parser_classes for pattern in _cls.patterns])
|
|
39
|
+
parser_matcher.append_handler(parser_handler)
|
|
46
40
|
|
|
47
41
|
|
|
48
42
|
# 缓存结果
|
|
@@ -53,28 +47,24 @@ def clear_result_cache():
|
|
|
53
47
|
_RESULT_CACHE.clear()
|
|
54
48
|
|
|
55
49
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
@parser_matcher.handle()
|
|
60
|
-
async def _(
|
|
50
|
+
async def parser_handler(
|
|
61
51
|
event: Event,
|
|
62
|
-
|
|
63
|
-
matched: re.Match[str] = KwdRegexMatched(),
|
|
52
|
+
sr: SearchResult = Searched(),
|
|
64
53
|
):
|
|
65
54
|
"""统一的解析处理器"""
|
|
66
55
|
# 响应用户处理中
|
|
67
56
|
await _message_reaction(event, "resolving")
|
|
68
57
|
|
|
69
|
-
cache_key = matched.group(0)
|
|
70
58
|
# 1. 获取缓存结果
|
|
59
|
+
cache_key = sr.searched.group(0)
|
|
71
60
|
result = _RESULT_CACHE.get(cache_key)
|
|
61
|
+
|
|
72
62
|
if result is None:
|
|
73
63
|
# 2. 获取对应平台 parser
|
|
74
|
-
parser = KEYWORD_PARSER_MAP[keyword]
|
|
64
|
+
parser = KEYWORD_PARSER_MAP[sr.keyword]
|
|
75
65
|
|
|
76
66
|
try:
|
|
77
|
-
result = await parser.parse(
|
|
67
|
+
result = await parser.parse(sr.keyword, sr.searched)
|
|
78
68
|
except Exception:
|
|
79
69
|
# await UniMessage(str(e)).send()
|
|
80
70
|
await _message_reaction(event, "fail")
|
|
@@ -99,17 +89,23 @@ async def _(
|
|
|
99
89
|
await _message_reaction(event, "done")
|
|
100
90
|
|
|
101
91
|
|
|
102
|
-
|
|
92
|
+
from nonebot_plugin_alconna import uniseg
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
async def _message_reaction(
|
|
96
|
+
event: Event,
|
|
97
|
+
status: Literal["fail", "resolving", "done"],
|
|
98
|
+
) -> None:
|
|
103
99
|
emoji_map = {
|
|
104
100
|
"fail": ["10060", "❌"],
|
|
105
101
|
"resolving": ["424", "👀"],
|
|
106
102
|
"done": ["144", "🎉"],
|
|
107
103
|
}
|
|
108
|
-
message_id = get_message_id(event)
|
|
109
|
-
target = get_target(event)
|
|
104
|
+
message_id = uniseg.get_message_id(event)
|
|
105
|
+
target = uniseg.get_target(event)
|
|
110
106
|
if target.adapter == SupportAdapter.onebot11:
|
|
111
107
|
emoji = emoji_map[status][0]
|
|
112
108
|
else:
|
|
113
109
|
emoji = emoji_map[status][1]
|
|
114
110
|
|
|
115
|
-
await message_reaction(emoji, message_id=message_id)
|
|
111
|
+
await uniseg.message_reaction(emoji, message_id=message_id)
|