57 Commits

Author SHA1 Message Date
Sergey
819b641889 Update README.md 2018-12-25 00:37:19 +03:00
Sergey
957505d53d https://vk.com/dev/version_update
https://vk.com/dev/version_update
2018-02-07 22:22:11 +03:00
Sergey
60d090aee7 Merge branch 'master' into webhook-dev 2018-02-07 22:21:20 +03:00
Kylmakalle
82afba28a2 https://vk.com/dev/version_update 2018-02-07 22:11:21 +03:00
Sergey
b9f5c3156c Update README.md 2017-10-08 19:19:52 +03:00
Kylmakalle
d6b730d699 Audio recieve support 2017-09-10 02:37:12 +03:00
Kylmakalle
022e96c09c Fixed chat chooser 2017-09-09 22:25:00 +03:00
Kylmakalle
8afba01113 fixed chat chooser 2017-09-09 22:12:38 +03:00
Kylmakalle
f1659018df Merge remote-tracking branch 'refs/remotes/origin/webhook' into webhook-dev 2017-09-09 21:51:58 +03:00
Kylmakalle
393fca6529 Revert "Merge pull request #9 from Kylmakalle/webhook"
This reverts commit 47fc72df23, reversing
changes made to ff27f0b2d7.

wrong merge reverting
2017-09-05 00:52:31 +03:00
Sergey
47fc72df23 Merge pull request #9 from Kylmakalle/webhook
Webhook updates from Master
2017-09-05 00:44:15 +03:00
Sergey
b19b94e6a9 Merge branch 'master' into webhook 2017-09-05 00:43:34 +03:00
Kylmakalle
ff27f0b2d7 Separated supervior, fix for /dialogs command 2017-08-27 15:24:09 +03:00
Kylmakalle
7bbf18375d Removed reundant escape function, tg style notify for music 2017-07-13 20:02:41 +03:00
Kylmakalle
bd09c8b9c4 Removed reundant escape function, tg style notify for music 2017-07-13 19:58:38 +03:00
Kylmakalle
41c0e36838 Fixed supervisor cycling 2017-07-13 15:21:57 +03:00
Kylmakalle
084f895897 Fixed supervisor cycling 2017-07-13 15:21:16 +03:00
Kylmakalle
7c744a8d23 Revert "Merge branch 'master' into webhook"
This reverts commit ca5e005caf, reversing
changes made to 1c5866b88d.

