From 2f762025d07c26092e90a2e4f5e45e5d6900364d Mon Sep 17 00:00:00 2001
From: Yee Jia Rong <28086837+fourjr@users.noreply.github.com>
Date: Sun, 21 Nov 2021 18:49:41 +0800
Subject: [PATCH] Support LOTTIE images, resolves #3119
---
CHANGELOG.md | 1 +
Pipfile | 1 +
Pipfile.lock | 167 +++++++++++++++++++++++++++++++++++++++++++++-
README.md | 2 +-
bot.py | 11 ++-
core/changelog.py | 1 +
core/thread.py | 58 +++++++++++++---
7 files changed, 226 insertions(+), 15 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18935f9f23..5db8a4b950 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,7 @@ however, insignificant breaking changes do not guarantee a major version bump, s
- Stickers were not working in Modmail.
- Large server sizes results in Guild.name == None. ([GH #3088](https://github.com/kyb3r/modmail/issues/3088))
- Attachments did not work on plain replies. ([GH #3102](https://github.com/kyb3r/modmail/issues/3102))
+- Support LOTTIE stickers. ([GH #3119](https://github.com/kyb3r/modmail/issues/3119))
### Internal
diff --git a/Pipfile b/Pipfile
index 51569d26e5..a78db95d18 100644
--- a/Pipfile
+++ b/Pipfile
@@ -21,6 +21,7 @@ pymongo = {extras = ["srv"], version = "*"} # Required by motor
python-dateutil = "~=2.8.1"
python-dotenv = "~=0.18.0"
uvloop = {version = ">=0.15.2", markers = "sys_platform != 'win32'"}
+lottie = {version = "==0.6.10", extras = ["pdf"]}
[scripts]
bot = "python bot.py"
diff --git a/Pipfile.lock b/Pipfile.lock
index e1a77d86b5..1fa9e5e64a 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "aaa53487befe4f19feda64131fbc5bde140c1ec1a59ff2656d2ad1da2c50b390"
+ "sha256": "29d6f377cdb874102deb4df1406ff6d0a66834fcb89660f3c9599a2343cda038"
},
"pipfile-spec": 6,
"requires": {
@@ -75,6 +75,76 @@
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==21.2.0"
},
+ "cairocffi": {
+ "hashes": [
+ "sha256:108a3a7cb09e203bdd8501d9baad91d786d204561bd71e9364e8b34897c47b91"
+ ],
+ "markers": "python_version >= '3.7'",
+ "version": "==1.3.0"
+ },
+ "cairosvg": {
+ "hashes": [
+ "sha256:98c276b7e4f0caf01e5c7176765c104ffa1aa1461d63b2053b04ab663cf7052b",
+ "sha256:b0b9929cf5dba005178d746a8036fcf0025550f498ca54db61873322384783bc"
+ ],
+ "markers": "python_version >= '3.5'",
+ "version": "==2.5.2"
+ },
+ "cffi": {
+ "hashes": [
+ "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3",
+ "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2",
+ "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636",
+ "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20",
+ "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728",
+ "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27",
+ "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66",
+ "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443",
+ "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0",
+ "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7",
+ "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39",
+ "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605",
+ "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a",
+ "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37",
+ "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029",
+ "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139",
+ "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc",
+ "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df",
+ "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14",
+ "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880",
+ "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2",
+ "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a",
+ "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e",
+ "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474",
+ "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024",
+ "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8",
+ "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0",
+ "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e",
+ "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a",
+ "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e",
+ "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032",
+ "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6",
+ "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e",
+ "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b",
+ "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e",
+ "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954",
+ "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962",
+ "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c",
+ "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4",
+ "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55",
+ "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962",
+ "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023",
+ "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c",
+ "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6",
+ "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8",
+ "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382",
+ "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7",
+ "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc",
+ "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997",
+ "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"
+ ],
+ "version": "==1.15.0"
+ },
"chardet": {
"hashes": [
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
@@ -91,6 +161,22 @@
"index": "pypi",
"version": "==0.4.4"
},
+ "cssselect2": {
+ "hashes": [
+ "sha256:2f4a9f20965367bae459e3bb42561f7927e0cfe5b7ea1692757cf67ef5d7dace",
+ "sha256:93fbb9af860e95dd40bf18c3b2b6ed99189a07c0f29ba76f9c5be71344664ec8"
+ ],
+ "markers": "python_version >= '3.6'",
+ "version": "==0.4.1"
+ },
+ "defusedxml": {
+ "hashes": [
+ "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69",
+ "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"
+ ],
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+ "version": "==0.7.1"
+ },
"discord-py": {
"git": "https://github.com/Rapptz/discord.py.git",
"ref": "45d498c1b76deaf3b394d17ccf56112fa691d160"
@@ -131,6 +217,16 @@
"index": "pypi",
"version": "==0.6.0"
},
+ "lottie": {
+ "extras": [
+ "pdf"
+ ],
+ "hashes": [
+ "sha256:d3281d09a8db94da49f60267123b9e0473e3a51c282da2d5e61908d33843f1cc"
+ ],
+ "index": "pypi",
+ "version": "==0.6.10"
+ },
"motor": {
"hashes": [
"sha256:1196db507142ef8f00d953efa2f37b39335ef2d72af6ce4fbccfd870b65c5e9f",
@@ -232,6 +328,60 @@
"index": "pypi",
"version": "==2.6"
},
+ "pillow": {
+ "hashes": [
+ "sha256:066f3999cb3b070a95c3652712cffa1a748cd02d60ad7b4e485c3748a04d9d76",
+ "sha256:0a0956fdc5defc34462bb1c765ee88d933239f9a94bc37d132004775241a7585",
+ "sha256:0b052a619a8bfcf26bd8b3f48f45283f9e977890263e4571f2393ed8898d331b",
+ "sha256:1394a6ad5abc838c5cd8a92c5a07535648cdf6d09e8e2d6df916dfa9ea86ead8",
+ "sha256:1bc723b434fbc4ab50bb68e11e93ce5fb69866ad621e3c2c9bdb0cd70e345f55",
+ "sha256:244cf3b97802c34c41905d22810846802a3329ddcb93ccc432870243211c79fc",
+ "sha256:25a49dc2e2f74e65efaa32b153527fc5ac98508d502fa46e74fa4fd678ed6645",
+ "sha256:2e4440b8f00f504ee4b53fe30f4e381aae30b0568193be305256b1462216feff",
+ "sha256:3862b7256046fcd950618ed22d1d60b842e3a40a48236a5498746f21189afbbc",
+ "sha256:3eb1ce5f65908556c2d8685a8f0a6e989d887ec4057326f6c22b24e8a172c66b",
+ "sha256:3f97cfb1e5a392d75dd8b9fd274d205404729923840ca94ca45a0af57e13dbe6",
+ "sha256:493cb4e415f44cd601fcec11c99836f707bb714ab03f5ed46ac25713baf0ff20",
+ "sha256:4acc0985ddf39d1bc969a9220b51d94ed51695d455c228d8ac29fcdb25810e6e",
+ "sha256:5503c86916d27c2e101b7f71c2ae2cddba01a2cf55b8395b0255fd33fa4d1f1a",
+ "sha256:5b7bb9de00197fb4261825c15551adf7605cf14a80badf1761d61e59da347779",
+ "sha256:5e9ac5f66616b87d4da618a20ab0a38324dbe88d8a39b55be8964eb520021e02",
+ "sha256:620582db2a85b2df5f8a82ddeb52116560d7e5e6b055095f04ad828d1b0baa39",
+ "sha256:62cc1afda735a8d109007164714e73771b499768b9bb5afcbbee9d0ff374b43f",
+ "sha256:70ad9e5c6cb9b8487280a02c0ad8a51581dcbbe8484ce058477692a27c151c0a",
+ "sha256:72b9e656e340447f827885b8d7a15fc8c4e68d410dc2297ef6787eec0f0ea409",
+ "sha256:72cbcfd54df6caf85cc35264c77ede902452d6df41166010262374155947460c",
+ "sha256:792e5c12376594bfcb986ebf3855aa4b7c225754e9a9521298e460e92fb4a488",
+ "sha256:7b7017b61bbcdd7f6363aeceb881e23c46583739cb69a3ab39cb384f6ec82e5b",
+ "sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d",
+ "sha256:82aafa8d5eb68c8463b6e9baeb4f19043bb31fefc03eb7b216b51e6a9981ae09",
+ "sha256:84c471a734240653a0ec91dec0996696eea227eafe72a33bd06c92697728046b",
+ "sha256:8c803ac3c28bbc53763e6825746f05cc407b20e4a69d0122e526a582e3b5e153",
+ "sha256:93ce9e955cc95959df98505e4608ad98281fff037350d8c2671c9aa86bcf10a9",
+ "sha256:9a3e5ddc44c14042f0844b8cf7d2cd455f6cc80fd7f5eefbe657292cf601d9ad",
+ "sha256:a4901622493f88b1a29bd30ec1a2f683782e57c3c16a2dbc7f2595ba01f639df",
+ "sha256:a5a4532a12314149d8b4e4ad8ff09dde7427731fcfa5917ff16d0291f13609df",
+ "sha256:b8831cb7332eda5dc89b21a7bce7ef6ad305548820595033a4b03cf3091235ed",
+ "sha256:b8e2f83c56e141920c39464b852de3719dfbfb6e3c99a2d8da0edf4fb33176ed",
+ "sha256:c70e94281588ef053ae8998039610dbd71bc509e4acbc77ab59d7d2937b10698",
+ "sha256:c8a17b5d948f4ceeceb66384727dde11b240736fddeda54ca740b9b8b1556b29",
+ "sha256:d82cdb63100ef5eedb8391732375e6d05993b765f72cb34311fab92103314649",
+ "sha256:d89363f02658e253dbd171f7c3716a5d340a24ee82d38aab9183f7fdf0cdca49",
+ "sha256:d99ec152570e4196772e7a8e4ba5320d2d27bf22fdf11743dd882936ed64305b",
+ "sha256:ddc4d832a0f0b4c52fff973a0d44b6c99839a9d016fe4e6a1cb8f3eea96479c2",
+ "sha256:e3dacecfbeec9a33e932f00c6cd7996e62f53ad46fbe677577394aaa90ee419a",
+ "sha256:eb9fc393f3c61f9054e1ed26e6fe912c7321af2f41ff49d3f83d05bacf22cc78"
+ ],
+ "markers": "python_version >= '3.6'",
+ "version": "==8.4.0"
+ },
+ "pycparser": {
+ "hashes": [
+ "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9",
+ "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"
+ ],
+ "version": "==2.21"
+ },
"pymongo": {
"extras": [
"srv"
@@ -372,6 +522,14 @@
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
+ "tinycss2": {
+ "hashes": [
+ "sha256:0353b5234bcaee7b1ac7ca3dea7e02cd338a9f8dcbb8f2dcd32a5795ec1e5f9a",
+ "sha256:fbdcac3044d60eb85fdb2aa840ece43cf7dbe798e373e6ee0be545d4d134e18a"
+ ],
+ "markers": "python_version >= '3.6'",
+ "version": "==1.1.0"
+ },
"typing-extensions": {
"hashes": [
"sha256:2cdf80e4e04866a9b3689a51869016d36db0814d84b8d8a568d22781d45d27ed",
@@ -402,6 +560,13 @@
"markers": "sys_platform != 'win32'",
"version": "==0.16.0"
},
+ "webencodings": {
+ "hashes": [
+ "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
+ "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
+ ],
+ "version": "==0.5.1"
+ },
"yarl": {
"hashes": [
"sha256:044daf3012e43d4b3538562da94a88fb12a6490652dbc29fb19adfa02cf72eac",
diff --git a/README.md b/README.md
index cf62cfe5d6..7492a53116 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
-
+
diff --git a/bot.py b/bot.py
index c2e3ee5adf..38bd6423b2 100644
--- a/bot.py
+++ b/bot.py
@@ -50,9 +50,6 @@
logger = getLogger(__name__)
-# # prevent "coroutine noop was never awaited" warning.
-# asyncio.coroutines._DEBUG = False # type: ignore
-
temp_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "temp")
if not os.path.exists(temp_dir):
@@ -1691,6 +1688,14 @@ def main():
except ImportError:
pass
+ try:
+ import cairosvg
+ except OSError:
+ logger.error(
+ "Unable to import cairosvg, install GTK Installer for Windows: https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases/latest"
+ )
+ sys.exit(0)
+
# check discord version
if discord.__version__ != "2.0.0a":
logger.error(
diff --git a/core/changelog.py b/core/changelog.py
index 4ede9f09f1..a4f88ed323 100644
--- a/core/changelog.py
+++ b/core/changelog.py
@@ -97,6 +97,7 @@ def embed(self) -> Embed:
for name, value in self.fields.items():
embed.add_field(name=name, value=truncate(value, 1024), inline=False)
embed.set_footer(text=f"Current version: v{self.bot.version}")
+
embed.set_thumbnail(url=self.bot.user.display_avatar.url)
return embed
diff --git a/core/thread.py b/core/thread.py
index ff2ea791cd..09f8bd3d41 100644
--- a/core/thread.py
+++ b/core/thread.py
@@ -1,8 +1,11 @@
import asyncio
+import base64
import copy
+import functools
import io
import re
import time
+import traceback
import typing
import warnings
from datetime import timedelta
@@ -12,6 +15,8 @@
import discord
from discord.ext.commands import MissingRequiredArgument, CommandError
+from lottie.importers import importers as l_importers
+from lottie.exporters import exporters as l_exporters
from core.models import DMDisabled, DummyMessage, getLogger
from core.time import human_timedelta
@@ -987,16 +992,49 @@ async def send(
if is_image_url(url, convert_size=False)
]
images.extend(image_urls)
- images.extend(
- (
- i.url
- if i.format in (discord.StickerFormatType.png, discord.StickerFormatType.apng)
- else None,
- i.name,
- True,
- )
- for i in message.stickers
- )
+
+ def lottie_to_png(data):
+ importer = l_importers.get("lottie")
+ exporter = l_exporters.get("png")
+ with io.BytesIO() as stream:
+ stream.write(data)
+ stream.seek(0)
+ an = importer.process(stream)
+
+ with io.BytesIO() as stream:
+ exporter.process(an, stream)
+ stream.seek(0)
+ return stream.read()
+
+ for i in message.stickers:
+ if i.format in (discord.StickerFormatType.png, discord.StickerFormatType.apng):
+ images.append((i.url, i.name, True))
+ elif i.format == discord.StickerFormatType.lottie:
+ # save the json lottie representation
+ try:
+ async with self.bot.session.get(i.url) as resp:
+ data = await resp.read()
+
+ # convert to a png
+ img_data = await self.bot.loop.run_in_executor(None, functools.partial(lottie_to_png, data))
+ b64_data = base64.b64encode(img_data).decode()
+
+ # upload to imgur
+ async with self.bot.session.post(
+ "https://api.imgur.com/3/image",
+ headers={"Authorization": "Client-ID 50e96145ac5e085"},
+ data={"image": b64_data},
+ ) as resp:
+ result = await resp.json()
+ url = result["data"]["link"]
+
+ except Exception:
+ traceback.print_exc()
+ images.append((None, i.name, True))
+ else:
+ images.append((url, i.name, True))
+ else:
+ images.append((None, i.name, True))
embedded_image = False