Skip to content

Commit

Permalink
feat(autotranslate): add channel linking, to send translations into a…
Browse files Browse the repository at this point in the history
… different channel

Warning: There is currently no way to disable or delete a link, unless you contact the server owner!
  • Loading branch information
Pukimaa committed Oct 1, 2023
1 parent 6051be8 commit c08cec3
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 3 deletions.
211 changes: 209 additions & 2 deletions cogs/language/autotranslate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import io
import os
import i18n
import json
import discord
from main import TakoBot
from ftlangdetect import detect
Expand Down Expand Up @@ -100,8 +101,214 @@ async def delete_original(self, interaction: discord.Interaction, value: bool):
ephemeral=True,
)

@commands.Cog.listener()
async def on_message(self, message: discord.Message):
# TODO: Add descriptions to command and arguments
@app_commands.command()
@app_commands.guild_only()
async def link(
self,
interaction: discord.Interaction,
source_channel: discord.TextChannel | discord.Thread,
target_channel: discord.TextChannel | discord.Thread,
source_lang: str = "auto",
target_lang: str | None = None,
):
if source_lang == target_lang:
return await interaction.response.send_message(
i18n.t(
"errors.auto_translate_same_lang",
locale=get_language(self.bot, interaction.guild_id),
),
ephemeral=True,
)
if source_channel == target_channel:
return await interaction.response.send_message(
i18n.t(
"errors.auto_translate_same_channel",
locale=get_language(self.bot, interaction.guild_id),
),
ephemeral=True,
)
data = await self.bot.db_pool.fetchval(
"SELECT autotranslate_link FROM channels WHERE channel_id = $1",
source_channel.id,
)
if not data:
data = []
link_data = {
"target_channel": target_channel.id,
"source_lang": source_lang,
"target_lang": target_lang,
}
if link_data in data:
return await interaction.response.send_message(
i18n.t(
"errors.auto_translate_link_exists",
locale=get_language(self.bot, interaction.guild_id),
),
ephemeral=True,
)
data.append(json.dumps(link_data))
await self.bot.db_pool.execute(
"INSERT INTO channels (channel_id, autotranslate_link) VALUES ($1, $2) ON CONFLICT(channel_id) DO UPDATE SET autotranslate_link = $2",
source_channel.id,
data,
)
await interaction.response.send_message(
i18n.t(
"misc.auto_translate_linked",
locale=get_language(self.bot, interaction.guild_id),
source_channel=source_channel.mention,
source_lang=source_lang,
target_channel=target_channel.mention,
target_lang=target_lang,
),
ephemeral=True,
)

# TODO: Add command to delete links

@commands.Cog.listener(name="on_message")
async def on_message_link(self, message: discord.Message):
try:
fetched_val = await self.bot.db_pool.fetchval(
"SELECT autotranslate_link FROM channels WHERE channel_id = $1",
message.channel.id,
)
except AttributeError:
return
if not fetched_val:
return
for autotranslate_link in fetched_val:
if (
not message.content
or not autotranslate_link
or message.author.id == self.bot.user.id # type: ignore
or message.webhook_id
or not message.guild
):
continue

data = json.loads(autotranslate_link)
source_lang = data["source_lang"]
target_lang = data["target_lang"]
target_channel: discord.abc.GuildChannel | discord.Thread = self.bot.get_channel(data["target_channel"]) # type: ignore
if target_channel == discord.abc.PrivateChannel:
continue

attachments: list[dict] = []
if message.attachments:
for attachment in message.attachments:
bytes = await attachment.read()
attachments.append(
{
"bytes": bytes,
"spoiler": attachment.is_spoiler(),
"filename": attachment.filename,
"description": attachment.description,
}
)
size = 0
boost_level = message.guild.premium_tier if hasattr(message, "guild") else 0
size_limit = 8000000
match boost_level:
case 2:
size_limit = 50000000
case 3:
size_limit = 100000000
new_attachments = []
attachment_removed = False
for attachment in attachments:
file_size = len(attachment["bytes"])
size += file_size
if size > size_limit:
size -= file_size
attachment_removed = True
continue
attachment_bytes = io.BytesIO(attachment["bytes"])
new_attachments.append(
discord.File(
attachment_bytes,
spoiler=attachment["spoiler"],
filename=attachment["filename"],
description=attachment["description"],
)
)
attachments = new_attachments
too_large_embed, too_large_file = error_embed(
self.bot,
i18n.t("errors.too_large_title", locale=source_lang),
i18n.t("errors.too_large", locale=source_lang),
message.guild.id,
style="warning",
)

