From 8202d215dd31aae2bfe99bcbeaee73b06e42bc28 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Mon, 3 Jul 2017 12:40:03 +0300 Subject: [PATCH 01/17] Telegram voices support --- bot.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bot.py b/bot.py index 91eda8d..601cda9 100644 --- a/bot.py +++ b/bot.py @@ -400,8 +400,9 @@ def send_doc(message, userid, group, forward_messages=None): elif filetype == 'voice': openedfile = open(file, 'rb') files = {'file': openedfile} - fileonserver = ujson.loads(requests.post(vk.API(session).docs.getUploadServer()['upload_url'], - files=files).text) + fileonserver = ujson.loads( + requests.post(vk.API(session).docs.getUploadServer(type='audio_message')['upload_url'], + files=files).text) attachment = vk.API(session).docs.save(file=fileonserver['file'], title='Аудиосообщение', tags='') openedfile.close() From b1bc1e1b770038ef2f77fff0f87696998a6353de Mon Sep 17 00:00:00 2001 From: Sergey Date: Mon, 3 Jul 2017 20:33:14 +0300 Subject: [PATCH 02/17] vk api timeout increase --- vk_messages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vk_messages.py b/vk_messages.py index 8a4137a..6e28d59 100644 --- a/vk_messages.py +++ b/vk_messages.py @@ -26,7 +26,7 @@ class VkPolling: print('Error: {}'.format(e)) if updates: handle_updates(vk_user, bot, chat_id, updates) - for i in range(50): + for i in range(60): if self._running: time.sleep(0.1) else: From 76e975d626fab674d42a6ced0b709a75792d6858 Mon Sep 17 00:00:00 2001 From: Sergey Date: Mon, 3 Jul 2017 20:43:55 +0300 Subject: [PATCH 03/17] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c2c1df9..344b94d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # tgvkbot Бот позволяет получать и отправлять сообщения VK находясь в Telegram -Команды: `/start`, `/stop` +Поддерживаются вебхуки и лонгполлинг, закомментируйте и раскомментируйте нужные строки -Краткую инструкцию бот пришлёт в чат. -# Бот в стадии разработки! -Полный функционал, инструкции по лёгкой установке и деплою (на Heroku), а так же хостингу на своём сервере будут позже. -**Stay Tuned!** +Настройка вебхуков по гайду от [@Groosha](https://www.gitbook.com/book/groosha/telegram-bot-lessons) + + +[Использование](https://www.asergey.me/usage) From 0bdcaf53a3f4f57aae278dc80669e9f6b5538304 Mon Sep 17 00:00:00 2001 From: Sergey Date: Mon, 3 Jul 2017 20:44:10 +0300 Subject: [PATCH 04/17] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 344b94d..b0fdc09 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,4 @@ Настройка вебхуков по гайду от [@Groosha](https://www.gitbook.com/book/groosha/telegram-bot-lessons) -[Использование](https://www.asergey.me/usage) +[Использование](https://www.asergey.me/tgvkbot/usage) From 51fc48af4cf02c6f430edf29ea587088f6ff94d7 Mon Sep 17 00:00:00 2001 From: Sergey Date: Tue, 4 Jul 2017 15:33:42 +0300 Subject: [PATCH 05/17] usage link --- bot.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/bot.py b/bot.py index 601cda9..e141e63 100644 --- a/bot.py +++ b/bot.py @@ -611,21 +611,7 @@ def reply_text(message): verifycode(code) create_thread(message.from_user.id, code) bot.send_message(message.from_user.id, 'Вход выполнен!').wait() - # ---------------- INSTRUCTIONS ---------------- # - bot.send_message(message.from_user.id, 'Бот позволяет получать и отвечать на текстовые сообщения' - ' из ВКонтакте\nПример личного сообщения:').wait() - bot.send_message(message.from_user.id, '*Иван Петров:*\nПривет, я тут классный мессенджер нашёл,' - ' попробуешь? telegram.org/download', - parse_mode='Markdown').wait() - bot.send_message(message.from_user.id, 'Для сообщений из групповых чатов будет указываться' - ' чат после имени отправителя:').wait() - bot.send_message(message.from_user.id, '*Ник Невидов @ My English is perfect:*\n' - 'London is the capital of Great Britain', - parse_mode='Markdown').wait() - bot.send_message(message.from_user.id, 'Чтобы ответить, используй Reply на нужное сообщение.' - ' (нет, на эти не сработает, нужно реальное)', - parse_mode='Markdown').wait() - # ---------------- INSTRUCTIONS ---------------- # + bot.send_message(message.from_user.id, '[Использование](https://asergey.me/tgvkbot/usage/)', parse_mode='Markdown').wait() except: bot.send_message(message.from_user.id, 'Неверная ссылка, попробуй ещё раз!').wait() else: From 2e58fd3fce8c4e485bcfdf4b85b956bc979f176e Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Tue, 4 Jul 2017 15:36:46 +0300 Subject: [PATCH 06/17] More accurate message handling --- bot.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/bot.py b/bot.py index e141e63..0dd2df5 100644 --- a/bot.py +++ b/bot.py @@ -611,21 +611,22 @@ def reply_text(message): verifycode(code) create_thread(message.from_user.id, code) bot.send_message(message.from_user.id, 'Вход выполнен!').wait() - bot.send_message(message.from_user.id, '[Использование](https://asergey.me/tgvkbot/usage/)', parse_mode='Markdown').wait() + bot.send_message(message.from_user.id, '[Использование](https://asergey.me/tgvkbot/usage/)', + parse_mode='Markdown').wait() except: bot.send_message(message.from_user.id, 'Неверная ссылка, попробуй ещё раз!').wait() else: bot.send_message(message.from_user.id, 'Вход уже выполнен!\n/stop для выхода.').wait() - return - if message.reply_to_message and message.reply_to_message.text == 'Поиск беседы 🔍': - search_users(message, message.text) - return - try: - vk_sender(message, send_text) - except Exception: - bot.reply_to(message, 'Произошла неизвестная ошибка при отправке', - parse_mode='Markdown').wait() + elif message.reply_to_message and message.reply_to_message.text == 'Поиск беседы 🔍': + search_users(message, message.text) + + else: + try: + vk_sender(message, send_text) + except Exception: + bot.reply_to(message, 'Произошла неизвестная ошибка при отправке', + parse_mode='Markdown').wait() print('Error: {}'.format(traceback.format_exc())) From 77a2e43400d13efb329612d1355e46cc72bcd320 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Tue, 4 Jul 2017 22:12:16 +0300 Subject: [PATCH 07/17] Stability improovements --- bot.py | 31 ++++++++++++++++++++++--------- vk_messages.py | 16 ++++++++++------ 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/bot.py b/bot.py index 0dd2df5..ee22273 100644 --- a/bot.py +++ b/bot.py @@ -9,6 +9,7 @@ import traceback import ujson import vk import wget +import time from PIL import Image from telebot import types @@ -17,8 +18,6 @@ import cherrypy from credentials import token, vk_app_id, bot_url, local_port from vk_messages import VkMessage, VkPolling -logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log') - vk_threads = {} vk_dialogs = {} @@ -170,11 +169,13 @@ def callback_buttons(call): def create_thread(uid, vk_token): a = VkPolling() - t = threading.Thread(name='vk' + str(uid), target=a.run, args=(VkMessage(vk_token), bot, uid,)) + longpoller = VkMessage(vk_token) + t = threading.Thread(name='vk' + str(uid), target=a.run, args=(longpoller, bot, uid,)) t.setDaemon(True) t.start() vk_threads[str(uid)] = a vk_tokens.set(str(uid), vk_token) + vk.API(longpoller.session).account.setOffline() def check_thread(uid): @@ -184,11 +185,22 @@ def check_thread(uid): return True -# Creating VkPolling threads and dialogs info after bot reboot using existing tokens -for uid in vk_tokens.scan_iter(): - if check_thread(uid.decode("utf-8")): - 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")) +# Creating VkPolling threads and dialogs info after bot's reboot/exception using existing tokens +def thread_supervisor(): + while True: + for uid in vk_tokens.scan_iter(): + if check_thread(uid.decode("utf-8")): + try: + 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")) + except requests.exceptions.ReadTimeout as e: + time.sleep(10) + time.sleep(120) + + +supervisor = threading.Thread(name='supervisor', target=thread_supervisor) +supervisor.setDaemon(True) +supervisor.start() def stop_thread(message): @@ -627,7 +639,7 @@ def reply_text(message): except Exception: bot.reply_to(message, 'Произошла неизвестная ошибка при отправке', parse_mode='Markdown').wait() - print('Error: {}'.format(traceback.format_exc())) + print('Error: {}'.format(traceback.format_exc())) # bot.polling(none_stop=True) @@ -643,6 +655,7 @@ class WebhookServer(object): if __name__ == '__main__': + logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log') bot.remove_webhook() bot.set_webhook('https://{}/{}/'.format(bot_url, token)) cherrypy.config.update( diff --git a/vk_messages.py b/vk_messages.py index 6e28d59..2dfaa1c 100644 --- a/vk_messages.py +++ b/vk_messages.py @@ -1,8 +1,8 @@ +import logging import os import redis import requests import time -import traceback import vk import wget @@ -11,6 +11,8 @@ vk_tokens = redis.StrictRedis(connection_pool=tokens_pool) class VkPolling: + logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log') + def __init__(self): self._running = True @@ -19,14 +21,16 @@ class VkPolling: def run(self, vk_user, bot, chat_id): while self._running: - updates = [] + timeout = 50 try: updates = vk_user.get_new_messages() + if updates: + handle_updates(vk_user, bot, chat_id, updates) except requests.exceptions.ReadTimeout as e: - print('Error: {}'.format(e)) - if updates: - handle_updates(vk_user, bot, chat_id, updates) - for i in range(60): + print(e) + timeout *= 2 + print('Retry VK Polling in {} sec'.format(timeout)) + for i in range(timeout): if self._running: time.sleep(0.1) else: From 118f3379cb7c5d6b197ed189ceb8fc20438afb09 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Tue, 4 Jul 2017 22:55:39 +0300 Subject: [PATCH 08/17] A bit more debug --- vk_messages.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vk_messages.py b/vk_messages.py index 2dfaa1c..6c1e664 100644 --- a/vk_messages.py +++ b/vk_messages.py @@ -4,6 +4,7 @@ import redis import requests import time import vk +import traceback import wget tokens_pool = redis.ConnectionPool(host='localhost', port=6379, db=0) @@ -26,10 +27,9 @@ class VkPolling: updates = vk_user.get_new_messages() if updates: handle_updates(vk_user, bot, chat_id, updates) - except requests.exceptions.ReadTimeout as e: - print(e) + except requests.exceptions.ReadTimeout: + print(traceback.format_exc()) timeout *= 2 - print('Retry VK Polling in {} sec'.format(timeout)) for i in range(timeout): if self._running: time.sleep(0.1) From d7b1011107b28cf1a900564a1aa43a79f9eb53cc Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Tue, 4 Jul 2017 22:59:37 +0300 Subject: [PATCH 09/17] Moar debug --- vk_messages.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vk_messages.py b/vk_messages.py index 6c1e664..17ea6b6 100644 --- a/vk_messages.py +++ b/vk_messages.py @@ -30,6 +30,7 @@ class VkPolling: except requests.exceptions.ReadTimeout: print(traceback.format_exc()) timeout *= 2 + print('Retrying VK Polling in {} seconds.'.format(timeout/10)) for i in range(timeout): if self._running: time.sleep(0.1) From c6ad06ddd7501988e06f65fcc072dd1604861a3c Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Wed, 5 Jul 2017 21:20:52 +0300 Subject: [PATCH 10/17] Some stability improvements --- bot.py | 14 ++++++++------ vk_messages.py | 18 ++++++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/bot.py b/bot.py index ee22273..7da24e8 100644 --- a/bot.py +++ b/bot.py @@ -581,7 +581,7 @@ def reply_sticker(message): except Exception: bot.reply_to(message, '*Произошла неизвестная ошибка при отправке*', parse_mode='Markdown').wait() # TODO?: Bugreport system - print('Error: {}'.format(traceback.format_exc())) + logging.exception('Error: {}'.format(traceback.format_exc())) @bot.message_handler(content_types=['photo']) @@ -609,7 +609,7 @@ def reply_contact(message): except Exception: bot.reply_to(message, '*Произошла неизвестная ошибка при отправке*', parse_mode='Markdown').wait() - print('Error: {}'.format(traceback.format_exc())) + logging.exception('Error: {}'.format(traceback.format_exc())) @bot.message_handler(content_types=['text']) @@ -620,9 +620,10 @@ def reply_text(message): code = extract_unique_code(m.group(0)) if check_thread(message.from_user.id): try: - verifycode(code) + user = verifycode(code) create_thread(message.from_user.id, code) - bot.send_message(message.from_user.id, 'Вход выполнен!').wait() + bot.send_message(message.from_user.id, + 'Вход выполнен в аккаунт {} {}!'.format(user['first_name'], user['last_name'])).wait() bot.send_message(message.from_user.id, '[Использование](https://asergey.me/tgvkbot/usage/)', parse_mode='Markdown').wait() except: @@ -639,7 +640,7 @@ def reply_text(message): except Exception: bot.reply_to(message, 'Произошла неизвестная ошибка при отправке', parse_mode='Markdown').wait() - print('Error: {}'.format(traceback.format_exc())) + logging.exception('Error: {}'.format(traceback.format_exc())) # bot.polling(none_stop=True) @@ -659,5 +660,6 @@ if __name__ == '__main__': bot.remove_webhook() bot.set_webhook('https://{}/{}/'.format(bot_url, token)) 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, + 'log.screen': False}) cherrypy.quickstart(WebhookServer(), '/', {'/': {}}) diff --git a/vk_messages.py b/vk_messages.py index 17ea6b6..43c5477 100644 --- a/vk_messages.py +++ b/vk_messages.py @@ -4,16 +4,15 @@ import redis import requests import time import vk -import traceback +from vk.exceptions import VkAPIError import wget +logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log') tokens_pool = redis.ConnectionPool(host='localhost', port=6379, db=0) vk_tokens = redis.StrictRedis(connection_pool=tokens_pool) class VkPolling: - logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log') - def __init__(self): self._running = True @@ -28,9 +27,8 @@ class VkPolling: if updates: handle_updates(vk_user, bot, chat_id, updates) except requests.exceptions.ReadTimeout: - print(traceback.format_exc()) timeout *= 2 - print('Retrying VK Polling in {} seconds.'.format(timeout/10)) + logging.warning('Retrying VK Polling in {} seconds.'.format(int(timeout / 10))) for i in range(timeout): if self._running: time.sleep(0.1) @@ -284,7 +282,15 @@ class VkMessage: def get_new_messages(self): api = vk.API(self.session) - new = api.messages.getLongPollHistory(ts=self.ts, pts=self.pts) + try: + new = api.messages.getLongPollHistory(ts=self.ts, pts=self.pts) + except VkAPIError.code == 10: + timeout = 3 + logging.warning('Retrying getLongPollHistory in {} seconds'.format(timeout)) + time.sleep(timeout) + self.ts, self.pts = get_tses(self.session) + new = api.messages.getLongPollHistory(ts=self.ts, pts=self.pts) + msgs = new['messages'] self.pts = new["new_pts"] count = msgs[0] From 43a617394a75789321fc820f9f532a0dec700a66 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Wed, 5 Jul 2017 21:54:27 +0300 Subject: [PATCH 11/17] Stability improvemements [2] --- bot.py | 1 + vk_messages.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bot.py b/bot.py index 7da24e8..0bebc97 100644 --- a/bot.py +++ b/bot.py @@ -30,6 +30,7 @@ vk_tokens = redis.StrictRedis(connection_pool=tokens_pool) currentchat = {} bot = telebot.AsyncTeleBot(token) +bot.remove_webhook() 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' \ diff --git a/vk_messages.py b/vk_messages.py index 43c5477..df37641 100644 --- a/vk_messages.py +++ b/vk_messages.py @@ -4,7 +4,6 @@ import redis import requests import time import vk -from vk.exceptions import VkAPIError import wget logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log') @@ -284,7 +283,7 @@ class VkMessage: api = vk.API(self.session) try: new = api.messages.getLongPollHistory(ts=self.ts, pts=self.pts) - except VkAPIError.code == 10: + except: timeout = 3 logging.warning('Retrying getLongPollHistory in {} seconds'.format(timeout)) time.sleep(timeout) From 25e81c46df571fe107f513646e9bfdd60816dac4 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Thu, 6 Jul 2017 00:51:41 +0300 Subject: [PATCH 12/17] exceptions test --- bot.py | 6 +++--- vk_messages.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bot.py b/bot.py index 0bebc97..c44896a 100644 --- a/bot.py +++ b/bot.py @@ -582,7 +582,7 @@ def reply_sticker(message): except Exception: bot.reply_to(message, '*Произошла неизвестная ошибка при отправке*', parse_mode='Markdown').wait() # TODO?: Bugreport system - logging.exception('Error: {}'.format(traceback.format_exc())) + print('Error: {}'.format(traceback.format_exc())) @bot.message_handler(content_types=['photo']) @@ -610,7 +610,7 @@ def reply_contact(message): except Exception: bot.reply_to(message, '*Произошла неизвестная ошибка при отправке*', parse_mode='Markdown').wait() - logging.exception('Error: {}'.format(traceback.format_exc())) + print('Error: {}'.format(traceback.format_exc())) @bot.message_handler(content_types=['text']) @@ -641,7 +641,7 @@ def reply_text(message): except Exception: bot.reply_to(message, 'Произошла неизвестная ошибка при отправке', parse_mode='Markdown').wait() - logging.exception('Error: {}'.format(traceback.format_exc())) + print('Error: {}'.format(traceback.format_exc())) # bot.polling(none_stop=True) diff --git a/vk_messages.py b/vk_messages.py index df37641..8205110 100644 --- a/vk_messages.py +++ b/vk_messages.py @@ -27,7 +27,7 @@ class VkPolling: handle_updates(vk_user, bot, chat_id, updates) except requests.exceptions.ReadTimeout: timeout *= 2 - logging.warning('Retrying VK Polling in {} seconds.'.format(int(timeout / 10))) + print('Retrying VK Polling in {} seconds.'.format(int(timeout / 10))) for i in range(timeout): if self._running: time.sleep(0.1) @@ -283,9 +283,9 @@ class VkMessage: api = vk.API(self.session) try: new = api.messages.getLongPollHistory(ts=self.ts, pts=self.pts) - except: + except vk.api.VkAPIError: timeout = 3 - logging.warning('Retrying getLongPollHistory in {} seconds'.format(timeout)) + print('Retrying getLongPollHistory in {} seconds'.format(timeout)) time.sleep(timeout) self.ts, self.pts = get_tses(self.session) new = api.messages.getLongPollHistory(ts=self.ts, pts=self.pts) From f88ac8bfafb04801dd929c565da7ca28a3741ed9 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Thu, 6 Jul 2017 19:33:31 +0300 Subject: [PATCH 13/17] Support for groups and big stability improvemnts --- bot.py | 63 +++++++++++++++++++++++++++++++++----------------- vk_messages.py | 33 ++++++++++++++++++++------ 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/bot.py b/bot.py index c44896a..ae5887f 100644 --- a/bot.py +++ b/bot.py @@ -70,6 +70,8 @@ def replace_shields(text): def request_user_dialogs(session, userid): order = [] users_ids = [] + group_ids = [] + positive_group_ids = [] dialogs = vk.API(session).messages.getDialogs(count=200) for chat in dialogs[1:]: if 'chat_id' in chat: @@ -80,14 +82,28 @@ def request_user_dialogs(session, userid): elif chat['uid'] > 0: order.append({'title': None, 'id': chat['uid']}) users_ids.append(chat['uid']) + elif chat['uid'] < 0: + order.append({'title': None, 'id': chat['uid']}) + group_ids.append(chat['uid']) + + for g in group_ids: + positive_group_ids.append(str(g)[1:]) + users = vk.API(session).users.get(user_ids=users_ids, fields=['first_name', 'last_name', 'uid']) + groups = vk.API(session).groups.getById(group_ids=positive_group_ids, fields=[]) for output in order: if output['title'] == ' ... ' or not output['title']: - for x in users: - if x['uid'] == output['id']: - current_user = x - break - output['title'] = '{} {}'.format(current_user['first_name'], current_user['last_name']) + if output['id'] > 0: + for x in users: + if x['uid'] == output['id']: + output['title'] = '{} {}'.format(x['first_name'], x['last_name']) + break + + else: + for f in groups: + if str(f['gid']) == str(output['id'])[1:]: + output['title'] = '{}'.format(f['name']) + break for button in range(len(order)): 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)] @@ -139,8 +155,13 @@ def search_users(message, text): def callback_buttons(call): if call.message: if 'page' in call.data: + try: + create_markup(call.message, call.from_user.id, int(call.data.split('page')[1]), True) + except: + session = VkMessage(vk_tokens.get(str(call.from_user.id))).session + request_user_dialogs(session, call.from_user.id) + create_markup(call.message, call.from_user.id, int(call.data.split('page')[1]), True) bot.answer_callback_query(call.id).wait() - create_markup(call.message, call.from_user.id, int(call.data.split('page')[1]), True) elif 'search' in call.data: markup = types.ForceReply(selective=False) bot.answer_callback_query(call.id, 'Поиск беседы 🔍').wait() @@ -157,15 +178,20 @@ def callback_buttons(call): 'Вы в беседе {}'.format(chat['title']), parse_mode='HTML').wait() currentchat[str(call.from_user.id)] = call.data - elif call.data.isdigit(): + elif call.data.lstrip('-').isdigit(): session = VkMessage(vk_tokens.get(str(call.from_user.id))).session - user = vk.API(session).users.get(user_ids=call.data, fields=[])[0] + if '-' in call.data: + user = vk.API(session).groups.getById(group_id=call.data.lstrip('-'), fields=[])[0] + user = {'first_name': user['name'], 'last_name': ''} + else: + 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.from_user.id, 'Вы в чате с {} {}'.format(user['first_name'], user['last_name']), parse_mode='HTML').wait() - currentchat[str(call.from_user.id)] = call.data + currentchat[str(call.from_user.id)] = {'title': user['first_name'] + ' ' + user['last_name'], + 'id': call.data} def create_thread(uid, vk_token): @@ -193,7 +219,6 @@ def thread_supervisor(): if check_thread(uid.decode("utf-8")): try: 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")) except requests.exceptions.ReadTimeout as e: time.sleep(10) time.sleep(120) @@ -238,21 +263,17 @@ def info_extractor(info): def chat_command(message): if logged(message): if str(message.from_user.id) in currentchat: - if 'group' in currentchat[str(message.from_user.id)]: - session = VkMessage(vk_tokens.get(str(message.from_user.id))).session - chat = vk.API(session).messages.getChat( - chat_id=currentchat[str(message.from_user.id)].split('group')[1], - fields=[]) + if 'group' in currentchat[str(message.from_user.id)]['id']: + chat = currentchat[str(message.from_user.id)] if chat['title'].replace('\\', ''): chat['title'] = chat['title'].replace('\\', '') bot.send_message(message.from_user.id, 'Вы в беседе {}'.format(chat['title']), parse_mode='HTML').wait() else: - session = VkMessage(vk_tokens.get(str(message.from_user.id))).session - user = vk.API(session).users.get(user_ids=currentchat[str(message.from_user.id)], fields=[])[0] + chat = currentchat[str(message.from_user.id)] bot.send_message(message.from_user.id, - 'Вы в чате с {} {}'.format(user['first_name'], user['last_name']), + 'Вы в чате с {}'.format(chat['title']), parse_mode='HTML').wait() else: bot.send_message(message.from_user.id, @@ -368,12 +389,12 @@ def vk_sender(message, method): elif str(message.from_user.id) in currentchat: info = [] - if 'group' in currentchat[str(message.from_user.id)]: + if 'group' in currentchat[str(message.from_user.id)]['id']: info.append('0') - info.append(currentchat[str(message.from_user.id)].split('group')[1]) + info.append(currentchat[str(message.from_user.id)]['id'].split('group')[1]) info.append('1') else: - info.append(currentchat[str(message.from_user.id)]) + info.append(currentchat[str(message.from_user.id)]['id']) info.append('0') info.append('0') form_request(message, method, info) diff --git a/vk_messages.py b/vk_messages.py index 8205110..9df8463 100644 --- a/vk_messages.py +++ b/vk_messages.py @@ -36,7 +36,12 @@ class VkPolling: def handle_messages(m, vk_user, bot, chat_id, mainmessage=None): - user = vk.API(vk_user.session).users.get(user_ids=m["uid"], fields=[])[0] + if m['uid'] > 0: + user = vk.API(vk_user.session).users.get(user_ids=m["uid"], fields=[])[0] + else: + group = vk.API(vk_user.session).groups.getById(group_ids=str(m['uid'])[1:])[0] + user = {'first_name': group['name'], 'last_name': None} + if 'body' in m and not 'attachment' in m and not 'geo' in m and not 'fwd_messages' in m: data = add_user_info(m, user["first_name"], user["last_name"])[:-1] + add_reply_info(m) bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False, @@ -244,15 +249,29 @@ def add_reply_info(m): def add_user_info(m, first_name, last_name): if 'body' in m and m['body']: - if 'chat_id' in m: - return '{} {} @ {}:\n{}\n'.format(first_name, last_name, m['title'], m['body'].replace('
', '\n')) + if last_name: + if 'chat_id' in m: + return '{} {} @ {}:\n{}\n'.format(first_name, last_name, m['title'], + m['body'].replace('
', '\n')) + else: + return '{} {}:\n{}\n'.format(first_name, last_name, m['body'].replace('
', '\n')) else: - return '{} {}:\n{}\n'.format(first_name, last_name, m['body'].replace('
', '\n')) + if 'chat_id' in m: + return '{} @ {}:\n{}\n'.format(first_name, m['title'], + m['body'].replace('
', '\n')) + else: + return '{}:\n{}\n'.format(first_name, m['body'].replace('
', '\n')) else: - if 'chat_id' in m: - return '{} {} @ {}:\n'.format(first_name, last_name, m['title']) + if last_name: + if 'chat_id' in m: + return '{} {} @ {}:\n'.format(first_name, last_name, m['title']) + else: + return '{} {}:\n'.format(first_name, last_name) else: - return '{} {}:\n'.format(first_name, last_name) + if 'chat_id' in m: + return '{} @ {}:\n'.format(first_name, m['title']) + else: + return '{}:\n'.format(first_name) def check_notification(value): From fa57f787b0b09cb825a7745459b7f42a56259b6e Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Sat, 8 Jul 2017 01:24:13 +0300 Subject: [PATCH 14/17] Sending TG gifs as VK videos --- bot.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/bot.py b/bot.py index ae5887f..65cbfad 100644 --- a/bot.py +++ b/bot.py @@ -418,9 +418,9 @@ def send_text(message, userid, group, forward_messages=None): def send_doc(message, userid, group, forward_messages=None): filetype = message.content_type session = VkMessage(vk_tokens.get(str(message.from_user.id))).session - file = wget.download( - FILE_URL.format(token, bot.get_file(getattr(message, filetype).file_id).wait().file_path)) - if filetype == 'document': + if filetype == 'document' and 'video' not in message.document.mime_type: + file = wget.download( + FILE_URL.format(token, bot.get_file(getattr(message, filetype).file_id).wait().file_path)) openedfile = open(file, 'rb') files = {'file': openedfile} fileonserver = ujson.loads(requests.post(vk.API(session).docs.getUploadServer()['upload_url'], @@ -432,6 +432,8 @@ def send_doc(message, userid, group, forward_messages=None): os.remove(file) elif filetype == 'voice': + file = wget.download( + FILE_URL.format(token, bot.get_file(getattr(message, filetype).file_id).wait().file_path)) openedfile = open(file, 'rb') files = {'file': openedfile} fileonserver = ujson.loads( @@ -442,7 +444,13 @@ def send_doc(message, userid, group, forward_messages=None): openedfile.close() os.remove(file) + elif filetype == 'document' and 'video' in message.document.mime_type: + vk_sender(message, send_video) + return + else: # filetype == 'audio': + file = wget.download( + FILE_URL.format(token, bot.get_file(getattr(message, filetype).file_id).wait().file_path)) newfile = file.split('.')[0] + '.aac' os.rename(file, newfile) openedfile = open(newfile, 'rb') From 87af6c9b8dd18add0cb578fffcb09b00728bef89 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Sat, 8 Jul 2017 01:24:53 +0300 Subject: [PATCH 15/17] timeout fixes --- vk_messages.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/vk_messages.py b/vk_messages.py index 9df8463..aed8310 100644 --- a/vk_messages.py +++ b/vk_messages.py @@ -4,6 +4,7 @@ import redis import requests import time import vk +import ujson import wget logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log') @@ -20,13 +21,13 @@ class VkPolling: def run(self, vk_user, bot, chat_id): while self._running: - timeout = 50 + timeout = 30 try: updates = vk_user.get_new_messages() if updates: handle_updates(vk_user, bot, chat_id, updates) - except requests.exceptions.ReadTimeout: - timeout *= 2 + except requests.exceptions.ReadTimeout as e: + print('Error', e) print('Retrying VK Polling in {} seconds.'.format(int(timeout / 10))) for i in range(timeout): if self._running: @@ -301,13 +302,15 @@ class VkMessage: api = vk.API(self.session) try: - new = api.messages.getLongPollHistory(ts=self.ts, pts=self.pts) + ts_pts = ujson.dumps({"ts": self.ts, "pts": self.pts}) + new = api.execute(code='return API.messages.getLongPollHistory({});'.format(ts_pts)) # api.messages.getLongPollHistory(ts=self.ts, pts=self.pts) except vk.api.VkAPIError: timeout = 3 print('Retrying getLongPollHistory in {} seconds'.format(timeout)) time.sleep(timeout) self.ts, self.pts = get_tses(self.session) - new = api.messages.getLongPollHistory(ts=self.ts, pts=self.pts) + ts_pts = ujson.dumps({"ts": self.ts, "pts": self.pts}) + new = api.execute(code='return API.messages.getLongPollHistory({});'.format(ts_pts)) msgs = new['messages'] self.pts = new["new_pts"] From 336b84436cc30a474e60bc3d78c3ed61dd516be8 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Sun, 9 Jul 2017 14:48:31 +0300 Subject: [PATCH 16/17] Exceptions logging (debug) --- vk_messages.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/vk_messages.py b/vk_messages.py index aed8310..fb9566c 100644 --- a/vk_messages.py +++ b/vk_messages.py @@ -27,8 +27,7 @@ class VkPolling: if updates: handle_updates(vk_user, bot, chat_id, updates) except requests.exceptions.ReadTimeout as e: - print('Error', e) - print('Retrying VK Polling in {} seconds.'.format(int(timeout / 10))) + logging.warning('Retrying VK Polling in {} seconds.'.format(int(timeout / 10))) for i in range(timeout): if self._running: time.sleep(0.1) @@ -303,10 +302,10 @@ class VkMessage: api = vk.API(self.session) try: ts_pts = ujson.dumps({"ts": self.ts, "pts": self.pts}) - new = api.execute(code='return API.messages.getLongPollHistory({});'.format(ts_pts)) # api.messages.getLongPollHistory(ts=self.ts, pts=self.pts) + new = api.execute(code='return API.messages.getLongPollHistory({});'.format(ts_pts)) except vk.api.VkAPIError: timeout = 3 - print('Retrying getLongPollHistory in {} seconds'.format(timeout)) + logging.warning('Retrying getLongPollHistory in {} seconds'.format(timeout)) time.sleep(timeout) self.ts, self.pts = get_tses(self.session) ts_pts = ujson.dumps({"ts": self.ts, "pts": self.pts}) From faa580e86114a76b8f312bf396572dd18cd40ee2 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Sun, 9 Jul 2017 22:47:05 +0300 Subject: [PATCH 17/17] Final version of stability update --- bot.py | 20 ++++++++++++++------ vk_messages.py | 5 +++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/bot.py b/bot.py index 65cbfad..f014708 100644 --- a/bot.py +++ b/bot.py @@ -216,12 +216,20 @@ def check_thread(uid): def thread_supervisor(): while True: for uid in vk_tokens.scan_iter(): - if check_thread(uid.decode("utf-8")): - try: - create_thread(uid.decode("utf-8"), vk_tokens.get(uid)) - except requests.exceptions.ReadTimeout as e: - time.sleep(10) - time.sleep(120) + tries = 0 + while check_thread(uid.decode("utf-8")): + if tries < 6: + try: + create_thread(uid.decode("utf-8"), vk_tokens.get(uid)) + except: + tries = tries + 1 + else: + mark = types.InlineKeyboardMarkup() + login = types.InlineKeyboardButton('ВХОД', url=link) + mark.add(login) + bot.send_message(uid.decode("utf-8"), 'Непредвиденная ошибка, требуется повторный логин ВК!', + parse_mode='HTML', reply_markup=mark) + time.sleep(60) supervisor = threading.Thread(name='supervisor', target=thread_supervisor) diff --git a/vk_messages.py b/vk_messages.py index fb9566c..4755be0 100644 --- a/vk_messages.py +++ b/vk_messages.py @@ -26,8 +26,9 @@ class VkPolling: updates = vk_user.get_new_messages() if updates: handle_updates(vk_user, bot, chat_id, updates) - except requests.exceptions.ReadTimeout as e: - logging.warning('Retrying VK Polling in {} seconds.'.format(int(timeout / 10))) + except requests.exceptions.ReadTimeout: + logging.warning('Retrying VK Polling.') + timeout = 0 for i in range(timeout): if self._running: time.sleep(0.1)