Reverting wrong merge
2017-07-10 15:23:33 +03:00
Sergey
256bee2b86 Update README.md 2017-07-10 01:50:16 +03:00
Sergey
70c0bdb94c Update README.md 2017-07-10 01:50:09 +03:00
Sergey
b361455e31 Support for groups, stability improvements, sending TG gifs as VK videos 2017-07-09 22:54:33 +03:00
Sergey
ca5e005caf Merge branch 'master' into webhook 2017-07-09 22:54:16 +03:00
Sergey
1c5866b88d Merge pull request #3 from Kylmakalle/webhook-dev
Webhook dev updates
2017-07-09 22:49:41 +03:00
Kylmakalle
faa580e861 Final version of stability update 2017-07-09 22:47:05 +03:00
Kylmakalle
336b84436c Exceptions logging (debug) 2017-07-09 14:48:31 +03:00
Kylmakalle
87af6c9b8d timeout fixes 2017-07-08 01:24:53 +03:00
Kylmakalle
fa57f787b0 Sending TG gifs as VK videos 2017-07-08 01:24:13 +03:00
Kylmakalle
f88ac8bfaf Support for groups and big stability improvemnts 2017-07-06 19:33:31 +03:00
Kylmakalle
25e81c46df exceptions test 2017-07-06 00:51:41 +03:00
Kylmakalle
43a617394a Stability improvemements [2] 2017-07-05 21:54:27 +03:00
Kylmakalle
c6ad06ddd7 Some stability improvements 2017-07-05 21:20:52 +03:00
Kylmakalle
d7b1011107 Moar debug 2017-07-04 22:59:37 +03:00
Kylmakalle
118f3379cb A bit more debug 2017-07-04 22:55:39 +03:00
Kylmakalle
77a2e43400 Stability improovements 2017-07-04 22:12:16 +03:00
Kylmakalle
1e2abc3018 More accurate message handler 2017-07-04 15:37:41 +03:00
Kylmakalle
2e58fd3fce More accurate message handling 2017-07-04 15:36:46 +03:00
Sergey
51fc48af4c usage link 2017-07-04 15:33:42 +03:00
Sergey
0bdcaf53a3 Update README.md 2017-07-03 20:44:10 +03:00
Sergey
76e975d626 Update README.md 2017-07-03 20:43:55 +03:00
Sergey
ba80706a7a Update README.md 2017-07-03 20:42:28 +03:00
Sergey
b1bc1e1b77 vk api timeout increase 2017-07-03 20:33:14 +03:00
Sergey
036af574f2 vk api timeout increase 2017-07-03 20:32:55 +03:00
Sergey
45d9a37f0d Audio messages Support 2017-07-03 12:42:24 +03:00
Kylmakalle
8202d215dd Telegram voices support 2017-07-03 12:40:03 +03:00
Sergey
8e2c3e993d Update bot.py 2017-07-03 03:51:54 +03:00
Sergey
1142628241 Update README.md 2017-07-02 23:45:01 +03:00
Sergey
398b1328c3 Update app.json 2017-07-02 20:03:32 +03:00
Sergey
af3f7856ad Rename requirments.txt to requirements.txt 2017-07-02 20:02:56 +03:00
Sergey
f7eb111e5b Update app.json 2017-07-02 19:58:24 +03:00
Sergey
32ddca4e4f Update app.json 2017-07-02 19:56:05 +03:00
Sergey
ca2dacc35f Update app.json 2017-07-02 19:53:49 +03:00
Sergey
73072b4e6d Create runtime.txt 2017-07-02 19:51:58 +03:00
Sergey
fabf2e8ee1 Update app.json 2017-07-02 19:47:51 +03:00
Sergey
d18bae2daa Create Procfile 2017-07-02 19:40:51 +03:00
Sergey
f81b294c18 Create requirments.txt 2017-07-02 19:40:37 +03:00
Sergey
73bbc60cf3 Update LICENSE 2017-07-02 19:25:56 +03:00
Sergey
f84a9ba455 Update LICENSE 2017-07-02 19:24:53 +03:00
8 changed files with 348 additions and 176 deletions

View File

@@ -5,9 +5,8 @@ Copyright (c) 2017 Sergey
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
to use, copy, modify, merge, publish, distribute, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

1
Procfile Normal file
View File

@@ -0,0 +1 @@
bot: python3 bot.py

View File

