From 19dcf4dea00b65f606b7f148ebc3dfab36a69c23 Mon Sep 17 00:00:00 2001
From: felinae98 <731499577@qq.com>
Date: Tue, 4 Oct 2022 15:38:59 +0800
Subject: [PATCH 1/7] fix: fix raise wrong exception in bilibili-live

---
 src/plugins/nonebot_bison/platform/bilibili.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/plugins/nonebot_bison/platform/bilibili.py b/src/plugins/nonebot_bison/platform/bilibili.py
index 7d5a763..b18851e 100644
--- a/src/plugins/nonebot_bison/platform/bilibili.py
+++ b/src/plugins/nonebot_bison/platform/bilibili.py
@@ -201,7 +201,7 @@ class Bilibililive(StatusChange):
                 info["cover"] = res_dict["data"]["live_room"]["cover"]
                 return info
             else:
-                raise self.ParseTargetException(res.text)
+                raise self.FetchError()
 
     def compare_status(self, target: Target, old_status, new_status) -> list[RawPost]:
         if (

From 356b5841a5b27d66d78e8b9f568f88400f3afcf1 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Tue, 4 Oct 2022 07:41:39 +0000
Subject: [PATCH 2/7] :memo: Update changelog

---
 CHANGELOG.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1182ba7..daf16f9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,10 @@
 - 在StatusChange中提供了如果api返回错误不更新status的方法 [@felinae98](https://github.com/felinae98) ([#96](https://github.com/felinae98/nonebot-bison/pull/96))
 - 添加 CustomPost [@felinae98](https://github.com/felinae98) ([#81](https://github.com/felinae98/nonebot-bison/pull/81))
 
+### Bug 修复
+
+- fix: 修复 bilibili-live 中获取状态错误后产生的错误行为 [@felinae98](https://github.com/felinae98) ([#111](https://github.com/felinae98/nonebot-bison/pull/111))
+
 ## v0.5.4
 
 ### 新功能

From 6851bb5765702bcc6a002a2f31335c764c3ae3c3 Mon Sep 17 00:00:00 2001
From: felinae98 <731499577@qq.com>
Date: Mon, 3 Oct 2022 22:14:33 +0800
Subject: [PATCH 3/7] feat: add temp client for bilibili

---
 .../nonebot_bison/platform/bilibili.py        | 146 ++++++++++++------
 src/plugins/nonebot_bison/utils/http.py       |  11 +-
 2 files changed, 101 insertions(+), 56 deletions(-)

diff --git a/src/plugins/nonebot_bison/platform/bilibili.py b/src/plugins/nonebot_bison/platform/bilibili.py
index b18851e..5f04be1 100644
--- a/src/plugins/nonebot_bison/platform/bilibili.py
+++ b/src/plugins/nonebot_bison/platform/bilibili.py
@@ -1,14 +1,42 @@
+import functools
 import json
 import re
+from datetime import datetime, timedelta
 from typing import Any, Optional
 
+import httpx
+from nonebot.log import logger
+
 from ..post import Post
 from ..types import Category, RawPost, Tag, Target
-from ..utils import http_client
+from ..utils.http import http_args
 from .platform import CategoryNotSupport, NewMessage, StatusChange
 
 
-class Bilibili(NewMessage):
+class _BilibiliClient:
+
+    _http_client: httpx.AsyncClient
+    _client_refresh_time: Optional[datetime]
+    cookie_expire_time = timedelta(hours=5)
+
+    async def _init_session(self):
+        self._http_client = httpx.AsyncClient(**http_args)
+        res = await self._http_client.get("https://bilibili.com")
+        if res.status_code != 200:
+            logger.warning("unable to refresh temp cookie")
+        else:
+            self._client_refresh_time = datetime.now()
+
+    async def _refresh_client(self):
+        if (
+            self._client_refresh_time is None
+            or datetime.now() - self._client_refresh_time > self.cookie_expire_time
+            or self._http_client is None
+        ):
+            await self._init_session()
+
+
+class Bilibili(_BilibiliClient, NewMessage):
 
     categories = {
         1: "一般动态",
@@ -28,15 +56,23 @@ class Bilibili(NewMessage):
     has_target = True
     parse_target_promot = "请输入用户主页的链接"
 
+    def ensure_client(fun):
+        @functools.wraps(fun)
+        async def wrapped(self, *args, **kwargs):
+            await self._refresh_client()
+            return await fun(self, *args, **kwargs)
+
+        return wrapped
+
+    @ensure_client
     async def get_target_name(self, target: Target) -> Optional[str]:
-        async with http_client() 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"]
+        res = await self._http_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 parse_target(self, target_text: str) -> Target:
         if re.match(r"\d+", target_text):
@@ -48,19 +84,19 @@ class Bilibili(NewMessage):
         else:
             raise self.ParseTargetException()
 
+    @ensure_client
     async def get_sub_list(self, target: Target) -> list[RawPost]:
-        async with http_client() as client:
-            params = {"host_uid": target, "offset": 0, "need_top": 0}
-            res = await client.get(
-                "https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history",
-                params=params,
-                timeout=4.0,
-            )
-            res_dict = json.loads(res.text)
-            if res_dict["code"] == 0:
-                return res_dict["data"].get("cards")
-            else:
-                return []
+        params = {"host_uid": target, "offset": 0, "need_top": 0}
+        res = await self._http_client.get(
+            "https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history",
+            params=params,
+            timeout=4.0,
+        )
+        res_dict = json.loads(res.text)
+        if res_dict["code"] == 0:
+            return res_dict["data"].get("cards")
+        else:
+            return []
 
     def get_id(self, post: RawPost) -> Any:
         return post["desc"]["dynamic_id"]
@@ -157,7 +193,7 @@ class Bilibili(NewMessage):
         return Post("bilibili", text=text, url=url, pics=pic, target_name=target_name)
 
 
-class Bilibililive(StatusChange):
+class Bilibililive(_BilibiliClient, StatusChange):
     # Author : Sichongzou
     # Date : 2022-5-18 8:54
     # Description : bilibili开播提醒
@@ -172,36 +208,44 @@ class Bilibililive(StatusChange):
     name = "Bilibili直播"
     has_target = True
 
-    async def get_target_name(self, target: Target) -> Optional[str]:
-        async with http_client() 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"]
+    def ensure_client(fun):
+        @functools.wraps(fun)
+        async def wrapped(self, *args, **kwargs):
+            await self._refresh_client()
+            return await fun(self, *args, **kwargs)
 
+        return wrapped
+
+    @ensure_client
+    async def get_target_name(self, target: Target) -> Optional[str]:
+        res = await self._http_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"]
+
+    @ensure_client
     async def get_status(self, target: Target):
-        async with http_client() 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["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
-            else:
-                raise self.FetchError()
+        params = {"mid": target}
+        res = await self._http_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["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
+        else:
+            raise self.FetchError()
 
     def compare_status(self, target: Target, old_status, new_status) -> list[RawPost]:
         if (
diff --git a/src/plugins/nonebot_bison/utils/http.py b/src/plugins/nonebot_bison/utils/http.py
index 082aa55..9dd80d8 100644
--- a/src/plugins/nonebot_bison/utils/http.py
+++ b/src/plugins/nonebot_bison/utils/http.py
@@ -4,8 +4,9 @@ import httpx
 
 from ..plugin_config import plugin_config
 
-http_client = functools.partial(
-    httpx.AsyncClient,
-    proxies=plugin_config.bison_proxy or None,
-    headers={"user-agent": plugin_config.bison_ua},
-)
+http_args = {
+    "proxies": plugin_config.bison_proxy or None,
+    "headers": {"user-agent": plugin_config.bison_ua},
+}
+
+http_client = functools.partial(httpx.AsyncClient, **http_args)

From 98a5ae6b4c22aa7a31ea8ee6433bed07ae1e09c5 Mon Sep 17 00:00:00 2001
From: felinae98 <731499577@qq.com>
Date: Mon, 3 Oct 2022 22:27:56 +0800
Subject: [PATCH 4/7] fixup! feat: add temp client for bilibili

fix bug
---
 src/plugins/nonebot_bison/platform/bilibili.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/plugins/nonebot_bison/platform/bilibili.py b/src/plugins/nonebot_bison/platform/bilibili.py
index 5f04be1..e2dc306 100644
--- a/src/plugins/nonebot_bison/platform/bilibili.py
+++ b/src/plugins/nonebot_bison/platform/bilibili.py
@@ -29,7 +29,7 @@ class _BilibiliClient:
 
     async def _refresh_client(self):
         if (
-            self._client_refresh_time is None
+            getattr(self, "_client_refresh_time", None) is None
             or datetime.now() - self._client_refresh_time > self.cookie_expire_time
             or self._http_client is None
         ):

From 0a4fd60e7a8a558c3699afc0f73dad0d7849cbc8 Mon Sep 17 00:00:00 2001
From: felinae98 <731499577@qq.com>
Date: Mon, 3 Oct 2022 23:08:21 +0800
Subject: [PATCH 5/7] fixup! feat: add temp client for bilibili

fix bug
---
 tests/platforms/test_bilibili_live.py | 4 ++++
 tests/test_config_manager_add.py      | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/tests/platforms/test_bilibili_live.py b/tests/platforms/test_bilibili_live.py
index 53885ef..4335c82 100644
--- a/tests/platforms/test_bilibili_live.py
+++ b/tests/platforms/test_bilibili_live.py
@@ -26,6 +26,10 @@ async def test_fetch_bilibili_live_status(bili_live, dummy_user_subinfo):
         "https://api.bilibili.com/x/space/acc/info?mid=13164144"
     )
     bili_live_router.mock(return_value=Response(200, json=mock_bili_live_status))
+
+    bilibili_main_page_router = respx.get("https://bilibili.com")
+    bilibili_main_page_router.mock(return_value=Response(200))
+
     target = "13164144"
     res = await bili_live.fetch_new_post(target, [dummy_user_subinfo])
     assert bili_live_router.called
diff --git a/tests/test_config_manager_add.py b/tests/test_config_manager_add.py
index dcf63e5..ce7b917 100644
--- a/tests/test_config_manager_add.py
+++ b/tests/test_config_manager_add.py
@@ -440,6 +440,9 @@ async def test_add_with_bilibili_target_parser(app: App):
         return_value=Response(200, json=get_json("bilibili_arknights_profile.json"))
     )
 
+    bilibili_main_page_router = respx.get("https://bilibili.com")
+    bilibili_main_page_router.mock(return_value=Response(200))
+
     async with app.test_matcher(add_sub_matcher) as ctx:
         bot = ctx.create_bot()
         event_1 = fake_group_message_event(

From 88e3d4de12e6ab55039336cc12df69e6dabc0cc9 Mon Sep 17 00:00:00 2001
From: felinae98 <731499577@qq.com>
Date: Tue, 4 Oct 2022 15:34:51 +0800
Subject: [PATCH 6/7] fixup! feat: add temp client for bilibili

fix bug
---
 src/plugins/nonebot_bison/platform/bilibili.py | 5 ++++-
 tests/platforms/test_bilibili_live.py          | 2 +-
 tests/test_config_manager_add.py               | 2 +-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/plugins/nonebot_bison/platform/bilibili.py b/src/plugins/nonebot_bison/platform/bilibili.py
index e2dc306..2ec613e 100644
--- a/src/plugins/nonebot_bison/platform/bilibili.py
+++ b/src/plugins/nonebot_bison/platform/bilibili.py
@@ -21,8 +21,11 @@ class _BilibiliClient:
 
     async def _init_session(self):
         self._http_client = httpx.AsyncClient(**http_args)
-        res = await self._http_client.get("https://bilibili.com")
+        res = await self._http_client.get("https://www.bilibili.com/")
         if res.status_code != 200:
+            import ipdb
+
+            ipdb.set_trace()
             logger.warning("unable to refresh temp cookie")
         else:
             self._client_refresh_time = datetime.now()
diff --git a/tests/platforms/test_bilibili_live.py b/tests/platforms/test_bilibili_live.py
index 4335c82..0867a80 100644
--- a/tests/platforms/test_bilibili_live.py
+++ b/tests/platforms/test_bilibili_live.py
@@ -27,7 +27,7 @@ async def test_fetch_bilibili_live_status(bili_live, dummy_user_subinfo):
     )
     bili_live_router.mock(return_value=Response(200, json=mock_bili_live_status))
 
-    bilibili_main_page_router = respx.get("https://bilibili.com")
+    bilibili_main_page_router = respx.get("https://www.bilibili.com/")
     bilibili_main_page_router.mock(return_value=Response(200))
 
     target = "13164144"
diff --git a/tests/test_config_manager_add.py b/tests/test_config_manager_add.py
index ce7b917..d087f07 100644
--- a/tests/test_config_manager_add.py
+++ b/tests/test_config_manager_add.py
@@ -440,7 +440,7 @@ async def test_add_with_bilibili_target_parser(app: App):
         return_value=Response(200, json=get_json("bilibili_arknights_profile.json"))
     )
 
-    bilibili_main_page_router = respx.get("https://bilibili.com")
+    bilibili_main_page_router = respx.get("https://www.bilibili.com/")
     bilibili_main_page_router.mock(return_value=Response(200))
 
     async with app.test_matcher(add_sub_matcher) as ctx:

From 3a6bd98b8cb7a3edb4b5a2bc5734dfa7f28ee9d2 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Thu, 6 Oct 2022 17:43:30 +0000
Subject: [PATCH 7/7] :memo: Update changelog

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index daf16f9..f4e7220 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
 
 ### 新功能
 
+- feat: 临时解决 bilibili 的反爬机制 [@felinae98](https://github.com/felinae98) ([#110](https://github.com/felinae98/nonebot-bison/pull/110))
 - 在StatusChange中提供了如果api返回错误不更新status的方法 [@felinae98](https://github.com/felinae98) ([#96](https://github.com/felinae98/nonebot-bison/pull/96))
 - 添加 CustomPost [@felinae98](https://github.com/felinae98) ([#81](https://github.com/felinae98/nonebot-bison/pull/81))