async def en_secondary_operation(bot: Bot, event: GroupMessageEvent, state: T_State): logger.debug(f'Handle brach with {state["operation"]}') gid = str(event.group_id) if gid not in exitremind_settings: exitremind_settings[gid] = DEFAULT_REMIND settings = exitremind_settings[gid] if state['operation'] == 'add_leave': settings['leave'].append(event.raw_message) msg = '好的,已经添加一个主动退群提醒语句' elif state['operation'] == 'add_kick': settings['kick'].append(event.raw_message) msg = '好的,已经添加一个管理踢人提醒语句' elif state['operation'] == 'delete': if event.raw_message.isdigit(): index = int(event.raw_message) if index > 0 and index <= len(settings['leave']) + len(settings['kick']): if index <= len(settings['leave']): del settings['leave'][index - 1] msg = f'已删除序号为{index}的退群提醒语句' else: index -= len(settings['leave']) del settings['kick'][index - 1] msg = f'已删除序号为{index}的管理踢人提醒语句' else: await remind_editor.finish('输入的参数不在列表内,请检查序号') else: await remind_editor.finish('只支持纯数字参数,请重新开启此对话进行操作') else: logger.error(f"Unkown session with operation: {state['operation']}") await remind_editor.finish('未知的对话进度,请联系维护组进行排查') save_en_settings() await remind_editor.finish(msg)
async def get_lolicon(kwd: str = '', r18: int = 0, num: int = 1, size1200: bool = False) -> dict: """ :Summary: 连接loliconAPI的异步函数 :Args: * ``kwd``: 若指定关键字,将会返回从插画标题、作者、标签中模糊搜索的结果 * ``r18``: 0为非 R18,1为 R18,2为混合 * ``num``: 一次返回的结果数量,范围为1到10,不提供 APIKEY 时固定为1;在指定关键字的情况下,结果数量可能会不足指定的数量 * ``size1200``: 是否使用 master_1200 缩略图,即长或宽最大为 1200px 的缩略图,以节省流量或提升加载速度(某些原图的大小可以达到十几MB) :Returns: json: { ``code``: int 返回码,可能值详见后续部分 ``msg``: string 错误信息之类的 ``count``: int 结果数 ``data``: list[dict(setu)] 色图数据列表 } ``setu``: { ``pid``: int 作品 PID ``p``: int 作品所在 P ``uid``: int 作者 UID ``title``: string 作品标题 ``author``: sting 作者名(入库时,并过滤掉 @ 及其后内容) ``url``: string 图片链接(可能存在有些作品因修改或删除而导致 404 的情况) ``r18``: bool 是否 R18(在色图库中的分类,并非作者标识的 R18) ``width``: int 原图宽度 px ``height``: int 原图高度 px ``tags``: list[string] 作品标签,包含标签的中文翻译(有的话) } ``code``:{ ``-1``: 内部错误,请向 [email protected] 反馈 ``0``: 成功 ``404``: 找不到符合关键字的色图 } """ async with httpx.AsyncClient() as client: params = {'r18': r18, 'keyword': kwd, 'num': num, 'size1200': size1200} resp = await client.get(API, params=params, timeout=120) result = resp.json() logger.debug(result) return result
def exitremind_rule(bot: Bot, event: GroupDecreaseNoticeEvent, state: T_State): """排除自己被踢出群的情况,排除退群语句被删除到没有了的情况""" if not isinstance(event, GroupDecreaseNoticeEvent): return False logger.debug(f'Group {event.group_id} decrease Got!!') logger.debug(isinstance(event, GroupDecreaseNoticeEvent)) if event.sub_type == 'kick_me': return False gid = str(event.group_id) if gid in exitremind_settings: if event.sub_type == 'leave' and len(exitremind_settings[gid]['leave']) == 0 \ or event.sub_type == 'kick' and len(exitremind_settings[gid]['kick']) == 0: return False return True
def store_talk(bot: Bot, event: GroupMessageEvent, state: T_State): if event.post_type not in ( 'message', 'message_sent') or event.message_type != 'group': return False # 消息不一致,重置存储 if event.group_id not in cur_msg or event.raw_message != cur_msg[ event.group_id]['message']: cur_msg[event.group_id] = { 'message': event.raw_message, 'times': 0, 'uid_ls': {event.user_id} } logger.debug(f'{str(cur_msg)}') return False gr = cur_msg[event.group_id] # 复读过的人不在列表中,计算概率,如果是复读过的人会完全忽略消息,不刷新列表也不增加次数 if event.user_id not in gr['uid_ls']: # if event.raw_message == gr['message']: gr['times'] += 1 gr['uid_ls'].add(event.user_id) logger.debug(f'{str(cur_msg)}') if event.self_id not in gr[ 'uid_ls'] and event.user_id != event.self_id: # 自己已在消息记录中,也可能是自己发送的消息,不能触发自己复读 c = random() r = (1 - repeat_rate)**gr['times'] # if random() > (1 - repeat_rate) ** gr['times']: logger.debug(f"c: {c}, r: {r}") if c > r: logger.debug(f'在第{gr["times"]}次触发了复读') state['raw_msg'] = gr['message'] return True
def test_downloader_01(): with open('./examples/manifest.json', 'r') as manifest_file: data = json.load(manifest_file) project_ids = [file['projectID'] for file in data['files']] downloader = Downloader() with downloader: for index, project_id in enumerate(project_ids): if index >= 10: break project_url = downloader.get_project_url(project_id) name = os.path.basename(project_url) logger.debug('The name of project {} was {}'.format( project_id, name)) time.sleep(0.5)
def getX(key, expire_time=3600 * 24, update=False) -> dict: try: redis_cli = get_redis() val = redis_cli.get(key) if None != val and update: redis_cli.expire(key, expire_time) logger.debug("set {key} expiretime:{expire}".format( key=key, expire=datetime.datetime.fromtimestamp( int(time.time()) + expire_time))) return DBResult.format(TSZ_MODEL_REDIS, QUERY_SUCCESS, val.decode()) except Exception as e: errmsg = "Catch Execption in Redis getX({key}). ErrMsg:{msg}".format( key=key, msg=e) logger.warning(errmsg) return DBResult.format(TSZ_MODEL_REDIS, QUERY_FALED, errmsg)
def chat_checker(bot: Bot, event: MessageEvent, state: T_State): """闲聊触发率规则 优先级规则内,to_me时必定触发 否则真实触发率为 群设置聊天触发率 * 返回信息的可信度 """ msg = event.message.extract_plain_text() if not msg or len(msg) > 50 or event.raw_message in BAN_MESSAGE or\ event.raw_message == '钓鱼': return False # 回复别人的对话不会触发 for seg in event.message: if seg.type == 'at' and seg.data["qq"] not in ( str(event.self_id), 'all' ) or event.reply and event.reply.sender.user_id != event.self_id: return False if event.message_type == 'group' and not event.is_tome(): nothing_to_bot = True # 对话中带有bot名字,归到到下面一起判断 for name in BOTNAMES: if name in msg: person = '你' if msg.endswith( BOTNAME) else '' # 名称在中间的时候替换成第二人称,名称在末尾时直接去掉 msg = msg.replace(name, person) nothing_to_bot = False break gid = str(event.group_id) prob = prob_settings[gid] if gid in prob_settings else 0.05 # 默认触发率5% if nothing_to_bot and random() > prob: return False else: ai_reply = ai_chat(msg) if ai_reply is None: logger.error( f'Failed to get tencent AI chat!') # 内部错误时返回的的是None return False else: reply, confidence = ai_chat(msg) if reply in BAN_EXPRESSION or len(reply) > 50: return False logger.debug(f'{msg} 获得触发率 {confidence:.5f}') if random() > confidence: return False else: state["reply"] = reply return True
async def show_record(bot: Bot, event: GroupMessageEvent): arg = str(event.message).split('号记录')[0] if not arg.isdigit(): await recorder.finish(reply_header(event, '哪有这种代号的记录啊?!')) fake_id = int(arg) if fake_id not in recalled[event.group_id]: await recorder.finish(reply_header(event, '这条记录不存在或者因为太久所以被消除了~')) msg_id, passive, timestamp = recalled[event.group_id][fake_id] try: msginfo = await bot.get_msg(message_id=msg_id) logger.debug( f"Got recalled message({type(msginfo['message'])}): {str(msginfo['message'])}" ) except ActionFailed: await recorder.finish(reply_header(event, '这条记录不存在或者因为太久所以被消除了~')) for seg in msginfo["message"]: logger.debug(f'Check type of segment: {seg}\n{seg["type"]}') if seg['type'] not in ('text', 'face', 'image', 'at', 'reply'): # 可以夹在普通消息框里的片段 can_append = False break else: can_append = True time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S") try: litigant_info = await bot.get_group_member_info( group_id=event.group_id, user_id=msginfo["sender"]["user_id"]) name = litigant_info["card"] or litigant_info["nickname"] or str( litigant_info["user_id"]) except ActionFailed: name = msginfo["sender"]["user_id"] # 没获取到的话可能群员退群了 if passive: header = f"{name}在{time}被撤回了:\n" else: header = f"{name}在{time}撤回了:\n" if can_append: await recorder.finish(Message(header) + (Message(msginfo["message"]))) else: await recorder.send(Message(header)) await asleep(1) # await recorder.finish(msginfo["message"]) await recorder.finish(Message(msginfo["raw_message"]))
def test_downloader_02(): with open('./examples/manifest.json', 'r') as manifest_file: data = json.load(manifest_file) project_ids = [file['projectID'] for file in data['files']] file_ids = [file['fileID'] for file in data['files']] downloader = Downloader() with downloader: for index, project_id in enumerate(project_ids): if index >= 3: break project_url = downloader.get_project_url(project_id) name = os.path.basename(project_url) logger.debug('The name of project {} was {}'.format( project_id, name)) filename, data = downloader.download_mod_file( project_id, project_url, file_ids[index]) with open('{}'.format(filename), 'wb') as mod_file: mod_file.write(data) time.sleep(0.5)
def welcome_rule(bot: Bot, event: GroupIncreaseNoticeEvent, state: T_State): """排除自己加群的情况,排除加群语句被删除到没有了的情况""" if not isinstance(event, GroupIncreaseNoticeEvent): return False logger.debug(f'Group {event.group_id} increase Got!!') logger.debug(isinstance(event, GroupIncreaseNoticeEvent)) if event.user_id == event.self_id: return False logger.debug('非自身加群') gid = str(event.group_id) if gid in welcome_settings: if event.sub_type == 'approve' and len(welcome_settings[gid]['approve']) == 0: # or event.sub_type == 'invite' and len(welcome_settings[gid]['invite']) == 0: return False return True
async def sx_rev(bot: Bot, event: MessageEvent, state: T_State): logger.debug(f'Match sx {state["_matched_groups"]}') abbr = state["_matched_groups"][0] try: data = await get_sx(abbr) except aiohttp.ClientError as err: logger.error(f'query sx {abbr} error: {err}') await sx.finish("查询出错了,要不要稍后再试试?") try: name = data[0]['name'] logger.debug(f'查询缩写:{name}') content = data[0]['trans'] logger.debug(f'查找到的缩写:{content}') if len(content) == 0: await sx.finish(f'没有找到缩写可能为{name}的内容') msg = f'{name} 的意思可能为:' if len(content) > 1: msg += '\n' await sx.send(msg + "、".join(content)) except: await sx.finish(f'没有找到缩写可能为{abbr}的内容')
def get_setu(gid: int, kwds: Sequence[str], num: int=1, r18: int=0): """从数据库中获得色图数据 Args: gid (int): 呼叫色图的群号,相同群内会有两个小时的记录去重,私聊传入0以不做处理 kwd (tuple): 关键词,元组内的词会做交集查询 num (int, optional): 查询数量. Defaults to 1. r18 (int, optional): 是否包含r18图片,0:没有R18,1:只有R18,2:混合. Defaults to 0. Returns: tuple: 返回是否调用成功以及返回的结果,如果没有查询结果会返回无结果还是结果已经用尽,如果有结果会返回数据列表 数据结构:{ 'count' (int): 返回数量,为了与lolicon结构保持一致, 'data' (list):{ 'title' (str): 作品名, 'author' (str): 作者, 'source' (str): pid_p, 'file' (Path): 文件路径 } } """ if gid: if gid not in Setu_Called_Data: Setu_Called_Data[gid] = Setu_Called(gid) his = Setu_Called_Data[gid] with GalleryDB() as glrdb: # TODO: 优化随机查询的方式取代orded by rand() cmd = 'SELECT pid, p, title, author, url, id FROM lolicon WHERE ' if r18 != 2: cmd += f'r18={r18} AND ' # 过滤已经调用过的图片 if gid and len(his.called) > 1: cmd += f'id NOT IN {tuple(his.called)} AND ' # 添加关键词条件并随机抽取 cmd += ' AND '.join(['(tags LIKE %s OR title LIKE %s OR author LIKE %s)'] * len(kwds)) cmd += ' ORDER BY RAND() LIMIT %s' # 三个一组的关键词参数与一个limit参数 params = concat_seq(*[(k, k, k) for k in map(lambda x: '%' + x + '%', kwds)]) + (num,) logger.debug(f'执行SQL>>{cmd}'%params) # logger.debug(f'执行SQL>>{cmd}') # logger.debug(f'{params=}') results = glrdb.queryall(cmd, params) if not results: if gid and kwds in his.called_kwds: return False, f'暂时没有更多关于"{"|".join(kwds)}"的涩图了' else: return False, f'没有找到关于"{"|".join(kwds)}"的涩图' # TODO: 换了标签之后再搜索到相同的图用这个标签不太合适,换成"有x张相关图刚才已经发过了" setu_ls = [] # 所有色图列表 for record in results: filestem = str(record[0]) + '_p' + str(record[1]) # 名字是pid_p suffix : str = record[4].split('.')[-1] # 后缀从url里解析 filename = filestem + '.' + suffix filepath = Path(SETUPATH)/filename logger.debug(f'定位本地文件{filepath}') if not filepath.exists(): logger.warning(f'Did not found local file [{filename}]') try: r = requests.get(record[4]) filepath.write_bytes(r.content) logger.info(f'Downloaded file [{filename}] into setupath') except Exception as err: logger.exception(f'Failed to download file [{filename}]: {err}') setu_ls.append(None) continue data = { 'title': record[2], 'author': record[3], 'source': filestem, 'file': filepath } setu_ls.append(data) if gid: his.called.add(record[5]) # 添加id记录 if gid: his.called_kwds.add(kwds) # 添加关键词记录 his.check_expired() # 检查记录是否过期 return True, {'count': len(setu_ls), 'data': setu_ls}
async def check_fortune(bot: Bot, event: MessageEvent): name = event.sender.card if event.message_type == 'group' else event.sender.nickname dlmt = DailyNumberLimiter(event.user_id, func_name='运势', max_num=1) stick = query_fortune(event.user_id) rp = 0 # 如果抽中了特殊的签要发生一些事件 TODO:加入一些今天功能冷却减少之类的什么奖励吧 if dlmt.check(close_conn=False) or not stick: stick = choice(sticks) if dlmt.count == 0: if stick.name == '28.jpg': # 恋爱运,惩罚 rp = 1 elif stick.name == '27.jpg': # 凶,奖励 rp = 2 elif stick.name in ('8.jpg', '16.jpg', '19.jpg'): # 金运,给钱 rp = 3 elif stick.name in ('15.jpg', '23.jpg'): # 全体运,群内统统滴奖励,私聊无效 rp = 4 elif stick.name == '17.jpg': # 关系运, 私聊的时候给予奖励吧 rp = 5 draw_fortune(event.user_id, stick.name) dlmt.increase() else: dlmt.conn.close() stick = assets_folder / stick logger.debug(f'{event.user_id} got stick {stick.name}') await fortune.send(f'{name}今日的运势是' + imgseg(stick), at_sender=True) if rp: await asleep(1.5) if event.message_type == 'group': name = event.sender.card or event.sender.nickname or event.get_user_id( ) else: name = event.sender.nickname or event.get_user_id() if rp == 1 and is_user(event.user_id): exp = randint(9, 15) fund = randint(20, 30) user = UserLevel(event.user_id) await user.expup(-exp, bot, event) user.turnover(-fund, check_overdraft=False) await fortune.finish( f'虽然你抽中了恋爱运也不一定会遇到恋爱事件,不过对和恋爱沾边的家伙给予惩罚才是正义的\n{name}的exp -{exp}, 资金 -{fund}', at_sender=True) elif rp == 2 and is_user(event.user_id): exp = randint(15, 25) fund = randint(30, 50) user = UserLevel(event.user_id) await user.expup(exp, bot, event) user.turnover(fund) await fortune.finish( 'Emmmm,因为占卜的师傅如果不是有别的什么目的的话,为了讨好前来占卜的人都会尽量说是吉签嘛\n 抽到这个凶签这种小概率事件,某种意义上这才是奇迹真正应该有的样子' f'\n{name}获得了{exp}exp和{fund}资金', at_sender=True) elif rp == 3 and is_user(event.user_id): fund = randint(20, 30) user = UserLevel(event.user_id) user.turnover(fund) await fortune.finish( f'因为{BOTNAME}给不了你软妹币所以也只好送些这个给你了~不过说不定哪天它会像比特币一样突然价值激增哦~\n{name}获得了{fund}资金', at_sender=True) elif rp == 4: if event.message_type == 'group': await fortune.send('大家会感谢你的,无私的散财者~骗你的( •̀ ω •́ )✧', at_sender=True) memberlist = await bot.get_group_member_list( group_id=event.group_id) uids = filter_users(*[m['user_id'] for m in memberlist]) if len(uids) > 5: uids = get_active_user(*uids) logger.debug(f'获得奖励的群员{uids}') if uids: for uid in uids: exp = randint(5, 8) fund = randint(5, 8) user = UserLevel(uid) await user.expup(exp, bot, event=None, gid=event.group_id) try: member = await bot.get_group_member_info( group_id=event.group_id, user_id=uid) except ActionFailed as e: logger.warning( f'可能是已经退群的群员: group: {event.group_id} qq: {uid}, error: {e}' ) await fortune.send( group_id=event.group_id, message= f'本应该在群内的成员({uid})貌似获取不到了,是不是退群了呢?没有的话请联系维护组查看一下出问题的原因哦~' ) continue name = member['card'] or member['nickname'] or str(uid) await fortune.send(message=MessageSegment.text( f'{name}获得了{exp}exp和{fund}资金') + MessageSegment.at(qq=uid)) await asleep(1.5) else: await fortune.finish('啊嘞,这个群里好像还没有能获得奖励的伙伴呢~') else: await fortune.finish('可惜这里是私聊所以全体运的效果生效不了了呢~') elif rp == 5 and is_user(event.user_id): if event.message_type == 'group': await fortune.finish('啊~获得了可以增加亲密度的签,但是这个签只有私聊抽中的时候才有效哦~残念', at_sender=True) else: exp = randint(25, 40) fund = randint(40, 50) user = UserLevel(event.user_id) await user.expup(exp, bot, event) user.turnover(fund) await fortune.finish( f'真的为了什么才和{BOTNAME}进行私密对话的吗?送你{exp}exp和{fund}资金吧,除了这些{BOTNAME}也没有其它的了' )