async def help(session: CommandSession): """help: 帮助 用法: help [cmd] 示例: help help progress """ group_id = session.ctx['group_id'] argv = session.args['argv'] commands = get_all_commands() lines = [get_random_header()] try: if not argv: # global help at_str = "@闹闹 " for name, cmd in commands.items(): if cmd.permission == GROUP: docstr = cmd.func.__doc__ brief = docstr.split('\n')[0] if docstr else name line = at_str if cmd.only_to_me else "" line += brief lines.append(line) for msg in multiline_msg_generator(lines=lines, lineno=False): await session.bot.send_msg_rate_limited(group_id=group_id, message=msg) return cmd = argv[0] usage = commands[cmd].func.__doc__ if cmd == "register": # render docstring dynamically examples = [ f"{oj}: {url.format('<id>')}" for oj, url in PLATFORM_URLS.items() ] random.shuffle(examples) usage %= "\n".join(examples) lines += usage.split('\n') for msg in multiline_msg_generator(lines=lines, lineno=False): await session.bot.send_msg_rate_limited(group_id=group_id, message=msg) except: await session.finish(f"命令{cmd}不存在或文档未定义!@Nuulll 甩锅")
async def update_database(session: CommandSession): """update: 立刻更新账号数据(冷却时间10分钟) 除此之外,爬虫会在每日18点左右自动更新账号数据(如有bug请 @Nuullll) 用法: update """ group_id = session.ctx['group_id'] qq_id = session.ctx['user_id'] debug = session.ctx.get('debug', False) if not debug: dm = DataManager(group_id) accounts = dm.query_binded_accounts(qq_id) await session.send("正在更新数据", at_sender=True) if not accounts: await session.finish("请先绑定账号!命令:register") latest = dm.get_latest_csttime_by_qq(qq_id) now = cstnow() delta = int((now - latest).total_seconds()) print(latest, now, delta) await session.send(f"最近更新: {latest}") if delta < USER_UPDATE_COOLDOWN: await session.finish(f"技能冷却中:剩余{USER_UPDATE_COOLDOWN-delta}秒") for user_id, platform in accounts: ok, snapshot = await dm.get_and_save_user_summary( qq_id, user_id, platform) if not ok: await session.send("ID错误或网络错误!请检查后重试。") for msg in multiline_msg_generator(snapshot.lines): await session.bot.send_msg_rate_limited(group_id=group_id, message=msg) else: dm = DataManager(group_id) accounts = dm.query_binded_accounts(qq_id) for user_id, platform in accounts: ok, snapshot = await dm.get_and_save_user_summary( qq_id, user_id, platform) for msg in multiline_msg_generator(snapshot.lines): await session.bot.send_msg_rate_limited(user_id=724463877, message=msg)
async def report_total(session: CommandSession): group_id = session.ctx['group_id'] group_info = await session.bot.get_group_info(group_id=group_id) group_name = group_info['group_name'] member_count = group_info['member_count'] dm = DataManager(group_id) starttime = long_long_ago() endtime = cstnow() data = dm.report(starttime, endtime) data = [[alias, ac_now] for alias, _, ac_now in data if ac_now > 0] data.sort(reverse=True, key=itemgetter(1)) lines = autoalign(data, formatter=lambda x: "| {} | {:<5} |".format(*x)) entries = min(member_count, REPORT_TOTAL_MAX_ENTRIES, len(data)) header = f"{group_name} Top {entries} / {member_count}\n" header += "# | Name | Accepted |" await session.send(header) for msg in multiline_msg_generator(lines[:entries], lineno=True): await session.bot.send_msg_rate_limited(group_id=group_id, message=msg)
async def handle_ls(session: CommandSession): group_id = session.ctx['group_id'] user_id = session.ctx['user_id'] # args argv = session.args['argv'] ls_all = True if '-a' in argv or '--all' in argv else False try: members = await session.bot.get_group_member_list(group_id=group_id) except Exception as e: print(type(e), e) lines = [ '{} [{}]'.format( member['card'] if member['card'] else member['nickname'], member['user_id']) for member in members ] count = len(lines) header = '正在获取群成员列表...共{}人'.format(count) try: await session.bot.send_msg(group_id=group_id, message=header) for msg in multiline_msg_generator(lines=lines, lineno=True): await session.bot.send_msg_rate_limited(group_id=group_id, message=msg) if not ls_all: await session.bot.send_msg( group_id=group_id, message="Try `ls -a` or `ls --all` for full message.") break except Exception as e: print(type(e), e)
async def send_repo_info(session: CommandSession): """repo: 查看闹闹机器人开源仓库 用法: repo """ lines = [get_random_header()] lines += [ 'GITHUB: https://github.com/Nuullll/nullbot', '欢迎大家follow, star, watch三连' ] for msg in multiline_msg_generator(lines=lines, lineno=False): await session.send(msg)
async def report(session: CommandSession): group_id = session.ctx['group_id'] dm = DataManager(group_id) starttime = last_sunday() endtime = cstnow() data = dm.report(starttime, endtime) data = [[alias, ac_now, ac_now - ac_before] for alias, ac_before, ac_now in data if ac_now > 0] data.sort(reverse=True, key=itemgetter(2, 1)) lines = autoalign(data, formatter=lambda x: "| {} | {:<5} (+{}) |".format(*x)) header = f"{starttime} - {endtime}\n" header += "| Name | Accepted (+delta) |" await session.send(header) for msg in multiline_msg_generator(lines, lineno=True): await session.bot.send_msg_rate_limited(group_id=group_id, message=msg)
async def get_latest_blogs(): bot = nb.get_bot() # members = await session.bot.get_group_member_list(group_id=group_id) # # build qq_id -> card dict # card_dict = {member['user_id']: (member['card'] if member['card'] else member['nickname']) for member in members} # query all recent_updated = [] now = datetime.now() url_map = DataManager.query_blog() for qq_id, blog_urls in url_map.items(): for url in blog_urls: # if qq_id not in card_dict: # line = f"{render_cq_at(qq_id)} {url}" # else: # line = f"{card_dict[qq_id]} {url}" # lines.append(line) text, dt = guess_blog_update_time(url) if text is None: continue if (now - dt).days <= 2: recent_updated.append((qq_id, url, dt.strftime("%Y-%m-%d"))) if not recent_updated: return lines = [f"{render_cq_at('all')} 以下博客近2天内有更新,大家快去学习吧"] for qq_id, url, dt_str in recent_updated: line = f"{render_cq_at(qq_id)} {url} {dt_str}" lines.append(line) for group_id in AUTO_BLOG_PUSHES: for msg in multiline_msg_generator(lines=lines, lineno=False): await bot.send_msg_rate_limited(group_id=group_id, message=msg)
async def query_registered(session: CommandSession): argv = session.args['argv'] group_id = session.ctx['group_id'] dm = DataManager(group_id) members = await session.bot.get_group_member_list(group_id=group_id) lines = [] for member in members: alias = member['card'] if member['card'] else member['nickname'] qq_id = member['user_id'] accounts = dm.query_binded_accounts(qq_id) msg = f"{alias}: " if accounts: msg += ", ".join([f"{u}@{p}" for u, p in accounts]) else: msg += "NaN" lines.append(msg) for msg in multiline_msg_generator(lines=lines, lineno=True): await session.bot.send_msg_rate_limited(group_id=group_id, message=msg)
async def handle_blog(session: CommandSession): """blog: 查询本群公开博客列表/绑定博客/解绑博客 用法: blog // 查询博客列表 blog add <your blog url> blog remove <your blog url> [-a] 示例: blog add https://blog.nuullll.com blog remove https://blog.nuullll.com blog remove -a // 解绑本人所有博客 """ argv = session.args['argv'] group_id = session.event.group_id qq_id = session.event.user_id dm = DataManager(group_id) try: op = argv[0].lower() url = argv[1] if op == "add": if not is_valid_url(url): await session.send("闹闹无法获取博客内容,请检查url或网站可达性,或稍后再试") return dm.bind_blog(qq_id, url) await session.send("绑定成功!") elif op == "remove": remove_all = url == "-a" valid = is_valid_url(url) if not valid and not remove_all: await session.send("闹闹无法获取博客内容,请检查url或网站可达性,或稍后再试") return if valid: if not dm.unbind_blog(qq_id, url): await session.send("该博客未绑定,请检查url") return if remove_all: url_map = dm.query_blog(qq_id=qq_id) for url in url_map[qq_id]: dm.unbind_blog(qq_id, url) await session.send("解绑成功!") else: raise ValueError("Usage error.") return except: pass # query all lines = [get_random_header()] url_map = dm.query_blog() for qq_id, blog_urls in url_map.items(): for url in blog_urls: line = f"{render_cq_at(qq_id)} {url}" lines.append(line) for msg in multiline_msg_generator(lines=lines, lineno=False): await session.bot.send_msg_rate_limited(group_id=group_id, message=msg)
async def register_helper(session, for_other=False): examples = [f"{oj}: {url.format('<id>')}" for oj, url in PLATFORM_URLS.items()] shuffle(examples) USAGE = """ 用法: register <your OJ profile url> 目前支持的OJ平台: """ + "\n".join(examples) + """ 示例: register https://leetcode.com/nuullll """ group_id = session.ctx['group_id'] if not for_other: url = session.current_arg_text.strip() if not url: await session.finish("未检测到url\n" + USAGE) return url = url.split()[0] qq_id = session.ctx['user_id'] else: argv = session.args['argv'] qq_id, url = argv try: if qq_id.isnumeric(): qq_id = int(qq_id) else: # infer CQ code qq_id = parse_cq_at(qq_id) except: await session.finish('参数错误!') return platform = '' user_id = '' for oj, template in PLATFORM_URLS.items(): # escape special character in template template = template.replace('?', '\?') m = re.search(template.format('([a-zA-Z0-9_-]+)'), url) if m: platform = oj user_id = m.group(1) break if not user_id: await session.finish("请检查URL格式\n" + USAGE) return dm = DataManager(group_id) binded, bind_qq = dm.is_account_binded(user_id, platform) if binded: if bind_qq == qq_id: await session.finish(f"您已绑定{user_id}@{platform},请勿重复操作。") else: await session.finish(f"绑定失败,{user_id}@{platform}已被用户[CQ:at,qq={bind_qq}]绑定!") return ok, snapshot = await dm.get_and_save_user_summary(qq_id, user_id, platform) if not ok: await session.send("ID错误或网络错误!请检查后重试。") return if not dm.bind_account(qq_id, user_id, platform): await session.finish("绑定失败,代码线程不安全。") return await session.send(f"{user_id}@{platform}绑定成功!") for msg in multiline_msg_generator(snapshot.lines): await session.send(msg)
async def handle_blog(session: CommandSession): """blog: 查询本群公开博客列表/绑定博客/解绑博客 用法: blog // 查询博客列表 blog add <your blog url> blog remove <your blog url> [-a] 示例: blog add https://blog.nuullll.com blog remove https://blog.nuullll.com blog remove -a // 解绑本人所有博客 """ argv = session.args['argv'] group_id = session.event.group_id qq_id = session.event.user_id dm = DataManager(group_id) try: op = argv[0].lower() url = argv[1] if op == "add": if not is_valid_url(url): await session.send("闹闹无法获取博客内容,请检查url或网站可达性,或稍后再试") return if dm.bind_blog(qq_id, url): await session.send("绑定成功!") else: await session.send("该博客你已经绑定过啦!") elif op == "remove": remove_all = url == "-a" if remove_all: url_map = dm.query_blog(qq_id=qq_id) for url in url_map[qq_id]: dm.unbind_blog(qq_id, url) else: if not dm.unbind_blog(qq_id, url): await session.send("该博客未绑定,请检查url") return await session.send("解绑成功!") else: raise ValueError("Usage error.") return except: pass members = await session.bot.get_group_member_list(group_id=group_id) # build qq_id -> card dict name_dict = { member['user_id']: (member['card'], member['nickname']) for member in members } # query all lines = [] url_map = dm.query_blog() for qq_id, blog_urls in url_map.items(): for url in blog_urls: if qq_id not in name_dict: line = f"{render_cq_at(qq_id)} {url}" else: card, nickname = name_dict[qq_id] card = f"({card})" if card else "" line = f"{nickname}{card} {url}" lines.append(line) shuffle(lines) lines = [get_random_header()] + lines for msg in multiline_msg_generator(lines=lines, lineno=False): await session.bot.send_msg_rate_limited(group_id=group_id, message=msg)