@@ -1,12 +1,28 @@
### Новая версия в разработке!
Актуальная ветка разработки находится [здесь](https://github.com/Kylmakalle/tgvkbot/tree/async-dev)
Подробнее в [чате](https://t.me/joinchat/BZq6jwxeTh04qBzilM5x3g)
# tgvkbot
Бот позволяет получать и отправлять сообщения VK находясь в Telegram
Команды: `/start`, `/stop`
Краткую инструкцию бот пришлёт в чат.
# Бот в стадии разработки!
Полный функционал, инструкции по лёгкой установке и деплою (на Heroku), а так же хостингу на своём сервере будут позже.
**Stay Tuned!**
https://www.asergey.me/tgvkbot
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
[Ветка](https://github.com/Kylmakalle/tgvkbot/tree/webhook) для деплоя на локальной машине (поддерживаются вебхуки и лонгполлинг, закомментируйте и раскомментируйте нужные строки)
Настройка вебхуков по гайду от [@Groosha](https://www.gitbook.com/book/groosha/telegram-bot-lessons)
Бэкенд API для получения музыки через https://asergey.me/vkmusapi/
https://gist.github.com/Kylmakalle/e63902025c527ac3610989530f4fa417
## Stay Tuned!
олноценные комментарии к коду будут чуть позже_

View File

@@ -3,6 +3,12 @@
"description": "Бот позволяет получать и отправлять сообщения VK находясь в Telegram",
"repository": "https://github.com/Kylmakalle/tgvkbot",
"keywords": ["vk", "bot", "telegram"],
"website": "https://asergey.me/tgvkbot/",
"buildpacks":[
{
"url": "heroku/python"
}
],
"env": {
"TELEGRAM_TOKEN": {
"description": "Telegram bot API токен от https://t.me/BotFather",

273
bot.py
View File

@@ -1,10 +1,10 @@
import logging
import os
import re
import redis
import requests
import telebot
import threading
import time
import traceback
import ujson
import vk
@@ -15,12 +15,12 @@ from telebot import types
from credentials import token, vk_app_id
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 = {}
VK_API_VERSION = '3.0'
FILE_URL = 'https://api.telegram.org/file/bot{0}/{1}'
vk_tokens = redis.from_url(os.environ.get("REDIS_URL"))
@@ -28,10 +28,11 @@ vk_tokens = redis.from_url(os.environ.get("REDIS_URL"))
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' \
'&response_type=token&v=5.65'.format(vk_app_id)
'&response_type=token&v={}'.format(vk_app_id, VK_API_VERSION)
def get_pages_switcher(markup, page, pages):
@@ -67,24 +68,47 @@ def replace_shields(text):
def request_user_dialogs(session, userid):
order = []
users_ids = []
dialogs = vk.API(session).messages.getDialogs(count=200)
group_ids = []
positive_group_ids = []
api = vk.API(session, v=VK_API_VERSION)
dialogs = api.messages.getDialogs(count=200)
for chat in dialogs[1:]:
if 'chat_id' in chat:
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:
order.append({'title': None, 'id': chat['uid']})
users_ids.append(chat['uid'])
users = vk.API(session).users.get(user_ids=users_ids, fields=['first_name', 'last_name', '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:])
if users_ids:
users = api.users.get(user_ids=users_ids, fields=['first_name', 'last_name', 'uid'])
else:
users = []
if positive_group_ids:
groups = api.groups.getById(group_ids=positive_group_ids, fields=[])
else:
groups = []
for output in order:
if output['title'] == ' ... ' or not output['title']:
if output['id'] > 0:
for x in users:
if x['uid'] == output['id']:
current_user = x
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
output['title'] = '{} {}'.format(current_user['first_name'], current_user['last_name'])
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)]
@@ -110,15 +134,14 @@ def create_markup(message, user, page, edit=False):
def search_users(message, text):
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
markup = types.InlineKeyboardMarkup(row_width=1)
result = vk.API(session).messages.searchDialogs(q=text, limit=10, fields=[])
result = api.messages.searchDialogs(q=text, limit=10, fields=[])
for chat in result:
if chat['type'] == 'profile':
markup.add(types.InlineKeyboardButton('{} {}'.format(chat['first_name'], chat['last_name']),
callback_data=str(chat['uid'])))
elif chat['type'] == 'chat':
if chat['title'].replace('\\', ''):
chat['title'] = chat['title'].replace('\\', '')
markup.add(
types.InlineKeyboardButton(replace_shields(chat['title']),
callback_data='group' + str(chat['chat_id'])))
@@ -136,8 +159,13 @@ def search_users(message, text):
def callback_buttons(call):
if call.message:
if 'page' in call.data:
bot.answer_callback_query(call.id).wait()
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()
elif 'search' in call.data:
markup = types.ForceReply(selective=False)
bot.answer_callback_query(call.id, 'Поиск беседы 🔍').wait()
@@ -145,33 +173,42 @@ def callback_buttons(call):
parse_mode='HTML', reply_markup=markup).wait()
elif 'group' in call.data:
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=[])
api = vk.API(session, v=VK_API_VERSION)
chat = api.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.from_user.id,
'<i>Вы в беседе {}</i>'.format(chat['title']),
parse_mode='HTML').wait()
currentchat[str(call.from_user.id)] = call.data
elif call.data.isdigit():
currentchat[str(call.from_user.id)] = {'title': chat['title'], 'id': 'group' + str(chat['chat_id'])}
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]
api = vk.API(session, v=VK_API_VERSION)
if '-' in call.data:
user = api.groups.getById(group_id=call.data.lstrip('-'), fields=[])[0]
user = {'first_name': user['name'], 'last_name': ''}
else:
user = api.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,
'<i>Вы в чате с {} {}</i>'.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):
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)
session = longpoller.session
api = vk.API(session, v=VK_API_VERSION)
api.account.setOffline()
def check_thread(uid):
@@ -181,11 +218,38 @@ 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")):
# Creating VkPolling threads and dialogs info after bot's reboot/exception using existing tokens
def thread_reviver(uid):
tries = 0
while check_thread(uid.decode("utf-8")):
if tries < 4:
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:
time.sleep(10)
tries = tries + 1
else:
mark = types.InlineKeyboardMarkup()
login = types.InlineKeyboardButton('ВХОД', url=link)
mark.add(login)
bot.send_message(uid.decode("utf-8"), '<b>Непредвиденная ошибка, требуется повторный логин ВК!</b>',
parse_mode='HTML', reply_markup=mark).wait()
break
def thread_supervisor():
while True:
for uid in vk_tokens.scan_iter():
reviver_thread = threading.Thread(name='reviver' + str(uid.decode('utf-8')), target=thread_reviver,
args=(uid,))
reviver_thread.setDaemon(True)
reviver_thread.start()
time.sleep(60)
supervisor = threading.Thread(name='supervisor', target=thread_supervisor)
supervisor.setDaemon(True)
supervisor.start()
def stop_thread(message):
@@ -209,7 +273,7 @@ def extract_unique_code(text):
def verifycode(code):
session = vk.Session(access_token=code)
api = vk.API(session)
api = vk.API(session, v=VK_API_VERSION)
return dict(api.account.getProfileInfo(fields=[]))
@@ -222,21 +286,15 @@ 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 chat['title'].replace('\\', ''):
chat['title'] = chat['title'].replace('\\', '')
if 'group' in currentchat[str(message.from_user.id)]['id']:
chat = currentchat[str(message.from_user.id)]
bot.send_message(message.from_user.id,
'<i>Вы в беседе {}</i>'.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,
'<i>Вы в чате с {} {}</i>'.format(user['first_name'], user['last_name']),
'<i>Вы в чате с {}</i>'.format(chat['title']),
parse_mode='HTML').wait()
else:
bot.send_message(message.from_user.id,
@@ -352,12 +410,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)
@@ -372,46 +430,57 @@ def audio_title_creator(message, performer=None, title=None):
def send_text(message, userid, group, forward_messages=None):
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
if group:
vk.API(session).messages.send(chat_id=userid, message=message.text, forward_messages=forward_messages)
api.messages.send(chat_id=userid, message=message.text, forward_messages=forward_messages)
else:
vk.API(session).messages.send(user_id=userid, message=message.text, forward_messages=forward_messages)
api.messages.send(user_id=userid, message=message.text, forward_messages=forward_messages)
def send_doc(message, userid, group, forward_messages=None):
filetype = message.content_type
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
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))
if filetype == 'document':
openedfile = open(file, 'rb')
files = {'file': openedfile}
fileonserver = ujson.loads(requests.post(vk.API(session).docs.getUploadServer()['upload_url'],
fileonserver = ujson.loads(requests.post(api.docs.getUploadServer()['upload_url'],
files=files).text)
attachment = vk.API(session).docs.save(file=fileonserver['file'],
attachment = api.docs.save(file=fileonserver['file'],
title=getattr(message, filetype).file_name,
tags='')
openedfile.close()
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(requests.post(vk.API(session).docs.getUploadServer()['upload_url'],
fileonserver = ujson.loads(
requests.post(api.docs.getUploadServer(type='audio_message')['upload_url'],
files=files).text)
attachment = vk.API(session).docs.save(file=fileonserver['file'], title='Аудиосообщение',
attachment = api.docs.save(file=fileonserver['file'], title='Аудиосообщение',
tags='')
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')
files = {'file': openedfile}
fileonserver = ujson.loads(requests.post(vk.API(session).docs.getUploadServer()['upload_url'],
fileonserver = ujson.loads(requests.post(api.docs.getUploadServer()['upload_url'],
files=files).text)
attachment = vk.API(session).docs.save(file=fileonserver['file'],
attachment = api.docs.save(file=fileonserver['file'],
title=audio_title_creator(message, message.audio.performer,
message.audio.title), tags='')
openedfile.close()
@@ -420,23 +489,23 @@ def send_doc(message, userid, group, forward_messages=None):
if group:
if message.caption:
vk.API(session).messages.send(chat_id=userid, message=message.caption,
api.messages.send(chat_id=userid, message=message.caption,
attachment='doc{}_{}'.format(attachment[0]['owner_id'],
attachment[0]['did']),
forward_messages=forward_messages)
else:
vk.API(session).messages.send(chat_id=userid,
api.messages.send(chat_id=userid,
attachment='doc{}_{}'.format(attachment[0]['owner_id'],
attachment[0]['did']),
forward_messages=forward_messages)
else:
if message.caption:
vk.API(session).messages.send(user_id=userid, message=message.caption,
api.messages.send(user_id=userid, message=message.caption,
attachment='doc{}_{}'.format(attachment[0]['owner_id'],
attachment[0]['did']),
forward_messages=forward_messages)
else:
vk.API(session).messages.send(user_id=userid,
api.messages.send(user_id=userid,
attachment='doc{}_{}'.format(attachment[0]['owner_id'],
attachment[0]['did']),
forward_messages=forward_messages)
@@ -445,27 +514,28 @@ def send_doc(message, userid, group, forward_messages=None):
def send_photo(message, userid, group, forward_messages=None):
filetype = message.content_type
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
file = wget.download(
FILE_URL.format(token, bot.get_file(getattr(message, filetype)[-1].file_id).wait().file_path))
openedfile = open(file, 'rb')
files = {'file': openedfile}
fileonserver = ujson.loads(requests.post(vk.API(session).photos.getMessagesUploadServer()['upload_url'],
fileonserver = ujson.loads(requests.post(api.photos.getMessagesUploadServer()['upload_url'],
files=files).text)
attachment = vk.API(session).photos.saveMessagesPhoto(server=fileonserver['server'], photo=fileonserver['photo'],
attachment = api.photos.saveMessagesPhoto(server=fileonserver['server'], photo=fileonserver['photo'],
hash=fileonserver['hash'])
if group:
if message.caption:
vk.API(session).messages.send(chat_id=userid, message=message.caption, attachment=attachment[0]['id'],
api.messages.send(chat_id=userid, message=message.caption, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
vk.API(session).messages.send(chat_id=userid, attachment=attachment[0]['id'],
api.messages.send(chat_id=userid, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
if message.caption:
vk.API(session).messages.send(user_id=userid, message=message.caption, attachment=attachment[0]['id'],
api.messages.send(user_id=userid, message=message.caption, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
vk.API(session).messages.send(user_id=userid, attachment=attachment[0]['id'],
api.messages.send(user_id=userid, attachment=attachment[0]['id'],
forward_messages=forward_messages)
openedfile.close()
os.remove(file)
@@ -474,28 +544,29 @@ def send_photo(message, userid, group, forward_messages=None):
def send_sticker(message, userid, group, forward_messages=None):
filetype = message.content_type
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
file = wget.download(
FILE_URL.format(token, bot.get_file(getattr(message, filetype).file_id).wait().file_path))
Image.open(file).save("{}.png".format(file))
openedfile = open('{}.png'.format(file), 'rb')
files = {'file': openedfile}
fileonserver = ujson.loads(requests.post(vk.API(session).photos.getMessagesUploadServer()['upload_url'],
fileonserver = ujson.loads(requests.post(api.photos.getMessagesUploadServer()['upload_url'],
files=files).text)
attachment = vk.API(session).photos.saveMessagesPhoto(server=fileonserver['server'], photo=fileonserver['photo'],
attachment = api.photos.saveMessagesPhoto(server=fileonserver['server'], photo=fileonserver['photo'],
hash=fileonserver['hash'])
if group:
if message.caption:
vk.API(session).messages.send(chat_id=userid, message=message.caption, attachment=attachment[0]['id'],
api.messages.send(chat_id=userid, message=message.caption, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
vk.API(session).messages.send(chat_id=userid, attachment=attachment[0]['id'],
api.messages.send(chat_id=userid, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
if message.caption:
vk.API(session).messages.send(user_id=userid, message=message.caption, attachment=attachment[0]['id'],
api.messages.send(user_id=userid, message=message.caption, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
vk.API(session).messages.send(user_id=userid, attachment=attachment[0]['id'],
api.messages.send(user_id=userid, attachment=attachment[0]['id'],
forward_messages=forward_messages)
openedfile.close()
os.remove('{}.png'.format(file))
@@ -505,48 +576,49 @@ def send_sticker(message, userid, group, forward_messages=None):
def send_video(message, userid, group, forward_messages=None):
filetype = message.content_type
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
file = wget.download(
FILE_URL.format(token, bot.get_file(getattr(message, filetype).file_id).wait().file_path))
openedfile = open(file, 'rb')
files = {'video_file': openedfile}
if group:
attachment = vk.API(session).video.save(is_private=1)
attachment = api.video.save(is_private=1)
fileonserver = ujson.loads(requests.post(attachment['upload_url'],
files=files).text)
video = 'video{}_{}'.format(attachment['owner_id'], attachment['owner_id']['video_id'])
if message.caption:
vk.API(session).messages.send(chat_id=userid, message=message.caption, attachment=video,
api.messages.send(chat_id=userid, message=message.caption, attachment=video,
forward_messages=forward_messages)
else:
vk.API(session).messages.send(chat_id=userid, attachment=video, forward_messages=forward_messages)
api.messages.send(chat_id=userid, attachment=video, forward_messages=forward_messages)
else:
attachment = vk.API(session).video.save(is_private=1)
attachment = api.video.save(is_private=1)
fileonserver = ujson.loads(requests.post(attachment['upload_url'],
files=files).text)
video = 'video{}_{}'.format(attachment['owner_id'], attachment['vid'])
if message.caption:
vk.API(session).messages.send(user_id=userid, message=message.caption, attachment=video,
api.messages.send(user_id=userid, message=message.caption, attachment=video,
forward_messages=forward_messages)
else:
vk.API(session).messages.send(user_id=userid, attachment=video, forward_messages=forward_messages)
api.messages.send(user_id=userid, attachment=video, forward_messages=forward_messages)
openedfile.close()
os.remove(file)
def send_contact(message, userid, group, forward_messages=None):
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
if message.contact.last_name:
text = 'Контакт: {} {}'.format(message.contact.first_name, message.contact.last_name)
else:
text = 'Контакт: {}'.format(message.contact.first_name)
if group:
vk.API(session).messages.send(chat_id=userid, message=text, forward_messages=forward_messages)
vk.API(session).messages.send(chat_id=userid, message=message.contact, forward_messages=forward_messages)
api.messages.send(chat_id=userid, message=text, forward_messages=forward_messages)
api.messages.send(chat_id=userid, message=message.contact, forward_messages=forward_messages)
else:
vk.API(session).messages.send(user_id=userid, message=text, forward_messages=forward_messages)
vk.API(session).messages.send(chat_id=userid, message=message.contact, forward_messages=forward_messages)
api.messages.send(user_id=userid, message=text, forward_messages=forward_messages)
api.messages.send(chat_id=userid, message=message.contact, forward_messages=forward_messages)
@bot.message_handler(content_types=['document', 'voice', 'audio'])
@@ -604,39 +676,46 @@ 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()
# ---------------- INSTRUCTIONS ---------------- #
bot.send_message(message.from_user.id, 'Бот позволяет получать и отвечать на текстовые сообщения'
' из ВКонтакте\nПример личного сообщения:').wait()
bot.send_message(message.from_user.id, '*Иван Петров:*\nПривет, я тут классный мессенджер нашёл,'
' попробуешь? telegram.org/download',
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()
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 ---------------- #
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
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()))
bot.polling(none_stop=True)
"""class WebhookServer(object):
# index равнозначно /, т.к. отсутствию части после ip-адреса (грубо говоря)
@cherrypy.expose
def index(self):
length = int(cherrypy.request.headers['content-length'])
json_string = cherrypy.request.body.read(length).decode("utf-8")
update = telebot.types.Update.de_json(json_string)
bot.process_new_updates([update])
return ''
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(
{'server.socket_host': '127.0.0.1', 'server.socket_port': local_port, 'engine.autoreload.on': False,
'log.screen': False})
cherrypy.quickstart(WebhookServer(), '/', {'/': {}})"""

6
requirements.txt Normal file
View File

@@ -0,0 +1,6 @@
pyTelegramBotAPI
vk
redis
Pillow
ujson
wget

1
runtime.txt Normal file
View File

@@ -0,0 +1 @@
python-3.6.1

View File

@@ -1,10 +1,15 @@
import logging
import os
import redis
import requests
import time
import ujson
import vk
import wget
VK_POLLING_VERSION = '3.0'
logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log')
vk_tokens = redis.from_url(os.environ.get("REDIS_URL"))
@@ -17,14 +22,15 @@ class VkPolling:
def run(self, vk_user, bot, chat_id):
while self._running:
updates = []
timeout = 30
try:
updates = vk_user.get_new_messages()
except requests.exceptions.ReadTimeout as e:
print('Error: {}'.format(e))
if updates:
handle_updates(vk_user, bot, chat_id, updates)
for i in range(50):
except requests.exceptions.ReadTimeout:
logging.warning('Retrying VK Polling.')
timeout = 0
for i in range(timeout):
if self._running:
time.sleep(0.1)
else:
@@ -32,7 +38,13 @@ 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]
api = vk.API(vk_user.session, v=VK_POLLING_VERSION)
if m['uid'] > 0:
user = api.users.get(user_ids=m["uid"], fields=[])[0]
else:
group = api.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,
@@ -91,8 +103,38 @@ def attachment_handler(m, user, bot, chat_id, mainmessage=None):
send_doc_link(attach, m, user, bot, chat_id, mainmessage)
elif attach['type'] == 'audio':
headers = {'content-type': 'application/json'}
audio = requests.get('https://asergey.me/vkmusapi/',
json={'aid': attach['audio']['aid'], 'owner_id': attach['audio']['owner_id']},
headers=headers)
try:
if audio.status_code == 200 and audio.json()['ok']:
audio_dict = audio.json()
data = add_user_info(m, user["first_name"],
user["last_name"]) + '🎧 <i>Аудиозапись</i>' + add_reply_info(m)
audio_msg = bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m),
reply_to_message_id=mainmessage).wait()
action = bot.send_chat_action(chat_id, 'upload_document')
bot.send_audio(chat_id, audio_dict['vk_response']['url'],
duration=audio_dict['vk_response']['duration'],
title=audio_dict['vk_response']['title'],
performer=audio_dict['vk_response']['artist'],
disable_notification=check_notification(m),
reply_to_message_id=audio_msg.message_id).wait()
action.wait()
else:
data = add_user_info(m, user['first_name'], user[
'last_name']) + '🎵 <a href="https://m.vk.com/audio?q={}%20-%20{}">{} - {}</a>'.format(
'last_name']) + '🎧 <a href="https://m.vk.com/audio?q={}%20-%20{}">{} - {}</a>'.format(
attach['audio']['artist'].replace(' ', '%20'),
attach['audio']['title'].replace(' ', '%20'), attach['audio']['artist'],
attach['audio']['title']) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m), reply_to_message_id=mainmessage).wait()
except Exception as e:
print(e)
data = add_user_info(m, user['first_name'], user[
'last_name']) + '🎧 <a href="https://m.vk.com/audio?q={}%20-%20{}">{} - {}</a>'.format(
attach['audio']['artist'].replace(' ', '%20'),
attach['audio']['title'].replace(' ', '%20'), attach['audio']['artist'],
attach['audio']['title']) + add_reply_info(m)
@@ -189,8 +231,8 @@ def attachment_handler(m, user, bot, chat_id, mainmessage=None):
disable_notification=check_notification(m),
reply_to_message_id=mainmessage).wait()
try:
user = vk.API(get_session(vk_tokens.get(str(chat_id)))).users.get(user_ids=attach['wall_reply']["uid"],
fields=[])[0]
api = vk.API(get_session(vk_tokens.get(str(chat_id))), v=VK_POLLING_VERSION)
user = api.users.get(user_ids=attach['wall_reply']["uid"], fields=[])[0]
if attach['wall_reply']['text']:
data = add_user_info(m, user["first_name"], user["last_name"]) + \
attach['wall_reply']['text'].replace('<br>', '\n') + add_reply_info(m)
@@ -240,15 +282,29 @@ def add_reply_info(m):
def add_user_info(m, first_name, last_name):
if 'body' in m and m['body']:
if last_name:
if 'chat_id' in m:
return '<b>{} {} @ {}:</b>\n{}\n'.format(first_name, last_name, m['title'], m['body'].replace('<br>', '\n'))
return '<b>{} {} @ {}:</b>\n{}\n'.format(first_name, last_name, m['title'],
m['body'].replace('<br>', '\n'))
else:
return '<b>{} {}:</b>\n{}\n'.format(first_name, last_name, m['body'].replace('<br>', '\n'))
else:
if 'chat_id' in m:
return '<b>{} @ {}:</b>\n{}\n'.format(first_name, m['title'],
m['body'].replace('<br>', '\n'))
else:
return '<b>{}:</b>\n{}\n'.format(first_name, m['body'].replace('<br>', '\n'))
else:
if last_name:
if 'chat_id' in m:
return '<b>{} {} @ {}:</b>\n'.format(first_name, last_name, m['title'])
else:
return '<b>{} {}:</b>\n'.format(first_name, last_name)
else:
if 'chat_id' in m:
return '<b>{} @ {}:</b>\n'.format(first_name, m['title'])
else:
return '<b>{}:</b>\n'.format(first_name)
def check_notification(value):
@@ -276,8 +332,18 @@ class VkMessage:
def get_new_messages(self):
api = vk.API(self.session)
new = api.messages.getLongPollHistory(ts=self.ts, pts=self.pts)
api = vk.API(self.session, v=VK_POLLING_VERSION)
try:
ts_pts = ujson.dumps({"ts": self.ts, "pts": self.pts})
new = api.execute(code='return API.messages.getLongPollHistory({});'.format(ts_pts))
except vk.api.VkAPIError:
timeout = 3
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})
new = api.execute(code='return API.messages.getLongPollHistory({});'.format(ts_pts))
msgs = new['messages']
self.pts = new["new_pts"]
count = msgs[0]
@@ -286,9 +352,7 @@ class VkMessage:
if count == 0:
pass
else:
messages = msgs[1:]
for m in messages:
res.append(m)
res = msgs[1:]
return res
@@ -297,7 +361,7 @@ def get_session(token):
def get_tses(session):
api = vk.API(session)
api = vk.API(session, v=VK_POLLING_VERSION)
ts = api.messages.getLongPollServer(need_pts=1)
return ts['ts'], ts['pts']