rewrite: Various bug fixes.

This commit is contained in:
2023-05-25 16:45:54 +03:00
parent 0863d13088
commit fe8cf35885
11 changed files with 237 additions and 21 deletions

View File

@@ -11,7 +11,7 @@ from discord.enums import Locale
logger = logging.getLogger(__name__)
SOURCE_LOCALE = 'en_uk'
SOURCE_LOCALE = 'en-GB'
ctx_locale: ContextVar[str] = ContextVar('locale', default=SOURCE_LOCALE)
ctx_translator: ContextVar['LeoBabel'] = ContextVar('translator', default=None) # type: ignore

View File

@@ -0,0 +1,5 @@
from .cog import ParaCog
async def setup(bot):
await bot.add_cog(ParaCog(bot))

215
src/modules/paradox/cog.py Normal file
View File

@@ -0,0 +1,215 @@
from typing import Optional
import asyncio
from io import BytesIO
from PIL import Image
import discord
from discord.ext import commands as cmds
from discord import app_commands as appcmds
from discord.ui.button import button
from utils.lib import error_embed
from utils.ui import LeoUI
from meta import LionCog, LionBot, LionContext
emoji_rotate_cw = "↩️"
emoji_rotate_ccw = "↪️"
emoji_close = ""
class ParaCog(LionCog):
def __init__(self, bot: LionBot):
self.bot = bot
@cmds.hybrid_command(
name="quote",
description="Quote a previous message by id from this or another channel."
)
@appcmds.describe(
message_id="Message id of the message you want to quote."
)
async def quote_cmd(self, ctx: LionContext, message_id: str):
message_id = message_id.strip()
if not message_id or not message_id.isdigit():
await ctx.error_reply("Please provide a valid message id.")
msgid = int(message_id)
if ctx.interaction:
await ctx.interaction.response.defer(thinking=True)
# Look in the current channel
message = None
try:
message = await ctx.channel.fetch_message(msgid)
except discord.HTTPException:
pass
if message is None:
# Search for the message in other channels
channels = [channel for channel in ctx.guild.text_channels if channel.id != ctx.channel.id]
message = await self.message_seeker(msgid, channels)
if message is None:
# We couldn't find the message in any of the channels the user could see.
embed = discord.Embed(
title="Message not found!",
colour=discord.Colour.red(),
description=f"Could not find a message in this server with the id `{msgid}`"
)
else:
content = message.content
header = f"[Click to jump to message]({message.jump_url})"
content = (
'\n'.join(f"> {line}" for line in message.content.splitlines()) + '\n' + header
)
embed = discord.Embed(
description=content,
colour=discord.Colour.light_grey(),
timestamp=message.created_at
)
embed.set_author(name=message.author.name, icon_url=message.author.avatar.url)
embed.set_footer(text=f"Sent in #{message.channel.name}")
await ctx.interaction.edit_original_response(embed=embed)
async def message_seeker(self, msgid: int, channels: list[discord.TextChannel]):
tasks = []
for channel in channels:
task = asyncio.create_task(self.channel_message_seeker(channel, msgid))
tasks.append(task)
for coro in asyncio.as_completed(tasks):
result = await coro
if result is None:
continue
else:
for task in tasks:
task.cancel()
return result
return None
async def channel_message_seeker(self, channel, msgid):
try:
message = await channel.fetch_message(msgid)
except discord.HTTPException:
return None
else:
return message
@cmds.hybrid_command(
name='rotate',
description="Rotate an image sent in the last 10 messages."
)
@appcmds.describe(
angle="Angle to rotate in degrees anticlockwise."
)
async def rotate_cmd(self, ctx: LionContext, angle: Optional[int] = 90):
await ctx.interaction.response.defer(thinking=True)
image_url = None
async for message in ctx.channel.history(limit=10):
if (
message.attachments and
message.attachments[-1].content_type.startswith('image')
):
image_url = message.attachments[-1].proxy_url
break
for embed in reversed(message.embeds):
if embed.type == 'image':
image_url = embed.url
break
elif embed.type == 'rich':
if embed.image:
image_url = embed.image.proxy_url
break
if image_url is None:
await ctx.interaction.edit_original_response(
embed=error_embed("Could not find an image in the last 10 images.")
)
else:
# We have an image, now rotate it.
async with ctx.bot.web_client.get(image_url) as r:
if r.status == 200:
response = await r.read()
else:
return await ctx.interaction.edit_original_response(
embed=error_embed("Retrieving the previous image failed.")
)
with Image.open(BytesIO(response)) as im:
ui = RotateUI(im, str(ctx.author.id))
await ui.run(ctx.interaction, angle)
class RotateUI(LeoUI):
def __init__(self, image, name):
super().__init__()
self.original = image
self.filename = name
self._out_message: Optional[discord.Message] = None
self._rotated: Optional[Image] = None
self._interaction: Optional[discord.Interaction] = None
self._angle = 0
@button(emoji=emoji_rotate_ccw)
async def press_ccw(self, interaction, press):
await interaction.response.defer()
self._angle += 90
await self.update()
@button(emoji=emoji_close)
async def press_close(self, interaction, press):
await interaction.response.defer()
await self._interaction.delete_original_response()
await self.close()
@button(emoji=emoji_rotate_cw)
async def press_cw(self, interaction, press):
await interaction.response.defer()
self._angle -= 90
await self.update()
async def cleanup(self):
if self.original:
self.original.close()
async def run(self, interaction, angle: int):
self._angle = angle
self._interaction = interaction
await self.update()
await self.wait()
async def update(self):
with self._rotate() as rotated:
with BytesIO() as output:
self.save_into(rotated, output)
await self._interaction.edit_original_response(
attachments=[discord.File(output, filename=f"{self.filename}.jpg")],
view=self
)
def save_into(self, rotated, output):
exif = self.original.info.get('exif', None)
if exif:
rotated.convert('RGB').save(output, exif=exif, format="JPEG", quality=85, optimize=True)
else:
rotated.convert("RGB").save(output, format="JPEG", quality=85, optimize=True)
output.seek(0)
def _rotate(self):
"""
Rotate original image by the provided amount.
"""
im = self.original
with im.rotate(self._angle, expand=1) as rotated:
bbox = rotated.getbbox()
return rotated.crop(bbox)

