Skip to content

Commit

Permalink
DiscordChatExporterPy 2.5 (#74)
Browse files Browse the repository at this point in the history
* Support for interactions and verified bots (#71)

* Addition of a verified bot tag and support for logging interactions

* part 1 fix

* part 2 fix

* part 3 fix

* part 4 fix

* part 5 fix

* part 6 fix

* part 7 fix

* part 8 fix

* part 9 fix

* removed not used css, added underline for interation-link on hover

* added interaction command icon

* renamed icon to make visible it could be command icon

* add support for interactions in references, fix parse mode for command names

* remove followup symbol appearing twice for unknown reference

* unify code, handle reference & interaction as followup as long as they are the same

* code cleanup

* fix followup icons

* fix followup icons part 2

* fix edge case for references containing only a link to an attachment

* okay doesn't work this way

* fix formating

* CSS Changes

Co-authored-by: mahtoid <matthewmoss98@gmail.com>

* Add Guild ID to Summary (#72)

* Add GUILD_ID

* Add Guild ID

* Add before and after history support

* docstrings

* Use MessageType for Message construct

* Disnake to use 'None' instead of 'Embed.Empty'

Co-authored-by: Lukas Dobler <69309597+doluk@users.noreply.github.com>
Co-authored-by: deveninabox <44348797+deveninabox@users.noreply.github.com>
  • Loading branch information
3 people committed Nov 20, 2022
1 parent 07cbe4c commit ba6b640
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 42 deletions.
57 changes: 57 additions & 0 deletions chat_exporter/chat_exporter.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import datetime
import io
from typing import List, Optional

Expand All @@ -10,6 +11,15 @@ async def quick_export(
guild: Optional[discord.Guild] = None,
bot: Optional[discord.Client] = None,
):
"""
Create a quick export of your Discord channel.
This function will produce the transcript and post it back in to your channel.
:param channel: discord.TextChannel
:param guild: (optional) discord.Guild
:param bot: (optional) discord.Client
:return: discord.Message (posted transcript)
"""

if guild:
channel.guild = guild

Expand All @@ -21,6 +31,8 @@ async def quick_export(
pytz_timezone="UTC",
military_time=True,
fancy_times=True,
before=None,
after=None,
support_dev=True,
bot=bot,
).export()
Expand All @@ -46,8 +58,24 @@ async def export(
bot: Optional[discord.Client] = None,
military_time: Optional[bool] = True,
fancy_times: Optional[bool] = True,
before: Optional[datetime.datetime] = None,
after: Optional[datetime.datetime] = None,
support_dev: Optional[bool] = True,
):
"""
Create a customised transcript of your Discord channel.
This function will return the transcript which you can then turn in to a file to post wherever.
:param channel: discord.TextChannel - channel to Export
:param limit: (optional) integer - limit of messages to capture
:param tz_info: (optional) TZ Database Name - set the timezone of your transcript
:param guild: (optional) discord.Guild - solution for edpy
:param bot: (optional) discord.Client - set getting member role colour
:param military_time: (optional) boolean - set military time (24hour clock)
:param fancy_times: (optional) boolean - set javascript around time display
:param before: (optional) datetime.datetime - allows before time for history
:param after: (optional) datetime.datetime - allows after time for history
:return: string - transcript file make up
"""
if guild:
channel.guild = guild

Expand All @@ -59,6 +87,8 @@ async def export(
pytz_timezone=tz_info,
military_time=military_time,
fancy_times=fancy_times,
before=before,
after=after,
support_dev=support_dev,
bot=bot,
).export()
Expand All @@ -75,6 +105,18 @@ async def raw_export(
fancy_times: Optional[bool] = True,
support_dev: Optional[bool] = True,
):
"""
Create a customised transcript with your own captured Discord messages
This function will return the transcript which you can then turn in to a file to post wherever.
:param channel: discord.TextChannel - channel to Export
:param messages: List[discord.Message] - list of Discord messages to export
:param tz_info: (optional) TZ Database Name - set the timezone of your transcript
:param guild: (optional) discord.Guild - solution for edpy
:param bot: (optional) discord.Client - set getting member role colour
:param military_time: (optional) boolean - set military time (24hour clock)
:param fancy_times: (optional) boolean - set javascript around time display
:return: string - transcript file make up
"""
if guild:
channel.guild = guild

Expand All @@ -86,6 +128,8 @@ async def raw_export(
pytz_timezone=tz_info,
military_time=military_time,
fancy_times=fancy_times,
before=None,
after=None,
support_dev=support_dev,
bot=bot,
).export()
Expand All @@ -96,6 +140,13 @@ async def quick_link(
channel: discord.TextChannel,
message: discord.Message
):
"""
Create a quick link for your transcript file.
This function will return an embed with a link to view the transcript online.
:param channel: discord.TextChannel
:param message: discord.Message
:return: discord.Message (posted link)
"""
embed = discord.Embed(
title="Transcript Link",
description=(
Expand All @@ -110,4 +161,10 @@ async def quick_link(
async def link(
message: discord.Message
):
"""
Returns a link which you can use to display in a message.
This function will return a string of the link.
:param message: discord.Message
:return: string (link: https://mahto.id/chat-exporter?url=ATTACHMENT_URL)
"""
return "https://mahto.id/chat-exporter?url=" + message.attachments[0].url
4 changes: 3 additions & 1 deletion chat_exporter/construct/assets/embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
PARSE_MODE_SPECIAL_EMBED,
)

modules_which_use_none = ["nextcord", "disnake"]


def _gather_checker():
if hasattr(discord.Embed, "Empty") and discord.module != "nextcord":
if discord.module not in modules_which_use_none and hasattr(discord.Embed, "Empty"):
return discord.Embed.Empty
return None

Expand Down
64 changes: 50 additions & 14 deletions chat_exporter/construct/message.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import html
from typing import List, Optional
from typing import List, Optional, Union

from pytz import timezone
from datetime import timedelta
Expand All @@ -11,12 +11,14 @@
from chat_exporter.ext.html_generator import (
fill_out,
bot_tag,
bot_tag_verified,
message_body,
message_pin,
message_thread,
message_content,
message_reference,
message_reference_unknown,
message_interaction,
img_attachment,
start_message,
end_message,
Expand All @@ -27,7 +29,11 @@


def _gather_user_bot(author: discord.Member):
return bot_tag if author.bot else ""
if author.bot and author.public_flags.verified_bot:
return bot_tag_verified
elif author.bot:
return bot_tag
return ""


def _set_edit_at(message_edited_at):
Expand Down Expand Up @@ -69,9 +75,9 @@ def __init__(
async def construct_message(
self,
) -> (str, dict):
if "pins_add" in self.message.type:
if discord.MessageType.pins_add == self.message.type:
await self.build_pin()
elif "thread_created" in self.message.type:
elif discord.MessageType.thread_created == self.message.type:
await self.build_thread()
else:
await self.build_message()
Expand All @@ -80,6 +86,7 @@ async def construct_message(
async def build_message(self):
await self.build_content()
await self.build_reference()
await self.build_interaction()
await self.build_sticker()
await self.build_assets()
await self.build_message_template()
Expand Down Expand Up @@ -146,10 +153,16 @@ 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:
if not message.content and not message.interaction:
message.content = "Click to see attachment"
elif not message.content and message.interaction:
message.content = "Click to see command"

attachment_icon = DiscordUtils.reference_attachment_icon if message.embeds or message.attachments else ""
icon = ""
if not message.interaction and (message.embeds or message.attachments):
icon = DiscordUtils.reference_attachment_icon
elif message.interaction:
icon = DiscordUtils.interaction_command_icon

_, message_edited_at = self.set_time(message)

Expand All @@ -165,8 +178,30 @@ async def build_reference(self):
("USER_COLOUR", user_colour, PARSE_MODE_NONE),
("CONTENT", message.content, PARSE_MODE_REFERENCE),
("EDIT", message_edited_at, PARSE_MODE_NONE),
("ATTACHMENT_ICON", attachment_icon, PARSE_MODE_NONE),
("MESSAGE_ID", str(self.message.reference.message_id), PARSE_MODE_NONE)
("ICON", icon, PARSE_MODE_NONE),
("USER_ID", str(message.author.id), PARSE_MODE_NONE),
("MESSAGE_ID", str(self.message.reference.message_id), PARSE_MODE_NONE),
])

async def build_interaction(self):
if not self.message.interaction:
self.message.interaction = ""
return

user: Union[discord.Member, discord.User] = self.message.interaction.user
is_bot = _gather_user_bot(user)
user_colour = await self._gather_user_colour(user)
avatar_url = user.display_avatar if user.display_avatar else DiscordUtils.default_avatar
self.message.interaction = await fill_out(self.guild, message_interaction, [
("AVATAR_URL", str(avatar_url), PARSE_MODE_NONE),
("BOT_TAG", is_bot, PARSE_MODE_NONE),
("NAME_TAG", "%s#%s" % (user.name, user.discriminator), PARSE_MODE_NONE),
("NAME", str(html.escape(user.display_name))),
("USER_COLOUR", user_colour, PARSE_MODE_NONE),
("FILLER", "used ", PARSE_MODE_NONE),
("COMMAND", "/" + self.message.interaction.name, PARSE_MODE_NONE),
("USER_ID", str(user.id), PARSE_MODE_NONE),
("INTERACTION_ID", str(self.message.interaction.id), PARSE_MODE_NONE),
])

async def build_sticker(self):
Expand Down Expand Up @@ -223,7 +258,7 @@ async def build_message_template(self):

def _generate_message_divider_check(self):
return bool(
self.previous_message is None or self.message.reference != "" or
self.previous_message is None or self.message.reference != "" or self.message.interaction != "" or
self.previous_message.author.id != self.message.author.id or self.message.webhook_id is not None or
self.message.created_at > (self.previous_message.created_at + timedelta(minutes=4))
)
Expand All @@ -236,12 +271,12 @@ async def generate_message_divider(self, channel_audit=False):
if channel_audit:
return

reference_symbol = ""
followup_symbol = ""
is_bot = _gather_user_bot(self.message.author)
avatar_url = self.message.author.display_avatar if self.message.author.display_avatar else DiscordUtils.default_avatar

if self.message.reference != "":
reference_symbol = "<div class='chatlog__reference-symbol'></div>"
if self.message.reference != "" or self.message.interaction:
followup_symbol = "<div class='chatlog__followup-symbol'></div>"

time = self.message.created_at
if not self.message.created_at.tzinfo:
Expand All @@ -250,8 +285,9 @@ async def generate_message_divider(self, channel_audit=False):
default_timestamp = time.astimezone(timezone(self.pytz_timezone)).strftime("%d-%m-%Y %H:%M")

self.message_html += await fill_out(self.guild, start_message, [
("REFERENCE_SYMBOL", reference_symbol, PARSE_MODE_NONE),
("REFERENCE", self.message.reference, PARSE_MODE_NONE),
("REFERENCE_SYMBOL", followup_symbol, PARSE_MODE_NONE),
("REFERENCE", self.message.reference if self.message.reference else self.message.interaction,
PARSE_MODE_NONE),
("AVATAR_URL", str(avatar_url), PARSE_MODE_NONE),
("NAME_TAG", "%s#%s" % (self.message.author.name, self.message.author.discriminator), PARSE_MODE_NONE),
("USER_ID", str(self.message.author.id)),
Expand Down
15 changes: 13 additions & 2 deletions chat_exporter/construct/transcript.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def __init__(
pytz_timezone,
military_time: bool,
fancy_times: bool,
before: Optional[datetime.datetime],
after: Optional[datetime.datetime],
support_dev: bool,
bot: Optional[discord.Client],
):
Expand All @@ -38,6 +40,8 @@ def __init__(
self.limit = int(limit) if limit else None
self.military_time = military_time
self.fancy_times = fancy_times
self.before = before
self.after = after
self.support_dev = support_dev
self.pytz_timezone = pytz_timezone

Expand Down Expand Up @@ -127,6 +131,7 @@ async def export_transcript(self, message_html: str, meta_data: str):

self.html = await fill_out(self.channel.guild, total, [
("SERVER_NAME", f"{guild_name}"),
("GUILD_ID", str(self.channel.guild.id), PARSE_MODE_NONE),
("SERVER_AVATAR_URL", str(guild_icon), PARSE_MODE_NONE),
("CHANNEL_NAME", f"{self.channel.name}"),
("MESSAGE_COUNT", str(len(self.messages))),
Expand All @@ -146,8 +151,14 @@ async def export_transcript(self, message_html: str, meta_data: str):
class Transcript(TranscriptDAO):
async def export(self):
if not self.messages:
self.messages = [message async for message in self.channel.history(limit=self.limit)]
self.messages.reverse()
self.messages = [message async for message in self.channel.history(
limit=self.limit,
before=self.before,
after=self.after,
)]

if not self.after:
self.messages.reverse()

try:
return await super().build_transcript()
Expand Down
1 change: 1 addition & 0 deletions chat_exporter/ext/discord_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ class DiscordUtils:
file_attachment_unknown: str = 'https://cdn.jsdelivr.net/gh/mahtoid/DiscordUtils@master/discord-unknown.svg'
button_external_link: str = '<img class="chatlog__reference-icon" src="https://cdn.jsdelivr.net/gh/mahtoid/DiscordUtils@master/discord-external-link.svg">'
reference_attachment_icon: str = '<img class="chatlog__reference-icon" src="https://cdn.jsdelivr.net/gh/mahtoid/DiscordUtils@master/discord-attachment.svg">'
interaction_command_icon: str = '<img class="chatlog__interaction-icon" src="https://cdn.jsdelivr.net/gh/mahtoid/DiscordUtils@master/discord-command.svg">'
interaction_dropdown_icon: str = '<img class="chatlog__dropdown-icon" src="https://cdn.jsdelivr.net/gh/mahtoid/DiscordUtils@master/discord-dropdown.svg">'
2 changes: 2 additions & 0 deletions chat_exporter/ext/html_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ def read_file(filename):
# MESSAGES
start_message = read_file(dir_path + "/html/message/start.html")
bot_tag = read_file(dir_path + "/html/message/bot-tag.html")
bot_tag_verified = read_file(dir_path + "/html/message/bot-tag-verified.html")
message_content = read_file(dir_path + "/html/message/content.html")
message_reference = read_file(dir_path + "/html/message/reference.html")
message_interaction = read_file(dir_path + "/html/message/interaction.html")
message_pin = read_file(dir_path + "/html/message/pin.html")
message_thread = read_file(dir_path + "/html/message/thread.html")
message_reference_unknown = read_file(dir_path + "/html/message/reference_unknown.html")
Expand Down
Loading

0 comments on commit ba6b640

Please sign in to comment.