示例#1
0
def mediaseg(
    src: Union[str, Path],
    type_: Optional[Literal['image', 'record',
                            'video']] = None) -> MessageSegment:
    """生成图片、语音或短视频的MessageSegment

    Args:
        src (Union[str, Path]): 路径,会自动转化绝对路径
        type_ (Optional[Literal[, optional): 文件类型,如果不指定的话会依据文件后缀来判断是什么类型. Defaults to None.

    Returns:
        MessageSegment: 直接可发送的消息段
    """
    if type_ is None:
        if isinstance(src, str):
            src = Path(src)
        if src.suffix in ('.jpg', '.png', '.jpeg', '.gif'):
            return MessageSegment.image('file:///' + str(src.resolve()))
        elif src.suffix in ('.mp3', '.aac', '.amr', '.wav', '.m4a'):
            return MessageSegment.record('file:///' + str(src.resolve()))
        elif src.suffix in ('.mp4', '.flv', '.m4v'):
            return MessageSegment.video('file:///' + str(src.resolve()))
        else:
            logger.error(f'Unkwon or unsupported file format with {src}')
    else:
        return MessageSegment(type=type_,
                              data={"file": 'file:///' + str(src.resolve())})
示例#2
0
def localize(url: str, filename: str, failed_times: int = 0) -> Optional[str]:
    """本地化图片存储在语料库图片文件夹

    Args:
        url (str): 要下载的url
        filename (str): 下载后存储的文件名称
        failed_times (int, optional): 初始失败次数. Defaults to 0.

    Returns:
        Optional[str]: 成功下载会返回下载后的文件储存路径,否则返回None
    """

    searchfile = CORPUS_IMAGES_PATH.glob(filename.split('.')[0] + ".*")
    for f in searchfile:
        fp = f
        logger.debug(f'File [{filename}] has localized with {fp}')
        return fp.name
    fp = CORPUS_IMAGES_PATH / filename
    try:
        urlretrieve(url, fp)
        realpath = fp.with_suffix('.' + what(fp))  # 修复文件为真正的后缀
        fp.rename(realpath)
        logger.info(f'Localize image [{filename}] with path: {realpath.name}')
        return realpath.name
    except Exception as err:
        failed_times += 1
        logger.warning(
            f'Download file [{url}] error {failed_times} times: {err}')
        if failed_times < 6:
            return localize(url, filename, failed_times=failed_times)
        else:
            logger.error(
                f'Can not download file [{url}] with filename[{fp}]: {err}')
            return None
示例#3
0
 def __exit__(self, exc_type, exc_val, exc_tb):
     if exc_type is None:
         if self.q is False:
             self.commit()
         self.close()
     else:
         logger.error(
             f'EXCType: {exc_type}; EXCValue: {exc_val}; EXCTraceback: {exc_tb}'
         )
示例#4
0
def ai_chat(query):
    try:
        params = {
            "Query": query
        }
        req.from_json_string(json.dumps(params))
        resp = client.ChatBot(req)
        return resp.Reply, resp.Confidence

    except TencentCloudSDKException as err: 
        logger.error(err)
示例#5
0
async def save_img(url: str, filepath: Union[str, Path]):
    '''
    存储网络图片并将filepath文件名自动更正成正确的后缀
    '''
    async with httpx.AsyncClient() as client:
        resp = await client.get(url, timeout=600)
    if resp.status_code != httpx.codes.OK:
        logger.error(f'Filed to request url: {url}')
        # print(f'Filed to request url: {url}')
        return
    if not isinstance(filepath, Path):
        filepath = Path(filepath)
    filepath.write_bytes(resp.content)
    real_suffix = f".{what(filepath).replace('jpeg', 'jpg')}"
    if real_suffix != filepath.suffix.lower():
        filepath.rename(filepath.with_suffix(real_suffix))
    return filepath
示例#6
0
def update_prob(sid: Union[int, Tuple[int, int]], prob: int):
    """更新出现率

    Args:
        sid (Union[int, Tuple[int, int]]): 对话id,若要更新多个则传入最小id和最id组成的数组
        prob (int): 更新后的出现率
    """
    if prob < 0 or prob > 100:
        logger.error(f'Probability {prob} out of range!')
        return
    with QbotDB() as qb:
        if isinstance(sid, int):
            qb.update('UPDATE corpus SET probability=%s WHERE id=%s;',
                      (prob, sid))
        else:
            min_, max_ = sid
            qb.update(
                f'UPDATE corpus SET probability=%s WHERE id BETWEEN %s AND %s;',
                (prob, min_, max_))
