def replyOne(self, message, gen_reply): if self.whitelist and getSender(message) not in self.whitelist: if getSender(message) > CONF_START: return if self.users[message['user_id']]['first_name'] + ' ' + self.users[message['user_id']]['last_name'] not in self.whitelist: return if message['user_id'] == self.self_id: # chat with myself return if 'chat_id' in message and not self.checkConf(message['chat_id']): return try: if self.tm.isBusy(getSender(message)) and not self.tm.get(getSender(message)).attr['unimportant']: return except Exception: return if message['id'] < self.last_message.bySender(getSender(message)).get('id', 0): return try: ans = gen_reply(message) except Exception as e: ans = None logging.exception('local {}: {}'.format(e.__class__.__name__, str(e))) time.sleep(1) if ans: self.replyMessage(message, ans[0], ans[1])
def getBotReply(message): message['body'] = escape(message['body']) raw_answer = bot.interact('{} {} {} | {}'.format(('conf' if message.get('chat_id') else 'user'), message['user_id'], limiter_cache.get(getSender(message)), message['body'])) if '|' in raw_answer: limiters, answer = raw_answer.split('|', maxsplit=1) else: limiters = '' answer = raw_answer limiter_cache.add(getSender(message), limiters) if answer == '$noans' and not (message.get('_is_sticker') and message.get('chat_id')): if (message['body'].upper() == message['body'].lower() and '?' not in message['body']) or message.get('_is_sticker'): answer = random.choice(smiles) else: answer = noans[0] next_ans = random.randint(1, len(noans) - 1) noans[0], noans[next_ans] = noans[next_ans], noans[0] elif answer == '$blacklisted' or answer == '$noans': answer = '' console_message = '' if '{' in answer: answer, gender = applyGender(answer, message['user_id']) console_message += ' (' + gender + ')' while '\\' in answer: sticker = _sticker_re.match(answer) if sticker: console_message += ' (' + answer + ')' answer = '' message['_sticker_id'] = int(sticker.group(1)) break res = _cmd_re.sub(lambda m: preprocessReply(m.group(1), m.group(2).strip('][').split(']['), message['user_id'], message.setdefault('_onsend_actions', [])), answer) console_message += ' (' + answer + ')' answer = res if '_old_body' not in message: message['_old_body'] = message['body'] if message['_old_body'] and message['_old_body'][0].isdigit() and message['_old_body'] == message['_old_body'].lower(): message['_old_body'] = '' if message['_old_body'] == message['_old_body'].lower() and message['_old_body'] != message['_old_body'].upper(): last_reply_lower.add(message['user_id']) answer = answer.lower() elif message['_old_body'].upper() == message['_old_body'].lower() and message['user_id'] in last_reply_lower: answer = answer.lower() else: last_reply_lower.discard(message['user_id']) if message.get('_method'): console_message += ' (' + message['_method'] + ')' text_msg = '({}) {} : {}{}'.format(vk.printableSender(message, False), message['body'], renderSmile(answer), console_message) html_msg = '({}) {} : {}{}'.format(vk.printableSender(message, True), html.escape(message['body']), renderSmile(answer).replace('&', '&'), console_message) logging.info(text_msg, extra={'db': html_msg}) return answer
def lastDialogs(self): def cb(req, resp): d.append((req['peer_id'], resp['count'])) dialogs = self.api.messages.getDialogs(count=self.stats_dialog_count, preview_length=1) d = [] confs = {} try: items = list(dialogs['items']) for dialog in items: if getSender(dialog['message']) in self.banned: continue self.api.messages.getHistory.delayed(peer_id=getSender(dialog['message']), count=0).callback(cb) if 'title' in dialog['message']: confs[getSender(dialog['message'])] = dialog['message']['title'] self.api.sync() except TypeError: logging.warning('Unable to fetch dialogs') return (None, None, None) return (dialogs['count'], d, confs)
def lastDialogs(self): def cb(req, resp): if resp: d.append((req['peer_id'], resp['count'])) dialogs = self.api.messages.getDialogs(count=self.stats_dialog_count, preview_length=1) d = [] confs = {} try: items = list(dialogs['items']) for dialog in items: if getSender(dialog['message']) in self.banned: continue self.api.messages.getHistory.delayed(peer_id=getSender( dialog['message']), count=0).callback(cb) if 'title' in dialog['message']: confs[getSender( dialog['message'])] = dialog['message']['title'] self.confs.load([i - CONF_START for i in confs]) invited = {} for i in confs: if self.confs[i - CONF_START] and self.confs[ i - CONF_START].get('invited_by'): invited[i] = self.confs[i - CONF_START]['invited_by'] self.users.load(invited.values()) for i in invited.copy(): invited[i] = [ invited[i], self.printableName(invited[i], '{name}'), self.users[invited[i]]['sex'] == 1 ] self.api.sync() except TypeError: logging.warning('Unable to fetch dialogs') return (None, None, None, None) return (dialogs['count'], d, confs, invited)
def replyMessage(self, message, answer, skip_mark_as_read=False): sender = getSender(message) sender_msg = self.last_message.bySender(sender) if 'id' in message and message['id'] <= sender_msg.get('id', 0): return if not answer: if self.tm.isBusy(sender): return if not sender_msg or time.time() - sender_msg['time'] > self.forget_interval: tl = Timeline().sleep(self.delay_on_first_reply).do(lambda: self.api.messages.markAsRead(peer_id=sender)) tl.attr['unimportant'] = True self.tm.run(sender, tl, tl.terminate) elif answer is None: # ignored self.api.messages.markAsRead.delayed(peer_id=sender, _once=True) else: tl = Timeline().sleep((self.delay_on_reply - 1) * random.random() + 1).do(lambda: self.api.messages.markAsRead(peer_id=sender)) tl.attr['unimportant'] = True self.tm.run(sender, tl, tl.terminate) if answer is not None: self.last_message.byUser(message['user_id'])['text'] = message['body'] self.last_message.updateTime(sender) if sender > CONF_START and 'action' not in message: sender_msg.setdefault('ignored', {})[message['user_id']] = time.time() return typing_time = 0 if not answer.startswith('&#'): typing_time = len(answer) / self.chars_per_second resend = False # answer is not empty if sender_msg.get('reply', '').upper() == answer.upper() and sender_msg['user_id'] == message['user_id']: logging.info('Resending') typing_time = 0 resend = True def _send(attr): if not set(sender_msg.get('ignored', [])) <= {message['user_id']}: ctime = time.time() for uid, ts in sender_msg['ignored'].items(): if uid != message['user_id'] and ctime - ts < self.same_conf_interval * 3: attr['reply'] = True try: if resend: res = self.sendMessage(sender, '', sender_msg['id']) elif attr.get('reply'): res = self.sendMessage(sender, answer, message['id']) else: res = self.sendMessage(sender, answer) if res is None: del self.users[sender] self.logSender('Failed to send a message to %sender%', message) return msg = self.last_message.add(sender, message, res, answer) if resend: msg['resent'] = True except Exception as e: logging.exception('thread {}: {}'.format(e.__class__.__name__, str(e))) cur_delay = (self.delay_on_reply - 1) * random.random() + 1 send_time = cur_delay + typing_time user_delay = 0 if sender_msg and sender != self.admin: user_delay = sender_msg['time'] - time.time() + (self.same_user_interval if sender < CONF_START else self.same_conf_interval) # can be negative tl = Timeline(max(send_time, user_delay)) if 'chat_id' in message: tl.attr['user_id'] = message['user_id'] if not sender_msg or time.time() - sender_msg['time'] > self.forget_interval: if not skip_mark_as_read: tl.sleep(self.delay_on_first_reply) tl.do(lambda: self.api.messages.markAsRead(peer_id=sender)) else: tl.sleepUntil(send_time, (self.delay_on_reply - 1) * random.random() + 1) if not skip_mark_as_read: tl.do(lambda: self.api.messages.markAsRead(peer_id=sender)) tl.sleep(cur_delay) if message.get('_onsend_actions'): for i in message['_onsend_actions']: tl.do(i) tl.sleep(cur_delay) if typing_time: tl.doEveryFor(vkapi.utils.TYPING_INTERVAL, lambda: self.api.messages.setActivity(type='typing', user_id=sender), typing_time) tl.do(_send, True) self.tm.run(sender, tl, tl.terminate)
def reply(message): if getSender(message) in banign.banned or getSender(message) < 0: vk.banned_list.append(getSender(message)) return None uid = message['user_id'] if getSender(message) in friend_controller.noadd or uid in friend_controller.noadd: return (None, False) if 'deactivated' in vk.users[uid] or vk.users[uid]['blacklisted'] or vk.users[uid]['blacklisted_by_me']: return (None, False) if 'body' not in message: message['body'] = '' if message['body'] is None: return (None, False) if 'id' not in message: # friendship request message['body'] = message['message'] message['_method'] = 'friendship request' return (getBotReply(message), True) if isBotMessage(message['body']): vk.logSender('(%sender%) {} - ignored (bot message)'.format(message['body']), message) if 'chat_id' in message and not vk.no_leave_conf: bot_users[uid] = bot_users.get(uid, 0) + 1 if bot_users[uid] >= 3: logging.info('Too many bot messages') log.write('conf', vk.loggableConf(message['chat_id']) + ' (bot messages)') vk.leaveConf(message['chat_id']) return ('', False) elif uid in bot_users: del bot_users[uid] message['body'] = preprocessMessage(message) if message['body'] is None: return ('', False) if message['body']: if message.get('_is_sticker') and config.get('vkbot.ignore_stickers', 'b'): vk.logSender('(%sender%) {} - ignored'.format(message['body']), message) return ('', False) if message.get('_is_voice') and 'chat_id' in message: vk.logSender('(%sender%) {} - ignored'.format(message['body']), message) return ('', False) user_msg = vk.last_message.byUser(uid) if message['body'] == user_msg.get('text') and message['body'] != '..': user_msg['count'] = user_msg.get('count', 0) + 1 # this modifies the cache entry too if message.get('_is_voice') and user_msg == vk.last_message.bySender(getSender(message)) and not user_msg.get('resent'): vk.logSender('(%sender%) {} - voice again'.format(message['body']), message) return (user_msg.get('reply'), False) if message.get('_is_sticker'): return ('', False) if user_msg['count'] == 5: noaddUsers([uid], reason='flood') elif user_msg['count'] < 5: vk.logSender('(%sender%) {} - ignored (repeated)'.format(message['body']), message) return ('', False) if 'reply' in user_msg and message['body'].upper() == user_msg['reply'].upper() and len(message['body'].split()) > 1: vk.logSender('(%sender%) {} - ignored (my reply)'.format(message['body']), message) user_msg['text'] = user_msg['reply'] # this modifies the cache entry too # user_msg['count'] = 1 # do we need it? return ('', False) t = evalExpression(message['body']) if t: if getBotReplyFlat(message['body']): return ('', False) vk.logSender('(%sender%) {} = {} (calculated)'.format(message['body'], t), message) log.write('calc', '{}: "{}" = {}'.format(vk.loggableName(uid), message['body'], t)) return (t, False) tbody = message['body'].replace('<br>', '') if tbody.upper() == tbody and sum(i.isalpha() for i in tbody) > 1 and config.get('vkbot.ignore_caps', 'b'): vk.logSender('(%sender%) {} - ignored (caps)'.format(message['body']), message) return ('', False) return (getBotReply(message), False)