From fbc766520ad7c845ccc11ebb524e875c0e1f94e7 Mon Sep 17 00:00:00 2001 From: LWR Date: Sat, 9 Nov 2024 00:07:29 +0800 Subject: [PATCH 01/11] fix: Fixed possible ZeroDivisionError when generate double ranking diagram --- starbot/painter/RankingGenerator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starbot/painter/RankingGenerator.py b/starbot/painter/RankingGenerator.py index d768a13..30ee138 100644 --- a/starbot/painter/RankingGenerator.py +++ b/starbot/painter/RankingGenerator.py @@ -158,7 +158,7 @@ class RankingGenerator: chart = PicGenerator(width, (face_size * count) + (row_space * (count - 1))) chart.set_row_space(row_space) for i in range(count): - bar_width = int(abs(counts[i]) / top_count * top_bar_width) + bar_width = int(abs(counts[i]) / top_count * top_bar_width) if top_count != 0 else 0.1 if bar_width != 0: if counts[i] > 0: bar = cls.__get_rank_bar_pic(bar_width, bar_height, start_color, end_color) From f92b4d71366e19046f5c1ae87fe85f2f2461cd69 Mon Sep 17 00:00:00 2001 From: LWR Date: Sat, 9 Nov 2024 00:15:17 +0800 Subject: [PATCH 02/11] docs: Update version --- starbot/core/bot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/starbot/core/bot.py b/starbot/core/bot.py index 54d1dbd..fc5ebb0 100644 --- a/starbot/core/bot.py +++ b/starbot/core/bot.py @@ -26,7 +26,7 @@ class StarBot: """ StarBot 类 """ - VERSION = "2.0.10" + VERSION = "2.0.11" STARBOT_ASCII_LOGO = "\n".join( ( r" _____ _ ____ _ ", @@ -35,7 +35,7 @@ class StarBot: r" \___ \| __/ _` | '__| _ < / _ \| __|", r" ____) | || (_| | | | |_) | (_) | |_ ", r" |_____/ \__\__,_|_| |____/ \___/ \__|", - f" StarBot - (v{VERSION}) 2024-06-30", + f" StarBot - (v{VERSION}) 2024-11-09", r" Github: https://github.com/Starlwr/StarBot", r"", r"", From a7df9e58de6cb9f8c5dac718fe4423dc643c1a68 Mon Sep 17 00:00:00 2001 From: LWR Date: Mon, 11 Nov 2024 23:02:53 +0800 Subject: [PATCH 03/11] fix: Fixed possible slice step is 0 when generate box profit diagram --- starbot/painter/LiveReportGenerator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starbot/painter/LiveReportGenerator.py b/starbot/painter/LiveReportGenerator.py index 67bde61..a84d5bf 100644 --- a/starbot/painter/LiveReportGenerator.py +++ b/starbot/painter/LiveReportGenerator.py @@ -674,7 +674,7 @@ class LiveReportGenerator: end = abs_max + (-abs_max % 10) step = int((end - start) / 10) - yticks = list(range(start, end)[::step]) + yticks = list(range(start, end)[::step]) if step != 0 else [0] yticks.append(end) return cls.__get_line_diagram( indexs, profits, [], yticks, [], [], (-1, length), (start, end), width From f50b81e958f44eb85ef046bbf35c1f32c71e6d70 Mon Sep 17 00:00:00 2001 From: LWR Date: Sun, 1 Dec 2024 23:54:51 +0800 Subject: [PATCH 04/11] fix: Fixed exception when API returns non-JSON data --- starbot/utils/network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starbot/utils/network.py b/starbot/utils/network.py index 4939de1..a8084f6 100644 --- a/starbot/utils/network.py +++ b/starbot/utils/network.py @@ -134,7 +134,7 @@ async def request(method: str, content_type = resp.headers.get("content-type") # 不是 application/json - if content_type.lower().index("application/json") == -1: + if content_type.lower().find("application/json") == -1: raise ResponseException("响应不是 application/json 类型") raw_data = await resp.text() From e683569d92cfa95b64c31aaeef836c9761c20b43 Mon Sep 17 00:00:00 2001 From: LWR Date: Mon, 2 Dec 2024 00:00:28 +0800 Subject: [PATCH 05/11] feat: Added a tip for expired cookie --- starbot/core/dynamic.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/starbot/core/dynamic.py b/starbot/core/dynamic.py index 5467676..2d21056 100644 --- a/starbot/core/dynamic.py +++ b/starbot/core/dynamic.py @@ -31,6 +31,9 @@ async def dynamic_spider(datasource: DataSource): except ResponseCodeException as ex: if ex.code == -6: continue + if ex.code == 4100000: + logger.error("B 站登录凭据已失效, 无法继续抓取动态,请配置新登录凭据后重启服务") + continue logger.error(f"动态推送任务抓取最新动态异常, HTTP 错误码: {ex.code} ({ex.msg})") except NetworkException: continue From 7965198c8529dc716a4b247071b2cf9ee6d48a18 Mon Sep 17 00:00:00 2001 From: LWR Date: Wed, 4 Dec 2024 00:25:59 +0800 Subject: [PATCH 06/11] fix: Fixed error caused by api risk control --- starbot/core/room.py | 2 ++ starbot/utils/network.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/starbot/core/room.py b/starbot/core/room.py index 0a918c6..e3f10f8 100644 --- a/starbot/core/room.py +++ b/starbot/core/room.py @@ -209,6 +209,8 @@ class Up(BaseModel): if ex.code == 19002005: locked = True logger.warning(f"{self.uname} ({self.room_id}) 的直播间已加密") + else: + logger.error(f"{self.uname} ({self.room_id}) 的直播间信息获取失败, 错误信息: {ex.code} ({ex.msg})") if not locked: self.uname = room_info["anchor_info"]["base_info"]["uname"] diff --git a/starbot/utils/network.py b/starbot/utils/network.py index a8084f6..a029117 100644 --- a/starbot/utils/network.py +++ b/starbot/utils/network.py @@ -73,7 +73,7 @@ async def request(method: str, # 使用 Referer 和 UA 请求头以绕过反爬虫机制 default_headers = { "Referer": "https://www.bilibili.com", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.218.400 QQBrowser/12.1.5496.400" + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.97 Safari/537.36 Core/1.116.462.400 QQBrowser/13.3.6197.400" } headers = default_headers @@ -156,7 +156,7 @@ async def request(method: str, if code != 0: # 4101131: 加载错误,请稍后再试, 22015: 您的账号异常,请稍后再试 - if code == 4101131 or code == 22015: + if code == 4101131 or code == 22015 or code == -352: await asyncio.sleep(10) continue From 354b1b661f03617ed9260534256fe8695ebff841 Mon Sep 17 00:00:00 2001 From: LWR Date: Wed, 4 Dec 2024 00:27:40 +0800 Subject: [PATCH 07/11] docs: Update version --- starbot/core/bot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/starbot/core/bot.py b/starbot/core/bot.py index fc5ebb0..d6a3ae4 100644 --- a/starbot/core/bot.py +++ b/starbot/core/bot.py @@ -26,7 +26,7 @@ class StarBot: """ StarBot 类 """ - VERSION = "2.0.11" + VERSION = "2.0.12" STARBOT_ASCII_LOGO = "\n".join( ( r" _____ _ ____ _ ", @@ -35,7 +35,7 @@ class StarBot: r" \___ \| __/ _` | '__| _ < / _ \| __|", r" ____) | || (_| | | | |_) | (_) | |_ ", r" |_____/ \__\__,_|_| |____/ \___/ \__|", - f" StarBot - (v{VERSION}) 2024-11-09", + f" StarBot - (v{VERSION}) 2024-12-04", r" Github: https://github.com/Starlwr/StarBot", r"", r"", From 06334653daa422184b19fe6e1b1233cf274c1073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E5=A4=A9=E5=AE=AC?= <67567242+fangtiancheng@users.noreply.github.com> Date: Tue, 7 Jan 2025 22:37:39 +0800 Subject: [PATCH 08/11] feat: Add wbi utils --- starbot/api/user.json | 22 +++++++++++++++ starbot/core/user.py | 38 +++++++++++++++++++++++-- starbot/core/wbi.py | 66 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 starbot/core/wbi.py diff --git a/starbot/api/user.json b/starbot/api/user.json index ff4f49b..81b69f3 100644 --- a/starbot/api/user.json +++ b/starbot/api/user.json @@ -15,6 +15,17 @@ }, "comment": "用户基本信息" }, + "info_wbi": { + "url": "https://api.bilibili.com/x/space/wbi/acc/info", + "method": "GET", + "verify": false, + "params": { + "mid": "int: uid", + "w_rid": "str: Wbi签名", + "wts": "int: 当前时间戳" + }, + "comment": "用户基本信息(WBI版本)" + }, "relation": { "url": "https://api.bilibili.com/x/relation/stat", "method": "GET", @@ -42,6 +53,17 @@ }, "comment": "直播间基本信息" }, + "live_wbi": { + "url": "https://api.bilibili.com/x/space/wbi/acc/info", + "method": "GET", + "verify": false, + "params": { + "mid": "int: uid", + "w_rid": "str: Wbi签名", + "wts": "int: 当前时间戳" + }, + "comment": "直播间基本信息(WBI版本)" + }, "video": { "url": "https://api.bilibili.com/x/space/arc/search", "method": "GET", diff --git a/starbot/core/user.py b/starbot/core/user.py index efcfabf..2b4c0e8 100644 --- a/starbot/core/user.py +++ b/starbot/core/user.py @@ -6,8 +6,10 @@ import json import time from enum import Enum -from typing import List +from typing import List, Dict +from deprecated import deprecated +from .wbi import encWbi, getWbiKeys from ..utils.Credential import Credential from ..utils.network import request from ..utils.utils import get_api @@ -100,7 +102,7 @@ class User: 用户相关 """ - def __init__(self, uid: int, credential: Credential = None): + def __init__(self, uid: int, credential: Credential = None, wbi_keys: Dict[str, str] = None): """ Args: uid: 用户 UID @@ -112,7 +114,12 @@ class User: credential = Credential() self.credential = credential self.__self_info = None - + self.__wbi_keys = wbi_keys + + def set_wbi_keys(self, wbi_keys: Dict[str, str]) -> None: + self.__wbi_keys = wbi_keys + + @deprecated(reason='you should use get_user_info_wbi') async def get_user_info(self): """ 获取用户信息(昵称,性别,生日,签名,头像 URL,空间横幅 URL 等) @@ -123,6 +130,16 @@ class User: } return await request("GET", url=api["url"], params=params, credential=self.credential) + async def get_user_info_wbi(self): + if self.__wbi_keys == None: + raise RuntimeError("wbi keys is None") + api = API["info"]["info_wbi"] + params = { + "mid": self.uid + } + params_wbi = encWbi(params, **self.__wbi_keys) + return await request("GET", url=api["url"], params=params, credential=self.credential) + async def __get_self_info(self): """ 获取自己的信息,如果存在缓存则使用缓存 @@ -155,6 +172,7 @@ class User: } return await request("GET", url=api["url"], params=params, credential=self.credential) + @deprecated(reason="you should use get_live_info_wbi") async def get_live_info(self): """ 获取用户直播间信息 @@ -165,6 +183,19 @@ class User: } return await request("GET", url=api["url"], params=params, credential=self.credential) + async def get_live_info_wbi(self): + """ + 获取用户直播间信息 + """ + if self.__wbi_keys == None: + raise RuntimeError("wbi keys is None") + api = API["info"]["live_wbi"] + params = { + "mid": self.uid + } + params_wbi = encWbi(params, **self.__wbi_keys) + return await request("GET", url=api["url"], params=params_wbi, credential=self.credential) + async def get_videos(self, tid: int = 0, pn: int = 1, @@ -239,6 +270,7 @@ class User: } return await request("GET", url=api["url"], params=params, credential=self.credential) + @deprecated(reason="https://github.com/SocialSisterYi/bilibili-API-collect/issues/852") async def get_dynamics(self, offset: int = 0, need_top: bool = False): """ 获取用户动态 diff --git a/starbot/core/wbi.py b/starbot/core/wbi.py new file mode 100644 index 0000000..2594f01 --- /dev/null +++ b/starbot/core/wbi.py @@ -0,0 +1,66 @@ +# https://socialsisteryi.github.io/bilibili-API-collect/docs/misc/sign/wbi.html#python + +from functools import reduce +from hashlib import md5 +import urllib.parse +import time +import requests + +mixinKeyEncTab = [ + 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, + 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, + 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, + 36, 20, 34, 44, 52 +] + +def getMixinKey(orig: str): + '对 imgKey 和 subKey 进行字符顺序打乱编码' + return reduce(lambda s, i: s + orig[i], mixinKeyEncTab, '')[:32] + +def encWbi(params: dict, img_key: str, sub_key: str): + '为请求参数进行 wbi 签名' + mixin_key = getMixinKey(img_key + sub_key) + curr_time = round(time.time()) + params['wts'] = curr_time # 添加 wts 字段 + params = dict(sorted(params.items())) # 按照 key 重排参数 + # 过滤 value 中的 "!'()*" 字符 + params = { + k : ''.join(filter(lambda chr: chr not in "!'()*", str(v))) + for k, v + in params.items() + } + query = urllib.parse.urlencode(params) # 序列化参数 + wbi_sign = md5((query + mixin_key).encode()).hexdigest() # 计算 w_rid + params['w_rid'] = wbi_sign + return params + +def getWbiKeys() -> tuple[str, str]: + '获取最新的 img_key 和 sub_key' + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', + 'Referer': 'https://www.bilibili.com/' + } + resp = requests.get('https://api.bilibili.com/x/web-interface/nav', headers=headers) + resp.raise_for_status() + json_content = resp.json() + img_url: str = json_content['data']['wbi_img']['img_url'] + sub_url: str = json_content['data']['wbi_img']['sub_url'] + img_key = img_url.rsplit('/', 1)[1].split('.')[0] + sub_key = sub_url.rsplit('/', 1)[1].split('.')[0] + return img_key, sub_key + +if __name__ == '__main__': + img_key, sub_key = getWbiKeys() + + signed_params = encWbi( + params={ + 'foo': '114', + 'bar': '514', + 'baz': 1919810 + }, + img_key=img_key, + sub_key=sub_key + ) + query = urllib.parse.urlencode(signed_params) + print(signed_params) + print(query) From 79afbf8a9652d882e8da5392f960cf3d4b4151f9 Mon Sep 17 00:00:00 2001 From: LWR Date: Tue, 7 Jan 2025 22:41:19 +0800 Subject: [PATCH 09/11] refactor: Refactor wbi utils --- starbot/core/user.py | 38 ++----------------------- starbot/core/wbi.py | 66 -------------------------------------------- starbot/utils/wbi.py | 45 ++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 101 deletions(-) delete mode 100644 starbot/core/wbi.py create mode 100644 starbot/utils/wbi.py diff --git a/starbot/core/user.py b/starbot/core/user.py index 2b4c0e8..efcfabf 100644 --- a/starbot/core/user.py +++ b/starbot/core/user.py @@ -6,10 +6,8 @@ import json import time from enum import Enum -from typing import List, Dict -from deprecated import deprecated +from typing import List -from .wbi import encWbi, getWbiKeys from ..utils.Credential import Credential from ..utils.network import request from ..utils.utils import get_api @@ -102,7 +100,7 @@ class User: 用户相关 """ - def __init__(self, uid: int, credential: Credential = None, wbi_keys: Dict[str, str] = None): + def __init__(self, uid: int, credential: Credential = None): """ Args: uid: 用户 UID @@ -114,12 +112,7 @@ class User: credential = Credential() self.credential = credential self.__self_info = None - self.__wbi_keys = wbi_keys - - def set_wbi_keys(self, wbi_keys: Dict[str, str]) -> None: - self.__wbi_keys = wbi_keys - - @deprecated(reason='you should use get_user_info_wbi') + async def get_user_info(self): """ 获取用户信息(昵称,性别,生日,签名,头像 URL,空间横幅 URL 等) @@ -130,16 +123,6 @@ class User: } return await request("GET", url=api["url"], params=params, credential=self.credential) - async def get_user_info_wbi(self): - if self.__wbi_keys == None: - raise RuntimeError("wbi keys is None") - api = API["info"]["info_wbi"] - params = { - "mid": self.uid - } - params_wbi = encWbi(params, **self.__wbi_keys) - return await request("GET", url=api["url"], params=params, credential=self.credential) - async def __get_self_info(self): """ 获取自己的信息,如果存在缓存则使用缓存 @@ -172,7 +155,6 @@ class User: } return await request("GET", url=api["url"], params=params, credential=self.credential) - @deprecated(reason="you should use get_live_info_wbi") async def get_live_info(self): """ 获取用户直播间信息 @@ -183,19 +165,6 @@ class User: } return await request("GET", url=api["url"], params=params, credential=self.credential) - async def get_live_info_wbi(self): - """ - 获取用户直播间信息 - """ - if self.__wbi_keys == None: - raise RuntimeError("wbi keys is None") - api = API["info"]["live_wbi"] - params = { - "mid": self.uid - } - params_wbi = encWbi(params, **self.__wbi_keys) - return await request("GET", url=api["url"], params=params_wbi, credential=self.credential) - async def get_videos(self, tid: int = 0, pn: int = 1, @@ -270,7 +239,6 @@ class User: } return await request("GET", url=api["url"], params=params, credential=self.credential) - @deprecated(reason="https://github.com/SocialSisterYi/bilibili-API-collect/issues/852") async def get_dynamics(self, offset: int = 0, need_top: bool = False): """ 获取用户动态 diff --git a/starbot/core/wbi.py b/starbot/core/wbi.py deleted file mode 100644 index 2594f01..0000000 --- a/starbot/core/wbi.py +++ /dev/null @@ -1,66 +0,0 @@ -# https://socialsisteryi.github.io/bilibili-API-collect/docs/misc/sign/wbi.html#python - -from functools import reduce -from hashlib import md5 -import urllib.parse -import time -import requests - -mixinKeyEncTab = [ - 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, - 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, - 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, - 36, 20, 34, 44, 52 -] - -def getMixinKey(orig: str): - '对 imgKey 和 subKey 进行字符顺序打乱编码' - return reduce(lambda s, i: s + orig[i], mixinKeyEncTab, '')[:32] - -def encWbi(params: dict, img_key: str, sub_key: str): - '为请求参数进行 wbi 签名' - mixin_key = getMixinKey(img_key + sub_key) - curr_time = round(time.time()) - params['wts'] = curr_time # 添加 wts 字段 - params = dict(sorted(params.items())) # 按照 key 重排参数 - # 过滤 value 中的 "!'()*" 字符 - params = { - k : ''.join(filter(lambda chr: chr not in "!'()*", str(v))) - for k, v - in params.items() - } - query = urllib.parse.urlencode(params) # 序列化参数 - wbi_sign = md5((query + mixin_key).encode()).hexdigest() # 计算 w_rid - params['w_rid'] = wbi_sign - return params - -def getWbiKeys() -> tuple[str, str]: - '获取最新的 img_key 和 sub_key' - headers = { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', - 'Referer': 'https://www.bilibili.com/' - } - resp = requests.get('https://api.bilibili.com/x/web-interface/nav', headers=headers) - resp.raise_for_status() - json_content = resp.json() - img_url: str = json_content['data']['wbi_img']['img_url'] - sub_url: str = json_content['data']['wbi_img']['sub_url'] - img_key = img_url.rsplit('/', 1)[1].split('.')[0] - sub_key = sub_url.rsplit('/', 1)[1].split('.')[0] - return img_key, sub_key - -if __name__ == '__main__': - img_key, sub_key = getWbiKeys() - - signed_params = encWbi( - params={ - 'foo': '114', - 'bar': '514', - 'baz': 1919810 - }, - img_key=img_key, - sub_key=sub_key - ) - query = urllib.parse.urlencode(signed_params) - print(signed_params) - print(query) diff --git a/starbot/utils/wbi.py b/starbot/utils/wbi.py new file mode 100644 index 0000000..03ddef4 --- /dev/null +++ b/starbot/utils/wbi.py @@ -0,0 +1,45 @@ +# https://socialsisteryi.github.io/bilibili-API-collect/docs/misc/sign/wbi.html#python + +from functools import reduce +from hashlib import md5 +import urllib.parse +import time + +from starbot.utils.network import request +from starbot.utils.utils import get_credential + +mixinKeyEncTab = [ + 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, + 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, + 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, + 36, 20, 34, 44, 52 +] + + +def get_mixin_key(orig: str): + return reduce(lambda s, i: s + orig[i], mixinKeyEncTab, '')[:32] + + +def enc_wbi(params: dict, img_key: str, sub_key: str): + mixin_key = get_mixin_key(img_key + sub_key) + curr_time = round(time.time()) + params['wts'] = curr_time # 添加 wts 字段 + params = dict(sorted(params.items())) # 按照 key 重排参数 + # 过滤 value 中的 "!'()*" 字符 + params = { + k: ''.join(filter(lambda c: c not in "!'()*", str(v))) + for k, v + in params.items() + } + query = urllib.parse.urlencode(params) # 序列化参数 + wbi_sign = md5((query + mixin_key).encode()).hexdigest() # 计算 w_rid + params['w_rid'] = wbi_sign + return params + + +async def get_wbi_keys() -> tuple[str, str]: + """获取最新的 img_key 和 sub_key""" + result = await request("GET", "https://api.bilibili.com/x/web-interface/nav", credential=get_credential()) + img_url = result['wbi_img']['img_url'] + sub_url = result['wbi_img']['sub_url'] + return img_url.rsplit('/', 1)[1].split('.')[0], sub_url.rsplit('/', 1)[1].split('.')[0] From 4e70b4605d775270881214ea29e1e1ffa3d21167 Mon Sep 17 00:00:00 2001 From: LWR Date: Wed, 8 Jan 2025 00:07:56 +0800 Subject: [PATCH 10/11] fix: Fixed None error caused by api risk control --- starbot/core/live.py | 42 ++++++++++++++++++++++++++++++++++++++ starbot/core/room.py | 48 ++++++++++++++++++++++++++------------------ 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/starbot/core/live.py b/starbot/core/live.py index 71547f6..c2acd14 100644 --- a/starbot/core/live.py +++ b/starbot/core/live.py @@ -167,6 +167,48 @@ class LiveRoom: } return await request(api['method'], api["url"], params, credential=self.credential) + async def get_room_info_v2(self): + """ + 获取直播间信息(标题,简介等) + """ + api = "https://api.live.bilibili.com/room/v1/Room/get_info" + params = { + "room_id": self.room_display_id + } + return await request("GET", api, params, credential=self.credential) + + async def get_fans_medal_info(self, uid: int): + """ + 获取粉丝勋章信息 + + Args: + uid: 用户 UID + """ + api = "https://api.live.bilibili.com/xlive/app-ucenter/v1/fansMedal/fans_medal_info" + params = { + "target_id": uid, + "room_id": self.room_display_id + } + return await request("GET", api, params, credential=self.credential) + + async def get_guards_info(self, uid: int): + """ + 获取大航海信息 + + Args: + uid: 用户 UID + """ + api = "https://api.live.bilibili.com/xlive/app-room/v2/guardTab/topListNew" + params = { + "roomid": self.room_display_id, + "page": 1, + "ruid": uid, + "page_size": 20, + "typ": 5, + "platform": "web" + } + return await request("GET", api, params, credential=self.credential) + async def get_user_info_in_room(self): """ 获取自己在直播间的信息(粉丝勋章等级,直播用户等级等) diff --git a/starbot/core/room.py b/starbot/core/room.py index e3f10f8..91ce2f2 100644 --- a/starbot/core/room.py +++ b/starbot/core/room.py @@ -2,6 +2,7 @@ import asyncio import time import typing from asyncio import AbstractEventLoop +from datetime import datetime from typing import Optional, Any, Union, List from loguru import logger @@ -183,6 +184,8 @@ class Up(BaseModel): locked = False room_info = {} + fans_medal_info = {} + guards_info = {} # 是否为真正开播 if "live_time" in event["data"]: @@ -204,7 +207,9 @@ class Up(BaseModel): logger.opt(colors=True).info(f"[开播] {self.uname} ({self.room_id})") try: - room_info = await self.__live_room.get_room_info() + room_info = await self.__live_room.get_room_info_v2() + fans_medal_info = await self.__live_room.get_fans_medal_info(self.uid) + guards_info = await self.__live_room.get_guards_info(self.uid) except ResponseCodeException as ex: if ex.code == 19002005: locked = True @@ -213,18 +218,23 @@ class Up(BaseModel): logger.error(f"{self.uname} ({self.room_id}) 的直播间信息获取失败, 错误信息: {ex.code} ({ex.msg})") if not locked: - self.uname = room_info["anchor_info"]["base_info"]["uname"] + # 此处若有合适 API 需更新一下最新昵称 + pass - live_start_time = room_info["room_info"]["live_start_time"] if not locked else int(time.time()) + if locked: + live_start_time = int(time.time()) + else: + if room_info["live_time"] != "0000-00-00 00:00:00": + time_format = "%Y-%m-%d %H:%M:%S" + live_start_time = int(datetime.strptime(room_info["live_time"], time_format).timestamp()) + else: + live_start_time = int(time.time()) await redis.set_live_start_time(self.room_id, live_start_time) if not locked: - fans_count = room_info["anchor_info"]["relation_info"]["attention"] - if room_info["anchor_info"]["medal_info"] is None: - fans_medal_count = 0 - else: - fans_medal_count = room_info["anchor_info"]["medal_info"]["fansclub"] - guard_count = room_info["guard_info"]["count"] + fans_count = room_info["attention"] + fans_medal_count = fans_medal_info["fans_medal_light_count"] + guard_count = guards_info["info"]["num"] await redis.set_fans_count(self.room_id, live_start_time, fans_count) await redis.set_fans_medal_count(self.room_id, live_start_time, fans_medal_count) await redis.set_guard_count(self.room_id, live_start_time, guard_count) @@ -233,12 +243,11 @@ class Up(BaseModel): # 推送开播消息 if not locked: - arg_base = room_info["room_info"] args = { "{uname}": self.uname, - "{title}": arg_base["title"], + "{title}": room_info["title"], "{url}": f"https://live.bilibili.com/{self.room_id}", - "{cover}": "".join(["{urlpic=", arg_base["cover"], "}"]) + "{cover}": "".join(["{urlpic=", room_info["user_cover"], "}"]) } else: args = { @@ -484,11 +493,15 @@ class Up(BaseModel): locked = False room_info = {} + fans_medal_info = {} + guards_info = {} # 基础数据变动 if self.__any_live_report_item_enabled(["fans_change", "fans_medal_change", "guard_change"]): try: - room_info = await self.__live_room.get_room_info() + room_info = await self.__live_room.get_room_info_v2() + fans_medal_info = await self.__live_room.get_fans_medal_info(self.uid) + guards_info = await self.__live_room.get_guards_info(self.uid) except ResponseCodeException as ex: if ex.code == 19002005: locked = True @@ -508,21 +521,18 @@ class Up(BaseModel): else: guard_count = -1 - if room_info["anchor_info"]["medal_info"] is None: - fans_medal_count_after = 0 - else: - fans_medal_count_after = room_info["anchor_info"]["medal_info"]["fansclub"] + fans_medal_count_after = fans_medal_info["fans_medal_light_count"] live_report_param.update({ # 粉丝变动 "fans_before": fans_count, - "fans_after": room_info["anchor_info"]["relation_info"]["attention"], + "fans_after": room_info["attention"], # 粉丝团(粉丝勋章数)变动 "fans_medal_before": fans_medal_count, "fans_medal_after": fans_medal_count_after, # 大航海变动 "guard_before": guard_count, - "guard_after": room_info["guard_info"]["count"] + "guard_after": guards_info["info"]["num"] }) # 直播数据 From ebf7343586760685448e56323fd77845e00a7dc7 Mon Sep 17 00:00:00 2001 From: LWR Date: Wed, 8 Jan 2025 00:08:15 +0800 Subject: [PATCH 11/11] docs: Update version --- starbot/core/bot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/starbot/core/bot.py b/starbot/core/bot.py index d6a3ae4..f866027 100644 --- a/starbot/core/bot.py +++ b/starbot/core/bot.py @@ -26,7 +26,7 @@ class StarBot: """ StarBot 类 """ - VERSION = "2.0.12" + VERSION = "2.0.14" STARBOT_ASCII_LOGO = "\n".join( ( r" _____ _ ____ _ ", @@ -35,7 +35,7 @@ class StarBot: r" \___ \| __/ _` | '__| _ < / _ \| __|", r" ____) | || (_| | | | |_) | (_) | |_ ", r" |_____/ \__\__,_|_| |____/ \___/ \__|", - f" StarBot - (v{VERSION}) 2024-12-04", + f" StarBot - (v{VERSION}) 2025-01-08", r" Github: https://github.com/Starlwr/StarBot", r"", r"",