Skip to content

Commit 32fb32c

Browse files
committed
fix(chatform): Do not interpret 祝 and 秘 as smileys.
1 parent aeef7e2 commit 32fb32c

4 files changed

Lines changed: 206 additions & 20 deletions

File tree

.restyled.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,14 @@ restylers:
1010
enabled: false
1111
- clazy:
1212
enabled: false
13+
# Disable conflicting python linters.
14+
# Conflicts with "isort"
15+
- reorder-python-imports:
16+
enabled: false
17+
# Conflicts with "black"
18+
- yapf:
19+
enabled: false
20+
# Fix compatibilitry with "black" for "autopep8"
21+
- autopep8:
22+
arguments: ["--max-line-length", "88"]
1323
- "*"

smileys/EmojiOne/emoticons.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,11 +2358,9 @@
23582358
</emoticon>
23592359
<emoticon file="3297">
23602360
<string>㊗</string>
2361-
<string>祝</string>
23622361
</emoticon>
23632362
<emoticon file="3299">
23642363
<string>㊙</string>
2365-
<string>秘</string>
23662364
</emoticon>
23672365
<emoticon file="00a9">
23682366
<string>©</string>

smileys/blocked_smileys.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"EmojiOne": {
3+
"3297": [""],
4+
"3299": [""]
5+
}
6+
}

smileys/update_smileys.py

Lines changed: 190 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
#!/usr/bin/env python3
2+
import argparse
3+
import json
24
import os
3-
import sys
45
from xml.dom import minidom # nosec
56

67

78
def load_smileys(path: str) -> dict[str, list[str]]:
8-
"""Load smileys from emoticons.xml file.
9+
"""Loads smileys from emoticons.xml file.
910
1011
Args:
1112
path: Path to the emoticons.xml file.
1213
13-
Returns:
14-
A dictionary where the keys are the filenames (without suffix) of the
14+
Returns
15+
-------
16+
smileys: A dictionary where the keys are the filenames (without suffix) of the
1517
smileys and the values are the strings that will be replaced by the
1618
file when sent in a message.
19+
1720
"""
1821
smileys: dict[str, list[str]] = {}
1922
dom = minidom.parse(path) # nosec
@@ -33,12 +36,12 @@ def save_smileys(path: str, smileys: dict[str, list[str]]) -> None:
3336
Args:
3437
path: Path to the emoticons.xml file.
3538
smileys: The same format as the return value of load_smileys.
39+
3640
"""
3741
doc = minidom.Document()
3842
root = doc.createElement("messaging-emoticon-map")
3943
root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
40-
root.setAttribute("xsi:noNamespaceSchemaLocation",
41-
"../messaging-emoticon-map.xsd")
44+
root.setAttribute("xsi:noNamespaceSchemaLocation", "../messaging-emoticon-map.xsd")
4245
doc.appendChild(root)
4346
for file, strings in smileys.items():
4447
emoticon = doc.createElement("emoticon")
@@ -69,11 +72,13 @@ def emoji_to_string(emoji: tuple[int, ...]) -> str:
6972

7073
def add_missing_smileys(path: str, smileys: dict[str, list[str]]) -> None:
7174
"""Add smileys that exist in the path but not in the smileys dict."""
72-
for emoji_str in sorted(filter_svgs(os.listdir(path)),
73-
key=parse_emoji_sequence):
75+
for emoji_str in sorted(filter_svgs(os.listdir(path)), key=parse_emoji_sequence):
7476
emoji = emoji_to_string(parse_emoji_sequence(emoji_str))
75-
if (emoji_str not in smileys or len(smileys[emoji_str]) == 1
76-
and smileys[emoji_str][0] == emoji):
77+
if (
78+
emoji_str not in smileys
79+
or len(smileys[emoji_str]) == 1
80+
and smileys[emoji_str][0] == emoji
81+
):
7782
smileys[emoji_str] = [emoji]
7883
if emoji not in smileys[emoji_str]:
7984
smileys[emoji_str].append(emoji)
@@ -95,7 +100,8 @@ def prefer_emoji(emoji: str, string: str) -> str:
95100

