async def handle_admin_mail_bind(bot: Bot, event: GroupMessageEvent, state: T_State): mailbox_list = state['mailbox_list'] email_address = state['email_address'] if email_address not in mailbox_list: logger.warning( f'Group:{event.group_id}/User:{event.user_id} 绑定邮箱: {email_address} 失败, 不在可绑定邮箱中的邮箱' ) await admin_mail_bind.finish('该邮箱不在可绑定邮箱中!') group_id = event.group_id res = DBGroup(group_id=group_id).mailbox_add(mailbox=DBEmailBox( address=email_address)) if res.success(): logger.info( f'Group:{event.group_id}/User:{event.user_id} 绑定邮箱: {email_address} 成功' ) await admin_mail_bind.finish('Success! 绑定成功') else: logger.error( f'Group:{event.group_id}/User:{event.user_id} 绑定邮箱: {email_address} 失败, error: {res.info}' ) await admin_mail_bind.finish('绑定邮箱失败QAQ, 请检联系管理员处理')
async def get_result(__url: str, paras: dict) -> dict: timeout_count = 0 while timeout_count < 3: try: timeout = aiohttp.ClientTimeout(total=10) async with aiohttp.ClientSession(timeout=timeout) as __session: headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36' } async with __session.get(url=__url, params=paras, headers=headers, timeout=timeout) as resp: json = await resp.json() return json except Exception as e: error_info = f'{repr(e)} Occurred in get_result trying {timeout_count + 1} using paras: {paras}' logger.info(error_info) finally: timeout_count += 1 else: error_info = f'Failed too many times in get_result using paras: {paras}' logger.warning(error_info) return {'header': {'status': 1}, 'results': []}
async def fetch_new_post( self, _: Target, users: list[User]) -> list[tuple[User, list[Post]]]: try: config = Config() post_list = await self.get_sub_list() new_posts = await self.filter_common(post_list) res: list[tuple[User, list[Post]]] = [] if not new_posts: return [] else: for post in new_posts: logger.info('fetch new post from {}: {}'.format( self.platform_name, self.get_id(post))) for user in users: required_tags = config.get_sub_tags( self.platform_name, 'default', user.user_type, user.user) if self.enable_tag else [] cats = config.get_sub_category(self.platform_name, 'default', user.user_type, user.user) user_raw_post = await self.filter_user_custom( new_posts, cats, required_tags) user_post: list[Post] = [] for raw_post in user_raw_post: user_post.append(await self._parse_with_cache(raw_post)) res.append((user, user_post)) self.cache = {} return res except httpx.RequestError as err: logger.warning("network connection error: {}, url: {}".format( type(err), err.request.url)) return []
async def get_ascii2d_redirects(_url: str) -> dict: timeout_count = 0 while timeout_count < 3: try: timeout = aiohttp.ClientTimeout(total=10) async with aiohttp.ClientSession(timeout=timeout) as __session: headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36', 'accept-language': 'zh-CN,zh;q=0.9' } async with __session.get(url=_url, headers=headers, timeout=timeout, allow_redirects=False) as resp: res_headers = resp.headers res_dict = {'error': False, 'body': dict(res_headers)} return res_dict except Exception as e: error_info = f'{repr(e)} Occurred in get_ascii2d_redirects trying {timeout_count + 1} using url: {_url}' logger.info(error_info) finally: timeout_count += 1 else: error_info = f'Failed too many times in get_result using url: {_url}' logger.warning(error_info) return {'error': True, 'body': None}
async def get_ascii2d_result(__url: str) -> str: timeout_count = 0 while timeout_count < 3: try: timeout = aiohttp.ClientTimeout(total=10) async with aiohttp.ClientSession(timeout=timeout) as __session: headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/83.0.4103.116 Safari/537.36', 'accept-language': 'zh-CN,zh;q=0.9' } async with __session.get(url=__url, headers=headers, timeout=timeout) as resp: res_headers = await resp.text() return res_headers except Exception as e: error_info = f'{repr(e)} Occurred in get_ascii2d_result trying {timeout_count + 1} using url: {__url}' logger.info(error_info) finally: timeout_count += 1 else: error_info = f'Failed too many times in get_result using url: {__url}' logger.warning(error_info) return ''
async def handle_announce(bot: Bot, event: Event, state: T_State): group = state['group'] msg = state['announce_text'] if group == 'all': t = DBTable(table_name='Group') for item in t.list_col('group_id').result: group_id = item[0] await bot.call_api(api='send_group_msg', group_id=group_id, message=msg) elif group == 'notice': t = DBTable(table_name='Group') for item in t.list_col_with_condition('group_id', 'notice_permissions', 1).result: group_id = item[0] await bot.call_api(api='send_group_msg', group_id=group_id, message=msg) elif group == 'command': t = DBTable(table_name='Group') for item in t.list_col_with_condition('group_id', 'command_permissions', 1).result: group_id = item[0] await bot.call_api(api='send_group_msg', group_id=group_id, message=msg) elif re.match(r'^\d+$', group): group_id = int(group) await bot.call_api(api='send_group_msg', group_id=group_id, message=msg) else: logger.warning(f'公告未发送, 不合规的群组类型或群号: {group}') await announce.finish('不合规的群组类型或群号') logger.warning(f'公告已成功发送群组: {group}') await announce.finish('公告发送完成')
async def get_image(pic_url: str): timeout_count = 0 while timeout_count < 3: try: timeout = aiohttp.ClientTimeout(total=10) async with aiohttp.ClientSession(timeout=timeout) as session: headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36' } async with session.get(url=pic_url, headers=headers, timeout=timeout) as resp: _res = await resp.read() return _res except Exception as _e: error_info = f'{repr(_e)} Occurred in get_image trying {timeout_count + 1} using paras: {pic_url}' logger.info(error_info) finally: timeout_count += 1 else: error_info = f'Failed too many times in get_image using paras: {pic_url}' logger.warning(error_info) return None
async def delete_msg(msg_ids: list): bot = nonebot.get_bot() for msg_id in msg_ids: try: await bot.call_action("delete_msg", message_id=msg_id["message_id"]) except Exception as e: logger.warning("下载进度消息撤回失败!", e)
async def handle_admin_mail_add(bot: Bot, event: MessageEvent, state: T_State): address = state['address'] server_host = state['server_host'] password = state['password'] check_result = await check_mailbox(address=address, server_host=server_host, password=password) if not check_result.success(): logger.warning( f'{event.user_id} 添加邮箱: {address} 失败, 邮箱验证不通过, error: {check_result.info}' ) await admin_mail_add.finish('验证邮箱失败了QAQ, 请检查邮箱信息或稍后再试') # 对密码加密保存 password = encrypt_password(plaintext=password) add_result = DBEmailBox(address=address).add(server_host=server_host, password=password) if add_result.success(): logger.info(f'{event.user_id} 添加邮箱: {address} 成功') await admin_mail_add.finish('Success! 邮箱添加成功') else: logger.error( f'{event.user_id} 添加邮箱: {address} 失败, 数据库写入失败, error: {add_result.info}' ) await admin_mail_add.finish('邮箱添加失败QAQ, 请检联系管理员处理')
async def handle_moepic(bot: Bot, event: GroupMessageEvent, state: T_State): tags = state['tags'] if tags: _res_list = list() for tag in tags: _res = DBPixivillust.list_illust(nsfw_tag=0, keyword=tag) if _res.success(): _pids = set(_res.result) _res_list.append(_pids) if len(_res_list) > 1: # 处理tag交集, 同时满足所有tag for item in _res_list[1:]: _res_list[0].intersection_update(item) pid_list = _res_list[0] elif len(_res_list) == 1: pid_list = _res_list[0] else: pid_list = _res_list else: # 没有tag则随机获取 pid_list = DBPixivillust.rand_illust(num=3, nsfw_tag=0) if not pid_list: logger.info( f"Group: {event.group_id}, User: {event.user_id} 没有找到他/她想要的萌图") await moepic.finish('找不到萌图QAQ') elif len(pid_list) > 3: pid_list = random.sample(pid_list, k=3) await moepic.send('稍等, 正在下载图片~') # 处理article中图片内容 tasks = [] for pid in pid_list: tasks.append(fetch_illust_b64(pid=pid)) p_res = await asyncio.gather(*tasks) fault_count = 0 for image_res in p_res: try: if not image_res.success(): fault_count += 1 logger.warning(f'图片下载失败, error: {image_res.info}') continue else: img_seg = MessageSegment.image(image_res.result) # 发送图片 await moepic.send(img_seg) except Exception as e: logger.warning( f"图片发送失败, group: {event.group_id}. error: {repr(e)}") continue if fault_count == len(pid_list): logger.info( f"Group: {event.group_id}, User: {event.user_id} 没能看到他/她想要的萌图") await moepic.finish('似乎出现了网络问题, 所有的图片都下载失败了QAQ') else: logger.info( f"Group: {event.group_id}, User: {event.user_id} 找到了他/她想要的萌图")
async def handle_draw(bot: Bot, event: GroupMessageEvent, state: T_State): image_url = state['image_url'] if not re.match(r'^(\[CQ:image,file=[abcdef\d]{32}\.image,url=.+])', image_url): await search_image.reject('你发送的似乎不是图片呢, 请重新发送, 取消命令请发送【取消】:') # 提取图片url image_url = re.sub(r'^(\[CQ:image,file=[abcdef\d]{32}\.image,url=)', '', image_url) image_url = re.sub(r'(])$', '', image_url) try: await search_image.send('获取识别结果中, 请稍后~') identify_result = await get_identify_result(url=image_url) # saucenao 没有结果时再使用 ascii2d 进行搜索 if not identify_result: identify_ascii2d_result = await get_ascii2d_identify_result( url=image_url) # 合并搜索结果 identify_result.extend(identify_ascii2d_result) if identify_result: for item in identify_result: try: if type(item['ext_urls']) == list: ext_urls = '' for urls in item['ext_urls']: ext_urls += f'{urls}\n' ext_urls = ext_urls.strip() else: ext_urls = item['ext_urls'] ext_urls = ext_urls.strip() img_b64 = await pic_2_base64(item['thumbnail']) if not img_b64.success(): msg = f"识别结果: {item['index_name']}\n\n相似度: {item['similarity']}\n资源链接: {ext_urls}" await search_image.send(msg) else: img_seg = MessageSegment.image(img_b64.result) msg = f"识别结果: {item['index_name']}\n\n相似度: {item['similarity']}\n资源链接: {ext_urls}\n{img_seg}" await search_image.send(Message(msg)) except Exception as e: logger.warning(f'处理和发送识别结果时发生了错误: {repr(e)}') continue logger.info(f"Group: {event.group_id}, user: {event.user_id} " f"使用searchimage成功搜索了一张图片") return else: await search_image.send('没有找到相似度足够高的图片QAQ') logger.info(f"Group: {event.group_id}, user: {event.user_id} " f"使用了searchimage, 但没有找到相似的图片") return except Exception as e: await search_image.send('识图失败, 发生了意外的错误QAQ') logger.error(f"Group: {event.group_id}, user: {event.user_id} " f"使用命令searchimage时发生了错误: {repr(e)}") return
async def group_upgrade(bot: Bot, event: GroupMessageEvent, state: T_State) -> Result: group_id = event.group_id # 调用api获取群信息 group_info = await bot.call_api(api='get_group_info', group_id=group_id) group_name = group_info['group_name'] group = DBGroup(group_id=group_id) # 添加并初始化群信息 _result = group.add(name=group_name) if not _result.success(): return Result(True, _result.info, -1) # 更新用户 group_member_list = await bot.call_api(api='get_group_member_list', group_id=group_id) failed_user = [] # 首先清除数据库中退群成员 exist_member_list = [] for user_info in group_member_list: user_qq = user_info['user_id'] exist_member_list.append(int(user_qq)) db_member_list = [] for user_id, nickname in group.member_list().result: db_member_list.append(user_id) del_member_list = list(set(db_member_list).difference(set(exist_member_list))) for user_id in del_member_list: group.member_del(user=DBUser(user_id=user_id)) # 更新群成员 for user_info in group_member_list: # 用户信息 user_qq = user_info['user_id'] user_nickname = user_info['nickname'] user_group_nickmane = user_info['card'] if not user_group_nickmane: user_group_nickmane = user_nickname _user = DBUser(user_id=user_qq) _result = _user.add(nickname=user_nickname) if not _result.success(): failed_user.append(_user.qq) logger.warning(f'User: {user_qq}, {_result.info}') continue _result = group.member_add(user=_user, user_group_nickname=user_group_nickmane) if not _result.success(): failed_user.append(_user.qq) logger.warning(f'User: {user_qq}, {_result.info}') group.init_member_status() return Result(False, f'Success with ignore user: {failed_user}', 0)
def update(self): importlib.reload(_pcr_data) self._roster.clear() for idx, names in _pcr_data.CHARA_NAME.items(): for n in names: n = util.normalize_str(n) if n not in self._roster: self._roster[n] = idx else: logger.warning( f'priconne.chara.Roster: 出现重名{n}于id{idx}与id{self._roster[n]}' ) self._all_name_list = self._roster.keys()
async def refresh_group_info(): from nonebot import get_bots for bot_id, bot in get_bots().items(): group_list = await bot.call_api('get_group_list') for group in group_list: group_id = group.get('group_id') # 调用api获取群信息 group_info = await bot.call_api(api='get_group_info', group_id=group_id) group_name = group_info['group_name'] group = DBGroup(group_id=group_id) # 添加并初始化群信息 group.add(name=group_name) # 更新用户 group_member_list = await bot.call_api(api='get_group_member_list', group_id=group_id) # 首先清除数据库中退群成员 exist_member_list = [] for user_info in group_member_list: user_qq = user_info['user_id'] exist_member_list.append(int(user_qq)) db_member_list = [] for user_id, nickname in group.member_list().result: db_member_list.append(user_id) del_member_list = list(set(db_member_list).difference(set(exist_member_list))) for user_id in del_member_list: group.member_del(user=DBUser(user_id=user_id)) # 更新群成员 for user_info in group_member_list: # 用户信息 user_qq = user_info['user_id'] user_nickname = user_info['nickname'] user_group_nickmane = user_info['card'] if not user_group_nickmane: user_group_nickmane = user_nickname _user = DBUser(user_id=user_qq) _result = _user.add(nickname=user_nickname) if not _result.success(): logger.warning(f'Refresh group info, User: {user_qq}, {_result.info}') continue _result = group.member_add(user=_user, user_group_nickname=user_group_nickmane) if not _result.success(): logger.warning(f'Refresh group info, User: {user_qq}, {_result.info}') group.init_member_status() logger.info(f'Refresh group info completed, Bot: {bot_id}, Group: {group_id}')
async def group_init(bot: Bot, event: GroupMessageEvent, state: T_State) -> Result: group_id = event.group_id # 调用api获取群信息 group_info = await bot.call_api(api='get_group_info', group_id=group_id) group_name = group_info['group_name'] group = DBGroup(group_id=group_id) # 添加并初始化群信息 _result = group.add(name=group_name) if not _result.success(): return Result(True, _result.info, -1) _result = group.permission_set(notice=1, command=1, level=10) if not _result.success(): return Result(True, _result.info, -1) _result = group.member_clear() if not _result.success(): return Result(True, _result.info, -1) # 添加用户 group_member_list = await bot.call_api(api='get_group_member_list', group_id=group_id) failed_user = [] for user_info in group_member_list: # 用户信息 user_qq = user_info['user_id'] user_nickname = user_info['nickname'] user_group_nickmane = user_info['card'] if not user_group_nickmane: user_group_nickmane = user_nickname _user = DBUser(user_id=user_qq) _result = _user.add(nickname=user_nickname) if not _result.success(): failed_user.append(_user.qq) logger.warning(f'User: {user_qq}, {_result.info}') continue _result = group.member_add(user=_user, user_group_nickname=user_group_nickmane) if not _result.success(): failed_user.append(_user.qq) logger.warning(f'User: {user_qq}, {_result.info}') group.init_member_status() return Result(False, f'Success with ignore user: {failed_user}', 0)
async def check_down_status(hash_str: str, group_ids: list, name: str): qb = await get_qb_client() if not qb: return info = qb.get_torrent(hash_str) files = qb.get_torrent_files(hash_str) bot = nonebot.get_bot() if info["total_downloaded"] - info["total_size"] >= 0.000000: all_time = (datetime.datetime.now() - down_info[hash_str]["start_time"]).seconds await send_msg(f"👏 {name}\nHash: {hash_str} \n下载完成!耗时:{all_time} s") down_info[hash_str]["status"] = DOWN_STATUS_UPLOADING for group_id in group_ids: for tmp in files: # 异常包起来防止超时报错导致后续不执行 try: if config.qb_down_path and len(config.qb_down_path) > 0: path = config.qb_down_path + tmp["name"] else: path = info["save_path"] + tmp["name"] await send_msg(f"{name}\nHash: {hash_str} \n开始上传到群:{group_id}") try: await bot.call_action( action="upload_group_file", group_id=group_id, file=path, name=tmp["name"], ) except Exception as e: await send_msg( f"{name}\nHash: {hash_str} \n上传到群:{group_id}失败!请手动上传!" ) logger.error(e) except TimeoutError as e: logger.warning(e) scheduler.remove_job(hash_str) down_info[hash_str]["status"] = DOWN_STATUS_UPLOAD_OK else: await delete_msg(down_info[hash_str]["downing_tips_msg_id"]) msg_id = await send_msg( f"{name}\n" f"Hash: {hash_str} \n" f"下载了 {round(info['total_downloaded'] / info['total_size'] * 100, 2)}%\n" f"平均下载速度:{round(info['dl_speed_avg'] / 1024, 2)} KB/s" ) down_info[hash_str]["downing_tips_msg_id"] = msg_id
async def get_identify_result(img_url: str) -> Result: payload = {'url': img_url} result_json = await fetch_json(url=API_URL, paras=payload) if not result_json.success(): return result_json _res = result_json.result if not _res.get('docs'): return Result(error=True, info='no result found', result=[]) _result = [] for item in _res.get('docs'): try: if item.get('similarity') < 0.80: continue _result.append({ 'raw_at': item.get('at'), 'at': str(datetime.timedelta(seconds=item.get('at'))), 'anilist_id': item.get('anilist_id'), 'anime': item.get('anime'), 'episode': item.get('episode'), 'tokenthumb': item.get('tokenthumb'), 'filename': item.get('filename'), 'similarity': item.get('similarity'), 'title_native': item.get('title_native'), 'title_chinese': item.get('title_chinese'), 'is_adult': item.get('is_adult'), }) except Exception as e: logger.warning(f'result parse failed: {repr(e)}, raw_json: {item}') continue return Result(error=False, info='Success', result=_result)
async def fetch_and_send(target_type: str): config = Config() target = config.get_next_target(target_type) if not target: return logger.debug('try to fecth new posts from {}, target: {}'.format( target_type, target)) send_list = config.target_user_cache[target_type][target] bot_list = list(nonebot.get_bots().values()) bot = bot_list[0] if bot_list else None to_send = await platform_manager[target_type].fetch_new_post( target, send_list) for user, send_list in to_send: for send_post in send_list: logger.debug('send to {}: {}'.format(user, send_post)) if not bot: logger.warning('no bot connected') else: send_msgs(bot, user.user, user.user_type, await send_post.generate_messages())
async def do_send_msgs(): global LAST_SEND_TIME if time.time() - LAST_SEND_TIME < 1.4: return if QUEUE: bot, user, user_type, msg, retry_time = QUEUE.pop(0) try: if user_type == 'group': await bot.call_api('send_group_msg', group_id=user, message=msg) elif user_type == 'private': await bot.call_api('send_private_msg', user_id=user, message=msg) except: if retry_time > 0: QUEUE.insert(0, (bot, user, user_type, msg, retry_time - 1)) else: logger.warning('send msg err {}'.format(msg)) LAST_SEND_TIME = time.time()
def get_image(game_name: str, item_name: str) -> Image.Image: """获取图像,从本地或网络""" # 本地是否存在资源 try: return R.img(f'gacha/{game_name}/{item_name}.png').open().convert( "RGBA") except FileNotFoundError: logger.warning(f'没有在本地找到"{item_name}",将试图从网络获取。') # 检查本地是否存在对应文件夹 game_dir = os.path.join(RES_DIR, game_name) if not os.path.exists(game_dir): os.makedirs(game_dir) # 从卡片信息找到图像url url = [i for i in CONFIG['game_name']['cards'] if i.name == item_name] if not url: raise ValueError(f'找不到{item_name}') url = url[0] # 保存到本地 save_path = os.path.join(game_dir, f'{item_name}.png') download_icon(url, save_path) return Image.open(save_path).convert("RGBA")
async def handle_nhentai(bot: Bot, event: GroupMessageEvent, state: T_State): sub_command = state["sub_command"] sub_arg = state["sub_arg"] if sub_command not in ['search', 'download']: await nhentai.finish('没有这个命令哦QAQ') if sub_command == 'search': _res = await nh_search(tag=sub_arg) if _res.success(): nh_list = list(_res.result.get('body')) msg = '' for item in nh_list: _id = item.get('id') title = item.get('title') msg += f'\nID: {_id} / {title}\n' logger.info(f"Group: {event.group_id}, User: {event.user_id} 搜索成功") await nhentai.finish(f"已为你找到了如下结果: \n{msg}\n{'='*8}\n可通过id下载") else: logger.warning(f"Group: {event.group_id}, User: {event.user_id} 搜索失败, error info: {_res.info}") await nhentai.finish('搜索失败QAQ, 请稍后再试') elif sub_command == 'download': if not re.match(r'^\d+$', sub_arg): logger.warning(f"Group: {event.group_id}, User: {event.user_id} 搜索失败, id错误") await nhentai.finish('失败了QAQ, id应为纯数字') else: await nhentai.send('正在下载资源, 请稍后~') _res = await nh_download(_id=sub_arg) if not _res.success(): logger.warning(f"Group: {event.group_id}, User: {event.user_id} 下载失败, error info: {_res.info}") await nhentai.finish('下载失败QAQ, 请稍后再试') else: password = _res.result.get('password') file = _res.result.get('file') file_abs = os.path.abspath(file) await bot.call_api(api='upload_group_file', group_id=event.group_id, file=file_abs, name=f'{sub_arg}.7z') logger.info(f"Group: {event.group_id}, User: {event.user_id} 下载成功") await nhentai.finish(f'成功, 解压密码: {password}') else: pass
sv = Service('pcr_gacha') jewel_limit = DailyNumberLimiter(6000) tenjo_limit = DailyNumberLimiter(10) JEWEL_EXCEED_NOTICE = f'您今天已经抽过{jewel_limit.max}钻了,欢迎明早5点后再来!' TENJO_EXCEED_NOTICE = f'您今天已经抽过{tenjo_limit.max}张天井券了,欢迎明早5点后再来!' POOL = ('MIX', 'JP', 'TW', 'BL') DEFAULT_POOL = POOL[0] _pool_config_file = os.path.expanduser('~/.hoshino/group_pool_config.json') _group_pool = {} try: with open(_pool_config_file, encoding='utf8') as f: _group_pool = json.load(f) except FileNotFoundError as e: logger.warning( 'group_pool_config.json not found, will create when needed.') _group_pool = defaultdict(lambda: DEFAULT_POOL, _group_pool) def dump_pool_config(): with open(_pool_config_file, 'w', encoding='utf8') as f: json.dump(_group_pool, f, ensure_ascii=False) gacha_10_aliases = ('抽十连', '十连', '十连!', '十连抽', '来个十连', '来发十连', '来次十连', '抽个十连', '抽发十连', '抽次十连', '十连扭蛋', '扭蛋十连', '10连', '10连!', '10连抽', '来个10连', '来发10连', '来次10连', '抽个10连', '抽发10连', '抽次10连', '10连扭蛋', '扭蛋10连', '十連', '十連!', '十連抽', '來個十連', '來發十連', '來次十連', '抽個十連', '抽發十連', '抽次十連', '十連轉蛋', '轉蛋十連', '10連', '10連!', '10連抽', '來個10連', '來發10連', '來次10連', '抽個10連', '抽發10連', '抽次10連', '10連轉蛋', '轉蛋10連') gacha_1_aliases = ('单抽', '单抽!', '来发单抽', '来个单抽', '来次单抽', '扭蛋单抽', '单抽扭蛋', '單抽', '單抽!', '來發單抽', '來個單抽', '來次單抽', '轉蛋單抽', '單抽轉蛋') gacha_300_aliases = ('抽一井', '来一井', '来发井', '抽发井',
async def check_dynamic(dy_uid): # 获取动态并返回动态类型及内容 try: _res = await get_user_dynamic_history(dy_uid=dy_uid) if not _res.success(): logger.error(f'bilibili_dynamic_monitor: 获取动态失败, uid: {dy_uid}, error: {_res.info}') return except Exception as _e: logger.error(f'bilibili_dynamic_monitor: 获取动态失败, uid: {dy_uid}, error: {repr(_e)}') return dynamic_info = dict(_res.result) # 用户所有的动态id _res = get_user_dynamic(user_id=dy_uid) if not _res.success(): logger.error(f'bilibili_dynamic_monitor: 获取用户已有动态失败, uid: {dy_uid}, error: {_res.info}') return user_dy_id_list = list(_res.result) sub = DBSubscription(sub_type=2, sub_id=dy_uid) # 获取订阅了该直播间的所有群 sub_group = sub.sub_group_list().result # 需通知的群 notice_group = list(set(all_noitce_groups) & set(sub_group)) for num in range(len(dynamic_info)): try: # 如果有新的动态 if dynamic_info[num]['id'] not in user_dy_id_list: logger.info(f"用户: {dy_uid}/{dynamic_info[num]['name']} 新动态: {dynamic_info[num]['id']}") # 转发的动态 if dynamic_info[num]['type'] == 1: # 获取原动态信息 origin_dynamic_id = dynamic_info[num]['origin'] _dy_res = await get_dynamic_info(dynamic_id=origin_dynamic_id) if not _dy_res.success(): msg = '{}转发了{}的动态!\n\n“{}”\n{}\n{}\n@{}: {}'.format( dynamic_info[num]['name'], 'Unknown', dynamic_info[num]['content'], dynamic_info[num]['url'], '=' * 16, 'Unknown', '获取原动态失败' ) else: origin_dynamic_info = _dy_res.result # 原动态type=2, 带图片 if origin_dynamic_info['type'] == 2: # 处理图片序列 pic_segs = '' for pic_url in origin_dynamic_info['origin_pics']: _res = await pic_2_base64(pic_url) pic_b64 = _res.result pic_segs += f'{MessageSegment.image(pic_b64)}\n' msg = '{}转发了{}的动态!\n\n“{}”\n{}\n{}\n@{}: {}\n{}'.format( dynamic_info[num]['name'], origin_dynamic_info['name'], dynamic_info[num]['content'], dynamic_info[num]['url'], '=' * 16, origin_dynamic_info['name'], origin_dynamic_info['content'], pic_segs ) # 原动态为其他类型, 无图 else: msg = '{}转发了{}的动态!\n\n“{}”\n{}\n{}\n@{}: {}'.format( dynamic_info[num]['name'], origin_dynamic_info['name'], dynamic_info[num]['content'], dynamic_info[num]['url'], '=' * 16, origin_dynamic_info['name'], origin_dynamic_info['content'] ) for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']}") except Exception as _e: logger.warning(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']} 失败, " f"error: {repr(_e)}") continue # 原创的动态(有图片) elif dynamic_info[num]['type'] == 2: # 处理图片序列 pic_segs = '' for pic_url in dynamic_info[num]['pic_urls']: _res = await pic_2_base64(pic_url) pic_b64 = _res.result pic_segs += f'{MessageSegment.image(pic_b64)}\n' msg = '{}发布了新动态!\n\n“{}”\n{}\n{}'.format( dynamic_info[num]['name'], dynamic_info[num]['content'], dynamic_info[num]['url'], pic_segs) for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']}") except Exception as _e: logger.warning(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']} 失败, " f"error: {repr(_e)}") continue # 原创的动态(无图片) elif dynamic_info[num]['type'] == 4: msg = '{}发布了新动态!\n\n“{}”\n{}'.format( dynamic_info[num]['name'], dynamic_info[num]['content'], dynamic_info[num]['url']) for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']}") except Exception as _e: logger.warning(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']} 失败, " f"error: {repr(_e)}") continue # 视频 elif dynamic_info[num]['type'] == 8: msg = '{}发布了新的视频!\n\n《{}》\n“{}”\n{}'.format( dynamic_info[num]['name'], dynamic_info[num]['origin'], dynamic_info[num]['content'], dynamic_info[num]['url']) for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']}") except Exception as _e: logger.warning(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']} 失败, " f"error: {repr(_e)}") continue # 小视频 elif dynamic_info[num]['type'] == 16: msg = '{}发布了新的小视频动态!\n\n“{}”\n{}'.format( dynamic_info[num]['name'], dynamic_info[num]['content'], dynamic_info[num]['url']) for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']}") except Exception as _e: logger.warning(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']} 失败, " f"error: {repr(_e)}") continue # 番剧 elif dynamic_info[num]['type'] in [32, 512]: msg = '{}发布了新的番剧!\n\n《{}》\n{}'.format( dynamic_info[num]['name'], dynamic_info[num]['origin'], dynamic_info[num]['url']) for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']}") except Exception as _e: logger.warning(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']} 失败, " f"error: {repr(_e)}") continue # 文章 elif dynamic_info[num]['type'] == 64: msg = '{}发布了新的文章!\n\n《{}》\n“{}”\n{}'.format( dynamic_info[num]['name'], dynamic_info[num]['origin'], dynamic_info[num]['content'], dynamic_info[num]['url']) for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']}") except Exception as _e: logger.warning(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']} 失败, " f"error: {repr(_e)}") continue # 音频 elif dynamic_info[num]['type'] == 256: msg = '{}发布了新的音乐!\n\n《{}》\n“{}”\n{}'.format( dynamic_info[num]['name'], dynamic_info[num]['origin'], dynamic_info[num]['content'], dynamic_info[num]['url']) for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']}") except Exception as _e: logger.warning(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']} 失败, " f"error: {repr(_e)}") continue # B站活动相关 elif dynamic_info[num]['type'] == 2048: msg = '{}发布了一条活动相关动态!\n\n【{}】\n“{}”\n{}'.format( dynamic_info[num]['name'], dynamic_info[num]['origin'], dynamic_info[num]['content'], dynamic_info[num]['url']) for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']}") except Exception as _e: logger.warning(f"向群组: {group_id} 发送新动态通知: {dynamic_info[num]['id']} 失败, " f"error: {repr(_e)}") continue elif dynamic_info[num]['type'] == -1: logger.warning(f"未知的动态类型: {dynamic_info[num]['id']}") # 更新动态内容到数据库 dy_id = dynamic_info[num]['id'] dy_type = dynamic_info[num]['type'] content = dynamic_info[num]['content'] # 向数据库中写入动态信息 dynamic = DBDynamic(uid=dy_uid, dynamic_id=dy_id) _res = dynamic.add(dynamic_type=dy_type, content=content) if _res.success(): logger.info(f"向数据库写入动态信息: {dynamic_info[num]['id']} 成功") else: logger.error(f"向数据库写入动态信息: {dynamic_info[num]['id']} 失败") except Exception as _e: logger.error(f'bilibili_dynamic_monitor: 解析新动态: {dy_uid} 的时发生了错误, error info: {repr(_e)}')
async def handle_pixiv(bot: Bot, event: GroupMessageEvent, state: T_State): mode = state['mode'] if mode == '日榜': await pixiv.send('稍等, 正在下载资源~') payload = {'key': API_KEY, 'num': 3, 'mode': 'daily'} _res = await fetch_json(url=RANK_API_URL, paras=payload) rank_data = _res.result if _res.success() and not rank_data.get('error'): error_count = 0 for pid in rank_data.get('body'): logger.debug(f'获取Pixiv资源: {pid}.') # 获取illust _res = await fetch_image(pid=pid) if _res.success(): msg = _res.result.get('msg') img_seg = MessageSegment.image(_res.result.get('b64')) # 发送图片和图片信息 await pixiv.send(Message(img_seg).append(msg)) else: logger.warning( f"User: {event.user_id} 获取Pixiv资源失败, 网络超时或 {pid} 不存在") error_count += 1 else: if error_count == len(rank_data.get('body')): await pixiv.finish('加载失败, 网络超时QAQ') else: logger.warning(f"User: {event.user_id} 获取Pixiv Rank失败, 网络超时") await pixiv.finish('加载失败, 网络超时QAQ') elif mode == '周榜': await pixiv.send('稍等, 正在下载资源~') payload = {'key': API_KEY, 'num': 3, 'mode': 'weekly'} _res = await fetch_json(url=RANK_API_URL, paras=payload) rank_data = _res.result if _res.success() and not rank_data.get('error'): error_count = 0 for pid in rank_data.get('body'): logger.debug(f'获取Pixiv资源: {pid}.') # 获取illust _res = await fetch_image(pid=pid) if _res.success(): msg = _res.result.get('msg') img_seg = MessageSegment.image(_res.result.get('b64')) # 发送图片和图片信息 await pixiv.send(Message(img_seg).append(msg)) else: logger.warning( f"User: {event.user_id} 获取Pixiv资源失败, 网络超时或 {pid} 不存在") error_count += 1 else: if error_count == len(rank_data.get('body')): await pixiv.finish('加载失败, 网络超时QAQ') else: logger.warning(f"User: {event.user_id} 获取Pixiv Rank失败, 网络超时") await pixiv.finish('加载失败, 网络超时QAQ') elif mode == '月榜': await pixiv.send('稍等, 正在下载资源~') payload = {'key': API_KEY, 'num': 3, 'mode': 'monthly'} _res = await fetch_json(url=RANK_API_URL, paras=payload) rank_data = _res.result if _res.success() and not rank_data.get('error'): error_count = 0 for pid in rank_data.get('body'): logger.debug(f'获取Pixiv资源: {pid}.') # 获取illust _res = await fetch_image(pid=pid) if _res.success(): msg = _res.result.get('msg') img_seg = MessageSegment.image(_res.result.get('b64')) # 发送图片和图片信息 await pixiv.send(Message(img_seg).append(msg)) else: logger.warning( f"User: {event.user_id} 获取Pixiv资源失败, 网络超时或 {pid} 不存在") error_count += 1 else: if error_count == len(rank_data.get('body')): await pixiv.finish('加载失败, 网络超时QAQ') else: logger.warning(f"User: {event.user_id} 获取Pixiv Rank失败, 网络超时") await pixiv.send('加载失败, 网络超时QAQ') elif re.match(r'^\d+$', mode): pid = mode logger.debug(f'获取Pixiv资源: {pid}.') await pixiv.send('稍等, 正在下载图片~') # 获取illust _res = await fetch_image(pid=pid) if _res.success(): msg = _res.result.get('msg') img_seg = MessageSegment.image(_res.result.get('b64')) # 发送图片和图片信息 await pixiv.send(Message(img_seg).append(msg)) else: logger.warning( f"User: {event.user_id} 获取Pixiv资源失败, 网络超时或 {pid} 不存在") await pixiv.send('加载失败, 网络超时或没有这张图QAQ') else: await pixiv.reject( '你输入的命令好像不对呢……请输入"月榜"、"周榜"、"日榜"或者PixivID, 取消命令请发送【取消】:')
async def get_ascii2d_identify_result(url: str) -> list: async def get_ascii2d_redirects(_url: str) -> dict: timeout_count = 0 while timeout_count < 3: try: timeout = aiohttp.ClientTimeout(total=10) async with aiohttp.ClientSession(timeout=timeout) as __session: headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36', 'accept-language': 'zh-CN,zh;q=0.9' } async with __session.get(url=_url, headers=headers, timeout=timeout, allow_redirects=False) as resp: res_headers = resp.headers res_dict = {'error': False, 'body': dict(res_headers)} return res_dict except Exception as e: error_info = f'{repr(e)} Occurred in get_ascii2d_redirects trying {timeout_count + 1} using url: {_url}' logger.info(error_info) finally: timeout_count += 1 else: error_info = f'Failed too many times in get_result using url: {_url}' logger.warning(error_info) return {'error': True, 'body': None} async def get_ascii2d_result(__url: str) -> str: timeout_count = 0 while timeout_count < 3: try: timeout = aiohttp.ClientTimeout(total=10) async with aiohttp.ClientSession(timeout=timeout) as __session: headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/83.0.4103.116 Safari/537.36', 'accept-language': 'zh-CN,zh;q=0.9' } async with __session.get(url=__url, headers=headers, timeout=timeout) as resp: res_headers = await resp.text() return res_headers except Exception as e: error_info = f'{repr(e)} Occurred in get_ascii2d_result trying {timeout_count + 1} using url: {__url}' logger.info(error_info) finally: timeout_count += 1 else: error_info = f'Failed too many times in get_result using url: {__url}' logger.warning(error_info) return '' search_url = f'{API_URL_ASCII2D}{url}' __result_json = await get_ascii2d_redirects(_url=search_url) if not __result_json['error']: ascii2d_color_url = __result_json['body']['Location'] ascii2d_bovw_url = re.sub(r'https://ascii2d\.net/search/color/', r'https://ascii2d.net/search/bovw/', ascii2d_color_url) else: logger.error( f'get_ascii2d_identify_result failed: 获取识别结果url发生错误, 错误信息详见日志.') return [] color_res = await get_ascii2d_result(ascii2d_color_url) bovw_res = await get_ascii2d_result(ascii2d_bovw_url) pre_bs_list = [] if color_res: pre_bs_list.append(color_res) if bovw_res: pre_bs_list.append(bovw_res) if not pre_bs_list: logger.error(f'get_ascii2d_identify_result ERROR: 获取识别结果异常, 错误信息详见日志.') return [] __result = [] for result in pre_bs_list: try: gallery_soup = BeautifulSoup(result, 'lxml') # 模式 search_mode = gallery_soup.find('h5', { 'class': 'p-t-1 text-xs-center' }).get_text(strip=True) # 每一个搜索结果 row = gallery_soup.find_all('div', {'class': 'row item-box'}) except Exception as page_err: logger.warning( f'get_ascii2d_identify_result failed: {repr(page_err)}, 解析结果页时发生错误.' ) continue # ascii2d搜索偏差过大,pixiv及twitter结果只取第一个 pixiv_count = 0 twitter_count = 0 for row_item in row: # 对每个搜索结果进行解析 try: detail = row_item.find('div', {'class': 'detail-box gray-link'}) is_null = detail.get_text(strip=True) if not is_null: continue # 来源部分,ascii2d网页css调整大概率导致此处解析失败,调试重点关注 source_type = detail.find('h6').find('small').get_text( strip=True) if source_type == 'pixiv': if pixiv_count > 0: break else: pixiv_count += 1 elif source_type == 'twitter': if twitter_count > 0: break else: twitter_count += 1 else: continue source = detail.find('h6').get_text('/', strip=True) source_url = detail.find('h6').find('a', { 'title': None, 'style': None }).get('href') # 预览图部分,ascii2d网页css调整大概率导致此处解析失败,调试重点关注 preview_img_url = row_item. \ find('div', {'class': 'col-xs-12 col-sm-12 col-md-4 col-xl-4 text-xs-center image-box'}). \ find('img').get('src') __result.append({ 'similarity': 'null', 'thumbnail': f'https://ascii2d.net{preview_img_url}', 'index_name': f'ascii2d - {search_mode} - {source}', 'ext_urls': source_url }) except Exception as row_err: logger.warning( f'get_ascii2d_identify_result ERROR: {repr(row_err)}, 解搜索结果条目时发生错误.' ) continue return __result
async def pixivision_monitor(): logger.debug(f"pixivision_monitor: checking started") # 获取当前bot列表 bots = [] for bot_id, bot in get_bots().items(): bots.append(bot) # 获取所有有通知权限的群组 all_noitce_groups = [] t = DBTable(table_name='Group') for item in t.list_col_with_condition('group_id', 'notice_permissions', 1).result: all_noitce_groups.append(int(item[0])) # 初始化tag黑名单 block_tag_id = [] block_tag_name = [] for block_tag in TAG_BLOCK_LIST: block_tag_id.append(block_tag.get('id')) block_tag_name.append(block_tag.get('name')) # 提取数据库中已有article的id列表 exist_article = [] t = DBTable(table_name='Pixivision') for item in t.list_col('aid').result: exist_article.append(int(item[0])) # 获取最新一页pixivision的article new_article = [] _res = await get_pixivsion_article() if _res.success() and not _res.result.get('error'): try: pixivsion_article = dict(_res.result) for article in pixivsion_article['body']['illustration']: article_tags_id = [] article_tags_name = [] for tag in article['tags']: article_tags_id.append(int(tag['tag_id'])) article_tags_name.append(str(tag['tag_name'])) # 跳过黑名单tag的article if list(set(article_tags_id) & set(block_tag_id)) or list( set(article_tags_name) & set(block_tag_name)): continue # 获取新的article内容 if int(article['id']) not in exist_article: logger.info( f"pixivision_monitor: 检查到新的Pixivision article: {article['id']}" ) new_article.append({ 'aid': int(article['id']), 'tags': article_tags_name }) except Exception as e: logger.error( f'pixivision_monitor: an error occured in checking pixivision: {repr(e)}' ) return else: logger.error( f'pixivision_monitor: checking pixivision timeout or other error: {_res.info}' ) return if not new_article: logger.info(f'pixivision_monitor: checking completed, 没有新的article') return sub = DBSubscription(sub_type=8, sub_id=-1) # 获取订阅了该直播间的所有群 sub_group = sub.sub_group_list().result # 需通知的群 notice_group = list(set(all_noitce_groups) & set(sub_group)) # 处理新的aritcle for article in new_article: aid = int(article['aid']) tags = list(article['tags']) a_res = await pixivsion_article_parse(aid=aid, tags=tags) if a_res.success(): if not notice_group: continue article_data = a_res.result msg = f"新的Pixivision特辑!\n\n" \ f"《{article_data['title']}》\n\n{article_data['description']}\n{article_data['url']}" for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) except Exception as e: logger.warning( f"向群组: {group_id} 发送article简介信息失败, error: {repr(e)}" ) continue # 处理article中图片内容 tasks = [] for pid in article_data['illusts_list']: tasks.append(fetch_image_b64(pid=pid)) p_res = await asyncio.gather(*tasks) image_error = 0 for image_res in p_res: if not image_res.success(): image_error += 1 continue else: img_seg = MessageSegment.image(image_res.result) # 发送图片 for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=img_seg) except Exception as e: logger.warning( f"向群组: {group_id} 发送图片内容失败, error: {repr(e)}") continue logger.info(f"article: {aid} 图片已发送完成, 失败: {image_error}") else: logger.error(f"article: {aid} 信息解析失败, info: {a_res.info}") logger.info( f'pixivision_monitor: checking completed, 已处理新的article: {repr(new_article)}' )
async def check_live(room_id: int): # 获取直播间信息 _res = await get_live_info(room_id=room_id) if not _res.success(): logger.error( f'bilibili_live_monitor: 获取直播间信息失败, room_id: {room_id}, error: {_res.info}' ) return live_info = _res.result sub = DBSubscription(sub_type=1, sub_id=room_id) # 获取订阅了该直播间的所有群 sub_group = sub.sub_group_list().result # 需通知的群 notice_group = list(set(all_noitce_groups) & set(sub_group)) up_name = live_up_name[room_id] # 检查是否是已开播状态, 若已开播则监测直播间标题变动 # 为避免开播时同时出现标题变更通知和开播通知, 在检测到直播状态变化时更新标题, 且仅在直播状态为直播中时发送标题变更通知 if live_info['status'] != live_status[room_id]\ and live_info['status'] == 1\ and live_info['title'] != live_title[room_id]: # 更新标题 live_title[room_id] = live_info['title'] logger.info( f"直播间: {room_id}/{up_name} 标题变更为: {live_info['title']}") elif live_info[ 'status'] == 1 and live_info['title'] != live_title[room_id]: # 通知有通知权限且订阅了该直播间的群 cover_pic = await pic_2_base64(url=live_info.get('cover_img')) if cover_pic.success(): msg = f"{up_name}的直播间换标题啦!\n\n【{live_info['title']}】\n{MessageSegment.image(cover_pic.result)}" else: # msg = f"{up_name}的直播间换标题啦!\n\n【{live_info['title']}】\n{live_info['url']}" msg = f"{up_name}的直播间换标题啦!\n\n【{live_info['title']}】" for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info(f"向群组: {group_id} 发送直播间: {room_id} 标题变更通知") except Exception as _e: logger.warning( f"向群组: {group_id} 发送直播间: {room_id} 标题变更通知失败, error: {repr(_e)}" ) continue live_title[room_id] = live_info['title'] logger.info( f"直播间: {room_id}/{up_name} 标题变更为: {live_info['title']}") # 检测开播/下播 # 检查直播间状态与原状态是否一致 if live_info['status'] != live_status[room_id]: try: # 现在状态为未开播 if live_info['status'] == 0: live_start_info = f"LiveEnd! Room: {room_id}/{up_name}" new_event = DBHistory(time=int(time.time()), self_id=-1, post_type='bilibili', detail_type='live') new_event.add(sub_type='live_end', user_id=room_id, user_name=up_name, raw_data=repr(live_info), msg_data=live_start_info) msg = f'{up_name}下播了' # 通知有通知权限且订阅了该直播间的群 for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info( f"向群组: {group_id} 发送直播间: {room_id} 下播通知") except Exception as _e: logger.warning( f"向群组: {group_id} 发送直播间: {room_id} 下播通知失败, error: {repr(_e)}" ) continue # 更新直播间状态 live_status[room_id] = live_info['status'] logger.info(f"直播间: {room_id}/{up_name} 下播了") # 现在状态为直播中 elif live_info['status'] == 1: # 记录准确开播信息 live_start_info = f"LiveStart! Room: {room_id}/{up_name}, Title: {live_info['title']}, " \ f"TrueTime: {live_info['time']}" new_event = DBHistory(time=int(time.time()), self_id=-1, post_type='bilibili', detail_type='live') new_event.add(sub_type='live_start', user_id=room_id, user_name=up_name, raw_data=repr(live_info), msg_data=live_start_info) cover_pic = await pic_2_base64( url=live_info.get('cover_img')) if cover_pic.success(): msg = f"{live_info['time']}\n{up_name}开播啦!\n\n【{live_info['title']}】" \ f"\n{MessageSegment.image(cover_pic.result)}" else: # msg = f"{live_info['time']}\n{up_name}开播啦!\n\n【{live_info['title']}】\n{live_info['url']}" msg = f"{live_info['time']}\n{up_name}开播啦!\n\n【{live_info['title']}】" for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info( f"向群组: {group_id} 发送直播间: {room_id} 开播通知") except Exception as _e: logger.warning( f"向群组: {group_id} 发送直播间: {room_id} 开播通知失败, error: {repr(_e)}" ) continue live_status[room_id] = live_info['status'] logger.info(f"直播间: {room_id}/{up_name} 开播了") # 现在状态为未开播(轮播中) elif live_info['status'] == 2: live_start_info = f"LiveEnd! Room: {room_id}/{up_name}" new_event = DBHistory(time=int(time.time()), self_id=-1, post_type='bilibili', detail_type='live') new_event.add(sub_type='live_end_with_playlist', user_id=room_id, user_name=up_name, raw_data=repr(live_info), msg_data=live_start_info) msg = f'{up_name}下播了(轮播中)' for group_id in notice_group: for _bot in bots: try: await _bot.call_api(api='send_group_msg', group_id=group_id, message=msg) logger.info( f"向群组: {group_id} 发送直播间: {room_id} 下播通知") except Exception as _e: logger.warning( f"向群组: {group_id} 发送直播间: {room_id} 下播通知失败, error: {repr(_e)}" ) continue live_status[room_id] = live_info['status'] logger.info(f"直播间: {room_id}/{up_name} 下播了(轮播中)") except Exception as _e: logger.warning( f'试图向群组发送直播间: {room_id}/{up_name} 的直播通知时发生了错误: {repr(_e)}')