From c8c1dd4bfede5f3b3e682757aca2b906b498782f Mon Sep 17 00:00:00 2001 From: gryf Date: Sat, 26 Nov 2016 17:55:33 +0100 Subject: [PATCH] Small fixes, version bump, alpha stage, added emoji map. --- README.rst | 33 +- setup.py | 9 +- slack_backup/client.py | 11 +- slack_backup/download.py | 2 +- slack_backup/emoji.py | 1822 +++++++++++++++++++++++++++++++++++++ slack_backup/reporters.py | 74 +- 6 files changed, 1918 insertions(+), 33 deletions(-) create mode 100644 slack_backup/emoji.py diff --git a/README.rst b/README.rst index e51e52a..574ae0d 100644 --- a/README.rst +++ b/README.rst @@ -4,9 +4,9 @@ Slack backup .. image:: https://travis-ci.org/gryf/slack-backup.svg?branch=master :target: https://travis-ci.org/gryf/slack-backup -This simple project which aim is to collect conversations from Slack using its -API and optionally user account information, and provides convenient way to -represent as a log. +This project aim is to collect conversations from Slack using its API and +optionally user account information, and provides convenient way to represent +as a log. Requirements ------------ @@ -111,6 +111,33 @@ where: The rest of the options (``-d`` and ``-v``) have same meaning as in ``fetch`` command. +See help for the ``slack-backup`` command for complete list of options. + + +Details +------- + +During first run, database with provided name is generated. For ease of use +sqlite database is used, although it is easy to switch the engine, since there +is an ORM (SQLAlchemy) used. + +Slack users, channels and messages are mapped to SQLAlchemy models, as well as +other information, like: + +- user profiles +- channel topic +- channel purpose +- message reactions +- message attachments +- and files + +Channels and users are always synchronized in every run, so every modification +to the user or channels are overwriting old data. During first run, all messages +are retrieved for all/selected channels. Every other run will only fetch those +messages, which are older then newest message in the database - so that we don't +loose any old messages, which might be automatically removed from Slack servers. +The drawback of this behaviour is that all past messages which was altered in +the meantime will not be updated. License ------- diff --git a/setup.py b/setup.py index 0561118..519c1e0 100644 --- a/setup.py +++ b/setup.py @@ -2,12 +2,15 @@ """ Setup for the slack-backup project """ -from distutils.core import setup +try: + from setuptools import setup +except ImportError: + from distutils.core import setup setup(name="slack-backup", packages=["slack_backup"], - version="0.1", + version="0.2", description="Make copy of slack converstaions", author="Roman Dobosz", author_email="gryf73@gmail.com", @@ -18,7 +21,7 @@ setup(name="slack-backup", scripts=["scripts/slack-backup"], classifiers=["Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", - "Development Status :: 2 - Pre-Alpha", + "Development Status :: 3 - Alpha", "Environment :: Console", "Intended Audience :: End Users/Desktop", "License :: OSI Approved :: BSD License", diff --git a/slack_backup/client.py b/slack_backup/client.py index 60b803a..0338d1c 100644 --- a/slack_backup/client.py +++ b/slack_backup/client.py @@ -146,10 +146,17 @@ class Client(object): Create message with corresponding possible metadata, like reactions, files etc. """ - message = o.Message(data) - message.user = self.q(o.User).\ + user = self.q(o.User).\ filter(o.User.slackid == data['user']).one() + + if data['type'] == 'message' and not data['text'].strip(): + logging.info("Skipping message from `%s' since it's empty", + user.name) + return + + message = o.Message(data) message.channel = channel + message.user = user if data.get('is_starred'): message.is_starred = True diff --git a/slack_backup/download.py b/slack_backup/download.py index 4c2d376..9ffad39 100644 --- a/slack_backup/download.py +++ b/slack_backup/download.py @@ -78,7 +78,7 @@ class Download(object): path = os.path.join(path, fname) count = 1 - while os.path.exists(path): + while filetype != 'avatar' and os.path.exists(path): base, ext = os.path.splitext(path) path = base + "%0.3d" % count + ext diff --git a/slack_backup/emoji.py b/slack_backup/emoji.py new file mode 100644 index 0000000..e0382db --- /dev/null +++ b/slack_backup/emoji.py @@ -0,0 +1,1822 @@ +# -*- coding: utf-8 -*- +""" +This module contains emoji list +""" + + +EMOJI = {'plain': {":bowtie:": ':)8', + ":smile:": ':)', + ":simple_smile:": ':)', + ":slightly_smiling_face:": ':)', + ":laughing:": ':D', + ":blush:": ':$', + ":smiley:": ':-)', + ":relaxed:": ':3', + ":smirk:": ';)', + ":heart_eyes:": '8-)', + ":kissing_heart:": ':* <3', + ":kissing_closed_eyes:": ':*', + ":flushed:": 'O_O', + ":relieved:": '^_^!', + ":satisfied:": 'XD', + ":grin:": ':D', + ":wink:": ';-)', + ":stuck_out_tongue_winking_eye:": ';-P', + ":stuck_out_tongue_closed_eyes:": 'X-P', + ":grinning:": ':D', + ":kissing:": ':*', + ":kissing_smiling_eyes:": ':*', + ":stuck_out_tongue:": ':-P', + ":sleeping:": '-_- zZ', + ":worried:": '(ใƒผใƒผ`)', + ":frowning:": '>:-(', + ":anguished:": 'D-:', + ":open_mouth:": ':-O', + ":grimacing:": '>:-#', + ":confused:": ':-/', + ":hushed:": ':-', + ":expressionless:": ':-|', + ":unamused:": ':-7', + ":sweat_smile:": "(^_^')", + ":sweat:": "(-_-')", + ":disappointed_relieved:": "(`_'!)", + ":weary:": 'D-:', + ":pensive:": '-_-', + ":disappointed:": ':(', + ":confounded:": ':-$', + ":fearful:": ':-O', + ":cold_sweat:": "(O_O')", + ":persevere:": 'X-(', + ":cry:": ":'-(", + ":sob:": '(T_T)', + ":joy:": '(^o^)/', + ":astonished:": '8-O', + ":scream:": 'X-O', + ":tired_face:": 'D-X', + ":angry:": "(`##')", + ":rage:": "\(`###')>", + ":triumph:": '(-A-)', + ":sleepy:": '(-_-) zZ', + ":sunglasses:": 'B-)', + ":dizzy_face:": 'X-o', + ":imp:": ']:->', + ":smiling_imp:": ']:-)', + ":neutral_face:": ':-|', + ":no_mouth:": '(. .)', + ":innocent:": 'O :-)', + ":yellow_heart:": '<3', + ":blue_heart:": '<3', + ":purple_heart:": '<3', + ":heart:": '<3', + ":green_heart:": '<3', + ":broken_heart:": '', + ":metal:": '\\m/', + ":fu:": 't(-__-t)', + ":raising_hand:": 'o/', + ":kiss:": ':*', + ":eyes:": 'O_O', + ":tongue:": ':-P', + ":speech_balloon:": '.oO(......)', + ":thought_balloon:": '.oO( )'}, + 'unicode': {":bowtie:": 'โ‹ˆ ๐Ÿ˜', + ":smile:": '๐Ÿ˜', + ":simple_smile:": '๐Ÿ™‚', + ":slightly_smiling_face:": '๐Ÿ™‚', + ":laughing:": '๐Ÿ˜†', + ":blush:": '๐Ÿ˜Š', + ":smiley:": '๐Ÿ˜ƒ', + ":relaxed:": 'โ˜บ', + ":smirk:": '๐Ÿ˜', + ":heart_eyes:": '๐Ÿ˜', + ":kissing_heart:": '๐Ÿ˜˜', + ":kissing_closed_eyes:": '๐Ÿ˜š', + ":flushed:": '๐Ÿ˜ณ', + ":relieved:": '๐Ÿ˜Œ', + ":satisfied:": '๐Ÿ˜†', + ":grin:": '๐Ÿ˜€', + ":wink:": '๐Ÿ˜‰', + ":stuck_out_tongue_winking_eye:": '๐Ÿ˜œ', + ":stuck_out_tongue_closed_eyes:": '๐Ÿ˜', + ":grinning:": '๐Ÿ˜€', + ":kissing:": '๐Ÿ˜—', + ":kissing_smiling_eyes:": '๐Ÿ˜™', + ":stuck_out_tongue:": '๐Ÿ˜›', + ":sleeping:": '๐Ÿ˜ด', + ":worried:": '๐Ÿ˜Ÿ', + ":frowning:": '๐Ÿ˜ฆ', + ":anguished:": '๐Ÿ˜ง', + ":open_mouth:": '๐Ÿ˜ฎ', + ":grimacing:": '๐Ÿ˜ฌ', + ":confused:": '๐Ÿ˜•', + ":hushed:": '๐Ÿ˜ฏ', + ":expressionless:": '๐Ÿ˜‘', + ":unamused:": '๐Ÿ˜’', + ":sweat_smile:": '๐Ÿ˜…', + ":sweat:": '๐Ÿ˜“', + ":disappointed_relieved:": '๐Ÿ˜ฅ', + ":weary:": '๐Ÿ˜ฉ', + ":pensive:": '๐Ÿ˜”', + ":disappointed:": '๐Ÿ˜ž', + ":confounded:": '๐Ÿ˜–', + ":fearful:": '๐Ÿ˜จ', + ":cold_sweat:": '๐Ÿ˜“', + ":persevere:": '๐Ÿ˜ฃ', + ":cry:": '๐Ÿ˜ข', + ":sob:": '๐Ÿ˜ญ', + ":joy:": '๐Ÿ˜‚', + ":astonished:": '๐Ÿ˜ฒ', + ":scream:": '๐Ÿ˜ฑ', + ":tired_face:": '๐Ÿ˜ซ', + ":angry:": '๐Ÿ˜ ', + ":rage:": '๐Ÿ˜ก', + ":triumph:": '๐Ÿ˜ค', + ":sleepy:": '๐Ÿ˜ช', + ":yum:": '๐Ÿ˜‹', + ":mask:": '๐Ÿ˜ท', + ":sunglasses:": '๐Ÿ˜Ž', + ":dizzy_face:": '๐Ÿ˜ต', + ":imp:": '๐Ÿ‘ฟ', + ":smiling_imp:": '๐Ÿ˜ˆ', + ":neutral_face:": '๐Ÿ˜', + ":no_mouth:": '๐Ÿ˜ถ', + ":innocent:": '๐Ÿ˜‡', + ":alien:": '๐Ÿ‘ฝ', + ":yellow_heart:": '๐Ÿ’›', + ":blue_heart:": '๐Ÿ’™', + ":purple_heart:": '๐Ÿ’œ', + ":heart:": 'โค', + ":green_heart:": '๐Ÿ’š', + ":broken_heart:": '๐Ÿ’”', + ":heartbeat:": '๐Ÿ’“', + ":heartpulse:": '๐Ÿ’“', + ":two_hearts:": '๐Ÿ’•', + ":revolving_hearts:": '๐Ÿ’ž', + ":cupid:": '๐Ÿ’˜', + ":sparkling_heart:": '๐Ÿ’–', + ":sparkles:": 'โœจ', + ":star:": 'โญ', + ":star2:": '๐ŸŒŸ', + ":dizzy:": '๐Ÿ’ซ', + ":boom:": '๐Ÿ’ฅ', + ":collision:": '๐Ÿ’ฅ', + ":anger:": '๐Ÿ’ข', + ":exclamation:": 'โ—', + ":question:": 'โ“', + ":grey_exclamation:": 'โ•', + ":grey_question:": 'โ”', + ":zzz:": '๐Ÿ’ค', + ":dash:": '๐Ÿ’จ', + ":sweat_drops:": '๐Ÿ’ฆ', + ":notes:": '๐ŸŽถ', + ":musical_note:": '๐ŸŽต', + ":fire:": '๐Ÿ”ฅ', + ":hankey:": '๐Ÿ’ฉ', + ":poop:": '๐Ÿ’ฉ', + ":shit:": '๐Ÿ’ฉ', + ":+1:": '๐Ÿ‘', + ":thumbsup:": '๐Ÿ‘', + ":-1:": '๐Ÿ‘Ž', + ":thumbsdown:": '๐Ÿ‘Ž', + ":ok_hand:": '๐Ÿ‘Œ', + ":punch:": '๐Ÿ‘Š', + ":facepunch:": '๐Ÿ‘Š', + ":fist:": 'โœŠ', + ":v:": 'โœŒ', + ":wave:": '๐Ÿ‘‹', + ":hand:": 'โœ‹', + ":raised_hand:": 'โœ‹', + ":open_hands:": '๐Ÿ‘', + ":point_up:": '๐Ÿ‘†', + ":point_down:": '๐Ÿ‘‡', + ":point_left:": '๐Ÿ‘ˆ', + ":point_right:": '๐Ÿ‘‰', + ":raised_hands:": '๐Ÿ™Œ', + ":pray:": '๐Ÿ™', + ":point_up_2:": '๐Ÿ‘†', + ":clap:": '๐Ÿ‘', + ":muscle:": '๐Ÿ’ช', + ":metal:": '๐Ÿค˜', + ":fu:": '๐Ÿ–•', + ":runner:": '๐Ÿƒ', + ":running:": '๐Ÿƒ', + ":couple:": '๐Ÿ‘ซ', + ":family:": '๐Ÿ‘ช', + ":two_men_holding_hands:": '๐Ÿ‘ฌ', + ":two_women_holding_hands:": '๐Ÿ‘ญ', + ":dancer:": '๐Ÿ’ƒ', + ":dancers:": '๐Ÿ‘ฏ', + ":ok_woman:": '๐Ÿ™†', + ":no_good:": '๐Ÿ™…', + ":information_desk_person:": '๐Ÿ’', + ":raising_hand:": '๐Ÿ™‹', + ":bride_with_veil:": '๐Ÿ‘ฐ', + ":person_with_pouting_face:": '๐Ÿ™Ž', + ":person_frowning:": '๐Ÿ™', + ":bow:": '๐Ÿ™‡', + ":couplekiss:": '๐Ÿ’', + ":couple_with_heart:": '๐Ÿ’‘', + ":massage:": '๐Ÿ’†', + ":haircut:": '๐Ÿ’‡', + ":nail_care:": '๐Ÿ’…', + ":boy:": '๐Ÿ‘ฆ', + ":girl:": '๐Ÿ‘ง', + ":woman:": '๐Ÿ‘ฉ', + ":man:": '๐Ÿ‘จ', + ":baby:": '๐Ÿ‘ถ', + ":older_woman:": '๐Ÿ‘ต', + ":older_man:": '๐Ÿ‘ด', + ":person_with_blond_hair:": '๐Ÿ‘ฑ', + ":man_with_gua_pi_mao:": '๐Ÿ‘ฒ', + ":man_with_turban:": '๐Ÿ‘ณ', + ":construction_worker:": '๐Ÿ‘ท', + ":cop:": '๐Ÿ‘ฎ', + ":angel:": '๐Ÿ‘ผ', + ":princess:": '๐Ÿ‘ธ', + ":smiley_cat:": '๐Ÿ˜บ', + ":smile_cat:": '๐Ÿ˜บ', + ":heart_eyes_cat:": '๐Ÿ˜ป', + ":kissing_cat:": '๐Ÿ˜ฝ', + ":smirk_cat:": '๐Ÿ˜ผ', + ":scream_cat:": '๐Ÿ™€', + ":crying_cat_face:": '๐Ÿ˜ฟ', + ":joy_cat:": '๐Ÿ˜น', + ":pouting_cat:": '๐Ÿ˜พ', + ":japanese_ogre:": '๐Ÿ‘น', + ":japanese_goblin:": '๐Ÿ‘บ', + ":see_no_evil:": '๐Ÿ™ˆ', + ":hear_no_evil:": '๐Ÿ™‰', + ":speak_no_evil:": '๐Ÿ™Š', + ":guardsman:": '๐Ÿ’‚', + ":skull:": '๐Ÿ’€', + ":feet:": '๐Ÿ‘ฃ', + ":lips:": '๐Ÿ‘„', + ":kiss:": '๐Ÿ’‹', + ":droplet:": '๐Ÿ’ง', + ":ear:": '๐Ÿ‘‚', + ":eyes:": '๐Ÿ‘€', + ":nose:": '๐Ÿ‘ƒ', + ":tongue:": '๐Ÿ‘…', + ":love_letter:": '๐Ÿ’Œ', + ":bust_in_silhouette:": '๐Ÿ‘ค', + ":busts_in_silhouette:": '๐Ÿ‘ฅ', + ":speech_balloon:": '๐Ÿ’ฌ', + ":thought_balloon:": '๐Ÿ’ญ', + ":sunny:": 'โ˜€', + ":umbrella:": 'โ˜”', + ":cloud:": 'โ˜', + ":snowflake:": 'โ„', + ":snowman:": 'โ˜ƒ', + ":zap:": 'โšก', + ":cyclone:": '๐ŸŒ€', + ":foggy:": '๐ŸŒซ', + ":ocean:": '๐ŸŒŠ', + ":cat:": '๐Ÿฑ', + ":dog:": '๐Ÿถ', + ":mouse:": '๐Ÿญ', + ":hamster:": '๐Ÿน', + ":rabbit:": '๐Ÿฐ', + ":wolf:": '๐Ÿบ', + ":frog:": '๐Ÿธ', + ":tiger:": '๐Ÿฏ', + ":koala:": '๐Ÿจ', + ":bear:": '๐Ÿป', + ":pig:": '๐Ÿท', + ":pig_nose:": '๐Ÿฝ', + ":cow:": '๐Ÿฎ', + ":boar:": '๐Ÿ—', + ":monkey_face:": '๐Ÿต', + ":monkey:": '๐Ÿ’', + ":horse:": '๐Ÿด', + ":racehorse:": '๐ŸŽ', + ":camel:": '๐Ÿช', + ":sheep:": '๐Ÿ', + ":elephant:": '๐Ÿ˜', + ":panda_face:": '๐Ÿผ', + ":snake:": '๐Ÿ', + ":bird:": '๐Ÿฆ', + ":baby_chick:": '๐Ÿค', + ":hatched_chick:": '๐Ÿฃ', + ":hatching_chick:": '๐Ÿฃ', + ":chicken:": '๐Ÿ”', + ":penguin:": '๐Ÿง', + ":turtle:": '๐Ÿข', + ":bug:": '๐Ÿ›', + ":honeybee:": '๐Ÿ', + ":ant:": '๐Ÿœ', + ":beetle:": '๐Ÿž', + ":snail:": '๐ŸŒ', + ":octopus:": '๐Ÿ™', + ":tropical_fish:": '๐Ÿ ', + ":fish:": '๐ŸŸ', + ":whale:": '๐Ÿณ', + ":whale2:": '๐Ÿ‹', + ":dolphin:": '๐Ÿฌ', + ":cow2:": '๐Ÿ„', + ":ram:": '๐Ÿ', + ":rat:": '๐Ÿ€', + ":water_buffalo:": '๐Ÿƒ', + ":tiger2:": '๐Ÿ…', + ":rabbit2:": '๐Ÿ‡', + ":dragon:": '๐Ÿ‰', + ":goat:": '๐Ÿ', + ":rooster:": '๐Ÿ“', + ":dog2:": '๐Ÿ•', + ":pig2:": '๐Ÿ–', + ":mouse2:": '๐Ÿ', + ":ox:": '๐Ÿ‚', + ":dragon_face:": '๐Ÿฒ', + ":blowfish:": '๐Ÿก', + ":crocodile:": '๐ŸŠ', + ":dromedary_camel:": '๐Ÿช', + ":leopard:": '๐Ÿ†', + ":cat2:": '๐Ÿˆ', + ":poodle:": '๐Ÿฉ', + ":paw_prints:": '๐Ÿพ', + ":bouquet:": '๐Ÿ’', + ":cherry_blossom:": '๐ŸŒธ', + ":tulip:": '๐ŸŒท', + ":four_leaf_clover:": '๐Ÿ€', + ":rose:": '๐ŸŒน', + ":sunflower:": '๐ŸŒป', + ":hibiscus:": '๐ŸŒบ', + ":maple_leaf:": '๐Ÿ', + ":leaves:": '๐Ÿƒ', + ":fallen_leaf:": '๐Ÿ‚', + ":herb:": '๐ŸŒฟ', + ":mushroom:": '๐Ÿ„', + ":cactus:": '๐ŸŒต', + ":palm_tree:": '๐ŸŒด', + ":evergreen_tree:": '๐ŸŒฒ', + ":deciduous_tree:": '๐ŸŒณ', + ":chestnut:": '๐ŸŒฐ', + ":seedling:": '๐ŸŒฑ', + ":blossom:": '๐ŸŒผ', + ":ear_of_rice:": '๐ŸŒพ', + ":shell:": '๐Ÿš', + ":globe_with_meridians:": '๐ŸŒ', + ":sun_with_face:": '๐ŸŒž', + ":full_moon_with_face:": '๐ŸŒ', + ":new_moon_with_face:": '๐ŸŒš', + ":new_moon:": '๐ŸŒ‘', + ":waxing_crescent_moon:": '๐ŸŒ’', + ":first_quarter_moon:": '๐ŸŒ“', + ":waxing_gibbous_moon:": '๐ŸŒ”', + ":full_moon:": '๐ŸŒ•', + ":waning_gibbous_moon:": '๐ŸŒ–', + ":last_quarter_moon:": '๐ŸŒ—', + ":waning_crescent_moon:": '๐ŸŒ˜', + ":last_quarter_moon_with_face:": '๐ŸŒœ', + ":first_quarter_moon_with_face:": '๐ŸŒ›', + ":crescent_moon:": '๐ŸŒ™', + ":earth_africa:": '๐ŸŒ', + ":earth_americas:": '๐ŸŒŽ', + ":earth_asia:": '๐ŸŒ', + ":volcano:": '๐ŸŒ‹', + ":milky_way:": '๐ŸŒŒ', + ":partly_sunny:": 'โ›…', + ":bamboo:": '๐ŸŽ', + ":gift_heart:": '๐Ÿ’', + ":dolls:": '๐ŸŽŽ', + ":school_satchel:": '๐ŸŽ’', + ":mortar_board:": '๐ŸŽ“', + ":flags:": '๐ŸŽ', + ":fireworks:": '๐ŸŽ†', + ":sparkler:": '๐ŸŽ‡', + ":wind_chime:": '๐ŸŽ', + ":jack_o_lantern:": '๐ŸŽƒ', + ":ghost:": '๐Ÿ‘ป', + ":santa:": '๐ŸŽ…', + ":christmas_tree:": '๐ŸŽ„', + ":gift:": '๐ŸŽ', + ":bell:": '๐Ÿ””', + ":no_bell:": '๐Ÿ”•', + ":tanabata_tree:": '๐ŸŽ‹', + ":tada:": '๐ŸŽ‰', + ":confetti_ball:": '๐ŸŽŠ', + ":balloon:": '๐ŸŽˆ', + ":crystal_ball:": '๐Ÿ”ฎ', + ":cd:": '๐Ÿ’ฟ', + ":dvd:": '๐Ÿ“€', + ":floppy_disk:": '๐Ÿ’พ', + ":camera:": '๐Ÿ“ท', + ":video_camera:": '๐Ÿ“น', + ":movie_camera:": '๐ŸŽฅ', + ":computer:": '๐Ÿ’ป', + ":tv:": '๐Ÿ“บ', + ":iphone:": '๐Ÿ“ฑ', + ":phone:": 'โ˜Ž', + ":telephone:": 'โ˜Ž', + ":telephone_receiver:": '๐Ÿ“ž', + ":pager:": '๐Ÿ“Ÿ', + ":fax:": '๐Ÿ“ ', + ":minidisc:": '๐Ÿ’ฝ', + ":vhs:": '๐Ÿ“ผ', + ":sound:": '๐Ÿ”ˆ', + ":speaker:": '๐Ÿ”ˆ', + ":mute:": '๐Ÿ”‡', + ":loudspeaker:": '๐Ÿ“ข', + ":mega:": '๐Ÿ“ฃ', + ":hourglass:": 'โŒ›', + ":hourglass_flowing_sand:": 'โณ', + ":alarm_clock:": 'โฐ', + ":watch:": 'โŒš', + ":radio:": '๐Ÿ“ป', + ":satellite:": '๐Ÿ“ก', + ":loop:": 'โžฟ', + ":mag:": '๐Ÿ”', + ":mag_right:": '๐Ÿ”Ž', + ":unlock:": '๐Ÿ”“', + ":lock:": '๐Ÿ”’', + ":lock_with_ink_pen:": '๐Ÿ”', + ":closed_lock_with_key:": '๐Ÿ”', + ":key:": '๐Ÿ”‘', + ":bulb:": '๐Ÿ’ก', + ":flashlight:": '๐Ÿ”ฆ', + ":high_brightness:": '๐Ÿ”†', + ":low_brightness:": '๐Ÿ”…', + ":electric_plug:": '๐Ÿ”Œ', + ":battery:": '๐Ÿ”‹', + ":calling:": '๐Ÿ“ฒ', + ":email:": '๐Ÿ“ง', + ":mailbox:": '๐Ÿ“ซ', + ":postbox:": '๐Ÿ“ฎ', + ":bath:": '๐Ÿ›€', + ":bathtub:": '๐Ÿ›', + ":shower:": '๐Ÿšฟ', + ":toilet:": '๐Ÿšฝ', + ":wrench:": '๐Ÿ”ง', + ":nut_and_bolt:": '๐Ÿ”ฉ', + ":hammer:": '๐Ÿ”จ', + ":seat:": '๐Ÿ’บ', + ":moneybag:": '๐Ÿ’ฐ', + ":yen:": '๐Ÿ’ด', + ":dollar:": '๐Ÿ’ต', + ":pound:": '๐Ÿ’ท', + ":euro:": '๐Ÿ’ถ', + ":credit_card:": '๐Ÿ’ณ', + ":e-mail:": '๐Ÿ“ง', + ":inbox_tray:": '๐Ÿ“ฅ', + ":outbox_tray:": '๐Ÿ“ค', + ":envelope:": 'โœ‰', + ":incoming_envelope:": '๐Ÿ“จ', + ":postal_horn:": '๐Ÿ“ฏ', + ":mailbox_closed:": '๐Ÿ“ช', + ":mailbox_with_mail:": '๐Ÿ“ฌ', + ":mailbox_with_no_mail:": '๐Ÿ“ญ', + ":package:": '๐Ÿ“ฆ', + ":door:": '๐Ÿšช', + ":smoking:": '๐Ÿšฌ', + ":bomb:": '๐Ÿ’ฃ', + ":gun:": '๐Ÿ”ซ', + ":hocho:": '๐Ÿ”ช', + ":pill:": '๐Ÿ’Š', + ":syringe:": '๐Ÿ’‰', + ":page_facing_up:": '๐Ÿ“„', + ":page_with_curl:": '๐Ÿ“ƒ', + ":bookmark_tabs:": '๐Ÿ“‘', + ":bar_chart:": '๐Ÿ“Š', + ":chart_with_upwards_trend:": '๐Ÿ“ˆ', + ":chart_with_downwards_trend:": '๐Ÿ“‰', + ":scroll:": '๐Ÿ“œ', + ":clipboard:": '๐Ÿ“‹', + ":calendar:": '๐Ÿ“…', + ":date:": '๐Ÿ“…', + ":card_index:": '๐Ÿ—‚', + ":file_folder:": '๐Ÿ“', + ":open_file_folder:": '๐Ÿ“‚', + ":scissors:": 'โœ‚', + ":pushpin:": '๐Ÿ“Œ', + ":paperclip:": '๐Ÿ“Ž', + ":black_nib:": 'โœ’', + ":pencil2:": 'โœ', + ":straight_ruler:": '๐Ÿ“', + ":triangular_ruler:": '๐Ÿ“', + ":closed_book:": '๐Ÿ“•', + ":green_book:": '๐Ÿ“—', + ":blue_book:": '๐Ÿ“˜', + ":orange_book:": '๐Ÿ“™', + ":notebook:": '๐Ÿ““', + ":notebook_with_decorative_cover:": '๐Ÿ“”', + ":ledger:": '๐Ÿ“’', + ":books:": '๐Ÿ“š', + ":bookmark:": '๐Ÿ”–', + ":name_badge:": '๐Ÿ“›', + ":microscope:": '๐Ÿ”ฌ', + ":telescope:": '๐Ÿ”ญ', + ":newspaper:": '๐Ÿ“ฐ', + ":football:": '๐Ÿˆ', + ":basketball:": '๐Ÿ€', + ":soccer:": 'โšฝ', + ":baseball:": 'โšพ', + ":tennis:": '๐ŸŽพ', + ":8ball:": '๐ŸŽฑ', + ":rugby_football:": '๐Ÿ‰', + ":bowling:": '๐ŸŽณ', + ":golf:": 'โ›ณ', + ":mountain_bicyclist:": '๐Ÿšต', + ":bicyclist:": '๐Ÿšด', + ":horse_racing:": '๐Ÿ‡', + ":snowboarder:": '๐Ÿ‚', + ":swimmer:": '๐ŸŠ', + ":surfer:": '๐Ÿ„', + ":spades:": 'โ™ ', + ":hearts:": 'โ™ฅ', + ":clubs:": 'โ™ฃ', + ":diamonds:": 'โ™ฆ', + ":gem:": '๐Ÿ’Ž', + ":ring:": '๐Ÿ’', + ":trophy:": '๐Ÿ†', + ":musical_score:": '๐ŸŽผ', + ":musical_keyboard:": '๐ŸŽน', + ":violin:": '๐ŸŽป', + ":space_invader:": '๐Ÿ‘พ', + ":video_game:": '๐ŸŽฎ', + ":black_joker:": '๐Ÿƒ', + ":flower_playing_cards:": '๐ŸŽด', + ":game_die:": '๐ŸŽฒ', + ":dart:": '๐ŸŽฏ', + ":mahjong:": '๐Ÿ€„', + ":clapper:": '๐ŸŽฌ', + ":memo:": '๐Ÿ“', + ":pencil:": '๐Ÿ“', + ":book:": '๐Ÿ“–', + ":art:": '๐ŸŽจ', + ":microphone:": '๐ŸŽค', + ":headphones:": '๐ŸŽง', + ":trumpet:": '๐ŸŽบ', + ":saxophone:": '๐ŸŽท', + ":guitar:": '๐ŸŽธ', + ":shoe:": '๐Ÿ‘Ÿ', + ":sandal:": '๐Ÿ‘ก', + ":high_heel:": '๐Ÿ‘ ', + ":lipstick:": '๐Ÿ’„', + ":boot:": '๐Ÿ‘ข', + ":shirt:": '๐Ÿ‘•', + ":tshirt:": '๐Ÿ‘•', + ":necktie:": '๐Ÿ‘”', + ":womans_clothes:": '๐Ÿ‘š', + ":dress:": '๐Ÿ‘—', + ":running_shirt_with_sash:": '๐ŸŽฝ', + ":jeans:": '๐Ÿ‘–', + ":kimono:": '๐Ÿ‘˜', + ":bikini:": '๐Ÿ‘™', + ":ribbon:": '๐ŸŽ€', + ":tophat:": '๐ŸŽฉ', + ":crown:": '๐Ÿ‘‘', + ":womans_hat:": '๐Ÿ‘’', + ":mans_shoe:": '๐Ÿ‘ž', + ":closed_umbrella:": '๐ŸŒ‚', + ":briefcase:": '๐Ÿ’ผ', + ":handbag:": '๐Ÿ‘œ', + ":pouch:": '๐Ÿ‘', + ":purse:": '๐Ÿ‘›', + ":eyeglasses:": '๐Ÿ‘“', + ":fishing_pole_and_fish:": '๐ŸŽฃ', + ":coffee:": 'โ˜•', + ":tea:": '๐Ÿต', + ":sake:": '๐Ÿถ', + ":baby_bottle:": '๐Ÿผ', + ":beer:": '๐Ÿบ', + ":beers:": '๐Ÿป', + ":cocktail:": '๐Ÿธ', + ":wine_glass:": '๐Ÿท', + ":fork_and_knife:": '๐Ÿด', + ":pizza:": '๐Ÿ•', + ":hamburger:": '๐Ÿ”', + ":fries:": '๐ŸŸ', + ":poultry_leg:": '๐Ÿ—', + ":meat_on_bone:": '๐Ÿ–', + ":spaghetti:": '๐Ÿ', + ":curry:": '๐Ÿ›', + ":fried_shrimp:": '๐Ÿค', + ":bento:": '๐Ÿฑ', + ":sushi:": '๐Ÿฃ', + ":fish_cake:": '๐Ÿฅ', + ":rice_ball:": '๐Ÿ™', + ":rice_cracker:": '๐Ÿ˜', + ":rice:": '๐Ÿš', + ":ramen:": '๐Ÿœ', + ":stew:": '๐Ÿฒ', + ":oden:": '๐Ÿข', + ":dango:": '๐Ÿก', + ":egg:": '๐Ÿณ', + ":bread:": '๐Ÿž', + ":doughnut:": '๐Ÿฉ', + ":custard:": '๐Ÿฎ', + ":icecream:": '๐Ÿฆ', + ":ice_cream:": '๐Ÿจ', + ":shaved_ice:": '๐Ÿง', + ":birthday:": '๐ŸŽ‚', + ":cake:": '๐Ÿฐ', + ":cookie:": '๐Ÿช', + ":chocolate_bar:": '๐Ÿซ', + ":candy:": '๐Ÿฌ', + ":lollipop:": '๐Ÿญ', + ":honey_pot:": '๐Ÿฏ', + ":apple:": '๐ŸŽ', + ":green_apple:": '๐Ÿ', + ":tangerine:": '๐ŸŠ', + ":lemon:": '๐Ÿ‹', + ":cherries:": '๐Ÿ’', + ":grapes:": '๐Ÿ‡', + ":watermelon:": '๐Ÿ‰', + ":strawberry:": '๐Ÿ“', + ":peach:": '๐Ÿ‘', + ":melon:": '๐Ÿˆ', + ":banana:": '๐ŸŒ', + ":pear:": '๐Ÿ', + ":pineapple:": '๐Ÿ', + ":sweet_potato:": '๐Ÿ ', + ":eggplant:": '๐Ÿ†', + ":tomato:": '๐Ÿ…', + ":corn:": '๐ŸŒฝ', + ":house:": '๐Ÿ ', + ":house_with_garden:": '๐Ÿก', + ":school:": '๐Ÿซ', + ":office:": '๐Ÿข', + ":post_office:": '๐Ÿฃ', + ":hospital:": '๐Ÿฅ', + ":bank:": '๐Ÿฆ', + ":convenience_store:": '๐Ÿช', + ":love_hotel:": '๐Ÿฉ', + ":hotel:": '๐Ÿจ', + ":wedding:": '๐Ÿ’’', + ":church:": 'โ›ช', + ":department_store:": '๐Ÿฌ', + ":european_post_office:": '๐Ÿค', + ":japanese_castle:": "๐Ÿฏ", + ":european_castle:": "๐Ÿฐ", + ":tent:": "โ›บ", + ":factory:": "๐Ÿญ", + ":tokyo_tower:": "๐Ÿ—ผ", + ":japan:": "๐Ÿ—พ", + ":mount_fuji:": '๐Ÿ—ป', + ":sunrise_over_mountains:": '๐ŸŒ„', + ":sunrise:": '๐ŸŒ„', + ":statue_of_liberty:": '๐Ÿ—ฝ', + ":bridge_at_night:": '๐ŸŒ‰', + ":carousel_horse:": '๐ŸŽ ', + ":rainbow:": '๐ŸŒˆ', + ":ferris_wheel:": '๐ŸŽก', + ":fountain:": 'โ›ฒ', + ":roller_coaster:": '๐ŸŽข', + ":ship:": '๐Ÿ›ณ', + ":speedboat:": '๐Ÿšค', + ":boat:": 'โ›ต', + ":sailboat:": 'โ›ต', + ":rowboat:": '๐Ÿšฃ', + ":anchor:": 'โš“', + ":rocket:": '๐Ÿš€', + ":airplane:": 'โœˆ', + ":helicopter:": '๐Ÿš', + ":steam_locomotive:": '๐Ÿš‚', + ":tram:": '๐ŸšŠ', + ":mountain_railway:": '๐Ÿšž', + ":bike:": '๐Ÿšฒ', + ":aerial_tramway:": '๐Ÿšก', + ":suspension_railway:": '๐ŸšŸ', + ":mountain_cableway:": '๐Ÿš ', + ":tractor:": '๐Ÿšœ', + ":blue_car:": '๐Ÿš—', + ":oncoming_automobile:": '๐Ÿš˜', + ":car:": '๐Ÿš—', + ":red_car:": '๐Ÿš—', + ":taxi:": '๐Ÿš•', + ":oncoming_taxi:": '๐Ÿš–', + ":articulated_lorry:": '๐Ÿšš', + ":bus:": '๐ŸšŒ', + ":oncoming_bus:": '๐Ÿš', + ":rotating_light:": '๐Ÿšจ', + ":police_car:": '๐Ÿš“', + ":oncoming_police_car:": '๐Ÿš”', + ":fire_engine:": '๐Ÿš’', + ":ambulance:": '๐Ÿš‘', + ":minibus:": '๐Ÿš', + ":truck:": '๐Ÿšš', + ":train:": '๐Ÿš†', + ":station:": '๐Ÿš‰', + ":train2:": '๐Ÿš…', + ":bullettrain_front:": '๐Ÿš…', + ":bullettrain_side:": '๐Ÿš…', + ":light_rail:": '๐Ÿšˆ', + ":monorail:": '๐Ÿš', + ":railway_car:": '๐Ÿšƒ', + ":trolleybus:": '๐Ÿšƒ', + ":ticket:": '๐ŸŽซ', + ":fuelpump:": 'โ›ฝ', + ":vertical_traffic_light:": '๐Ÿšฆ', + ":traffic_light:": '๐Ÿšฅ', + ":warning:": 'โš ', + ":construction:": '๐Ÿšง', + ":beginner:": '๐Ÿ”ฐ', + ":atm:": '๐Ÿง', + ":slot_machine:": '๐ŸŽฐ', + ":busstop:": '๐Ÿš', + ":barber:": '๐Ÿ’ˆ', + ":hotsprings:": 'โ™จ', + ":checkered_flag:": '๐Ÿ', + ":crossed_flags:": '๐ŸŽŒ', + ":izakaya_lantern:": '๐Ÿฎ', + ":moyai:": '๐Ÿ—ฟ', + ":circus_tent:": '๐ŸŽช', + ":performing_arts:": '๐ŸŽญ', + ":round_pushpin:": '๐Ÿ“', + ":triangular_flag_on_post:": '๐Ÿšฉ', + ":one:": '1๏ธโƒฃ', + ":two:": '2๏ธโƒฃ', + ":three:": '3๏ธโƒฃ', + ":four:": '4๏ธโƒฃ', + ":five:": '5๏ธโƒฃ', + ":six:": '6๏ธโƒฃ', + ":seven:": '7๏ธโƒฃ', + ":eight:": '8๏ธโƒฃ', + ":nine:": '9๏ธโƒฃ', + ":keycap_ten:": '๐Ÿ”Ÿ', + ":1234:": '๐Ÿ”ข', + ":zero:": '0๏ธโƒฃ', + ":hash:": '#๏ธโƒฃ', + ":symbols:": '๐Ÿ”ฃ', + ":arrow_backward:": "โ—€", + ":arrow_down:": "โฌ‡", + ":arrow_forward:": "โ–ถ", + ":arrow_left:": "โฌ…", + ":capital_abcd:": "๐Ÿ” ", + ":abcd:": "๐Ÿ”ก", + ":abc:": "๐Ÿ”ค", + ":arrow_lower_left:": 'โ†™', + ":arrow_lower_right:": 'โ†˜', + ":arrow_right:": 'โžก', + ":arrow_up:": 'โฌ†', + ":arrow_upper_left:": 'โ†–', + ":arrow_upper_right:": 'โ†—', + ":arrow_double_down:": 'โฌ', + ":arrow_double_up:": 'โซ', + ":arrow_down_small:": '๐Ÿ”ฝ', + ":arrow_heading_down:": 'โคต', + ":arrow_heading_up:": 'โคด', + ":leftwards_arrow_with_hook:": 'โ†ฉ', + ":arrow_right_hook:": 'โ†ช', + ":left_right_arrow:": 'โ†”', + ":arrow_up_down:": 'โ†•', + ":arrow_up_small:": '๐Ÿ”ผ', + ":arrows_clockwise:": '๐Ÿ”ƒ', + ":arrows_counterclockwise:": '๐Ÿ”„', + ":rewind:": 'โช', + ":fast_forward:": 'โฉ', + ":information_source:": 'โ„น', + ":ok:": '๐Ÿ†—', + ":twisted_rightwards_arrows:": '๐Ÿ”€', + ":repeat:": '๐Ÿ”', + ":repeat_one:": '๐Ÿ”‚', + ":new:": '๐Ÿ†•', + ":top:": '๐Ÿ”', + ":up:": '๐Ÿ†™', + ":cool:": '๐Ÿ†’', + ":free:": '๐Ÿ†“', + ":ng:": '๐Ÿ†–', + ":cinema:": '๐ŸŽฆ', + ":koko:": '๐Ÿˆ', # here + ":signal_strength:": '๐Ÿ“ถ', + ":u5272:": '๐Ÿˆน', # discount + ":u5408:": '๐Ÿˆด', # passing grade + ":u55b6:": '๐Ÿˆบ', # open for business + ":u6307:": '๐Ÿˆฏ', # reserved + ":u6708:": '๐Ÿˆท', # monthly amount + ":u6709:": '๐Ÿˆถ', # not free of charge + ":u6e80:": '๐Ÿˆต', # no vacancy + ":u7121:": '๐Ÿˆš', # free of charge + ":u7533:": '๐Ÿˆธ', # application + ":u7a7a:": '๐Ÿˆณ', # vacancy + ":u7981:": '๐Ÿˆฒ', # prohibited + ":sa:": '๐Ÿˆ‚', # service charge + ":restroom:": '๐Ÿšป', + ":mens:": '๐Ÿšน', + ":womens:": '๐Ÿšบ', + ":baby_symbol:": '๐Ÿšผ', + ":no_smoking:": '๐Ÿšญ', + ":parking:": '๐Ÿ…ฟ', + ":wheelchair:": 'โ™ฟ', + ":metro:": '๐Ÿš‡', + ":baggage_claim:": '๐Ÿ›„', + ":accept:": '๐Ÿ‰‘', # acceptable + ":wc:": '๐Ÿšพ', + ":potable_water:": '๐Ÿšฐ', + ":put_litter_in_its_place:": '๐Ÿšฎ', + ":secret:": 'ใŠ™', # secret + ":congratulations:": 'ใŠ—', # congratulations + ":m:": 'โ“‚', + ":passport_control:": '๐Ÿ›‚', + ":left_luggage:": '๐Ÿ›…', + ":customs:": '๐Ÿ›ƒ', + ":ideograph_advantage:": '๐Ÿ‰', # bargain + ":cl:": '๐Ÿ†‘', + ":sos:": '๐Ÿ†˜', + ":id:": '๐Ÿ†”', + ":no_entry_sign:": '๐Ÿšซ', + ":underage:": '๐Ÿ”ž', + ":no_mobile_phones:": '๐Ÿ“ต', + ":do_not_litter:": '๐Ÿšฏ', + ":non-potable_water:": '๐Ÿšฑ', + ":no_bicycles:": '๐Ÿšณ', + ":no_pedestrians:": '๐Ÿšท', + ":children_crossing:": '๐Ÿšธ', + ":no_entry:": 'โ›”', + ":eight_spoked_asterisk:": 'โœณ', + ":sparkle:": 'โ‡', + ":eight_pointed_black_star:": 'โœด', + ":heart_decoration:": '๐Ÿ’Ÿ', + ":vs:": '๐Ÿ†š', + ":vibration_mode:": '๐Ÿ“ณ', + ":mobile_phone_off:": '๐Ÿ“ด', + ":currency_exchange:": '๐Ÿ’ฑ', + ":aries:": 'โ™ˆ', + ":taurus:": 'โ™‰', + ":gemini:": 'โ™Š', + ":cancer:": 'โ™‹', + ":leo:": 'โ™Œ', + ":virgo:": 'โ™', + ":libra:": 'โ™Ž', + ":scorpius:": 'โ™', + ":sagittarius:": 'โ™', + ":capricorn:": 'โ™‘', + ":aquarius:": 'โ™’', + ":pisces:": 'โ™“', + ":ophiuchus:": 'โ›Ž', + ":six_pointed_star:": '๐Ÿ”ฏ', + ":negative_squared_cross_mark:": 'โŽ', + ":a:": '๐Ÿ…ฐ', + ":b:": '๐Ÿ…ฑ', + ":ab:": '๐Ÿ†Ž', + ":o2:": '๐Ÿ…พ', + ":diamond_shape_with_a_dot_inside:": '๐Ÿ’ ', + ":recycle:": 'โ™ป', + ":end:": '๐Ÿ”š', + ":back:": '๐Ÿ”™', + ":on:": '๐Ÿ”›', + ":soon:": '๐Ÿ”œ', + ":clock12:": "๐Ÿ•›", + ":clock1230:": "๐Ÿ•ง", + ":clock1:": '๐Ÿ•', + ":clock130:": '๐Ÿ•œ', + ":clock2:": '๐Ÿ•‘', + ":clock230:": '๐Ÿ•', + ":clock3:": '๐Ÿ•’', + ":clock330:": '๐Ÿ•ž', + ":clock4:": '๐Ÿ•“', + ":clock430:": '๐Ÿ•Ÿ', + ":clock5:": '๐Ÿ•”', + ":clock530:": '๐Ÿ• ', + ":clock6:": '๐Ÿ••', + ":clock630:": '๐Ÿ•ก', + ":clock7:": '๐Ÿ•–', + ":clock730:": '๐Ÿ•ข', + ":clock8:": '๐Ÿ•—', + ":clock830:": '๐Ÿ•ฃ', + ":clock9:": '๐Ÿ•˜', + ":clock930:": '๐Ÿ•ค', + ":clock10:": '๐Ÿ•™', + ":clock1030:": '๐Ÿ•ฅ', + ":clock11:": '๐Ÿ•š', + ":clock1130:": '๐Ÿ•ฆ', + ":heavy_dollar_sign:": '๐Ÿ’ฒ', + ":copyright:": 'ยฉ', + ":registered:": 'ยฎ', + ":tm:": 'โ„ข', + ":x:": 'โŒ', + ":heavy_exclamation_mark:": 'โ—', + ":bangbang:": 'โ€ผ', + ":interrobang:": 'โ‰', + ":o:": 'โญ•', + ":heavy_multiplication_x:": 'โœ–', + ":heavy_plus_sign:": 'โž•', + ":heavy_minus_sign:": 'โž–', + ":heavy_division_sign:": 'โž—', + ":white_flower:": '๐Ÿ’ฎ', + ":100:": '๐Ÿ’ฏ', + ":heavy_check_mark:": 'โœ”', + ":ballot_box_with_check:": 'โ˜‘', + ":radio_button:": '๐Ÿ”˜', + ":link:": '๐Ÿ”—', + ":curly_loop:": 'โžฐ', + ":wavy_dash:": 'ใ€ฐ', + ":part_alternation_mark:": 'ใ€ฝ', + ":trident:": '๐Ÿ”ฑ', + ":black_small_square:": 'โ–ช', + ":white_small_square:": 'โ–ซ', + ":black_medium_small_square:": 'โ—พ', + ":white_medium_small_square:": 'โ—ฝ', + ":black_medium_square:": 'โ—ผ', + ":white_medium_square:": 'โ—ป', + ":black_large_square:": 'โฌ›', + ":white_large_square:": 'โฌœ', + ":white_check_mark:": "โœ…", + ":black_square_button:": '๐Ÿ”ฒ', + ":white_square_button:": '๐Ÿ”ณ', + ":black_circle:": 'โšซ', + ":white_circle:": 'โšช', + ":red_circle:": '๐Ÿ”ด', + ":large_blue_circle:": '๐Ÿ”ต', + ":large_blue_diamond:": '๐Ÿ”ท', + ":large_orange_diamond:": '๐Ÿ”ถ', + ":small_blue_diamond:": '๐Ÿ”น', + ":small_orange_diamond:": '๐Ÿ”ธ', + ":small_red_triangle:": '๐Ÿ”บ', + ":small_red_triangle_down:": '๐Ÿ”ป'}} + +# template +# +# {":bowtie:": +# ":smile:": +# ":simple_smile:": +# ":laughing:": +# ":blush:": +# ":smiley:": +# ":relaxed:": +# ":smirk:": +# ":heart_eyes:": +# ":kissing_heart:": +# ":kissing_closed_eyes:": +# ":flushed:": +# ":relieved:": +# ":satisfied:": +# ":grin:": +# ":wink:": +# ":stuck_out_tongue_winking_eye:": +# ":stuck_out_tongue_closed_eyes:": +# ":grinning:": +# ":kissing:": +# ":kissing_smiling_eyes:": +# ":stuck_out_tongue:": +# ":sleeping:": +# ":worried:": +# ":frowning:": +# ":anguished:": +# ":open_mouth:": +# ":grimacing:": +# ":confused:": +# ":hushed:": +# ":expressionless:": +# ":unamused:": +# ":sweat_smile:": +# ":sweat:": +# ":disappointed_relieved:": +# ":weary:": +# ":pensive:": +# ":disappointed:": +# ":confounded:": +# ":fearful:": +# ":cold_sweat:": +# ":persevere:": +# ":cry:": +# ":sob:": +# ":joy:": +# ":astonished:": +# ":scream:": +# ":neckbeard:": +# ":tired_face:": +# ":angry:": +# ":rage:": +# ":triumph:": +# ":sleepy:": +# ":yum:": +# ":mask:": +# ":sunglasses:": +# ":dizzy_face:": +# ":imp:": +# ":smiling_imp:": +# ":neutral_face:": +# ":no_mouth:": +# ":innocent:": +# ":alien:": +# ":yellow_heart:": +# ":blue_heart:": +# ":purple_heart:": +# ":heart:": +# ":green_heart:": +# ":broken_heart:": +# ":heartbeat:": +# ":heartpulse:": +# ":two_hearts:": +# ":revolving_hearts:": +# ":cupid:": +# ":sparkling_heart:": +# ":sparkles:": +# ":star:": +# ":star2:": +# ":dizzy:": +# ":boom:": +# ":collision:": +# ":anger:": +# ":exclamation:": +# ":question:": +# ":grey_exclamation:": +# ":grey_question:": +# ":zzz:": +# ":dash:": +# ":sweat_drops:": +# ":notes:": +# ":musical_note:": +# ":fire:": +# ":hankey:": +# ":poop:": +# ":shit:": +# ":+1:": +# ":thumbsup:": +# ":-1:": +# ":thumbsdown:": +# ":ok_hand:": +# ":punch:": +# ":facepunch:": +# ":fist:": +# ":v:": +# ":wave:": +# ":hand:": +# ":raised_hand:": +# ":open_hands:": +# ":point_up:": +# ":point_down:": +# ":point_left:": +# ":point_right:": +# ":raised_hands:": +# ":pray:": +# ":point_up_2:": +# ":clap:": +# ":muscle:": +# ":metal:": +# ":fu:": +# ":runner:": +# ":running:": +# ":couple:": +# ":family:": +# ":two_men_holding_hands:": +# ":two_women_holding_hands:": +# ":dancer:": +# ":dancers:": +# ":ok_woman:": +# ":no_good:": +# ":information_desk_person:": +# ":raising_hand:": +# ":bride_with_veil:": +# ":person_with_pouting_face:": +# ":person_frowning:": +# ":bow:": +# ":couplekiss:": +# ":couple_with_heart:": +# ":massage:": +# ":haircut:": +# ":nail_care:": +# ":boy:": +# ":girl:": +# ":woman:": +# ":man:": +# ":baby:": +# ":older_woman:": +# ":older_man:": +# ":person_with_blond_hair:": +# ":man_with_gua_pi_mao:": +# ":man_with_turban:": +# ":construction_worker:": +# ":cop:": +# ":angel:": +# ":princess:": +# ":smiley_cat:": +# ":smile_cat:": +# ":heart_eyes_cat:": +# ":kissing_cat:": +# ":smirk_cat:": +# ":scream_cat:": +# ":crying_cat_face:": +# ":joy_cat:": +# ":pouting_cat:": +# ":japanese_ogre:": +# ":japanese_goblin:": +# ":see_no_evil:": +# ":hear_no_evil:": +# ":speak_no_evil:": +# ":guardsman:": +# ":skull:": +# ":feet:": +# ":lips:": +# ":kiss:": +# ":droplet:": +# ":ear:": +# ":eyes:": +# ":nose:": +# ":tongue:": +# ":love_letter:": +# ":bust_in_silhouette:": +# ":busts_in_silhouette:": +# ":speech_balloon:": +# ":thought_balloon:": +# ":feelsgood:": +# ":finnadie:": +# ":goberserk:": +# ":godmode:": +# ":hurtrealbad:": +# ":rage1:": +# ":rage2:": +# ":rage3:": +# ":rage4:": +# ":suspect:": +# ":trollface:": +# ":sunny:": +# ":umbrella:": +# ":cloud:": +# ":snowflake:": +# ":snowman:": +# ":zap:": +# ":cyclone:": +# ":foggy:": +# ":ocean:": +# ":cat:": +# ":dog:": +# ":mouse:": +# ":hamster:": +# ":rabbit:": +# ":wolf:": +# ":frog:": +# ":tiger:": +# ":koala:": +# ":bear:": +# ":pig:": +# ":pig_nose:": +# ":cow:": +# ":boar:": +# ":monkey_face:": +# ":monkey:": +# ":horse:": +# ":racehorse:": +# ":camel:": +# ":sheep:": +# ":elephant:": +# ":panda_face:": +# ":snake:": +# ":bird:": +# ":baby_chick:": +# ":hatched_chick:": +# ":hatching_chick:": +# ":chicken:": +# ":penguin:": +# ":turtle:": +# ":bug:": +# ":honeybee:": +# ":ant:": +# ":beetle:": +# ":snail:": +# ":octopus:": +# ":tropical_fish:": +# ":fish:": +# ":whale:": +# ":whale2:": +# ":dolphin:": +# ":cow2:": +# ":ram:": +# ":rat:": +# ":water_buffalo:": +# ":tiger2:": +# ":rabbit2:": +# ":dragon:": +# ":goat:": +# ":rooster:": +# ":dog2:": +# ":pig2:": +# ":mouse2:": +# ":ox:": +# ":dragon_face:": +# ":blowfish:": +# ":crocodile:": +# ":dromedary_camel:": +# ":leopard:": +# ":cat2:": +# ":poodle:": +# ":paw_prints:": +# ":bouquet:": +# ":cherry_blossom:": +# ":tulip:": +# ":four_leaf_clover:": +# ":rose:": +# ":sunflower:": +# ":hibiscus:": +# ":maple_leaf:": +# ":leaves:": +# ":fallen_leaf:": +# ":herb:": +# ":mushroom:": +# ":cactus:": +# ":palm_tree:": +# ":evergreen_tree:": +# ":deciduous_tree:": +# ":chestnut:": +# ":seedling:": +# ":blossom:": +# ":ear_of_rice:": +# ":shell:": +# ":globe_with_meridians:": +# ":sun_with_face:": +# ":full_moon_with_face:": +# ":new_moon_with_face:": +# ":new_moon:": +# ":waxing_crescent_moon:": +# ":first_quarter_moon:": +# ":waxing_gibbous_moon:": +# ":full_moon:": +# ":waning_gibbous_moon:": +# ":last_quarter_moon:": +# ":waning_crescent_moon:": +# ":last_quarter_moon_with_face:": +# ":first_quarter_moon_with_face:": +# ":crescent_moon:": +# ":earth_africa:": +# ":earth_americas:": +# ":earth_asia:": +# ":volcano:": +# ":milky_way:": +# ":partly_sunny:": +# ":octocat:": +# ":squirrel:": +# ":bamboo:": +# ":gift_heart:": +# ":dolls:": +# ":school_satchel:": +# ":mortar_board:": +# ":flags:": +# ":fireworks:": +# ":sparkler:": +# ":wind_chime:": +# ":rice_scene:": +# ":jack_o_lantern:": +# ":ghost:": +# ":santa:": +# ":christmas_tree:": +# ":gift:": +# ":bell:": +# ":no_bell:": +# ":tanabata_tree:": +# ":tada:": +# ":confetti_ball:": +# ":balloon:": +# ":crystal_ball:": +# ":cd:": +# ":dvd:": +# ":floppy_disk:": +# ":camera:": +# ":video_camera:": +# ":movie_camera:": +# ":computer:": +# ":tv:": +# ":iphone:": +# ":phone:": +# ":telephone:": +# ":telephone_receiver:": +# ":pager:": +# ":fax:": +# ":minidisc:": +# ":vhs:": +# ":sound:": +# ":speaker:": +# ":mute:": +# ":loudspeaker:": +# ":mega:": +# ":hourglass:": +# ":hourglass_flowing_sand:": +# ":alarm_clock:": +# ":watch:": +# ":radio:": +# ":satellite:": +# ":loop:": +# ":mag:": +# ":mag_right:": +# ":unlock:": +# ":lock:": +# ":lock_with_ink_pen:": +# ":closed_lock_with_key:": +# ":key:": +# ":bulb:": +# ":flashlight:": +# ":high_brightness:": +# ":low_brightness:": +# ":electric_plug:": +# ":battery:": +# ":calling:": +# ":email:": +# ":mailbox:": +# ":postbox:": +# ":bath:": +# ":bathtub:": +# ":shower:": +# ":toilet:": +# ":wrench:": +# ":nut_and_bolt:": +# ":hammer:": +# ":seat:": +# ":moneybag:": +# ":yen:": +# ":dollar:": +# ":pound:": +# ":euro:": +# ":credit_card:": +# ":money_with_wings:": +# ":e-mail:": +# ":inbox_tray:": +# ":outbox_tray:": +# ":envelope:": +# ":incoming_envelope:": +# ":postal_horn:": +# ":mailbox_closed:": +# ":mailbox_with_mail:": +# ":mailbox_with_no_mail:": +# ":package:": +# ":door:": +# ":smoking:": +# ":bomb:": +# ":gun:": +# ":hocho:": +# ":pill:": +# ":syringe:": +# ":page_facing_up:": +# ":page_with_curl:": +# ":bookmark_tabs:": +# ":bar_chart:": +# ":chart_with_upwards_trend:": +# ":chart_with_downwards_trend:": +# ":scroll:": +# ":clipboard:": +# ":calendar:": +# ":date:": +# ":card_index:": +# ":file_folder:": +# ":open_file_folder:": +# ":scissors:": +# ":pushpin:": +# ":paperclip:": +# ":black_nib:": +# ":pencil2:": +# ":straight_ruler:": +# ":triangular_ruler:": +# ":closed_book:": +# ":green_book:": +# ":blue_book:": +# ":orange_book:": +# ":notebook:": +# ":notebook_with_decorative_cover:": +# ":ledger:": +# ":books:": +# ":bookmark:": +# ":name_badge:": +# ":microscope:": +# ":telescope:": +# ":newspaper:": +# ":football:": +# ":basketball:": +# ":soccer:": +# ":baseball:": +# ":tennis:": +# ":8ball:": +# ":rugby_football:": +# ":bowling:": +# ":golf:": +# ":mountain_bicyclist:": +# ":bicyclist:": +# ":horse_racing:": +# ":snowboarder:": +# ":swimmer:": +# ":surfer:": +# ":ski:": +# ":spades:": +# ":hearts:": +# ":clubs:": +# ":diamonds:": +# ":gem:": +# ":ring:": +# ":trophy:": +# ":musical_score:": +# ":musical_keyboard:": +# ":violin:": +# ":space_invader:": +# ":video_game:": +# ":black_joker:": +# ":flower_playing_cards:": +# ":game_die:": +# ":dart:": +# ":mahjong:": +# ":clapper:": +# ":memo:": +# ":pencil:": +# ":book:": +# ":art:": +# ":microphone:": +# ":headphones:": +# ":trumpet:": +# ":saxophone:": +# ":guitar:": +# ":shoe:": +# ":sandal:": +# ":high_heel:": +# ":lipstick:": +# ":boot:": +# ":shirt:": +# ":tshirt:": +# ":necktie:": +# ":womans_clothes:": +# ":dress:": +# ":running_shirt_with_sash:": +# ":jeans:": +# ":kimono:": +# ":bikini:": +# ":ribbon:": +# ":tophat:": +# ":crown:": +# ":womans_hat:": +# ":mans_shoe:": +# ":closed_umbrella:": +# ":briefcase:": +# ":handbag:": +# ":pouch:": +# ":purse:": +# ":eyeglasses:": +# ":fishing_pole_and_fish:": +# ":coffee:": +# ":tea:": +# ":sake:": +# ":baby_bottle:": +# ":beer:": +# ":beers:": +# ":cocktail:": +# ":tropical_drink:": +# ":wine_glass:": +# ":fork_and_knife:": +# ":pizza:": +# ":hamburger:": +# ":fries:": +# ":poultry_leg:": +# ":meat_on_bone:": +# ":spaghetti:": +# ":curry:": +# ":fried_shrimp:": +# ":bento:": +# ":sushi:": +# ":fish_cake:": +# ":rice_ball:": +# ":rice_cracker:": +# ":rice:": +# ":ramen:": +# ":stew:": +# ":oden:": +# ":dango:": +# ":egg:": +# ":bread:": +# ":doughnut:": +# ":custard:": +# ":icecream:": +# ":ice_cream:": +# ":shaved_ice:": +# ":birthday:": +# ":cake:": +# ":cookie:": +# ":chocolate_bar:": +# ":candy:": +# ":lollipop:": +# ":honey_pot:": +# ":apple:": +# ":green_apple:": +# ":tangerine:": +# ":lemon:": +# ":cherries:": +# ":grapes:": +# ":watermelon:": +# ":strawberry:": +# ":peach:": +# ":melon:": +# ":banana:": +# ":pear:": +# ":pineapple:": +# ":sweet_potato:": +# ":eggplant:": +# ":tomato:": +# ":corn:": +# ":house:": +# ":house_with_garden:": +# ":school:": +# ":office:": +# ":post_office:": +# ":hospital:": +# ":bank:": +# ":convenience_store:": +# ":love_hotel:": +# ":hotel:": +# ":wedding:": +# ":church:": +# ":department_store:": +# ":european_post_office:": +# ":city_sunrise:": +# ":city_sunset:": +# ":japanese_castle:": +# ":european_castle:": +# ":tent:": +# ":factory:": +# ":tokyo_tower:": +# ":japan:": +# ":mount_fuji:": +# ":sunrise_over_mountains:": +# ":sunrise:": +# ":stars:": +# ":statue_of_liberty:": +# ":bridge_at_night:": +# ":carousel_horse:": +# ":rainbow:": +# ":ferris_wheel:": +# ":fountain:": +# ":roller_coaster:": +# ":ship:": +# ":speedboat:": +# ":boat:": +# ":sailboat:": +# ":rowboat:": +# ":anchor:": +# ":rocket:": +# ":airplane:": +# ":helicopter:": +# ":steam_locomotive:": +# ":tram:": +# ":mountain_railway:": +# ":bike:": +# ":aerial_tramway:": +# ":suspension_railway:": +# ":mountain_cableway:": +# ":tractor:": +# ":blue_car:": +# ":oncoming_automobile:": +# ":car:": +# ":red_car:": +# ":taxi:": +# ":oncoming_taxi:": +# ":articulated_lorry:": +# ":bus:": +# ":oncoming_bus:": +# ":rotating_light:": +# ":police_car:": +# ":oncoming_police_car:": +# ":fire_engine:": +# ":ambulance:": +# ":minibus:": +# ":truck:": +# ":train:": +# ":station:": +# ":train2:": +# ":bullettrain_front:": +# ":bullettrain_side:": +# ":light_rail:": +# ":monorail:": +# ":railway_car:": +# ":trolleybus:": +# ":ticket:": +# ":fuelpump:": +# ":vertical_traffic_light:": +# ":traffic_light:": +# ":warning:": +# ":construction:": +# ":beginner:": +# ":atm:": +# ":slot_machine:": +# ":busstop:": +# ":barber:": +# ":hotsprings:": +# ":checkered_flag:": +# ":crossed_flags:": +# ":izakaya_lantern:": +# ":moyai:": +# ":circus_tent:": +# ":performing_arts:": +# ":round_pushpin:": +# ":triangular_flag_on_post:": +# ":jp:": +# ":kr:": +# ":cn:": +# ":us:": +# ":fr:": +# ":es:": +# ":it:": +# ":ru:": +# ":gb:": +# ":uk:": +# ":de:": +# ":one:": +# ":two:": +# ":three:": +# ":four:": +# ":five:": +# ":six:": +# ":seven:": +# ":eight:": +# ":nine:": +# ":keycap_ten:": +# ":1234:": +# ":zero:": +# ":hash:": +# ":symbols:": +# ":arrow_backward:": +# ":arrow_down:": +# ":arrow_forward:": +# ":arrow_left:": +# ":capital_abcd:": +# ":abcd:": +# ":abc:": +# ":arrow_lower_left:": +# ":arrow_lower_right:": +# ":arrow_right:": +# ":arrow_up:": +# ":arrow_upper_left:": +# ":arrow_upper_right:": +# ":arrow_double_down:": +# ":arrow_double_up:": +# ":arrow_down_small:": +# ":arrow_heading_down:": +# ":arrow_heading_up:": +# ":leftwards_arrow_with_hook:": +# ":arrow_right_hook:": +# ":left_right_arrow:": +# ":arrow_up_down:": +# ":arrow_up_small:": +# ":arrows_clockwise:": +# ":arrows_counterclockwise:": +# ":rewind:": +# ":fast_forward:": +# ":information_source:": +# ":ok:": +# ":twisted_rightwards_arrows:": +# ":repeat:": +# ":repeat_one:": +# ":new:": +# ":top:": +# ":up:": +# ":cool:": +# ":free:": +# ":ng:": +# ":cinema:": +# ":koko:": +# ":signal_strength:": +# ":u5272:": +# ":u5408:": +# ":u55b6:": +# ":u6307:": +# ":u6708:": +# ":u6709:": +# ":u6e80:": +# ":u7121:": +# ":u7533:": +# ":u7a7a:": +# ":u7981:": +# ":sa:": +# ":restroom:": +# ":mens:": +# ":womens:": +# ":baby_symbol:": +# ":no_smoking:": +# ":parking:": +# ":wheelchair:": +# ":metro:": +# ":baggage_claim:": +# ":accept:": +# ":wc:": +# ":potable_water:": +# ":put_litter_in_its_place:": +# ":secret:": +# ":congratulations:": +# ":m:": +# ":passport_control:": +# ":left_luggage:": +# ":customs:": +# ":ideograph_advantage:": +# ":cl:": +# ":sos:": +# ":id:": +# ":no_entry_sign:": +# ":underage:": +# ":no_mobile_phones:": +# ":do_not_litter:": +# ":non-potable_water:": +# ":no_bicycles:": +# ":no_pedestrians:": +# ":children_crossing:": +# ":no_entry:": +# ":eight_spoked_asterisk:": +# ":sparkle:": +# ":eight_pointed_black_star:": +# ":heart_decoration:": +# ":vs:": +# ":vibration_mode:": +# ":mobile_phone_off:": +# ":chart:": +# ":currency_exchange:": +# ":aries:": +# ":taurus:": +# ":gemini:": +# ":cancer:": +# ":leo:": +# ":virgo:": +# ":libra:": +# ":scorpius:": +# ":sagittarius:": +# ":capricorn:": +# ":aquarius:": +# ":pisces:": +# ":ophiuchus:": +# ":six_pointed_star:": +# ":negative_squared_cross_mark:": +# ":a:": +# ":b:": +# ":ab:": +# ":o2:": +# ":diamond_shape_with_a_dot_inside:": +# ":recycle:": +# ":end:": +# ":back:": +# ":on:": +# ":soon:": +# ":clock1:": +# ":clock130:": +# ":clock10:": +# ":clock1030:": +# ":clock11:": +# ":clock1130:": +# ":clock12:": +# ":clock1230:": +# ":clock2:": +# ":clock230:": +# ":clock3:": +# ":clock330:": +# ":clock4:": +# ":clock430:": +# ":clock5:": +# ":clock530:": +# ":clock6:": +# ":clock630:": +# ":clock7:": +# ":clock730:": +# ":clock8:": +# ":clock830:": +# ":clock9:": +# ":clock930:": +# ":heavy_dollar_sign:": +# ":copyright:": +# ":registered:": +# ":tm:": +# ":x:": +# ":heavy_exclamation_mark:": +# ":bangbang:": +# ":interrobang:": +# ":o:": +# ":heavy_multiplication_x:": +# ":heavy_plus_sign:": +# ":heavy_minus_sign:": +# ":heavy_division_sign:": +# ":white_flower:": +# ":100:": +# ":heavy_check_mark:": +# ":ballot_box_with_check:": +# ":radio_button:": +# ":link:": +# ":curly_loop:": +# ":wavy_dash:": +# ":part_alternation_mark:": +# ":trident:": +# ":black_small_square:": +# ":white_small_square:": +# ":black_medium_small_square:": +# ":white_medium_small_square:": +# ":black_medium_square:": +# ":white_medium_square:": +# ":black_large_square:": +# ":white_large_square:": +# ":white_check_mark:": +# ":black_square_button:": +# ":white_square_button:": +# ":black_circle:": +# ":white_circle:": +# ":red_circle:": +# ":large_blue_circle:": +# ":large_blue_diamond:": +# ":large_orange_diamond:": +# ":small_blue_diamond:": +# ":small_orange_diamond:": +# ":small_red_triangle:": +# ":small_red_triangle_down:": +# ":shipit:":} diff --git a/slack_backup/reporters.py b/slack_backup/reporters.py index 5591a4d..adb4b22 100644 --- a/slack_backup/reporters.py +++ b/slack_backup/reporters.py @@ -10,9 +10,14 @@ import os import errno import logging import re +try: + from html.parser import HTMLParser +except ImportError: + from HTMLParser import HTMLParser from slack_backup import objects as o from slack_backup import utils +from slack_backup import emoji class Reporter(object): @@ -40,16 +45,18 @@ class Reporter(object): 'file': '๐Ÿ“‚', 'topic': '๐ŸŸ…', 'separator': 'โ”‚'}} + self.emoji = emoji.EMOJI.get(args.theme, {}) self.channels = self._get_channels(args.channels) self.users = self.q(o.User).all() - self._re_first_idnick = re.compile(r'^(?P' - r'<@(?PU[A-Z,0-9]+)\|.+>)') - self._re_first_id = re.compile('^(?P' - '<@(?PU[A-Z,0-9]+)>)') - self._re_idnick = re.compile(r'.*(?P' - r'<@(?PU[A-Z,0-9]+)\|.+>)') - self._re_id = re.compile('.*(?P<@(?PU[A-Z,0-9]+)>)') + self._slackid_pat = [re.compile(r'^(?P' + r'<@(?PU[A-Z,0-9]+)\|.+>)'), + re.compile('^(?P' + '<@(?PU[A-Z,0-9]+)>)'), + re.compile(r'.*(?P' + r'<@(?PU[A-Z,0-9]+)\|.+>)'), + re.compile('.*(?P<@(?P' + 'U[A-Z,0-9]+)>)')] def generate(self): """Generate raport it's a dummmy one - for use with none reporter""" @@ -154,11 +161,9 @@ class TextReporter(Reporter): """ msg_txt = self._filter_slackid(msg.text) msg_txt = self._fix_newlines(msg_txt) + for emoticon in self.emoji: + msg_txt = msg_txt.replace(emoticon, self.emoji[emoticon]) formatter = self.types.get(msg.type, self._msg) - if not msg_txt.strip(): - logging.info("Skipping message from `%s' since it's empty", - msg.user.name) - return '' return formatter(msg, msg_txt) @@ -202,8 +207,9 @@ class TextReporter(Reporter): def _msg_file(self, msg, text): """return formatter for file""" - groups = self._re_first_idnick.match(msg.text).groupdict() + groups = self._slackid_pat[0].match(msg.text).groupdict() text = msg.text.replace(groups['replace'], '') + text = self._filter_slackid(msg.text) filename = msg.file.filepath if filename: filename = os.path.relpath(msg.file.filepath, start=self.out) @@ -211,14 +217,18 @@ class TextReporter(Reporter): filename = msg.file.url if not filename: - logging.warning("Dude, we have a file object, but nothing has " - "found. Name of the file object is `i%s'", + logging.warning("There is have a file object, but nothing has " + "found. Name of the file object is `%s'", msg.file.name) filename = msg.file.name text = self._filter_slackid(text) + text = self._remove_entities(text) text = self._fix_newlines(text) + for emoticon in self.emoji: + text = text.replace(emoticon, self.emoji[emoticon]) + data = {'date': msg.datetime().strftime("%Y-%m-%d %H:%M:%S"), 'msg': text, 'max_len': self._max_len, @@ -230,24 +240,40 @@ class TextReporter(Reporter): 'shared file "{filename}"{msg}\n'.format(**data)) def _msg(self, msg, text): - """return formatter for /me""" + """return formatter for all other message types""" + data = {'date': msg.datetime().strftime("%Y-%m-%d %H:%M:%S"), 'msg': text, 'max_len': self._max_len, 'separator': self._get_symbol('separator'), 'nick': msg.user.name} - return '{date} {nick:>{max_len}} {separator} {msg}\n'.format(**data) + result = '{date} {nick:>{max_len}} {separator} {msg}\n'.format(**data) + + if msg.attachments: + for att in msg.attachments: + if att.title: + att_text = "\n" + att.title + '\n' + else: + att_text = "\n" + self._fix_newlines(att.fallback) + '\n' + + if att.text: + att_text += att.text + + att_text = self._fix_newlines(att_text) + # remove first newline + att_text = att_text[1:] + + result += att_text + '\n' + + return result + + def _remove_entities(self, text): + """replace html entites into appropriate chars""" + text = HTMLParser().unescape(text) def _filter_slackid(self, text): """filter out all of the id from slack""" - for pat in (self._re_first_idnick, self._re_first_id): - while pat.search(text): - groups = pat.search(text).groupdict('slackid') - user = [u for u in self.users - if u.slackid == groups['slackid']][0] - text = text.replace(groups['replace'], user.name + ":") - - for pat in (self._re_idnick, self._re_id): + for pat in self._slackid_pat: while pat.search(text): groups = pat.search(text).groupdict('slackid') user = [u for u in self.users