96101

97102
def sort_strings(smileys: dict[str, list[str]]) -> None:
98-
"""Sort the strings in the smileys dict.
103+
"""
104+
Sort the strings in the smileys dict.
99105
100106
We put the emoji string first.
101107
"""
@@ -104,15 +110,181 @@ def sort_strings(smileys: dict[str, list[str]]) -> None:
104110
strings.sort(key=lambda s: prefer_emoji(emoji, s))
105111

106112

113+
def block_smiley_maybe(
114+
smileys: dict[str, list[str]],
115+
blocked_smileys_in_pack: dict[str, list[str]],
116+
block: str | None,
117+
) -> bool:
118+
"""Block smiley defined in block and return True if blocked smiley list was modified.
119+
120+
Args
121+
----
122+
smileys: The loaded set of smileys.
123+
blocked_smileys_in_pack: the list of currently blocked smileys.
124+
block: The smiley to be blocked.
125+
126+
Returns
127+
-------
128+
True if blocked_smileys_in_pack was modified, False otherwise.
129+
130+
"""
131+
is_dirty = False
132+
if not block:
133+
return is_dirty
134+
block_name = None
135+
for name, strings in smileys.items():
136+
smiley_set = set(strings)
137+
if block in smiley_set:
138+
block_name = name
139+
block_list = blocked_smileys_in_pack.get(block_name, [])
140+
if block not in block_list:
141+
# Add blocked smiley.
142+
block_list.append(block)
143+
blocked_smileys_in_pack[block_name] = block_list
144+
is_dirty = True
145+
else:
146+
print(f'The smiley "{block}" is already blocked.')
147+
break
148+
if not block_name:
149+
is_blocked = False
150+
for name, strings in blocked_smileys_in_pack.items():
151+
if block in strings:
152+
print(f'The smiley "{block}" is already blocked.')
153+
break
154+
if is_blocked:
155+
print(f'The smiley to block "{block}" was not found.')
156+
return is_dirty
157+
158+
159+
def unblock_smiley_maybe(
160+
smileys: dict[str, list[str]],
161+
blocked_smileys_in_pack: dict[str, list[str]],
162+
unblock: str | None,
163+
) -> bool:
164+
"""Unblocks smiley defined in unblock and return True if blocked smiley list was modified.
165+
166+
Args:
167+
smileys: The loaded set of smileys.
168+
blocked_smileys_in_pack: the list of currently blocked smileys.
169+
unblock: The smiley to be unblocked.
170+
171+
Returns
172+
-------
173+
True if blocked_smileys_in_pack was modified, False otherwise.
174+
175+
"""
176+
is_dirty = False
177+
unblock_name = None
178+
if not unblock:
179+
return is_dirty
180+
for name, strings in blocked_smileys_in_pack.items():
181+
smiley_set = set(strings)
182+
if unblock in smiley_set:
183+
# Unblock smiley.
184+
unblock_name = name
185+
blocked_smileys_in_pack[unblock_name].remove(unblock)
186+
smiley_list = smileys.get(unblock_name, [])
187+
smiley_list.append(unblock)
188+
smileys[unblock_name] = list(set(smiley_list))
189+
is_dirty = True
190+
break
191+
if not unblock_name:
192+
print(f'The smiley to unblock "{unblock}" was not found in the blocklist.')
193+
return is_dirty
194+
195+
196+
def load_and_update_blocklist(
197+
smileypack: str,
198+
smileys: dict[str, list[str]],
199+
block: str | None,
200+
unblock: str | None,
201+
) -> dict[str, list[str]]:
202+
"""Loads the smiley block list, update and save it.
203+
204+
We also add unblocked smileys to the smileys dictionary.
205+
206+
Args:
207+
smileypack: The name of a smiley pack to update/load.
208+
smileys: The loaded set of smileys.
209+
block: The smiley to be blocked.
210+
unblock: The smiley to be unblocked.
211+
212+
Returns
213+
-------
214+
The dictionary, containing where the keys are the filenames (without suffix) of the
215+
smileys and the values are strings that will be replaced by the
216+
file when sent in a message.
217+
218+
"""
219+
if block == unblock:
220+
raise ValueError("The smiley cannot be blocked and unblocked simultaneously.")
221+
block_list_file = os.path.join(os.path.dirname(__file__), "blocked_smileys.json")
222+
blocked_smileys: dict[str, dict[str, set[str]]] = {}
223+
if os.path.isfile(block_list_file):
224+
with open(block_list_file, "r") as f:
225+
blocked_smileys: dict[str, set[str]] = json.load(f)
226+
blocked_smileys_in_pack = blocked_smileys.get(smileypack, {})
227+
# Update the dictionary of blocked smileys if needed.
228+
is_dirty = block_smiley_maybe(smileys, blocked_smileys_in_pack, block)
229+
# Search for the smiley to unblock in the block list and remove it.
230+
is_dirty = (
231+
unblock_smiley_maybe(smileys, blocked_smileys_in_pack, unblock) or is_dirty
232+
)
233+
234+
if is_dirty:
235+
sort_strings(blocked_smileys_in_pack)
236+
blocked_smileys[smileypack] = blocked_smileys_in_pack
237+
with open(block_list_file, "w") as f:
238+
json.dump(blocked_smileys, f, ensure_ascii=False, indent=2)
239+
return blocked_smileys.get(smileypack, {})
240+
241+
242+
def remove_blocked_smileys(
243+
smileys: dict[str, list[str]], blocked_smileys: dict[str, list[str]]
244+
) -> None:
245+
"""Removed all blocked_smileys from smileys.
246+
247+
Args:
248+
smileys: The loaded set of smileys.
249+
blocked_smileys: The loaded smileys to be blocked.
250+
251+
"""
252+
for fname, strings in blocked_smileys.items():
253+
if fname in smileys:
254+
smileys[fname] = list(set(smileys[fname]).difference(set(strings)))
255+
256+
107257
def main() -> None:
108-
if len(sys.argv) != 2:
109-
print(f"Usage: {sys.argv[0]} <smileypack>")
110-
sys.exit(1)
111-
smileys = load_smileys(os.path.join(sys.argv[1], "emoticons.xml"))
112-
add_missing_smileys(sys.argv[1], smileys)
113-
remove_missing_smileys(sys.argv[1], smileys)
258+
parser = argparse.ArgumentParser(
259+
description="The script to parse and fix smileys directories."
260+
)
261+
parser.add_argument("smileypack", help="The folder with smileys.")
262+
parser.add_argument(
263+
"-b",
264+
"--block-smiley",
265+
help="The smiley to be added to blocklist.",
266+
required=False,
267+
default=None,
268+
)
269+
parser.add_argument(
270+
"-u",
271+
"--unblock-smiley",
272+
help="The smiley to be removed from blocklist.",
273+
required=False,
274+
default=None,
275+
)
276+
args = parser.parse_args()
277+
smileys = load_smileys(
278+
os.path.join(os.path.dirname(__file__), args.smileypack, "emoticons.xml")
279+
)
280+
add_missing_smileys(args.smileypack, smileys)
281+
remove_missing_smileys(args.smileypack, smileys)
282+
blocked_smileys = load_and_update_blocklist(
283+
args.smileypack, smileys, args.block_smiley, args.unblock_smiley
284+
)
285+
remove_blocked_smileys(smileys, blocked_smileys)
114286
sort_strings(smileys)
115-
save_smileys(os.path.join(sys.argv[1], "emoticons.xml"), smileys)
287+
save_smileys(os.path.join(args.smileypack, "emoticons.xml"), smileys)
116288

117289

118290
if __name__ == "__main__":

0 commit comments

Comments
 (0)