From 840519baa1c0249a8c52488cb1946c1bee599ce6 Mon Sep 17 00:00:00 2001 From: Sichongzou <68594934+Sichongzou@users.noreply.github.com> Date: Wed, 18 May 2022 09:00:03 +0800 Subject: [PATCH 01/29] Update bilibili.py --- .../nonebot_bison/platform/bilibili.py | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/plugins/nonebot_bison/platform/bilibili.py b/src/plugins/nonebot_bison/platform/bilibili.py index ad21a8a..3ccd7af 100644 --- a/src/plugins/nonebot_bison/platform/bilibili.py +++ b/src/plugins/nonebot_bison/platform/bilibili.py @@ -5,7 +5,7 @@ import httpx from ..post import Post from ..types import Category, RawPost, Tag, Target -from .platform import CategoryNotSupport, NewMessage +from .platform import CategoryNotSupport, NewMessage,StatusChange class Bilibili(NewMessage): @@ -144,3 +144,62 @@ class Bilibili(NewMessage): else: raise CategoryNotSupport(post_type) return Post("bilibili", text=text, url=url, pics=pic, target_name=target_name) + +class Bilibililive(StatusChange): +# Author : Sichongzou +# Date : 2022-5-18 8:54 +# Description : bilibili开播提醒 +# E-mail : 1557157806@qq.com + categories = {} + platform_name = "bilibililive" + enable_tag = True + enabled = True + is_common = True + schedule_type = "interval" + schedule_kw = {"seconds": 10} + name = "B站直播" + has_target = True + + async def get_target_name(self, target: Target) -> Optional[str]: + async with httpx.AsyncClient() as client: + res = await client.get( + "https://api.bilibili.com/x/space/acc/info", params={"mid": target} + ) + res_data = json.loads(res.text) + if res_data["code"]: + return None + return res_data["data"]["name"] + + async def get_status(self, target: Target): + async with httpx.AsyncClient() as client: + params = {"mid": target} + res = await client.get( + "https://api.bilibili.com/x/space/acc/info", + params=params, + timeout=4.0, + ) + res_dict = json.loads(res.text) + if res_dict["code"] == 0: + info={} + info["uid"]=res_dict["data"]["mid"] + info["uname"]=res_dict["data"]["name"] + info["live_state"]=res_dict["data"]["live_room"]["liveStatus"] + info["url"]=res_dict["data"]["live_room"]["url"] + info["title"]=res_dict["data"]["live_room"]["title"] + info["cover"]=res_dict["data"]["live_room"]["cover"] + return info + else: + return [] + + def compare_status(self, target: Target, old_status, new_status) -> list[RawPost]: + if(new_status["live_state"]!=old_status["live_state"] and new_status["live_state"]==1): + return [new_status] + else: + return[] + + async def parse(self, raw_post: RawPost) -> Post: + url=raw_post["url"] + pic=[raw_post["cover"]] + target_name=raw_post["uname"] + text=target_name+"老师的直播 开播啦!小伙伴们请务必速速来围观!" + return Post("bilibililive", text=text, url=url, pics=pic, target_name=target_name) From aa29c57d05c3b366b327fb7d2e32f9748950ada6 Mon Sep 17 00:00:00 2001 From: Sichongzou <68594934+Sichongzou@users.noreply.github.com> Date: Wed, 18 May 2022 09:02:13 +0800 Subject: [PATCH 02/29] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b9ed3db..527b317 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ - 专栏 - 转发 - 纯文字 + - 开播提醒 - RSS - 富文本转换为纯文本 - 提取出所有图片 From 3204e84346594a51b44a5c6c365d7c0921999c3f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 18 May 2022 01:04:24 +0000 Subject: [PATCH 03/29] auto fix by pre-commit hooks --- .../nonebot_bison/platform/bilibili.py | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/plugins/nonebot_bison/platform/bilibili.py b/src/plugins/nonebot_bison/platform/bilibili.py index 3ccd7af..0c543ff 100644 --- a/src/plugins/nonebot_bison/platform/bilibili.py +++ b/src/plugins/nonebot_bison/platform/bilibili.py @@ -5,7 +5,7 @@ import httpx from ..post import Post from ..types import Category, RawPost, Tag, Target -from .platform import CategoryNotSupport, NewMessage,StatusChange +from .platform import CategoryNotSupport, NewMessage, StatusChange class Bilibili(NewMessage): @@ -145,11 +145,12 @@ class Bilibili(NewMessage): raise CategoryNotSupport(post_type) return Post("bilibili", text=text, url=url, pics=pic, target_name=target_name) + class Bilibililive(StatusChange): -# Author : Sichongzou -# Date : 2022-5-18 8:54 -# Description : bilibili开播提醒 -# E-mail : 1557157806@qq.com + # Author : Sichongzou + # Date : 2022-5-18 8:54 + # Description : bilibili开播提醒 + # E-mail : 1557157806@qq.com categories = {} platform_name = "bilibililive" enable_tag = True @@ -180,26 +181,31 @@ class Bilibililive(StatusChange): ) res_dict = json.loads(res.text) if res_dict["code"] == 0: - info={} - info["uid"]=res_dict["data"]["mid"] - info["uname"]=res_dict["data"]["name"] - info["live_state"]=res_dict["data"]["live_room"]["liveStatus"] - info["url"]=res_dict["data"]["live_room"]["url"] - info["title"]=res_dict["data"]["live_room"]["title"] - info["cover"]=res_dict["data"]["live_room"]["cover"] + info = {} + info["uid"] = res_dict["data"]["mid"] + info["uname"] = res_dict["data"]["name"] + info["live_state"] = res_dict["data"]["live_room"]["liveStatus"] + info["url"] = res_dict["data"]["live_room"]["url"] + info["title"] = res_dict["data"]["live_room"]["title"] + info["cover"] = res_dict["data"]["live_room"]["cover"] return info else: return [] def compare_status(self, target: Target, old_status, new_status) -> list[RawPost]: - if(new_status["live_state"]!=old_status["live_state"] and new_status["live_state"]==1): + if ( + new_status["live_state"] != old_status["live_state"] + and new_status["live_state"] == 1 + ): return [new_status] else: - return[] - + return [] + async def parse(self, raw_post: RawPost) -> Post: - url=raw_post["url"] - pic=[raw_post["cover"]] - target_name=raw_post["uname"] - text=target_name+"老师的直播 开播啦!小伙伴们请务必速速来围观!" - return Post("bilibililive", text=text, url=url, pics=pic, target_name=target_name) + url = raw_post["url"] + pic = [raw_post["cover"]] + target_name = raw_post["uname"] + text = target_name + "老师的直播 开播啦!小伙伴们请务必速速来围观!" + return Post( + "bilibililive", text=text, url=url, pics=pic, target_name=target_name + ) From 05e0158904a56adeedb903b9208e175d336ef31d Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Mon, 23 May 2022 14:15:34 +0800 Subject: [PATCH 04/29] catch ssl error --- src/plugins/nonebot_bison/platform/platform.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/plugins/nonebot_bison/platform/platform.py b/src/plugins/nonebot_bison/platform/platform.py index 19f002d..b5de376 100644 --- a/src/plugins/nonebot_bison/platform/platform.py +++ b/src/plugins/nonebot_bison/platform/platform.py @@ -1,3 +1,4 @@ +import ssl import time from abc import ABC, abstractmethod from collections import defaultdict @@ -250,6 +251,9 @@ class NewMessage(MessageProcess, abstract=True): ) ) return [] + except ssl.SSLError as err: + logger.warning(f"ssl error: {err}") + return [] class StatusChange(Platform, abstract=True): @@ -294,6 +298,9 @@ class StatusChange(Platform, abstract=True): ) ) return [] + except ssl.SSLError as err: + logger.warning(f"ssl error: {err}") + return [] class SimplePost(MessageProcess, abstract=True): @@ -325,6 +332,9 @@ class SimplePost(MessageProcess, abstract=True): ) ) return [] + except ssl.SSLError as err: + logger.warning(f"ssl error: {err}") + return [] class NoTargetGroup(Platform, abstract=True): From 63b72d9c5bf9968a3a164b4c3a12d2ff5ff0246f Mon Sep 17 00:00:00 2001 From: Azide Date: Mon, 23 May 2022 14:38:35 +0800 Subject: [PATCH 05/29] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86bilibili?= =?UTF-8?q?=E7=9B=B4=E6=92=AD=E7=9A=84=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nonebot_bison/platform/bilibili.py | 16 +-- .../platforms/static/bili_live_status-0.json | 114 ++++++++++++++++++ .../platforms/static/bili_live_status-1.json | 114 ++++++++++++++++++ tests/platforms/test_bilibili_live.py | 41 +++++++ 4 files changed, 277 insertions(+), 8 deletions(-) create mode 100644 tests/platforms/static/bili_live_status-0.json create mode 100644 tests/platforms/static/bili_live_status-1.json create mode 100644 tests/platforms/test_bilibili_live.py diff --git a/src/plugins/nonebot_bison/platform/bilibili.py b/src/plugins/nonebot_bison/platform/bilibili.py index 0c543ff..ae196e4 100644 --- a/src/plugins/nonebot_bison/platform/bilibili.py +++ b/src/plugins/nonebot_bison/platform/bilibili.py @@ -1,4 +1,5 @@ import json +from turtle import title from typing import Any, Optional import httpx @@ -152,13 +153,13 @@ class Bilibililive(StatusChange): # Description : bilibili开播提醒 # E-mail : 1557157806@qq.com categories = {} - platform_name = "bilibililive" + platform_name = "bilibili-live" enable_tag = True enabled = True is_common = True schedule_type = "interval" schedule_kw = {"seconds": 10} - name = "B站直播" + name = "Bilibili直播" has_target = True async def get_target_name(self, target: Target) -> Optional[str]: @@ -185,7 +186,7 @@ class Bilibililive(StatusChange): info["uid"] = res_dict["data"]["mid"] info["uname"] = res_dict["data"]["name"] info["live_state"] = res_dict["data"]["live_room"]["liveStatus"] - info["url"] = res_dict["data"]["live_room"]["url"] + info["room_id"] = res_dict["data"]["live_room"]["roomid"] info["title"] = res_dict["data"]["live_room"]["title"] info["cover"] = res_dict["data"]["live_room"]["cover"] return info @@ -202,10 +203,9 @@ class Bilibililive(StatusChange): return [] async def parse(self, raw_post: RawPost) -> Post: - url = raw_post["url"] + url = "https://live.bilibili.com/{}".format(raw_post["room_id"]) pic = [raw_post["cover"]] target_name = raw_post["uname"] - text = target_name + "老师的直播 开播啦!小伙伴们请务必速速来围观!" - return Post( - "bilibililive", text=text, url=url, pics=pic, target_name=target_name - ) + title = raw_post["title"] + text = "{} 直播中:\n{}\n\n小伙伴们速速前来围观!".format(target_name, title) + return Post(self.name, text=text, url=url, pics=pic, target_name=target_name) diff --git a/tests/platforms/static/bili_live_status-0.json b/tests/platforms/static/bili_live_status-0.json new file mode 100644 index 0000000..e907dc9 --- /dev/null +++ b/tests/platforms/static/bili_live_status-0.json @@ -0,0 +1,114 @@ +{ + "code": 0, + "message": "0", + "ttl": 1, + "data": { + "mid": 13164144, + "name": "魔法Zc目录", + "sex": "男", + "face": "http://i0.hdslb.com/bfs/face/a84fa10f90f7060d0336384954ee1cde7a8e9bc6.jpg", + "face_nft": 0, + "sign": "每日18:00~22:00欢乐直播!请勿在任何乌有相关内容中刷Zc,尊重角色;商务合作qq271374252", + "rank": 10000, + "level": 6, + "jointime": 0, + "moral": 0, + "silence": 0, + "coins": 0, + "fans_badge": true, + "fans_medal": { + "show": false, + "wear": false, + "medal": null + }, + "official": { + "role": 1, + "title": "bilibili 2021百大UP主、知名游戏UP主、直播高能主播", + "desc": "", + "type": 0 + }, + "vip": { + "type": 2, + "status": 1, + "due_date": 1702051200000, + "vip_pay_type": 0, + "theme_type": 0, + "label": { + "path": "", + "text": "年度大会员", + "label_theme": "annual_vip", + "text_color": "#FFFFFF", + "bg_style": 1, + "bg_color": "#FB7299", + "border_color": "" + }, + "avatar_subscript": 1, + "nickname_color": "#FB7299", + "role": 3, + "avatar_subscript_url": "http://i0.hdslb.com/bfs/vip/icon_Certification_big_member_22_3x.png" + }, + "pendant": { + "pid": 3399, + "name": "2233幻星集", + "image": "http://i0.hdslb.com/bfs/garb/item/20c07ded13498a5b12db99660c766ddd92ecfe31.png", + "expire": 0, + "image_enhance": "http://i0.hdslb.com/bfs/garb/item/20c07ded13498a5b12db99660c766ddd92ecfe31.png", + "image_enhance_frame": "" + }, + "nameplate": { + "nid": 1, + "name": "黄金殿堂", + "image": "http://i2.hdslb.com/bfs/face/82896ff40fcb4e7c7259cb98056975830cb55695.png", + "image_small": "http://i0.hdslb.com/bfs/face/627e342851dfda6fe7380c2fa0cbd7fae2e61533.png", + "level": "稀有勋章", + "condition": "单个自制视频总播放数\u003e=100万" + }, + "user_honour_info": { + "mid": 0, + "colour": null, + "tags": [] + }, + "is_followed": true, + "top_photo": "http://i2.hdslb.com/bfs/space/853fea2728651588a2cdef0a1e586bcefff8e3d8.png", + "theme": {}, + "sys_notice": {}, + "live_room": { + "roomStatus": 1, + "liveStatus": 0, + "url": "https://live.bilibili.com/3044248?broadcast_type=0\u0026is_room_feed=1", + "title": "【Zc】早朝危机合约!", + "cover": "http://i0.hdslb.com/bfs/live/new_room_cover/cf7d4d3b2f336c6dba299644c3af952c5db82612.jpg", + "roomid": 3044248, + "roundStatus": 1, + "broadcast_type": 0, + "watched_show": { + "switch": true, + "num": 13753, + "text_small": "1.3万", + "text_large": "1.3万人看过", + "icon": "https://i0.hdslb.com/bfs/live/a725a9e61242ef44d764ac911691a7ce07f36c1d.png", + "icon_location": "", + "icon_web": "https://i0.hdslb.com/bfs/live/8d9d0f33ef8bf6f308742752d13dd0df731df19c.png" + } + }, + "birthday": "07-21", + "school": { + "name": "" + }, + "profession": { + "name": "", + "department": "", + "title": "", + "is_show": 0 + }, + "tags": [ + "评论区UP主", + "目标是星辰大海" + ], + "series": { + "user_upgrade_status": 3, + "show_upgrade_window": false + }, + "is_senior_member": 1 + } +} \ No newline at end of file diff --git a/tests/platforms/static/bili_live_status-1.json b/tests/platforms/static/bili_live_status-1.json new file mode 100644 index 0000000..9d0d02f --- /dev/null +++ b/tests/platforms/static/bili_live_status-1.json @@ -0,0 +1,114 @@ +{ + "code": 0, + "message": "0", + "ttl": 1, + "data": { + "mid": 13164144, + "name": "魔法Zc目录", + "sex": "男", + "face": "http://i0.hdslb.com/bfs/face/a84fa10f90f7060d0336384954ee1cde7a8e9bc6.jpg", + "face_nft": 0, + "sign": "每日18:00~22:00欢乐直播!请勿在任何乌有相关内容中刷Zc,尊重角色;商务合作qq271374252", + "rank": 10000, + "level": 6, + "jointime": 0, + "moral": 0, + "silence": 0, + "coins": 0, + "fans_badge": true, + "fans_medal": { + "show": false, + "wear": false, + "medal": null + }, + "official": { + "role": 1, + "title": "bilibili 2021百大UP主、知名游戏UP主、直播高能主播", + "desc": "", + "type": 0 + }, + "vip": { + "type": 2, + "status": 1, + "due_date": 1702051200000, + "vip_pay_type": 0, + "theme_type": 0, + "label": { + "path": "", + "text": "年度大会员", + "label_theme": "annual_vip", + "text_color": "#FFFFFF", + "bg_style": 1, + "bg_color": "#FB7299", + "border_color": "" + }, + "avatar_subscript": 1, + "nickname_color": "#FB7299", + "role": 3, + "avatar_subscript_url": "http://i0.hdslb.com/bfs/vip/icon_Certification_big_member_22_3x.png" + }, + "pendant": { + "pid": 3399, + "name": "2233幻星集", + "image": "http://i0.hdslb.com/bfs/garb/item/20c07ded13498a5b12db99660c766ddd92ecfe31.png", + "expire": 0, + "image_enhance": "http://i0.hdslb.com/bfs/garb/item/20c07ded13498a5b12db99660c766ddd92ecfe31.png", + "image_enhance_frame": "" + }, + "nameplate": { + "nid": 1, + "name": "黄金殿堂", + "image": "http://i2.hdslb.com/bfs/face/82896ff40fcb4e7c7259cb98056975830cb55695.png", + "image_small": "http://i0.hdslb.com/bfs/face/627e342851dfda6fe7380c2fa0cbd7fae2e61533.png", + "level": "稀有勋章", + "condition": "单个自制视频总播放数\u003e=100万" + }, + "user_honour_info": { + "mid": 0, + "colour": null, + "tags": [] + }, + "is_followed": true, + "top_photo": "http://i2.hdslb.com/bfs/space/853fea2728651588a2cdef0a1e586bcefff8e3d8.png", + "theme": {}, + "sys_notice": {}, + "live_room": { + "roomStatus": 1, + "liveStatus": 1, + "url": "https://live.bilibili.com/3044248?broadcast_type=0\u0026is_room_feed=1", + "title": "【Zc】早朝危机合约!", + "cover": "http://i0.hdslb.com/bfs/live/new_room_cover/cf7d4d3b2f336c6dba299644c3af952c5db82612.jpg", + "roomid": 3044248, + "roundStatus": 1, + "broadcast_type": 0, + "watched_show": { + "switch": true, + "num": 13753, + "text_small": "1.3万", + "text_large": "1.3万人看过", + "icon": "https://i0.hdslb.com/bfs/live/a725a9e61242ef44d764ac911691a7ce07f36c1d.png", + "icon_location": "", + "icon_web": "https://i0.hdslb.com/bfs/live/8d9d0f33ef8bf6f308742752d13dd0df731df19c.png" + } + }, + "birthday": "07-21", + "school": { + "name": "" + }, + "profession": { + "name": "", + "department": "", + "title": "", + "is_show": 0 + }, + "tags": [ + "评论区UP主", + "目标是星辰大海" + ], + "series": { + "user_upgrade_status": 3, + "show_upgrade_window": false + }, + "is_senior_member": 1 + } +} \ No newline at end of file diff --git a/tests/platforms/test_bilibili_live.py b/tests/platforms/test_bilibili_live.py new file mode 100644 index 0000000..ccdb78f --- /dev/null +++ b/tests/platforms/test_bilibili_live.py @@ -0,0 +1,41 @@ +from datetime import datetime + +import feedparser +import pytest +import respx +from httpx import Response +from nonebug.app import App +from pytz import timezone + +from .utils import get_file, get_json + + +@pytest.fixture +def bili_live(app: App): + from nonebot_bison.platform import platform_manager + + return platform_manager["bilibili-live"] + + +@pytest.mark.asyncio +@respx.mock +async def test_fetch_bilibili_live_status(bili_live, dummy_user_subinfo): + bili_live_router = respx.get( + "https://api.bilibili.com/x/space/acc/info?mid=13164144" + ) + bili_live_router.mock( + return_value=Response(200, json=get_json("bili_live_status-0.json")) + ) + target = "13164144" + res = await bili_live.fetch_new_post(target, [dummy_user_subinfo]) + assert bili_live_router.called + assert len(res) == 0 + bili_live_router.mock( + return_value=Response(200, json=get_json("bili_live_status-1.json")) + ) + res2 = await bili_live.fetch_new_post(target, [dummy_user_subinfo]) + post = res2[0][1][0] + assert post.target_type == "Bilibili直播" + assert post.text == "魔法Zc目录 直播中:\n【Zc】早朝危机合约!\n\n小伙伴们速速前来围观!" + assert post.url == "https://live.bilibili.com/3044248" + assert post.target_name == "魔法Zc目录" From e375a000ee7e3ee55d0bc53a69936989eb55f283 Mon Sep 17 00:00:00 2001 From: Azide Date: Mon, 23 May 2022 14:54:05 +0800 Subject: [PATCH 06/29] =?UTF-8?q?=E7=AE=80=E5=8C=96=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=AD=A5=E9=AA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platforms/static/bili_live_status-1.json | 114 ------------------ ...ve_status-0.json => bili_live_status.json} | 0 tests/platforms/test_bilibili_live.py | 11 +- 3 files changed, 5 insertions(+), 120 deletions(-) delete mode 100644 tests/platforms/static/bili_live_status-1.json rename tests/platforms/static/{bili_live_status-0.json => bili_live_status.json} (100%) diff --git a/tests/platforms/static/bili_live_status-1.json b/tests/platforms/static/bili_live_status-1.json deleted file mode 100644 index 9d0d02f..0000000 --- a/tests/platforms/static/bili_live_status-1.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "code": 0, - "message": "0", - "ttl": 1, - "data": { - "mid": 13164144, - "name": "魔法Zc目录", - "sex": "男", - "face": "http://i0.hdslb.com/bfs/face/a84fa10f90f7060d0336384954ee1cde7a8e9bc6.jpg", - "face_nft": 0, - "sign": "每日18:00~22:00欢乐直播!请勿在任何乌有相关内容中刷Zc,尊重角色;商务合作qq271374252", - "rank": 10000, - "level": 6, - "jointime": 0, - "moral": 0, - "silence": 0, - "coins": 0, - "fans_badge": true, - "fans_medal": { - "show": false, - "wear": false, - "medal": null - }, - "official": { - "role": 1, - "title": "bilibili 2021百大UP主、知名游戏UP主、直播高能主播", - "desc": "", - "type": 0 - }, - "vip": { - "type": 2, - "status": 1, - "due_date": 1702051200000, - "vip_pay_type": 0, - "theme_type": 0, - "label": { - "path": "", - "text": "年度大会员", - "label_theme": "annual_vip", - "text_color": "#FFFFFF", - "bg_style": 1, - "bg_color": "#FB7299", - "border_color": "" - }, - "avatar_subscript": 1, - "nickname_color": "#FB7299", - "role": 3, - "avatar_subscript_url": "http://i0.hdslb.com/bfs/vip/icon_Certification_big_member_22_3x.png" - }, - "pendant": { - "pid": 3399, - "name": "2233幻星集", - "image": "http://i0.hdslb.com/bfs/garb/item/20c07ded13498a5b12db99660c766ddd92ecfe31.png", - "expire": 0, - "image_enhance": "http://i0.hdslb.com/bfs/garb/item/20c07ded13498a5b12db99660c766ddd92ecfe31.png", - "image_enhance_frame": "" - }, - "nameplate": { - "nid": 1, - "name": "黄金殿堂", - "image": "http://i2.hdslb.com/bfs/face/82896ff40fcb4e7c7259cb98056975830cb55695.png", - "image_small": "http://i0.hdslb.com/bfs/face/627e342851dfda6fe7380c2fa0cbd7fae2e61533.png", - "level": "稀有勋章", - "condition": "单个自制视频总播放数\u003e=100万" - }, - "user_honour_info": { - "mid": 0, - "colour": null, - "tags": [] - }, - "is_followed": true, - "top_photo": "http://i2.hdslb.com/bfs/space/853fea2728651588a2cdef0a1e586bcefff8e3d8.png", - "theme": {}, - "sys_notice": {}, - "live_room": { - "roomStatus": 1, - "liveStatus": 1, - "url": "https://live.bilibili.com/3044248?broadcast_type=0\u0026is_room_feed=1", - "title": "【Zc】早朝危机合约!", - "cover": "http://i0.hdslb.com/bfs/live/new_room_cover/cf7d4d3b2f336c6dba299644c3af952c5db82612.jpg", - "roomid": 3044248, - "roundStatus": 1, - "broadcast_type": 0, - "watched_show": { - "switch": true, - "num": 13753, - "text_small": "1.3万", - "text_large": "1.3万人看过", - "icon": "https://i0.hdslb.com/bfs/live/a725a9e61242ef44d764ac911691a7ce07f36c1d.png", - "icon_location": "", - "icon_web": "https://i0.hdslb.com/bfs/live/8d9d0f33ef8bf6f308742752d13dd0df731df19c.png" - } - }, - "birthday": "07-21", - "school": { - "name": "" - }, - "profession": { - "name": "", - "department": "", - "title": "", - "is_show": 0 - }, - "tags": [ - "评论区UP主", - "目标是星辰大海" - ], - "series": { - "user_upgrade_status": 3, - "show_upgrade_window": false - }, - "is_senior_member": 1 - } -} \ No newline at end of file diff --git a/tests/platforms/static/bili_live_status-0.json b/tests/platforms/static/bili_live_status.json similarity index 100% rename from tests/platforms/static/bili_live_status-0.json rename to tests/platforms/static/bili_live_status.json diff --git a/tests/platforms/test_bilibili_live.py b/tests/platforms/test_bilibili_live.py index ccdb78f..52648fd 100644 --- a/tests/platforms/test_bilibili_live.py +++ b/tests/platforms/test_bilibili_live.py @@ -20,19 +20,18 @@ def bili_live(app: App): @pytest.mark.asyncio @respx.mock async def test_fetch_bilibili_live_status(bili_live, dummy_user_subinfo): + mock_bili_live_status = get_json("bili_live_status.json") + bili_live_router = respx.get( "https://api.bilibili.com/x/space/acc/info?mid=13164144" ) - bili_live_router.mock( - return_value=Response(200, json=get_json("bili_live_status-0.json")) - ) + bili_live_router.mock(return_value=Response(200, json=mock_bili_live_status)) target = "13164144" res = await bili_live.fetch_new_post(target, [dummy_user_subinfo]) assert bili_live_router.called assert len(res) == 0 - bili_live_router.mock( - return_value=Response(200, json=get_json("bili_live_status-1.json")) - ) + mock_bili_live_status["data"]["live_room"]["liveStatus"] = 1 + bili_live_router.mock(return_value=Response(200, json=mock_bili_live_status)) res2 = await bili_live.fetch_new_post(target, [dummy_user_subinfo]) post = res2[0][1][0] assert post.target_type == "Bilibili直播" From 1254995b3c15bdf8f6093aa2090dc08ae635d535 Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Tue, 24 May 2022 00:08:41 +0800 Subject: [PATCH 07/29] fix #77, add ua config --- docs/usage/README.md | 1 + src/plugins/nonebot_bison/plugin_config.py | 1 + src/plugins/nonebot_bison/utils/http.py | 11 +++++------ tests/test_proxy.py | 3 ++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/usage/README.md b/docs/usage/README.md index 647da48..cb34657 100644 --- a/docs/usage/README.md +++ b/docs/usage/README.md @@ -137,6 +137,7 @@ sidebar: auto ::: - `BISON_PROXY`: 使用的代理连接,形如`http://:`(可选) +- `BISON_UA`: 使用的 User-Agent,默认为 Chrome ## 使用 diff --git a/src/plugins/nonebot_bison/plugin_config.py b/src/plugins/nonebot_bison/plugin_config.py index dfd43f3..0a539f5 100644 --- a/src/plugins/nonebot_bison/plugin_config.py +++ b/src/plugins/nonebot_bison/plugin_config.py @@ -18,6 +18,7 @@ class PlugConfig(BaseSettings): # 0:不启用;1:首条消息单独发送,剩余照片合并转发;2以及以上:所有消息全部合并转发 bison_resend_times: int = 0 bison_proxy: Optional[str] + bison_ua: str = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" class Config: extra = "ignore" diff --git a/src/plugins/nonebot_bison/utils/http.py b/src/plugins/nonebot_bison/utils/http.py index f46af30..082aa55 100644 --- a/src/plugins/nonebot_bison/utils/http.py +++ b/src/plugins/nonebot_bison/utils/http.py @@ -4,9 +4,8 @@ import httpx from ..plugin_config import plugin_config -if plugin_config.bison_proxy: - http_client = functools.partial( - httpx.AsyncClient, proxies=plugin_config.bison_proxy - ) -else: - http_client = httpx.AsyncClient +http_client = functools.partial( + httpx.AsyncClient, + proxies=plugin_config.bison_proxy or None, + headers={"user-agent": plugin_config.bison_ua}, +) diff --git a/tests/test_proxy.py b/tests/test_proxy.py index ec4a22e..44a9124 100644 --- a/tests/test_proxy.py +++ b/tests/test_proxy.py @@ -1,6 +1,5 @@ import pytest from nonebug import App -from nonebug.fixture import nonebug_init async def test_without_proxy(app: App): @@ -8,6 +7,8 @@ async def test_without_proxy(app: App): c = http_client() assert not c._mounts + req = c.build_request("GET", "http://example.com") + assert "Chrome" in req.headers["User-Agent"] @pytest.mark.parametrize( From 1875e89f7b85e8047225e076972b0890aa49f0ef Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 May 2022 16:14:00 +0000 Subject: [PATCH 08/29] :memo: Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e511ed..3114d6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ - 增加代理设置 [@felinae98](https://github.com/felinae98) ([#71](https://github.com/felinae98/nonebot-bison/pull/71)) - 增加Parse Target功能 [@felinae98](https://github.com/felinae98) ([#72](https://github.com/felinae98/nonebot-bison/pull/72)) +### Bug 修复 + +- 捕获SSL异常 [@felinae98](https://github.com/felinae98) ([#75](https://github.com/felinae98/nonebot-bison/pull/75)) + ## v0.5.3 - on_command 设置 block=True (#63) @MeetWq From fcf8be38f04176b2d1876f2d54bfdad8dbce6a33 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 24 May 2022 05:11:21 +0000 Subject: [PATCH 09/29] :memo: Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3114d6c..95c33c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### 新功能 +- 添加User-Agent配置 [@felinae98](https://github.com/felinae98) ([#78](https://github.com/felinae98/nonebot-bison/pull/78)) - 增加代理设置 [@felinae98](https://github.com/felinae98) ([#71](https://github.com/felinae98/nonebot-bison/pull/71)) - 增加Parse Target功能 [@felinae98](https://github.com/felinae98) ([#72](https://github.com/felinae98/nonebot-bison/pull/72)) From 526742bbdf692d2c8059cb20bcc9a09781ac48cc Mon Sep 17 00:00:00 2001 From: Azide Date: Tue, 24 May 2022 13:24:30 +0800 Subject: [PATCH 10/29] =?UTF-8?q?=E4=BF=AE=E6=94=B9README=E4=B8=ADbilibili?= =?UTF-8?q?-live=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 527b317..6bd3fcb 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ - 专栏 - 转发 - 纯文字 +- Bilibili 直播 - 开播提醒 - RSS - 富文本转换为纯文本 From 5906cc5b829a27a4509c34dd6f5c73eb4433ad6c Mon Sep 17 00:00:00 2001 From: Azide Date: Tue, 24 May 2022 15:10:49 +0800 Subject: [PATCH 11/29] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3?= =?UTF-8?q?=EF=BC=8C=E8=A1=A5=E5=85=85=E9=85=8D=E7=BD=AE=E9=A1=B9=E7=9A=84?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=B9=E6=B3=95=E8=AF=B4=E6=98=8E=EF=BC=8C?= =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=BC=80=E5=8F=91=E6=96=87=E6=A1=A3=E4=B8=AD?= =?UTF-8?q?=E9=80=82=E9=85=8D=E6=96=B0=E7=BD=91=E7=AB=99=E7=9A=84=E4=BB=8B?= =?UTF-8?q?=E7=BB=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/dev/README.md | 54 ++++++++++++++++++++++++++++++++++++++++---- docs/usage/README.md | 32 ++++++++++++++++---------- 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/docs/dev/README.md b/docs/dev/README.md index 945e47c..5cf6d4d 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -80,11 +80,32 @@ sidebar: auto - `enable_tag` 平台发布内容是否带 Tag,例如微博 - `platform_name` 唯一的,英文的识别标识,比如`weibo` - `async get_target_name(Target) -> Optional[str]` 通常用于获取帐号的名称,如果平台没有帐号概念,可以直接返回平台的`name` -- `async parse(RawPost) -> Post`将获取到的 RawPost 处理成 Post +- `get_sub_lst(Target) -> list[RawPost]` 用于获取对应 Target 的 RawPost 列表,与上一次`get_sub_list`获取的列表比较,过滤出新的 RawPost - `get_tags(RawPost) -> Optional[Collection[Tag]]` (可选) 从 RawPost 中提取 Tag - `get_category(RawPos) -> Optional[Category]` (可选)从 RawPost 中提取 Category +- `async parse(RawPost) -> Post`将获取到的 RawPost 处理成 Post -例如要适配微博,我希望 bot 搬运新的消息,所以微博的类应该这样定义: +#### 简要的处理流程 + +- `nonebot_bison.platform.platform.NewMessage` + ::: details 大致流程 + 1. 调用`get_sub_list`拿到 RawPost 列表 + 2. 调用`get_id`判断是否重复,如果没有重复就说明是新的 RawPost + 3. 如果有`get_category`和`get_date`,则调用判断 RawPost 是否满足条件 + 4. 调用`parse`生成正式推文 + ::: + - 参考[nonebot_bison.platform.Weibo](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/src/plugins/nonebot_bison/platform/weibo.py) +- `nonebot_bison.platform.platform.StatusChange` + :::details 大致流程 + 1. `get_status`获取当前状态 + 2. 传入`compare_status`比较前状态 + 3. 通过则进入`parser`生成 Post + ::: + - 参考[nonenot_bison.platform.AkVersion](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/src/plugins/nonebot_bison/platform/arknights.py#L86) + +#### 一些例子 + +例如要适配微博,我希望 bot 搬运新的消息,所以微博的类应该这样实现: ```python class Weibo(NewMessage): @@ -103,10 +124,35 @@ class Weibo(NewMessage): schedule_type = "interval" schedule_kw = {"seconds": 3} has_target = True + + async def get_target_name(self, target: Target) -> Optional[str]: + #获取Target对应的用户名 + ... + async def get_sub_list(self, target: Target) -> list[RawPost]: + #获取对应Target的RawPost列表,会与上一次get_sub_list获取的列表比较,过滤出新的RawPost + ... + def get_id(self, post: RawPost) -> Any: + #获取可以标识每个Rawpost的,不与之前RawPost重复的id,用于过滤出新的RawPost + ... + def get_date(self, raw_post: RawPost) -> float: + #获取RawPost的发布时间,若bot过滤出的新RawPost发布时间与当前时间差超过2小时,该RawPost将被忽略,可以返回None + ... + def get_tags(self, raw_post: RawPost) -> Optional[list[Tag]]: + #获取RawPost中包含的微博话题(#xxx#中的内容) + ... + def get_category(self, raw_post: RawPost) -> Category: + #获取该RawPost在该类定义categories的具体分类(转发?视频?图文?...?) + ... + async def parse(self, raw_post: RawPost) -> Post: + #将需要bot推送的RawPost处理成正式推送的Post + ... ``` -当然我们非常希望你对自己适配的平台写一些单元测试,你可以模仿`tests/platforms/test_*.py`中的内容写 -一些单元测试。为保证多次运行测试的一致性,可以 mock http 的响应,测试的内容包括获取 RawPost,处理成 Post +当然我们非常希望你对自己适配的平台写一些单元测试 + +你可以参照`tests/platforms/test_*.py`中的内容对单元测试进行编写。 + +为保证多次运行测试的一致性,可以 mock http 的响应,测试的内容应包括[获取 RawPost](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/tests/platforms/test_weibo.py#L59),处理成 Post ,测试分类以及提取 tag 等,当然最好和 rsshub 做一个交叉验证。 ::: danger diff --git a/docs/usage/README.md b/docs/usage/README.md index cb34657..39bf8e6 100644 --- a/docs/usage/README.md +++ b/docs/usage/README.md @@ -94,23 +94,27 @@ sidebar: auto ## 配置 -可参考[源文件](https://github.com/felinae98/nonebot-bison/blob/main/src/plugins/nonebot_bison/plugin_config.py) +::: tip INFO + +- 所有配置项可参考[源文件](https://github.com/felinae98/nonebot-bison/blob/main/src/plugins/nonebot_bison/plugin_config.py) +- **配置项的配置方法** 请参考[NoneBot 配置方式](https://v2.nonebot.dev/docs/tutorial/configuration#%E9%85%8D%E7%BD%AE%E6%96%B9%E5%BC%8F),在`.env`/`.env.*`文件中写入希望配置的 Bison 配置项 + ::: - `BISON_CONFIG_PATH`: 插件存放配置文件的位置,如果不设定默认为项目目录下的`data`目录 - `BISON_USE_PIC`: 将文字渲染成图片后进行发送,多用于规避风控 - `BISON_BROWSER`: 本插件使用 Chrome 来渲染图片 - - 使用 browserless 提供的 Chrome 管理服务,设置为`ws://xxxxxxxx`,值为 Chrome Endpoint(推荐) - - 使用 cdp 连接相关服务,设置为`wsc://xxxxxxxxx` - - 使用本地安装的 Chrome,设置为`local:`,例如`local:/usr/bin/google-chrome-stable` - 如果不进行配置,那么会在启动时候自动进行安装,在官方的 docker 镜像中已经安装了浏览器 + - 使用本地安装的 Chrome,设置为`local:`,例如`local:/usr/bin/google-chrome-stable` + - 使用 cdp 连接相关服务,设置为`wsc://xxxxxxxxx` + - 使用 browserless 提供的 Chrome 管理服务,设置为`ws://xxxxxxxx`,值为 Chrome Endpoint ::: warning 截止发布时,本项目尚不能完全与 browserless 兼容,目前建议使用镜像内自带的浏览器,即 不要配置这个变量 ::: - `BISON_SKIP_BROWSER_CHECK`: 是否在启动时自动下载浏览器,如果选择`False`会在用到浏览器时自动下载, 默认`True` -- `BISON_OUTER_URL`: 从外部访问服务器的地址,默认为`http://localhost:8080/bison`,如果你的插件部署 - 在服务器上,建议配置为`http://<你的服务器ip>:8080/bison` +- `BISON_OUTER_URL`: 从外部访问服务器的地址,默认为`http://localhost:8080/bison/`,如果你的插件部署 + 在服务器上,建议配置为`http://<你的服务器ip>:8080/bison/` ::: warning 如果需要从外网或者 Docker 容器外访问后台页面,请确保`HOST=0.0.0.0` ::: @@ -124,7 +128,7 @@ sidebar: auto - `1`: 首条消息单独发送,剩余图片合并转发 - `2`: 所有消息全部合并转发 - ::: details 配置项示例 + ::: details BISON_USE_PIC_MERGE 配置项示例 - 当`BISON_USE_PIC_MERGE=1`时: ![simple1](/images/forward-msg-simple1.png) @@ -155,12 +159,16 @@ sidebar: auto 所有命令都需要@bot 触发 - 添加订阅(仅管理员和群主和 SUPERUSER):`添加订阅` - ::: tip 关于中止订阅 - 对于[**v0.5.1**](https://github.com/felinae98/nonebot-bison/releases/tag/v0.5.1)及以上的版本中,已经为`添加订阅`命令添加了中止订阅的功能。 - 在添加订阅命令的~~几乎~~各个阶段,都可以向 Bot 发送`取消`消息来中止订阅过程(需要订阅发起者本人发送) + ::: details 关于中止添加订阅 + 对于[**v0.5.1**](https://github.com/felinae98/nonebot-bison/releases/tag/v0.5.1)及以上的版本中,已经为`添加订阅`命令添加了中止添加功能。 + 在`添加订阅`命令的~~几乎~~各个阶段,都可以向 Bot 发送`取消`消息来中止订阅过程(需要发起者本人发送) ::: - 查询订阅:`查询订阅` - 删除订阅(仅管理员和群主和 SUPERUSER):`删除订阅` + ::: details 关于中止删除订阅 + 对于[**v0.5.3**](https://github.com/felinae98/nonebot-bison/releases/tag/v0.5.3)及以上的版本中,已经为`删除订阅`命令添加了中止删除功能。 + 在`删除订阅`命令的~~几乎~~各个阶段,都可以向 Bot 发送`取消`消息来中止订阅过程(需要发起者本人发送) + ::: #### 私聊机器人获取后台地址 @@ -179,8 +187,8 @@ sidebar: auto #### 私聊机器人进行配置(需要 SUPERUER 权限) 请私聊 bot`群管理` -::: tip 关于中止订阅 -与普通的[`添加订阅`](#在本群中进行配置)命令一样,在`群管理`命令中使用的`添加订阅`命令也可以使用`取消`来中止订阅过程 +::: details 关于中止订阅 +与普通的[`添加订阅`/`删除订阅`](#在本群中进行配置)命令一样,在`群管理`命令中使用的`添加订阅`/`删除订阅`命令也可以使用`取消`来中止订阅过程 ::: ### 所支持平台的 uid From b75a6e04ba66d3f5151afff9d27650a509885eda Mon Sep 17 00:00:00 2001 From: AzideCupric <57004769+AzideCupric@users.noreply.github.com> Date: Tue, 24 May 2022 18:43:39 +0800 Subject: [PATCH 12/29] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 调整介绍get_sub_list函数的位置,并补充同类的函数介绍 --- docs/dev/README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/dev/README.md b/docs/dev/README.md index 5cf6d4d..27da96b 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -80,11 +80,24 @@ sidebar: auto - `enable_tag` 平台发布内容是否带 Tag,例如微博 - `platform_name` 唯一的,英文的识别标识,比如`weibo` - `async get_target_name(Target) -> Optional[str]` 通常用于获取帐号的名称,如果平台没有帐号概念,可以直接返回平台的`name` -- `get_sub_lst(Target) -> list[RawPost]` 用于获取对应 Target 的 RawPost 列表,与上一次`get_sub_list`获取的列表比较,过滤出新的 RawPost - `get_tags(RawPost) -> Optional[Collection[Tag]]` (可选) 从 RawPost 中提取 Tag - `get_category(RawPos) -> Optional[Category]` (可选)从 RawPost 中提取 Category - `async parse(RawPost) -> Post`将获取到的 RawPost 处理成 Post +不同订阅类型的需要分别实现的方法如下: + +- `get_sub_list(Target) -> list[RawPost]` + - 对于`nonebot_bison.platform.platform.NewMessage` + - `get_sub_list(Target) -> list[RawPost]` 用于获取对应 Target 的 RawPost 列表,与上一次`get_sub_list`获取的列表比较,过滤出新的 RawPost + - 对于`nonebot_bison.platform.platform.SimplePost` + - `get_sub_list` 用于获取对应 Target 的 RawPost 列表,但不会与上次获取的结果进行比较,而是直接进行发送 +- `get_status(Target) -> Any` + - 对于`nonebot_bison.platform.platform.StatusChange` + - `get_status`用于获取对应Target当前的状态,随后将获取的状态作为参数`new_status`传入`compare_status`中 +- `compare_status(self, target: Target, old_status, new_status) -> list[RawPost]` + - 对于`nonebot_bison.platform.platform.StatusChange` + - `compare_status` 用于比较储存的`old_status`与新传入的`new_status`,并返回发生变更的RawPost列表 + #### 简要的处理流程 - `nonebot_bison.platform.platform.NewMessage` From cbb43bea258026c65abc0d4a47515dba27150aff Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 May 2022 10:43:48 +0000 Subject: [PATCH 13/29] auto fix by pre-commit hooks --- docs/dev/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dev/README.md b/docs/dev/README.md index 27da96b..0c6a433 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -93,10 +93,10 @@ sidebar: auto - `get_sub_list` 用于获取对应 Target 的 RawPost 列表,但不会与上次获取的结果进行比较,而是直接进行发送 - `get_status(Target) -> Any` - 对于`nonebot_bison.platform.platform.StatusChange` - - `get_status`用于获取对应Target当前的状态,随后将获取的状态作为参数`new_status`传入`compare_status`中 -- `compare_status(self, target: Target, old_status, new_status) -> list[RawPost]` + - `get_status`用于获取对应 Target 当前的状态,随后将获取的状态作为参数`new_status`传入`compare_status`中 +- `compare_status(self, target: Target, old_status, new_status) -> list[RawPost]` - 对于`nonebot_bison.platform.platform.StatusChange` - - `compare_status` 用于比较储存的`old_status`与新传入的`new_status`,并返回发生变更的RawPost列表 + - `compare_status` 用于比较储存的`old_status`与新传入的`new_status`,并返回发生变更的 RawPost 列表 #### 简要的处理流程 From 88fd2bf456c442e89b432c87f0f3440912941513 Mon Sep 17 00:00:00 2001 From: Azide Date: Wed, 25 May 2022 00:24:22 +0800 Subject: [PATCH 14/29] =?UTF-8?q?=E7=B2=BE=E7=AE=80bilibili-live=E7=9A=84?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/nonebot_bison/platform/bilibili.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/plugins/nonebot_bison/platform/bilibili.py b/src/plugins/nonebot_bison/platform/bilibili.py index ae196e4..151196c 100644 --- a/src/plugins/nonebot_bison/platform/bilibili.py +++ b/src/plugins/nonebot_bison/platform/bilibili.py @@ -207,5 +207,11 @@ class Bilibililive(StatusChange): pic = [raw_post["cover"]] target_name = raw_post["uname"] title = raw_post["title"] - text = "{} 直播中:\n{}\n\n小伙伴们速速前来围观!".format(target_name, title) - return Post(self.name, text=text, url=url, pics=pic, target_name=target_name) + return Post( + self.name, + text=title, + url=url, + pics=pic, + target_name=target_name, + compress=True, + ) From 9be070a578be0682c4f0d524fcb586053a209eca Mon Sep 17 00:00:00 2001 From: AzideCupric Date: Thu, 26 May 2022 11:00:03 +0800 Subject: [PATCH 15/29] =?UTF-8?q?=E4=BF=AE=E6=AD=A3test=5Fbilibili=5Flive?= =?UTF-8?q?=E7=9A=84=E5=8C=B9=E9=85=8D=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/platforms/test_bilibili_live.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/platforms/test_bilibili_live.py b/tests/platforms/test_bilibili_live.py index 52648fd..130c8dc 100644 --- a/tests/platforms/test_bilibili_live.py +++ b/tests/platforms/test_bilibili_live.py @@ -35,6 +35,8 @@ async def test_fetch_bilibili_live_status(bili_live, dummy_user_subinfo): res2 = await bili_live.fetch_new_post(target, [dummy_user_subinfo]) post = res2[0][1][0] assert post.target_type == "Bilibili直播" - assert post.text == "魔法Zc目录 直播中:\n【Zc】早朝危机合约!\n\n小伙伴们速速前来围观!" + assert post.text == "【Zc】早朝危机合约!" assert post.url == "https://live.bilibili.com/3044248" assert post.target_name == "魔法Zc目录" + assert post.pics == ["http://i0.hdslb.com/bfs/live/new_room_cover/cf7d4d3b2f336c6dba299644c3af952c5db82612.jpg"] + assert post.compress == True From f89ae85dccd8bfb73ff14d6add2c1555021c2996 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 May 2022 03:11:06 +0000 Subject: [PATCH 16/29] auto fix by pre-commit hooks --- tests/platforms/test_bilibili_live.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/platforms/test_bilibili_live.py b/tests/platforms/test_bilibili_live.py index 130c8dc..53885ef 100644 --- a/tests/platforms/test_bilibili_live.py +++ b/tests/platforms/test_bilibili_live.py @@ -38,5 +38,7 @@ async def test_fetch_bilibili_live_status(bili_live, dummy_user_subinfo): assert post.text == "【Zc】早朝危机合约!" assert post.url == "https://live.bilibili.com/3044248" assert post.target_name == "魔法Zc目录" - assert post.pics == ["http://i0.hdslb.com/bfs/live/new_room_cover/cf7d4d3b2f336c6dba299644c3af952c5db82612.jpg"] + assert post.pics == [ + "http://i0.hdslb.com/bfs/live/new_room_cover/cf7d4d3b2f336c6dba299644c3af952c5db82612.jpg" + ] assert post.compress == True From cb2f7cc2c70af1a9a2c797b891249a36cfacdaed Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 26 May 2022 10:03:04 +0000 Subject: [PATCH 17/29] :memo: Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95c33c5..38cb7a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### 新功能 +- 添加bilibili开播提醒 [@Sichongzou](https://github.com/Sichongzou) ([#60](https://github.com/felinae98/nonebot-bison/pull/60)) - 添加User-Agent配置 [@felinae98](https://github.com/felinae98) ([#78](https://github.com/felinae98/nonebot-bison/pull/78)) - 增加代理设置 [@felinae98](https://github.com/felinae98) ([#71](https://github.com/felinae98/nonebot-bison/pull/71)) - 增加Parse Target功能 [@felinae98](https://github.com/felinae98) ([#72](https://github.com/felinae98/nonebot-bison/pull/72)) From 8b28a66caeb24c3615df56caf8a149136c778ff6 Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Thu, 26 May 2022 20:51:07 +0800 Subject: [PATCH 18/29] update dev/README.md --- docs/dev/README.md | 55 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/docs/dev/README.md b/docs/dev/README.md index 0c6a433..70cb636 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -53,7 +53,7 @@ sidebar: auto 例如:微博,Bilibili - `nonebot_bison.platform.platform.StatusChange` 每次爬虫获取一个状态,在状态改变时发布推送 例如:游戏开服提醒,主播上播提醒 -- `nonebot_bison.platform.platform.SimplePost` 与`NewMessage`相似,但是不过滤新的消息 +- `nonebot_bison.platform.platform.SimplePost` 与`NewMessage`相似,但是不过滤之前发过的 ,每次发送全部消息 例如:每日榜单定时发送 @@ -64,10 +64,14 @@ sidebar: auto - 没有账号的概念 例如:游戏公告,教务处公告 +## 实现方法 + 现在你需要在`src/plugins/nonebot_bison/platform`下新建一个 py 文件, 在里面新建一个类,继承推送类型的基类,重载一些关键的函数,然后……就完成了,不需要修改别的东西了。 -任何一种订阅类型需要实现的方法/字段如下: +### 公共方法/成员 + +任何一种订阅类型需要实现的方法/成员如下: - `schedule_type`, `schedule_kw` 调度的参数,本质是使用 apscheduler 的[trigger 参数](https://apscheduler.readthedocs.io/en/3.x/userguide.html?highlight=trigger#choosing-the-right-scheduler-job-store-s-executor-s-and-trigger-s),`schedule_type`可以是`date`,`interval`和`cron`, `schedule_kw`是对应的参数,一个常见的配置是`schedule_type=interval`, `schedule_kw={'seconds':30}` @@ -82,40 +86,73 @@ sidebar: auto - `async get_target_name(Target) -> Optional[str]` 通常用于获取帐号的名称,如果平台没有帐号概念,可以直接返回平台的`name` - `get_tags(RawPost) -> Optional[Collection[Tag]]` (可选) 从 RawPost 中提取 Tag - `get_category(RawPos) -> Optional[Category]` (可选)从 RawPost 中提取 Category -- `async parse(RawPost) -> Post`将获取到的 RawPost 处理成 Post +- `async parse(RawPost) -> Post` 将获取到的 RawPost 处理成 Post +- `async parse_target(str) -> Target` (可选)定制化处理传入用户输入的 Target 字符串,返回 Target(一般是把用户的主页链接解析为 Target),如果输入本身就是 Target,则直接返回 Target +- `parse_target_promot` (可选)在要求用户输入 Target 的时候显示的提示文字 -不同订阅类型的需要分别实现的方法如下: +### 特有的方法/成员 -- `get_sub_list(Target) -> list[RawPost]` +- `async get_sub_list(Target) -> list[RawPost]` 输入一个`Target`,输出一个`RawPost`的 list - 对于`nonebot_bison.platform.platform.NewMessage` - `get_sub_list(Target) -> list[RawPost]` 用于获取对应 Target 的 RawPost 列表,与上一次`get_sub_list`获取的列表比较,过滤出新的 RawPost - 对于`nonebot_bison.platform.platform.SimplePost` - `get_sub_list` 用于获取对应 Target 的 RawPost 列表,但不会与上次获取的结果进行比较,而是直接进行发送 -- `get_status(Target) -> Any` +- `get_id(RawPost) -> Any` 输入一个`RawPost`,从`RawPost`中获取一个唯一的 ID,这个 ID 会用来判断这条`RawPost`是不是之前收到过 +- `get_date(RawPost) -> Optional[int]` 输入一个`RawPost`,如果可以从`RawPost`中提取出发文的时间,返回发文时间的 timestamp,否则返回`None` +- `async get_status(Target) -> Any` - 对于`nonebot_bison.platform.platform.StatusChange` - `get_status`用于获取对应 Target 当前的状态,随后将获取的状态作为参数`new_status`传入`compare_status`中 - `compare_status(self, target: Target, old_status, new_status) -> list[RawPost]` - 对于`nonebot_bison.platform.platform.StatusChange` - `compare_status` 用于比较储存的`old_status`与新传入的`new_status`,并返回发生变更的 RawPost 列表 -#### 简要的处理流程 +### 不同类型 Platform 的实现适配以及逻辑 - `nonebot_bison.platform.platform.NewMessage` + 需要实现: + + - `async get_sub_list(Target) -> list[RawPost]` + - `get_id(RawPost)` + - `get_date(RawPost)` (可选) + ::: details 大致流程 + 1. 调用`get_sub_list`拿到 RawPost 列表 2. 调用`get_id`判断是否重复,如果没有重复就说明是新的 RawPost 3. 如果有`get_category`和`get_date`,则调用判断 RawPost 是否满足条件 4. 调用`parse`生成正式推文 ::: + - 参考[nonebot_bison.platform.Weibo](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/src/plugins/nonebot_bison/platform/weibo.py) + - `nonebot_bison.platform.platform.StatusChange` + 需要实现: + + - `async get_status(Target) -> Any` + - `compare_status(Target, old_status, new_status) -> list[RawPost]` + :::details 大致流程 + 1. `get_status`获取当前状态 2. 传入`compare_status`比较前状态 3. 通过则进入`parser`生成 Post ::: + - 参考[nonenot_bison.platform.AkVersion](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/src/plugins/nonebot_bison/platform/arknights.py#L86) +- `nonebot_bison.platform.platform.SimplePost` + 需要实现: + + - `async get_sub_list(Target) -> list[RawPost]` + - `get_date(RawPost)` (可选) + + ::: details 大致流程 + + 1. 调用`get_sub_list`拿到 RawPost 列表 + 2. 如果有`get_category`和`get_date`,则调用判断 RawPost 是否满足条件 + 3. 调用`parse`生成正式推文 + ::: + #### 一些例子 例如要适配微博,我希望 bot 搬运新的消息,所以微博的类应该这样实现: @@ -172,7 +209,3 @@ class Weibo(NewMessage): Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Python asyncio 的机制有一定了解,当然, 依葫芦画瓢也是足够的 ::: - -## 类的方法与成员变量 - -## 方法与变量的定义 From 65181e80edcdc531cbb787b778dfecf9cead1155 Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Thu, 26 May 2022 20:56:48 +0800 Subject: [PATCH 19/29] update readme --- docs/dev/README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/dev/README.md b/docs/dev/README.md index 70cb636..ef85df7 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -93,18 +93,18 @@ sidebar: auto ### 特有的方法/成员 - `async get_sub_list(Target) -> list[RawPost]` 输入一个`Target`,输出一个`RawPost`的 list - - 对于`nonebot_bison.platform.platform.NewMessage` - - `get_sub_list(Target) -> list[RawPost]` 用于获取对应 Target 的 RawPost 列表,与上一次`get_sub_list`获取的列表比较,过滤出新的 RawPost - - 对于`nonebot_bison.platform.platform.SimplePost` - - `get_sub_list` 用于获取对应 Target 的 RawPost 列表,但不会与上次获取的结果进行比较,而是直接进行发送 + - 对于`nonebot_bison.platform.platform.NewMessage` + `get_sub_list(Target) -> list[RawPost]` 用于获取对应 Target 的 RawPost 列表,与上一次`get_sub_list`获取的列表比较,过滤出新的 RawPost + - 对于`nonebot_bison.platform.platform.SimplePost` + `get_sub_list` 用于获取对应 Target 的 RawPost 列表,但不会与上次获取的结果进行比较,而是直接进行发送 - `get_id(RawPost) -> Any` 输入一个`RawPost`,从`RawPost`中获取一个唯一的 ID,这个 ID 会用来判断这条`RawPost`是不是之前收到过 - `get_date(RawPost) -> Optional[int]` 输入一个`RawPost`,如果可以从`RawPost`中提取出发文的时间,返回发文时间的 timestamp,否则返回`None` - `async get_status(Target) -> Any` - - 对于`nonebot_bison.platform.platform.StatusChange` - - `get_status`用于获取对应 Target 当前的状态,随后将获取的状态作为参数`new_status`传入`compare_status`中 + - 对于`nonebot_bison.platform.platform.StatusChange` + `get_status`用于获取对应 Target 当前的状态,随后将获取的状态作为参数`new_status`传入`compare_status`中 - `compare_status(self, target: Target, old_status, new_status) -> list[RawPost]` - - 对于`nonebot_bison.platform.platform.StatusChange` - - `compare_status` 用于比较储存的`old_status`与新传入的`new_status`,并返回发生变更的 RawPost 列表 + - 对于`nonebot_bison.platform.platform.StatusChange` + `compare_status` 用于比较储存的`old_status`与新传入的`new_status`,并返回发生变更的 RawPost 列表 ### 不同类型 Platform 的实现适配以及逻辑 @@ -123,7 +123,7 @@ sidebar: auto 4. 调用`parse`生成正式推文 ::: - - 参考[nonebot_bison.platform.Weibo](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/src/plugins/nonebot_bison/platform/weibo.py) + 参考[nonebot_bison.platform.Weibo](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/src/plugins/nonebot_bison/platform/weibo.py) - `nonebot_bison.platform.platform.StatusChange` 需要实现: @@ -138,7 +138,7 @@ sidebar: auto 3. 通过则进入`parser`生成 Post ::: - - 参考[nonenot_bison.platform.AkVersion](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/src/plugins/nonebot_bison/platform/arknights.py#L86) + 参考[nonenot_bison.platform.AkVersion](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/src/plugins/nonebot_bison/platform/arknights.py#L86) - `nonebot_bison.platform.platform.SimplePost` 需要实现: From 1ecbdf3a1bca894b1d1d43f0aff448774b9bd740 Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Thu, 26 May 2022 21:18:49 +0800 Subject: [PATCH 20/29] update --- docs/dev/README.md | 76 +++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/docs/dev/README.md b/docs/dev/README.md index ef85df7..f470b37 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -69,43 +69,6 @@ sidebar: auto 现在你需要在`src/plugins/nonebot_bison/platform`下新建一个 py 文件, 在里面新建一个类,继承推送类型的基类,重载一些关键的函数,然后……就完成了,不需要修改别的东西了。 -### 公共方法/成员 - -任何一种订阅类型需要实现的方法/成员如下: - -- `schedule_type`, `schedule_kw` 调度的参数,本质是使用 apscheduler 的[trigger 参数](https://apscheduler.readthedocs.io/en/3.x/userguide.html?highlight=trigger#choosing-the-right-scheduler-job-store-s-executor-s-and-trigger-s),`schedule_type`可以是`date`,`interval`和`cron`, - `schedule_kw`是对应的参数,一个常见的配置是`schedule_type=interval`, `schedule_kw={'seconds':30}` -- `is_common` 是否常用,如果被标记为常用,那么和机器人交互式对话添加订阅时,会直接出现在选择列表中,否则 - 需要输入`全部`才会出现。 -- `enabled` 是否启用 -- `name` 平台的正式名称,例如`微博` -- `has_target` 平台是否有“帐号” -- `category` 平台的发布内容分类,例如 B 站包括专栏,视频,图文动态,普通动态等,如果不包含分类功能则设为`{}` -- `enable_tag` 平台发布内容是否带 Tag,例如微博 -- `platform_name` 唯一的,英文的识别标识,比如`weibo` -- `async get_target_name(Target) -> Optional[str]` 通常用于获取帐号的名称,如果平台没有帐号概念,可以直接返回平台的`name` -- `get_tags(RawPost) -> Optional[Collection[Tag]]` (可选) 从 RawPost 中提取 Tag -- `get_category(RawPos) -> Optional[Category]` (可选)从 RawPost 中提取 Category -- `async parse(RawPost) -> Post` 将获取到的 RawPost 处理成 Post -- `async parse_target(str) -> Target` (可选)定制化处理传入用户输入的 Target 字符串,返回 Target(一般是把用户的主页链接解析为 Target),如果输入本身就是 Target,则直接返回 Target -- `parse_target_promot` (可选)在要求用户输入 Target 的时候显示的提示文字 - -### 特有的方法/成员 - -- `async get_sub_list(Target) -> list[RawPost]` 输入一个`Target`,输出一个`RawPost`的 list - - 对于`nonebot_bison.platform.platform.NewMessage` - `get_sub_list(Target) -> list[RawPost]` 用于获取对应 Target 的 RawPost 列表,与上一次`get_sub_list`获取的列表比较,过滤出新的 RawPost - - 对于`nonebot_bison.platform.platform.SimplePost` - `get_sub_list` 用于获取对应 Target 的 RawPost 列表,但不会与上次获取的结果进行比较,而是直接进行发送 -- `get_id(RawPost) -> Any` 输入一个`RawPost`,从`RawPost`中获取一个唯一的 ID,这个 ID 会用来判断这条`RawPost`是不是之前收到过 -- `get_date(RawPost) -> Optional[int]` 输入一个`RawPost`,如果可以从`RawPost`中提取出发文的时间,返回发文时间的 timestamp,否则返回`None` -- `async get_status(Target) -> Any` - - 对于`nonebot_bison.platform.platform.StatusChange` - `get_status`用于获取对应 Target 当前的状态,随后将获取的状态作为参数`new_status`传入`compare_status`中 -- `compare_status(self, target: Target, old_status, new_status) -> list[RawPost]` - - 对于`nonebot_bison.platform.platform.StatusChange` - `compare_status` 用于比较储存的`old_status`与新传入的`new_status`,并返回发生变更的 RawPost 列表 - ### 不同类型 Platform 的实现适配以及逻辑 - `nonebot_bison.platform.platform.NewMessage` @@ -153,7 +116,44 @@ sidebar: auto 3. 调用`parse`生成正式推文 ::: -#### 一些例子 +### 公共方法/成员 + +任何一种订阅类型需要实现的方法/成员如下: + +- `schedule_type`, `schedule_kw` 调度的参数,本质是使用 apscheduler 的[trigger 参数](https://apscheduler.readthedocs.io/en/3.x/userguide.html?highlight=trigger#choosing-the-right-scheduler-job-store-s-executor-s-and-trigger-s),`schedule_type`可以是`date`,`interval`和`cron`, + `schedule_kw`是对应的参数,一个常见的配置是`schedule_type=interval`, `schedule_kw={'seconds':30}` +- `is_common` 是否常用,如果被标记为常用,那么和机器人交互式对话添加订阅时,会直接出现在选择列表中,否则 + 需要输入`全部`才会出现。 +- `enabled` 是否启用 +- `name` 平台的正式名称,例如`微博` +- `has_target` 平台是否有“帐号” +- `category` 平台的发布内容分类,例如 B 站包括专栏,视频,图文动态,普通动态等,如果不包含分类功能则设为`{}` +- `enable_tag` 平台发布内容是否带 Tag,例如微博 +- `platform_name` 唯一的,英文的识别标识,比如`weibo` +- `async get_target_name(Target) -> Optional[str]` 通常用于获取帐号的名称,如果平台没有帐号概念,可以直接返回平台的`name` +- `get_tags(RawPost) -> Optional[Collection[Tag]]` (可选) 从 RawPost 中提取 Tag +- `get_category(RawPos) -> Optional[Category]` (可选)从 RawPost 中提取 Category +- `async parse(RawPost) -> Post` 将获取到的 RawPost 处理成 Post +- `async parse_target(str) -> Target` (可选)定制化处理传入用户输入的 Target 字符串,返回 Target(一般是把用户的主页链接解析为 Target),如果输入本身就是 Target,则直接返回 Target +- `parse_target_promot` (可选)在要求用户输入 Target 的时候显示的提示文字 + +### 特有的方法/成员 + +- `async get_sub_list(Target) -> list[RawPost]` 输入一个`Target`,输出一个`RawPost`的 list + - 对于`nonebot_bison.platform.platform.NewMessage` + `get_sub_list(Target) -> list[RawPost]` 用于获取对应 Target 的 RawPost 列表,与上一次`get_sub_list`获取的列表比较,过滤出新的 RawPost + - 对于`nonebot_bison.platform.platform.SimplePost` + `get_sub_list` 用于获取对应 Target 的 RawPost 列表,但不会与上次获取的结果进行比较,而是直接进行发送 +- `get_id(RawPost) -> Any` 输入一个`RawPost`,从`RawPost`中获取一个唯一的 ID,这个 ID 会用来判断这条`RawPost`是不是之前收到过 +- `get_date(RawPost) -> Optional[int]` 输入一个`RawPost`,如果可以从`RawPost`中提取出发文的时间,返回发文时间的 timestamp,否则返回`None` +- `async get_status(Target) -> Any` + - 对于`nonebot_bison.platform.platform.StatusChange` + `get_status`用于获取对应 Target 当前的状态,随后将获取的状态作为参数`new_status`传入`compare_status`中 +- `compare_status(self, target: Target, old_status, new_status) -> list[RawPost]` + - 对于`nonebot_bison.platform.platform.StatusChange` + `compare_status` 用于比较储存的`old_status`与新传入的`new_status`,并返回发生变更的 RawPost 列表 + +## 一些例子 例如要适配微博,我希望 bot 搬运新的消息,所以微博的类应该这样实现: From 50c70b5a0f14f1d6bbce22dc427dbae0e91c4715 Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Thu, 26 May 2022 21:21:44 +0800 Subject: [PATCH 21/29] update --- docs/dev/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/dev/README.md b/docs/dev/README.md index f470b37..c1ba90e 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -153,6 +153,18 @@ sidebar: auto - 对于`nonebot_bison.platform.platform.StatusChange` `compare_status` 用于比较储存的`old_status`与新传入的`new_status`,并返回发生变更的 RawPost 列表 +当然我们非常希望你对自己适配的平台写一些单元测试 + +你可以参照`tests/platforms/test_*.py`中的内容对单元测试进行编写。 + +为保证多次运行测试的一致性,可以 mock http 的响应,测试的内容应包括[获取 RawPost](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/tests/platforms/test_weibo.py#L59),处理成 Post +,测试分类以及提取 tag 等,当然最好和 rsshub 做一个交叉验证。 + +::: danger +Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Python asyncio 的机制有一定了解,当然, +依葫芦画瓢也是足够的 +::: + ## 一些例子 例如要适配微博,我希望 bot 搬运新的消息,所以微博的类应该这样实现: @@ -197,15 +209,3 @@ class Weibo(NewMessage): #将需要bot推送的RawPost处理成正式推送的Post ... ``` - -当然我们非常希望你对自己适配的平台写一些单元测试 - -你可以参照`tests/platforms/test_*.py`中的内容对单元测试进行编写。 - -为保证多次运行测试的一致性,可以 mock http 的响应,测试的内容应包括[获取 RawPost](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/tests/platforms/test_weibo.py#L59),处理成 Post -,测试分类以及提取 tag 等,当然最好和 rsshub 做一个交叉验证。 - -::: danger -Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Python asyncio 的机制有一定了解,当然, -依葫芦画瓢也是足够的 -::: From 443d9e9426f5385faf6baa14bba5db7183ff59d8 Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Thu, 26 May 2022 21:28:53 +0800 Subject: [PATCH 22/29] update --- docs/dev/README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/dev/README.md b/docs/dev/README.md index c1ba90e..f18891c 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -31,6 +31,11 @@ sidebar: auto 本插件需要你的帮助!只需要会写简单的爬虫,就能给本插件适配新的网站。 +::: danger +Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Python asyncio 的机制有一定了解,当然, +依葫芦画瓢也是足够的 +::: + ## 基本概念 - `nonebot_bison.post.Post`: 可以理解为推送内容,其中包含需要发送的文字,图片,链接,平台信息等 @@ -153,6 +158,8 @@ sidebar: auto - 对于`nonebot_bison.platform.platform.StatusChange` `compare_status` 用于比较储存的`old_status`与新传入的`new_status`,并返回发生变更的 RawPost 列表 +### 单元测试 + 当然我们非常希望你对自己适配的平台写一些单元测试 你可以参照`tests/platforms/test_*.py`中的内容对单元测试进行编写。 @@ -160,11 +167,6 @@ sidebar: auto 为保证多次运行测试的一致性,可以 mock http 的响应,测试的内容应包括[获取 RawPost](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/tests/platforms/test_weibo.py#L59),处理成 Post ,测试分类以及提取 tag 等,当然最好和 rsshub 做一个交叉验证。 -::: danger -Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Python asyncio 的机制有一定了解,当然, -依葫芦画瓢也是足够的 -::: - ## 一些例子 例如要适配微博,我希望 bot 搬运新的消息,所以微博的类应该这样实现: From 1c5c2addeb928234327fd81589edde4214aecd23 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 26 May 2022 13:33:41 +0000 Subject: [PATCH 23/29] :memo: Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38cb7a6..6c51db7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ - 捕获SSL异常 [@felinae98](https://github.com/felinae98) ([#75](https://github.com/felinae98/nonebot-bison/pull/75)) +### 文档 + +- 完善开发文档 [@AzideCupric](https://github.com/AzideCupric) ([#80](https://github.com/felinae98/nonebot-bison/pull/80)) + ## v0.5.3 - on_command 设置 block=True (#63) @MeetWq From 22f88403da8177d400666e24b1d30399177d11cd Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Fri, 27 May 2022 11:54:06 +0800 Subject: [PATCH 24/29] update setup-python --- .github/actions/setup-python/action.yml | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/.github/actions/setup-python/action.yml b/.github/actions/setup-python/action.yml index 9c14210..b393db1 100644 --- a/.github/actions/setup-python/action.yml +++ b/.github/actions/setup-python/action.yml @@ -18,23 +18,14 @@ runs: - name: Install poetry uses: Gr1N/setup-poetry@v7 - - name: Cache Windows dependencies - uses: actions/cache@v2 - if: ${{ runner.os == 'Windows' }} - with: - path: ~/AppData/Local/pypoetry/Cache/virtualenvs - key: ${{ runner.os }}-poetry-${{ inputs.python-version }}-${{ hashFiles('**/poetry.lock') }} + - id: poetry-cache + run: echo "::set-output name=dir::$(poetry config virtualenvs.path)" + shell: bash - - name: Cache Linux dependencies - uses: actions/cache@v2 - if: ${{ runner.os == 'Linux' }} + - uses: actions/cache@v2 with: - path: ~/.cache/pypoetry/virtualenvs - key: ${{ runner.os }}-poetry-${{ inputs.python-version }}-${{ hashFiles('**/poetry.lock') }} + path: ${{ steps.poetry-cache.outputs.dir }} + key: ${{ runner.os }}-poetry-${{ steps.python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} - - name: Cache macOS dependencies - uses: actions/cache@v2 - if: ${{ runner.os == 'macOS' }} - with: - path: ~/Library/Caches/pypoetry/virtualenvs - key: ${{ runner.os }}-poetry-${{ inputs.python-version }}-${{ hashFiles('**/poetry.lock') }} \ No newline at end of file + - run: poetry install -E all + shell: bash From 6e107ddc79adbfce8972790fa31bf864f73392bf Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Fri, 27 May 2022 11:59:19 +0800 Subject: [PATCH 25/29] update setup-python --- .github/actions/setup-python/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-python/action.yml b/.github/actions/setup-python/action.yml index b393db1..94de36a 100644 --- a/.github/actions/setup-python/action.yml +++ b/.github/actions/setup-python/action.yml @@ -27,5 +27,5 @@ runs: path: ${{ steps.poetry-cache.outputs.dir }} key: ${{ runner.os }}-poetry-${{ steps.python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} - - run: poetry install -E all + - run: poetry install shell: bash From 3ffc3f81b5741effe369d4cc99615e193f2360fe Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Sun, 29 May 2022 00:22:57 +0800 Subject: [PATCH 26/29] update ci --- .github/workflows/main.yml | 8 ++++++++ .github/workflows/website-preview.yml | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3725705..e9e5bf9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,15 @@ on: push: branches: - main + paths: &path + - admin-frontend/** + - docker/** + - src/** + - tests/** + - pyproject.toml + - poetry.lock pull_request: + paths: *path concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/website-preview.yml b/.github/workflows/website-preview.yml index d6946b3..668a096 100644 --- a/.github/workflows/website-preview.yml +++ b/.github/workflows/website-preview.yml @@ -2,6 +2,10 @@ name: Site Deploy(Preview) on: pull_request_target: + paths: + - docs/** + - package.json + - yarn.lock jobs: preview: From fef30da69d5579dce9c25d75e2dd2a918069c5d6 Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Sun, 29 May 2022 00:49:11 +0800 Subject: [PATCH 27/29] catch json decode error --- .../nonebot_bison/platform/platform.py | 135 ++++++++---------- src/plugins/nonebot_bison/scheduler.py | 2 +- 2 files changed, 62 insertions(+), 75 deletions(-) diff --git a/src/plugins/nonebot_bison/platform/platform.py b/src/plugins/nonebot_bison/platform/platform.py index b5de376..22c1200 100644 --- a/src/plugins/nonebot_bison/platform/platform.py +++ b/src/plugins/nonebot_bison/platform/platform.py @@ -1,3 +1,4 @@ +import json import ssl import time from abc import ABC, abstractmethod @@ -60,6 +61,25 @@ class Platform(metaclass=RegistryABCMeta, base=True): ) -> list[tuple[User, list[Post]]]: ... + async def do_fetch_new_post( + self, target: Target, users: list[UserSubInfo] + ) -> list[tuple[User, list[Post]]]: + try: + return await self.fetch_new_post(target, users) + except httpx.RequestError as err: + logger.warning( + "network connection error: {}, url: {}".format( + type(err), err.request.url + ) + ) + return [] + except ssl.SSLError as err: + logger.warning(f"ssl error: {err}") + return [] + except json.JSONDecodeError as err: + logger.warning(f"json error, parsing: {err.doc}") + return [] + @abstractmethod async def parse(self, raw_post: RawPost) -> Post: ... @@ -227,33 +247,22 @@ class NewMessage(MessageProcess, abstract=True): async def fetch_new_post( self, target: Target, users: list[UserSubInfo] ) -> list[tuple[User, list[Post]]]: - try: - post_list = await self.get_sub_list(target) - new_posts = await self.filter_common_with_diff(target, post_list) - if not new_posts: - return [] - else: - for post in new_posts: - logger.info( - "fetch new post from {} {}: {}".format( - self.platform_name, - target if self.has_target else "-", - self.get_id(post), - ) + post_list = await self.get_sub_list(target) + new_posts = await self.filter_common_with_diff(target, post_list) + if not new_posts: + return [] + else: + for post in new_posts: + logger.info( + "fetch new post from {} {}: {}".format( + self.platform_name, + target if self.has_target else "-", + self.get_id(post), ) - res = await self.dispatch_user_post(target, new_posts, users) - self.parse_cache = {} - return res - except httpx.RequestError as err: - logger.warning( - "network connection error: {}, url: {}".format( - type(err), err.request.url ) - ) - return [] - except ssl.SSLError as err: - logger.warning(f"ssl error: {err}") - return [] + res = await self.dispatch_user_post(target, new_posts, users) + self.parse_cache = {} + return res class StatusChange(Platform, abstract=True): @@ -274,33 +283,22 @@ class StatusChange(Platform, abstract=True): async def fetch_new_post( self, target: Target, users: list[UserSubInfo] ) -> list[tuple[User, list[Post]]]: - try: - new_status = await self.get_status(target) - res = [] - if old_status := self.get_stored_data(target): - diff = self.compare_status(target, old_status, new_status) - if diff: - logger.info( - "status changes {} {}: {} -> {}".format( - self.platform_name, - target if self.has_target else "-", - old_status, - new_status, - ) + new_status = await self.get_status(target) + res = [] + if old_status := self.get_stored_data(target): + diff = self.compare_status(target, old_status, new_status) + if diff: + logger.info( + "status changes {} {}: {} -> {}".format( + self.platform_name, + target if self.has_target else "-", + old_status, + new_status, ) - res = await self.dispatch_user_post(target, diff, users) - self.set_stored_data(target, new_status) - return res - except httpx.RequestError as err: - logger.warning( - "network connection error: {}, url: {}".format( - type(err), err.request.url ) - ) - return [] - except ssl.SSLError as err: - logger.warning(f"ssl error: {err}") - return [] + res = await self.dispatch_user_post(target, diff, users) + self.set_stored_data(target, new_status) + return res class SimplePost(MessageProcess, abstract=True): @@ -309,32 +307,21 @@ class SimplePost(MessageProcess, abstract=True): async def fetch_new_post( self, target: Target, users: list[UserSubInfo] ) -> list[tuple[User, list[Post]]]: - try: - new_posts = await self.get_sub_list(target) - if not new_posts: - return [] - else: - for post in new_posts: - logger.info( - "fetch new post from {} {}: {}".format( - self.platform_name, - target if self.has_target else "-", - self.get_id(post), - ) + new_posts = await self.get_sub_list(target) + if not new_posts: + return [] + else: + for post in new_posts: + logger.info( + "fetch new post from {} {}: {}".format( + self.platform_name, + target if self.has_target else "-", + self.get_id(post), ) - res = await self.dispatch_user_post(target, new_posts, users) - self.parse_cache = {} - return res - except httpx.RequestError as err: - logger.warning( - "network connection error: {}, url: {}".format( - type(err), err.request.url ) - ) - return [] - except ssl.SSLError as err: - logger.warning(f"ssl error: {err}") - return [] + res = await self.dispatch_user_post(target, new_posts, users) + self.parse_cache = {} + return res class NoTargetGroup(Platform, abstract=True): diff --git a/src/plugins/nonebot_bison/scheduler.py b/src/plugins/nonebot_bison/scheduler.py index 307c0b5..cf976c8 100644 --- a/src/plugins/nonebot_bison/scheduler.py +++ b/src/plugins/nonebot_bison/scheduler.py @@ -59,7 +59,7 @@ async def fetch_and_send(target_type: str): send_user_list, ) ) - to_send = await platform_manager[target_type].fetch_new_post( + to_send = await platform_manager[target_type].do_fetch_new_post( target, send_userinfo_list ) if not to_send: From ef67ee1b8406d54d8cf8464bc203342c109de8a9 Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Sun, 29 May 2022 00:55:44 +0800 Subject: [PATCH 28/29] update workflow --- .github/workflows/main.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e9e5bf9..5f3fa00 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,7 @@ on: push: branches: - main - paths: &path + paths: - admin-frontend/** - docker/** - src/** @@ -12,7 +12,13 @@ on: - pyproject.toml - poetry.lock pull_request: - paths: *path + paths: + - admin-frontend/** + - docker/** + - src/** + - tests/** + - pyproject.toml + - poetry.lock concurrency: group: ${{ github.workflow }}-${{ github.ref }} From 9bce69191b7287e23e4c06b08cc5b5f5fa8a78ff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 May 2022 17:11:49 +0000 Subject: [PATCH 29/29] :memo: Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c51db7..3ecf05f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Bug 修复 +- 捕获 JSONDecodeError [@felinae98](https://github.com/felinae98) ([#82](https://github.com/felinae98/nonebot-bison/pull/82)) - 捕获SSL异常 [@felinae98](https://github.com/felinae98) ([#75](https://github.com/felinae98/nonebot-bison/pull/75)) ### 文档