From 624d15f4b1435fc9a96d6083b6a35d5ded721121 Mon Sep 17 00:00:00 2001 From: Lukas Dobler <69309597+doluk@users.noreply.github.com> Date: Fri, 29 Nov 2024 23:14:53 +0100 Subject: [PATCH] DiscordChatExporterPy 2.8.1 * Fallback to filename if proxy url isn't suitable to determine file type Signed-off-by: doluk <69309597+doluk@users.noreply.github.com> * Prevent emojis in guild or channel name to break title or meta tags Signed-off-by: doluk <69309597+doluk@users.noreply.github.com> * Refactor message content handling logic Signed-off-by: doluk <69309597+doluk@users.noreply.github.com> --------- Signed-off-by: doluk <69309597+doluk@users.noreply.github.com> --- chat_exporter/construct/assets/attachment.py | 29 +++++++++++--------- chat_exporter/construct/message.py | 11 ++++---- chat_exporter/construct/transcript.py | 6 ++-- chat_exporter/ext/html_generator.py | 10 ++++++- chat_exporter/html/base.html | 14 +++++----- 5 files changed, 42 insertions(+), 28 deletions(-) diff --git a/chat_exporter/construct/assets/attachment.py b/chat_exporter/construct/assets/attachment.py index c936630..6d18d9e 100644 --- a/chat_exporter/construct/assets/attachment.py +++ b/chat_exporter/construct/assets/attachment.py @@ -88,16 +88,19 @@ async def get_file_icon(self) -> str: "arj", "pkg", "z" ) - extension = self.attachments.proxy_url.rsplit('.', 1)[1] - if extension in acrobat_types: - return DiscordUtils.file_attachment_acrobat - elif extension in webcode_types: - return DiscordUtils.file_attachment_webcode - elif extension in code_types: - return DiscordUtils.file_attachment_code - elif extension in document_types: - return DiscordUtils.file_attachment_document - elif extension in archive_types: - return DiscordUtils.file_attachment_archive - else: - return DiscordUtils.file_attachment_unknown + for tmp in [self.attachments.proxy_url, self.attachments.filename]: + if not tmp: + continue + extension = tmp.rsplit('.', 1)[-1] + if extension in acrobat_types: + return DiscordUtils.file_attachment_acrobat + elif extension in webcode_types: + return DiscordUtils.file_attachment_webcode + elif extension in code_types: + return DiscordUtils.file_attachment_code + elif extension in document_types: + return DiscordUtils.file_attachment_document + elif extension in archive_types: + return DiscordUtils.file_attachment_archive + + return DiscordUtils.file_attachment_unknown diff --git a/chat_exporter/construct/message.py b/chat_exporter/construct/message.py index 7bd3565..777410c 100644 --- a/chat_exporter/construct/message.py +++ b/chat_exporter/construct/message.py @@ -181,12 +181,8 @@ async def build_reference(self): is_bot = _gather_user_bot(message.author) user_colour = await self._gather_user_colour(message.author) - if not message.content and not getattr(message, 'interaction_metadata', None) and not getattr(message, 'interaction', None): - message.content = "Click to see attachment" - elif not message.content and ((hasattr(message, 'interaction_metadata') and message.interaction_metadata) or message.interaction): - message.content = "Click to see command" - icon = "" + dummy = "" def get_interaction_status(interaction_message): if hasattr(interaction_message, 'interaction_metadata'): return interaction_message.interaction_metadata @@ -195,8 +191,13 @@ def get_interaction_status(interaction_message): interaction_status = get_interaction_status(message) if not interaction_status and (message.embeds or message.attachments): icon = DiscordUtils.reference_attachment_icon + dummy = "Click to see attachment" elif interaction_status: icon = DiscordUtils.interaction_command_icon + dummy = "Click to see command" + + if not message.content: + message.content = dummy _, message_edited_at = self.set_time(message) diff --git a/chat_exporter/construct/transcript.py b/chat_exporter/construct/transcript.py index 526a449..4ea1fea 100644 --- a/chat_exporter/construct/transcript.py +++ b/chat_exporter/construct/transcript.py @@ -17,7 +17,7 @@ from chat_exporter.parse.mention import pass_bot from chat_exporter.ext.discord_utils import DiscordUtils from chat_exporter.ext.html_generator import ( - fill_out, total, channel_topic, meta_data_temp, fancy_time, channel_subject, PARSE_MODE_NONE + fill_out, total, channel_topic, meta_data_temp, fancy_time, channel_subject, PARSE_MODE_NONE, PARSE_MODE_HTML_SAFE ) @@ -167,7 +167,9 @@ async def export_transcript(self, message_html: str, meta_data: str): ("CHANNEL_ID", str(self.channel.id), PARSE_MODE_NONE), ("MESSAGE_PARTICIPANTS", str(len(meta_data)), PARSE_MODE_NONE), ("FANCY_TIME", _fancy_time, PARSE_MODE_NONE), - ("SD", sd, PARSE_MODE_NONE) + ("SD", sd, PARSE_MODE_NONE), + ("SERVER_NAME_SAFE", f"{guild_name}", PARSE_MODE_HTML_SAFE), + ("CHANNEL_NAME_SAFE", f"{html.escape(self.channel.name)}", PARSE_MODE_HTML_SAFE), ]) diff --git a/chat_exporter/ext/html_generator.py b/chat_exporter/ext/html_generator.py index d4c4515..3054d7e 100644 --- a/chat_exporter/ext/html_generator.py +++ b/chat_exporter/ext/html_generator.py @@ -1,3 +1,5 @@ +import html +import json import os from chat_exporter.parse.mention import ParseMention @@ -12,6 +14,7 @@ PARSE_MODE_SPECIAL_EMBED = 4 PARSE_MODE_REFERENCE = 5 PARSE_MODE_EMOJI = 6 +PARSE_MODE_HTML_SAFE = 7 async def fill_out(guild, base, replacements): @@ -34,8 +37,13 @@ async def fill_out(guild, base, replacements): v = await ParseMarkdown(v).message_reference_flow() elif mode == PARSE_MODE_EMOJI: v = await ParseMarkdown(v).special_emoji_flow() + elif mode == PARSE_MODE_HTML_SAFE: + # escape html characters + v = html.escape(v, quote=True) + # escape characters that could be used for xss + v = json.dumps(v, ensure_ascii=False)[1:-1] - base = base.replace("{{" + k + "}}", v.strip()) + base = base.replace("{{" + k + "}}", str(v or "").strip()) return base diff --git a/chat_exporter/html/base.html b/chat_exporter/html/base.html index cb4a671..da72cc5 100644 --- a/chat_exporter/html/base.html +++ b/chat_exporter/html/base.html @@ -10,22 +10,22 @@ - {{SERVER_NAME}} - {{CHANNEL_NAME}} + {{SERVER_NAME_SAFE}} - {{CHANNEL_NAME_SAFE}} - - + + - - + + - - + +