nonebot-plugin-bilidownloader-woju 0.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.
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: nonebot-plugin-bilidownloader-woju
3
+ Version: 0.1.1
4
+ Summary: 哔哩哔哩文件下载器插件 for NoneBot2
5
+ Author-email: Wojusensei <3442006415@qq.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Wojusensei/nonebot-plugin-bilibili-downloader
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: nonebot2>=2.3.0
12
+ Requires-Dist: nonebot-adapter-onebot>=2.0.0
13
+ Requires-Dist: bilibili-api-python>=17.0.0
14
+ Requires-Dist: httpx>=0.24.0
15
+ Requires-Dist: nonebot-plugin-localstore>=0.5.0
16
+
17
+ # nonebot-plugin-bilibili-downloader
18
+
19
+ ✨ 从B站视频下载音频/视频/封面的 NoneBot2 插件 ✨
20
+
21
+ ## 功能
22
+
23
+ - `/mp3 视频链接` → 发送音频文件(MP3/M4A)
24
+ - `/mp4 视频链接` → 发送视频文件(MP4)
25
+ - `/封面图 视频链接` → 发送封面图片
26
+
27
+ ## 安装
28
+
29
+ ```bash
30
+ nb plugin install nonebot-plugin-bilibili-downloader
31
+
32
+ ## 使用
33
+ 在群聊中 @机器人 并输入命令
34
+
35
+ 命令格式:/mp3 BV1xx411c7mD 或 /mp4 https://www.bilibili.com/video/BV1xx411c7mD
36
+
37
+ bot会自动下载并发送文件
38
+
39
+ ## 配置
40
+ 无需任何配置,即装即用
41
+
42
+ ## 注意
43
+ 需要给bot发送文件的权限,临时文件使用 localstore 自动管理
44
+
45
+ ## 开源协议
46
+ MIT
@@ -0,0 +1,30 @@
1
+ # nonebot-plugin-bilibili-downloader
2
+
3
+ ✨ 从B站视频下载音频/视频/封面的 NoneBot2 插件 ✨
4
+
5
+ ## 功能
6
+
7
+ - `/mp3 视频链接` → 发送音频文件(MP3/M4A)
8
+ - `/mp4 视频链接` → 发送视频文件(MP4)
9
+ - `/封面图 视频链接` → 发送封面图片
10
+
11
+ ## 安装
12
+
13
+ ```bash
14
+ nb plugin install nonebot-plugin-bilibili-downloader
15
+
16
+ ## 使用
17
+ 在群聊中 @机器人 并输入命令
18
+
19
+ 命令格式:/mp3 BV1xx411c7mD 或 /mp4 https://www.bilibili.com/video/BV1xx411c7mD
20
+
21
+ bot会自动下载并发送文件
22
+
23
+ ## 配置
24
+ 无需任何配置,即装即用
25
+
26
+ ## 注意
27
+ 需要给bot发送文件的权限,临时文件使用 localstore 自动管理
28
+
29
+ ## 开源协议
30
+ MIT
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "nonebot-plugin-bilidownloader-woju"
7
+ version = "0.1.1"
8
+ description = "哔哩哔哩文件下载器插件 for NoneBot2"
9
+ authors = [{name = "Wojusensei", email = "3442006415@qq.com"}]
10
+ readme = "README.md"
11
+ license = {text = "MIT"}
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ ]
15
+ dependencies = [
16
+ "nonebot2>=2.3.0",
17
+ "nonebot-adapter-onebot>=2.0.0",
18
+ "bilibili-api-python>=17.0.0",
19
+ "httpx>=0.24.0",
20
+ "nonebot-plugin-localstore>=0.5.0",
21
+ ]
22
+ requires-python = ">=3.9"
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/Wojusensei/nonebot-plugin-bilibili-downloader"
26
+
27
+ [tool.setuptools]
28
+ packages = ["nonebot_plugin_bilibili_downloader"]
29
+ package-dir = {"" = "src"}
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,207 @@
1
+ import re
2
+ from pathlib import Path
3
+ from typing import Tuple, Optional
4
+ import httpx
5
+ from nonebot import on_command
6
+ from nonebot.adapters.onebot.v11 import Bot, Event, MessageSegment
7
+ from nonebot.params import CommandArg
8
+ from nonebot.plugin import PluginMetadata
9
+ from nonebot.log import logger
10
+ from bilibili_api import video
11
+ from nonebot_plugin_localstore import get_cache_dir
12
+
13
+ from .config import Config
14
+
15
+
16
+ __plugin_meta__ = PluginMetadata(
17
+ name="���������������",
18
+ description="��Bվ��Ƶ������Ƶ(MP3)����Ƶ(MP4)�ͷ���ͼ",
19
+ usage=(
20
+ "@������ /mp3 ��Ƶ��ַ �� ������Ƶ�ļ�\n"
21
+ "@������ /mp4 ��Ƶ��ַ �� ������Ƶ�ļ�\n"
22
+ "@������ /����ͼ ��Ƶ��ַ �� ���ͷ���ͼƬ"
23
+ ),
24
+ type="application",
25
+ homepage="https://github.com/Wojusensei/nonebot-plugin-bilibili-downloader",
26
+ config=Config,
27
+ supported_adapters={"~onebot.v11"},
28
+ )
29
+
30
+
31
+ CACHE_DIR = get_cache_dir("nonebot_plugin_bilibili_downloader")
32
+ CACHE_DIR.mkdir(parents=True, exist_ok=True)
33
+
34
+
35
+ def extract_bvid(url: str) -> Optional[str]:
36
+ if re.match(r'^BV[0-9A-Za-z]{10}$', url):
37
+ return url
38
+ match = re.search(r'BV[0-9A-Za-z]{10}', url)
39
+ return match.group() if match else None
40
+
41
+
42
+ def get_video_url_from_message(msg: str) -> str:
43
+ bvid = extract_bvid(msg)
44
+ if bvid:
45
+ return f"https://www.bilibili.com/video/{bvid}"
46
+ return msg.strip()
47
+
48
+
49
+ async def get_video_info(bvid: str):
50
+ v = video.Video(bvid=bvid)
51
+ info = await v.get_info()
52
+ return info
53
+
54
+
55
+ async def download_file(url: str, dest_path: Path) -> Tuple[bool, str]:
56
+ try:
57
+ async with httpx.AsyncClient(timeout=60.0, follow_redirects=True) as client:
58
+ resp = await client.get(url)
59
+ resp.raise_for_status()
60
+ dest_path.write_bytes(resp.content)
61
+ return True, ""
62
+ except Exception as e:
63
+ return False, str(e)
64
+
65
+
66
+ def clean_temp_file(path: Path):
67
+ try:
68
+ if path.exists():
69
+ path.unlink()
70
+ except Exception as e:
71
+ logger.warning(f"������ʱ�ļ�ʧ�� {path}: {e}")
72
+
73
+
74
+ mp3_cmd = on_command("/mp3", aliases={"mp3"}, priority=10, block=True)
75
+ mp4_cmd = on_command("/mp4", aliases={"mp4"}, priority=10, block=True)
76
+ cover_cmd = on_command("/����ͼ", aliases={"����ͼ"}, priority=10, block=True)
77
+
78
+
79
+ @mp3_cmd.handle()
80
+ async def handle_mp3(event: Event, args: str = CommandArg()):
81
+ raw = args.extract_plain_text().strip()
82
+ if not raw:
83
+ await mp3_cmd.finish("���ṩBվ��Ƶ���ӻ�BV�ţ����磺\n/mp3 BV1xx411c7mD")
84
+
85
+ video_url = get_video_url_from_message(raw)
86
+ bvid = extract_bvid(video_url)
87
+ if not bvid:
88
+ await mp3_cmd.finish("δ��ʶ��BV�ţ����������Ƿ���ȷ")
89
+
90
+ await mp3_cmd.send(f"?? ���ڻ�ȡ��Ƶ��Ϣ��{bvid}")
91
+
92
+ try:
93
+ info = await get_video_info(bvid)
94
+ except Exception as e:
95
+ logger.error(f"��ȡ��Ƶ��Ϣʧ��: {e}")
96
+ await mp3_cmd.finish(f"��ȡ��Ƶ��Ϣʧ�ܣ�{str(e)}")
97
+
98
+ v = video.Video(bvid=bvid)
99
+ try:
100
+ download_info = await v.get_download_url()
101
+ dash = download_info.get("data", {}).get("dash", {})
102
+ audio_list = dash.get("audio")
103
+ if not audio_list:
104
+ await mp3_cmd.finish("����Ƶû�п��õ���Ƶ��")
105
+ best_audio = max(audio_list, key=lambda x: x.get("bandwidth", 0))
106
+ audio_url = best_audio["baseUrl"]
107
+ except Exception as e:
108
+ await mp3_cmd.finish(f"��ȡ��Ƶ��ַʧ�ܣ�{str(e)}")
109
+
110
+ title = info.get("title", bvid)
111
+ safe_title = re.sub(r'[\\/*?:"<>|]', "", title)[:50]
112
+ temp_file = CACHE_DIR / f"{bvid}_audio.mp3"
113
+ await mp3_cmd.send("?? ����������Ƶ�ļ���������Ҫʮ���롭")
114
+
115
+ ok, err = await download_file(audio_url, temp_file)
116
+ if not ok:
117
+ await mp3_cmd.finish(f"����ʧ�ܣ�{err}")
118
+
119
+ try:
120
+ await mp3_cmd.send(MessageSegment.file(temp_file))
121
+ await mp3_cmd.send(f"? ��Ƶ�ѷ��ͣ�{safe_title}")
122
+ except Exception as e:
123
+ await mp3_cmd.send(f"�����ļ�ʱ������{str(e)}")
124
+ finally:
125
+ clean_temp_file(temp_file)
126
+
127
+
128
+ @mp4_cmd.handle()
129
+ async def handle_mp4(event: Event, args: str = CommandArg()):
130
+ raw = args.extract_plain_text().strip()
131
+ if not raw:
132
+ await mp4_cmd.finish("���ṩBվ��Ƶ���ӻ�BV�ţ����磺\n/mp4 BV1xx411c7mD")
133
+
134
+ video_url = get_video_url_from_message(raw)
135
+ bvid = extract_bvid(video_url)
136
+ if not bvid:
137
+ await mp4_cmd.finish("δ��ʶ��BV��")
138
+
139
+ await mp4_cmd.send(f"?? ���ڻ�ȡ��Ƶ��Ϣ��{bvid}")
140
+ try:
141
+ info = await get_video_info(bvid)
142
+ except Exception as e:
143
+ await mp4_cmd.finish(f"��ȡ��Ƶ��Ϣʧ�ܣ�{str(e)}")
144
+
145
+ v = video.Video(bvid=bvid)
146
+ try:
147
+ download_info = await v.get_download_url()
148
+ dash = download_info.get("data", {}).get("dash", {})
149
+ video_list = dash.get("video")
150
+ if not video_list:
151
+ await mp4_cmd.finish("����Ƶû�п��õ���Ƶ��")
152
+ best_video = max(video_list, key=lambda x: x.get("bandwidth", 0))
153
+ video_url = best_video["baseUrl"]
154
+ except Exception as e:
155
+ await mp4_cmd.finish(f"��ȡ��Ƶ��ַʧ�ܣ�{str(e)}")
156
+
157
+ title = info.get("title", bvid)
158
+ safe_title = re.sub(r'[\\/*?:"<>|]', "", title)[:50]
159
+ temp_file = CACHE_DIR / f"{bvid}_video.mp4"
160
+ await mp4_cmd.send("?? ����������Ƶ�ļ�������ʱ��ϳ�����")
161
+
162
+ ok, err = await download_file(video_url, temp_file)
163
+ if not ok:
164
+ await mp4_cmd.finish(f"����ʧ�ܣ�{err}")
165
+
166
+ try:
167
+ await mp4_cmd.send(MessageSegment.file(temp_file))
168
+ await mp4_cmd.send(f"? ��Ƶ�ѷ��ͣ�{safe_title}")
169
+ except Exception as e:
170
+ await mp4_cmd.send(f"�����������{str(e)}")
171
+ finally:
172
+ clean_temp_file(temp_file)
173
+
174
+
175
+ @cover_cmd.handle()
176
+ async def handle_cover(event: Event, args: str = CommandArg()):
177
+ raw = args.extract_plain_text().strip()
178
+ if not raw:
179
+ await cover_cmd.finish("���ṩBվ��Ƶ���ӻ�BV�ţ����磺\n/����ͼ BV1xx411c7mD")
180
+
181
+ video_url = get_video_url_from_message(raw)
182
+ bvid = extract_bvid(video_url)
183
+ if not bvid:
184
+ await cover_cmd.finish("δ��ʶ��BV��")
185
+
186
+ await cover_cmd.send(f"?? ���ڻ�ȡ���棺{bvid}")
187
+ try:
188
+ info = await get_video_info(bvid)
189
+ except Exception as e:
190
+ await cover_cmd.finish(f"��ȡ��Ϣʧ�ܣ�{str(e)}")
191
+
192
+ cover_url = info.get("pic")
193
+ if not cover_url:
194
+ await cover_cmd.finish("û���ҵ�����ͼ")
195
+
196
+ temp_file = CACHE_DIR / f"{bvid}_cover.jpg"
197
+ ok, err = await download_file(cover_url, temp_file)
198
+ if not ok:
199
+ await cover_cmd.finish(f"���ط���ʧ�ܣ�{err}")
200
+
201
+ try:
202
+ await cover_cmd.send(MessageSegment.image(temp_file))
203
+ await cover_cmd.send("? ����ͼ�ѷ���")
204
+ except Exception as e:
205
+ await cover_cmd.send(f"����ͼƬ������{str(e)}")
206
+ finally:
207
+ clean_temp_file(temp_file)
@@ -0,0 +1,6 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class Config(BaseModel):
5
+ \"\"\"Plugin Config\"\"\"
6
+ pass
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: nonebot-plugin-bilidownloader-woju
3
+ Version: 0.1.1
4
+ Summary: 哔哩哔哩文件下载器插件 for NoneBot2
5
+ Author-email: Wojusensei <3442006415@qq.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Wojusensei/nonebot-plugin-bilibili-downloader
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: nonebot2>=2.3.0
12
+ Requires-Dist: nonebot-adapter-onebot>=2.0.0
13
+ Requires-Dist: bilibili-api-python>=17.0.0
14
+ Requires-Dist: httpx>=0.24.0
15
+ Requires-Dist: nonebot-plugin-localstore>=0.5.0
16
+
17
+ # nonebot-plugin-bilibili-downloader
18
+
19
+ ✨ 从B站视频下载音频/视频/封面的 NoneBot2 插件 ✨
20
+
21
+ ## 功能
22
+
23
+ - `/mp3 视频链接` → 发送音频文件(MP3/M4A)
24
+ - `/mp4 视频链接` → 发送视频文件(MP4)
25
+ - `/封面图 视频链接` → 发送封面图片
26
+
27
+ ## 安装
28
+
29
+ ```bash
30
+ nb plugin install nonebot-plugin-bilibili-downloader
31
+
32
+ ## 使用
33
+ 在群聊中 @机器人 并输入命令
34
+
35
+ 命令格式:/mp3 BV1xx411c7mD 或 /mp4 https://www.bilibili.com/video/BV1xx411c7mD
36
+
37
+ bot会自动下载并发送文件
38
+
39
+ ## 配置
40
+ 无需任何配置,即装即用
41
+
42
+ ## 注意
43
+ 需要给bot发送文件的权限,临时文件使用 localstore 自动管理
44
+
45
+ ## 开源协议
46
+ MIT
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/nonebot_plugin_bilibili_downloader/__init__.py
4
+ src/nonebot_plugin_bilibili_downloader/config.py
5
+ src/nonebot_plugin_bilidownloader_woju.egg-info/PKG-INFO
6
+ src/nonebot_plugin_bilidownloader_woju.egg-info/SOURCES.txt
7
+ src/nonebot_plugin_bilidownloader_woju.egg-info/dependency_links.txt
8
+ src/nonebot_plugin_bilidownloader_woju.egg-info/requires.txt
9
+ src/nonebot_plugin_bilidownloader_woju.egg-info/top_level.txt
@@ -0,0 +1,5 @@
1
+ nonebot2>=2.3.0
2
+ nonebot-adapter-onebot>=2.0.0
3
+ bilibili-api-python>=17.0.0
4
+ httpx>=0.24.0
5
+ nonebot-plugin-localstore>=0.5.0