diff --git a/README.md b/README.md index b9ed3db..40dd42f 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ - 图文 - 视频 - 纯文字 + - 转发 - Bilibili - 视频 - 图文 @@ -44,6 +45,7 @@ - 塞壬唱片新闻 - 游戏内公告 - 版本更新等通知 + - 泰拉记事社漫画 - 网易云音乐 - 歌手发布新专辑 - 电台更新 diff --git a/src/plugins/nonebot_bison/admin_page/__init__.py b/src/plugins/nonebot_bison/admin_page/__init__.py index 0436296..4ea89d8 100644 --- a/src/plugins/nonebot_bison/admin_page/__init__.py +++ b/src/plugins/nonebot_bison/admin_page/__init__.py @@ -129,8 +129,7 @@ def register_router_fastapi(driver: Driver, socketio): def init(): driver = get_driver() - if driver.type == "fastapi": - assert isinstance(driver, Driver) + if isinstance(driver, Driver): register_router_fastapi(driver, socket_app) else: logger.warning(f"Driver {driver.type} not supported") diff --git a/src/plugins/nonebot_bison/config_manager.py b/src/plugins/nonebot_bison/config_manager.py index 931bf3e..7e5a3f4 100644 --- a/src/plugins/nonebot_bison/config_manager.py +++ b/src/plugins/nonebot_bison/config_manager.py @@ -244,38 +244,46 @@ def do_del_sub(del_sub: Type[Matcher]): config: Config = Config() user_info = state["target_user_info"] assert isinstance(user_info, User) - sub_list = config.list_subscribe( - # state.get("_user_id") or event.group_id, "group" - user_info.user, - user_info.user_type, - ) - res = "订阅的帐号为:\n" - state["sub_table"] = {} - for index, sub in enumerate(sub_list, 1): - state["sub_table"][index] = { - "target_type": sub["target_type"], - "target": sub["target"], - } - res += "{} {} {} {}\n".format( - index, sub["target_type"], sub["target_name"], sub["target"] + try: + sub_list = config.list_subscribe( + # state.get("_user_id") or event.group_id, "group" + user_info.user, + user_info.user_type, ) - platform = platform_manager[sub["target_type"]] - if platform.categories: - res += " [{}]".format( - ", ".join( - map(lambda x: platform.categories[Category(x)], sub["cats"]) - ) + assert sub_list + except AssertionError: + await del_sub.finish("暂无已订阅账号\n请使用“添加订阅”命令添加订阅") + else: + res = "订阅的帐号为:\n" + state["sub_table"] = {} + for index, sub in enumerate(sub_list, 1): + state["sub_table"][index] = { + "target_type": sub["target_type"], + "target": sub["target"], + } + res += "{} {} {} {}\n".format( + index, sub["target_type"], sub["target_name"], sub["target"] ) - if platform.enable_tag: - res += " {}".format(", ".join(sub["tags"])) - res += "\n" - res += "请输入要删除的订阅的序号" - await bot.send(event=event, message=Message(await parse_text(res))) + platform = platform_manager[sub["target_type"]] + if platform.categories: + res += " [{}]".format( + ", ".join( + map(lambda x: platform.categories[Category(x)], sub["cats"]) + ) + ) + if platform.enable_tag: + res += " {}".format(", ".join(sub["tags"])) + res += "\n" + res += "请输入要删除的订阅的序号\n输入'取消'中止" + await bot.send(event=event, message=Message(await parse_text(res))) @del_sub.receive() async def do_del(event: Event, state: T_State): + user_msg = str(event.get_message()).strip() + if user_msg == "取消": + await del_sub.finish("删除中止") try: - index = int(str(event.get_message()).strip()) + index = int(user_msg) config = Config() user_info = state["target_user_info"] assert isinstance(user_info, User) @@ -297,12 +305,13 @@ add_sub_matcher = on_command( rule=configurable_to_me, permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER, priority=5, + block=True, ) add_sub_matcher.handle()(set_target_user_info) do_add_sub(add_sub_matcher) -query_sub_matcher = on_command("查询订阅", rule=configurable_to_me, priority=5) +query_sub_matcher = on_command("查询订阅", rule=configurable_to_me, priority=5, block=True) query_sub_matcher.handle()(set_target_user_info) do_query_sub(query_sub_matcher) @@ -312,11 +321,14 @@ del_sub_matcher = on_command( rule=configurable_to_me, permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER, priority=5, + block=True, ) del_sub_matcher.handle()(set_target_user_info) do_del_sub(del_sub_matcher) -group_manage_matcher = on_command("群管理", rule=to_me(), permission=SUPERUSER, priority=4) +group_manage_matcher = on_command( + "群管理", rule=to_me(), permission=SUPERUSER, priority=4, block=True +) @group_manage_matcher.handle() diff --git a/src/plugins/nonebot_bison/platform/arknights.py b/src/plugins/nonebot_bison/platform/arknights.py index 0b3c21f..4a5c523 100644 --- a/src/plugins/nonebot_bison/platform/arknights.py +++ b/src/plugins/nonebot_bison/platform/arknights.py @@ -189,3 +189,47 @@ class MonsterSiren(NewMessage): compress=True, override_use_pic=False, ) + + +class TerraHistoricusComic(NewMessage): + + categories = {4: "泰拉记事社漫画"} + platform_name = "arknights" + name = "明日方舟游戏信息" + enable_tag = False + enabled = True + is_common = False + schedule_type = "interval" + schedule_kw = {"seconds": 30} + has_target = False + + async def get_target_name(self, _: Target) -> str: + return "明日方舟游戏信息" + + async def get_sub_list(self, _) -> list[RawPost]: + async with httpx.AsyncClient() as client: + raw_data = await client.get( + "https://terra-historicus.hypergryph.com/api/recentUpdate" + ) + return raw_data.json()["data"] + + def get_id(self, post: RawPost) -> Any: + return f'{post["comicCid"]}/{post["episodeCid"]}' + + def get_date(self, _) -> None: + return None + + def get_category(self, _) -> Category: + return Category(4) + + async def parse(self, raw_post: RawPost) -> Post: + url = f'https://terra-historicus.hypergryph.com/comic/{raw_post["comicCid"]}/episode/{raw_post["episodeCid"]}' + return Post( + "terra-historicus", + text=f'{raw_post["title"]} - {raw_post["episodeShortTitle"]}', + pics=[raw_post["coverUrl"]], + url=url, + target_name="泰拉记事社漫画", + compress=True, + override_use_pic=False, + ) diff --git a/src/plugins/nonebot_bison/platform/weibo.py b/src/plugins/nonebot_bison/platform/weibo.py index bcd0995..38cd68d 100644 --- a/src/plugins/nonebot_bison/platform/weibo.py +++ b/src/plugins/nonebot_bison/platform/weibo.py @@ -123,7 +123,11 @@ class Weibo(NewMessage): "Mobile Safari/537.36", } info = raw_post["mblog"] - if info["isLongText"] or info["pic_num"] > 9: + retweeted = False + if info.get("retweeted_status"): + retweeted = True + pic_num = info["retweeted_status"]["pic_num"] if retweeted else info["pic_num"] + if info["isLongText"] or pic_num > 9: async with httpx.AsyncClient() as client: res = await client.get( "https://m.weibo.cn/detail/{}".format(info["mid"]), headers=header @@ -140,7 +144,12 @@ class Weibo(NewMessage): ) ) parsed_text = self._get_text(info["text"]) - pic_urls = [img["large"]["url"] for img in info.get("pics", [])] + raw_pics_list = ( + info["retweeted_status"].get("pics", []) + if retweeted + else info.get("pics", []) + ) + pic_urls = [img["large"]["url"] for img in raw_pics_list] detail_url = "https://weibo.com/{}/{}".format(info["user"]["id"], info["bid"]) # return parsed_text, detail_url, pic_urls return Post( diff --git a/tests/platforms/static/terra-hist-0.json b/tests/platforms/static/terra-hist-0.json new file mode 100644 index 0000000..4d09cf3 --- /dev/null +++ b/tests/platforms/static/terra-hist-0.json @@ -0,0 +1 @@ +{"code":0,"msg":"","data":[{"coverUrl":"https://web.hycdn.cn/comic/pic/20220507/c4da4fb95587101f1867a30fe85cb557.png","comicCid":"6253","title":"123罗德岛!?","subtitle":"你可能不知道的罗德岛小剧场!","episodeCid":"5771","episodeType":1,"episodeShortTitle":"「流明」篇","updateTime":1652025600},{"coverUrl":"https://web.hycdn.cn/comic/pic/20220505/5c296539f5dc808603f20dda86879c9c.png","comicCid":"0696","title":"A1行动预备组","subtitle":"","episodeCid":"2897","episodeType":1,"episodeShortTitle":"01","updateTime":1651852800},{"coverUrl":"https://web.hycdn.cn/comic/pic/20220428/f4dc1e91420d18eccb80d60bba322d42.png","comicCid":"6253","title":"123罗德岛!?","subtitle":"你可能不知道的罗德岛小剧场!","episodeCid":"6346","episodeType":1,"episodeShortTitle":"「艾丽妮」篇","updateTime":1651507200}]} diff --git a/tests/platforms/static/terra-hist-1.json b/tests/platforms/static/terra-hist-1.json new file mode 100644 index 0000000..a70358b --- /dev/null +++ b/tests/platforms/static/terra-hist-1.json @@ -0,0 +1 @@ +{"code":0,"msg":"","data":[{"coverUrl":"https://web.hycdn.cn/comic/pic/20220507/ab8a2ff408ec7d587775aed70b178ec0.png","comicCid":"6253","title":"123罗德岛!?","subtitle":"你可能不知道的罗德岛小剧场!","episodeCid":"4938","episodeType":1,"episodeShortTitle":"「掠风」篇","updateTime":1652112000},{"coverUrl":"https://web.hycdn.cn/comic/pic/20220507/c4da4fb95587101f1867a30fe85cb557.png","comicCid":"6253","title":"123罗德岛!?","subtitle":"你可能不知道的罗德岛小剧场!","episodeCid":"5771","episodeType":1,"episodeShortTitle":"「流明」篇","updateTime":1652025600},{"coverUrl":"https://web.hycdn.cn/comic/pic/20220505/5c296539f5dc808603f20dda86879c9c.png","comicCid":"0696","title":"A1行动预备组","subtitle":"","episodeCid":"2897","episodeType":1,"episodeShortTitle":"01","updateTime":1651852800},{"coverUrl":"https://web.hycdn.cn/comic/pic/20220428/f4dc1e91420d18eccb80d60bba322d42.png","comicCid":"6253","title":"123罗德岛!?","subtitle":"你可能不知道的罗德岛小剧场!","episodeCid":"6346","episodeType":1,"episodeShortTitle":"「艾丽妮」篇","updateTime":1651507200}]} \ No newline at end of file diff --git a/tests/platforms/test_arknights.py b/tests/platforms/test_arknights.py index 7b3f386..ba81db0 100644 --- a/tests/platforms/test_arknights.py +++ b/tests/platforms/test_arknights.py @@ -61,6 +61,7 @@ async def test_fetch_new( "https://ak-conf.hypergryph.com/config/prod/announce_meta/IOS/preannouncement.meta.json" ) monster_siren_router = respx.get("https://monster-siren.hypergryph.com/api/news") + terra_list = respx.get("https://terra-historicus.hypergryph.com/api/recentUpdate") ak_list_router.mock(return_value=Response(200, json=arknights_list__1)) detail_router.mock( return_value=Response(200, text=get_file("arknights-detail-807")) @@ -72,6 +73,7 @@ async def test_fetch_new( return_value=Response(200, json=get_json("arknights-pre-0.json")) ) monster_siren_router.mock(return_value=Response(200, json=monster_siren_list_0)) + terra_list.mock(return_value=Response(200, json=get_json("terra-hist-0.json"))) target = "" res = await arknights.fetch_new_post(target, [dummy_user_subinfo]) assert ak_list_router.called @@ -90,7 +92,17 @@ async def test_fetch_new( assert len(post.pics) == 1 # assert(post.pics == ['https://ak-fs.hypergryph.com/announce/images/20210623/e6f49aeb9547a2278678368a43b95b07.jpg']) print(res3[0][1]) - r = await post.generate_messages() + await post.generate_messages() + terra_list.mock(return_value=Response(200, json=get_json("terra-hist-1.json"))) + res = await arknights.fetch_new_post(target, [dummy_user_subinfo]) + assert len(res) == 1 + post = res[0][1][0] + assert post.target_type == "terra-historicus" + assert post.text == "123罗德岛!? - 「掠风」篇" + assert post.url == "https://terra-historicus.hypergryph.com/comic/6253/episode/4938" + assert post.pics == [ + "https://web.hycdn.cn/comic/pic/20220507/ab8a2ff408ec7d587775aed70b178ec0.png" + ] @pytest.mark.render @@ -116,6 +128,7 @@ async def test_send_with_render( "https://ak-conf.hypergryph.com/config/prod/announce_meta/IOS/preannouncement.meta.json" ) monster_siren_router = respx.get("https://monster-siren.hypergryph.com/api/news") + terra_list = respx.get("https://terra-historicus.hypergryph.com/api/recentUpdate") ak_list_router.mock(return_value=Response(200, json=arknights_list_0)) detail_router.mock( return_value=Response(200, text=get_file("arknights-detail-805")) @@ -127,6 +140,7 @@ async def test_send_with_render( return_value=Response(200, json=get_json("arknights-pre-0.json")) ) monster_siren_router.mock(return_value=Response(200, json=monster_siren_list_0)) + terra_list.mock(return_value=Response(200, json=get_json("terra-hist-0.json"))) target = "" res = await arknights.fetch_new_post(target, [dummy_user_subinfo]) assert ak_list_router.called diff --git a/tests/platforms/test_weibo.py b/tests/platforms/test_weibo.py index c241408..178debc 100644 --- a/tests/platforms/test_weibo.py +++ b/tests/platforms/test_weibo.py @@ -23,7 +23,14 @@ def weibo_ak_list_1(): @pytest.mark.asyncio +@respx.mock async def test_get_name(weibo): + profile_router = respx.get( + "https://m.weibo.cn/api/container/getIndex?containerid=1005056279793937" + ) + profile_router.mock( + return_value=Response(200, json=get_json("weibo_ak_profile.json")) + ) name = await weibo.get_target_name("6279793937") assert name == "明日方舟Arknights" diff --git a/tests/test_config_manager_abort.py b/tests/test_config_manager_abort.py index da307f4..65921a1 100644 --- a/tests/test_config_manager_abort.py +++ b/tests/test_config_manager_abort.py @@ -281,3 +281,49 @@ async def test_abort_add_on_tag(app: App): True, ) ctx.should_finished() + + +# 删除订阅阶段中止 +@pytest.mark.asyncio +async def test_abort_del_sub(app: App): + from nonebot.adapters.onebot.v11.bot import Bot + from nonebot.adapters.onebot.v11.message import Message + from nonebot_bison.config import Config + from nonebot_bison.config_manager import del_sub_matcher + from nonebot_bison.platform import platform_manager + + config = Config() + config.user_target.truncate() + config.add_subscribe( + 10000, + "group", + "6279793937", + "明日方舟Arknights", + "weibo", + [platform_manager["weibo"].reverse_category["图文"]], + ["明日方舟"], + ) + async with app.test_matcher(del_sub_matcher) as ctx: + bot = ctx.create_bot(base=Bot) + assert isinstance(bot, Bot) + event = fake_group_message_event( + message=Message("删除订阅"), to_me=True, sender=fake_admin_user + ) + ctx.receive_event(bot, event) + ctx.should_pass_rule() + ctx.should_pass_permission() + ctx.should_call_send( + event, + Message( + "订阅的帐号为:\n1 weibo 明日方舟Arknights 6279793937\n [图文] 明日方舟\n请输入要删除的订阅的序号\n输入'取消'中止" + ), + True, + ) + event_abort = fake_group_message_event( + message=Message("取消"), sender=fake_admin_user + ) + ctx.receive_event(bot, event_abort) + ctx.should_call_send(event_abort, "删除中止", True) + ctx.should_finished() + subs = config.list_subscribe(10000, "group") + assert subs diff --git a/tests/test_config_manager_add.py b/tests/test_config_manager_add.py index a38a1a8..ae679c0 100644 --- a/tests/test_config_manager_add.py +++ b/tests/test_config_manager_add.py @@ -387,8 +387,8 @@ async def test_add_with_get_id(app: App): True, ) """ - line 362: - 鬼知道为什么要在这里这样写, + 关于Message([MessageSegment(*BotReply.add_reply_on_id_input_search())]): + 异客知道为什么要在这里这样写, 没有[]的话assert不了(should_call_send使用[MessageSegment(...)]的格式进行比较) 不在这里MessageSegment()的话也assert不了(指不能让add_reply_on_id_input_search直接返回一个MessageSegment对象) amen diff --git a/tests/test_config_manager_query_del.py b/tests/test_config_manager_query_del.py index 51dd80d..f995a9c 100644 --- a/tests/test_config_manager_query_del.py +++ b/tests/test_config_manager_query_del.py @@ -67,7 +67,7 @@ async def test_del_sub(app: App): ctx.should_call_send( event, Message( - "订阅的帐号为:\n1 weibo 明日方舟Arknights 6279793937\n [图文] 明日方舟\n请输入要删除的订阅的序号" + "订阅的帐号为:\n1 weibo 明日方舟Arknights 6279793937\n [图文] 明日方舟\n请输入要删除的订阅的序号\n输入'取消'中止" ), True, ) @@ -85,3 +85,30 @@ async def test_del_sub(app: App): ctx.should_finished() subs = config.list_subscribe(10000, "group") assert len(subs) == 0 + + +@pytest.mark.asyncio +async def test_del_empty_sub(app: App): + from nonebot.adapters.onebot.v11.bot import Bot + from nonebot.adapters.onebot.v11.message import Message + from nonebot_bison.config import Config + from nonebot_bison.config_manager import del_sub_matcher + from nonebot_bison.platform import platform_manager + + config = Config() + config.user_target.truncate() + async with app.test_matcher(del_sub_matcher) as ctx: + bot = ctx.create_bot(base=Bot) + assert isinstance(bot, Bot) + event = fake_group_message_event( + message=Message("删除订阅"), to_me=True, sender=fake_admin_user + ) + ctx.receive_event(bot, event) + ctx.should_pass_rule() + ctx.should_pass_permission() + ctx.should_finished() + ctx.should_call_send( + event, + "暂无已订阅账号\n请使用“添加订阅”命令添加订阅", + True, + )