diff --git a/bilibili_api/article.py b/bilibili_api/article.py index b066a5c1..f3bca20d 100644 --- a/bilibili_api/article.py +++ b/bilibili_api/article.py @@ -24,6 +24,7 @@ from .utils.network import Api from .exceptions.NetworkException import ApiException, NetworkException from .video import get_cid_info_sync +from .utils import cache_pool from . import dynamic from .note import Note, NoteType @@ -173,8 +174,17 @@ async def turn_to_dynamic(self) -> "dynamic.Dynamic": Returns: Dynamic: 动态实例 """ + if cache_pool.article2dynamic.get(self.get_cvid()) is None: + cache_pool.article2dynamic[self.get_cvid()] = (await self.get_all())[ + "readInfo" + ]["dyn_id_str"] + cache_pool.dynamic2article[cache_pool.article2dynamic[self.get_cvid()]] = ( + self.get_cvid() + ) + if cache_pool.dynamic_is_article.get(cache_pool.article2dynamic[self.get_cvid()]) is None: + cache_pool.dynamic_is_article[cache_pool.article2dynamic[self.get_cvid()]] = True return dynamic.Dynamic( - dynamic_id=(await self.get_all())["readInfo"]["dyn_id_str"], + dynamic_id=cache_pool.article2dynamic[self.get_cvid()], credential=self.credential, ) @@ -185,22 +195,19 @@ async def is_note(self) -> bool: Returns: bool: 是否为笔记 """ - return (await self.get_all())["readInfo"]["category"]["id"] in [41, 42] + if cache_pool.article_is_note.get(self.get_cvid()) is None: + cache_pool.article_is_note[self.get_cvid()] = (await self.get_all())[ + "readInfo" + ]["category"]["id"] in [41, 42] + return cache_pool.article_is_note[self.get_cvid()] - async def turn_to_note(self) -> "Note": + def turn_to_note(self) -> "Note": """ - 将专栏转为笔记(需保证专栏是笔记,过程中会有核验,共产生一次请求) - - 如果希望避免核验专栏是否是笔记,可以手动转换以避免请求。 - - ``` python - n = note.Note(cvid=ar.get_cvid(), note_type=note.NoteType.PUBLIC) - ``` + 将专栏转为笔记,不会核验。如需核验使用 `await is_note()` Returns: Note: 笔记实例 """ - raise_for_statement(await self.is_note(), "此专栏不是笔记,无法转换。") return Note( cvid=self.get_cvid(), note_type=NoteType.PUBLIC, credential=self.credential ) diff --git a/bilibili_api/dynamic.py b/bilibili_api/dynamic.py index d18811a5..2ade5bb8 100644 --- a/bilibili_api/dynamic.py +++ b/bilibili_api/dynamic.py @@ -21,6 +21,7 @@ from .utils.network import Api from .exceptions.DynamicExceedImagesException import DynamicExceedImagesException from .article import Article +from .utils import cache_pool API = utils.get_api("dynamic") API_opus = utils.get_api("opus") @@ -824,20 +825,50 @@ async def is_article(self) -> bool: Returns: bool: 是否为专栏 """ - return (await self.get_info())["item"]["basic"]["comment_type"] == 12 + if cache_pool.dynamic_is_article.get(self.get_dynamic_id()) is None: + cache_pool.dynamic_is_article[self.get_dynamic_id()] = ( + await self.get_info() + )["item"]["basic"]["comment_type"] == 12 + return cache_pool.dynamic_is_article[self.get_dynamic_id()] async def turn_to_article(self) -> "Article": """ 将专栏发布动态转为对应专栏(评论、点赞等数据专栏/动态/图文共享) + 不会核验。如需核验使用 `await is_article()`。 + 转换后可投币。 Returns: Article: 专栏实例 """ - raise_for_statement(await self.is_article(), "此动态无对应专栏。") + if cache_pool.dynamic2article.get(self.get_dynamic_id()) is None: + # 此处使用 is_article 需要调用 get_info + # 而获取动态对应专栏也需要 get_info,且请求结果会缓存 + # 因此最终只会请求一次,可以认为是提前请求 + if not await self.is_article(): + # 为防止 rid_str 字段其他的值匹配到对应专栏, + # 用动态的 id 覆盖 + cache_pool.dynamic2article[self.get_dynamic_id()] = ( + self.get_dynamic_id() + ) + else: + cache_pool.dynamic2article[self.get_dynamic_id()] = ( + await self.get_info() + )["item"]["basic"]["rid_str"] + # 所以为什么这里不设置核验呢,~~为了追求和 Article.turn_to_note 一样的对称美~~ + # 考虑 article 和 note 转换,note 初始化可以瞎填,不能保证存在 + # 而转换的时候无需网络请求,因此可能转换完 article 的 is_note 会被造假 + # 因此 Note.turn_to_article 没有 cache_pool 缓存 + # 同理 Article.turn_to_note 也没有缓存,缓存只存在于 await is_note(),有请求 + # 如果在 Article.turn_to_note 中加入核验,某些情境下会多出请求,因此将核验剥离 + # 这样既可以实现核验,也可以不核验。 + # 这里这么做也是这个遵循目的,为此还需要保证将错就错不会造成其他逻辑问题。 + cache_pool.article2dynamic[ + cache_pool.dynamic2article[self.get_dynamic_id()] + ] = self.get_dynamic_id() return Article( - cvid=(await self.get_info())["item"]["basic"]["rid_str"], + cvid=cache_pool.dynamic2article[self.get_dynamic_id()], credential=self.credential, ) diff --git a/bilibili_api/utils/cache_pool.py b/bilibili_api/utils/cache_pool.py new file mode 100644 index 00000000..c803f506 --- /dev/null +++ b/bilibili_api/utils/cache_pool.py @@ -0,0 +1,4 @@ +article2dynamic: dict = {} +dynamic2article: dict = {} +article_is_note: dict = {} +dynamic_is_article: dict = {} diff --git a/bilibili_api/utils/network.py b/bilibili_api/utils/network.py index 926dd39f..7fc834ce 100644 --- a/bilibili_api/utils/network.py +++ b/bilibili_api/utils/network.py @@ -498,7 +498,7 @@ async def _prepare_request(self, **kwargs) -> dict: cookies["buvid3"] = self.credential.buvid3 # cookies["Domain"] = ".bilibili.com" - cookies["opus-goback"] = 1 + cookies["opus-goback"] = "1" if self.bili_ticket: cookies["bili_ticket"] = await get_bili_ticket() diff --git a/tests/test_opus.py b/tests/test_opus.py deleted file mode 100644 index 3cd9e148..00000000 --- a/tests/test_opus.py +++ /dev/null @@ -1,21 +0,0 @@ -from bilibili_api import opus -from .common import get_credential - -o = opus.Opus(863994527716737095, get_credential()) - - -async def test_a_Opus_get_info(): - return await o.get_info() - - -async def test_b_transfer(): - return ( - o.turn_to_article() - .turn_to_opus() - .turn_to_article() - .turn_to_opus() - .turn_to_dynamic() - .turn_to_opus() - .turn_to_dynamic() - .turn_to_opus() - )