Esempio n. 1
0
    async def on_message(self, msg: Message):
        if msg.is_self():  # for self testing
            if msg.type() == MessageType.MESSAGE_TYPE_IMAGE or msg.type(
            ) == MessageType.MESSAGE_TYPE_EMOTICON:
                st_time = time.time()
                try:
                    ret_json = await self.msg_handler(msg)
                except KeyError as e:  # echoing meme image have no keys
                    print(str(e))
                    return
                except (requests.exceptions.ConnectionError
                        or requests.exceptions.ConnectTimeout) as e:
                    await msg.say('访问后端出错:' + str(e))
                    return
                # example returning json: {'img_name': '/001/001.jpg', 'md5': 'ff7bd2b664bf65962a924912bfd17507'}
                if ret_json['md5'] in self.cache_dict:  # hit cache
                    ret_path: str = self.cache_dict[ret_json['md5']]
                    if 'log' in ret_json:
                        ret_json['log'] += '\n回复图片命中缓存!'
                else:
                    ret_img = self.s.get(
                        url=self.config_dict['backend']['backend_static_url'] +
                        ret_json['img_name'])
                    if not str(ret_img.status_code).startswith(
                            '2'):  # not 2XX response code
                        raise FileNotFoundError(
                            "Can't get img from URL {}, with HTTP status code {}"
                            .format(
                                self.config_dict['backend']
                                ['backend_static_url'] + ret_json['img_name'],
                                str(ret_img.status_code)))
                    ret_path = os.path.join(
                        self.config_dict['general']['image_temp_dir'],
                        str(uuid.uuid4()) + os.path.extsep +
                        ret_json['img_name'].split('.')[-1])
                    with open(ret_path, 'wb') as f:
                        f.write(ret_img.content)
                    self.cache_dict[ret_json['md5']] = ret_path
                ret_json['log'] += '\n前后端交互耗时:%.2fs' % (time.time() - st_time)

                if self.debug and 'log' in ret_json:
                    await msg.say(ret_json['log'])

                with open(ret_path, 'rb') as f:
                    content: str = base64.b64encode(f.read())
                    ret_img = FileBox.from_base64(
                        name=os.path.basename(ret_path), base64=content)
                    # file_box = FileBox.from_url(
                    #     'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/'
                    #     'u=1116676390,2305043183&fm=26&gp=0.jpg',
                    #     name='ding-dong.jpg')
                    # await msg.say(file_box)
                    # ret_img = FileBox.from_file(ret_path)
                    await msg.say(ret_img)
Esempio n. 2
0
 async def contact_avatar(self, contact_id: str,
                          file_box: Optional[FileBox] = None) -> FileBox:
     """get the contact avatar"""
     contact_payload = self.mocker.environment.\
         get_contact_payload(contact_id)
     if not file_box:
         return FileBox.from_base64(
             contact_payload.avatar,
             name=f'{contact_payload.name}.png'
         )
     contact_payload.avatar = file_box.base64
     self.mocker.environment.update_contact_payload(contact_payload)
 async def message_file(self, message_id: str) -> FileBox:
     """
     extract file from message
     :param message_id:
     :return:
     """
     if self.puppet_stub is None:
         raise Exception('puppet_stub should not be none')
     response = await self.puppet_stub.message_file(id=message_id)
     json_response = json.loads(response.filebox)
     if 'base64' not in json_response:
         raise Exception('file response data structure is not correct')
     file_box = FileBox.from_base64(json_response['base64'],
                                    name=json_response['name'])
     return file_box
Esempio n. 4
0
 async def message_image(self, message_id: str, image_type: ImageType = 3
                         ) -> FileBox:
     """
     get message image data
     :param message_id:
     :param image_type:
     :return:
     """
     response = await self.puppet_stub.message_image(id=message_id, type=image_type)
     json_response = json.loads(response.filebox)
     if 'base64' not in json_response:
         raise WechatyPuppetGrpcError('image response data structure is not correct')
     file_box = FileBox.from_base64(
         json_response['base64'],
         name=json_response['name']
     )
     return file_box
