nonebot-plugin-bili-dynamic 0.2.2__tar.gz → 0.2.4__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_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/PKG-INFO +2 -2
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/qrcode_login.py +56 -20
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/renderer.py +6 -3
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic.egg-info/PKG-INFO +2 -2
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic.egg-info/SOURCES.txt +2 -1
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic.egg-info/requires.txt +1 -1
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/pyproject.toml +2 -2
- nonebot_plugin_bili_dynamic-0.2.4/tests/test_qrcode_login.py +46 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/LICENSE +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/README.md +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/__init__.py +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/api.py +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/commands.py +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/config.py +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/cookie_store.py +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/database.py +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/link_parser.py +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/models.py +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/monitor.py +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic/translator.py +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic.egg-info/dependency_links.txt +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic.egg-info/entry_points.txt +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/nonebot_plugin_bili_dynamic.egg-info/top_level.txt +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/setup.cfg +0 -0
- {nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/tests/test_dynamic_expire.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nonebot-plugin-bili-dynamic
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: B站动态/直播推送 NoneBot2 插件(基于 Colter23/mirai 插件移植)
|
|
5
5
|
Author: Tony
|
|
6
6
|
License: MIT
|
|
@@ -27,7 +27,7 @@ Requires-Dist: httpx>=0.27.0
|
|
|
27
27
|
Requires-Dist: pillow>=10.0.0
|
|
28
28
|
Requires-Dist: skia-python>=87.5
|
|
29
29
|
Requires-Dist: qrcode[pil]>=7.4.2
|
|
30
|
-
Requires-Dist: tortoise-orm[accel]
|
|
30
|
+
Requires-Dist: tortoise-orm[accel]<1.0,>=0.21.0
|
|
31
31
|
Requires-Dist: aerich>=0.7.0
|
|
32
32
|
Requires-Dist: pydantic>=2.0.0
|
|
33
33
|
Requires-Dist: typing-extensions>=4.0.0
|
|
@@ -13,6 +13,46 @@ from nonebot.adapters.onebot.v11 import Bot, MessageEvent, MessageSegment
|
|
|
13
13
|
import httpx
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
def _extract_login_cookies(set_cookie_headers: list, login_url: str) -> Dict:
|
|
17
|
+
"""从扫码成功响应中提取登录 Cookie。
|
|
18
|
+
|
|
19
|
+
优先解析 Set-Cookie 响应头(B站官方下发凭证的通道),
|
|
20
|
+
部分情况下 data.url 的 query 里不再携带 SESSDATA,
|
|
21
|
+
因此 URL query 只作为兜底。
|
|
22
|
+
"""
|
|
23
|
+
import http.cookies
|
|
24
|
+
from urllib.parse import urlparse, parse_qs
|
|
25
|
+
|
|
26
|
+
wanted = ("SESSDATA", "BILI_JCT", "DEDEUSERID")
|
|
27
|
+
cookies: Dict[str, str] = {}
|
|
28
|
+
|
|
29
|
+
# 1) Set-Cookie 响应头(可能有多个,逐个解析)
|
|
30
|
+
for header in set_cookie_headers or []:
|
|
31
|
+
try:
|
|
32
|
+
morsel = http.cookies.SimpleCookie()
|
|
33
|
+
morsel.load(header)
|
|
34
|
+
for key, m in morsel.items():
|
|
35
|
+
if key.upper() in wanted and m.value:
|
|
36
|
+
cookies.setdefault(key, m.value)
|
|
37
|
+
except Exception as e:
|
|
38
|
+
logger.warning(f"[QRLogin] parse set-cookie failed: {e}")
|
|
39
|
+
|
|
40
|
+
# 2) 兜底:从 data.url 的 query 参数中提取
|
|
41
|
+
# 注意:parse_qs 已做过一次 URL 解码,不要再 unquote,
|
|
42
|
+
# 真实 SESSDATA 字面量里本就包含 %2C,二次解码会损坏值
|
|
43
|
+
if login_url:
|
|
44
|
+
try:
|
|
45
|
+
parsed = urlparse(login_url)
|
|
46
|
+
query_params = parse_qs(parsed.query)
|
|
47
|
+
for key, values in query_params.items():
|
|
48
|
+
if key.upper() in wanted and values:
|
|
49
|
+
cookies.setdefault(key, values[0])
|
|
50
|
+
except Exception as e:
|
|
51
|
+
logger.error(f"[QRLogin] parse url failed: {e}")
|
|
52
|
+
|
|
53
|
+
return cookies
|
|
54
|
+
|
|
55
|
+
|
|
16
56
|
class BiliQRCodeLogin:
|
|
17
57
|
"""B站扫码登录器"""
|
|
18
58
|
|
|
@@ -94,27 +134,23 @@ class BiliQRCodeLogin:
|
|
|
94
134
|
poll_code = poll_data.get("code", 86083)
|
|
95
135
|
|
|
96
136
|
if poll_code == 0:
|
|
97
|
-
#
|
|
98
|
-
#
|
|
137
|
+
# 登录成功!凭证通过 Set-Cookie 响应头下发,
|
|
138
|
+
# data.url 的 query 参数只是兜底(部分情况下不再携带 SESSDATA)
|
|
99
139
|
login_url = poll_data.get("url", "")
|
|
100
|
-
cookies =
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
logger.info(f"[QRLogin] extracted from url query: {list(cookies.keys())}")
|
|
115
|
-
except Exception as e:
|
|
116
|
-
logger.error(f"[QRLogin] parse url failed: {e}")
|
|
117
|
-
|
|
140
|
+
cookies = _extract_login_cookies(
|
|
141
|
+
resp.headers.get_list("set-cookie"),
|
|
142
|
+
login_url,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
if cookies:
|
|
146
|
+
logger.info(f"[QRLogin] extracted cookies: {list(cookies.keys())}")
|
|
147
|
+
else:
|
|
148
|
+
logger.error(
|
|
149
|
+
f"[QRLogin] 登录成功但未提取到 Cookie, "
|
|
150
|
+
f"set-cookie headers: {len(resp.headers.get_list('set-cookie'))} 条, "
|
|
151
|
+
f"data.url: {login_url[:80]}"
|
|
152
|
+
)
|
|
153
|
+
|
|
118
154
|
return 0, cookies
|
|
119
155
|
|
|
120
156
|
return poll_code, None
|
|
@@ -375,7 +375,8 @@ async def _download_image(url: str) -> Optional[skia.Image]:
|
|
|
375
375
|
client = await _client()
|
|
376
376
|
resp = await client.get(url)
|
|
377
377
|
if resp.status_code == 200 and resp.content:
|
|
378
|
-
|
|
378
|
+
# MakeWithCopy:MakeFromEncoded 零拷贝不持有数据,resp.content 释放后即成悬垂指针
|
|
379
|
+
img = skia.Image.MakeFromEncoded(skia.Data.MakeWithCopy(resp.content))
|
|
379
380
|
if img:
|
|
380
381
|
try:
|
|
381
382
|
img = img.makeRasterImage() or img
|
|
@@ -549,7 +550,8 @@ def _make_pil_processed_image(
|
|
|
549
550
|
pil = pil.convert("RGB")
|
|
550
551
|
buf = io.BytesIO()
|
|
551
552
|
pil.save(buf, format="PNG")
|
|
552
|
-
|
|
553
|
+
# MakeWithCopy:MakeFromEncoded 零拷贝不持有数据,防止临时 buffer 被 GC 后悬垂
|
|
554
|
+
return skia.Image.MakeFromEncoded(skia.Data.MakeWithCopy(buf.getvalue()))
|
|
553
555
|
except Exception as e:
|
|
554
556
|
logger.debug(f"[BiliDynamic] Pillow 图片预处理失败: {e}")
|
|
555
557
|
return None
|
|
@@ -687,7 +689,8 @@ def _draw_fake_qr(canvas: skia.Canvas, link: str, color: int, x: float, y: float
|
|
|
687
689
|
img = qr.make_image(fill_color="black", back_color="white").convert("RGB")
|
|
688
690
|
buf = io.BytesIO()
|
|
689
691
|
img.save(buf, format="PNG")
|
|
690
|
-
|
|
692
|
+
# MakeWithCopy:MakeFromEncoded 零拷贝不持有数据,防止临时 buffer 被 GC 后悬垂
|
|
693
|
+
qimg = skia.Image.MakeFromEncoded(skia.Data.MakeWithCopy(buf.getvalue()))
|
|
691
694
|
if qimg:
|
|
692
695
|
_draw_image_rrect(canvas, qimg, skia.RRect.MakeRectXY(skia.Rect.MakeXYWH(x, y, size, size), 0, 0))
|
|
693
696
|
except Exception:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nonebot-plugin-bili-dynamic
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: B站动态/直播推送 NoneBot2 插件(基于 Colter23/mirai 插件移植)
|
|
5
5
|
Author: Tony
|
|
6
6
|
License: MIT
|
|
@@ -27,7 +27,7 @@ Requires-Dist: httpx>=0.27.0
|
|
|
27
27
|
Requires-Dist: pillow>=10.0.0
|
|
28
28
|
Requires-Dist: skia-python>=87.5
|
|
29
29
|
Requires-Dist: qrcode[pil]>=7.4.2
|
|
30
|
-
Requires-Dist: tortoise-orm[accel]
|
|
30
|
+
Requires-Dist: tortoise-orm[accel]<1.0,>=0.21.0
|
|
31
31
|
Requires-Dist: aerich>=0.7.0
|
|
32
32
|
Requires-Dist: pydantic>=2.0.0
|
|
33
33
|
Requires-Dist: typing-extensions>=4.0.0
|
|
@@ -19,4 +19,5 @@ nonebot_plugin_bili_dynamic.egg-info/dependency_links.txt
|
|
|
19
19
|
nonebot_plugin_bili_dynamic.egg-info/entry_points.txt
|
|
20
20
|
nonebot_plugin_bili_dynamic.egg-info/requires.txt
|
|
21
21
|
nonebot_plugin_bili_dynamic.egg-info/top_level.txt
|
|
22
|
-
tests/test_dynamic_expire.py
|
|
22
|
+
tests/test_dynamic_expire.py
|
|
23
|
+
tests/test_qrcode_login.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "nonebot-plugin-bili-dynamic"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.4"
|
|
4
4
|
description = "B站动态/直播推送 NoneBot2 插件(基于 Colter23/mirai 插件移植)"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = {text = "MIT"}
|
|
@@ -29,7 +29,7 @@ dependencies = [
|
|
|
29
29
|
"pillow>=10.0.0",
|
|
30
30
|
"skia-python>=87.5",
|
|
31
31
|
"qrcode[pil]>=7.4.2",
|
|
32
|
-
"tortoise-orm[accel]>=0.21.0",
|
|
32
|
+
"tortoise-orm[accel]>=0.21.0,<1.0",
|
|
33
33
|
"aerich>=0.7.0",
|
|
34
34
|
"pydantic>=2.0.0",
|
|
35
35
|
"typing-extensions>=4.0.0",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""扫码登录 Cookie 提取测试"""
|
|
2
|
+
import nonebot
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@pytest.fixture(scope="module", autouse=True)
|
|
7
|
+
def init_nonebot():
|
|
8
|
+
nonebot.init()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_extract_from_set_cookie_only():
|
|
12
|
+
"""data.url query 不含凭证时,能从 Set-Cookie 头提取(真实失败场景)"""
|
|
13
|
+
from nonebot_plugin_bili_dynamic.qrcode_login import _extract_login_cookies
|
|
14
|
+
|
|
15
|
+
headers = [
|
|
16
|
+
"SESSDATA=abc123%2C456*7; Domain=.bilibili.com; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Path=/",
|
|
17
|
+
"bili_jct=token789; Domain=.bilibili.com; Path=/",
|
|
18
|
+
"DedeUserID=123456; Domain=.bilibili.com; Path=/",
|
|
19
|
+
"sid=othersid; Domain=.bilibili.com; Path=/",
|
|
20
|
+
]
|
|
21
|
+
cookies = _extract_login_cookies(headers, "https://www.bilibili.com/")
|
|
22
|
+
assert cookies["SESSDATA"] == "abc123%2C456*7"
|
|
23
|
+
assert cookies["bili_jct"] == "token789"
|
|
24
|
+
assert cookies["DedeUserID"] == "123456"
|
|
25
|
+
assert "sid" not in cookies
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_extract_from_url_query_fallback():
|
|
29
|
+
"""旧格式:凭证在 data.url 的 query 里"""
|
|
30
|
+
from nonebot_plugin_bili_dynamic.qrcode_login import _extract_login_cookies
|
|
31
|
+
|
|
32
|
+
url = (
|
|
33
|
+
"https://passport.biligame.com/x/passport-login/web/crossDomain"
|
|
34
|
+
"?DedeUserID=123456&DedeUserID__ckMd5=deadbeef&Expires=15551000"
|
|
35
|
+
"&SESSDATA=abc123%252C456&bili_jct=token789&gourl=https%3A%2F%2Fwww.bilibili.com"
|
|
36
|
+
)
|
|
37
|
+
cookies = _extract_login_cookies([], url)
|
|
38
|
+
assert cookies["DedeUserID"] == "123456"
|
|
39
|
+
assert cookies["SESSDATA"] == "abc123%2C456"
|
|
40
|
+
assert cookies["bili_jct"] == "token789"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_extract_empty_when_nothing():
|
|
44
|
+
from nonebot_plugin_bili_dynamic.qrcode_login import _extract_login_cookies
|
|
45
|
+
|
|
46
|
+
assert _extract_login_cookies([], "") == {}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nonebot_plugin_bili_dynamic-0.2.2 → nonebot_plugin_bili_dynamic-0.2.4}/tests/test_dynamic_expire.py
RENAMED
|
File without changes
|