def message_text_handler(update: telegram.Update, context: telegram.ext.CallbackContext) -> None: message = update.effective_message if message is None: return chat = update.effective_chat if chat is None: return chat_type = chat.type bot = context.bot if cli_args.debug and not utils.check_admin( bot, context, message, analytics_handler, ADMIN_USER_ID): return message_id = message.message_id chat_id = message.chat.id user = message.from_user entities = message.parse_entities() if user is not None: create_or_update_user(bot, user) analytics_handler.track(context, analytics.AnalyticsType.MESSAGE, user) valid_entities = { entity: text for entity, text in entities.items() if entity.type in [telegram.MessageEntity.URL, telegram.MessageEntity.TEXT_LINK] } entity, text = next(iter(valid_entities.items())) if entity is None: return input_link = entity.url if input_link is None: input_link = text with io.BytesIO() as output_bytes: caption = None video_url = None audio_url = None try: yt_dl_options = {'logger': logger, 'no_color': True} with youtube_dl.YoutubeDL(yt_dl_options) as yt_dl: video_info = yt_dl.extract_info(input_link, download=False) if 'entries' in video_info: video = video_info['entries'][0] else: video = video_info if 'title' in video: caption = video['title'] else: caption = input_link file_size = None if 'requested_formats' in video: requested_formats = video['requested_formats'] video_data = list( filter( lambda requested_format: requested_format['vcodec'] != 'none', requested_formats))[0] audio_data = list( filter( lambda requested_format: requested_format['acodec'] != 'none', requested_formats))[0] if 'filesize' in video_data: file_size = video_data['filesize'] video_url = video_data['url'] if file_size is None: file_size = utils.get_file_size(video_url) audio_url = audio_data['url'] elif 'url' in video: video_url = video['url'] file_size = utils.get_file_size(video_url) if file_size is not None: if not utils.ensure_size_under_limit( file_size, telegram.constants.MAX_FILESIZE_UPLOAD, update, context): return except Exception as error: logger.error(f'youtube-dl error: {error}') if chat_type == telegram.Chat.PRIVATE and (caption is None or video_url is None): bot.send_message(chat_id, 'No video found on this link.', disable_web_page_preview=True, reply_to_message_id=message_id) return mp4_bytes = utils.convert(constants.OutputType.VIDEO, input_video_url=video_url, input_audio_url=audio_url) if not utils.ensure_valid_converted_file( file_bytes=mp4_bytes, update=update, context=context): return if mp4_bytes is not None: output_bytes.write(mp4_bytes) output_bytes.seek(0) if caption is not None: caption = caption[:telegram.constants.MAX_CAPTION_LENGTH] utils.send_video(bot, chat_id, message_id, output_bytes, caption, chat_type)
def message_answer_handler(update: telegram.Update, context: telegram.ext.CallbackContext) -> None: callback_query = update.callback_query if callback_query is None: return raw_callback_data = callback_query.data if raw_callback_data is None: callback_query.answer() return callback_data = json.loads(raw_callback_data) if callback_data is None: callback_query.answer() return message = update.effective_message if message is None: return chat = update.effective_chat if chat is None: return chat_type = chat.type bot = context.bot attachment = message.effective_attachment if attachment is None: return if not isinstance(attachment, telegram.Video): return file_size = attachment.file_size if file_size is not None and not utils.ensure_size_under_limit( file_size, telegram.constants.MAX_FILESIZE_DOWNLOAD, update, context): return attachment_file_id = attachment.file_id message_id = message.message_id chat_id = message.chat.id user = update.effective_user if user is not None: create_or_update_user(bot, user) analytics_handler.track(context, analytics.AnalyticsType.MESSAGE, user) if chat_type == telegram.Chat.PRIVATE: bot.send_chat_action(chat_id, telegram.ChatAction.TYPING) input_file = bot.get_file(attachment_file_id) input_file_url = input_file.file_path probe = None try: probe = ffmpeg.probe(input_file_url) except ffmpeg.Error: pass with io.BytesIO() as output_bytes: output_type = constants.OutputType.NONE invalid_format = None if probe: for stream in probe['streams']: codec_name = stream.get('codec_name') if codec_name is not None: invalid_format = codec_name if codec_name in constants.VIDEO_CODEC_NAMES: output_type = constants.OutputType.VIDEO_NOTE mp4_bytes = utils.convert(output_type, input_video_url=input_file_url) if not utils.ensure_valid_converted_file( file_bytes=mp4_bytes, update=update, context=context): callback_query.answer() return if mp4_bytes is not None: output_bytes.write(mp4_bytes) break continue if output_type == constants.OutputType.NONE: if chat_type == telegram.Chat.PRIVATE: if invalid_format is None and input_file_url is not None: parts = os.path.splitext(input_file_url) if parts is not None and len(parts) >= 2: extension = parts[1] if extension is not None: invalid_format = extension[1:] bot.send_message( chat_id=chat_id, text=f'File type "{invalid_format}" is not yet supported.', reply_to_message_id=message_id) callback_query.answer() return output_bytes.seek(0) output_file_size = output_bytes.getbuffer().nbytes if output_type == constants.OutputType.VIDEO_NOTE: if not utils.ensure_size_under_limit( output_file_size, telegram.constants.MAX_FILESIZE_UPLOAD, update, context, file_reference_text='Converted file'): callback_query.answer() return bot.send_chat_action(chat_id, telegram.ChatAction.UPLOAD_VIDEO) utils.send_video_note(bot, chat_id, message_id, output_bytes) callback_query.answer() return if chat_type == telegram.Chat.PRIVATE: bot.send_message(chat_id, 'File type is not yet supported.', reply_to_message_id=message_id) callback_query.answer()
def message_file_handler(update: telegram.Update, context: telegram.ext.CallbackContext) -> None: message = update.effective_message chat = update.effective_chat if chat is None: return chat_type = chat.type bot = context.bot if message is None: return if cli_args.debug and not utils.check_admin( bot, context, message, analytics_handler, ADMIN_USER_ID): return message_id = message.message_id chat_id = message.chat.id attachment = message.effective_attachment if attachment is None: return if type(attachment) is list: if chat_type == telegram.Chat.PRIVATE: bot.send_message( chat_id, 'You need to send the image as a file to convert it to a sticker.', reply_to_message_id=message_id) return if not isinstance( attachment, (telegram.Audio, telegram.Document, telegram.Voice, telegram.Sticker)): return message_type = telegram.utils.helpers.effective_message_type(message) file_size = attachment.file_size if file_size is None: return if not utils.ensure_size_under_limit( file_size, telegram.constants.MAX_FILESIZE_DOWNLOAD, update, context): return user = message.from_user input_file_id = attachment.file_id input_file_name = None if isinstance(attachment, (telegram.Audio, telegram.Document)): input_file_name = attachment.file_name if input_file_name is None and isinstance(attachment, telegram.Audio): input_file_name = attachment.title if user is not None: create_or_update_user(bot, user) analytics_handler.track(context, analytics.AnalyticsType.MESSAGE, user) if chat_type == telegram.Chat.PRIVATE: bot.send_chat_action(chat_id, telegram.ChatAction.TYPING) input_file = bot.get_file(input_file_id) input_file_url = input_file.file_path probe = None try: probe = ffmpeg.probe(input_file_url) except ffmpeg.Error: pass with io.BytesIO() as output_bytes: output_type = constants.OutputType.NONE caption = None invalid_format = None if message_type == 'voice': output_type = constants.OutputType.FILE mp3_bytes = utils.convert(output_type, input_audio_url=input_file_url) if not utils.ensure_valid_converted_file( file_bytes=mp3_bytes, update=update, context=context): return if mp3_bytes is not None: output_bytes.write(mp3_bytes) output_bytes.name = 'voice.mp3' elif message_type == 'sticker': with io.BytesIO() as input_bytes: input_file.download(out=input_bytes) try: image = PIL.Image.open(input_bytes) with io.BytesIO() as image_bytes: image.save(image_bytes, format='PNG') image_bytes.seek(0) output_bytes.write(image_bytes.read()) output_type = constants.OutputType.PHOTO sticker = message['sticker'] emoji = sticker['emoji'] set_name = sticker['set_name'] caption = f'Sticker for the emoji "{emoji}" from the set "{set_name}"' except Exception as error: logger.error(f'PIL error: {error}') else: if probe: for stream in probe['streams']: codec_name = stream.get('codec_name') if codec_name is not None: invalid_format = codec_name if codec_name in constants.VIDEO_CODEC_NAMES: output_type = constants.OutputType.VIDEO mp4_bytes = utils.convert( output_type, input_video_url=input_file_url) if not utils.ensure_valid_converted_file( file_bytes=mp4_bytes, update=update, context=context): return if mp4_bytes is not None: output_bytes.write(mp4_bytes) break continue if output_type == constants.OutputType.NONE: for stream in probe['streams']: codec_name = stream.get('codec_name') if codec_name is not None: invalid_format = codec_name if codec_name in constants.AUDIO_CODEC_NAMES: output_type = constants.OutputType.AUDIO opus_bytes = utils.convert( output_type, input_audio_url=input_file_url) if not utils.ensure_valid_converted_file( file_bytes=opus_bytes, update=update, context=context): return if opus_bytes is not None: output_bytes.write(opus_bytes) break elif codec_name == 'opus': input_file.download(out=output_bytes) output_type = constants.OutputType.AUDIO break continue if output_type == constants.OutputType.NONE: with io.BytesIO() as input_bytes: input_file.download(out=input_bytes) input_bytes.seek(0) try: images = pdf2image.convert_from_bytes(input_bytes.read()) image = images[0] with io.BytesIO() as image_bytes: image.save(image_bytes, format='PNG') image_bytes.seek(0) output_bytes.write(image_bytes.read()) output_type = constants.OutputType.PHOTO except Exception as error: logger.error(f'pdf2image error: {error}') if output_type == constants.OutputType.NONE: try: image = PIL.Image.open(input_bytes) with io.BytesIO() as image_bytes: image.save(image_bytes, format='WEBP') image_bytes.seek(0) output_bytes.write(image_bytes.read()) output_type = constants.OutputType.STICKER except Exception as error: logger.error(f'PIL error: {error}') if output_type == constants.OutputType.NONE: if chat_type == telegram.Chat.PRIVATE: if invalid_format is None and input_file_url is not None: parts = os.path.splitext(input_file_url) if parts is not None and len(parts) >= 2: extension = parts[1] if extension is not None: invalid_format = extension[1:] bot.send_message( chat_id=chat_id, text=f'File type "{invalid_format}" is not yet supported.', reply_to_message_id=message_id) return output_bytes.seek(0) output_file_size = output_bytes.getbuffer().nbytes if caption is None and input_file_name is not None: caption = input_file_name[:telegram.constants.MAX_CAPTION_LENGTH] if output_type == constants.OutputType.AUDIO: if not utils.ensure_size_under_limit( output_file_size, telegram.constants.MAX_FILESIZE_UPLOAD, update, context, file_reference_text='Converted file'): return bot.send_chat_action(chat_id, telegram.ChatAction.UPLOAD_AUDIO) bot.send_voice(chat_id, output_bytes, caption=caption, reply_to_message_id=message_id) return elif output_type == constants.OutputType.VIDEO: if not utils.ensure_size_under_limit( output_file_size, telegram.constants.MAX_FILESIZE_UPLOAD, update, context, file_reference_text='Converted file'): return bot.send_chat_action(chat_id, telegram.ChatAction.UPLOAD_VIDEO) utils.send_video(bot, chat_id, message_id, output_bytes, caption, chat_type) return elif output_type == constants.OutputType.PHOTO: if not utils.ensure_size_under_limit( output_file_size, constants.MAX_PHOTO_FILESIZE_UPLOAD, update, context, file_reference_text='Converted file'): return bot.send_photo(chat_id, output_bytes, caption=caption, reply_to_message_id=message_id) return elif output_type == constants.OutputType.STICKER: bot.send_sticker(chat_id, output_bytes, reply_to_message_id=message_id) return elif output_type == constants.OutputType.FILE: if not utils.ensure_size_under_limit( output_file_size, telegram.constants.MAX_FILESIZE_UPLOAD, update, context, file_reference_text='Converted file'): return bot.send_chat_action(chat_id, telegram.ChatAction.UPLOAD_DOCUMENT) bot.send_document(chat_id, output_bytes, reply_to_message_id=message_id) return if chat_type == telegram.Chat.PRIVATE: bot.send_message(chat_id, 'File type is not yet supported.', reply_to_message_id=message_id)
def message_answer_handler(update: Update, context: CallbackContext): callback_query = update.callback_query callback_data = json.loads(callback_query.data) if not callback_data: callback_query.answer() return original_attachment_file_id = callback_data[ATTACHMENT_FILE_ID_KEY] message = update.effective_message chat_type = update.effective_chat.type bot = context.bot message_id = message.message_id chat_id = message.chat.id user = update.effective_user create_or_update_user(bot, user) analytics.track(AnalyticsType.MESSAGE, user) if chat_type == Chat.PRIVATE: bot.send_chat_action(chat_id, ChatAction.TYPING) input_file = bot.get_file(original_attachment_file_id) input_file_url = input_file.file_path probe = None try: probe = ffmpeg.probe(input_file_url) except: pass with io.BytesIO() as output_bytes: output_type = OutputType.NONE invalid_format = None if probe: for stream in probe['streams']: codec_name = stream.get('codec_name') codec_type = stream.get('codec_type') if codec_name is not None and codec_type == VIDEO_CODED_TYPE: invalid_format = codec_name if codec_name in VIDEO_CODEC_NAMES: output_type = OutputType.VIDEO_NOTE mp4_bytes = convert(output_type, input_video_url=input_file_url) output_bytes.write(mp4_bytes) break else: continue if output_type == OutputType.NONE: if chat_type == Chat.PRIVATE: if invalid_format is None: invalid_format = os.path.splitext(input_file_url)[1][1:] bot.send_message(chat_id, 'File type "{}" is not yet supported.'.format( invalid_format), reply_to_message_id=message_id) callback_query.answer() return output_bytes.seek(0) output_file_size = output_bytes.getbuffer().nbytes if output_type == OutputType.VIDEO_NOTE: if not ensure_size_under_limit( output_file_size, MAX_FILESIZE_UPLOAD, update, context, file_reference_text='Converted file'): callback_query.answer() return bot.send_chat_action(chat_id, ChatAction.UPLOAD_VIDEO) send_video_note(bot, chat_id, message_id, output_bytes) callback_query.answer() return if chat_type == Chat.PRIVATE: bot.send_message(chat_id, 'File type is not yet supported.', reply_to_message_id=message_id) callback_query.answer()
def message_text_handler(update: Update, context: CallbackContext): message = update.message chat_type = update.effective_chat.type bot = context.bot if cli_args.debug and not check_admin(bot, message, analytics, ADMIN_USER_ID): return message_id = message.message_id chat_id = message.chat.id user = message.from_user entities = message.parse_entities() create_or_update_user(bot, user) analytics.track(AnalyticsType.MESSAGE, user) entity, text = next( ((entity, text) for entity, text in entities.items() if entity.type in [MessageEntity.URL, MessageEntity.TEXT_LINK]), None) if entity is None: return input_link = entity.url if input_link is None: input_link = text with io.BytesIO() as output_bytes: caption = None video_url = None try: yt_dl_options = {'logger': logger, 'no_color': True} with youtube_dl.YoutubeDL(yt_dl_options) as yt_dl: video_info = yt_dl.extract_info(input_link, download=False) if 'entries' in video_info: video = video_info['entries'][0] else: video = video_info if 'title' in video: caption = video['title'] else: caption = input_link requested_formats = video['requested_formats'] video_data = list( filter(lambda format: format['vcodec'] != 'none', requested_formats))[0] audio_data = list( filter(lambda format: format['acodec'] != 'none', requested_formats))[0] if not ensure_size_under_limit(video_data['filesize'], MAX_FILESIZE_UPLOAD, update, context): return video_url = video_data['url'] audio_url = audio_data['url'] except Exception as error: logger.error('youtube-dl error: {}'.format(error)) if chat_type == Chat.PRIVATE and (caption is None or video_url is None): bot.send_message(chat_id, 'No video found on "{}".'.format(input_link), disable_web_page_preview=True, reply_to_message_id=message_id) return mp4_bytes = convert(OutputType.VIDEO, input_video_url=video_url, input_audio_url=audio_url) output_bytes.write(mp4_bytes) output_bytes.seek(0) caption = caption[:MAX_CAPTION_LENGTH] # Video note isn't supported for videos downloaded from URLs yet. send_video(bot, chat_id, message_id, output_bytes, None, caption, chat_type)
def message_video_handler(update: Update, context: CallbackContext): message = update.effective_message chat_type = update.effective_chat.type bot = context.bot if chat_type != Chat.PRIVATE: return if cli_args.debug and not check_admin(bot, message, analytics, ADMIN_USER_ID): return message_id = message.message_id chat_id = message.chat.id attachment = message.video if not ensure_size_under_limit(attachment.file_size, MAX_FILESIZE_DOWNLOAD, update, context): return user = update.effective_user input_file_id = attachment.file_id create_or_update_user(bot, user) analytics.track(AnalyticsType.MESSAGE, user) bot.send_chat_action(chat_id, ChatAction.TYPING) input_file = bot.get_file(input_file_id) input_file_url = input_file.file_path probe = None try: probe = ffmpeg.probe(input_file_url) except: pass with io.BytesIO() as output_bytes: output_type = OutputType.NONE invalid_format = None if probe: for stream in probe['streams']: codec_name = stream.get('codec_name') codec_type = stream.get('codec_type') if codec_name is not None and codec_type == VIDEO_CODED_TYPE: invalid_format = codec_name if codec_name in VIDEO_CODEC_NAMES: output_type = OutputType.VIDEO_NOTE mp4_bytes = convert(output_type, input_video_url=input_file_url) output_bytes.write(mp4_bytes) break else: continue if output_type == OutputType.NONE: if invalid_format is None: invalid_format = os.path.splitext(input_file_url)[1][1:] bot.send_message( chat_id, 'File type "{}" is not yet supported.'.format(invalid_format), reply_to_message_id=message_id) output_bytes.seek(0) output_file_size = output_bytes.getbuffer().nbytes if output_type == OutputType.VIDEO_NOTE: if not ensure_size_under_limit( output_file_size, MAX_FILESIZE_UPLOAD, update, context, file_reference_text='Converted file'): return bot.send_chat_action(chat_id, ChatAction.UPLOAD_VIDEO) send_video_note(bot, chat_id, message_id, output_bytes) return bot.send_message(chat_id, 'File type is not yet supported.', reply_to_message_id=message_id)
def message_file_handler(update: Update, context: CallbackContext): message = update.message chat_type = update.effective_chat.type bot = context.bot if cli_args.debug and not check_admin(bot, message, analytics, ADMIN_USER_ID): return message_id = message.message_id chat_id = message.chat.id attachment = message.effective_attachment if type(attachment) is list: if chat_type == Chat.PRIVATE: bot.send_message( chat_id, 'You need to send the image as a file to convert it to a sticker.', reply_to_message_id=message_id) return if not ensure_size_under_limit(attachment.file_size, MAX_FILESIZE_DOWNLOAD, update, context): return user = message.from_user input_file_id = attachment.file_id input_file_name = attachment.file_name if getattr( attachment, 'file_name', None) else attachment.title create_or_update_user(bot, user) analytics.track(AnalyticsType.MESSAGE, user) if chat_type == Chat.PRIVATE: bot.send_chat_action(chat_id, ChatAction.TYPING) input_file = bot.get_file(input_file_id) input_file_url = input_file.file_path probe = None try: probe = ffmpeg.probe(input_file_url) except: pass with io.BytesIO() as output_bytes: output_type = OutputType.NONE invalid_format = None if probe: for stream in probe['streams']: codec_name = stream.get('codec_name') codec_type = stream.get('codec_type') if codec_name is not None and codec_type == VIDEO_CODED_TYPE: invalid_format = codec_name if codec_name == 'mp3': output_type = OutputType.AUDIO opus_bytes = convert(output_type, input_video_url=input_file_url) output_bytes.write(opus_bytes) break elif codec_name == 'opus': input_file.download(out=output_bytes) output_type = OutputType.AUDIO break elif codec_name in VIDEO_CODEC_NAMES: output_type = OutputType.VIDEO mp4_bytes = convert(output_type, input_video_url=input_file_url) output_bytes.write(mp4_bytes) break else: continue if output_type == OutputType.NONE: with io.BytesIO() as input_bytes: input_file.download(out=input_bytes) try: images = convert_from_bytes(input_bytes.getbuffer()) image = images[0] with io.BytesIO() as image_bytes: image.save(image_bytes, format='PNG') output_bytes.write(image_bytes.getbuffer()) output_type = OutputType.PHOTO except Exception as error: logger.error('pdf2image error: {}'.format(error)) if output_type == OutputType.NONE: try: image = Image.open(input_bytes) with io.BytesIO() as image_bytes: image.save(image_bytes, format='WEBP') output_bytes.write(image_bytes.getbuffer()) output_type = OutputType.STICKER except Exception as error: logger.error('PIL error: {}'.format(error)) if output_type == OutputType.NONE: if chat_type == Chat.PRIVATE: if invalid_format is None: invalid_format = os.path.splitext(input_file_url)[1][1:] bot.send_message(chat_id, 'File type "{}" is not yet supported.'.format( invalid_format), reply_to_message_id=message_id) return output_bytes.seek(0) output_file_size = output_bytes.getbuffer().nbytes caption = None if input_file_name is not None: caption = input_file_name[:MAX_CAPTION_LENGTH] if output_type == OutputType.AUDIO: if not ensure_size_under_limit( output_file_size, MAX_FILESIZE_UPLOAD, update, context, file_reference_text='Converted file'): return bot.send_chat_action(chat_id, ChatAction.UPLOAD_AUDIO) bot.send_voice(chat_id, output_bytes, caption=caption, reply_to_message_id=message_id) return elif output_type == OutputType.VIDEO: if not ensure_size_under_limit( output_file_size, MAX_FILESIZE_UPLOAD, update, context, file_reference_text='Converted file'): return bot.send_chat_action(chat_id, ChatAction.UPLOAD_VIDEO) send_video(bot, chat_id, message_id, output_bytes, attachment, caption, chat_type) return elif output_type == OutputType.PHOTO: if not ensure_size_under_limit( output_file_size, MAX_PHOTO_FILESIZE_UPLOAD, update, context, file_reference_text='Converted file'): return bot.send_photo(chat_id, output_bytes, caption=caption, reply_to_message_id=message_id) return elif output_type == OutputType.STICKER: bot.send_sticker(chat_id, output_bytes, reply_to_message_id=message_id) return if chat_type == Chat.PRIVATE: bot.send_message(chat_id, 'File type is not yet supported.', reply_to_message_id=message_id)