123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- # -*- coding: utf-8; -*-
- from __future__ import unicode_literals
- import re
- import six
- if six.PY3:
- from html import escape, unescape
- else:
- from cgi import escape
- from HTMLParser import HTMLParser
- import struct
- unescape = HTMLParser.unescape
- chr = unichr
- from .ruleset import unicode_replace,\
- shortcode_replace, ascii_replace
- class Emoji(object):
- ascii = False
- unicode_alt = True
- image_type = 'png'
- cache_bust_param = '?v=1.2.5'
- sprites = False
- image_png_path = 'https://cdn.jsdelivr.net/emojione/assets/png/'
- image_svg_path = 'https://cdn.jsdelivr.net/emojione/assets/svg/'
- image_path_svg_sprites = './../../assets/sprites/emojione.sprites.svg'
- ignored_regexp = '<object[^>]*>.*?<\/object>|<span[^>]*>.*?<\/span>|<(?:object|embed|svg|img|div|span|p|a)[^>]*>'
- unicode_regexp = "(" + '|'.join([re.escape(x.decode("utf-8")) for x in unicode_replace]) + ")"
- shortcode_regexp = ':([-+\\w]+):'
- ascii_regexp = '(\\<3|<3|\\<\\/3|<\\/3|\\:\'\\)|\\:\'\\-\\)|\\:D|\\:\\-D|\\=D|\\:\\)|\\:\\-\\)|\\=\\]|\\=\\)|\\:\\]|\'\\:\\)|\'\\:\\-\\)|\'\\=\\)|\'\\:D|\'\\:\\-D|\'\\=D|\\>\\:\\)|>\\:\\)|\\>;\\)|>;\\)|\\>\\:\\-\\)|>\\:\\-\\)|\\>\\=\\)|>\\=\\)|;\\)|;\\-\\)|\\*\\-\\)|\\*\\)|;\\-\\]|;\\]|;D|;\\^\\)|\'\\:\\(|\'\\:\\-\\(|\'\\=\\(|\\:\\*|\\:\\-\\*|\\=\\*|\\:\\^\\*|\\>\\:P|>\\:P|X\\-P|x\\-p|\\>\\:\\[|>\\:\\[|\\:\\-\\(|\\:\\(|\\:\\-\\[|\\:\\[|\\=\\(|\\>\\:\\(|>\\:\\(|\\>\\:\\-\\(|>\\:\\-\\(|\\:@|\\:\'\\(|\\:\'\\-\\(|;\\(|;\\-\\(|\\>\\.\\<|>\\.<|\\:\\$|\\=\\$|#\\-\\)|#\\)|%\\-\\)|%\\)|X\\)|X\\-\\)|\\*\\\\0\\/\\*|\\\\0\\/|\\*\\\\O\\/\\*|\\\\O\\/|O\\:\\-\\)|0\\:\\-3|0\\:3|0\\:\\-\\)|0\\:\\)|0;\\^\\)|O\\:\\-\\)|O\\:\\)|O;\\-\\)|O\\=\\)|0;\\-\\)|O\\:\\-3|O\\:3|B\\-\\)|B\\)|8\\)|8\\-\\)|B\\-D|8\\-D|\\-_\\-|\\-__\\-|\\-___\\-|\\>\\:\\\\|>\\:\\\\|\\>\\:\\/|>\\:\\/|\\:\\-\\/|\\:\\-\\.|\\:\\/|\\:\\\\|\\=\\/|\\=\\\\|\\:L|\\=L|\\:P|\\:\\-P|\\=P|\\:\\-p|\\:p|\\=p|\\:\\-Þ|\\:\\-Þ|\\:Þ|\\:Þ|\\:þ|\\:þ|\\:\\-þ|\\:\\-þ|\\:\\-b|\\:b|d\\:|\\:\\-O|\\:O|\\:\\-o|\\:o|O_O|\\>\\:O|>\\:O|\\:\\-X|\\:X|\\:\\-#|\\:#|\\=X|\\=x|\\:x|\\:\\-x|\\=#)'
- shortcode_compiled = re.compile(ignored_regexp+"|("+shortcode_regexp+")",
- re.IGNORECASE)
- unicode_compiled = re.compile(ignored_regexp+"|("+unicode_regexp+")",
- re.UNICODE)
- ascii_compiled = re.compile(ignored_regexp+"|("+ascii_regexp+")",
- re.IGNORECASE)
- @classmethod
- def to_image(cls, text):
- text = cls.unicode_to_image(text)
- text = cls.shortcode_to_image(text)
- return text
- @classmethod
- def unicode_to_image(cls, text):
- def replace_unicode(match):
- unicode_char = text[match.start():match.end()]
- unicode_encoded = unicode_char.encode('utf-8')
- if not unicode_encoded or unicode_encoded not in unicode_replace:
- return unicode_char # unsupported unicode char
- shortcode = unicode_replace[unicode_encoded]
- if cls.unicode_alt:
- alt = unicode_char
- else:
- alt = shortcode
- filename = shortcode_replace[shortcode]
- if cls.image_type == 'png':
- if cls.sprites:
- return '<span class="emojione emojione-%s" title="%s">%s</span>'\
- % (filename, escape(shortcode), alt)
- else:
- return '<img class="emojione" alt="%s" src="%s"/>' % (
- alt,
- cls.image_png_path+filename+'.png'+cls.cache_bust_param
- )
- else:
- if cls.sprites:
- return '<svg class="emojione"><description>%s</description>\
- <use xlink:href="%s#emoji-%s"</use></svg>' % (
- alt, cls.image_path_svg_sprites, filename)
- else:
- return '<object class="emojione" data="%s" \
- type="image/svg+xml" standby="%s"> %s</object>' % (
- cls.image_svg_path+filename+'.svg'+cls.cache_bust_param, alt, alt)
- text = re.sub(cls.unicode_compiled, replace_unicode, text)
- return text
- @classmethod
- def shortcode_to_image(cls, text):
- def replace_shortcode(match):
- shortcode = text[match.start():match.end()]
- if not shortcode or shortcode not in shortcode_replace:
- return shortcode
- unicode = shortcode_replace[shortcode]
- if cls.unicode_alt:
- alt = cls.convert(unicode)
- else:
- alt = shortcode
- filename = shortcode_replace[shortcode]
- if cls.image_type == 'png':
- if cls.sprites:
- return '<span class="emojione emojione-%s" title="%s">%s</span>'\
- % (filename, escape(shortcode), alt)
- else:
- return '<img class="emojione" alt="%s" src="%s"/>' % (
- alt,
- cls.image_png_path+filename+'.png'+cls.cache_bust_param
- )
- else:
- if cls.sprites:
- return '<svg class="emojione"><description>%s</description>\
- <use xlink:href="%s#emoji-%s"</use></svg>' % (
- alt, cls.image_path_svg_sprites, filename)
- else:
- return '<object class="emojione" data="%s" \
- type="image/svg+xml" standby="%s"> %s</object>' % (
- cls.image_svg_path+filename+'.svg'+cls.cache_bust_param, alt, alt)
- text = re.sub(cls.shortcode_compiled, replace_shortcode, text)
- if cls.ascii:
- return cls.ascii_to_image(text)
- return text
- @classmethod
- def shortcode_to_ascii(cls, text):
- def replace_shortcode(match):
- shortcode = text[match.start():match.end()]
- if not shortcode or shortcode not in shortcode_replace:
- return shortcode
- unicode = shortcode_replace[shortcode]
- reverse_ascii_unicode = {v: k for k, v in ascii_replace.items()}
- if unicode in reverse_ascii_unicode:
- return reverse_ascii_unicode[unicode]
- return shortcode
- return re.sub(cls.shortcode_compiled, replace_shortcode, text)
- @classmethod
- def shortcode_to_unicode(cls, text):
- def replace_shortcode(match):
- shortcode = text[match.start():match.end()]
- if not shortcode or shortcode not in shortcode_replace:
- return shortcode
- flipped_unicode_replace = {v: k for k, v in unicode_replace.items()}
- if shortcode in flipped_unicode_replace:
- return flipped_unicode_replace[shortcode].decode('utf8')
- return shortcode
- text = re.sub(cls.shortcode_compiled, replace_shortcode, text)
- if cls.ascii:
- return cls.ascii_to_unicode(text)
- return text
- @classmethod
- def ascii_to_unicode(cls, text):
- def replace_ascii(match):
- ascii = text[match.start():match.end()]
- ascii = unescape(ascii) # convert escaped HTML entities back to original chars
- if not ascii or ascii not in ascii_replace:
- return ascii
- return cls.convert(ascii_replace[ascii])
- return re.sub(cls.ascii_compiled, replace_ascii, text)
- @classmethod
- def ascii_to_image(cls, text):
- def replace_ascii(match):
- ascii = text[match.start():match.end()]
- ascii = unescape(ascii) # convert escaped HTML entities back to original chars
- if not ascii or ascii not in ascii_replace:
- return ascii
- unicode = ascii_replace[ascii]
- if cls.unicode_alt:
- alt = cls.convert(unicode)
- else:
- alt = escape(ascii)
- if cls.image_type == 'png':
- if cls.sprites:
- return '<span class="emojione emojione-%s" title="%s">%s</span>'\
- % (unicode, escape(ascii), alt)
- else:
- return '<img class="emojione" alt="%s" src="%s"/>' % (
- alt,
- cls.image_png_path+unicode+'.png'+cls.cache_bust_param
- )
- else:
- if cls.sprites:
- return '<svg class="emojione"><description>%s</description>\
- <use xlink:href="%s#emoji-%s"</use></svg>' % (
- alt, cls.image_path_svg_sprites, unicode)
- else:
- return '<object class="emojione" data="%s" \
- type="image/svg+xml" standby="%s"> %s</object>' % (
- cls.image_svg_path+unicode+'.svg'+cls.cache_bust_param,
- alt, alt)
- return re.sub(cls.ascii_compiled, replace_ascii, text)
- @classmethod
- def convert(cls, hex_unicode):
- def char(i):
- try:
- return chr(i)
- except ValueError:
- return struct.pack('i', i).decode('utf-32')
- """
- Convert a unicode in hex string to actual unicode char
- """
- if '-' not in hex_unicode:
- return char(int(hex_unicode, 16))
- parts = hex_unicode.split('-')
- return ''.join(char(int(x, 16)) for x in parts)
|