diff --git a/starbot/commands/builtin/__init__.py b/starbot/commands/builtin/__init__.py index 2a7727a..d7979da 100644 --- a/starbot/commands/builtin/__init__.py +++ b/starbot/commands/builtin/__init__.py @@ -12,3 +12,5 @@ import starbot.commands.builtin.data.user_data_total import starbot.commands.builtin.disable_command import starbot.commands.builtin.enable_command import starbot.commands.builtin.help +import starbot.commands.builtin.ranking.ranking +import starbot.commands.builtin.ranking.ranking_double diff --git a/starbot/commands/builtin/help.py b/starbot/commands/builtin/help.py new file mode 100644 index 0000000..881a5a3 --- /dev/null +++ b/starbot/commands/builtin/help.py @@ -0,0 +1,159 @@ +from typing import Union + +from graia.ariadne import Ariadne +from graia.ariadne.event.message import FriendMessage, GroupMessage +from graia.ariadne.message.chain import MessageChain +from graia.ariadne.message.element import Image +from graia.ariadne.message.parser.twilight import Twilight, FullMatch, UnionMatch +from graia.ariadne.model import Friend, Group +from graia.saya import Channel +from graia.saya.builtins.broadcast import ListenerSchema + +from ...painter.PicGenerator import PicGenerator, Color +from ...utils import config, redis + +prefix = config.get("COMMAND_PREFIX") + +channel = Channel.current() + + +@channel.use( + ListenerSchema( + listening_events=[FriendMessage, GroupMessage], + inline_dispatchers=[Twilight( + FullMatch(prefix), + UnionMatch("帮助", "菜单", "功能", "命令", "指令", "help") + )], + ) +) +async def _help(app: Ariadne, sender: Union[Friend, Group]): + disable_querys = ["DenyRoomData", "DenyRoomDataTotal", "DenyBind", "DenyUserData", "DenyUserDataTotal"] + disabled = [False] * 5 + if isinstance(sender, Group): + disabled = [await redis.exists_disable_command(x, sender.id) for x in disable_querys] + + width = 1000 + height = 100000 + pic = PicGenerator(width, height) + pic.set_pos(50, 50).draw_rounded_rectangle(0, 0, width, height, 35, Color.WHITE).copy_bottom(35) + + pic.draw_chapter("StarBot 帮助") + pic.draw_text("") + + pic.draw_section(f"1.{prefix}菜单") + commands = "、".join([f"{prefix}{x}" for x in ["帮助", "菜单", "功能", "命令", "指令", "help"]]) + pic.draw_text_multiline(50, ["命令: ", commands], [Color.RED, Color.BLACK]) + pic.draw_tip("获取 Starbot 帮助和命令菜单") + + pic.draw_section(f"2.{prefix}禁用命令") + commands = "、".join([f"{prefix}{x} [命令名]" for x in ["禁用", "disable"]]) + pic.draw_text_multiline(50, ["命令: ", commands], [Color.RED, Color.BLACK]) + pic.draw_text(["示例: ", "禁用 直播间总数据"], [Color.RED, Color.BLACK]) + pic.draw_tip("此命令仅群聊可用") + pic.draw_tip("可禁用的命令名: 绑定、直播间数据、直播间总数据、我的数据、我的总数据") + pic.draw_tip("命令禁用只针对本群,如有多群需同时禁用命令请每个群进行一次配置") + + pic.draw_section(f"3.{prefix}启用命令") + commands = "、".join([f"{prefix}{x} [命令名]" for x in ["启用", "enable"]]) + pic.draw_text_multiline(50, ["命令: ", commands], [Color.RED, Color.BLACK]) + pic.draw_text(["示例: ", "启用 直播间总数据"], [Color.RED, Color.BLACK]) + pic.draw_tip("此命令仅群聊可用") + pic.draw_tip("用于禁用命令后解除禁用") + + pic.draw_section(f"4.{prefix}直播间数据") + pic.draw_text_multiline(50, ["命令: ", f"{prefix}直播间数据"], [Color.RED, Color.BLACK]) + if disabled[0]: + pic.draw_text("本群已禁用此命令", Color.RED) + pic.draw_tip("查询本直播间最近一场直播的数据") + + pic.draw_section(f"5.{prefix}直播间总数据") + pic.draw_text_multiline(50, ["命令: ", f"{prefix}直播间总数据"], [Color.RED, Color.BLACK]) + if disabled[1]: + pic.draw_text("本群已禁用此命令", Color.RED) + pic.draw_tip("查询本直播间自注册之日起的累计总数据") + + pic.draw_section(f"6.{prefix}绑定") + commands = "、".join([f"{prefix}{x} [UID]" for x in ["绑定", "bind"]]) + pic.draw_text_multiline(50, ["命令: ", commands], [Color.RED, Color.BLACK]) + pic.draw_text(["示例: ", "绑定 114514"], [Color.RED, Color.BLACK]) + if disabled[2]: + pic.draw_text("本群已禁用此命令", Color.RED) + pic.draw_tip("将QQ号绑定至B站账号") + pic.draw_tip("绑定成功后即可查询自己在本直播间的数据") + pic.draw_tip("绑定后如需换绑直接使用新UID再次绑定即可") + + pic.draw_section(f"7.{prefix}我的数据") + pic.draw_text_multiline(50, ["命令: ", f"{prefix}我的数据"], [Color.RED, Color.BLACK]) + if disabled[3]: + pic.draw_text("本群已禁用此命令", Color.RED) + pic.draw_tip("查询自己在本直播间最近一场直播的数据、排名") + pic.draw_tip("需绑定B站账号后使用") + + pic.draw_section(f"8.{prefix}我的总数据") + pic.draw_text_multiline(50, ["命令: ", f"{prefix}我的总数据"], [Color.RED, Color.BLACK]) + if disabled[4]: + pic.draw_text("本群已禁用此命令", Color.RED) + pic.draw_tip("查询自己在本直播间自注册之日起的累计总数据、排名、占比") + pic.draw_tip("需绑定B站账号后使用") + + pic.draw_section(f"9.{prefix}数据排行榜") + types = [ + "弹幕排行", "弹幕总排行", + "盲盒排行", "盲盒总排行", + "盲盒盈亏排行", "盲盒盈亏总排行", + "礼物排行", "礼物总排行", + "SC排行", "SC总排行" + ] + commands = "、".join([f"{prefix}{x} <页码>" for x in types]) + pic.draw_text_multiline(50, ["命令: ", commands], [Color.RED, Color.BLACK]) + pic.draw_text(["示例: ", "弹幕排行、礼物总排行 3"], [Color.RED, Color.BLACK]) + pic.draw_tip("查询本直播间的数据排行榜") + pic.draw_tip("xx排行指本直播间最近一场直播的数据排行榜") + pic.draw_tip("xx总排行指本直播间自注册之日起的累计总数据排行榜") + pic.draw_tip("不输入页码参数默认查询第一页") + + pic.draw_section(f"10.{prefix}开播@我") + commands = "、".join([f"{prefix}{x}" for x in ["开播@我", "直播@我"]]) + pic.draw_text_multiline(50, ["命令: ", commands], [Color.RED, Color.BLACK]) + pic.draw_tip("此命令仅群聊可用") + pic.draw_tip("本直播间开播时单独@自己") + pic.draw_tip("如配置了@全体成员会优先@全体成员") + pic.draw_tip("当没有配置@全体成员或@全体成员失败时会单独@\"开播@我\"名单中的群成员") + + pic.draw_section(f"11.{prefix}取消开播@我") + commands = "、".join([f"{prefix}{x}" for x in ["取消开播@我", "退出开播@我", "开播不@我", "开播别@我"]]) + pic.draw_text_multiline(50, ["命令: ", commands], [Color.RED, Color.BLACK]) + pic.draw_tip("此命令仅群聊可用") + pic.draw_tip("退出本群的\"开播@我\"名单") + + pic.draw_section(f"12.{prefix}开播@名单") + commands = "、".join([f"{prefix}{x}" for x in ["开播@名单", "开播@列表"]]) + pic.draw_text_multiline(50, ["命令: ", commands], [Color.RED, Color.BLACK]) + pic.draw_tip("此命令仅群聊可用") + pic.draw_tip("查询本群的\"开播@我\"名单") + + pic.draw_section(f"13.{prefix}动态@我") + pic.draw_text_multiline(50, ["命令: ", f"{prefix}动态@我"], [Color.RED, Color.BLACK]) + pic.draw_tip("此命令仅群聊可用") + pic.draw_tip("主播发布新动态时单独@自己") + pic.draw_tip("如配置了@全体成员会优先@全体成员") + pic.draw_tip("当没有配置@全体成员或@全体成员失败时会单独@\"动态@我\"名单中的群成员") + + pic.draw_section(f"14.{prefix}取消动态@我") + commands = "、".join([f"{prefix}{x}" for x in ["取消动态@我", "退出动态@我", "动态不@我", "动态别@我"]]) + pic.draw_text_multiline(50, ["命令: ", commands], [Color.RED, Color.BLACK]) + pic.draw_tip("此命令仅群聊可用") + pic.draw_tip("退出本群的\"动态@我\"名单") + + pic.draw_section(f"15.{prefix}动态@名单") + commands = "、".join([f"{prefix}{x}" for x in ["动态@名单", "动态@列表"]]) + pic.draw_text_multiline(50, ["命令: ", commands], [Color.RED, Color.BLACK]) + pic.draw_tip("此命令仅群聊可用") + pic.draw_tip("查询本群的\"动态@我\"名单") + + # 底部版权信息,请务必保留此处 + pic.draw_text_right(25, "Designed By StarBot", Color.GRAY) + pic.draw_text_right(25, "https://github.com/Starlwr/StarBot", Color.LINK) + pic.crop_and_paste_bottom() + + await app.send_message(sender, MessageChain(Image(base64=pic.base64()))) diff --git a/starbot/commands/builtin/ranking/ranking.py b/starbot/commands/builtin/ranking/ranking.py new file mode 100644 index 0000000..e9137c2 --- /dev/null +++ b/starbot/commands/builtin/ranking/ranking.py @@ -0,0 +1,129 @@ +import math +import time +from typing import Union + +from graia.ariadne import Ariadne +from graia.ariadne.event.message import FriendMessage, GroupMessage +from graia.ariadne.message.chain import MessageChain +from graia.ariadne.message.element import Source, Image +from graia.ariadne.message.parser.twilight import Twilight, FullMatch, UnionMatch, ParamMatch, RegexResult, ResultValue +from graia.ariadne.model import Friend, Group +from graia.saya import Channel +from graia.saya.builtins.broadcast import ListenerSchema + +from ....core.datasource import DataSource +from ....core.model import PushType +from ....painter.PicGenerator import PicGenerator, Color +from ....painter.RankingGenerator import RankingGenerator +from ....utils import config, redis +from ....utils.utils import remove_command_param_placeholder, get_unames_and_faces_by_uids, timestamp_format + +prefix = config.get("COMMAND_PREFIX") + +type_map = { + "弹幕": (redis.len_user_danmu_count, redis.rev_range_user_danmu_count, "弹幕", "弹幕"), + "弹幕总": (redis.len_user_danmu_all, redis.rev_range_user_danmu_all, "弹幕", "弹幕总"), + "盲盒": (redis.len_user_box_count, redis.rev_range_user_box_count, "盲盒", "盲盒"), + "宝盒": (redis.len_user_box_count, redis.rev_range_user_box_count, "盲盒", "盲盒"), + "盲盒总": (redis.len_user_box_all, redis.rev_range_user_box_all, "盲盒", "盲盒总"), + "宝盒总": (redis.len_user_box_all, redis.rev_range_user_box_all, "盲盒", "盲盒总"), + "礼物": (redis.len_user_gift_profit, redis.rev_range_user_gift_profit, "礼物", "礼物"), + "礼物总": (redis.len_user_gift_all, redis.rev_range_user_gift_all, "礼物", "礼物总"), + "SC": (redis.len_user_sc_profit, redis.rev_range_user_sc_profit, "SC", "SC"), + "sc": (redis.len_user_sc_profit, redis.rev_range_user_sc_profit, "SC", "SC"), + "醒目留言": (redis.len_user_sc_profit, redis.rev_range_user_sc_profit, "SC", "SC"), + "SC总": (redis.len_user_sc_all, redis.rev_range_user_sc_all, "SC", "SC总"), + "sc总": (redis.len_user_sc_all, redis.rev_range_user_sc_all, "SC", "SC总"), + "醒目留言总": (redis.len_user_sc_all, redis.rev_range_user_sc_all, "SC", "SC总") +} + +channel = Channel.current() + + +@channel.use( + ListenerSchema( + listening_events=[FriendMessage, GroupMessage], + inline_dispatchers=[Twilight( + FullMatch(prefix), + "_type" @ ParamMatch(), + UnionMatch("榜", "排行", "排行榜"), + "page" @ ParamMatch(optional=True) + )], + ) +) +async def ranking(app: Ariadne, + source: Source, + sender: Union[Friend, Group], + page: RegexResult, + _type: MessageChain = ResultValue()): + _type = _type.display + if _type not in type_map: + return + + if page.matched: + page = remove_command_param_placeholder(page.result.display) + if not page.isdigit() or int(page) <= 0: + await app.send_message(sender, MessageChain("请输入正确的页码~"), quote=source) + return + page = int(page) + else: + page = 1 + + size = 10 + start = size * (page - 1) + end = start + size - 1 + + datasource: DataSource = app.options["StarBotDataSource"] + ups = datasource.get_ups_by_target(sender.id, PushType.Group if isinstance(sender, Group) else PushType.Friend) + + if not ups: + return + + for up in ups: + length = await type_map[_type][0](up.room_id) + page_length = math.ceil(length / size) + + if length == 0: + await app.send_message(sender, MessageChain(f"{up.uname} 的房间暂无{type_map[_type][2]}数据~"), quote=source) + return + + if page > page_length: + await app.send_message( + sender, + MessageChain(f"{up.uname} 的房间{type_map[_type][3]}榜页码范围为 1 ~ {page_length}\n请重新输入正确的页码~"), + quote=source + ) + return + + data = await type_map[_type][1](up.room_id, start, end) + top_count = (await type_map[_type][1](up.room_id, 0, 0))[0][1] + + uids = [x[0] for x in data] + counts = [x[1] for x in data] + unames, faces = await get_unames_and_faces_by_uids(uids) + + width = 1000 + height = 100000 + margin = 50 + pic = PicGenerator(width, height) + pic.set_pos(margin, margin).draw_rounded_rectangle(0, 0, width, height, 35, Color.WHITE).copy_bottom(35) + + pic.draw_section(f"{up.uname} 房间的{type_map[_type][3]}排行") + pic.draw_text(f"第 {start + 1} 名 ~ 第 {start + len(uids)} 名 ( 第 {page} 页 / 共 {page_length} 页 )") + pic.draw_tip(f"UID: {up.uid} 房间号: {up.room_id}") + pic.draw_tip(f"查询时间: {timestamp_format(int(time.time()), '%Y/%m/%d %H:%M:%S')}") + if page != page_length: + pic.draw_tip(f"继续查看下一页请发送 \"{prefix}{type_map[_type][3]}榜 {page + 1}\"") + pic.draw_text("") + + pic.draw_img_alpha( + RankingGenerator.get_ranking(pic.row_space, faces, unames, counts, pic.width - (margin * 2), top_count) + ) + + # 底部版权信息,请务必保留此处 + pic.draw_text("") + pic.draw_text_right(25, "Designed By StarBot", Color.GRAY) + pic.draw_text_right(25, "https://github.com/Starlwr/StarBot", Color.LINK) + pic.crop_and_paste_bottom() + + await app.send_message(sender, MessageChain(Image(base64=pic.base64()))) diff --git a/starbot/commands/builtin/ranking/ranking_double.py b/starbot/commands/builtin/ranking/ranking_double.py new file mode 100644 index 0000000..b52aa05 --- /dev/null +++ b/starbot/commands/builtin/ranking/ranking_double.py @@ -0,0 +1,124 @@ +import math +import time +from typing import Union + +from graia.ariadne import Ariadne +from graia.ariadne.event.message import FriendMessage, GroupMessage +from graia.ariadne.message.chain import MessageChain +from graia.ariadne.message.element import Source, Image +from graia.ariadne.message.parser.twilight import Twilight, FullMatch, UnionMatch, ParamMatch, RegexResult, ResultValue +from graia.ariadne.model import Friend, Group +from graia.saya import Channel +from graia.saya.builtins.broadcast import ListenerSchema + +from ....core.datasource import DataSource +from ....core.model import PushType +from ....painter.PicGenerator import PicGenerator, Color +from ....painter.RankingGenerator import RankingGenerator +from ....utils import config, redis +from ....utils.utils import remove_command_param_placeholder, get_unames_and_faces_by_uids, timestamp_format + +prefix = config.get("COMMAND_PREFIX") + +type_map = { + "盲盒盈亏": (redis.len_user_box_count, redis.rev_range_user_box_profit, "盲盒", "盲盒盈亏"), + "宝盒盈亏": (redis.len_user_box_count, redis.rev_range_user_box_profit, "盲盒", "盲盒盈亏"), + "盲盒盈亏总": (redis.len_user_box_all, redis.rev_range_user_box_profit_all, "盲盒", "盲盒盈亏总"), + "宝盒盈亏总": (redis.len_user_box_all, redis.rev_range_user_box_profit_all, "盲盒", "盲盒盈亏总") +} + +channel = Channel.current() + + +@channel.use( + ListenerSchema( + listening_events=[FriendMessage, GroupMessage], + inline_dispatchers=[Twilight( + FullMatch(prefix), + "_type" @ ParamMatch(), + UnionMatch("榜", "排行", "排行榜"), + "page" @ ParamMatch(optional=True) + )], + ) +) +async def ranking_double(app: Ariadne, + source: Source, + sender: Union[Friend, Group], + page: RegexResult, + _type: MessageChain = ResultValue()): + _type = _type.display + if _type not in type_map: + return + + if page.matched: + page = remove_command_param_placeholder(page.result.display) + if not page.isdigit() or int(page) <= 0: + await app.send_message(sender, MessageChain("请输入正确的页码~"), quote=source) + return + page = int(page) + else: + page = 1 + + size = 10 + start = size * (page - 1) + end = start + size - 1 + + datasource: DataSource = app.options["StarBotDataSource"] + ups = datasource.get_ups_by_target(sender.id, PushType.Group if isinstance(sender, Group) else PushType.Friend) + + if not ups: + return + + for up in ups: + length = await type_map[_type][0](up.room_id) + page_length = math.ceil(length / size) + + if length == 0: + await app.send_message(sender, MessageChain(f"{up.uname} 的房间暂无{type_map[_type][2]}数据~"), quote=source) + return + + if page > page_length: + await app.send_message( + sender, + MessageChain(f"{up.uname} 的房间{type_map[_type][3]}榜页码范围为 1 ~ {page_length}\n请重新输入正确的页码~"), + quote=source + ) + return + + data = await type_map[_type][1](up.room_id, start, end) + top_count = max( + (await type_map[_type][1](up.room_id, 0, 0))[0][1], + abs((await type_map[_type][1](up.room_id, -1, -1))[0][1]) + ) + + uids = [x[0] for x in data] + counts = [x[1] for x in data] + unames, faces = await get_unames_and_faces_by_uids(uids) + + width = 1000 + height = 100000 + margin = 50 + pic = PicGenerator(width, height) + pic.set_pos(margin, margin).draw_rounded_rectangle(0, 0, width, height, 35, Color.WHITE).copy_bottom(35) + + pic.draw_section(f"{up.uname} 房间的{type_map[_type][3]}排行") + pic.draw_text(f"第 {start + 1} 名 ~ 第 {start + len(uids)} 名 ( 第 {page} 页 / 共 {page_length} 页 )") + pic.draw_tip(f"UID: {up.uid} 房间号: {up.room_id}") + pic.draw_tip(f"查询时间: {timestamp_format(int(time.time()), '%Y/%m/%d %H:%M:%S')}") + if page != page_length: + pic.draw_tip(f"继续查看下一页请发送 \"{prefix}{type_map[_type][3]}榜 {page + 1}\"") + pic.draw_text("") + + pic.draw_img_alpha( + RankingGenerator.get_double_ranking( + pic.row_space, faces, unames, counts, pic.width - (margin * 2), top_count + ) + ) + + # 底部版权信息,请务必保留此处 + pic.draw_text("") + pic.draw_text_right(25, "Designed By StarBot", Color.GRAY) + pic.draw_text_right(25, "https://github.com/Starlwr/StarBot", Color.LINK) + pic.crop_and_paste_bottom() + + await app.send_message(sender, MessageChain(Image(base64=pic.base64()))) diff --git a/starbot/painter/RankingGenerator.py b/starbot/painter/RankingGenerator.py index 72b2cb8..1a39c9f 100644 --- a/starbot/painter/RankingGenerator.py +++ b/starbot/painter/RankingGenerator.py @@ -1,4 +1,4 @@ -from typing import Union, Tuple, List +from typing import Optional, Union, Tuple, List from PIL import Image, ImageDraw @@ -69,6 +69,7 @@ class RankingGenerator: unames: List[str], counts: Union[List[int], List[float]], width: int, + top_count: Optional[Union[int, float]] = None, start_color: Union[Color, Tuple[int, int, int]] = Color.DEEPBLUE, end_color: Union[Color, Tuple[int, int, int]] = Color.LIGHTBLUE) -> Image: """ @@ -80,6 +81,7 @@ class RankingGenerator: unames: 昵称列表,按照数量列表降序排序 counts: 数量列表,降序排序 width: 排行榜图片宽度 + top_count: 第一名数量,后续排行条长度会基于此数量计算长度。默认:自动取数量列表中第一名 start_color: 排行条渐变起始颜色。默认:深蓝色 (57, 119, 230) end_color: 排行条渐变终止颜色。默认:浅蓝色 (55, 187, 248) """ @@ -93,7 +95,8 @@ class RankingGenerator: bar_x = face_size - offset top_bar_width = width - face_size + offset - top_count = counts[0] + if top_count is None: + top_count = counts[0] chart = PicGenerator(width, (face_size * count) + (row_space * (count - 1))) chart.set_row_space(row_space) @@ -116,6 +119,7 @@ class RankingGenerator: unames: List[str], counts: Union[List[int], List[float]], width: int, + top_count: Optional[Union[int, float]] = None, start_color: Union[Color, Tuple[int, int, int]] = Color.DEEPRED, end_color: Union[Color, Tuple[int, int, int]] = Color.LIGHTRED, reverse_start_color: Union[Color, Tuple[int, int, int]] = Color.DEEPGREEN, @@ -129,6 +133,7 @@ class RankingGenerator: unames: 昵称列表,按照数量列表降序排序 counts: 数量列表,降序排序 width: 排行榜图片宽度 + top_count: 第一名数量,后续排行条长度会基于此数量计算长度。默认:自动取数量列表中第一名 start_color: 正向排行条渐变起始颜色,数量为正时使用。默认:深红色 (57, 119, 230) end_color: 正向排行条渐变终止颜色,数量为正时使用。默认:浅红色 (55, 187, 248) reverse_start_color: 反向排行条渐变起始颜色,数量为负时使用。默认:深绿色 (57, 119, 230) @@ -146,7 +151,8 @@ class RankingGenerator: bar_x = face_x + face_size - offset reverse_bar_x = face_x + offset top_bar_width = (width - face_size) / 2 + offset - top_count = max(max(counts), abs(min(counts))) + if top_count is None: + top_count = max(max(counts), abs(min(counts))) chart = PicGenerator(width, (face_size * count) + (row_space * (count - 1))) chart.set_row_space(row_space) diff --git a/starbot/utils/redis.py b/starbot/utils/redis.py index b3f0932..1d1a7c2 100644 --- a/starbot/utils/redis.py +++ b/starbot/utils/redis.py @@ -333,6 +333,13 @@ async def range_user_danmu_all(room_id: int, start: int = 0, end: int = -1) -> L return result +async def rev_range_user_danmu_all(room_id: int, start: int = 0, end: int = -1) -> List[Tuple[str, int]]: + await zunionstore(f"TempDanmuTotal:{room_id}", [f"UserDanmuCount:{room_id}", f"UserDanmuTotal:{room_id}"]) + result = await zrevrangewithscoresi(f"TempDanmuTotal:{room_id}", start, end) + await delete(f"TempDanmuTotal:{room_id}") + return result + + # 房间弹幕记录 async def get_room_danmu(room_id: int) -> List[str]: @@ -447,6 +454,13 @@ async def range_user_box_all(room_id: int, start: int = 0, end: int = -1) -> Lis return result +async def rev_range_user_box_all(room_id: int, start: int = 0, end: int = -1) -> List[Tuple[str, int]]: + await zunionstore(f"TempBoxTotal:{room_id}", [f"UserBoxCount:{room_id}", f"UserBoxTotal:{room_id}"]) + result = await zrevrangewithscoresi(f"TempBoxTotal:{room_id}", start, end) + await delete(f"TempBoxTotal:{room_id}") + return result + + # 房间盲盒盈亏 async def get_room_box_profit(room_id: int) -> float: @@ -524,6 +538,13 @@ async def range_user_box_profit_all(room_id: int, start: int = 0, end: int = -1) return result +async def rev_range_user_box_profit_all(room_id: int, start: int = 0, end: int = -1) -> List[Tuple[str, float]]: + await zunionstore(f"TempBoxProfitTotal:{room_id}", [f"UserBoxProfit:{room_id}", f"UserBoxProfitTotal:{room_id}"]) + result = await zrevrangewithscoresf1(f"TempBoxProfitTotal:{room_id}", start, end) + await delete(f"TempBoxProfitTotal:{room_id}") + return result + + # 房间盲盒盈亏记录,用于绘制直播报告中盲盒盈亏曲线图 async def get_room_box_profit_record(room_id: int) -> List[float]: @@ -654,6 +675,13 @@ async def range_user_gift_all(room_id: int, start: int = 0, end: int = -1) -> Li return result +async def rev_range_user_gift_all(room_id: int, start: int = 0, end: int = -1) -> List[Tuple[str, float]]: + await zunionstore(f"TempGiftTotal:{room_id}", [f"UserGiftProfit:{room_id}", f"UserGiftTotal:{room_id}"]) + result = await zrevrangewithscoresf1(f"TempGiftTotal:{room_id}", start, end) + await delete(f"TempGiftTotal:{room_id}") + return result + + # 房间礼物时间分布 async def get_room_gift_time(room_id: int) -> List[Tuple[str, float]]: @@ -754,6 +782,13 @@ async def range_user_sc_all(room_id: int, start: int = 0, end: int = -1) -> List return result +async def rev_range_user_sc_all(room_id: int, start: int = 0, end: int = -1) -> List[Tuple[str, int]]: + await zunionstore(f"TempScTotal:{room_id}", [f"UserScProfit:{room_id}", f"UserScTotal:{room_id}"]) + result = await zrevrangewithscoresi(f"TempScTotal:{room_id}", start, end) + await delete(f"TempScTotal:{room_id}") + return result + + # 房间 SC 时间分布 async def get_room_sc_time(room_id: int) -> List[Tuple[str, int]]: