diff --git a/bilibili_api/data/api/manga.json b/bilibili_api/data/api/manga.json index 97926a68..fcfec3aa 100644 --- a/bilibili_api/data/api/manga.json +++ b/bilibili_api/data/api/manga.json @@ -1,48 +1,71 @@ { "info": { "detail": { - "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/ComicDetail?device=pc&platform=web", + "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/ComicDetail", "method": "POST", - "verify": true, + "verify": false, + "bili_ticket": true, "params": { + "device": "str: 设备", + "platform": "str: 平台", + "nov": "int: 25" + }, + "data": { "comic_id": "int: 漫画 id" }, "comment": "获取漫画详情信息" }, "episode_info": { - "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/GetEpisode?device=pc&platform=web", + "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/GetEpisode", "method": "POST", - "verify": true, + "verify": false, "params": { + "device": "str: 设备", + "platform": "str: 平台", + "nov": "int: 25" + }, + "data": { "id": "int: 章节 id" }, "comment": "获取漫画某一章节/某一话的信息。" }, "episode_images": { - "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/GetImageIndex?device=pc&platform=web", + "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/GetImageIndex", "method": "POST", - "verify": true, + "verify": false, "params": { + "device": "str: 设备", + "platform": "str: 平台", + "nov": "int: 25" + }, + "data": { "ep_id": "int: 章节 id" }, "comment": "获取漫画某一章节/某一话的图片的链接。" }, "image_token": { - "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/ImageToken?device=pc&platform=web", + "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/ImageToken", "method": "POST", - "verify": true, + "verify": false, "params": { - "urls": "str: 内容如下:[\"图片链接\"]" + "device": "str: 设备", + "platform": "str: 平台", + "nov": "int: 25" + }, + "data": { + "urls": "str: 内容如下:[\"图片链接\"]", + "m1": "str: 由 ECDH P-256 生成的公钥的 base64" }, "comment": "获取漫画单张图片的 token" }, "index": { "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/ClassPage", "method": "POST", - "verify": true, + "verify": false, "params": { "device": "str: 设备", - "platform": "str: 平台" + "platform": "str: 平台", + "nov": "int: 25" }, "data": { "area_id": "int: 地区 id", @@ -56,18 +79,24 @@ "comment": "获取漫画索引" }, "index_params": { - "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/AllLabel?device=pc&platform=web", + "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/AllLabel", "method": "POST", - "verify": true, + "verify": false, + "params": { + "device": "str: 设备", + "platform": "str: 平台", + "nov": "int: 25" + }, "comment": "获取漫画索引的参数" }, "update": { "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/GetDailyPush", "method": "POST", - "verify": true, + "verify": false, "params": { "device": "str: 设备", - "platform": "str: 平台" + "platform": "str: 平台", + "nov": "int: 25" }, "data": { "date": "str: 日期,格式为 YYYY-MM-DD", @@ -79,10 +108,11 @@ "home_recommend": { "url": "https://manga.bilibili.com/twirp/comic.v1.Comic/HomeRecommend", "method": "POST", - "verify": true, + "verify": false, "params": { "device": "str: 设备", - "platform": "str: 平台" + "platform": "str: 平台", + "nov": "int: 25" }, "data": { "seed": "str: unknown param", @@ -93,19 +123,29 @@ }, "operate": { "add_favorite": { - "url": "https://manga.bilibili.com/twirp/bookshelf.v1.Bookshelf/AddFavorite?device=pc&platform=web", + "url": "https://manga.bilibili.com/twirp/bookshelf.v1.Bookshelf/AddFavorite", "method": "POST", - "verify": true, + "verify": false, "params": { + "device": "str: 设备", + "platform": "str: 平台", + "nov": "int: 25" + }, + "data": { "comic_ids": "int: 漫画 id" }, "comment": "追漫" }, "del_favorite": { - "url": "https://manga.bilibili.com/twirp/bookshelf.v1.Bookshelf/DeleteFavorite?device=pc&platform=web", + "url": "https://manga.bilibili.com/twirp/bookshelf.v1.Bookshelf/DeleteFavorite", "method": "POST", - "verify": true, + "verify": false, "params": { + "device": "str: 设备", + "platform": "str: 平台", + "nov": "int: 25" + }, + "data": { "comic_ids": "int: 漫画 id" }, "comment": "取消追漫" diff --git a/bilibili_api/manga.py b/bilibili_api/manga.py index c4807853..d611fa20 100644 --- a/bilibili_api/manga.py +++ b/bilibili_api/manga.py @@ -4,6 +4,7 @@ 漫画相关操作 """ +import base64 import datetime from enum import Enum from urllib.parse import urlparse @@ -17,6 +18,8 @@ from bilibili_api.utils.credential import Credential from bilibili_api.utils.network import HEADERS, Api +from Cryptodome.PublicKey import ECC + API = get_api("manga") @@ -162,21 +165,12 @@ async def get_info(self) -> dict: dict: 调用 API 返回的结果 """ api = API["info"]["detail"] - params = {"comic_id": self.__manga_id, "device": "pc", "platform": "web"} + params = {"device": "pc", "platform": "web", "nov": 25} + data = {"comic_id": self.get_manga_id()} return ( - await Api( - **api, - credential=self.credential, - no_csrf=( - False - if ( - self.credential.has_sessdata() - and self.credential.has_bili_jct() - ) - else True - ), - ) + await Api(**api, credential=self.credential, no_csrf=True, json_body=True) .update_params(**params) + .update_data(**data) .result ) @@ -257,21 +251,12 @@ async def get_images_url( raise ArgsException("episode_count 和 episode_id 中必须提供一个参数。") episode_id = await self.get_episode_id(episode_count) api = API["info"]["episode_images"] - params = {"ep_id": episode_id, "device": "pc", "platform": "web"} + params = {"device": "pc", "platform": "web", "nov": 25} + data = {"ep_id": episode_id} return ( - await Api( - **api, - credential=self.credential, - no_csrf=( - False - if ( - self.credential.has_sessdata() - and self.credential.has_bili_jct() - ) - else True - ), - ) + await Api(**api, credential=self.credential, no_csrf=True) .update_params(**params) + .update_data(**data) .result ) @@ -302,20 +287,15 @@ async def get_images( async def get_real_image_url(url: str) -> str: token_api = API["info"]["image_token"] + params = {"device": "pc", "platform": "web", "nov": 25} datas = {"urls": f'["{url}"]'} token_data = ( await Api( **token_api, credential=self.credential, - no_csrf=( - False - if ( - self.credential.has_sessdata() - and self.credential.has_bili_jct() - ) - else True - ), + no_csrf=True, ) + .update_params(**params) .update_data(**datas) .result ) @@ -353,23 +333,22 @@ async def manga_image_url_turn_to_Picture( url = urlparse(url).path credential = credential if credential else Credential() + def get_m1(): + key = ECC.generate(curve="P-256") + pubKey = key.public_key().export_key(format="raw") + return base64.b64encode(pubKey).decode("ascii") + async def get_real_image_url(url: str) -> str: token_api = API["info"]["image_token"] - datas = {"urls": f'["{url}"]'} + params = {"device": "pc", "platform": "web", "nov": 25} + datas = {"urls": f'["{url}"]', "m1": get_m1()} token_data = ( - await Api( - **token_api, - credential=credential, - no_csrf=( - False - if (credential.has_sessdata() and credential.has_bili_jct()) - else True - ), - ) + await Api(**token_api, credential=credential, no_csrf=True, json_body=True) + .update_params(**params) .update_data(**datas) .result ) - return f'{token_data[0]["url"]}?token={token_data[0]["token"]}' + return token_data[0]["complete_url"] url = await get_real_image_url(url) return await Picture.async_load_url(url) @@ -399,8 +378,15 @@ async def set_follow_manga( api = API["operate"]["add_favorite"] else: api = API["operate"]["del_favorite"] + + params = {"device": "pc", "platform": "web", "nov": 25} data = {"comic_ids": str(manga.get_manga_id())} - return await Api(**api, credential=credential).update_data(**data).result + return ( + await Api(**api, credential=credential) + .update_params(**params) + .update_data(**data) + .result + ) async def get_raw_manga_index( @@ -438,7 +424,7 @@ async def get_raw_manga_index( """ credential = credential if credential else Credential() api = API["info"]["index"] - params = {"device": "pc", "platform": "web"} + params = {"device": "pc", "platform": "web", "nov": 25} data = { "area_id": area.value, "order": order.value, @@ -519,7 +505,7 @@ async def get_manga_update( """ credential = credential if credential else Credential() api = API["info"]["update"] - params = {"device": "pc", "platform": "web"} + params = {"device": "pc", "platform": "web", "nov": 25} if isinstance(date, datetime.datetime): date = date.strftime("%Y-%m-%d") data = {"date": date, "page_num": pn, "page_size": ps} @@ -550,7 +536,7 @@ async def get_manga_home_recommend( """ credential = credential if credential else Credential() api = API["info"]["home_recommend"] - params = {"device": "pc", "platform": "web"} + params = {"device": "pc", "platform": "web", "nov": 25} data = {"page_num": pn, "seed": seed} manga_data = ( await Api(**api, credential=credential, no_csrf=True) diff --git a/bilibili_api/utils/network.py b/bilibili_api/utils/network.py index 7fc834ce..ee5b9799 100644 --- a/bilibili_api/utils/network.py +++ b/bilibili_api/utils/network.py @@ -503,9 +503,10 @@ async def _prepare_request(self, **kwargs) -> dict: if self.bili_ticket: cookies["bili_ticket"] = await get_bili_ticket() cookies["bili_ticket_expires"] = str(int(time.time()) + 2 * 86400) - settings.logger.info( - f'使用 bili_ticket [{cookies["bili_ticket"]}] expires [{cookies["bili_ticket_expires"]}]' - ) + if settings.request_log: + settings.logger.info( + f'使用 bili_ticket [{cookies["bili_ticket"]}] expires [{cookies["bili_ticket_expires"]}]' + ) if settings.request_log: settings.logger.info(self) diff --git a/bilibili_api/utils/picture.py b/bilibili_api/utils/picture.py index e8af1c99..69c0920f 100644 --- a/bilibili_api/utils/picture.py +++ b/bilibili_api/utils/picture.py @@ -78,7 +78,7 @@ async def async_load_url(url: str) -> "Picture": ) obj.content = resp.read() obj.url = url - obj.__set_picture_meta_from_bytes(url.split("/")[-1].split(".")[1]) + obj.__set_picture_meta_from_bytes(url.split("/")[-1].split(".")[1].split("?")[0]) return obj @staticmethod