diff --git a/telebot/types.py b/telebot/types.py
index 9f5a507..b793073 100644
--- a/telebot/types.py
+++ b/telebot/types.py
@@ -1313,6 +1313,7 @@ class Message(JsonDeserializable):
"strikethrough": "{text}",
"underline": "{text}",
"spoiler": "{text}",
+ "custom_emoji": "{text}"
}
if hasattr(self, "custom_subs"):
@@ -1321,7 +1322,7 @@ class Message(JsonDeserializable):
utf16_text = text.encode("utf-16-le")
html_text = ""
- def func(upd_text, subst_type=None, url=None, user=None):
+ def func(upd_text, subst_type=None, url=None, user=None, custom_emoji_id=None):
upd_text = upd_text.decode("utf-16-le")
if subst_type == "text_mention":
subst_type = "text_link"
@@ -1332,30 +1333,41 @@ class Message(JsonDeserializable):
if not subst_type or not _subs.get(subst_type):
return upd_text
subs = _subs.get(subst_type)
+ if subst_type == "custom_emoji":
+ return subs.format(text=upd_text, custom_emoji_id=custom_emoji_id)
return subs.format(text=upd_text, url=url)
offset = 0
+ start_index = 0
+ end_index = 0
for entity in entities:
if entity.offset > offset:
+ # when the offset is not 0: for example, a __b__
+ # we need to add the text before the entity to the html_text
html_text += func(utf16_text[offset * 2 : entity.offset * 2])
offset = entity.offset
- html_text += func(utf16_text[offset * 2 : (offset + entity.length) * 2], entity.type, entity.url, entity.user)
+
+ new_string = func(utf16_text[offset * 2 : (offset + entity.length) * 2], entity.type, entity.url, entity.user, entity.custom_emoji_id)
+ start_index = len(html_text)
+ html_text += new_string
offset += entity.length
+ end_index = len(html_text)
elif entity.offset == offset:
- html_text += func(utf16_text[offset * 2 : (offset + entity.length) * 2], entity.type, entity.url, entity.user)
+ new_string = func(utf16_text[offset * 2 : (offset + entity.length) * 2], entity.type, entity.url, entity.user, entity.custom_emoji_id)
+ start_index = len(html_text)
+ html_text += new_string
+ end_index = len(html_text)
offset += entity.length
else:
# Here we are processing nested entities.
# We shouldn't update offset, because they are the same as entity before.
# And, here we are replacing previous string with a new html-rendered text(previous string is already html-rendered,
# And we don't change it).
- entity_string = utf16_text[entity.offset * 2 : (entity.offset + entity.length) * 2]
- formatted_string = func(entity_string, entity.type, entity.url, entity.user)
- entity_string_decoded = entity_string.decode("utf-16-le")
- last_occurence = html_text.rfind(entity_string_decoded)
- string_length = len(entity_string_decoded)
- #html_text = html_text.replace(html_text[last_occurence:last_occurence+string_length], formatted_string)
- html_text = html_text[:last_occurence] + formatted_string + html_text[last_occurence+string_length:]
+ entity_string = html_text[start_index : end_index].encode("utf-16-le")
+ formatted_string = func(entity_string, entity.type, entity.url, entity.user, entity.custom_emoji_id).replace("&", "&").replace("<", "<").replace(">",">")
+ html_text = html_text[:start_index] + formatted_string + html_text[end_index:]
+ end_index = len(html_text)
+
if offset * 2 < len(utf16_text):
html_text += func(utf16_text[offset * 2:])
diff --git a/tests/test_types.py b/tests/test_types.py
index 8c15396..138c36b 100644
--- a/tests/test_types.py
+++ b/tests/test_types.py
@@ -275,10 +275,10 @@ def test_message_entity():
# TODO: Add support for nesting entities
- #sample_string_1 = r'{"update_id":934522126,"message":{"message_id":1374510,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682177590,"text":"b b b","entities":[{"offset":0,"length":2,"type":"bold"},{"offset":0,"length":1,"type":"italic"},{"offset":2,"length":2,"type":"bold"},{"offset":2,"length":1,"type":"italic"},{"offset":4,"length":1,"type":"bold"},{"offset":4,"length":1,"type":"italic"}]}}'
- #update = types.Update.de_json(sample_string_1)
- #message: types.Message = update.message
- #assert message.html_text == "b b b"
+ sample_string_1 = r'{"update_id":934522126,"message":{"message_id":1374510,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682177590,"text":"b b b","entities":[{"offset":0,"length":2,"type":"bold"},{"offset":0,"length":1,"type":"italic"},{"offset":2,"length":2,"type":"bold"},{"offset":2,"length":1,"type":"italic"},{"offset":4,"length":1,"type":"bold"},{"offset":4,"length":1,"type":"italic"}]}}'
+ update = types.Update.de_json(sample_string_1)
+ message: types.Message = update.message
+ assert message.html_text == "b b b"
sample_string_2 = r'{"update_id":934522166,"message":{"message_id":1374526,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682179716,"text":"b b b","entities":[{"offset":0,"length":1,"type":"bold"},{"offset":2,"length":1,"type":"bold"},{"offset":4,"length":1,"type":"italic"}]}}'
message_2 = types.Update.de_json(sample_string_2).message
@@ -286,12 +286,15 @@ def test_message_entity():
- #sample_string_3 = r'{"update_id":934522172,"message":{"message_id":1374530,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682179968,"text":"This is a bold text with a nested italic and bold text.","entities":[{"offset":10,"length":4,"type":"bold"},{"offset":27,"length":7,"type":"italic"},{"offset":34,"length":15,"type":"bold"},{"offset":34,"length":15,"type":"italic"}]}}'
- #message_3 = types.Update.de_json(sample_string_3).message
- #assert message_3.html_text == "This is a bold text with a nested italic and bold text."
+ sample_string_3 = r'{"update_id":934522172,"message":{"message_id":1374530,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682179968,"text":"This is a bold text with a nested italic and bold text.","entities":[{"offset":10,"length":4,"type":"bold"},{"offset":27,"length":7,"type":"italic"},{"offset":34,"length":15,"type":"bold"},{"offset":34,"length":15,"type":"italic"}]}}'
+ message_3 = types.Update.de_json(sample_string_3).message
+ assert message_3.html_text == "This is a bold text with a nested italic and bold text."
- assert True
+ sample_string_4 = r'{"update_id":934522437,"message":{"message_id":1374619,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682189507,"forward_from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"forward_date":1682189124,"text":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa😋😋","entities":[{"offset":0,"length":76,"type":"bold"},{"offset":0,"length":76,"type":"italic"},{"offset":0,"length":76,"type":"underline"},{"offset":0,"length":76,"type":"strikethrough"},{"offset":76,"length":2,"type":"custom_emoji","custom_emoji_id":"5456188142006575553"},{"offset":78,"length":2,"type":"custom_emoji","custom_emoji_id":"5456188142006575553"}]}}'
+ message_4 = types.Update.de_json(sample_string_4).message
+ assert message_4.html_text == 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa😋😋'
+