Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .restyled.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,14 @@ restylers:
enabled: false
- clazy:
enabled: false
# Disable conflicting python linters.
# Conflicts with "isort"
- reorder-python-imports:
enabled: false
# Conflicts with "black"
- yapf:
enabled: false
# Fix compatibilitry with "black" for "autopep8"
- autopep8:
arguments: ["--max-line-length", "88"]
- "*"
2 changes: 0 additions & 2 deletions smileys/EmojiOne/emoticons.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2358,11 +2358,9 @@
</emoticon>
<emoticon file="3297">
<string>㊗</string>
<string>祝</string>
</emoticon>
<emoticon file="3299">
<string>㊙</string>
<string>秘</string>
</emoticon>
<emoticon file="00a9">
<string>©</string>
Expand Down
6 changes: 6 additions & 0 deletions smileys/blocked_smileys.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"EmojiOne": {
"3297": ["祝"],
"3299": ["秘"]
}
}
209 changes: 190 additions & 19 deletions smileys/update_smileys.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
#!/usr/bin/env python3
import argparse
import json
import os
import sys
from xml.dom import minidom # nosec


def load_smileys(path: str) -> dict[str, list[str]]:
def load_smileys(path: str) -> dict[str, list[str]]: # noqa: D213
"""Load smileys from emoticons.xml file.

Args:
path: Path to the emoticons.xml file.

Returns:
A dictionary where the keys are the filenames (without suffix) of the
Returns
-------
smileys: A dictionary where the keys are the filenames (without suffix) of the
smileys and the values are the strings that will be replaced by the
file when sent in a message.

"""
smileys: dict[str, list[str]] = {}
dom = minidom.parse(path) # nosec
Expand All @@ -27,18 +30,18 @@ def load_smileys(path: str) -> dict[str, list[str]]:
return smileys


def save_smileys(path: str, smileys: dict[str, list[str]]) -> None:
def save_smileys(path: str, smileys: dict[str, list[str]]) -> None: # noqa: D213,D407
"""Save smileys to emoticons.xml file.

Args:
path: Path to the emoticons.xml file.
smileys: The same format as the return value of load_smileys.

"""
doc = minidom.Document()
root = doc.createElement("messaging-emoticon-map")
root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
root.setAttribute("xsi:noNamespaceSchemaLocation",
"../messaging-emoticon-map.xsd")
root.setAttribute("xsi:noNamespaceSchemaLocation", "../messaging-emoticon-map.xsd")
doc.appendChild(root)
for file, strings in smileys.items():
emoticon = doc.createElement("emoticon")
Expand Down Expand Up @@ -69,11 +72,13 @@ def emoji_to_string(emoji: tuple[int, ...]) -> str:

def add_missing_smileys(path: str, smileys: dict[str, list[str]]) -> None:
"""Add smileys that exist in the path but not in the smileys dict."""
for emoji_str in sorted(filter_svgs(os.listdir(path)),
key=parse_emoji_sequence):
for emoji_str in sorted(filter_svgs(os.listdir(path)), key=parse_emoji_sequence):
emoji = emoji_to_string(parse_emoji_sequence(emoji_str))
if (emoji_str not in smileys or len(smileys[emoji_str]) == 1
and smileys[emoji_str][0] == emoji):
if (
emoji_str not in smileys
or len(smileys[emoji_str]) == 1
and smileys[emoji_str][0] == emoji
):
smileys[emoji_str] = [emoji]
if emoji not in smileys[emoji_str]:
smileys[emoji_str].append(emoji)
Expand All @@ -94,7 +99,7 @@ def prefer_emoji(emoji: str, string: str) -> str:
return string


def sort_strings(smileys: dict[str, list[str]]) -> None:
def sort_strings(smileys: dict[str, list[str]]) -> None: # noqa: D213
"""Sort the strings in the smileys dict.

We put the emoji string first.
Expand All @@ -104,15 +109,181 @@ def sort_strings(smileys: dict[str, list[str]]) -> None:
strings.sort(key=lambda s: prefer_emoji(emoji, s))


def block_smiley_maybe(
smileys: dict[str, list[str]],
blocked_smileys_in_pack: dict[str, list[str]],
block: str | None,
) -> bool: # noqa: D213
"""Block smiley defined in block and return True if blocked smiley list was modified.

Args
----
smileys: The loaded set of smileys.
blocked_smileys_in_pack: the list of currently blocked smileys.
block: The smiley to be blocked.

Returns
-------
True if blocked_smileys_in_pack was modified, False otherwise.

