Compare commits

..

No commits in common. "393961410e65663bd7afef8e7d78c5ddd13c5fc6" and "186eda49344742682909302775474630f937b0d8" have entirely different histories.

12 changed files with 60 additions and 160 deletions

View File

@ -38,9 +38,9 @@ def range_type(string, min=0, max=100):
try:
value = int(string)
except ValueError:
raise argparse.ArgumentTypeError("value is not a valid integer")
raise argparse.ArgumentTypeError(f"value not a valid integer")
if min <= value <= max:
return value
else:
raise argparse.ArgumentTypeError(f"value is not in range {min}-{max}")
raise argparse.ArgumentTypeError(f"value not in range {min}-{max}")

View File

@ -1,16 +1,5 @@
from . import bot, tools, utils, voice
from .utils import Command, match, match_token, tokenize
__all__ = [
"bot",
"tools",
"utils",
"voice",
"Command",
"match",
"match_token",
"tokenize",
]
from .utils import *
def __reload_module__():

View File

@ -1,6 +1,7 @@
import re
import arguments
import commands
import utils
@ -66,7 +67,7 @@ async def clear(message):
if args.delete_command:
try:
await message.delete()
except Exception:
except:
pass
regex = None
@ -100,5 +101,5 @@ async def clear(message):
message,
f"purged **{messages}/{args.count} {'message' if args.count == 1 else 'messages'}**",
)
except Exception:
except:
pass

View File

@ -11,7 +11,7 @@ import youtubedl
from state import client, players
async def queue_or_play(message, edited=False):
async def queue_or_play(message):
await ensure_joined(message)
if not command_allowed(message):
return
@ -73,15 +73,6 @@ async def queue_or_play(message, edited=False):
if not (args := await parser.parse_args(message, tokens)):
return
if edited:
found = None
for queued in players[message.guild.id].queue:
if queued.trigger_message.id == message.id:
found = queued
break
if found:
players[message.guild.id].queue.remove(found)
if args.clear:
players[message.guild.id].queue.clear()
await utils.add_check_reaction(message)
@ -126,11 +117,10 @@ async def queue_or_play(message, edited=False):
)
)
>= 5
and not len(message.guild.voice_client.channel.members) == 2
):
await utils.reply(
message,
"you can only queue **5 items** without the manage channels permission!",
"you can only queue **5 songs** without the manage channels permission!",
)
return
@ -181,6 +171,7 @@ async def queue_or_play(message, edited=False):
def embed(description):
e = disnake.Embed(
title="Queued",
description=description,
color=constants.EMBED_COLOR,
)
@ -256,7 +247,6 @@ async def join(message):
return await message.guild.voice_client.move_to(message.channel)
await message.channel.connect()
await utils.add_check_reaction(message)
async def leave(message):
@ -264,7 +254,6 @@ async def leave(message):
return
await message.guild.voice_client.disconnect()
await utils.add_check_reaction(message)
async def resume(message):
@ -299,6 +288,9 @@ async def volume(message):
if not command_allowed(message):
return
if not message.guild.voice_client:
return
tokens = commands.tokenize(message.content)
parser = arguments.ArgumentParser(tokens[0], "set the current volume level")
parser.add_argument(
@ -311,7 +303,10 @@ async def volume(message):
return
if not message.guild.voice_client.source:
await utils.reply(message, "nothing is playing!")
await utils.reply(
message,
f"nothing is playing!",
)
return
if args.volume is None:
@ -324,17 +319,6 @@ async def volume(message):
await utils.add_check_reaction(message)
def delete_queued(messages):
found = []
for message in messages:
for queued in players[message.guild.id].queue:
if queued.trigger_message.id == message.id:
found.append(queued)
for queued in found:
if queued in players[messages[0].guild.id].queue:
players[messages[0].guild.id].queue.remove(queued)
def play_after_callback(e, message, once):
if e:
print(f"player error: {e}")
@ -352,11 +336,11 @@ def play_next(message, once=False):
)
except Exception as e:
client.loop.create_task(
utils.channel_send(message, f"error while trying to play: `{e}`")
message.channel.send(f"error while trying to play: `{e}`")
)
return
client.loop.create_task(
utils.channel_send(message, f"**0.** {queued.format(show_queuer=True)}")
message.channel.send(f"**0.** {queued.format(show_queuer=True)}")
)

