def token(bot, message): try: message = message.message loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) asyncio.get_event_loop().run_until_complete( redis.execute("HSET", "user:{0}".format(message.from_user.id), "active", "True", "VK_TOKEN", message.text.split(" ")[1])) asyncio.get_event_loop().run_until_complete( redis.execute("SADD", "users", "user:{0}".format(message.from_user.id))) bot.send_message( message.from_user.id, "Отлично! Я запомнил твой токен доступа VK, теперь буду пересылать " "сообщения оттуда. Спасибо, что используешь меня!") except Exception as e: try: bot.send_message( message.from_user.id, "❗ Произошла непредвиденная ошибка при выполнении метода. Сообщите об этом " "администратору для более быстрого ее исправления.") except: pass logging.error("Произошла ошибка при попытке выполнения метода.", exc_info=True) return e
def callback(bot, call): try: call = call.callback_query loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) if call.message: if call.data.startswith("channel_counters"): counter = call.data.split("|", 2) if counter[1] == "time": bot.answer_callback_query(callback_query_id=call.id, text="🕒 Время публикации данного поста: {0} MSK.".format( str(datetime.fromtimestamp( int(counter[2])).strftime("%d.%m.%y, %H:%M:%S"))), show_alert=True, cache_time=30) elif counter[1] == "likes": bot.answer_callback_query(callback_query_id=call.id, text="💖 Количество лайков: {0}.".format( str(counter[2])), show_alert=True, cache_time=30) elif counter[1] == "comments": bot.answer_callback_query(callback_query_id=call.id, text="💬 Количество комментариев: {0}.".format( str(counter[2])), show_alert=True, cache_time=30) elif counter[1] == "reposts": bot.answer_callback_query(callback_query_id=call.id, text="🔁 Количество репостов: {0}.".format( str(counter[2])), show_alert=True, cache_time=30) elif counter[1] == "views": bot.answer_callback_query(callback_query_id=call.id, text="👁 Количество просмотров: {0}.".format( str(counter[2])), show_alert=True, cache_time=30) elif counter[1] == "poll": poll = loop.run_until_complete(redis.execute("GET", str("poll&" + str(counter[2])))) if not poll: logging.debug("Poll Name is None, most likely this poll isn't in the cache.") refresh_stats(bot, call, expired=1) return bot.answer_callback_query(callback_query_id=call.id, text="📋 Название голосования: {0}.".format( str(poll[0:170])), show_alert=True, cache_time=30) elif counter[1] == "poll_ans": poll_answer = loop.run_until_complete(redis.execute("GET", str("poll_answer&" + str(counter[2])))) if not poll_answer: logging.debug("Poll Answer is None, most likely this poll isn't in the cache.") refresh_stats(bot, call, expired=1) return else: poll_answer = poll_answer.split("?|&|&|!", 1) bot.answer_callback_query(callback_query_id=call.id, text="❎ Количество голосов за {0}: {1} голосов.".format( str(poll_answer[0][0:140]), str(poll_answer[1])), show_alert=True, cache_time=30) elif call.data.startswith("channel_refresh_stats"): refresh_stats(bot, call) bot.answer_callback_query(callback_query_id=call.id, show_alert=False) except Exception as e: logging.error("Exception has been occurred while trying to execute the method.", exc_info=True) return e
def start(bot, message): try: message = message.message loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) if "ru" not in message.from_user.language_code: bot.send_message( message.from_user.id, "❗ Unfortunately, the bot doesn't speak your language. So if you are " "not able to understand Russian, use an online translator such as Google Translate." ) bot.send_message(message.from_user.id, config.startMessage, parse_mode="Markdown") loop.run_until_complete( redis.execute( "SET", "status:{0}".format(message.from_user.id), '{"status": "waiting", "method": "find_communities"}', "EX", 180)) except Exception as e: try: bot.send_message( message.from_user.id, "❗ Извините, что-то пошло не так, но в скором времени все исправится. " "Попробуйте выполнить то же самое действие через некоторое время (10-15 минут)." ) except: pass logging.error( "Exception has been occurred while trying to execute the method.", exc_info=True) return e
def start_polling(client): try: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) users = asyncio.get_event_loop().run_until_complete( redis.execute("SMEMBERS", "users"))['details'] logging.debug("Пользователи в Redis: " + str(users)) while True: for user in users: user_id = user user = asyncio.get_event_loop().run_until_complete( hgetall(user)) if parse_as_boolean(user['active']): # TODO: Использовать Dramatiq вместо этого самопального кода result = poll_user(user, user_id, client) logging.debug( "Выполнен polling пользователя {0}, результат: {1}". format(user_id, result)) sleep(0.1) except Exception as e: logging.error( "Произошла ошибка при попытке начала polling'а всех аккаунтов VK.", exc_info=True) return e
def message_handler(client, message): try: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) try: assert message.reply_to_message except AssertionError: return tg_message_id = "{0}_{1}".format(message.reply_to_message.chat.id, message.reply_to_message.message_id) vk_message_id = asyncio.get_event_loop().run_until_complete( redis.execute( "GET", "message:telegram:{0}".format(tg_message_id)))['details'] if not vk_message_id: logging.debug( "Сообщение, на которое ответил пользователь, не содержит ID сообщения из VK." ) if config.DEVELOPER_MODE: message.reply( "ℹ️ К сообщению, на которое вы ответили, не привязано ID сообщения из VK.", disable_notification=True) return user = asyncio.get_event_loop().run_until_complete( hgetall("user:{0}".format(message.from_user.id))) peer_id = vk_message_id.split("_")[0] try: assert message.sticker parse_sticker(client, message.sticker.file_id, user['VK_TOKEN'], user['VK_SECRET'], peer_id) except AssertionError: logging.debug("Похоже, что это сообщение не является стикером..") if message.text: data = { "peer_id": peer_id, "random_id": randbits(32), "message": message.text, "access_token": user['VK_TOKEN'], "v": 5.92 } response = requests.post("https://api.vk.com/method/messages.send", data=sign_data(data, "messages.send", user['VK_SECRET'])).json() logging.debug( "Сообщение было отправлено, VK вернул ответ: {0}".format( response)) if config.DEVELOPER_MODE: message.reply( "ℹ️ Сообщение было отправлено, VK вернул ответ:\n\n`{0}`.". format(response), disable_notification=True) except Exception as e: logging.error("Произошла ошибка при попытке выполнения метода.", exc_info=True) return e
def store(client, message): try: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) item_store_file, item_store_hash = asyncio.get_event_loop( ).run_until_complete(parse_item_store()) item_store_file_id = asyncio.get_event_loop().run_until_complete( Redis.execute("GET", "fortnite:store:file_id:{0}".format( item_store_hash)))['details'] if item_store_file_id and not config.DEVELOPER_MODE: logging.info( "Изображение текущего магазина предметов уже было загружено в Telegram, " "File ID: {0}.".format(item_store_file_id)) client.send_photo( message.chat.id, item_store_file_id, caption= "🛒 Текущий магазин предметов в Фортнайте." ) else: message = client.send_photo( message.chat.id, item_store_file, caption= "🛒 Текущий магазин предметов в Фортнайте." ) item_store_file_id = message['photo']['sizes'][-1]['file_id'] asyncio.get_event_loop().run_until_complete( Redis.execute( "SET", "fortnite:store:file_id:{0}".format(item_store_hash), item_store_file_id, "EX", 86400)) except Exception as e: logging.error( "Произошла ошибка при выполнении команды /store.", exc_info=True) return e
def message(bot, message): try: message = message.message loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) if not message.text.startswith("/"): status = loop.run_until_complete( redis.execute("GET", "status:{0}".format(message.from_user.id))) if status: status = json.loads(str(status)) if status['method'] == "find_communities": find_community(bot, message) loop.run_until_complete( redis.execute( "DEL", "status:{0}".format(message.from_user.id))) except Exception as e: logging.error( "Exception has been occurred while trying to execute the method.", exc_info=True) return e
def news(client, message): try: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) news_file, news_hash = asyncio.get_event_loop().run_until_complete( parse_news()) news_file_id = asyncio.get_event_loop().run_until_complete( Redis.execute( "GET", "fortnite:news:file_id:{0}".format(news_hash)))['details'] if news_file_id and not config.DEVELOPER_MODE: logging.info( "Изображение текущих новостей уже было загружено в Telegram, " "File ID: {0}.".format(news_file_id)) client.send_photo( message.chat.id, news_file_id, caption= "📰 Текущие новости Королевской Битвы и Сражения с Бурей.") else: message = client.send_photo( message.chat.id, news_file, caption= "📰 Текущие новости Королевской Битвы и Сражения с Бурей.") news_file_id = message['photo']['sizes'][-1]['file_id'] asyncio.get_event_loop().run_until_complete( Redis.execute("SET", "fortnite:news:file_id:{0}".format(news_hash), news_file_id, "EX", 86400)) except Exception as e: logging.error("Произошла ошибка при выполнении команды /news.", exc_info=True) return e
def cancel(bot, message): try: message = message.message loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete( redis.execute("DEL", "status:{0}".format(message.from_user.id))) bot.send_message(message.from_user.id, "Вы успешно отменили текущую операцию.") except Exception as e: try: bot.send_message( message.from_user.id, "❗ Извините, что-то пошло не так, но в скором времени все будет исправлено. " "Попробуйте выполнить то же самое действие через некоторое время (10-15 минут)." ) except: pass logging.error( "Exception has been occurred while trying to execute the method.", exc_info=True) return e
def activate(bot, message): try: message = message.message loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) asyncio.get_event_loop().run_until_complete( redis.execute("HSET", "users:{0}".format(message.from_user.id), "active", "True")) bot.send_message(message.from_user.id, "Хорошо! Я изменил твой статус на активный.") except Exception as e: try: bot.send_message( message.from_user.id, "❗ Произошла непредвиденная ошибка при выполнении метода. Сообщите об этом " "администратору для более быстрого ее исправления.") except: pass logging.error("Произошла ошибка при попытке выполнения метода.", exc_info=True) return e
async def redis_hgetall(key): return dict( zip_longest( *[iter((await (redis.execute("HGETALL", key)))['details'])] * 2, fillvalue=""))
def parse_sticker(client, file_id, access_token, sig_secret, peer_id): logging.debug("Обрабатывается стикер с File ID: {0}...".format(file_id)) sticker_hash = sha1(file_id.encode("UTF-8")).hexdigest() sticker_id = asyncio.get_event_loop().run_until_complete( redis.execute("GET", "files:vk:sticker:{0}".format(sticker_hash)))['details'] if not sticker_id: logging.debug( "Стикер не содержится в кэше, выполняются необходимые процессы...". format(sticker_hash)) with NamedTemporaryFile(suffix=".webp") as sticker_webp_file: logging.debug("Стикер скачивается во временный файл {1}...".format( file_id, sticker_webp_file.name)) client.download_media(file_id, sticker_webp_file.name) sticker_webp = Image.open(sticker_webp_file.name) with NamedTemporaryFile(suffix=".png") as sticker_png_file: sticker_webp.save(sticker_png_file.name, format="PNG") logging.debug( "Стикер переконвертирован в формат PNG, сохранен в файл: {0}" .format(sticker_png_file.name)) data = { "type": "graffiti", "access_token": access_token, "v": 5.92 } upload_server = requests.post( "https://api.vk.com/method/docs.getUploadServer", data=sign_data(data, "docs.getUploadServer", sig_secret)).json() logging.debug( "URL сервера VK, на который будет происходить загрузка стикера: {0}" .format(upload_server['response']['upload_url'])) files = {'file': open(sticker_png_file.name, 'rb')} uploaded_file = requests.post( upload_server['response']['upload_url'], files=files).json() logging.debug( "После загрузки стикера на сервер VK, получен ответ: {0}". format(uploaded_file)) data = { "file": uploaded_file['file'], "access_token": access_token, "v": 5.92 } saved_document = requests.post( "https://api.vk.com/method/docs.save", data=sign_data(data, "docs.save", sig_secret)).json() logging.debug( "Стикер сохранен как документ, получен ответ: {0}".format( saved_document)) sticker_id = "doc{0}_{1}_{2}".format( saved_document['response']['graffiti']['owner_id'], saved_document['response']['graffiti']['id'], saved_document['response']['graffiti']['access_key']) asyncio.get_event_loop().run_until_complete( redis.execute("SET", "files:vk:sticker:{0}".format(sticker_hash), sticker_id)) data = { "peer_id": peer_id, "random_id": randbits(32), "attachment": sticker_id, "access_token": access_token, "v": 5.92 } sent_message = requests.post("https://api.vk.com/method/messages.send", data=sign_data(data, "messages.send", sig_secret)).json() logging.debug( "Сообщение со стикером было отправлено, получен ответ: {0}".format( sent_message))
# -*- coding: utf-8 -*- from app import logging from app.remote.redis import Redis as redis from app.telegram.app import get_client as telegram_get_client from app.vk.app import start_polling as vk_start_polling from threading import Thread from time import sleep import logging import asyncio if __name__ == "__main__": try: asyncio.get_event_loop().run_until_complete(redis.connection()) client = telegram_get_client() Thread(target=client.start, name="telegram_client").start() # Telegram клиенту нужно немного времени, чтобы запуститься sleep(1) Thread(target=vk_start_polling, args=(client, ), name="vk_polling").start() except Exception as e: logging.critical("Произошла ошибка в работе приложения.", exc_info=True)
def statistics(bot, posts, chat_id, mtype="initiate", message_id=None): try: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) poll = None try: try: posts['attachments'] poll = [] for anum in range(len(posts['attachments'])): if posts['attachments'][anum]['type'] == "poll": poll.extend([{"question": str(posts['attachments'][anum]['poll']['question']), "answers": literal_eval( str(posts['attachments'][anum]['poll']['answers']))}]) except KeyError: logging.debug("KeyError Exception has been occurred, most likely the post doesn't have " "any attachments.", exc_info=True) except Exception as e: logging.error("Exception has been occurred while trying to execute the method.", exc_info=True) for elm in ["time", "likes", "comments", "reposts", "views"]: if elm is "time": pass else: try: posts[elm]['count'] except KeyError: posts[elm] = {"count": 0} markup = [] markup.extend([ [InlineKeyboardButton("🕒 {0}".format( str(datetime.fromtimestamp(int(posts['date'])).strftime("%d.%m.%y, %H:%M:%S"))), callback_data="channel_counters|time|{0}".format(str(posts['date'])))] ]) markup.extend([[ InlineKeyboardButton("💖 {0}".format( (str(round(int(posts['likes']['count']) / 1000.0) * 1) + "K" if int(posts['likes']['count']) > 1000 else str(posts['likes']['count']))), callback_data="channel_counters|likes|{0}".format(str(posts['likes']['count']))), InlineKeyboardButton("💬 {0}".format( (str(round(int(posts['comments']['count']) / 1000.0) * 1) + "K" if int(posts['comments']['count']) > 1000 else str(posts['comments']['count']))), callback_data="channel_counters|comments|{0}".format(str(posts['comments']['count']))), InlineKeyboardButton("🔁 {0}".format( (str(round(int(posts['reposts']['count']) / 1000.0) * 1) + "K" if int(posts['reposts']['count']) > 1000 else str(posts['reposts']['count']))), callback_data="channel_counters|reposts|{0}".format(str(posts['reposts']['count']))), InlineKeyboardButton("👁️ {0}".format( (str(round(int(posts['views']['count']) / 1000.0) * 1) + "K" if int(posts['views']['count']) > 1000 else str(posts['views']['count']))), callback_data="channel_counters|views|{0}".format(str(posts['views']['count']))), ]]) if poll: poll_uuid = uuid4() try: poll[0]['question'][31] poll_question = str(poll[0]['question'][0:30]) + "..." except IndexError: poll_question = str(poll[0]['question'][0:30]) markup.extend([ [InlineKeyboardButton("📋 {0}".format( str(poll_question)), callback_data="channel_counters|poll|{0}".format(str(poll_uuid)))]]) loop.run_until_complete(redis.execute("SET", str("poll&" + str(poll_uuid)), str(poll[0]['question']))) loop.run_until_complete(redis.execute("EXPIRE", str("poll&" + str(poll_uuid)), 900)) logging.debug("Poll UUID: " + str(poll_uuid)) for pint in range(len(poll[0]['answers'])): pollanswer_uuid = uuid4() try: poll[0]['answers'][pint]['text'][31] poll_question = str(poll[0]['answers'][pint]['text'][0:30]) + "..." except IndexError: poll_question = str(poll[0]['answers'][pint]['text'][0:30]) markup.extend([[ InlineKeyboardButton("❎ {0} — {1} 👍🏻".format( str(poll_question), (str(round(int(poll[0]['answers'][pint]['votes']) / 1000.0) * 1) + "K" if int( poll[0]['answers'][pint]['votes']) > 1000 else str(poll[0]['answers'][pint]['votes']))), callback_data="channel_counters|poll_ans|{0}".format( str(pollanswer_uuid)))]]) loop.run_until_complete(redis.execute("SET", str("poll_answer&" + str(pollanswer_uuid)), str( str(poll[0]['answers'][pint]['text']) + "?|&|&|!" + str(poll[0]['answers'][pint]['votes'])))) loop.run_until_complete(redis.execute("EXPIRE", str("poll_answer&" + str(pollanswer_uuid)), 1800)) logging.debug("Poll Answer UUID: " + str(pollanswer_uuid)) markup.extend([ [InlineKeyboardButton("🔄 Обновить статистику", callback_data="channel_refresh_stats|{0}".format( str(int(int(time())) + 600)))]]) markup = InlineKeyboardMarkup(markup) if mtype == "initiate": return markup elif mtype == "update": try: bot.edit_message_reply_markup(chat_id=chat_id, message_id=message_id, reply_markup=markup) return "OK" except BadRequest as e: if "Message is not modified" in str(e): return "IS NOT MODIFIED" else: logging.error("Exception BadRequest has been occurred while trying to edit message markup.", exc_info=True) return "ERROR" except Exception as e: logging.error("Exception has been occurred while trying to execute the method.", exc_info=True) return e
def poll_user(user, user_id, client): try: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) telegram_user_id = int(user_id.split(":")[1]) logging.debug("Выполняется polling пользователя c ID: {0}".format(user_id)) try: assert user['VK_TOKEN'] assert user['VK_SECRET'] except (AssertionError, KeyError, TypeError): return {"status": "ERROR", "details": "У пользователя указан неверный VK токен (или он отстутствует)"} try: assert user['VK_LP_KEY'] assert user['VK_LP_SERVER'] assert user['VK_LP_PTS'] except (AssertionError, KeyError, TypeError): logging.debug("У пользователя {0} нет данных о LongPoll сервере.".format(user_id)) data = {"need_pts": 1, "lp_version": 3, "access_token": user['VK_TOKEN'], "v": 5.92} response_lps = requests.post("https://api.vk.com/method/messages.getLongPollServer", data=sign_data(data, "messages.getLongPollServer", user['VK_SECRET'])).json() logging.debug("Ответ на запрос метода messages.getLongPollServer: " + str(response_lps)) response_lps = response_lps['response'] user['VK_LP_KEY'] = response_lps['key'] user['VK_LP_SERVER'] = response_lps['server'] user['VK_LP_PTS'] = response_lps['pts'] asyncio.get_event_loop().run_until_complete( redis.execute("HSET", user_id, "VK_LP_KEY", response_lps['key'], "VK_LP_SERVER", response_lps['server'], "VK_LP_PTS", response_lps['pts'])) data = {"key": user['VK_LP_KEY'], "server": user['VK_LP_SERVER'], "pts": user['VK_LP_PTS'], "fields": "screen_name", "mode": 2, "lp_version": 3, "access_token": user['VK_TOKEN'], "v": 5.92} response_lph = requests.post("https://api.vk.com/method/messages.getLongPollHistory", data=sign_data(data, "messages.getLongPollHistory", user['VK_SECRET'])).json() logging.debug("Ответ на запрос метода messages.getLongPollHistory: " + str(response_lph)) response_lph = response_lph['response'] for message in response_lph['messages']['items']: if int(message['out']) == 1: continue message_id = "{0}_{1}".format(message['peer_id'], message['conversation_message_id']) # Проверяем сообщение на наличие вложений в сообщении media = [] # TODO: Добавить chat_action (загрузка видео, аудио) for attachment in message['attachments']: if attachment['type'] == "photo": photo_sorted_sizes = sorted(attachment['photo']['sizes'], key=itemgetter('width')) with NamedTemporaryFile(suffix=".jpg", delete=False) as photo: photo.write(requests.get(photo_sorted_sizes[-1]['url'], stream=True).content) media.extend([InputMediaPhoto(photo.name)]) if attachment['type'] == "video": # Получаем видео, которое сможем загрузить при лимите в 1.5 ГБ video_url = None for video_quality in attachment['video']['files']: if video_quality == "hls" or video_quality == "external": continue video_size = int(requests.get(attachment['video']['files'][video_quality], stream=True). headers['Content-length']) if video_size < 1500 * 1024 * 1024: video_url = attachment['video']['files'][video_quality] if not video_url: continue video_hash = sha1(video_url.split("?extra")[0].encode("UTF-8")).hexdigest() video = asyncio.get_event_loop().run_until_complete( hgetall("files:telegram:video:{0}".format(video_hash))) if not video: logging.debug("Видео ({0}) не найдено в кэше, загружается новое.".format(video_hash)) with NamedTemporaryFile(suffix=".mp4") as video_file: logging.debug("Видео ({0}) сохраняется во временный файл {1}.".format( video_hash, video_file.name)) video_file.write(requests.get(video_url, stream=True).content) # Отправляем видео и сразу удаляем (это необходимо, чтобы получить File ID видео) video_message = client.send_video(telegram_user_id, video_file.name, disable_notification=True) client.delete_messages(telegram_user_id, video_message.message_id) video['FILE_ID'] = video_message.video.file_id video['CAPTION'] = attachment['video']['title'] asyncio.get_event_loop().run_until_complete(redis.execute( "HSET", "files:telegram:video:{0}".format(video_hash), "FILE_ID", video['FILE_ID'], "CAPTION", video['CAPTION'])) media.extend([InputMediaVideo(video['FILE_ID'], caption=video['CAPTION'])]) # TODO: Добавить поддержку плейлистов (корректное отображение) if attachment['type'] == "audio": audio_hash = sha1(attachment['audio']['url'].encode("UTF-8")).hexdigest() audio = asyncio.get_event_loop().run_until_complete( redis.execute("HGET", "files:telegram:audio:{0}".format(audio_hash), "FILE_ID"))['details'] # В Redis нет смысла сохранять исполнителя и название песни, так как при последующей отправке по # File ID, данные об исполнителе и названии песни остаются. if audio: logging.debug("Аудио ({0}) находится в кэше, отправляется по File ID.".format(audio_hash)) client.send_audio(telegram_user_id, audio) else: logging.debug("Аудио ({0}) не найдено в кэше, загружается новое.".format(audio_hash)) # VK может вернуть пустое URL, проверяем это сначала if not attachment['audio']['url']: logging.debug("Аудио, которое было отправлено пользователю, не может быть загружено, " "так как в нем не содержится ссылки (скорее всего, оно защищено " "авторскими правами и может воспроизводиться только из РФ).") client.send_message(telegram_user_id, "❗ Аудио ({0} — {1}) не может быть отправлено вам, так как " "оно защищено авторскими правами и может воспроизводиться только с " "территории Российской Федерации.".format( attachment['audio']['title'], attachment['audio']['artist'])) continue with NamedTemporaryFile(suffix=".mp3") as audio_file: logging.debug("Аудио ({0}) сохраняется во временный файл {1}.".format( audio_hash, audio_file.name)) audio_file.write(requests.get(attachment['audio']['url'], stream=True).content) audio = client.send_audio(telegram_user_id, audio_file.name, performer=attachment['audio']['artist'], title=attachment['audio']['title']).audio.file_id asyncio.get_event_loop().run_until_complete( redis.execute("HSET", "files:telegram:audio:{0}".format(audio_hash), "FILE_ID", audio)) if attachment['type'] == "sticker": sticker_hash = sha1(attachment['sticker']['images'][4]['url'].encode("UTF-8")).hexdigest() sticker = asyncio.get_event_loop().run_until_complete( redis.execute("HGET", "files:telegram:sticker:{0}".format(sticker_hash), "FILE_ID"))['details'] if sticker: logging.debug("Стикер ({0}) находится в кэше, отправляется по File ID.".format(sticker_hash)) client.send_sticker(telegram_user_id, sticker) else: logging.debug("Стикер ({0}) не найден в кэше, загружается новый.".format(sticker_hash)) sticker_png = Image.open( BytesIO(requests.get(attachment['sticker']['images'][4]['url'], stream=True).content)) with NamedTemporaryFile() as sticker_file: logging.debug("Стикер ({0}) сохраняется во временный файл {1}.".format( sticker_hash, sticker_file.name)) sticker_png.save(sticker_file, format="WEBP", lossless=True, quality=100, method=6) sticker = client.send_sticker(telegram_user_id, sticker_file.name).sticker.file_id asyncio.get_event_loop().run_until_complete( redis.execute("HSET", "files:telegram:sticker:{0}".format(sticker_hash), "FILE_ID", sticker)) if attachment['type'] == "audio_message": with NamedTemporaryFile(suffix=".ogg") as voice_message_file: logging.debug("Голосовое сообщение сохраняется во временный файл {0}.".format( voice_message_file.name)) voice_message_file.write( requests.get(attachment['audio_message']['link_ogg'], stream=True).content) client.send_voice(telegram_user_id, voice_message_file.name) # Проверяем, есть ли какое-то медиа (фотографии, видео) if media: client.send_media_group(telegram_user_id, media) sender = [sender for sender in response_lph['profiles'] if sender['id'] == message['from_id']][0] formatted_message_text = markup_multipurpose_fixes(message['text']) message_text = "**{0} {1}**{2}".format(sender['first_name'], sender['last_name'], # Если есть текст в сообщении, то добавляем его в сообщении "\n\n" + formatted_message_text if formatted_message_text else "") markup = InlineKeyboardMarkup([[InlineKeyboardButton("📋 Подробнее", callback_data=b"TEST")]]) message_data = client.send_message(telegram_user_id, message_text, reply_markup=markup) asyncio.get_event_loop().run_until_complete( redis.execute("SET", "message:telegram:{0}_{1}".format(message_data.chat.id, message_data.message_id), message_id) ) asyncio.get_event_loop().run_until_complete(redis.execute("HSET", user_id, "VK_LP_PTS", response_lph['new_pts'])) return {"status": "OK", "details": None} except Exception as e: logging.error("Произошла ошибка при polling'е аккаунта VK пользователя {0}.".format(user_id), exc_info=True) return e