示例#7
0
    def run(self, yaml_name=webConfig.LOGIN_SUCCESS, case_name=None):
        yaml_path = find_file(WebConfig.yaml_path, yaml_name + '.yaml')
        yaml_data = YamlReader(yaml_path).data
        self.scenarios = yaml_data[0].get('scenarios')
        self.setCase(case_name)
        requests = self.getRequests()

        if self.browser is None:
            self.openDefaultBrowser()

        img = None
        msg = '【%s】场景开始执行' % self.getCaseName()
        print(msg)
        logger.info(msg)
        for request in requests:
            msg = 'label:【%s】' % request.get('label')
            print(msg)
            logger.info(msg)
            for action in request.get('actions'):
                logger.info('action:%s' % action)
                if action == 'getScreenshot()':
                    time.sleep(1)
                    self.success_img.append(
                        self.browser.driver.get_screenshot_as_base64())
                    continue
                try:
                    msg = self.doAction(action)
                    if yaml_name != webConfig.LOGIN_SUCCESS:
                        print(msg)
                    logger.info(msg)
                except Exception as e:
                    print(str(e))
                    logger.error(str(e))
                    img = self.browser.driver.get_screenshot_as_base64()
                    self.imgs.append(img)
                    return False

        result = True if img is None else False
        return result
示例#8
0
async def send_others(bot: Bot, event: MessageEvent, state: T_State):
    # msg = MessageSegment.reply(id_=event.message_id) if event.message_type == 'group' else MessageSegment.text('')
    if state['img_type'] == 'meizi':
        call = get_nmb(False)
    elif state['img_type'] == 'photo':
        call = get_pw(False)
    elif state['img_type'] == 'bg':
        if state['lx'] in ('acg', '小姐姐', '风景', '随机'):
            lx = state['lx'].replace('acg', 'dongman').replace('小姐姐', 'meizi').replace('风景', 'fengjing').replace('随机', 'suiji')
        elif state['lx'] is not None:
            msg = MessageSegment.text( f'没有{state["lx"]}类型的壁纸')
            await rand_img.finish(reply_header(event, msg))
        else:
            lx = 'suiji'
        if state['pc'] is not None and state['pc'] == '手机':
            state['pc'] = 'mobile'
        call = get_sjbz(state['pc'], lx)
    elif state['img_type'] == 'acg':
        call = choice((get_asmdh(), get_nmb(True), get_pw(True)))

    logger.debug(f'调用杂图API: {call.__name__}')
    try:
        result = await call
    except httpx.HTTPError as e:
        logger.exception(e)
        msg = MessageSegment.text('图片丢掉了,要不你再试试?')
        await rand_img.finish(reply_header(event, msg))

    if isinstance(result, str):
        img = MessageSegment.image(result)
    elif isinstance(result, int):
        logger.error(f'{call.__name__} 失效,状态码: {result}')
        await rand_img.finish(reply_header(event, '这个API可能挂掉了,如果一直不好使就只好停用这个功能了'))
    else:
        img = imgseg(result)
    
    await rand_img.send(reply_header(event, img))
    return 'completed'
async def ofl_rmd(bot: Bot):
    dc_time = datetime.now().time().strftime("%H:%M:%S")
    logger.critical(f'Bot {bot.self_id} disconnected')

    ol_bots = [bt for strid, bt in get_bots().items()]
    if ol_bots:
        while ol_bots:
            notifier: Bot = choice(ol_bots)
            try:
                for su in SUPERUSERS:
                    await notifier.send_private_msg(
                        user_id=su,
                        message=f' {bot.self_id}disconnected at {dc_time}')
                break
            except BaseException as err:
                logger.error(
                    f'Bot {notifier.self_id} failed to send offline notification: {err}'
                )
                ol_bots.remove(notifier)
        else:
            logger.error(f'All bots failed to send notification!')

    else:
        logger.critical('There is no bot can send notification!')
示例#10
0
APP_ID = dict(cfg.items('key'))['app_id']
APP_KEY = dict(cfg.items('key'))['app_key']