"""
is_dirty = False
if not block:
return is_dirty
block_name = None
for name, strings in smileys.items():
smiley_set = set(strings)
if block in smiley_set:
block_name = name
block_list = blocked_smileys_in_pack.get(block_name, [])
if block not in block_list:
# Add blocked smiley.
block_list.append(block)
blocked_smileys_in_pack[block_name] = block_list
is_dirty = True
else:
print(f'The smiley "{block}" is already blocked.')
break
if not block_name:
is_blocked = False
for name, strings in blocked_smileys_in_pack.items():
if block in strings:
print(f'The smiley "{block}" is already blocked.')
break
if is_blocked:
print(f'The smiley to block "{block}" was not found.')
return is_dirty


def unblock_smiley_maybe(
smileys: dict[str, list[str]],
blocked_smileys_in_pack: dict[str, list[str]],
unblock: str | None,
) -> bool: # noqa: D213
"""Unblock smiley defined in unblock and return True if blocked smiley list was modified.

Args:
smileys: The loaded set of smileys.
blocked_smileys_in_pack: the list of currently blocked smileys.
unblock: The smiley to be unblocked.

Returns
-------
True if blocked_smileys_in_pack was modified, False otherwise.

"""
is_dirty = False
unblock_name = None
if not unblock:
return is_dirty
for name, strings in blocked_smileys_in_pack.items():
smiley_set = set(strings)
if unblock in smiley_set:
# Unblock smiley.
unblock_name = name
blocked_smileys_in_pack[unblock_name].remove(unblock)
smiley_list = smileys.get(unblock_name, [])
smiley_list.append(unblock)
smileys[unblock_name] = list(set(smiley_list))
is_dirty = True
break
if not unblock_name:
print(f'The smiley to unblock "{unblock}" was not found in the blocklist.')
return is_dirty


def load_and_update_blocklist(
smileypack: str,
smileys: dict[str, list[str]],
block: str | None,
unblock: str | None,
) -> dict[str, list[str]]: # noqa: D213
"""Load the smiley block list, update and save it.

We also add unblocked smileys to the smileys dictionary.

Args:
smileypack: The name of a smiley pack to update/load.
smileys: The loaded set of smileys.
block: The smiley to be blocked.
unblock: The smiley to be unblocked.

Returns
-------
The dictionary, containing where the keys are the filenames (without suffix) of the
smileys and the values are strings that will be replaced by the
file when sent in a message.

"""
if block == unblock:
raise ValueError("The smiley cannot be blocked and unblocked simultaneously.")
block_list_file = os.path.join(os.path.dirname(__file__), "blocked_smileys.json")
blocked_smileys: dict[str, dict[str, list[str]]] = {}
if os.path.isfile(block_list_file):
with open(block_list_file, "r") as f:
blocked_smileys = json.load(f)
blocked_smileys_in_pack = blocked_smileys.get(smileypack, {})
# Update the dictionary of blocked smileys if needed.
is_dirty = block_smiley_maybe(smileys, blocked_smileys_in_pack, block)
# Search for the smiley to unblock in the block list and remove it.
is_dirty = (
unblock_smiley_maybe(smileys, blocked_smileys_in_pack, unblock) or is_dirty
)

if is_dirty:
sort_strings(blocked_smileys_in_pack)
blocked_smileys[smileypack] = blocked_smileys_in_pack
with open(block_list_file, "w") as f:
json.dump(blocked_smileys, f, ensure_ascii=False, indent=2)
return blocked_smileys.get(smileypack, {})


def remove_blocked_smileys(
smileys: dict[str, list[str]], blocked_smileys: dict[str, list[str]]
) -> None: # noqa: D213, D407
"""Remove all blocked_smileys from smileys.

Args:
smileys: The loaded set of smileys.
blocked_smileys: The loaded smileys to be blocked.

"""
for fname, strings in blocked_smileys.items():
if fname in smileys:
smileys[fname] = list(set(smileys[fname]).difference(set(strings)))


def main() -> None:
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <smileypack>")
sys.exit(1)
smileys = load_smileys(os.path.join(sys.argv[1], "emoticons.xml"))
add_missing_smileys(sys.argv[1], smileys)
remove_missing_smileys(sys.argv[1], smileys)
parser = argparse.ArgumentParser(
description="The script to parse and fix smileys directories."
)
parser.add_argument("smileypack", help="The folder with smileys.")
parser.add_argument(
"-b",
"--block-smiley",
help="The smiley to be added to blocklist.",
required=False,
default=None,
)
parser.add_argument(
"-u",
"--unblock-smiley",
help="The smiley to be removed from blocklist.",
required=False,
default=None,
)
args = parser.parse_args()
smileys = load_smileys(
os.path.join(os.path.dirname(__file__), args.smileypack, "emoticons.xml")
)
add_missing_smileys(args.smileypack, smileys)
remove_missing_smileys(args.smileypack, smileys)
blocked_smileys = load_and_update_blocklist(
args.smileypack, smileys, args.block_smiley, args.unblock_smiley
)
remove_blocked_smileys(smileys, blocked_smileys)
sort_strings(smileys)
save_smileys(os.path.join(sys.argv[1], "emoticons.xml"), smileys)
save_smileys(os.path.join(args.smileypack, "emoticons.xml"), smileys)


if __name__ == "__main__":
Expand Down
Loading