View File

@ -13,7 +13,6 @@ RELOADABLE_MODULES = [
"constants",
"core",
"events",
"tasks",
"utils",
"voice",
"youtubedl",

27
core.py
View File

@ -4,20 +4,18 @@ import importlib
import inspect
import io
import textwrap
import time
import traceback
import disnake
import disnake_paginator
import commands
import constants
import core
import utils
from state import client, command_locks, idle_tracker
from state import client, command_locks, executed_messages
async def on_message(message, edited=False):
async def on_message(message):
if not message.content.startswith(constants.PREFIX) or message.author.bot:
return
@ -28,11 +26,6 @@ async def on_message(message, edited=False):
if not matched:
return
idle_tracker["last_used"] = time.time()
if idle_tracker["is_idle"]:
idle_tracker["is_idle"] = False
await client.change_presence(status=disnake.Status.online)
if len(matched) > 1:
await utils.reply(
message,
@ -88,7 +81,7 @@ async def on_message(message, edited=False):
if len(output) > 2000:
output = output.replace("`", "\\`")
await disnake_paginator.ButtonPaginator(
prefix="```\n",
prefix=f"```\n",
suffix="```",
invalid_user_function=utils.invalid_user_handler,
color=constants.EMBED_COLOR,
@ -99,7 +92,11 @@ async def on_message(message, edited=False):
elif len(output.strip()) == 0:
await utils.add_check_reaction(message)
else:
await utils.channel_send(message, output)
if message.id in executed_messages:
await executed_messages[message.id].edit(output)
else:
response = await message.channel.send(output)
executed_messages[message.id] = response
case C.CLEAR | C.PURGE if message.author.id in constants.OWNERS:
await commands.tools.clear(message)
case C.JOIN:
@ -108,7 +105,7 @@ async def on_message(message, edited=False):
await commands.voice.leave(message)
case C.QUEUE | C.PLAY:
async with command_locks[message.guild.id]:
await commands.voice.queue_or_play(message, edited)
await commands.voice.queue_or_play(message)
case C.SKIP:
async with command_locks[message.guild.id]:
await commands.voice.skip(message)
@ -132,9 +129,9 @@ async def on_message(message, edited=False):
async def on_voice_state_update(_, before, after):
def is_empty(channel):
return [m.id for m in (channel.members if channel else [])] == [client.user.id]
is_empty = lambda channel: [m.id for m in (channel.members if channel else [])] == [
client.user.id
]
c = None
if is_empty(before.channel):
c = before.channel

View File

@ -1,52 +1,47 @@
import asyncio
import threading
import commands
import core
import tasks
import events
from state import client
dynamic_handlers = {}
async def on_ready():
threading.Thread(
name="cleanup",
target=asyncio.run_coroutine_threadsafe,
args=(
tasks.cleanup(),
client.loop,
),
).start()
async def trigger_dynamic_handlers(event_type: str, *data):
if event_type in dynamic_handlers:
for dynamic_handler in dynamic_handlers[event_type]:
try:
await dynamic_handler(*data)
except Exception as e:
print(
f"error in dynamic event handler {dynamic_handler} for {event_type}: {e}"
)
async def on_message(message):
await events.trigger_dynamic_handlers("on_message", message)
await core.on_message(message)
async def on_message_edit(before, after):
await events.trigger_dynamic_handlers("on_message_edit", before, after)
if before.content == after.content:
return
await core.on_message(after, edited=True)
async def on_message_delete(message):
commands.voice.delete_queued([message])
async def on_bulk_message_delete(messages):
commands.voice.delete_queued(messages)
await core.on_message(after)
async def on_voice_state_update(member, before, after):
await events.trigger_dynamic_handlers(
"on_voice_state_update", member, before, after
)
await core.on_voice_state_update(member, before, after)
for k, v in client.get_listeners().items():
for f in v:
client.remove_listener(f, k)
client.add_listener(on_bulk_message_delete, "on_bulk_message_delete")
client.add_listener(on_message, "on_message")
client.add_listener(on_message_delete, "on_message_delete")
client.add_listener(on_message_edit, "on_message_edit")
client.add_listener(on_voice_state_update, "on_voice_state_update")

View File

@ -7,9 +7,8 @@ from state import client, start_time
@client.event
async def on_ready():
await events.trigger_dynamic_handlers("on_ready")
print(f"logged in as {client.user} in {round(time.time() - start_time, 1)}s")
await events.on_ready()
client.run(constants.SECRETS["TOKEN"])

View File

@ -1,32 +1,14 @@
import collections
import time
import disnake
class LimitedSizeDict(collections.OrderedDict):
def __init__(self, *args, **kwds):
self.size_limit = kwds.pop("size_limit", 1000)
super().__init__(*args, **kwds)
self._check_size_limit()
def __setitem__(self, key, value):
super().__setitem__(key, value)
self._check_size_limit()
def _check_size_limit(self):
if self.size_limit is not None:
while len(self) > self.size_limit:
self.popitem(last=False)
command_locks = {}
executed_messages = {}
players = {}
intents = disnake.Intents.default()
intents.message_content = True
intents.members = True
client = disnake.Client(intents=intents)
command_locks = LimitedSizeDict()
idle_tracker = {"is_idle": False, "last_used": time.time()}
message_responses = LimitedSizeDict()
players = {}
start_time = time.time()

View File

@ -1,25 +0,0 @@
import asyncio
import time
import disnake
from state import client, idle_tracker, players
async def cleanup():
while True:
await asyncio.sleep(3600)
targets = []
for id, player in players:
if len(player.queue) == 0:
targets.append(id)
for target in targets:
del players[target]
if (
not idle_tracker["is_idle"]
and time.time() - idle_tracker["last_used"] >= 3600
):
await client.change_presence(status=disnake.Status.idle)
idle_tracker["is_idle"] = True

View File

@ -1,13 +1,10 @@
import disnake
import constants
from state import message_responses
def format_duration(duration: int):
def format_plural(noun, count):
return noun if count == 1 else noun + "s"
format_plural = lambda noun, count: noun if count == 1 else noun + "s"
segments = []
weeks, duration = divmod(duration, 604800)
@ -37,27 +34,9 @@ async def add_check_reaction(message):
async def reply(message, *args, **kwargs):
if message.id in message_responses:
await message_responses[message.id].edit(
*args, **kwargs, allowed_mentions=disnake.AllowedMentions.none()
)
else:
response = await message.reply(
*args, **kwargs, allowed_mentions=disnake.AllowedMentions.none()
)
message_responses[message.id] = response
async def channel_send(message, *args, **kwargs):
if message.id in message_responses:
await message_responses[message.id].edit(
*args, **kwargs, allowed_mentions=disnake.AllowedMentions.none()
)
else:
response = await message.channel.send(
*args, **kwargs, allowed_mentions=disnake.AllowedMentions.none()
)
message_responses[message.id] = response
await message.reply(
*args, **kwargs, allowed_mentions=disnake.AllowedMentions.none()
)
async def invalid_user_handler(interaction):

View File

@ -68,7 +68,7 @@ class QueuedSong:
)
else:
return (
f"[`{self.player.title}`]({'<' if hide_preview else ''}{self.player.original_url}{'>' if hide_preview else ''}) **[{self.format_duration(self.player.duration) if self.player.duration else 'live'}]**"
f"[`{self.player.title}`]({'<' if hide_preview else ''}{self.player.original_url}{'>' if hide_preview else ''}) [{self.format_duration(self.player.duration) if self.player.duration else 'live'}]"
+ (f" (<@{self.trigger_message.author.id}>)" if show_queuer else "")
)