try: 
    cred = credential.Credential(APP_ID, APP_KEY) 
    httpProfile = HttpProfile()
    httpProfile.endpoint = "nlp.tencentcloudapi.com"

    clientProfile = ClientProfile()
    clientProfile.httpProfile = httpProfile
    client = nlp_client.NlpClient(cred, "ap-guangzhou", clientProfile) 

    req = models.ChatBotRequest()
except TencentCloudSDKException as err: 
    logger.error(err)


def ai_chat(query):
    try:
        params = {
            "Query": query
        }
        req.from_json_string(json.dumps(params))
        resp = client.ChatBot(req)
        return resp.Reply, resp.Confidence

    except TencentCloudSDKException as err: 
        logger.error(err)

    
示例#11
0
async def send_lolicon(bot: Bot, event: MessageEvent, state: T_State):

    gid = event.group_id if event.message_type=='group' else 0
    if gid:
        if str(gid) not in sl_settings:
            await setu.finish('''先设置本群sl再使用此功能吧
[设置sl 最小sl-最大sl]
例如:设置sl 0-4
────────────
sl说明:
大概可以解释成本群能接收的工口程度,sl越高的图被人看见越会触发社死事件
※ r18权限已改为sl, 当最大sl为5时即为开启r18权限,sl0-4级别仅适用于美图,色图会自动忽略
最低sl0:不含任何ero要素,纯陶冶情操,也有一部分风景图
最高sl5: 就是R18了
中间的等级依次过渡''')

        max_sl = sl_settings[str(gid)]['max_sl']
        min_sl = sl_settings[str(gid)]['min_sl']
        restricted = True if max_sl < 5 else False  # r18是否在本群受限
    else:
        restricted = False

    # 限制条件优先度:r18,5张最大数,等级限制数量,频率,资金,由于要检测参数只好先把个别参数解析混入条款中了
    uid = event.user_id

    # r18限制条款,顺便解析了r18
    r18_call = state["_matched_dict"]['r18_call'] or state["_matched_dict"]['r18_call2']
    if r18_call and restricted:
        await setu.finish(reply_header(event, f'当前群内最大sl为{max_sl},已禁止R18内容'))

    # 5张最大数量限制条款,顺便解析了num
    if state["_matched_dict"]['num']:
        num = cn2an(state["_matched_dict"]['num'].replace('两', '二'), 'smart')
    elif state["_matched_dict"]['num2']:
        num = cn2an(state["_matched_dict"]['num2'].replace('两', '二'), 'smart')
    else:
        num = 1

    if num > 5:
        await setu.finish(reply_header(event, '一次最多只能要5张'))
    elif num == 0:
        await setu.finish(reply_header(event, '你好奇怪的要求'))
    elif num < 0:
        await setu.finish(reply_header(event, f'好的,你现在欠大家{-num}张涩图,快发吧'))  # TODO: 想想办法把负数给提取出来

    # 等级限制数量条款,注册了用户信息
    userinfo = UserLevel(uid)
    if userinfo.level < num:
        if userinfo.level > 0:
            await setu.finish(f'您当前等级为{userinfo.level},最多一次要{userinfo.level}张')
        elif num > 1:
            await setu.finish(reply_header(event, '啊这..0级用户一次只能叫一张哦,使用[签到]或者学习对话可以提升等级~'))

    # 频率限制条款,注册了频率限制器
    flmt = FreqLimiter(uid, 'setu')
    if not flmt.check():
        refuse = f'你冲得太快了,请{ceil(flmt.left_time())}秒后再冲'  # 不用round主要是防止出现'还有0秒'的不科学情况
        if userinfo.level == 0:
            refuse += ',提升等级可以加快装填哦~'
        await setu.finish(reply_header(event, refuse))
    cd = cd_step(userinfo.level, 480)  # 冷却时间
    flmt.start_cd(cd)  # 先进行冷却,防止连续呼叫击穿频率装甲,要是没返回图的话解掉

    # 资金限制条款,注册了每日次数限制器
    cost = num * 3
    dlmt = DailyNumberLimiter(uid, '色图', 3)
    in_free = True if event.message_type == 'private' and event.sub_type == 'friend'\
            else dlmt.check(close_conn=False)  # 来自好友的对话不消耗金币

    if userinfo.fund < cost and not in_free:
        if userinfo.fund > 0:
            refuse = choice((f'你还剩{userinfo.fund}块钱啦,要饭也不至于这么穷吧!', f'你只剩{userinfo.fund}块钱了,要不考虑援交一下赚点钱?'))
        elif userinfo.level == 0 and userinfo.fund == 0:
            refuse = '每天有三次免费次数哦,使用[签到]领取资金来获得更多使用次数吧~'
        else:
            refuse = '你已经穷得裤子都穿不起了,到底是做了什么呀?!'
        dlmt.conn.close()  # 确认直接结束不会增加调用次数了,直接返还链接
        flmt.start_cd(0)
        await setu.finish(reply_header(event, refuse))

    kwd = state["_matched_dict"]['kwd'] or ''

    if r18_call:
        r18 = 1 if r18_call in ('r18', 'R18') else 0      
    else:
        if event.message_type == 'group':
            if max_sl < 5:
                r18 = 0
            elif min_sl == 5:
                r18 = 1
            elif min_sl < 5:
                r18 = 2
        else:
            r18 = 2
    
    msg = MessageSegment.reply(id_=event.message_id) if event.message_type == 'group' else MessageSegment.text('') # 由于当前私聊回复有bug所以只在群里设置信息开始为回复消息

    # 有搜索条件,从本地库中提
    if kwd:
        kwds = tuple(kwdrex.split(kwd))
        success, result = get_setu(gid, kwds, num, r18)
        if not success:
            flmt.start_cd(0)
            dlmt.conn.close()
            await setu.finish(reply_header(event, result))

        count = result['count']  # 返回数量,每次处理过后自减1
        miss_count = 0  # 丢失数量
        for data in result['data']:
            if data is None:
                miss_count += 1
                continue
            img : Path = data['file']
            logger.debug(f'当前处理本地图片{img.name}')
            info = f"{data['title']}\n画师:{data['author']}\nPID:{data['source']}\n"
            try:
                im_b64 = Image_Handler(img).save2b64()
            except OSError as err:
                miss_count += 1
                logger.error(f'File {img} may be damaged: {err}')
                continue
            except UnidentifiedImageError as imgerr:
                miss_count += 1
                logger.error(f'failed to open local file: {img}: {imgerr}')
                continue
            msg += MessageSegment.text(info) + MessageSegment.image(im_b64)
            if count > 1:
                msg += MessageSegment.text('\n=====================\n')
                count -= 1
            elif result['count'] < num:
                msg += MessageSegment.text(f'\n=====================\n没搜到{num}张,只搜到这些了')

    # 无搜索条件,链接API,5次错误退出并反馈错误
    else:
        logger.debug('Start getting lolicon API')
        failed_time = 0
        while failed_time < 5:
            try:
                result = await get_lolicon(kwd, r18, num)
                break
            except BaseException as e:
                failed_time += 1
                logger.exception(f"connect api faild {failed_time} time(s)\n{e}")
        else:
            logger.error(f'多次链接API失败,当前参数: kwd: [{kwd}], num: {num}, r18: {r18}')
            dlmt.conn.close()
            flmt.start_cd(0)
            await setu.finish('链接API失败, 若多次失败请反馈给维护组', at_sender=True)
        logger.debug('Receive lolicon API data!')

        # 处理数据
        if result['code'] == 0:
            count = result['count']  # 返回数量,每次处理过后自减1
            untreated_ls = []  # 未处理数据列表,遇到本地库中没有的数据要加入这个列表做并发下载
            miss_count = 0  # 丢失数量
            for data in result['data']:
                pid = data['pid']
                p = data['p']
                name = f'{pid}_p{p}'
                # 按 色图备份路径->美图原文件路径 顺序查找本地图,遇到没有本地路径的等待并发下载处理
                imgbkup = [f for f in Path(SETUPATH).glob(f'{name}.[jp][pn]*g')]
                if imgbkup:
                    img = imgbkup[0]
                else:
                    imgorg = [f for f in (Path(MEITUPATH)/'origin_info').rglob(f'{name}.[jp][pn]*g')]
                    if imgorg:
                        img = imgorg[0]
                    else:
                        untreated_ls.append(data)
                        continue
                logger.debug(f'当前处理本地图片{name}')
                info = f"{data['title']}\n画师:{data['author']}\nPID:{name}\n"
                try:
                    im_b64 = Image_Handler(img).save2b64()
                except UnidentifiedImageError as imgerr:
                    miss_count += 1
                    logger.error(f'failed to open local file: {img}: {imgerr}')
                    continue
                msg += MessageSegment.text(info) + MessageSegment.image(im_b64)
                if count > 1:
                    msg += MessageSegment.text('\n=====================\n')
                    count -= 1
                elif result['count'] < num:
                    msg += MessageSegment.text(f'\n=====================\n没搜到{num}张,只搜到这些了')
                
            # 对未处理过的数据进行并发下载,只下载1200做临时使用
            async with httpx.AsyncClient() as client:
                task_ls = []
                for imgurl in [d['url'] for d in untreated_ls]:
                    task_ls.append(client.get(get_1200(imgurl), timeout=120))
                imgs = await gather(*task_ls, return_exceptions=True)
                
            for i, data in enumerate(untreated_ls):
                if isinstance(imgs[i], BaseException):
                    miss_count += 1
                    logger.exception(data)
                    continue
                if imgs[i].status_code != httpx.codes.OK:
                    miss_count += 1
                    logger.error(f'Got unsuccessful status_code [{imgs[i].status_code}] when visit url: {imgs[i].url}')
                    continue
                pid = data['pid']
                p = data['p']
                name = f'{pid}_p{p}'
                info = f"{data['title']}\n画师:{data['author']}\nPID:{name}\n"
                logger.debug(f'当前处理网络图片{name}')
                try:
                    im_b64 = Image_Handler(imgs[i].content).save2b64()
                except BaseException as err:
                    logger.error(f"Error with handle {name}, url: [{data['url']}]\n{err}")
                    miss_count += 1
                    continue

                msg += MessageSegment.text(info) + MessageSegment.image(im_b64)
                if count > 1:
                    msg += MessageSegment.text('\n=====================\n')
                    count -= 1
                elif result['count'] < num:
                    msg += MessageSegment.text(f'\n=====================\n没搜到{num}张,只搜到这些了')
            if miss_count > 0 and num > 1:
                msg += MessageSegment.text(f'\n有{miss_count}张图丢掉了,{BOTNAME}也不知道丢到哪里去了T_T')
            elif miss_count == 1:
                msg += MessageSegment.text(f'{BOTNAME}拿来了图片但是弄丢了呜呜T_T')
        else:
            flmt.start_cd(0)
            dlmt.conn.close()
            await setu.finish(msg + MessageSegment.text('获取涩图失败,请稍后再试'))

    try:
        await setu.send(msg)
    except NetworkError as err:
        logger.error(f'Maybe callout error happend: {err}')
    except AdapterException as err:
        logger.error(f"Some Unkown error: {err}")

    if miss_count < result['count']:
        if not in_free:
            cost = (result['count'] - miss_count) * 3  # 返回数量可能少于调用量,并且要减去miss的数量
            userinfo.turnover(-cost)  # 如果超过每天三次的免费次数则扣除相应资金
        dlmt.increase()  # 调用量加一
    else:
        flmt.start_cd(0)  # 一张没得到也刷新CD
        dlmt.conn.close()

    # 下载原始图片做本地备份
    if not kwd:
        async with httpx.AsyncClient() as bakeuper:
            backup_ls = []
            json_ls = []
            for info in untreated_ls:
                url = info['url']
                json_data = {
                    'pid': info['pid'],
                    'p': info['p'],
                    'uid': info['uid'],
                    'title': info['title'],
                    'author': info['author'],
                    'url': url,
                    'r18': info['r18'],
                    'tags': info['tags']
                }
                backup_ls.append(bakeuper.get(url, timeout=500))
                json_ls.append(json_data)
            origims = await gather(*backup_ls, return_exceptions=True)
            for i, im in enumerate(origims):
                if isinstance(im, BaseException):
                    logger.exception(im)
                    continue
                if im.status_code != httpx.codes.OK:
                    logger.error(f'Got unsuccessful status_code [{im.status_code}] when visit url: {im.url}')
                    continue
                imgfp = Path(SETUPATH)/(str(json_ls[i]['pid']) + '_p' + str(json_ls[i]['p']) + '.' + json_ls[i]['url'].split('.')[-1])
                jsonfp = Path(SETUPATH)/(str(json_ls[i]['pid']) + '_p' + str(json_ls[i]['p']) + '.json')
                try:
                    with imgfp.open('wb') as f:
                        f.write(im.content)
                    logger.info(f'Downloaded image {imgfp.absolute()}')
                except BaseException as e:
                    logger.exception(e)
                with jsonfp.open('w', encoding='utf-8') as j:
                    json.dump(json_ls[i], j, ensure_ascii=False, escape_forward_slashes=False, indent=4)
                    logger.info(f'Generated json {jsonfp.absolute()}')
                increase_setu(**json_ls[i])