View File

@@ -503,7 +503,7 @@ class TimerCog(LionCog):
if ctx.guild.me.guild_permissions.manage_channels:
try:
channel = await ctx.guild.create_voice_channel(
name="Timer",
name=name or "Timer",
reason="Creating Pomodoro Voice Channel",
category=ctx.channel.category
)

View File

@@ -49,7 +49,7 @@ class RankEditor(FastModal):
def role_colour_setup(self):
self.role_colour.label = self.bot.translator.t(_p(
'ui:rank_editor|input:role_volour|label',
'ui:rank_editor|input:role_colour|label',
"Role Colour"
))
self.role_colour.placeholder = self.bot.translator.t(_p(
@@ -198,19 +198,15 @@ class RankEditor(FastModal):
))
self.message.placeholder = t(_p(
'ui:rank_editor|input:message|placeholder',
(
"Congratulatory message sent to the user upon achieving this rank."
)
"Congratulatory message sent to the user upon achieving this rank."
))
if self.rank_type is RankType.VOICE:
# TRANSLATOR NOTE: Don't change the keys here, they will be automatically replaced by the localised key
msg_default = t(_p(
'ui:rank_editor|input:message|default|type:voice',
(
"Congratulations {user_mention}!\n"
"For working hard for **{requires}**, you have achieved the rank of "
"**{role_name}** in **{guild_name}**! Keep up the good work."
)
"Congratulations {user_mention}!\n"
"For working hard for **{requires}**, you have achieved the rank of "
"**{role_name}** in **{guild_name}**! Keep up the good work."
))
elif self.rank_type is RankType.XP:
# TRANSLATOR NOTE: Don't change the keys here, they will be automatically replaced by the localised key

View File

@@ -216,7 +216,8 @@ class RoomCog(LionCog):
# TODO: Consider extending invites to members rather than giving them immediate access
# Potential for abuse in moderation-free channel a member can add anyone too
everyone_overwrite = discord.PermissionOverwrite(
view_channel=lguild.config.get(RoomSettings.Visible.setting_id).value
view_channel=lguild.config.get(RoomSettings.Visible.setting_id).value,
connect=False
)
# Build permission overwrites for owner and members, take into account visible setting

View File

@@ -103,7 +103,7 @@ class RoomUI(MessageUI):
# Input checking
response = response.strip()
if not response.isdigit():
if not response.isdigit() or (amount := int(response)) == 0:
await submit.response.send_message(
embed=error_embed(
t(_p(
@@ -113,7 +113,6 @@ class RoomUI(MessageUI):
), ephemeral=True
)
return
amount = int(response)
await submit.response.defer(thinking=True, ephemeral=True)
# Start transaction for deposit

View File

@@ -69,7 +69,7 @@ async def get_goals_card(
# Set and compute correct middle goal column
if mode in (CardMode.VOICE, CardMode.STUDY):
model = data.VoiceSessionStats
middle_completed = (await model.study_times_between(guildid or None, userid, start, end))[0]
middle_completed = int((await model.study_times_between(guildid or None, userid, start, end))[0] // 3600)
middle_goal = goals['study_goal']
elif mode is CardMode.TEXT:
model = TextTrackerData.TextSessions

View File

@@ -191,8 +191,8 @@ class TasklistCog(LionCog):
appcmds.Choice(
name=t(_p(
'argtype:taskid|error:no_matching',
"No tasks matching {partial}!",
)).format(partial=partial),
"No tasks matching '{partial}'!",
)).format(partial=partial[:100]),
value=partial
)
]
@@ -201,7 +201,7 @@ class TasklistCog(LionCog):
appcmds.Choice(name=task_string, value=label)
for label, task_string in matching
]
return options[:25]
return options[:25]
async def is_tasklist_channel(self, channel) -> bool:
if not channel.guild:

View File

@@ -1,9 +1,9 @@
async def setup(bot):
from .test import TestCog
# from .test import TestCog
# from .data import test_data
# bot.db.load_registry(test_data)
await bot.add_cog(TestCog(bot))
# await bot.add_cog(TestCog(bot))
pass

View File

@@ -590,7 +590,7 @@ class VoiceTrackerCog(LionCog):
VoiceSession._sessions_.pop(guild.id, None)
now = utc_now()
to_close = [] # (guildid, userid, _at)
for session in sessions.vallues():
for session in sessions.values():
if session.start_task is not None:
session.start_task.cancel()
if session.expiry_task is not None: