diff --git a/starbot/core/bot.py b/starbot/core/bot.py index 480b107..b599f33 100644 --- a/starbot/core/bot.py +++ b/starbot/core/bot.py @@ -8,9 +8,11 @@ from loguru import logger from .datasource import DataSource from .server import http_init +from ..exception import LiveException from ..exception.DataSourceException import DataSourceException from ..exception.RedisException import RedisException from ..utils import redis, config +from ..utils.network import request class StarBot: @@ -61,6 +63,44 @@ class StarBot: logger.error(ex.msg) return + # 通过 UID 列表批量获取信息 + uids = list(map(lambda u: str(u), self.__datasource.get_uid_list())) + info_url = "https://api.live.bilibili.com/room/v1/Room/get_status_info_by_uids?uids[]=" + "&uids[]=".join(uids) + info = await request("GET", info_url) + for uid in info: + base = info[uid] + uid = int(uid) + up = self.__datasource.get_up(uid) + up.uname = base["uname"] + up.room_id = base["room_id"] + status = base["live_status"] + logger.opt(colors=True).info(f"初始化 {up.uname} " + f"(UID: {up.uid}, " + f"房间号: {up.room_id}) 的直播间状态: " + f"{'直播中' if status == 1 else '未开播'}") + + await redis.hset("LiveStatus", up.room_id, status) + await redis.hset("StartTime", up.room_id, base["live_time"]) + await redis.hset_ifnotexists("EndTime", up.room_id, 0) + await redis.hset_ifnotexists("RoomDanmuCount", up.room_id, 0) + await redis.hset_ifnotexists("RoomDanmuTotal", up.room_id, 0) + await redis.hset_ifnotexists("RoomBoxCount", up.room_id, 0) + await redis.hset_ifnotexists("RoomBoxTotal", up.room_id, 0) + await redis.hset_ifnotexists("RoomBoxProfit", up.room_id, 0) + await redis.hset_ifnotexists("RoomBoxProfitTotal", up.room_id, 0) + await redis.hset_ifnotexists("RoomGiftProfit", up.room_id, 0) + await redis.hset_ifnotexists("RoomGiftTotal", up.room_id, 0) + await redis.hset_ifnotexists("RoomScProfit", up.room_id, 0) + await redis.hset_ifnotexists("RoomScTotal", up.room_id, 0) + await redis.hset_ifnotexists("RoomGuardCount", up.room_id, "0-0-0") + await redis.hset_ifnotexists("RoomGuardTotal", up.room_id, "0-0-0") + + for up in self.__datasource.get_up_list(): + try: + await up.connect() + except LiveException as ex: + logger.error(ex.msg) + # 启动 HTTP API 服务 if config.get("USE_HTTP_API"): asyncio.get_event_loop().create_task(http_init(self.__datasource)) diff --git a/starbot/core/easter_egg.py b/starbot/core/easter_egg.py new file mode 100644 index 0000000..1f97663 --- /dev/null +++ b/starbot/core/easter_egg.py @@ -0,0 +1,8 @@ +s = "Unccl oveguqnl gb zr!" + +d = {} +for c in (65, 97): + for i in range(26): + d[chr(i+c)] = chr((i+13) % 26 + c) + +print("".join([d.get(c, c) for c in s])) diff --git a/starbot/core/room.py b/starbot/core/room.py index 09d8dd1..d69f07d 100644 --- a/starbot/core/room.py +++ b/starbot/core/room.py @@ -3,10 +3,15 @@ import typing from asyncio import AbstractEventLoop from typing import Optional, List, Any +from loguru import logger from pydantic import BaseModel, PrivateAttr -from .live import LiveDanmaku +from .live import LiveDanmaku, LiveRoom from .model import PushTarget +from .user import User +from ..exception import LiveException +from ..utils import config, redis +from ..utils.utils import get_credential if typing.TYPE_CHECKING: from .sender import Bot @@ -51,6 +56,61 @@ class Up(BaseModel): def inject_bot(self, bot): self.__bot = bot + def any_live_on_enabled(self): + return any(map(lambda conf: conf.enabled, map(lambda group: group.live_on, self.targets))) + + def any_live_off_enabled(self): + return any(map(lambda conf: conf.enabled, map(lambda group: group.live_off, self.targets))) + + def any_live_report_enabled(self): + return any(map(lambda conf: conf.enabled, map(lambda group: group.live_report, self.targets))) + + async def connect(self): + """ + 连接直播间 + """ + if not all([self.uname, self.room_id]): + user = User(self.uid, get_credential()) + user_info = await user.get_user_info() + self.uname = user_info["name"] + if user_info["live_room"] is None: + raise LiveException(f"UP 主 {self.uname} ( UID: {self.uid} ) 还未开通直播间~") + self.room_id = user_info["live_room"]["roomid"] + self.__room = LiveDanmaku(self.room_id, credential=get_credential()) + + # 开播推送开关和下播推送开关均处于关闭状态时跳过连接直播间,以节省性能 + if config.get("ONLY_CONNECT_NECESSARY_ROOM"): + if not any([self.any_live_on_enabled(), self.any_live_off_enabled(), self.any_live_report_enabled()]): + logger.warning(f"{self.uname} 的开播, 下播和直播报告开关均处于关闭状态, 跳过连接直播间") + return + + logger.opt(colors=True).info(f"准备连接到 {self.uname} 的直播间 {self.room_id}") + + self.__loop.create_task(self.__room.connect()) + + @self.__room.on("VERIFICATION_SUCCESSFUL") + async def on_link(event): + if self.__is_reconnect: + logger.success(f"直播间 {self.room_id} 断线重连成功") + + live_room = LiveRoom(self.room_id, get_credential()) + room_info = await live_room.get_room_play_info() + last_status = await redis.hgeti("LiveStatus", self.room_id) + now_status = room_info["live_status"] + + if now_status != last_status: + await redis.hset("LiveStatus", self.room_id, now_status) + if last_status == 1: + logger.warning(f"直播间 {self.room_id} 断线期间下播") + pass + if now_status == 1: + logger.warning(f"直播间 {self.room_id} 断线期间开播") + pass + else: + self.__is_reconnect = True + + logger.success(f"已成功连接到 {self.uname} 的直播间 {self.room_id}") + def __eq__(self, other): if isinstance(other, Up): return self.uid == other.uid