diff --git a/README.rst b/README.rst index d676613..69d0f82 100644 --- a/README.rst +++ b/README.rst @@ -39,7 +39,6 @@ Usage @bot.event async def on_ready(): print("Live: " + bot.user.name) - chat_exporter.init_exporter(bot) @bot.command() @@ -49,7 +48,7 @@ Usage if __name__ == "__main__": bot.run("BOT_TOKEN_HERE") -*Optional: If you want to display Members Colours (Role Colours) then enable the Members Intent.* +*Optional: If you want the transcript to display Members (Role) Colours then enable the Members Intent.* Screenshots ----------- diff --git a/chat_exporter/__init__.py b/chat_exporter/__init__.py index cd0f1d7..b565a01 100644 --- a/chat_exporter/__init__.py +++ b/chat_exporter/__init__.py @@ -1,2 +1,2 @@ -from chat_exporter.chat_exporter import export, init_exporter, generate_transcript +from chat_exporter.chat_exporter import export, generate_transcript from chat_exporter import chat_exporter_html diff --git a/chat_exporter/chat_exporter.py b/chat_exporter/chat_exporter.py index e2c511d..843b10d 100644 --- a/chat_exporter/chat_exporter.py +++ b/chat_exporter/chat_exporter.py @@ -6,7 +6,7 @@ import traceback from chat_exporter.misc_tools import escape_html, member_colour_translator from chat_exporter.mention_convert import parse_mentions, escape_mentions, unescape_mentions -from chat_exporter.markdown_convert import parse_markdown, parse_embed_markdown, parse_emoji +from chat_exporter.markdown_convert import parse_markdown, parse_embed_markdown, parse_emoji, https_http_links from chat_exporter.emoji_convert import convert_emoji from pytz import timezone from datetime import timedelta @@ -16,13 +16,6 @@ eastern = timezone("US/Eastern") utc = timezone("UTC") -bot = None - - -def init_exporter(_bot): - global bot - bot = _bot - async def export(ctx): # noinspection PyBroadException @@ -62,7 +55,10 @@ async def export(ctx): await ctx.channel.send(embed=transcript_embed, file=transcript_file) -async def generate_transcript(channel): +async def generate_transcript(channel: discord.TextChannel, tz_info="US/Eastern"): + global eastern + eastern = timezone(tz_info) + # noinspection PyBroadException try: transcript = await produce_transcript(channel) @@ -98,6 +94,8 @@ async def produce_transcript(channel): for e in m.embeds: fields = "" for f in e.fields: + f.name = await https_http_links(f.name) + f.value = await https_http_links(f.value) if f.inline: cur_field = await fill_out(channel, msg_embed_field_inline, [ ("EMBED_FIELD_NAME", f.name), @@ -116,15 +114,25 @@ async def produce_transcript(channel): title = e.title \ if e.title != discord.Embed.Empty \ else "" + if title != "": + title = await https_http_links(title) r, g, b = (e.colour.r, e.colour.g, e.colour.b) \ if e.colour != discord.Embed.Empty \ else (0x20, 0x22, 0x25) # default colour desc = e.description \ if e.description != discord.Embed.Empty \ else "" + if desc != "": + desc = await https_http_links(desc) author = e.author.name \ if e.author.name != discord.Embed.Empty \ else "" + author_url = e.author.url \ + if e.author.url != discord.Embed.Empty \ + else "" + author_icon = e.author.icon_url \ + if e.author.icon_url != discord.Embed.Empty \ + else "" footer = e.footer.text \ if e.footer.text != discord.Embed.Empty \ else "" @@ -139,6 +147,8 @@ async def produce_transcript(channel): image = e.image.url \ if e.image.url != discord.Embed.Empty \ else "" + if author_url != "": + author = f'{author}' if image != "": image = await fill_out(channel, embed_image, [ @@ -163,11 +173,24 @@ async def produce_transcript(channel): ]) footer_fields += cur_footer + author_html = "" + if author != "": + if author_icon != "": + cur_author_icon = await fill_out(channel, embed_author_icon, [ + ("EMBED_AUTHOR", author), + ("EMBED_AUTHOR_ICON", author_icon) + ]) + else: + cur_author_icon = await fill_out(channel, embed_author, [ + ("EMBED_AUTHOR", author), + ]) + author_html += cur_author_icon + cur_embed = await fill_out(channel, msg_embed, [ ("EMBED_R", str(r)), ("EMBED_G", str(g)), ("EMBED_B", str(b)), - ("EMBED_AUTHOR", author, PARSE_MODE_EMBED_EMOJI), + ("EMBED_AUTHOR", author_html, PARSE_MODE_EMBED_EMOJI), ("EMBED_TITLE", title, PARSE_MODE_EMBED_EMOJI), ("EMBED_IMAGE", image), ("EMBED_THUMBNAIL", thumbnail), @@ -204,35 +227,7 @@ async def produce_transcript(channel): else: ze_bot_tag = "" - output = [] - if "http://" in m.content or "www." in m.content or "https://" in m.content: - for word in m.content.split(): - if word.startswith("<") and word.endswith(">"): - pattern = r"<(.*)>" - url = re.search(pattern, word).group(1) - url = f'{url}' - output.append(url) - elif "http://" in word: - pattern = r"http://(.*)" - word_link = re.search(pattern, word).group(1) - word_full = f'http://{word_link}' - word = re.sub(pattern, word_full, word) - output.append(word) - elif "www." in word: - pattern = r"www.(.*)" - word_link = re.search(pattern, word).group(1) - word_full = f'www.{word_link}' - word = re.sub(pattern, word_full, word) - output.append(word) - elif "https://" in word: - pattern = r"https://(.*)" - word_link = re.search(pattern, word).group(1) - word_full = f'https://{word_link}' - word = re.sub(pattern, word_full, word) - output.append(word) - else: - output.append(word) - m.content = " ".join(output) + m.content = await https_http_links(m.content) emojis = "" for reactions in m.reactions: @@ -345,7 +340,7 @@ async def fill_out(channel, base, replacements): v = await escape_mentions(v) v = await escape_mentions(v) v = await unescape_mentions(v) - v = await parse_mentions(v, channel.guild, bot) + v = await parse_mentions(v, channel.guild) if mode == PARSE_MODE_MARKDOWN: v = await parse_markdown(v) if mode == PARSE_MODE_EMBED: @@ -386,3 +381,5 @@ def read_file(filename): embed_footer_image = read_file(dir_path + "/chat_exporter_html/embed_footer_image.html") embed_image = read_file(dir_path + "/chat_exporter_html/embed_image.html") embed_thumbnail = read_file(dir_path + "/chat_exporter_html/embed_thumbnail.html") +embed_author = read_file(dir_path + "/chat_exporter_html/embed_author.html") +embed_author_icon = read_file(dir_path + "/chat_exporter_html/embed_author_icon.html") diff --git a/chat_exporter/chat_exporter_html/base.html b/chat_exporter/chat_exporter_html/base.html index 2bbfb19..244a2b8 100644 --- a/chat_exporter/chat_exporter_html/base.html +++ b/chat_exporter/chat_exporter_html/base.html @@ -11,31 +11,31 @@ @font-face { font-family: Whitney; - src: url(https://discordapp.com/assets/6c6374bad0b0b6d204d8d6dc4a18d820.woff); + src: url(https://cdn.jsdelivr.net/gh/mahtoid/DiscordFonts@master/whitney-300.woff); font-weight: 300; } @font-face { font-family: Whitney; - src: url(https://discordapp.com/assets/e8acd7d9bf6207f99350ca9f9e23b168.woff); + src: url(https://cdn.jsdelivr.net/gh/mahtoid/DiscordFonts@master/whitney-400.woff); font-weight: 400; } @font-face { font-family: Whitney; - src: url(https://discordapp.com/assets/3bdef1251a424500c1b3a78dea9b7e57.woff); + src: url(https://cdn.jsdelivr.net/gh/mahtoid/DiscordFonts@master/whitney-500.woff); font-weight: 500; } @font-face { font-family: Whitney; - src: url(https://discordapp.com/assets/be0060dafb7a0e31d2a1ca17c0708636.woff); + src: url(https://cdn.jsdelivr.net/gh/mahtoid/DiscordFonts@master/whitney-600.woff); font-weight: 600; } @font-face { font-family: Whitney; - src: url(https://discordapp.com/assets/8e12fb4f14d9c4592eb8ec9f22337b04.woff); + src: url(https://cdn.jsdelivr.net/gh/mahtoid/DiscordFonts@master/whitney-700.woff); font-weight: 700; } @@ -57,32 +57,33 @@ } .markdown { - white-space: pre-wrap; + max-width: 100%; line-height: 1.3; overflow-wrap: break-word; } -.spoiler--hidden .spoiler-text { - background-color: #202225; - color: rgba(0, 0, 0, 0); +.preserve-whitespace { + white-space: pre-wrap; } .spoiler { - width: fit-content; + display: inline-block; } .spoiler--hidden { cursor: pointer; } -.spoiler--hidden:hover .spoiler-text { - background-color: #202225; +.spoiler-text { + border-radius: 3px; +} + +.spoiler--hidden .spoiler-text { color: rgba(0, 0, 0, 0); } -.spoiler-text { - background-color: rgba(255, 255, 255, 0.1); - border-radius: 3px; +.spoiler--hidden .spoiler-text::selection { + color: rgba(0, 0, 0, 0); } .spoiler-image { @@ -95,24 +96,27 @@ box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.1); } -.spoiler--hidden .spoiler-image img { +.spoiler--hidden .spoiler-image * { filter: blur(44px); } -.spoiler--hidden .spoiler-image:after { - content: "SPOILER"; - color: #dcddde; - background-color: rgba(0, 0, 0, 0.6); - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); - font-weight: 600; - padding: 0.5em 0.7em; - border-radius: 20px; - letter-spacing: 0.05em; - font-size: 0.9em; -} + .spoiler--hidden .spoiler-image:after { + content: "SPOILER"; + color: #dcddde; + background-color: rgba(0, 0, 0, 0.6); + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + font-weight: 600; + padding: 100%; + /* This ruins those beutifully rounded buttons, but it's needed to prevent a FireFox bug with video and audio elemnts. */ + /* The bug is that you can click trough the spoiler layer and play the video or audio, I could not identify the cause. */ + /* I leave this here, in case someone is brave enough to venture in to madness that is undocumented browser behaviour. */ + border-radius: 20px; + letter-spacing: 0.05em; + font-size: 0.9em; + } .spoiler--hidden:hover .spoiler-image:after { color: #fff; @@ -120,10 +124,10 @@ } .quote { + margin: 0.1em 0; + padding-left: 0.6em; border-left: 4px solid; border-radius: 3px; - margin: 8px 0; - padding-left: 10px; } .pre { @@ -131,8 +135,8 @@ } .pre--multiline { - margin-top: 4px; - padding: 8px; + margin-top: 0.25em; + padding: 0.5em; border: 2px solid; border-radius: 5px; } @@ -140,93 +144,50 @@ .pre--inline { padding: 2px; border-radius: 3px; - font-size: 85%; + font-size: 0.85em; } .mention { + border-radius: 3px; + padding: 0 2px; + color: #7289da; + background: rgba(114, 137, 218, .1); font-weight: 500; } .emoji { - width: 1.45em; - height: 1.45em; - margin: 0 1px; + width: 1.25em; + height: 1.25em; + margin: 0 0.06em; vertical-align: -0.4em; } .emoji--small { - width: 1rem; - height: 1rem; + width: 1em; + height: 1em; } .emoji--large { - width: 2rem; - height: 2rem; + width: 2.8em; + height: 2.8em; } -/* === INFO === */ - -.info { - display: flex; - max-width: 100%; - margin: 0 5px 10px 5px; -} - -.info__guild-icon-container { - flex: 0; -} - -.info__guild-icon { - max-width: 88px; - max-height: 88px; -} - -.info__metadata { - flex: 1; - margin-left: 10px; -} - -.info__guild-name { - font-size: 1.2em; -} - -.info__channel-name { - font-size: 1em; -} - -.info__channel-topic { - margin-top: 2px; -} - -.info__channel-message-count { - margin-top: 2px; -} - -.info__channel-timezone { - margin-top: 2px; - font-size:0.9em; -} - -.info__channel-date-range { - margin-top: 2px; -} - -/* === CHATLOG === */ +/* Chatlog */ .chatlog { max-width: 100%; - margin-bottom: 24px; } .chatlog__message-group { - display: flex; - margin: 0 10px; - padding: 15px 0; + display: grid; + margin: 0 0.6em; + padding: 0.9em 0; border-top: 1px solid; + grid-template-columns: auto 1fr; } .chatlog__author-avatar-container { - flex: 0; + grid-column: 1; width: 40px; height: 40px; } @@ -238,55 +199,57 @@ } .chatlog__messages { - flex: 1; + grid-column: 2; + margin-left: 1.2em; min-width: 50%; - margin-left: 20px; } .chatlog__author-name { - font-size: 1em; font-weight: 500; } .chatlog__timestamp { - margin-left: 5px; - font-size: .75em; + margin-left: 0.3em; + font-size: 0.75em; } .chatlog__message { - padding: 2px 5px; - margin-right: -5px; - margin-left: -5px; + padding: 0.1em 0.3em; + margin: 0 -0.3em; background-color: transparent; transition: background-color 1s ease; } .chatlog__content { - font-size: .9375em; + font-size: 0.95em; word-wrap: break-word; } .chatlog__edited-timestamp { - margin-left: 3px; - font-size: .8em; + margin-left: 0.15em; + font-size: 0.8em; +} + +.chatlog__attachment { + margin-top: 0.3em; } .chatlog__attachment-thumbnail { - margin-top: 5px; - max-width: 50%; - max-height: 300px; + vertical-align: top; + max-width: 45vw; + max-height: 500px; border-radius: 3px; } .chatlog__embed { - margin-top: 5px; display: flex; + margin-top: 0.3em; max-width: 520px; } .chatlog__embed-color-pill { flex-shrink: 0; - width: 4px; + width: 0.25em; border-top-left-radius: 3px; border-bottom-left-radius: 3px; } @@ -294,15 +257,15 @@ .chatlog__embed-content-container { display: flex; flex-direction: column; - padding: 8px 10px; + padding: 0.5em 0.6em; border: 1px solid; border-top-right-radius: 3px; border-bottom-right-radius: 3px; } .chatlog__embed-content { - width: 100%; display: flex; + width: 100%; } .chatlog__embed-text { @@ -311,31 +274,31 @@ .chatlog__embed-author { display: flex; + margin-bottom: 0.3em; align-items: center; - margin-bottom: 5px; } .chatlog__embed-author-icon { + margin-right: 0.5em; width: 20px; height: 20px; - margin-right: 9px; border-radius: 50%; } .chatlog__embed-author-name { - font-size: .875em; + font-size: 0.875em; font-weight: 600; } .chatlog__embed-title { - margin-bottom: 4px; - font-size: .875em; + margin-bottom: 0.2em; + font-size: 0.875em; font-weight: 600; } .chatlog__embed-description { font-weight: 500; - font-size: 14px; + font-size: 0.85em; } .chatlog__embed-fields { @@ -347,7 +310,8 @@ flex: 0; min-width: 100%; max-width: 506px; - padding-top: 10px; + padding-top: 0.6em; + font-size: 0.875em; } .chatlog__embed-field--inline { @@ -357,26 +321,24 @@ } .chatlog__embed-field-name { - margin-bottom: 4px; - font-size: .875em; + margin-bottom: 0.2em; font-weight: 600; } .chatlog__embed-field-value { - font-size: .875em; font-weight: 500; } .chatlog__embed-thumbnail { flex: 0; - margin-left: 20px; + margin-left: 1.2em; max-width: 80px; max-height: 80px; border-radius: 3px; } .chatlog__embed-image-container { - margin-top: 10px; + margin-top: 0.6em; } .chatlog__embed-image { @@ -386,11 +348,11 @@ } .chatlog__embed-footer { - margin-top: 10px; + margin-top: 0.6em; } .chatlog__embed-footer-icon { - margin-right: 4px; + margin-right: 0.2em; width: 20px; height: 20px; border-radius: 50%; @@ -398,8 +360,8 @@ } .chatlog__embed-footer-text { + font-size: 0.75em; font-weight: 500; - font-size: .75em; } .chatlog__reactions { @@ -409,32 +371,41 @@ .chatlog__reaction { display: flex; align-items: center; - margin: 6px 2px 2px 2px; - padding: 3px 6px; + margin: 0.35em 0.1em 0.1em 0.1em; + padding: 0.2em 0.35em; border-radius: 3px; } .chatlog__reaction-count { min-width: 9px; - margin-left: 6px; - font-size: .875em; + margin-left: 0.35em; + font-size: 0.875em; } .chatlog__bot-tag { + position: relative; + top: -.2em; margin-left: 0.3em; - background: #7289da; - color: #ffffff; - font-size: 0.625em; - padding: 1px 2px; + padding: 0.05em 0.3em; border-radius: 3px; vertical-align: middle; line-height: 1.3; - position: relative; - top: -.2em; + background: #7289da; + color: #ffffff; + font-size: 0.625em; + font-weight: 500; +} + +/* Postamble */ + +.postamble { + margin: 1.4em 0.3em 0.6em 0.3em; + padding: 1em; + border-top: 1px solid; }