packs_to_delete.append( pack) # list of packs we will have to delete else: logger.debug('api exception: %s', telegram_error.message) if not packs_to_delete: update.message.reply_text(Strings.CLEANUP_NO_PACK) return with session_scope() as session: for _, pack_name, _ in packs_to_delete: logger.info('deleting pack from db...') session.query(Pack).filter( Pack.user_id == update.effective_user.id, Pack.name == pack_name).delete() logger.info('done') packs_links = [ '<a href="{}">{}</a>'.format(utils.name2link(pack[1]), pack[0]) for pack in packs_to_delete ] update.message.reply_html(Strings.CLEANUP_HEADER + '• {}'.format('\n• '.join(packs_links))) return ConversationHandler.END # /cleanup should end whatever conversation the user was having stickersbot.add_handler(CommandHandler(['cleanup', 'cu'], on_cleanup_command))
@decorators.action(ChatAction.TYPING) @decorators.failwithmessage def on_animated_sticker_receive(update: Update, _): logger.info('user sent an animated sticker') update.message.reply_text(Strings.ADD_STICKER_ANIMATED_UNSUPPORTED) return WAITING_STICKER stickersbot.add_handler( ConversationHandler(name='export_command', entry_points=[ CommandHandler(['export', 'e', 'dump'], on_export_command) ], states={ WAITING_STICKER: [ MessageHandler(CustomFilters.static_sticker, on_sticker_receive), MessageHandler(CustomFilters.animated_sticker, on_animated_sticker_receive), ], }, fallbacks=[ CommandHandler(['cancel', 'c', 'done', 'd'], cancel_command) ]))
request_kwargs = dict(caption=sticker.emojis_str, quote=True) if update.message.sticker.is_animated: request_kwargs['document'] = sticker.tgs_file request_kwargs['filename'] = update.message.sticker.file_id + '.json' else: request_kwargs['document'] = sticker.png_file request_kwargs[ 'filename'] = '@DamienSouara-' + update.message.sticker.file_id + '.png' sent_message: Message = update.message.reply_document(**request_kwargs) sticker.close() if sent_message.document: # only do this when we send the message as document # it will be useful to test problems with animated stickers. For example in mid 2020, the API started # to consider any animated sticker as invalid ("wrong file type" exception), and they were sent # back as file with a specific mimetype ("something something bad animated sticker"). In this way: # - sent back as animated sticker: everything ok # - sent back as file: there's something wrong with the code/api, better to edit the document with its mimetype sent_message.edit_caption(caption='{}\n{}'.format( sent_message.caption, Strings.TO_FILE_MIME_TYPE.format(sent_message.document.mime_type)), parse_mode=ParseMode.HTML) elif sent_message.sticker: update.message.reply_text(Strings.ANIMATED_STICKERS_NO_FILE) stickersbot.add_handler(MessageHandler(Filters.sticker, on_sticker_receive))
def on_help_command(update: Update, context: CallbackContext): logger.info('/help') update.message.reply_html(Strings.HELP_MESSAGE.format( context.bot.username)) return ConversationHandler.END @decorators.action(ChatAction.TYPING) @decorators.restricted @decorators.failwithmessage def on_start_command(update: Update, _): logger.info('/start') start_message = Strings.START_MESSAGE if config.bot.sourcecode: start_message = '{}\n🛠<a href="{}">source code</a>'.format( start_message, config.bot.sourcecode) if config.bot.get('channel', None): start_message = '{}\n📣 <a href="https://t.me/{}">announcements channel</a>'.format( start_message, config.bot.channel) update.message.reply_html(start_message, disable_web_page_preview=True) return ConversationHandler.END stickersbot.add_handler(CommandHandler('help', on_help_command)) stickersbot.add_handler(CommandHandler('start', on_start_command))
stickersbot.add_handler( ConversationHandler( name='pack_creation', entry_points=[ CommandHandler(['create', 'new', 'n'], on_create_command) ], states={ WAITING_TITLE: [MessageHandler(Filters.text, on_pack_title_receive)], WAITING_NAME: [MessageHandler(Filters.text, on_pack_name_receive)], WAITING_FIRST_STICKER: [ MessageHandler( CustomFilters.static_sticker | Filters.document.category('image/png'), on_first_sticker_receive) ], ADDING_STICKERS: [ MessageHandler( CustomFilters.static_sticker | Filters.document.category('image/png'), on_sticker_receive), MessageHandler(CustomFilters.animated_sticker, on_animated_sticker_receive), ] }, fallbacks=[ CommandHandler(['cancel', 'c', 'done', 'd'], cancel_command) ]))
update.message.reply_text(Strings.EXPORT_ONGOING) # end the conversations maybe? # return ConversationHandler.END # end the conversations maybe? stickersbot.add_handler( ConversationHandler( name='export_command', persistent=False, entry_points=[ CommandHandler(['export', 'e', 'dump'], on_export_command) ], states={ Status.WAITING_STICKER: [ MessageHandler(CustomFilters.static_sticker, on_sticker_receive, run_async=True), MessageHandler(CustomFilters.animated_sticker, on_animated_sticker_receive), ], # ConversationHandler.TIMEOUT: [MessageHandler(Filters.all, on_timeout)] ConversationHandler.WAITING: [MessageHandler(Filters.all, on_ongoing_async_operation)] }, fallbacks=[ CommandHandler(['cancel', 'c', 'done', 'd'], cancel_command) ], # conversation_timeout=15 * 60 ))
from bot import stickersbot from bot.utils import decorators from bot.utils import utils from bot.database.base import session_scope from bot.database.models.pack import Pack from bot.strings import Strings logger = logging.getLogger(__name__) @decorators.action(ChatAction.TYPING) @decorators.restricted @decorators.failwithmessage def on_list_command(update: Update, _): logger.info('/list') # packs = db.get_user_packs(update.effective_user.id, as_namedtuple=True) with session_scope() as session: packs = session.query(Pack).filter_by(user_id=update.effective_user.id).all() packs = packs[:100] # can't include more than 100 entities strings_list = ['<a href="{}">{}</a>'.format(utils.name2link(pack.name), pack.title) for pack in packs] if not strings_list: update.message.reply_text(Strings.LIST_NO_PACKS) return update.message.reply_html('• {}'.format('\n• '.join(strings_list))) stickersbot.add_handler(CommandHandler(['list', 'l'], on_list_command))
stickersbot.add_handler( ConversationHandler( name='pack_creation', persistent=True, entry_points=[ CommandHandler(['create', 'new', 'n'], on_create_static_pack_command), CommandHandler(['createanimated', 'newanimated', 'na'], on_create_animated_pack_command) ], states={ Status.WAITING_TITLE: [ MessageHandler( Filters.text & ~Filters.command(STANDARD_CANCEL_COMMANDS), on_pack_title_receive) ], Status.WAITING_NAME: [ MessageHandler( Filters.text & ~Filters.command(STANDARD_CANCEL_COMMANDS), on_pack_name_receive) ], Status.WAITING_FIRST_STICKER: [ MessageHandler( # this handler is shared by both static and animated stickers Filters.sticker | Filters.document.category('image/png'), on_first_sticker_receive) ], Status.WAITING_STATIC_STICKERS: [ MessageHandler( CustomFilters.static_sticker | Filters.document.category('image/png'), on_static_sticker_receive), MessageHandler(CustomFilters.animated_sticker, on_bad_static_sticker_receive), ], Status.WAITING_ANIMATED_STICKERS: [ MessageHandler(CustomFilters.animated_sticker, on_animated_sticker_receive), MessageHandler( CustomFilters.static_sticker | Filters.document.category('image/png'), on_bad_animated_sticker_receive), ] }, fallbacks=[CommandHandler(STANDARD_CANCEL_COMMANDS, cancel_command)]))
# noinspection PyPackageRequirements from telegram import ChatAction, Update from bot import stickersbot from bot.database.base import session_scope from bot.database.models.pack import Pack from bot.strings import Strings from bot.utils import decorators logger = logging.getLogger(__name__) @decorators.action(ChatAction.TYPING) @decorators.restricted @decorators.failwithmessage def on_forgetme_command(update: Update, _): logger.info('/forgetme') with session_scope() as session: deleted_rows = session.query(Pack).filter( Pack.user_id == update.effective_user.id).delete() logger.info('deleted rows: %d', deleted_rows or 0) update.message.reply_text(Strings.FORGETME_SUCCESS) return ConversationHandler.END # /forgetme should end whatever conversation the user was having stickersbot.add_handler(CommandHandler(['forgetme', 'fm'], on_forgetme_command))
return update.message.reply_html("Hold on, this might take some time...") results_list = [] for pack in packs: logger.debug('checking pack: %s', pack[1]) pack_result_dict = dict(title=pack[0], name=pack[1], result=None) try: sticker_set = context.bot.get_sticker_set( user_id=update.effective_user.id, name=pack[1]) pack_result_dict['result'] = len(sticker_set.stickers) except TelegramError as telegram_error: logger.debug('api exception: %s', telegram_error.message) pack_result_dict['result'] = telegram_error.message results_list.append(pack_result_dict) strings_list = [ '<a href="{}">{}</a>: {}'.format(utils.name2link(p['name']), p['title'], p['result']) for p in results_list ] update.message.reply_html('• {}'.format('\n• '.join(strings_list))) stickersbot.add_handler(CommandHandler(['count'], on_count_command))
pack) # list of packs we will have to delete else: logger.debug('api exception: %s', telegram_error.message) if not packs_to_delete: update.message.reply_text(Strings.CLEANUP_NO_PACK) return with session_scope() as session: for _, pack_name, _ in packs_to_delete: logger.info('deleting pack from db...') session.query(Pack).filter( Pack.user_id == update.effective_user.id, Pack.name == pack_name).delete() logger.info('done') packs_links = [ '<a href="{}">{}</a>'.format(utils.name2link(pack[1]), pack[0]) for pack in packs_to_delete ] update.message.reply_html(Strings.CLEANUP_HEADER + '• {}'.format('\n• '.join(packs_links))) return ConversationHandler.END # /cleanup should end whatever conversation the user was having stickersbot.add_handler( CommandHandler(['cleanup', 'cu'], on_cleanup_command, run_async=True))
quote=True) except error.UnknwonError as e: update.message.reply_html(Strings.REMOVE_STICKER_GENERIC_ERROR.format( pack_link, e.message), quote=True) else: # success update.message.reply_html( Strings.REMOVE_STICKER_SUCCESS.format(pack_link), quote=True) finally: # wait for other stickers return WAITING_STICKERS stickersbot.add_handler( ConversationHandler( name='adding_stickers', entry_points=[ CommandHandler(['remove', 'rem', 'r'], on_remove_command) ], states={ WAITING_STICKERS: [ MessageHandler( Filters.sticker | Filters.document.category('image/png'), on_sticker_receive) ] }, fallbacks=[ CommandHandler(['cancel', 'c', 'done', 'd'], cancel_command) ]))
from telegram import Update, ChatAction from bot import stickersbot from bot.markups import Keyboard from bot.strings import Strings from .fallback_commands import STANDARD_CANCEL_COMMANDS from ..utils import decorators logger = logging.getLogger(__name__) @decorators.action(ChatAction.TYPING) @decorators.restricted @decorators.failwithmessage @decorators.logconversation def cancel_command_no_conversation(update: Update, context: CallbackContext): logger.info('%s command outside of a conversation', update.message.text) update.message.reply_text(Strings.CANCEL_NO_CONVERSATION, reply_markup=Keyboard.HIDE) # remove temporary data context.user_data.pop('pack', None) return ConversationHandler.END # this handler MUST be added AFTER all the ConversationHandler that use the 'cancel_command' function as # fallback handler stickersbot.add_handler( CommandHandler(STANDARD_CANCEL_COMMANDS, cancel_command_no_conversation))
return Status.WAITING_STICKER @decorators.action(ChatAction.TYPING) @decorators.failwithmessage @decorators.logconversation def on_invalid_message(update: Update, _): logger.info('(remove) waiting sticker: wrong type of message received') update.message.reply_html(Strings.REMOVE_INVALID_MESSAGE) return Status.WAITING_STICKER stickersbot.add_handler( ConversationHandler( name='adding_stickers', # persistent=True, # do not make this conversation persistent entry_points=[CommandHandler(['remove', 'rem'], on_remove_command)], states={ Status.WAITING_STICKER: [ MessageHandler(Filters.sticker, on_sticker_receive), MessageHandler(Filters.all & ~CustomFilters.sticker_or_cancel, on_invalid_message), ], ConversationHandler.TIMEOUT: [MessageHandler(Filters.all, on_timeout)] }, fallbacks=[CommandHandler(STANDARD_CANCEL_COMMANDS, cancel_command)], conversation_timeout=15 * 60))
@decorators.failwithmessage def on_switch_pack_type(update: Update, context: CallbackContext): logger.info('swicth pack type inline keyboard') if not context.user_data.get('pack', None): update.callback_query.answer(Strings.PACK_TYPE_BUTTONS_EXPIRED) update.callback_query.message.edit_reply_markup( reply_markup=InlineKeyboard.REMOVE) return match = context.matches[0].group(1) reply_markup = InlineKeyboard.static_animated_switch( animated=match == 'animated') if match == 'animated': context.user_data['pack']['animated'] = True else: context.user_data['pack']['animated'] = False try: update.callback_query.message.edit_reply_markup( reply_markup=reply_markup) except BadRequest: pass update.callback_query.answer(Strings.PACK_TYPE_CHANGED.format(match)) stickersbot.add_handler( CallbackQueryHandler(on_switch_pack_type, pattern='packtype:(.+)'))
return Status.WAITING_STICKER_OR_PACK_NAME @decorators.action(ChatAction.TYPING) @decorators.restricted @decorators.failwithmessage @decorators.logconversation def on_waiting_pack_unexpected_message(update: Update, context: CallbackContext): logger.info('/readd: unexpected message') update.message.reply_html(Strings.READD_UNEXPECTED_MESSAGE) return Status.WAITING_STICKER_OR_PACK_NAME stickersbot.add_handler(ConversationHandler( name='readd_command', persistent=False, entry_points=[CommandHandler(['readd', 'rea', 'ra'], on_readd_command)], states={ Status.WAITING_STICKER_OR_PACK_NAME: [ MessageHandler(CustomFilters.static_sticker, on_waiting_pack_static_sticker), MessageHandler(CustomFilters.animated_sticker, on_waiting_pack_animated_sticker), MessageHandler(Filters.all & ~CustomFilters.done_or_cancel, on_waiting_pack_unexpected_message), ], ConversationHandler.TIMEOUT: [MessageHandler(Filters.all, on_timeout)] }, fallbacks=[CommandHandler(['cancel', 'c', 'done', 'd'], cancel_command)], # conversation_timeout=15 * 60 ))
stickersbot.add_handler( ConversationHandler( name='create_or_add', persistent=True, entry_points=[ # CREATE CommandHandler(['create', 'new'], create.on_create_static_pack_command), # ADD CommandHandler(['add', 'a'], add.on_add_command) ], states={ # CREATE Status.CREATE_WAITING_TITLE: [ MessageHandler( Filters.text & ~Filters.command(STANDARD_CANCEL_COMMANDS), create.on_pack_title_receive), MessageHandler(~Filters.text, create.on_waiting_title_invalid_message) ], Status.CREATE_WAITING_NAME: [ MessageHandler( Filters.text & ~Filters.command(STANDARD_CANCEL_COMMANDS), create.on_pack_name_receive), MessageHandler(~Filters.text, create.on_waiting_name_invalid_message) ], Status.CREATE_WAITING_FIRST_STICKER: [ MessageHandler(Filters.text & ~Filters.command, create.on_first_sticker_text_receive ), # in case the user sends the emojis # this handler is shared by both static and animated stickers MessageHandler(Filters.sticker | CustomFilters.png_file, create.on_first_sticker_receive), MessageHandler(~Filters.text, create.on_waiting_first_sticker_invalid_message) ], # ADD Status.ADD_WAITING_TITLE: [ MessageHandler(~Filters.text, add.on_waiting_title_invalid_message), MessageHandler( Filters.text & ~Filters.command(STANDARD_CANCEL_COMMANDS), add.on_pack_title) ], Status.ADD_WAITING_NAME: [ MessageHandler(~Filters.text, add.on_waiting_name_invalid_message), MessageHandler( Filters.text & ~Filters.command(STANDARD_CANCEL_COMMANDS), add.on_pack_name) ], # SHARED (ADD) Status.WAITING_STATIC_STICKERS: [ MessageHandler( Filters.text & ~Filters.command, add.on_text_receive), # in case the user sends the emojis MessageHandler(CustomFilters.static_sticker_or_png_file, add.on_static_sticker_receive), MessageHandler(CustomFilters.animated_sticker, add.on_bad_static_sticker_receive), # for everything that is not catched by the handlers above MessageHandler( Filters.all & ~Filters.command(STANDARD_CANCEL_COMMANDS), add.on_waiting_sticker_invalid_message) ], Status.WAITING_ANIMATED_STICKERS: [ MessageHandler( Filters.text & ~Filters.command, add.on_text_receive), # in case the user sends the emojis MessageHandler(CustomFilters.animated_sticker, add.on_animated_sticker_receive), MessageHandler(CustomFilters.static_sticker_or_png_file, add.on_bad_animated_sticker_receive), # for everything that is not catched by the handlers above MessageHandler( Filters.all & ~Filters.command(STANDARD_CANCEL_COMMANDS), add.on_waiting_sticker_invalid_message) ], # TIMEOUT ConversationHandler.TIMEOUT: [MessageHandler(Filters.all, on_timeout)] }, fallbacks=[CommandHandler(STANDARD_CANCEL_COMMANDS, cancel_command)], conversation_timeout=15 * 60))
update.message.reply_text(Strings.ADD_STICKER_EXPECTING_ANIMATED) return Status.WAITING_ANIMATED_STICKERS stickersbot.add_handler(ConversationHandler( name='adding_stickers', persistent=True, entry_points=[CommandHandler(['add', 'a'], on_add_command)], states={ Status.WAITING_TITLE: [MessageHandler(Filters.text & ~Filters.command(STANDARD_CANCEL_COMMANDS), on_pack_title)], Status.WAITING_NAME: [MessageHandler(Filters.text & ~Filters.command(STANDARD_CANCEL_COMMANDS), on_pack_name)], Status.WAITING_STATIC_STICKERS: [ MessageHandler( CustomFilters.static_sticker | Filters.document.category('image/png'), on_static_sticker_receive ), MessageHandler(CustomFilters.animated_sticker, on_bad_static_sticker_receive), ], Status.WAITING_ANIMATED_STICKERS: [ MessageHandler(CustomFilters.animated_sticker, on_animated_sticker_receive), MessageHandler( CustomFilters.static_sticker | Filters.document.category('image/png'), on_bad_animated_sticker_receive ), ] }, fallbacks=[CommandHandler(STANDARD_CANCEL_COMMANDS, cancel_command)] ))
return update.message.reply_html("Hold on, this might take some time...") results_list = [] for pack in packs: logger.debug('checking pack: %s', pack[1]) pack_result_dict = dict(title=pack[0], name=pack[1], result=None) try: sticker_set = context.bot.get_sticker_set(name=pack[1]) pack_result_dict['result'] = len(sticker_set.stickers) except TelegramError as telegram_error: logger.debug('api exception: %s', telegram_error.message) pack_result_dict['result'] = telegram_error.message results_list.append(pack_result_dict) strings_list = [ '<a href="{}">{}</a>: {}'.format(utils.name2link(p['name']), p['title'], p['result']) for p in results_list ] update.message.reply_html('• {}'.format('\n• '.join(strings_list))) stickersbot.add_handler( CommandHandler(['count'], on_count_command, run_async=True))
logger.info('user sent a static stciker to convert') sticker = StickerFile(update.message.sticker) sticker.download(prepare_png=True) update.message.reply_document(sticker.png_file, filename=update.message.sticker.file_id + '.png', quote=True) sticker.close() @decorators.restricted @decorators.action(ChatAction.UPLOAD_DOCUMENT) @decorators.failwithmessage def on_animated_sticker_receive(update: Update, _): logger.info('user sent an animated stciker to convert') # sending an animated sticker's .tgs file with send_document sends it as animated sticker update.message.reply_text(Strings.ANIMATED_STICKERS_NO_FILE, quote=True) return # sticker = StickerFile(update.message.sticker) # sticker.download(prepare_png=False) # update.message.reply_document(sticker.tgs_file, filename=update.message.sticker.file_id + '.tgs', quote=True) # sticker.close() stickersbot.add_handler(MessageHandler(CustomFilters.static_sticker, on_static_sticker_receive)) stickersbot.add_handler(MessageHandler(Filters.sticker, on_animated_sticker_receive))