Dialogs Menu

This commit is contained in:
Kylmakalle 2017-07-02 02:55:01 +03:00
parent aeb8232622
commit c04d960293
2 changed files with 140 additions and 74 deletions

198
bot.py
View File

@ -1,32 +1,37 @@
import logging import logging
import os import os
import re import re
import threading
import ujson
import cherrypy
import redis import redis
import requests import requests
import telebot import telebot
import threading
import traceback
import ujson
import vk import vk
import wget import wget
from PIL import Image from PIL import Image
from telebot import types from telebot import types
from credentials import token, vk_app_id, local_port import cherrypy
from credentials import token, vk_app_id, local_port, bot_url
from vk_messages import VkMessage, VkPolling from vk_messages import VkMessage, VkPolling
logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log') logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log')
vk_threads = {} vk_threads = {}
vk_dialogs = {}
FILE_URL = 'https://api.telegram.org/file/bot{0}/{1}' FILE_URL = 'https://api.telegram.org/file/bot{0}/{1}'
tokens_pool = redis.ConnectionPool(host='localhost', port=6379, db=0) tokens_pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
vk_tokens = redis.StrictRedis(connection_pool=tokens_pool) vk_tokens = redis.StrictRedis(connection_pool=tokens_pool)
currentchat = {}
bot = telebot.AsyncTeleBot(token) bot = telebot.AsyncTeleBot(token)
bot.remove_webhook() # bot.remove_webhook()
link = 'https://oauth.vk.com/authorize?client_id={}&' \ link = 'https://oauth.vk.com/authorize?client_id={}&' \
'display=page&redirect_uri=https://oauth.vk.com/blank.html&scope=friends,messages,offline,docs,photos,video' \ 'display=page&redirect_uri=https://oauth.vk.com/blank.html&scope=friends,messages,offline,docs,photos,video' \
@ -35,13 +40,14 @@ mark = types.InlineKeyboardMarkup()
yes = types.InlineKeyboardButton('ВХОД', url=link) yes = types.InlineKeyboardButton('ВХОД', url=link)
mark.add(yes) mark.add(yes)
"""def get_pages_switcher(offset, dialogs, markup):
if offset - 10 >= 0: def get_pages_switcher(markup, page, pages):
leftbutton = types.InlineKeyboardButton('', callback_data='page{}'.format(offset - 10)) # callback if page != 0:
leftbutton = types.InlineKeyboardButton('', callback_data='page{}'.format(page - 1)) # callback
else: else:
leftbutton = None leftbutton = None
if dialogs[0] - (offset + 10) >= -10: if page + 1 < len(pages):
rightbutton = types.InlineKeyboardButton('', callback_data='page{}'.format(offset + 10)) rightbutton = types.InlineKeyboardButton('', callback_data='page{}'.format(page + 1))
else: else:
rightbutton = None rightbutton = None
@ -54,44 +60,61 @@ mark.add(yes)
markup.row(rightbutton) markup.row(rightbutton)
def request_user_dialogs(session): def replace_shields(text):
text = text.replace('&lt;', '<')
text = text.replace('&gt;', '>')
text = text.replace('&amp;', '&')
text = text.replace('&copy;', '©')
text = text.replace('&reg;', '®')
text = text.replace('&laquo;', '«')
text = text.replace('&raquo;', '«')
text = text.replace('&deg;', '°')
text = text.replace('&trade;', '')
text = text.replace('&plusmn;', '±')
return text
def request_user_dialogs(session, userid):
order = [] order = []
users_ids = [] users_ids = []
dialogs = vk.API(session).messages.getDialogs(offset=offset, count=10) dialogs = vk.API(session).messages.getDialogs(count=200)
for chat in dialogs[1:]: for chat in dialogs[1:]:
if 'chat_id' in chat: if 'chat_id' in chat:
order.append({'title': chat['title'], 'id': chat['chat_id']}) if chat['title'].replace('\\', ''):
chat['title'] = chat['title'].replace('\\', '')
chat['title'] = replace_shields(chat['title'])
order.append({'title': chat['title'], 'id': 'group' + str(chat['chat_id'])})
elif chat['uid'] > 0: elif chat['uid'] > 0:
order.append({'title': chat['title'], 'id': chat['uid']}) order.append({'title': None, 'id': chat['uid']})
users_ids.append(chat['uid']) users_ids.append(chat['uid'])
users = vk.API(session).users.get(user_ids=users_ids, fields=[]) users = vk.API(session).users.get(user_ids=users_ids, fields=['first_name', 'last_name', 'uid'])
for output in order: for output in order:
if output['title'] == ' ... ': if output['title'] == ' ... ' or not output['title']:
for x in users: for x in users:
if x['uid'] == output['id']: if x['uid'] == output['id']:
current_user = x current_user = x
break break
output['title'] = '{} {}'.format(current_user['first_name'], current_user['last_name']) output['title'] = '{} {}'.format(current_user['first_name'], current_user['last_name'])
if not output['title']:
order.remove(output)
return order
def get_user_dialogs(message, order, edit=False):
markup = types.InlineKeyboardMarkup(row_width=2)
for button in range(len(order)): for button in range(len(order)):
order[button] = types.InlineKeyboardButton(order[button]['title'], callback_data=str(order[button]['id'])) order[button] = types.InlineKeyboardButton(order[button]['title'], callback_data=str(order[button]['id']))
rows = [order[x:x + 2] for x in range(0, len(order), 2)] rows = [order[x:x + 2] for x in range(0, len(order), 2)]
for row in rows: pages = [rows[x:x + 4] for x in range(0, len(rows), 4)]
try: vk_dialogs[str(userid)] = pages
markup.row(row[0], row[1])
except:
markup.row(row[0]) def create_markup(message, user, page, edit=False):
get_pages_switcher(offset, dialogs, markup) markup = types.InlineKeyboardMarkup(row_width=2)
for i in vk_dialogs[str(user)][page]:
markup.row(*i)
get_pages_switcher(markup, page, vk_dialogs[str(user)])
if edit: if edit:
print(bot.edit_message_reply_markup(message.chat.id, message.message_id, reply_markup=markup).wait()) bot.edit_message_text(
'<b>Выберите Диалог:</b> <code>{}/{}</code> стр.'.format(page + 1, len(vk_dialogs[str(user)])),
message.chat.id, message.message_id,
parse_mode='HTML', reply_markup=markup).wait()
else: else:
bot.send_message(message.chat.id, '<b>Выберите Диалог</b>', bot.send_message(message.chat.id,
'<b>Выберите Диалог:</b> <code>{}/{}</code> стр.'.format(page + 1, len(vk_dialogs[str(user)])),
parse_mode='HTML', reply_markup=markup).wait() parse_mode='HTML', reply_markup=markup).wait()
@ -100,9 +123,28 @@ def callback_buttons(call):
if call.message: if call.message:
if 'page' in call.data: if 'page' in call.data:
bot.answer_callback_query(call.id).wait() bot.answer_callback_query(call.id).wait()
print(call.data.split('page')[1]) create_markup(call.message, call.from_user.id, int(call.data.split('page')[1]), True)
get_user_dialogs(call.message, VkMessage(vk_tokens.get(str(call.from_user.id))).session, elif 'group' in call.data:
int(call.data.split('page')[1]), True)""" session = VkMessage(vk_tokens.get(str(call.from_user.id))).session
chat = vk.API(session).messages.getChat(chat_id=call.data.split('group')[1], fields=[])
bot.answer_callback_query(call.id,
'Вы в беседе {}'.format(replace_shields(chat['title']))).wait()
if chat['title'].replace('\\', ''):
chat['title'] = chat['title'].replace('\\', '')
bot.send_message(call.message.chat.id,
'<i>Вы в беседе {}</i>'.format(chat['title']),
parse_mode='HTML').wait()
currentchat[str(call.from_user.id)] = call.data
elif call.data.isdigit():
session = VkMessage(vk_tokens.get(str(call.from_user.id))).session
user = vk.API(session).users.get(user_ids=call.data, fields=[])[0]
bot.answer_callback_query(call.id,
'Вы в чате с {} {}'.format(user['first_name'], user['last_name'])).wait()
bot.send_message(call.message.chat.id,
'<i>Вы в чате с {} {}</i>'.format(user['first_name'], user['last_name']),
parse_mode='HTML').wait()
currentchat[str(call.from_user.id)] = call.data
def create_thread(uid, vk_token): def create_thread(uid, vk_token):
@ -121,10 +163,11 @@ def check_thread(uid):
return True return True
# Creating VkPolling threads after bot reboot using existing tokens # Creating VkPolling threads and dialogs info after bot reboot using existing tokens
for uid in vk_tokens.scan_iter(): for uid in vk_tokens.scan_iter():
if check_thread(uid.decode("utf-8")): if check_thread(uid.decode("utf-8")):
create_thread(uid.decode("utf-8"), vk_tokens.get(uid)) create_thread(uid.decode("utf-8"), vk_tokens.get(uid))
request_user_dialogs(VkMessage(vk_tokens.get(uid.decode("utf-8"))).session, uid.decode("utf-8"))
def stop_thread(message): def stop_thread(message):
@ -155,9 +198,11 @@ def info_extractor(info):
return info return info
"""@bot.message_handler(commands=['dialogs']) @bot.message_handler(commands=['dialogs'])
def dialogs_command(message): def dialogs_command(message):
get_user_dialogs(message, VkMessage(vk_tokens.get(str(message.from_user.id))).session, 0)""" session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
request_user_dialogs(session, message.from_user.id)
create_markup(message, message.from_user.id, 0)
@bot.message_handler(commands=['stop']) @bot.message_handler(commands=['stop'])
@ -171,7 +216,6 @@ def stop_command(message):
@bot.message_handler(commands=['start']) @bot.message_handler(commands=['start'])
def start_command(message): def start_command(message):
# TODO: Dialogs Menu
if check_thread(message.from_user.id): if check_thread(message.from_user.id):
bot.send_message(message.chat.id, bot.send_message(message.chat.id,
'Привет, этот бот поможет тебе общаться ВКонтакте, войди по кнопке ниже' 'Привет, этот бот поможет тебе общаться ВКонтакте, войди по кнопке ниже'
@ -186,15 +230,15 @@ def form_request(message, method, info):
if message.text and message.text.startswith('!'): if message.text and message.text.startswith('!'):
if len(message.text) - 1: if len(message.text) - 1:
message.text = message.text[1:] message.text = message.text[1:]
if info[1] != 'None': if info[2] != 'None':
method(message, info[1], group=True, forward_messages=info[1]) method(message, info[1], group=True, forward_messages=info[2])
else: else:
method(message, info[1], group=True) method(message, info[1], group=True)
elif message.caption and message.caption.startswith('!'): elif message.caption and message.caption.startswith('!'):
if len(message.caption) - 1: if len(message.caption) - 1:
message.caption = message.caption[1:] message.caption = message.caption[1:]
if info[1] != 'None': if info[2] != 'None':
method(message, info[1], group=True, forward_messages=info[1]) method(message, info[1], group=True, forward_messages=info[2])
else: else:
method(message, info[1], group=True) method(message, info[1], group=True)
else: else:
@ -204,26 +248,44 @@ def form_request(message, method, info):
if info[1] != 'None': if info[1] != 'None':
method(message, info[0], group=False, forward_messages=info[1]) method(message, info[0], group=False, forward_messages=info[1])
else: else:
method(message, info[1], group=True) method(message, info[0], group=False)
elif message.caption and message.caption.startswith('!'): elif message.caption and message.caption.startswith('!'):
if len(message.caption) - 1: if len(message.caption) - 1:
message.caption = message.caption[1:] message.caption = message.caption[1:]
if info[1] != 'None': if info[1] != 'None':
method(message, info[0], group=False, forward_messages=info[1]) method(message, info[0], group=False, forward_messages=info[1])
else: else:
method(message, info[1], group=True) method(message, info[0], group=False)
else: else:
method(message, info[0], group=False) method(message, info[0], group=False)
def logged(message):
if vk_tokens.get(str(message.from_user.id)):
return True
else:
bot.send_message(message.chat.id, 'Вход не выполнен! /start для входа').wait()
return False
def vk_sender(message, method): def vk_sender(message, method):
if message.reply_to_message: if logged(message):
if vk_tokens.get(str(message.from_user.id)): if message.reply_to_message:
info = info_extractor(message.reply_to_message.entities) info = info_extractor(message.reply_to_message.entities)
if info is not None: if info is not None:
form_request(message, method, info) form_request(message, method, info)
else:
bot.send_message(message.chat.id, 'Вход не выполнен! /start для входа').wait() elif str(message.from_user.id) in currentchat:
info = []
if 'group' in currentchat[str(message.from_user.id)]:
info.append('0')
info.append(currentchat[str(message.from_user.id)].split('group')[1])
info.append('1')
else:
info.append(currentchat[str(message.from_user.id)])
info.append('0')
info.append('0')
form_request(message, method, info)
def audio_title_creator(message, performer=None, title=None): def audio_title_creator(message, performer=None, title=None):
@ -257,7 +319,7 @@ def send_doc(message, userid, group, forward_messages=None):
openedfile.close() openedfile.close()
os.remove(file) os.remove(file)
if filetype == 'voice': elif filetype == 'voice':
openedfile = open(file, 'rb') openedfile = open(file, 'rb')
files = {'file': openedfile} files = {'file': openedfile}
fileonserver = ujson.loads(requests.post(vk.API(session).docs.getUploadServer()['upload_url'], fileonserver = ujson.loads(requests.post(vk.API(session).docs.getUploadServer()['upload_url'],
@ -267,7 +329,7 @@ def send_doc(message, userid, group, forward_messages=None):
openedfile.close() openedfile.close()
os.remove(file) os.remove(file)
if filetype == 'audio': else: # filetype == 'audio':
newfile = file.split('.')[0] + '.aac' newfile = file.split('.')[0] + '.aac'
os.rename(file, newfile) os.rename(file, newfile)
openedfile = open(newfile, 'rb') openedfile = open(newfile, 'rb')
@ -416,45 +478,47 @@ def send_contact(message, userid, group, forward_messages=None):
def reply_document(message): def reply_document(message):
try: try:
vk_sender(message, send_doc) vk_sender(message, send_doc)
except Exception as e: except:
bot.reply_to(message, 'Файл слишком большой, максимально допустимый размер *20мб*!', bot.reply_to(message, 'Файл слишком большой, максимально допустимый размер *20мб*!',
parse_mode='Markdown').wait() parse_mode='Markdown').wait()
print('Error: {}'.format(e))
@bot.message_handler(content_types=['sticker']) @bot.message_handler(content_types=['sticker'])
def reply_sticker(message): def reply_sticker(message):
try: try:
vk_sender(message, send_sticker) vk_sender(message, send_sticker)
except Exception as e: except Exception:
bot.reply_to(message, 'Произошла неизвестная ошибка при отправке', bot.reply_to(message, '*Произошла неизвестная ошибка при отправке*',
parse_mode='Markdown').wait() parse_mode='Markdown').wait() # TODO?: Bugreport system
print('Error: {}'.format(e)) print('Error: {}'.format(traceback.format_exc()))
@bot.message_handler(content_types=['photo']) @bot.message_handler(content_types=['photo'])
def reply_photo(message): def reply_photo(message):
try: try:
vk_sender(message, send_photo) vk_sender(message, send_photo)
except Exception as e: except:
bot.send_message(message.chat.id, 'Фото слишком большое, максимально допустимый размер *20мб*!', bot.send_message(message.chat.id, 'Фото слишком большое, максимально допустимый размер *20мб*!',
parse_mode='Markdown').wait() parse_mode='Markdown').wait()
print('Error: {}'.format(e))
@bot.message_handler(content_types=['video', 'video_note']) @bot.message_handler(content_types=['video', 'video_note'])
def reply_video(message): def reply_video(message):
try: try:
vk_sender(message, send_video) vk_sender(message, send_video)
except Exception as e: except:
bot.reply_to(message, 'Файл слишком большой, максимально допустимый размер *20мб*!', bot.reply_to(message, 'Файл слишком большой, максимально допустимый размер *20мб*!',
parse_mode='Markdown').wait() parse_mode='Markdown').wait()
print('Error: {}'.format(e))
@bot.message_handler(content_types=['contact']) @bot.message_handler(content_types=['contact'])
def reply_contact(message): def reply_contact(message):
vk_sender(message, send_contact) try:
vk_sender(message, send_contact)
except Exception:
bot.reply_to(message, '*Произошла неизвестная ошибка при отправке*',
parse_mode='Markdown').wait()
print('Error: {}'.format(traceback.format_exc()))
@bot.message_handler(content_types=['text']) @bot.message_handler(content_types=['text'])
@ -468,6 +532,7 @@ def reply_text(message):
verifycode(code) verifycode(code)
create_thread(message.from_user.id, code) create_thread(message.from_user.id, code)
bot.send_message(message.chat.id, 'Вход выполнен!').wait() bot.send_message(message.chat.id, 'Вход выполнен!').wait()
# ---------------- INSTRUCTIONS ---------------- #
bot.send_message(message.chat.id, 'Бот позволяет получать и отвечать на текстовые сообщения' bot.send_message(message.chat.id, 'Бот позволяет получать и отвечать на текстовые сообщения'
' из ВКонтакте\nПример личного сообщения:').wait() ' из ВКонтакте\nПример личного сообщения:').wait()
bot.send_message(message.chat.id, '*Иван Петров:*\nПривет, я тут классный мессенджер нашёл,' bot.send_message(message.chat.id, '*Иван Петров:*\nПривет, я тут классный мессенджер нашёл,'
@ -480,6 +545,7 @@ def reply_text(message):
bot.send_message(message.chat.id, 'Чтобы ответить, используй Reply на нужное сообщение.' bot.send_message(message.chat.id, 'Чтобы ответить, используй Reply на нужное сообщение.'
' (нет, на эти не сработает, нужно реальное)', ' (нет, на эти не сработает, нужно реальное)',
parse_mode='Markdown').wait() parse_mode='Markdown').wait()
# ---------------- INSTRUCTIONS ---------------- #
except: except:
bot.send_message(message.chat.id, 'Неверная ссылка, попробуй ещё раз!').wait() bot.send_message(message.chat.id, 'Неверная ссылка, попробуй ещё раз!').wait()
else: else:
@ -488,13 +554,13 @@ def reply_text(message):
try: try:
vk_sender(message, send_text) vk_sender(message, send_text)
except Exception as e: except Exception:
bot.reply_to(message, 'Произошла неизвестная ошибка при отправке', bot.reply_to(message, 'Произошла неизвестная ошибка при отправке',
parse_mode='Markdown').wait() parse_mode='Markdown').wait()
print('Error: {}'.format(e)) print('Error: {}'.format(traceback.format_exc()))
# bot.polling() # bot.polling(none_stop=True)
class WebhookServer(object): class WebhookServer(object):
# index равнозначно /, т.к. отсутствию части после ip-адреса (грубо говоря) # index равнозначно /, т.к. отсутствию части после ip-адреса (грубо говоря)
@cherrypy.expose @cherrypy.expose
@ -508,7 +574,7 @@ class WebhookServer(object):
if __name__ == '__main__': if __name__ == '__main__':
bot.remove_webhook() bot.remove_webhook()
bot.set_webhook('https://bot.asergey.me/{}/'.format(token)) bot.set_webhook('https://{}/{}/'.format(bot_url, token))
cherrypy.config.update( cherrypy.config.update(
{'server.socket_host': '127.0.0.1', 'server.socket_port': local_port, 'engine.autoreload.on': False}) {'server.socket_host': '127.0.0.1', 'server.socket_port': local_port, 'engine.autoreload.on': False})
cherrypy.quickstart(WebhookServer(), '/', {'/': {}}) cherrypy.quickstart(WebhookServer(), '/', {'/': {}})

View File

@ -1,10 +1,10 @@
import vk
import time
import requests
import wget
import os import os
import ujson
import redis import redis
import requests
import time
import traceback
import vk
import wget
tokens_pool = redis.ConnectionPool(host='localhost', port=6379, db=0) tokens_pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
vk_tokens = redis.StrictRedis(connection_pool=tokens_pool) vk_tokens = redis.StrictRedis(connection_pool=tokens_pool)
@ -22,11 +22,11 @@ class VkPolling:
updates = [] updates = []
try: try:
updates = vk_user.get_new_messages() updates = vk_user.get_new_messages()
except Exception as e: except Exception:
print('Error: {}'.format(e)) print('Error: {}'.format(traceback.format_exc()))
if updates: if updates:
handle_updates(vk_user, bot, chat_id, updates) handle_updates(vk_user, bot, chat_id, updates)
for i in range(45): for i in range(50):
if self._running: if self._running:
time.sleep(0.1) time.sleep(0.1)
else: else: