mirror of
https://github.com/suyiiyii/nonebot-bison.git
synced 2025-06-05 11:26:43 +08:00
Merge branch 'main' into next
This commit is contained in:
commit
22f6796b33
@ -2,6 +2,8 @@
|
||||
|
||||
## 最近更新
|
||||
|
||||
- feat (issue #67 ):添加屏蔽特定tag的功能 [@AzideCupric](https://github.com/AzideCupric) ([#101](https://github.com/felinae98/nonebot-bison/pull/101))
|
||||
|
||||
### 新功能
|
||||
|
||||
- 在StatusChange中提供了如果api返回错误不更新status的方法 [@felinae98](https://github.com/felinae98) ([#96](https://github.com/felinae98/nonebot-bison/pull/96))
|
||||
|
@ -215,3 +215,29 @@ RSS 链接即为 uid
|
||||
|
||||
在网易云网页上电台的链接一般为`https://music.163.com/#/djradio?id=793745436`,`id=`
|
||||
后面的数字即为 uid
|
||||
|
||||
### 平台订阅标签(Tag)
|
||||
|
||||
社交平台中的 Tag 一般指使用井号(`#`)作为前缀,将关键词进行标记,方便用户进行搜索的功能。
|
||||
例子:`#明日方舟# #每日打卡#(weibo、bilibili) #baracamp(Twitter)`
|
||||
|
||||
在 Bison 中,用户在添加平台账号订阅时(如果该平台提供有 hashtag 功能),
|
||||
会进行`输入需要订阅/屏蔽tag`的步骤。
|
||||
|
||||
如果需要订阅某些 tag,需要直接向 bison 发送需要订阅的一系列 tag,并使用空格进行分隔。
|
||||
例:`A1行动预备组 罗德厨房——回甘`
|
||||
|
||||
如果需要屏蔽某些 tag,需要在需要屏蔽的 tag 前加上前缀`~`,对于复数的 tag,使用空格进行分隔。
|
||||
例:`~123罗德岛 ~莱茵生命漫画`
|
||||
|
||||
可以综合运用以上规则进行同时订阅/屏蔽。
|
||||
例:`A1行动预备组 ~123罗德岛 罗德厨房——回甘 ~莱茵生命漫画`
|
||||
|
||||
#### Tag 的推送规则
|
||||
|
||||
每当 Bison 抓取到一条推送,推送中的 Tag 会经过一下检查:
|
||||
|
||||
- Bison 会对**需屏蔽 Tag**进行最优先检查,只要检测到本次推送中存在**任一**已记录的**需屏蔽 tag**,Bison 便会将该推送丢弃。
|
||||
- 上一个检查通过后,Bison 会对**需订阅 tag**进行检查,如果本次推送中存在**任一**已记录的**需订阅 tag**,Bison 便会将该推送发送到群中。
|
||||
- 当已记录的**需订阅 tag**为空时,只要通过了*第一条规则*的检查,Bison 就会将该推送发送到群中。
|
||||
- 当已记录的**需订阅 tag**不为空时,即使通过了*第一条规则*的检查,若本次推送不含**任何**已记录的**需订阅 tag**,Bison 也会将该推送丢弃。
|
||||
|
@ -137,7 +137,7 @@ def do_add_sub(add_sub: Type[Matcher]):
|
||||
state["id"] = target
|
||||
state["name"] = name
|
||||
except (LookupError):
|
||||
url = "https://nonebot-bison.vercel.app/usage/#%E6%89%80%E6%94%AF%E6%8C%81%E5%B9%B3%E5%8F%B0%E7%9A%84-uid"
|
||||
url = "https://nonebot-bison.netlify.app/usage/#%E6%89%80%E6%94%AF%E6%8C%81%E5%B9%B3%E5%8F%B0%E7%9A%84-uid"
|
||||
title = "Bison所支持的平台UID"
|
||||
content = "查询相关平台的uid格式或获取方式"
|
||||
image = "https://s3.bmp.ovh/imgs/2022/03/ab3cc45d83bd3dd3.jpg"
|
||||
@ -182,13 +182,17 @@ def do_add_sub(add_sub: Type[Matcher]):
|
||||
if not platform_manager[state["platform"]].enable_tag:
|
||||
state["tags"] = []
|
||||
return
|
||||
state["_prompt"] = '请输入要订阅的tag,订阅所有tag输入"全部标签"'
|
||||
state["_prompt"] = '请输入要订阅/屏蔽的tag(不含#号)\n多个tag请使用空格隔开\n具体规则回复"详情"'
|
||||
|
||||
async def parser_tags(event: MessageEvent, state: T_State):
|
||||
if not isinstance(state["tags"], Message):
|
||||
return
|
||||
if str(event.get_message()).strip() == "取消": # 一般不会有叫 取消 的tag吧
|
||||
await add_sub.finish("已中止订阅")
|
||||
if str(event.get_message()).strip() == "详情":
|
||||
await add_sub.reject(
|
||||
'订阅tag直接输入tag内容\n订阅所有tag输入"全部标签"\n屏蔽tag请在tag名称前添加~号\n详见https://nonebot-bison.netlify.app/usage/#平台订阅标签-tag'
|
||||
)
|
||||
if str(event.get_message()).strip() == "全部标签":
|
||||
state["tags"] = []
|
||||
else:
|
||||
|
@ -110,6 +110,43 @@ class Platform(metaclass=RegistryABCMeta, base=True):
|
||||
def set_stored_data(self, target: Target, data: Any):
|
||||
self.store[target] = data
|
||||
|
||||
def tag_separator(self, stored_tags: list[Tag]) -> tuple[list[Tag], list[Tag]]:
|
||||
"""返回分离好的正反tag元组"""
|
||||
subscribed_tags = []
|
||||
banned_tags = []
|
||||
for tag in stored_tags:
|
||||
if tag.startswith("~"):
|
||||
banned_tags.append(tag.lstrip("~"))
|
||||
else:
|
||||
subscribed_tags.append(tag)
|
||||
return subscribed_tags, banned_tags
|
||||
|
||||
def is_banned_post(
|
||||
self,
|
||||
post_tags: Collection[Tag],
|
||||
subscribed_tags: list[Tag],
|
||||
banned_tags: list[Tag],
|
||||
) -> bool:
|
||||
"""只要存在任意屏蔽tag则返回真,此行为优先级最高。
|
||||
存在任意被订阅tag则返回假,此行为优先级次之。
|
||||
若被订阅tag为空,则返回假。
|
||||
"""
|
||||
# 存在任意需要屏蔽的tag则为真
|
||||
if banned_tags:
|
||||
for tag in post_tags or []:
|
||||
if tag in banned_tags:
|
||||
return True
|
||||
# 检测屏蔽tag后,再检测订阅tag
|
||||
# 存在任意需要订阅的tag则为假
|
||||
if subscribed_tags:
|
||||
ban_it = True
|
||||
for tag in post_tags or []:
|
||||
if tag in subscribed_tags:
|
||||
ban_it = False
|
||||
return ban_it
|
||||
else:
|
||||
return False
|
||||
|
||||
async def filter_user_custom(
|
||||
self, raw_post_list: list[RawPost], cats: list[Category], tags: list[Tag]
|
||||
) -> list[RawPost]:
|
||||
@ -120,13 +157,9 @@ class Platform(metaclass=RegistryABCMeta, base=True):
|
||||
if cats and cat not in cats:
|
||||
continue
|
||||
if self.enable_tag and tags:
|
||||
flag = False
|
||||
post_tags = self.get_tags(raw_post)
|
||||
for tag in post_tags or []:
|
||||
if tag in tags:
|
||||
flag = True
|
||||
break
|
||||
if not flag:
|
||||
if self.is_banned_post(
|
||||
self.get_tags(raw_post), *self.tag_separator(tags)
|
||||
):
|
||||
continue
|
||||
res.append(raw_post)
|
||||
return res
|
||||
|
246
tests/platforms/static/bilibili_fake_dy_list.json
vendored
Normal file
246
tests/platforms/static/bilibili_fake_dy_list.json
vendored
Normal file
@ -0,0 +1,246 @@
|
||||
{
|
||||
"data": {
|
||||
"cards": [
|
||||
{
|
||||
"desc": {
|
||||
"type": 2
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": {
|
||||
"type": 1
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": {
|
||||
"type": 8
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": "明日方舟"
|
||||
},
|
||||
{
|
||||
"topic_name": "风笛"
|
||||
},
|
||||
{
|
||||
"topic_name": "琴柳"
|
||||
},
|
||||
{
|
||||
"topic_name": "风暴瞭望"
|
||||
},
|
||||
{
|
||||
"topic_name": "轮换池"
|
||||
},
|
||||
{
|
||||
"topic_name": "打卡挑战"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": {
|
||||
"type": 2
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": {
|
||||
"type": 1
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": "明日方舟"
|
||||
},
|
||||
{
|
||||
"topic_name": "饼学大厦"
|
||||
},
|
||||
{
|
||||
"topic_name": "可露希尔的秘密档案"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": {
|
||||
"type": 1
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": "罗德岛相簿"
|
||||
},
|
||||
{
|
||||
"topic_name": "可露希尔的秘密档案"
|
||||
},
|
||||
{
|
||||
"topic_name": "罗德岛闲逛部"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": {
|
||||
"type": 8
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": "明日方舟"
|
||||
},
|
||||
{
|
||||
"topic_name": "轮换学"
|
||||
},
|
||||
{
|
||||
"topic_name": "常驻标准寻访"
|
||||
},
|
||||
{
|
||||
"topic_name": "轮换池"
|
||||
},
|
||||
{
|
||||
"topic_name": "打卡挑战"
|
||||
},
|
||||
{
|
||||
"topic_name": "舟游"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": {
|
||||
"type": 2
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": "明日方舟"
|
||||
},
|
||||
{
|
||||
"topic_name": "饼学大厦"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": {
|
||||
"type": 4
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": {
|
||||
"type": 1
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": "明日方舟"
|
||||
},
|
||||
{
|
||||
"topic_name": "饼学大厦"
|
||||
},
|
||||
{
|
||||
"topic_name": "罗德岛相簿"
|
||||
},
|
||||
{
|
||||
"topic_name": "可露希尔的秘密档案"
|
||||
},
|
||||
{
|
||||
"topic_name": "罗德岛闲逛部"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": {
|
||||
"type": 1
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": "明日方舟"
|
||||
},
|
||||
{
|
||||
"topic_name": "饼学大厦"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": {
|
||||
"type": 1
|
||||
},
|
||||
"display": {
|
||||
"topic_info": {
|
||||
"topic_details": [
|
||||
{
|
||||
"topic_name": "明日方舟"
|
||||
},
|
||||
{
|
||||
"topic_name": "饼学大厦"
|
||||
},
|
||||
{
|
||||
"topic_name": "罗德岛相簿"
|
||||
},
|
||||
{
|
||||
"topic_name": "可露希尔的秘密档案"
|
||||
},
|
||||
{
|
||||
"topic_name": "罗德岛闲逛部"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
129
tests/platforms/static/tag_cases.json
vendored
Normal file
129
tests/platforms/static/tag_cases.json
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
[
|
||||
{
|
||||
"case": {
|
||||
"post_tags": [
|
||||
"111",
|
||||
"222",
|
||||
"333",
|
||||
"444"
|
||||
],
|
||||
"subscribed_tags": [
|
||||
"222"
|
||||
],
|
||||
"banned_tags": [
|
||||
"555"
|
||||
]
|
||||
},
|
||||
"result": false
|
||||
},
|
||||
{
|
||||
"case": {
|
||||
"post_tags": [
|
||||
"111",
|
||||
"222",
|
||||
"333",
|
||||
"444"
|
||||
],
|
||||
"subscribed_tags": [],
|
||||
"banned_tags": [
|
||||
"555"
|
||||
]
|
||||
},
|
||||
"result": false
|
||||
},
|
||||
{
|
||||
"case": {
|
||||
"post_tags": [
|
||||
"111",
|
||||
"222",
|
||||
"333",
|
||||
"444"
|
||||
],
|
||||
"subscribed_tags": [],
|
||||
"banned_tags": [
|
||||
"444"
|
||||
]
|
||||
},
|
||||
"result": true
|
||||
},
|
||||
{
|
||||
"case": {
|
||||
"post_tags": [
|
||||
"111",
|
||||
"222",
|
||||
"333",
|
||||
"444"
|
||||
],
|
||||
"subscribed_tags": [
|
||||
"222"
|
||||
],
|
||||
"banned_tags": []
|
||||
},
|
||||
"result": false
|
||||
},
|
||||
{
|
||||
"case": {
|
||||
"post_tags": [
|
||||
"111",
|
||||
"222",
|
||||
"333",
|
||||
"444"
|
||||
],
|
||||
"subscribed_tags": [],
|
||||
"banned_tags": []
|
||||
},
|
||||
"result": false
|
||||
},
|
||||
{
|
||||
"case": {
|
||||
"post_tags": [
|
||||
"111",
|
||||
"222",
|
||||
"333",
|
||||
"444"
|
||||
],
|
||||
"subscribed_tags": ["111","555","666"],
|
||||
"banned_tags": []
|
||||
},
|
||||
"result": false
|
||||
},
|
||||
{
|
||||
"case": {
|
||||
"post_tags": [
|
||||
"111",
|
||||
"222",
|
||||
"333",
|
||||
"444"
|
||||
],
|
||||
"subscribed_tags": ["111","555"],
|
||||
"banned_tags": ["333"]
|
||||
},
|
||||
"result": true
|
||||
},
|
||||
{
|
||||
"case": {
|
||||
"post_tags": [
|
||||
"111",
|
||||
"222",
|
||||
"333",
|
||||
"444"
|
||||
],
|
||||
"subscribed_tags": ["111","333"],
|
||||
"banned_tags": ["111"]
|
||||
},
|
||||
"result": true
|
||||
},
|
||||
{
|
||||
"case": {
|
||||
"post_tags": [
|
||||
"111",
|
||||
"222",
|
||||
"333",
|
||||
"444"
|
||||
],
|
||||
"subscribed_tags": ["222"],
|
||||
"banned_tags": ["555","333"]
|
||||
},
|
||||
"result": true
|
||||
}
|
||||
]
|
@ -98,3 +98,33 @@ async def test_parse_target(bilibili: "Bilibili"):
|
||||
await bilibili.parse_target(
|
||||
"https://www.bilibili.com/video/BV1qP4y1g738?spm_id_from=333.999.0.0"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def post_list():
|
||||
return get_json("bilibili_fake_dy_list.json")["data"]["cards"]
|
||||
|
||||
|
||||
# 测试新tag机制的平台推送情况
|
||||
@pytest.mark.asyncio
|
||||
async def test_filter_user_custom(bilibili, post_list):
|
||||
|
||||
only_banned_tags = ["~可露希尔的秘密档案"]
|
||||
res0 = await bilibili.filter_user_custom(post_list, [], only_banned_tags)
|
||||
assert len(res0) == 8
|
||||
|
||||
only_subscribed_tags = ["可露希尔的秘密档案"]
|
||||
res1 = await bilibili.filter_user_custom(post_list, [], only_subscribed_tags)
|
||||
assert len(res1) == 4
|
||||
|
||||
multi_subs_tags_1 = ["可露希尔的秘密档案", "罗德岛相簿"]
|
||||
res2 = await bilibili.filter_user_custom(post_list, [], multi_subs_tags_1)
|
||||
assert len(res2) == 4
|
||||
|
||||
multi_subs_tags_2 = ["罗德岛相簿", "风暴瞭望"]
|
||||
res3 = await bilibili.filter_user_custom(post_list, [], multi_subs_tags_2)
|
||||
assert len(res3) == 4
|
||||
|
||||
multi_subs_tags_3 = ["明日方舟", "~饼学大厦"]
|
||||
res4 = await bilibili.filter_user_custom(post_list, [], multi_subs_tags_3)
|
||||
assert len(res4) == 2
|
||||
|
32
tests/platforms/test_platform_tag_filter.py
Normal file
32
tests/platforms/test_platform_tag_filter.py
Normal file
@ -0,0 +1,32 @@
|
||||
import pytest
|
||||
from nonebug.app import App
|
||||
|
||||
from .utils import get_json
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def test_cases():
|
||||
return get_json("tag_cases.json")
|
||||
|
||||
|
||||
# 测试正反tag的判断情况
|
||||
@pytest.mark.asyncio
|
||||
async def test_filter_user_custom_tag(app: App, test_cases):
|
||||
from nonebot_bison.platform import platform_manager
|
||||
|
||||
bilibili = platform_manager["bilibili"]
|
||||
for case in test_cases:
|
||||
res = bilibili.is_banned_post(**case["case"])
|
||||
assert res == case["result"]
|
||||
|
||||
|
||||
# 测试正反tag的分离情况
|
||||
@pytest.mark.asyncio
|
||||
async def test_tag_separator(app: App):
|
||||
from nonebot_bison.platform import platform_manager
|
||||
|
||||
bilibili = platform_manager["bilibili"]
|
||||
tags = ["~111", "222", "333", "~444", "555"]
|
||||
res = bilibili.tag_separator(tags)
|
||||
assert res[0] == ["222", "333", "555"]
|
||||
assert res[1] == ["111", "444"]
|
@ -1,3 +1,5 @@
|
||||
from email import message
|
||||
|
||||
import pytest
|
||||
import respx
|
||||
from httpx import Response
|
||||
@ -151,12 +153,20 @@ async def test_add_with_target(app: App, init_scheduler):
|
||||
)
|
||||
ctx.receive_event(bot, event_5_ok)
|
||||
ctx.should_call_send(event_5_ok, Message(BotReply.add_reply_on_tags), True)
|
||||
event_6 = fake_group_message_event(
|
||||
event_6_more_info = fake_group_message_event(
|
||||
message=Message("详情"), sender=fake_admin_user
|
||||
)
|
||||
ctx.receive_event(bot, event_6_more_info)
|
||||
ctx.should_call_send(
|
||||
event_6_more_info, BotReply.add_reply_on_tags_need_more_info, True
|
||||
)
|
||||
ctx.should_rejected()
|
||||
event_6_ok = fake_group_message_event(
|
||||
message=Message("全部标签"), sender=fake_admin_user
|
||||
)
|
||||
ctx.receive_event(bot, event_6)
|
||||
ctx.receive_event(bot, event_6_ok)
|
||||
ctx.should_call_send(
|
||||
event_6, BotReply.add_reply_subscribe_success("明日方舟Arknights"), True
|
||||
event_6_ok, BotReply.add_reply_subscribe_success("明日方舟Arknights"), True
|
||||
)
|
||||
ctx.should_finished()
|
||||
subs = await config.list_subscribe(10000, "group")
|
||||
|
@ -99,7 +99,7 @@ class BotReply:
|
||||
|
||||
@staticmethod
|
||||
def add_reply_on_id_input_search():
|
||||
search_url = "https://nonebot-bison.vercel.app/usage/#%E6%89%80%E6%94%AF%E6%8C%81%E5%B9%B3%E5%8F%B0%E7%9A%84-uid"
|
||||
search_url = "https://nonebot-bison.netlify.app/usage/#%E6%89%80%E6%94%AF%E6%8C%81%E5%B9%B3%E5%8F%B0%E7%9A%84-uid"
|
||||
search_title = "Bison所支持的平台UID"
|
||||
search_content = "查询相关平台的uid格式或获取方式"
|
||||
search_image = "https://s3.bmp.ovh/imgs/2022/03/ab3cc45d83bd3dd3.jpg"
|
||||
@ -144,5 +144,6 @@ class BotReply:
|
||||
add_reply_on_id_input_error = "id输入错误"
|
||||
add_reply_on_target_parse_input_error = "不能从你的输入中提取出id,请检查你输入的内容是否符合预期"
|
||||
add_reply_on_platform_input_error = "平台输入错误"
|
||||
add_reply_on_tags = '请输入要订阅的tag,订阅所有tag输入"全部标签"'
|
||||
add_reply_on_tags = '请输入要订阅/屏蔽的tag(不含#号)\n多个tag请使用空格隔开\n具体规则回复"详情"'
|
||||
add_reply_on_tags_need_more_info = '订阅tag直接输入tag内容\n订阅所有tag输入"全部标签"\n屏蔽tag请在tag名称前添加~号\n详见https://nonebot-bison.netlify.app/usage/#平台订阅标签-tag'
|
||||
add_reply_abort = "已中止订阅"
|
||||
|
Loading…
x
Reference in New Issue
Block a user