Support for audio 🎵. Messaging api with Kate Mobile app id.
And miserable stability improvements.
This commit is contained in:
parent
ae21a3cfba
commit
324e2f0ae3
@ -11,5 +11,9 @@ chmod +x install.sh
|
||||
...
|
||||
|
||||
Telegram Token: 123456789:AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLL
|
||||
VK APP ID: 1234567
|
||||
VK APP ID: 1234567 # можно пропустить, будет использован идентификатор Kate Mobile
|
||||
```
|
||||
|
||||
# Сервисы музыки
|
||||
API - https://github.com/Kylmakalle/thatmusic-api
|
||||
Token Refresher - https://github.com/Kylmakalle/vk-audio-token/tree/refresh-api
|
||||
|
16
bot.py
16
bot.py
@ -102,3 +102,19 @@ async def get_content(url, docname='tgvkbot.document', chrome_headers=True, rewr
|
||||
bot = Bot(token=BOT_TOKEN)
|
||||
dp = Dispatcher(bot)
|
||||
dp.loop.set_task_factory(context.task_factory)
|
||||
import traceback
|
||||
|
||||
|
||||
@dp.errors_handler()
|
||||
async def all_errors_handler(dp, update, e):
|
||||
if 'message' in dir(update) and update.message:
|
||||
user = update.message.from_user.full_name
|
||||
user_id = update.message.from_user.id
|
||||
else:
|
||||
user = update.callback_query.from_user.full_name
|
||||
user_id = update.callback_query.from_user.id
|
||||
|
||||
logging.error(f'The update was: {update}')
|
||||
logging.exception(traceback.print_exc())
|
||||
|
||||
return True
|
||||
|
12
config.py
12
config.py
@ -28,7 +28,15 @@ DATABASE_HOST = os.environ.get('DATABASE_HOST', 'db')
|
||||
DATABASE_PORT = os.environ.get('DATABASE_PORT', '5432')
|
||||
DATABASE_NAME = os.environ.get('POSTGRES_DB', 'tgvkbot')
|
||||
|
||||
VK_APP_ID = os.environ.get('VK_APP_ID')
|
||||
VK_APP_ID = os.environ.get('VK_APP_ID', '2685278') # Kate mobile
|
||||
|
||||
AUDIO_URL = os.environ.get('AUDIO_URL', 'http://thatmusic.akentev.com/id/{owner_id}/{audio_id}')
|
||||
AUDIO_ACCESS_URL = os.environ.get('AUDIO_ACCESS_URL',
|
||||
'http://thatmusic.akentev.com/access_id/{token}/{owner_id}/{audio_id}')
|
||||
TOKEN_REFRESH_URL = os.environ.get('TOKEN_REFRESH_URL', 'http://thatmusic.akentev.com/refresh')
|
||||
|
||||
AUDIO_HEADERS = {
|
||||
'user-agent': 'KateMobileAndroid/52.1 lite-445 (Android 4.4.2; SDK 19; x86; unknown Android SDK built for x86; en)'}
|
||||
|
||||
BOT_TOKEN = os.environ.get('BOT_TOKEN')
|
||||
|
||||
@ -36,7 +44,7 @@ SETTINGS_VAR = os.environ.get('SETTINGS_VAR', 'DJANGO_TGVKBOT_SETTINGS_MODULE')
|
||||
|
||||
MAX_FILE_SIZE = os.environ.get('MAX_FILE_SIZE', 52428800)
|
||||
|
||||
API_VERSION = os.environ.get('API_VERSION', '5.73')
|
||||
API_VERSION = os.environ.get('API_VERSION', '5.78')
|
||||
|
||||
# https://www.miniwebtool.com/django-secret-key-generator/
|
||||
# Возможно достаточно заглушки в стиле 'tgvkbot-super-secret-key(nope)'
|
||||
|
@ -42,4 +42,4 @@ networks:
|
||||
web_nw:
|
||||
driver: bridge
|
||||
volumes:
|
||||
dbdata:
|
||||
dbdata:
|
||||
|
15
set_env.py
15
set_env.py
@ -1,4 +1,4 @@
|
||||
from config import API_VERSION
|
||||
from config import API_VERSION, VK_APP_ID
|
||||
from urllib.request import urlopen, Request
|
||||
from urllib.error import HTTPError
|
||||
from urllib.parse import urlencode
|
||||
@ -48,14 +48,15 @@ def set_env():
|
||||
while True:
|
||||
vk_app_id = input('VK APP ID: ')
|
||||
vk_app_id = vk_app_id.strip()
|
||||
try:
|
||||
get_auth_page(vk_app_id)
|
||||
break
|
||||
except HTTPError:
|
||||
print('VK APP ID is invalid, try again!')
|
||||
if vk_app_id:
|
||||
try:
|
||||
get_auth_page(vk_app_id)
|
||||
break
|
||||
except HTTPError:
|
||||
print('VK APP ID is invalid, try again!')
|
||||
|
||||
with open('env_file', 'w') as env_file:
|
||||
env_file.write(ENV_FILE_TEMPLATE % {'tg_token': tg_token, 'vk_app_id': vk_app_id})
|
||||
env_file.write(ENV_FILE_TEMPLATE % {'tg_token': tg_token, 'vk_app_id': vk_app_id or VK_APP_ID})
|
||||
|
||||
print('Success!')
|
||||
|
||||
|
33
telegram.py
33
telegram.py
@ -9,7 +9,8 @@ from vk_messages import vk_polling_tasks, vk_polling
|
||||
|
||||
log = logging.getLogger('telegram')
|
||||
|
||||
oauth_link = re.compile('https://oauth\.vk\.com/blank\.html#access_token=([a-z0-9]*)&expires_in=[0-9]*&user_id=[0-9]*')
|
||||
oauth_link = re.compile(
|
||||
'https://(oauth|api)\.vk\.com/blank\.html#access_token=([a-z0-9]*)&expires_in=[0-9]*&user_id=[0-9]*')
|
||||
|
||||
|
||||
async def get_pages_switcher(markup, page, pages):
|
||||
@ -273,6 +274,22 @@ async def search_dialogs(msg: types.Message, user=None):
|
||||
await bot.send_message(msg.chat.id, text, reply_markup=markup, parse_mode=ParseMode.HTML)
|
||||
|
||||
|
||||
async def refresh_token(vkuser):
|
||||
try:
|
||||
with aiohttp.ClientSession() as session:
|
||||
r = await session.request('GET', TOKEN_REFRESH_URL, params={'token': vkuser.token})
|
||||
data = await r.json()
|
||||
if data['ok']:
|
||||
vkuser.token = data['token']
|
||||
vkuser.save()
|
||||
session.close()
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@dp.callback_query_handler(func=lambda call: call and call.message and call.data and call.data.startswith('logged'))
|
||||
async def check_logged(call: types.CallbackQuery):
|
||||
vkuser = VkUser.objects.filter(owner__uid=call.from_user.id).count()
|
||||
@ -512,7 +529,7 @@ async def send_welcome(msg: types.Message):
|
||||
existing_vkuser = VkUser.objects.filter(owner=user).count()
|
||||
if not existing_vkuser:
|
||||
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,stories' \
|
||||
'display=page&redirect_uri=https://oauth.vk.com/blank.html&scope=friends,messages,offline,docs,photos,video,stories,audio' \
|
||||
'&response_type=token&v={}'.format(VK_APP_ID, API_VERSION)
|
||||
mark = InlineKeyboardMarkup()
|
||||
login = InlineKeyboardButton('ВХОД', url=link)
|
||||
@ -651,7 +668,8 @@ async def handle_text(msg: types.Message):
|
||||
if msg.chat.type == 'private':
|
||||
m = oauth_link.search(msg.text)
|
||||
if m:
|
||||
token = m.group(1)
|
||||
await bot.send_chat_action(msg.from_user.id, ChatActions.TYPING)
|
||||
token = m.group(2)
|
||||
if not VkUser.objects.filter(token=token).exists():
|
||||
try:
|
||||
session = VkSession(access_token=token, driver=await get_driver(token))
|
||||
@ -666,10 +684,13 @@ async def handle_text(msg: types.Message):
|
||||
if driver:
|
||||
driver.close()
|
||||
del DRIVERS[vkuser.token]
|
||||
refreshed_token = await refresh_token(vkuser)
|
||||
TASKS.append({'token': vkuser.token, 'task': asyncio.ensure_future(vk_polling(vkuser))})
|
||||
await msg.reply(
|
||||
'Вход выполнен в аккаунт {} {}!\n[Использование](https://asergey.me/tgvkbot/usage/)'.format(
|
||||
logged_in = await msg.reply(
|
||||
'Вход выполнен в аккаунт {} {}!\n[Использование](https://akentev.com/tgvkbot/usage/)'.format(
|
||||
vkuserinfo['first_name'], vkuserinfo.get('last_name', '')), parse_mode='Markdown')
|
||||
if refreshed_token:
|
||||
await logged_in.reply('*Вам доступна музыка 🎵*', parse_mode='Markdown')
|
||||
except VkAuthError:
|
||||
await msg.reply('Неверная ссылка, попробуйте ещё раз!')
|
||||
else:
|
||||
@ -724,7 +745,7 @@ async def handle_photo(msg: types.Message):
|
||||
if not vk_message:
|
||||
await msg.reply('<b>Произошла ошибка при отправке</b>', parse_mode=ParseMode.HTML)
|
||||
else:
|
||||
msg.reply('<b>Ошибка при загрузке файла. Сообщение не отправлено!</b>', parse_mode=ParseMode.HTML)
|
||||
await msg.reply('<b>Ошибка при загрузке файла. Сообщение не отправлено!</b>', parse_mode=ParseMode.HTML)
|
||||
|
||||
|
||||
@dp.message_handler(content_types=['document', 'voice', 'audio', 'sticker'])
|
||||
|
@ -555,7 +555,7 @@ async def process_message(msg, token=None, is_multichat=None, vk_chat_id=None, u
|
||||
disable_notify = bool(vk_msg.get('push_settings', False))
|
||||
attaches_scheme = []
|
||||
if vk_msg.get('attachments'):
|
||||
attaches_scheme = [await process_attachment(attachment) for attachment in
|
||||
attaches_scheme = [await process_attachment(attachment, token) for attachment in
|
||||
vk_msg['attachments']]
|
||||
if vk_msg.get('geo'):
|
||||
location = vk_msg['geo']['coordinates'].split(' ')
|
||||
@ -608,7 +608,10 @@ async def process_message(msg, token=None, is_multichat=None, vk_chat_id=None, u
|
||||
if check_url:
|
||||
body_parts[body_part] = body_parts[body_part].replace(i.group(0),
|
||||
hlink(f'{i.group(2)}', url=vk_url))
|
||||
await bot.send_chat_action(to_tg_chat, ChatActions.TYPING)
|
||||
try:
|
||||
await bot.send_chat_action(to_tg_chat, ChatActions.TYPING)
|
||||
except:
|
||||
return
|
||||
tg_message = await bot.send_message(vkuser.owner.uid, body_parts[body_part],
|
||||
parse_mode=ParseMode.HTML,
|
||||
reply_to_message_id=main_message,
|
||||
@ -630,7 +633,10 @@ async def process_message(msg, token=None, is_multichat=None, vk_chat_id=None, u
|
||||
check_url = await check_vk_url(vk_url)
|
||||
if check_url:
|
||||
body = body.replace(i.group(0), hlink(f'{i.group(2)}', url=vk_url))
|
||||
await bot.send_chat_action(to_tg_chat, ChatActions.TYPING)
|
||||
try:
|
||||
await bot.send_chat_action(to_tg_chat, ChatActions.TYPING)
|
||||
except:
|
||||
return
|
||||
header_message = tg_message = await bot.send_message(to_tg_chat, header + body,
|
||||
parse_mode=ParseMode.HTML,
|
||||
reply_to_message_id=main_message,
|
||||
@ -697,7 +703,10 @@ async def process_message(msg, token=None, is_multichat=None, vk_chat_id=None, u
|
||||
await bot.send_chat_action(to_tg_chat, ChatActions.FIND_LOCATION)
|
||||
tg_message = await tgsend(bot.send_venue, to_tg_chat, *attachment['content'],
|
||||
reply_to_message_id=main_message, disable_notification=disable_notify)
|
||||
|
||||
elif attachment['type'] == 'audio':
|
||||
await bot.send_chat_action(to_tg_chat, ChatActions.UPLOAD_DOCUMENT)
|
||||
tg_message = await tgsend(bot.send_audio, to_tg_chat, audio=attachment['content'],
|
||||
reply_to_message_id=main_message, disable_notification=disable_notify)
|
||||
Message.objects.create(
|
||||
vk_chat=vk_chat_id,
|
||||
vk_id=vk_msg_id,
|
||||
@ -753,14 +762,41 @@ async def check_vk_url(url):
|
||||
return False
|
||||
|
||||
|
||||
async def process_attachment(attachment):
|
||||
async def process_attachment(attachment, token=None):
|
||||
atype = attachment.get('type')
|
||||
if atype == 'photo':
|
||||
photo_url = attachment[atype][await get_max_photo(attachment[atype])]
|
||||
return {'content': photo_url, 'type': 'photo'}
|
||||
|
||||
elif atype == 'audio':
|
||||
pass
|
||||
if AUDIO_ACCESS_URL:
|
||||
if token:
|
||||
try:
|
||||
with aiohttp.ClientSession() as session:
|
||||
r = await session.request('GET', AUDIO_ACCESS_URL.format(token=token,
|
||||
owner_id=attachment[atype]['owner_id'],
|
||||
audio_id=attachment[atype]['id']))
|
||||
if r.status != 200:
|
||||
raise Exception
|
||||
audio = await r.read()
|
||||
audio = io.BytesIO(audio)
|
||||
return {'content': audio, 'type': 'audio'}
|
||||
except:
|
||||
pass
|
||||
elif AUDIO_URL:
|
||||
try:
|
||||
with aiohttp.ClientSession() as session:
|
||||
r = await session.request('GET', AUDIO_URL.format(owner_id=attachment[atype]['owner_id'],
|
||||
audio_id=attachment[atype]['id']))
|
||||
if r.status != 200:
|
||||
raise Exception
|
||||
audio = await r.read()
|
||||
audio = io.BytesIO(audio)
|
||||
return {'content': audio, 'type': 'audio'}
|
||||
except:
|
||||
pass
|
||||
|
||||
return {'content': '<i>Аудио</i>', 'type': 'text'}
|
||||
|
||||
elif atype == 'video':
|
||||
title = attachment[atype]['title']
|
||||
|
Loading…
x
Reference in New Issue
Block a user