Esempio n. 5
0
    async def on_message(self, msg: Message):
        from_contact = msg.talker()
        if msg.is_self():  # for self testing
            if msg.type(
            ) == MessageType.MESSAGE_TYPE_IMAGE or MessageType.MESSAGE_TYPE_EMOTICON:
                ret_json = await self.msg_handler(msg)
                # example returning json: {'img_name': '/001/001.jpg', 'md5': 'ff7bd2b664bf65962a924912bfd17507'}
                if ret_json['md5'] in self.cache_dict:  # hit cache
                    ret_path = self.cache_dict[ret_json['md5']]
                    if 'log' in ret_json:
                        ret_json['log'] += '\n回复图片命中缓存!'
                else:
                    ret_img = self.s.get(url=config.backend_static_url +
                                         ret_json['img_name'])
                    if not str(ret_img.status_code).startswith(
                            '2'):  # not 2XX response code
                        raise FileNotFoundError(
                            "Can't get img from URL {}, with HTTP status code {}"
                            .format(
                                config.backend_static_url +
                                ret_json['img_name'],
                                str(ret_img.status_code)))
                    ret_path = os.path.join(
                        config.image_temp_dir,
                        str(uuid.uuid4()) + '.' +
                        ret_json['img_name'].split('.')[-1])
                    with open(ret_path, 'wb') as f:
                        f.write(ret_img.content)
                    self.cache_dict[ret_json['md5']] = ret_path
                # ret_path = os.path.join(config.image_temp_dir, '0c4baea3-9792-4d07-8ec0-4fd62afd6117.jpg')
                if self.debug and 'log' in ret_json:
                    await msg.say(ret_json['log'])

                with open(ret_path, 'rb') as f:
                    content: str = base64.b64encode(f.read())
                    ret_img = FileBox.from_base64(
                        name=os.path.basename(ret_path), base64=content)
                    await msg.say(ret_img)