data = await detect(
message.content.replace("\n", " "),
path=os.path.join(os.getcwd(), "assets/lid.176.bin"),
)
data["score"] = data["score"] * 100
confidence = await self.bot.db_pool.fetchval(
"SELECT auto_translate_confidence FROM guilds WHERE guild_id = $1",
message.guild.id,
)
if not confidence:
confidence = 75
if confidence >= data["score"]:
return
if data["lang"] != source_lang:
return

webhook_id = None
if (
target_channel.type == discord.ChannelType.public_thread
or target_channel.type == discord.ChannelType.private_thread
):
for webhook in await target_channel.parent.webhooks(): # type: ignore
if webhook.name == f"AutoTranslate ({self.bot.user.id})": # type: ignore
webhook_id = webhook.id
else:
for webhook in await target_channel.webhooks(): # type: ignore
if webhook.name == f"AutoTranslate ({self.bot.user.id})": # type: ignore
webhook_id = webhook.id
if not webhook_id:
if (
target_channel.type == discord.ChannelType.public_thread
or target_channel.type == discord.ChannelType.private_thread
):
webhook = await target_channel.parent.create_webhook(name=f"AutoTranslate ({self.bot.user.id})") # type: ignore
else:
webhook = await target_channel.create_webhook(name=f"AutoTranslate ({self.bot.user.id})") # type: ignore
else:
webhook = await self.bot.fetch_webhook(webhook_id)

translation = await translate(message.content, target_lang, source_lang)
try:
await webhook.send(
username=f"{message.author.display_name} ({translation[1]}{target_lang})",
avatar_url=message.author.display_avatar.url,
files=attachments, # type: ignore
thread=target_channel if isinstance(target_channel, discord.Thread) else discord.utils.MISSING, # type: ignore
content=translation[0],
)
except:
continue

if attachment_removed:
await message.channel.send(
message.author.mention,
embed=too_large_embed,
file=too_large_file,
allowed_mentions=discord.AllowedMentions(
everyone=False,
users=[message.author],
roles=False,
replied_user=False,
),
)
continue

@commands.Cog.listener(name="on_message")
async def on_message_autotranslate(self, message: discord.Message):
if not message.guild:
return
try:
Expand Down
3 changes: 3 additions & 0 deletions i18n/errors/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ en:
not_locked: "%{channel} is currently not locked!"
api_error_title: "API Error"
api_error: "An error occured while trying to communicate with the API we are using.\n\nPlease try again later or visit [our support server](https://discord.gg/dfmXNTmzyp) with the following information:\n`%{error}`"
auto_translate_same_lang: "The source and target language is the same. Please choose different languages!"
auto_translate_same_channel: "The source and target channel is the same. Please choose different channels!"
auto_translate_link_exists: "There is already a translation link between these channels!"
1 change: 1 addition & 0 deletions i18n/misc/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ en:
auto_translate_confidence_set: "Confidence Threshold is now set to %{value}%"
auto_translate_reply_style_set: "Autotranslate reply style is now set to %{style}"
auto_translate_delete_original: "Deletion of the original message is now set to %{value}"
auto_translate_linked: "Succesfully linked channels. Messages from %{source_channel} (in language `%{source_lang}`) will now be translated to %{target_channel} (in language `${target_lang}`)."
topic_title: "Here's your topic:"
topic_footer: "Topic ID: %{id}"
topic_invalid_title: "We searched far and wide. Unfortunately, no topics were found."
Expand Down
7 changes: 7 additions & 0 deletions migrations/V4__autotranslate_channel_linking.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- Revises: V4
-- Creation Date: 2023-10-01 12:59:52.869202 UTC
-- Reason: Autotranslate Channel Linking
ALTER TABLE
channels
ADD
COLUMN IF NOT EXISTS autotranslate_link TEXT [];
2 changes: 1 addition & 1 deletion utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def delete_thumbnail(id: int, icon: str):
os.remove(f"assets/thumbnails/{icon}_{id}.png")


def get_language(bot, guild_id: int | None = None, new: bool = False):
def get_language(bot, guild_id: int | None = None):
""":class:`str`: Get the language of a guild.
Parameters
Expand Down

0 comments on commit c08cec3

Please sign in to comment.