async def cpdaily_submit(mode): current_dir = os.path.join(os.path.dirname(__file__), 'config.json') with open(current_dir, 'r', encoding='UTF-8') as f: f_data = json.load(f) manage_dir = os.path.join(os.path.dirname(__file__), 'manage.json') with open(manage_dir, 'r', encoding='UTF-8') as af: m_data = json.load(af) num = len(list(f_data.keys())) msg_list = [] for username in list(f_data.keys()): await asyncio.sleep(0.5) try: msg_list = await get_msg_list(username, f_data, m_data, mode, msg_list) except KeyError as e: if str(e) == "'data'": msg_list.append(f'{username}前一天未打卡,无法自动打卡,已跳过') logger.info(f'{username}前一天未打卡,无法自动打卡,已跳过') continue else: return f'出现错误:{e},可能是网站又又又炸了' logger.info('==所有用户处理结束==') if not msg_list: msg = f'全部{mode}成功提交' elif len(msg_list) == num: error_info = re.search(r'发生错误:\S*', msg_list[0]).group() msg = f'警告:\n全员提交失败!\n{error_info}' else: msg = f'全部提交完成,其中部分用户提交出现问题:\n' + '\n'.join(msg_list) return msg
async def handler_interaction(bot: HoshinoBot, ev: CQEvent, _): if interact.find_session(ev): session = interact.find_session(ev) if ev.raw_message == 'exit' and ev.user_id == session.creator: #创建者选择退出 session.close() await session.finish(ev, f'{session.name}已经结束,欢迎下次再玩!') if session.is_expire(): session.close() await bot.send(ev, f'时间已到,{session.name}自动结束') func = session.actions.get( ev.raw_message) if ev.user_id in session.users else None if func: logger.info(f'triggered interaction action {func.__name__}') try: await func(ev, session) except CanceledException as e: logger.info(e) except Exception as ex: logger.exception(ex) raise CanceledException('handled by interact handler') elif session.handle_msg: await session.handle_msg(ev, session) else: pass
async def saveCustomReply(): try: with open(customReply, "w", encoding="UTF-8") as json_file: json_file.write(ujson.dumps(custom_reply)) logger.info("customReply has been saved") except FileNotFoundError: raise "customReply.json not found, will create when needed."
async def wrapper(): try: logger.info(f'Scheduled job {func.__name__} start.') await func() logger.info(f'Scheduled job {func.__name__} completed.') except Exception as e: logger.exception(e) logger.error( f'{type(e)} occured when doing scheduled job {func.__name__}.')
def setu_producer(): while True: if len(_setu_list) < 10: setu_list = get_setu() for setu in setu_list: _setu_list.append(setu) dump_setu_config() logger.info(f'{len(setu_list)} setu is put into the setu list') time.sleep(30)
async def reset_password(): if request.method == 'GET': return await render_template('login.html', title='重置密码') else: if request.query_string: query_dict = dict(parse.parse_qsl(request.query_string.decode('utf8'))) else: query_dict = {} logger.info(query_dict) if 'qqid' in query_dict and 'key' in query_dict: pass return await render_template('login.html', title='重置密码')
async def get_msg_list(username, f_data, m_data, mode, msg_list): logger.info(f'开始处理用户{username}') try: # 登录并提交 flag, error_info = await login_submit(username, f_data[username]['password'], m_data['location'], m_data['region']) if flag: if flag == 'success': info = f'{mode}提交成功' elif flag == 'have_done': info = f'{username}已经提交过了' msg_list.append(info) elif flag == 'need_self': info = f'{username}本次请手动填报提交' msg_list.append(info) logger.info(info) emailmsg = f''' 你好: 来自{mode}提交系统的消息: {info} ''' await InfoSubmit(username, m_data, emailmsg, f_data[username]['email'], f_data[username]['enable_email']) else: logger.info(f'{username}发生错误:{error_info}') emailmsg = f''' 你好: 来自{mode}提交系统的消息: {mode}提交失败! {username}发生错误:{error_info} ''' await InfoSubmit(username, m_data, emailmsg, f_data[username]['email'], f_data[username]['enable_email']) msg_list.append(f'{username}发生错误:{error_info}') except requests.HTTPError: logger.info(f'{username}发生错误:密码错误') emailmsg = f''' 你好: 来自{mode}提交系统的消息: {mode}提交失败! {username}发生错误:密码错误 ''' await InfoSubmit(username, m_data, emailmsg, f_data[username]['email'], f_data[username]['enable_email']) msg_list.append(f'{username}发生错误:密码错误') return msg_list
async def setu_consumer(): if not _setu_list: return '色图库正在补充,请稍候再冲' setu = _setu_list.pop(0) dump_setu_config() logger.info('1 setu is take out from the setu list') pid = setu['pid'] title = setu['title'] tags = setu['tags'] author = setu['author'] date = setu['date'] msg = [ f"标题: {title}", f"画师: {author}", f"{R.img(f'setu/{date}/', f'{title}.jpg').cqcode}", f"源地址: https://pixiv.net/i/{pid}" ] return '\n'.join(msg)
async def reload_pcrdata(): try: dataget = await aiorequests.get( 'http://api.akiraxie.me/pcr/priconne_data.py', timeout=5) datacon = await dataget.content except Exception as e: logger.error(f'连接服务器失败. {type(e)}') logger.exception(e) return 1 if 200 != dataget.status_code: logger.warning('连接服务器失败') return 1 with open(pcrdatapath, 'wb') as f: f.write(datacon) f.close() reload_data() logger.info('更新角色数据成功') return 0
def init(): logger.info(f'Initializing Database...') if TESTING_MODE: logger.warning("PAY ATTENTION!NOW UNDER TESTING MODE!") for db in BaseDatabase.__subclasses__(): try: db_name = db.__name__ db.bind(database(db_name)) if skip_database_initialize: continue database(db_name).connect() if not db.table_exists(): database(db_name).create_tables([db]) logger.info(f'Table <{db_name}> not exists, will be created in database <{get_database(db_name)}>.') database(db_name).close() except Exception as e: traceback.print_exc() logger.critical(f'Error <{e}> encountered while initializing database <{get_database(db_name)}>.')
async def single_submit(username, mode): current_dir = os.path.join(os.path.dirname(__file__), 'config.json') with open(current_dir, 'r', encoding='UTF-8') as f: f_data = json.load(f) manage_dir = os.path.join(os.path.dirname(__file__), 'manage.json') with open(manage_dir, 'r', encoding='UTF-8') as af: m_data = json.load(af) msg_list = [] try: msg_list = await get_msg_list(username, f_data, m_data, mode, msg_list) except KeyError as e: return f'出现错误:{e},可能是网站又又又炸了' logger.info(f'=={username}处理结束==') if not msg_list: msg = f'{username}成功{mode}提交' else: msg = f'提交出现问题:\n' + '\n'.join(msg_list) return msg
async def reload_config(): try: dataget = await aiorequests.get( 'http://api.akiraxie.me/pcr/config.json', timeout=5) datacon = await dataget.content except Exception as e: logger.error(f'连接服务器失败. {type(e)}') logger.exception(e) return 1 if 200 != dataget.status_code: logger.warning('连接服务器失败') return 1 with open(jsonpath, 'wb') as f: f.write(datacon) f.close() importlib.reload(priconne_data) gen_name2id() logger.info('更新卡池配置成功') return 0
def download_chara_icon(id_, star, rurl='https://redive.estertion.win/icon/unit/'): url = rurl + f'{id_}{star}1.webp' save_path = R.img(f'priconne/unit/icon_unit_{id_}{star}1.png').path logger.info(f'Downloading chara icon from {url}') try: rsp = requests.get(url, stream=True, timeout=5) except Exception as e: logger.error(f'Failed to download {url}. {type(e)}') logger.exception(e) return 1, star if 200 == rsp.status_code: img = Image.open(BytesIO(rsp.content)) img.save(save_path) logger.info(f'Saved to {save_path}') return 0, star else: logger.error(f'Failed to download {url}. HTTP {rsp.status_code}') return 1, star
async def to_apply_for_title(bot, ev): music_name = [] for msg_seg in ev.message: if msg_seg.type == 'text' and msg_seg.data['text']: music_name.append(msg_seg.data['text'].strip()) if not music_name: await bot.send(ev, '你想听什么呀?', at_sender=True) else: music_name = ''.join(music_name) song_list = search_netease_cloud_music(music_name) if song_list: logger.info('成功获取到歌曲列表') key = f'{ev.group_id}-{ev.user_id}' temp[key] = {} # _music = MessageSegment.music(type_=_type, id_=_id) msg = ['我找到了这些~!'] for idx, song in enumerate(song_list): msg.append(f'{idx}. {song["name"]} - {song["artists"]}') temp[key][str(idx)] = {'id': song['id'], 'type': song['type']} msg.append('发送[选择]+序号来听歌吧~') await bot.send(ev, '\n'.join(msg), at_sender=True) else: await bot.send(ev, '什么也没有找到的说OxO')
async def inspect(gid, sid, group_name, inspect_type): r = requests.get(urljoin(BOT_AUTH_SERVER, f'charge/verify?group_id={gid}')).json() if r['status'] == 'ok': if 'data' in r and 'days' in r['data'] and 'seconds' in r['data']: days, hours, minutes, seconds = auth_data_to_dhms(r) if inspect_type == 'query': # 主动查询 await sv.bot.send_group_msg( group_id=int(gid), message=f"授权还有{days}天{hours}小时{minutes}分钟{seconds}秒") else: # 定时巡查 if days < 3: await sv.bot.send_group_msg( group_id=int(gid), message= f"授权只有{days}天{hours}小时{minutes}分钟{seconds}秒就要到期了,真的不续费吗?" ) else: await sv.bot.send_group_msg( group_id=int(gid), message=f"授权信息不正常,请联系客服人员 {SUPERUSERS}") if SUPERUSERS: for super_id in SUPERUSERS: await sv.bot.send_msg( user_id=int(super_id), message=f"group id {gid} auth info not correct", self_id=sid) logger.error(f"group id {gid} auth info not correct") logger.info(f"{gid} {group_name} auth ok") elif r['msg'] == 'expired': logger.info(f"{gid} {group_name} auth expired,quit group") try: await sv.bot.send_group_msg(group_id=int(gid), message='授权已经到期了,我走了哟') await sv.bot.set_group_leave(group_id=int(gid), is_dismiss=False, self_id=sid) except ActionFailed as e: if e.retcode == 103: logger.error('An owner cannot quit from a owning group') await sv.bot.send_group_msg(group_id=int(gid), message='哎呀,我是群主,走不掉呢', self_id=sid) else: logger.error(e) else: logger.info(f"{gid} {group_name} auth fail,quit group") await sv.bot.send_group_msg(group_id=int(gid), message='授权不存在,看来我走错地方了,我走了哟', self_id=sid) await sv.bot.set_group_leave(group_id=int(gid), is_dismiss=False, self_id=sid)
async def InfoSubmit(username, m_data, msg, email, enable_email): if not enable_email: logger.info("该用户已关闭邮件提醒服务") return my_sender = m_data['account'] # 发件人邮箱账号 my_pass = m_data['emailpassword'] # 发件人邮箱密码 try: msg = MIMEText(str(msg), 'plain', 'utf-8') msg['From'] = formataddr(["自动提交系统", my_sender]) # 括号里的对应发件人邮箱昵称、发件人邮箱账号 msg['To'] = formataddr([username, email]) # 括号里的对应收件人邮箱昵称、收件人邮箱账号 msg['Subject'] = '提交结果通知' # 邮件的标题 server = smtplib.SMTP_SSL( m_data['server'], m_data['port']) # 发件人邮箱中的SMTP服务器,端口是对应邮箱的ssl发送端口 server.login(my_sender, my_pass) # 括号中对应的是发件人邮箱账号、邮箱密码 server.sendmail(my_sender, email, msg.as_string()) # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件 server.quit() # 关闭连接 logger.info("邮件发送成功") except Exception: logger.info("邮件发送失败")
def close(self, message: Message_T = None): InteractHandler().close_session(self.group_id, self.name) logger.info(f'interaction session {self.name} has been closed')
async def login_submit(username: str, password: str, location: str, region: str): #### 开始登录 requestSession = requests.session() requestSession.headers.update({ 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; 114514FUCK) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.73 Mobile Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' }) # get cookie: SESSION ignore = requestSession.get('https://cas.hfut.edu.cn/cas/login') ignore.raise_for_status() # get cookie: JSESSIONID ignore = requestSession.get('https://cas.hfut.edu.cn/cas/vercode') ignore.raise_for_status() # get encryption key timeInMillisecond = round(time.time_ns() / 100000) responseForKey = requestSession.get( url='https://cas.hfut.edu.cn/cas/checkInitVercode', params={'_': timeInMillisecond}) responseForKey.raise_for_status() encryptionKey = responseForKey.cookies['LOGIN_FLAVORING'] # check if verification code is required if responseForKey.json(): logger.info('需要验证码,过一会再试试吧。') return False, '需要验证码,过一会再试试吧。' # try to login encryptedPassword = await encryptPassword(password, encryptionKey) checkIdResponse = requestSession.get( url='https://cas.hfut.edu.cn/cas/policy/checkUserIdenty', params={ '_': (timeInMillisecond + 1), 'username': username, 'password': encryptedPassword }) checkIdResponse.raise_for_status() checkIdResponseJson = checkIdResponse.json() if checkIdResponseJson['msg'] != 'success': # login failed if checkIdResponseJson['data']['mailRequired'] or checkIdResponseJson[ 'data']['phoneRequired']: # the problem may be solved manually logger.info('需要进行手机或邮箱认证,移步: https://cas.hfut.edu.cn/') return False, '需要进行手机或邮箱认证' logger.info(f'处理checkUserIdenty时出现错误:{checkIdResponseJson["msg"]}') return False, f'处理checkUserIdenty时出现错误:{checkIdResponseJson["msg"]}' requestSession.headers.update( {'Content-Type': 'application/x-www-form-urlencoded'}) loginResponse = requestSession.post( url='https://cas.hfut.edu.cn/cas/login', data={ 'username': username, 'capcha': '', 'execution': 'e1s1', '_eventId': 'submit', 'password': encryptedPassword, 'geolocation': "", 'submit': "登录" }) loginResponse.raise_for_status() requestSession.headers.pop('Content-Type') if 'cas协议登录成功跳转页面。' not in loginResponse.text: # log in failed logger.info('登录失败') return False, '未知原因,登录失败' # log in success logger.info('登录成功') #### 开始提交 ignore = requestSession.get( url='http://stu.hfut.edu.cn/xsfw/sys/swmjbxxapp/*default/index.do') # always 502, ignore this #ignore.raise_for_status() requestSession.headers.update({ 'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest' }) ignore = requestSession.post( url='http://stu.hfut.edu.cn/xsfw/sys/emapfunauth/welcomeAutoIndex.do') ignore.raise_for_status() requestSession.headers.pop('Content-Type') requestSession.headers.pop('X-Requested-With') ignore = requestSession.get( url='http://stu.hfut.edu.cn/xsfw/sys/emapfunauth/casValidate.do', params={'service': '/xsfw/sys/swmjbxxapp/*default/index.do'}) ignore.raise_for_status() requestSession.headers.update({ 'X-Requested-With': 'XMLHttpRequest', 'Referer': 'http://stu.hfut.edu.cn/xsfw/sys/swmjbxxapp/*default/index.do' }) ignore = requestSession.get( url= 'http://stu.hfut.edu.cn/xsfw/sys/emappagelog/config/swmxsyqxxsjapp.do') ignore.raise_for_status() # get role config requestSession.headers.pop('X-Requested-With') requestSession.headers.update( {'Content-Type': 'application/x-www-form-urlencoded'}) configData = { 'data': json.dumps({ 'APPID': '5811260348942403', 'APPNAME': 'swmxsyqxxsjapp' }) } roleConfigResponse = requestSession.post( url= 'http://stu.hfut.edu.cn/xsfw/sys/swpubapp/MobileCommon/getSelRoleConfig.do', data=configData) roleConfigResponse.raise_for_status() roleConfigJson = roleConfigResponse.json() if roleConfigJson['code'] != '0': # :( logger.info(f'处理roleConfig时发生错误:{roleConfigJson["msg"]}') return False, f'处理roleConfig时发生错误:{roleConfigJson["msg"]}' # get menu info menuInfoResponse = requestSession.post( url= 'http://stu.hfut.edu.cn/xsfw/sys/swpubapp/MobileCommon/getMenuInfo.do', data=configData) menuInfoResponse.raise_for_status() menuInfoJson = menuInfoResponse.json() if menuInfoJson['code'] != '0': # :( logger.info(f'处理menuInfo时发生错误:{menuInfoJson["msg"]}') return False, f'处理menuInfo时发生错误:{menuInfoJson["msg"]}' todayDateStr = "%.2d-%.2d-%.2d" % time.localtime()[:3] # if submitted ifSubmitted = requestSession.post( url= 'http://stu.hfut.edu.cn/xsfw/sys/swmxsyqxxsjapp/modules/mrbpa/judgeTodayHasData.do', data={'data': json.dumps({'TBSJ': todayDateStr})}) ifSubmittedJson = ifSubmitted.json() if len(ifSubmittedJson['data']) == 1: logger.info('今天已经打过卡了,处理结束') return 'have_done', '' # get setting... for what? requestSession.headers.pop('Content-Type') settingResponse = requestSession.get( url= 'http://stu.hfut.edu.cn/xsfw/sys/swmxsyqxxsjapp/modules/mrbpa/getSetting.do', data={'data': ''}) settingResponse.raise_for_status() settingJson = settingResponse.json() # get the form submitted last time requestSession.headers.update( {'Content-Type': 'application/x-www-form-urlencoded'}) lastSubmittedResponse = requestSession.post( url= 'http://stu.hfut.edu.cn/xsfw/sys/swmxsyqxxsjapp/modules/mrbpa/getStuXx.do', data={'data': json.dumps({'TBSJ': todayDateStr})}) lastSubmittedResponse.raise_for_status() lastSubmittedJson = lastSubmittedResponse.json() if lastSubmittedJson['code'] != '0': # something wrong with the form submitted last time logger.info('上次填报提交的信息出现了问题,本次最好手动填报提交。') return 'need_self', '' # get the form submitted yesterday todayDateStr_tmp = (date.today() + timedelta(days=-1)).strftime("%Y-%m-%d") yes_DateStr = f'{todayDateStr_tmp}-{username}' requestSession.headers.update( {'Content-Type': 'application/x-www-form-urlencoded'}) yes_SubmittedResponse = requestSession.post( url= 'http://stu.hfut.edu.cn/xsfw/sys/swmxsyqxxsjapp/modules/mrbpa/getStuXx.do', data={'data': json.dumps({ 'WID': yes_DateStr, 'TBSJ': todayDateStr })}) yes_SubmittedResponse.raise_for_status() yes_SubmittedJson = yes_SubmittedResponse.json() studentKeyResponse = requestSession.post( url= 'http://stu.hfut.edu.cn/xsfw/sys/swmxsyqxxsjapp/modules/mrbpa/studentKey.do', data={}) studentKeyJson = studentKeyResponse.json() # generate today's form to submit submitDataToday = lastSubmittedJson['data'] submitDataToday.update({ 'BY1': '1', 'DFHTJHBSJ': '', 'DZ_SFSB': '1', 'DZ_TBDZ': location, 'DZ_TBSJDZ': region, "DZ_AKMSFYC_DISPLAY": "否", "DZ_XCKSFYC_DISPLAY": "否", "DZ_AKMSFYC": "0", "DZ_XCKSFYC": "0", "DZ_SCAKMJT": yes_SubmittedJson['data']['DZ_SCAKMJT'], "DZ_SCXCKJT": yes_SubmittedJson['data']['DZ_SCXCKJT'], 'GCJSRQ': '', 'GCKSRQ': '', 'TBSJ': todayDateStr, 'studentKey': studentKeyJson['data']['studentKey'] }) paramKeyResponse = requestSession.post( url= 'http://stu.hfut.edu.cn/xsfw/sys/swmxsyqxxsjapp/modules/mrbpa/setCode.do', data={'data': json.dumps(submitDataToday)}) paramKeyJson = paramKeyResponse.json() # try to submit submitResponse = requestSession.post( url= 'http://stu.hfut.edu.cn/xsfw/sys/swmxsyqxxsjapp/modules/mrbpa/saveStuXx.do', data={'data': json.dumps(paramKeyJson['data'])}) submitResponse.raise_for_status() submitResponseJson = submitResponse.json() if submitResponseJson['code'] != '0': # failed logger.info(f'提交时出现错误:{submitResponseJson["msg"]}') return False, f'提交时出现错误:{submitResponseJson["msg"]}' # succeeded logger.info('提交成功') requestSession.headers.pop('Referer') requestSession.headers.pop('Content-Type') return 'success', ''
import os import asyncio import json from hoshino import Service, logger, priv from .submain import cpdaily_submit, single_submit # 首次启动时若配置文件不存在则自动生成配置文件 current_dir = os.path.join(os.path.dirname(__file__), 'config.json') if not os.path.exists(current_dir): init_data = {} with open(current_dir, 'w', encoding='UTF-8') as f: json.dump(init_data, f, indent=4, ensure_ascii=False) logger.info(f'cpdaily配置文件不存在,现已成功创建') sv_help = ''' [添加用户 学号 密码 QQ] 添加新用户 [删除用户 学号] 删除信息(限本人或维护组) [全员打卡] 全员手动打卡(限维护组) [单独打卡 学号] 顾名思义 [开启打卡邮件提醒 学号] 添加用户默认开启(限本人或维护组) [关闭打卡邮件提醒 学号] 不想要就关闭了它(限本人或维护组) [打卡用户列表] 看看所有用户 '''.strip() sv = Service('cpdaily_v2', help_=sv_help, enable_on_default=False, visible=False)
except: import json from hoshino import R, logger ImageFile.LOAD_TRUNCATED_IMAGES = True session = requests.session() apikey = '435221525ed48358ebab15' _setu_quene_file = os.path.expanduser('~/.hoshino/setu_quene_config.json') _setu_list = [] try: with open(_setu_quene_file, encoding='utf8') as f: _setu_list = json.load(f) logger.info( f'initial {len(_setu_list)} setu is put into the setu list') except FileNotFoundError as e: logger.warning( 'setu_quene_config.json not found, will create when needed.') def dump_setu_config(): with open(_setu_quene_file, 'w', encoding='utf8') as f: json.dump(_setu_list, f, ensure_ascii=False) def get_setu(): url = 'https://api.lolicon.app/setu/' params = {'apikey': apikey, 'r18': 0, 'num': 5, 'size1200': True} try: r = session.get(url=url, params=params, timeout=10)
async def get_poke(session: NoticeSession): ev = session.event logger.info(f'被{ev.user_id}戳了') if ev.self_id == ev['target_id']: uid = ev.user_id await session.send(MessageSegment(type_='poke', data={'qq': str(uid)}))
def reload_data(): importlib.reload(priconne_data) gen_name2id() logger.info('重载角色数据成功')