示例#12
0
def get_mitu(gid: int,
             kwd: tuple = (),
             num: int = 1,
             min_sl: int = 0,
             max_sl: int = 1):
    """从数据库中获得美图数据

    Args:
        gid (int): 呼叫美图的群号,相同群内会有两个小时的记录去重
        kwd (tuple, optional): 关键词,元组内的词会做交集查询. Defaults to ().
        num (int, optional): 查询数量. Defaults to 1.
        min_sl (int, optional): 最小的sl值. Defaults to 0.
        max_sl (int, optional): 最大的sl值. Defaults to 1.

    Returns:
        tuple: 返回是否调用成功以及返回的结果,如果没有查询结果会返回无结果还是结果已经用尽,如果有结果会返回数据列表
        数据结构:{
                'title' (str): 作品名,
                'author' (str): 作者,
                'source' (str): 来源, Pixiv pid_p
                'sl' (int): sl级别,
                'file' (int): 文件路径
                }
    """
    if gid not in Called_Data:
        Called_Data[gid] = Group_Called(gid)
    his = Called_Data[gid]
    kwds = "%" + '%'.join(kwd) + "%"  # like查询要在两边加上%占位符
    kwds_demojize = demojize(kwds)  # 查询数据库要用转义为普通字符的emoji
    with GalleryDB() as glrdb:
        # TODO: 优化随机查询的方式取代orded by rand()
        if len(his.called) > 1:
            cmd = f'''select title, author, source, sl, visits, id from gallery
            where sl between %s and %s and id not in {tuple(his.called)}
            and (tags like %s or title like %s or author like %s)
            ORDER BY RAND() LIMIT %s;'''
        else:
            cmd = '''select title, author, source, sl, visits, id from gallery
            where sl between %s and %s and (tags like %s or title like %s or author like %s)
            ORDER BY RAND() LIMIT %s;'''
        params = (min_sl, max_sl, kwds_demojize, kwds_demojize, kwds_demojize,
                  num)
        results = glrdb.queryall(cmd, params)
        # 随机查询不在called列表中的图片
        if not results:
            if kwds in his.called_kwds:
                return False, f'暂时没有更多关于"{kwds.replace("%", "|")[1:-1]}"的美图了'
            else:
                return False, f'没有找到关于"{kwds.replace("%", "|")[1:-1]}"的美图'  # TODO: 换了标签之后再搜索到相同的图用这个标签不太合适,换成"有x张相关图刚才已经发过了"
        mitu_ls = []  # 所有美图列表
        for record in results:
            if record[2].startswith(
                    'Pixiv'):  # 暂时只有pixiv图片,加入非p站图片之后要增加拼装文件名方法
                filestem = record[2][6:]  # 名字是去掉Pixiv 前缀剩下的pid_p
            searchfile = glob.glob(
                str(Path(MEITUPATH) / ('sl' + str(record[3])) / (filestem)) +
                '.[jp][pn]*g')  # 从本地图库中搜索图片,暂时只搜索jpg, png, jpeg,正常情况应该只能搜到一个

            if not searchfile:
                logger.error(f'Not found file {filestem}')
                mitu_ls.append(None)
                continue
            elif len(searchfile) > 1:
                logger.warning(f'查找到多个名称为{filestem}的图片,请检查图库')
            logger.debug(f'Found {len(searchfile)} file(s):' +
                         '\n'.join(searchfile))
            data = {
                'title': emojize(record[0]),
                'author': emojize(record[1]),
                'source': record[2],
                'sl': record[4],
                'file': searchfile[0]
            }
            mitu_ls.append(data)

            his.called.add(record[5])  # 添加id记录

        his.called_kwds.add(kwds)  # 添加关键词记录
        his.check_expired()  # 检查记录是否过期
        if len(results) == 1:
            increase_cmd = "UPDATE gallery SET visits=visits+1 WHERE id=%s;"
            increase_parm = (results[0][5], )
        else:
            id_ls = str(tuple([r[5] for r in results]))  # 如果有多条记录就传入元组同时加1
            increase_cmd = f"UPDATE gallery SET visits=visits+1 WHERE id in {id_ls};"
            increase_parm = ()
        glrdb.update(increase_cmd, increase_parm)  # 调用次数加一

        return True, mitu_ls