Esempio n. 6
0
    async def on_message(self, msg: Message):

        # 加载消息发送者
        talker = msg.talker()
        await talker.ready()

        # 忽略自己发的消息
        if talker.contact_id == self.my_contact_id:
            return

        # 加载聊天室信息
        room = msg.room()
        room_topic = None
        if room:
            await room.ready()
            room_topic = await room.topic()

        # 基本信息
        msg_text = msg.text()
        msg_text_inline = msg.text().replace('\n', '')
        msg_type = msg.message_type()
        msg_id = msg.message_id
        if msg_type == 6:
            log.info('Received text, msg_type = {}, id = {}'.format(
                msg_type, msg_id))
        else:
            log.info('Received text = {}, msg_type = {}, id = {}'.format(
                msg_text, msg_type, msg_id))

        # 保存聊天记录
        insert_data = {
            'contact_id': talker.contact_id,
            'contact_name': talker.name,
            'room_id': room.room_id if room else None,
            'room_name': room_topic,
            'msg_id': msg_id,
            'msg_text': msg_text[:20],
            'created_at': datetime.now()
        }
        keys = ','.join(['`{}`'.format(str(v)) for v in insert_data.keys()])
        values = ','.join(
            ['\'{}\''.format(str(v)) for v in insert_data.values()])
        sql = 'INSERT INTO {table}({keys}) VALUES({values})'.format(
            table='msg_records', keys=keys, values=values)
        try:
            self.db.cursor.execute(sql)
            self.db.db.commit()
        except Exception as e:
            log.error(e)
            self.db.db.rollback()

        # 鉴定是否为广告
        if room and not re.match(r'.*(kda|kadena|可达).*',
                                 msg_text_inline.lower()):
            is_ad = False
            if msg_type == 4:
                pass
            elif msg_type == 5:
                # 识别是否有二维码
                img = await msg.to_file_box()
                log.info('get img {}'.format(img.name))
                img_path = './images/{}'.format(img.name)
                img_file = await img.to_file(img_path)
                log.info('get img stored')
                img = cv2.imread(img_path)
                data, bbox, straight_qrcode = self.detector.detectAndDecode(
                    img)
                log.info('qrcode results: {}, {}, {}'.format(
                    data, bbox, straight_qrcode))
                if bbox is not None:
                    log.info('ad detected qr_code')
                    is_ad = True
                os.remove(img_path)
            elif msg_type == 6:
                if len(msg_text) >= 50 and re.match(
                        r'.*(http|空投|撸).*',
                        msg_text) and not re.match(r'.*bihu\.com.*', msg_text):
                    log.info('ad detected text')
                    is_ad = True

            if is_ad:
                sql = """SELECT count(*) as msg_cnt FROM {} where contact_id = '{}'""".format(
                    'msg_records', talker.contact_id)
                self.db.cursor.execute(sql)
                if list(self.db.cursor.fetchall())[0]['msg_cnt'] < 10:
                    q_list = list(self.ad_qa_dict.keys())
                    question = q_list[random.randrange(0, len(q_list))]
                    threading.Thread(target=self.kick_member,
                                     args=(talker, room, question)).start()
                    reply = '@{}\n你有打广告的嫌疑哦,请在15秒内回答以下问题,否则给你抱出去~~~\n{}'.format(
                        talker.name, question)
                    await room.say(reply, mention_ids=[talker.contact_id])
                    return

        # GOD的指令
        if talker.contact_id == self.god_contact_id and 'c/' in msg_text:
            if 'c/new' in msg_text:
                if '上一条' in msg_text:
                    sql = """SELECT msg_id FROM {} where contact_id = '{}' order by created_at desc""".format(
                        'msg_records', self.god_contact_id)
                    self.db.cursor.execute(sql)
                    refer_msg_id = list(self.db.cursor.fetchall())[1]['msg_id']
                    title = msg_text
                else:
                    root = ET.fromstring(msg_text)
                    refer_msg_id = root.find('.//refermsg//svrid').text
                    title = root.find('.//title').text
                keyword = re.findall('#.+#', title)[0].replace('#', '')
                log.info('title = {}, keyword = {}'.format(title, keyword))
                insert_data = {
                    'keyword': keyword,
                    'msg_id': refer_msg_id,
                    'created_at': datetime.now()
                }
                keys = ','.join(
                    ['`{}`'.format(str(v)) for v in insert_data.keys()])
                values = ','.join(
                    ['\'{}\''.format(str(v)) for v in insert_data.values()])
                sql = 'INSERT INTO {table}({keys}) VALUES({values})'.format(
                    table='materials', keys=keys, values=values)
                try:
                    self.db.cursor.execute(sql)
                    self.db.db.commit()
                    log.info('INSERT succesfully: {}'.format(sql))
                except Exception as e:
                    log.error(e)
                    self.db.db.rollback()

                reply = '指令已储存,关键词:{}'.format(keyword)
                await msg.say(reply)

            elif 'c/list' in msg_text:
                sql = """SELECT keyword FROM {} group by keyword""".format(
                    'materials')
                self.db.cursor.execute(sql)
                reply = '现有指令'
                for row in self.db.cursor.fetchall():
                    reply += '\n' + row['keyword']

                await msg.say(reply)

            elif 'c/show' in msg_text:
                keyword = re.findall('#.+#', msg_text)[0].replace('#', '')
                await self.send_msg_with_keyword(keyword,
                                                 contact=talker,
                                                 room=room)

            elif 'c/active' in msg_text:
                today = datetime.now()
                start_dt = datetime(today.year, today.month, today.day)
                sql = """SELECT contact_id, count(*) as msg_cnt
                        FROM {} where room_id = '{}' and created_at >= '{}'
                        group by contact_id""".format('msg_records',
                                                      room.room_id, start_dt)
                self.db.cursor.execute(sql)
                records = [
                    row['contact_id'] for row in self.db.cursor.fetchall()
                ]
                member_list = await room.member_list()
                reply = '今日群内未发言成员:'
                for member in member_list:
                    if member.contact_id != self.my_contact_id and member.contact_id not in records:
                        reply += '\n' + member.name

                topic = await room.topic()
                if '星火' in topic:
                    reply += '\n如果没法保持每天活跃,会被移出此群哦~'
                await msg.say(reply)

            elif 'c/fixroomname' in msg_text:
                log.info('to fix room name')
                sql = """SELECT * FROM {} WHERE room_id is not null and room_name = ''""".format(
                    'msg_records')
                self.db.cursor.execute(sql)
                for row in self.db.cursor.fetchall():
                    to_fix_room = self.Room(room_id=row['room_id'])
                    await to_fix_room.ready()
                    to_fix_room_name = await to_fix_room.topic()

                    sql = """UPDATE {} SET room_name = '{}' where id = {}""".format(
                        'msg_records', to_fix_room_name, row['id'])
                    try:
                        self.db.cursor.execute(sql)
                        self.db.db.commit()
                        log.info('update succesfully: {}'.format(sql))
                    except Exception as e:
                        log.error(e)
                        self.db.db.rollback()

                log.info('finished')

            elif 'c/kdashill_to_tg' in msg_text:
                log.info('to send telegram')
                sql = """SELECT * FROM {} WHERE has_sent_tg is null""".format(
                    'kdashill_records')
                self.db.cursor.execute(sql)
                for row in self.db.cursor.fetchall():
                    url = 'https://m.bihu.com/shortcontent/{}'.format(
                        row['content_id'])
                    data = None
                    with concurrent.futures.ThreadPoolExecutor() as executor:
                        future = executor.submit(self.telegram.send_msg, url)
                        data = future.result()

                    log.info('get res: {}'.format(data))
                    if data:
                        sql = """UPDATE {} SET has_sent_tg = {} where content_id = '{}'""".format(
                            'kdashill_records', 1, row['content_id'])
                        try:
                            self.db.cursor.execute(sql)
                            self.db.db.commit()
                            log.info('update succesfully: {}'.format(sql))
                        except Exception as e:
                            log.error(e)
                        self.db.db.rollback()

                    time.sleep(1)
                    break

            return

        # 推荐活动
        if room and re.match(r'.*[bihu|chainnode]\.com.*', msg_text_inline):
            content_id = None
            match_results = re.search(r'(?<=bihu\.com/s/)[0-9A-Za-z]{1,}',
                                      msg_text)
            if match_results:
                key = match_results[0]
                x = 0
                for y in key:
                    k = digit62.find(y)
                    if k >= 0:
                        x = x * 62 + k
                content_id = str(x)
                platform = 'bihu'
                log.info('transfer {} to {}'.format(key, content_id))
            elif 'bihu' in msg_text:
                match_results = re.search(
                    r'(?<=bihu\.com/shortcontent/)\d{1,}',
                    msg_text_inline.lower())
                content_id = match_results[0]
                platform = 'bihu'
            elif 'chainnode' in msg_text:
                match_results = re.search(r'(?<=chainnode\.com/post/)\d{1,}',
                                          msg_text_inline.lower())
                content_id = match_results[0]
                platform = 'chainnode'
            else:
                log.info('not find pattern')

            if content_id:
                log.info('get content id = {}'.format(content_id))
                data = None
                with concurrent.futures.ThreadPoolExecutor() as executor:
                    if platform == 'bihu':
                        future = executor.submit(self.crawler.fetch_bihu,
                                                 content_id)
                    else:
                        future = executor.submit(self.crawler.fetch_chainnode,
                                                 content_id)
                    data = future.result()

                log.info('fetched data = {}'.format(data))
                if data:
                    content_inline = data['content'].replace('\n', '')
                    post_date = data['post_date']
                    if not re.match(r'.*(kda|kadena|可达).*',
                                    content_inline.lower()):
                        reply = '未发现Kadena相关信息哦~'
                        reply = reply + ' @{}'.format(talker.name)
                        await room.say(reply, mention_ids=[talker.contact_id])
                        return
                    elif post_date < datetime(
                            2021, 3, 26) or post_date >= datetime(2021, 4, 2):
                        reply = '文章发布时间不在活动范围内,不能算入哦~'
                        reply = reply + ' @{}'.format(talker.name)
                        await room.say(reply, mention_ids=[talker.contact_id])
                        return

                    # 展示
                    sql = """SELECT * FROM {} where phase = 1 and platform = '{}' and content_id = '{}'""".format(
                        'kdashill_records', platform, content_id)
                    self.db.cursor.execute(sql)
                    results = list(self.db.cursor.fetchall())
                    if len(results):
                        # 处理重复
                        is_duplicate = True
                        ww_id = results[0]['id']
                        from_room = self.Room(room_id=results[0]['room_id'])
                        await from_room.ready()
                        from_room_name = await from_room.topic()
                        room_name_str = '「{}」\n'.format(
                            from_room_name.replace('Kadena', ''))
                        from_contact = self.Contact(
                            contact_id=results[0]['contact_id'])
                        await from_contact.ready()
                        from_contact_name = from_contact.name
                    else:
                        is_duplicate = False
                        sql = """SELECT max(id) as max_id FROM {} """.format(
                            'kdashill_records')
                        self.db.cursor.execute(sql)
                        max_id = list(self.db.cursor.fetchall())[0]['max_id']
                        ww_id = max_id + 1
                        room_name_str = '「{}」\n'.format(
                            room_topic.replace('Kadena', ''))
                        from_contact_name = talker.name

                    reply_title = '可达秀.{:02} @ {}'.format(
                        ww_id, from_contact_name)
                    if platform == 'bihu':
                        reply_url = 'https://m.bihu.com/shortcontent/{}'.format(
                            content_id)
                        score = 1
                        if 'img_url' in data:
                            prefix = 'https://oss-cdn1.bihu-static.com/'
                            reply_thumbnail = prefix + data['img_url']
                        else:
                            reply_thumbnail = 'https://m.bihu.com/static/img/pic300.jpg'
                    else:
                        score = 2
                        reply_url = 'https://www.chainnode.com/post/{}'.format(
                            content_id)
                        if 'img_url' in data:
                            reply_thumbnail = data['img_url']
                        else:
                            reply_thumbnail = 'https://webcdn.chainnode.com/mobile-1.3.15/img/ChainNode.4e5601a.svg'
                    reply_description = room_name_str + data['content'][:60]
                    log.info('to create url_link: {},{},{},{}'.format(
                        reply_url, reply_title, reply_thumbnail,
                        reply_description))
                    reply_link = UrlLink.create(reply_url, reply_title,
                                                reply_thumbnail,
                                                reply_description)
                    log.info('url created')

                    # 查重
                    if is_duplicate:
                        reply = '文章已有录入哦~'
                        reply = reply + ' @{}'.format(talker.name)
                        await room.say(reply, mention_ids=[talker.contact_id])

                        return

                    # 记分
                    insert_data = {
                        'phase': 2,
                        'platform': platform,
                        'content_id': content_id,
                        'contact_id': talker.contact_id,
                        'contact_name': talker.name,
                        'room_id': room.room_id,
                        'created_at': datetime.now(),
                        'score': score,
                    }
                    keys = ','.join(
                        ['`{}`'.format(str(v)) for v in insert_data.keys()])
                    values = ','.join([
                        '\'{}\''.format(str(v)) for v in insert_data.values()
                    ])
                    sql = 'INSERT INTO {table}({keys}) VALUES({values})'.format(
                        table='kdashill_records', keys=keys, values=values)
                    try:
                        self.db.cursor.execute(sql)
                        self.db.db.commit()
                        log.info('INSERT succesfully: {}'.format(sql))
                    except Exception as e:
                        log.error(e)
                        self.db.db.rollback()

                    # 报积分
                    sql = """SELECT contact_id, sum(score) as score FROM {} where phase = 2 group by contact_id order by score desc""".format(
                        'kdashill_records')
                    self.db.cursor.execute(sql)
                    rank = 0
                    for row in self.db.cursor.fetchall():
                        rank += 1
                        if row['contact_id'] == talker.contact_id:
                            reply = '感谢参加可达秀 [KDA-Show] 活动!🍻\n'
                            reply += '您当前积分为{},排名为{}'.format(
                                row['score'], rank)
                            break

                    reply = reply + ' @{}'.format(talker.name)
                    await room.say(reply, mention_ids=[talker.contact_id])

                    # 发送至其他群
                    sql = """SELECT room_id, max(room_name) as room_name FROM {} group by room_id""".format(
                        'msg_records')
                    self.db.cursor.execute(sql)
                    for row in self.db.cursor.fetchall():
                        if '可达社区信息流' in row['room_name']:
                            forward_room = self.Room(room_id=row['room_id'])
                            await forward_room.ready()
                            try:
                                await forward_room.say(reply_link)
                            except Exception as e:
                                log.exception(e)

                    # 发送至Telegram
                    #threading.Thread(target=self.telegram.send_msg, args=(reply_url)).start()

                    return

                else:
                    reply = '未查到相关网页'
                    reply = reply + ' @{}'.format(talker.name)
                    await room.say(reply, mention_ids=[talker.contact_id])
                    return

        # 关键词回复
        if re.match(r'(资料|学习|学习资料|新人)', msg_text_inline):
            await self.send_msg_with_keyword('新手指南', contact=talker, room=room)
            return

        coin_dict = {
            'kda': 'kadena',
            'btc': 'bitcoin',
            'eth': 'ethereum',
            'dot': 'polkadot',
            'link': 'chainlink',
            'atom': 'cosmos',
            'mkr': 'maker',
            'luna': 'terra-luna',
            'celo': 'celo',
        }
        if room and msg_text.lower() in coin_dict:
            name = msg_text.lower()
            full_name = coin_dict[name]
            url = 'https://api.coingecko.com/api/v3/coins/{}/market_chart?vs_currency=usd&days=30&interval=daily'.format(
                full_name)
            data = requests.get(url).json()
            log.info('get chart, response: {}'.format(data))
            url = 'http://*****:*****@{}'.format(self.my_contact_name)
                              in msg_text):
            data = {'msg': msg_text, 'appid': '0', 'key': 'free'}
            url = 'http://api.qingyunke.com/api.php'
            res = requests.get(url, params=data)
            log.info('get AI request: {}, {}, response: {}'.format(
                url, data, res.text))
            data = res.json()
            reply = data['content'].replace('{br}', '\n')
            reply = reply + ' @{}'.format(talker.name)
            if room:
                await room.say(reply, mention_ids=[talker.contact_id])
            else:
                await msg.say(reply)