Compare commits
No commits in common. "393961410e65663bd7afef8e7d78c5ddd13c5fc6" and "186eda49344742682909302775474630f937b0d8" have entirely different histories.
393961410e
...
186eda4934
@ -38,9 +38,9 @@ def range_type(string, min=0, max=100):
|
|||||||
try:
|
try:
|
||||||
value = int(string)
|
value = int(string)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise argparse.ArgumentTypeError("value is not a valid integer")
|
raise argparse.ArgumentTypeError(f"value not a valid integer")
|
||||||
|
|
||||||
if min <= value <= max:
|
if min <= value <= max:
|
||||||
return value
|
return value
|
||||||
else:
|
else:
|
||||||
raise argparse.ArgumentTypeError(f"value is not in range {min}-{max}")
|
raise argparse.ArgumentTypeError(f"value not in range {min}-{max}")
|
||||||
|
@ -1,16 +1,5 @@
|
|||||||
from . import bot, tools, utils, voice
|
from . import bot, tools, utils, voice
|
||||||
from .utils import Command, match, match_token, tokenize
|
from .utils import *
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
"bot",
|
|
||||||
"tools",
|
|
||||||
"utils",
|
|
||||||
"voice",
|
|
||||||
"Command",
|
|
||||||
"match",
|
|
||||||
"match_token",
|
|
||||||
"tokenize",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def __reload_module__():
|
def __reload_module__():
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
import arguments
|
import arguments
|
||||||
|
|
||||||
import commands
|
import commands
|
||||||
import utils
|
import utils
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ async def clear(message):
|
|||||||
if args.delete_command:
|
if args.delete_command:
|
||||||
try:
|
try:
|
||||||
await message.delete()
|
await message.delete()
|
||||||
except Exception:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
regex = None
|
regex = None
|
||||||
@ -100,5 +101,5 @@ async def clear(message):
|
|||||||
message,
|
message,
|
||||||
f"purged **{messages}/{args.count} {'message' if args.count == 1 else 'messages'}**",
|
f"purged **{messages}/{args.count} {'message' if args.count == 1 else 'messages'}**",
|
||||||
)
|
)
|
||||||
except Exception:
|
except:
|
||||||
pass
|
pass
|
||||||
|
@ -11,7 +11,7 @@ import youtubedl
|
|||||||
from state import client, players
|
from state import client, players
|
||||||
|
|
||||||
|
|
||||||
async def queue_or_play(message, edited=False):
|
async def queue_or_play(message):
|
||||||
await ensure_joined(message)
|
await ensure_joined(message)
|
||||||
if not command_allowed(message):
|
if not command_allowed(message):
|
||||||
return
|
return
|
||||||
@ -73,15 +73,6 @@ async def queue_or_play(message, edited=False):
|
|||||||
if not (args := await parser.parse_args(message, tokens)):
|
if not (args := await parser.parse_args(message, tokens)):
|
||||||
return
|
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:
|
if args.clear:
|
||||||
players[message.guild.id].queue.clear()
|
players[message.guild.id].queue.clear()
|
||||||
await utils.add_check_reaction(message)
|
await utils.add_check_reaction(message)
|
||||||
@ -126,11 +117,10 @@ async def queue_or_play(message, edited=False):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
>= 5
|
>= 5
|
||||||
and not len(message.guild.voice_client.channel.members) == 2
|
|
||||||
):
|
):
|
||||||
await utils.reply(
|
await utils.reply(
|
||||||
message,
|
message,
|
||||||
"you can only queue **5 items** without the manage channels permission!",
|
"you can only queue **5 songs** without the manage channels permission!",
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -181,6 +171,7 @@ async def queue_or_play(message, edited=False):
|
|||||||
|
|
||||||
def embed(description):
|
def embed(description):
|
||||||
e = disnake.Embed(
|
e = disnake.Embed(
|
||||||
|
title="Queued",
|
||||||
description=description,
|
description=description,
|
||||||
color=constants.EMBED_COLOR,
|
color=constants.EMBED_COLOR,
|
||||||
)
|
)
|
||||||
@ -256,7 +247,6 @@ async def join(message):
|
|||||||
return await message.guild.voice_client.move_to(message.channel)
|
return await message.guild.voice_client.move_to(message.channel)
|
||||||
|
|
||||||
await message.channel.connect()
|
await message.channel.connect()
|
||||||
await utils.add_check_reaction(message)
|
|
||||||
|
|
||||||
|
|
||||||
async def leave(message):
|
async def leave(message):
|
||||||
@ -264,7 +254,6 @@ async def leave(message):
|
|||||||
return
|
return
|
||||||
|
|
||||||
await message.guild.voice_client.disconnect()
|
await message.guild.voice_client.disconnect()
|
||||||
await utils.add_check_reaction(message)
|
|
||||||
|
|
||||||
|
|
||||||
async def resume(message):
|
async def resume(message):
|
||||||
@ -299,6 +288,9 @@ async def volume(message):
|
|||||||
if not command_allowed(message):
|
if not command_allowed(message):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if not message.guild.voice_client:
|
||||||
|
return
|
||||||
|
|
||||||
tokens = commands.tokenize(message.content)
|
tokens = commands.tokenize(message.content)
|
||||||
parser = arguments.ArgumentParser(tokens[0], "set the current volume level")
|
parser = arguments.ArgumentParser(tokens[0], "set the current volume level")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -311,7 +303,10 @@ async def volume(message):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not message.guild.voice_client.source:
|
if not message.guild.voice_client.source:
|
||||||
await utils.reply(message, "nothing is playing!")
|
await utils.reply(
|
||||||
|
message,
|
||||||
|
f"nothing is playing!",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if args.volume is None:
|
if args.volume is None:
|
||||||
@ -324,17 +319,6 @@ async def volume(message):
|
|||||||
await utils.add_check_reaction(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):
|
def play_after_callback(e, message, once):
|
||||||
if e:
|
if e:
|
||||||
print(f"player error: {e}")
|
print(f"player error: {e}")
|
||||||
@ -352,11 +336,11 @@ def play_next(message, once=False):
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
client.loop.create_task(
|
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
|
return
|
||||||
client.loop.create_task(
|
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)}")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ RELOADABLE_MODULES = [
|
|||||||
"constants",
|
"constants",
|
||||||
"core",
|
"core",
|
||||||
"events",
|
"events",
|
||||||
"tasks",
|
|
||||||
"utils",
|
"utils",
|
||||||
"voice",
|
"voice",
|
||||||
"youtubedl",
|
"youtubedl",
|
||||||
|
27
core.py
27
core.py
@ -4,20 +4,18 @@ import importlib
|
|||||||
import inspect
|
import inspect
|
||||||
import io
|
import io
|
||||||
import textwrap
|
import textwrap
|
||||||
import time
|
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import disnake
|
|
||||||
import disnake_paginator
|
import disnake_paginator
|
||||||
|
|
||||||
import commands
|
import commands
|
||||||
import constants
|
import constants
|
||||||
import core
|
import core
|
||||||
import utils
|
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:
|
if not message.content.startswith(constants.PREFIX) or message.author.bot:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -28,11 +26,6 @@ async def on_message(message, edited=False):
|
|||||||
if not matched:
|
if not matched:
|
||||||
return
|
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:
|
if len(matched) > 1:
|
||||||
await utils.reply(
|
await utils.reply(
|
||||||
message,
|
message,
|
||||||
@ -88,7 +81,7 @@ async def on_message(message, edited=False):
|
|||||||
if len(output) > 2000:
|
if len(output) > 2000:
|
||||||
output = output.replace("`", "\\`")
|
output = output.replace("`", "\\`")
|
||||||
await disnake_paginator.ButtonPaginator(
|
await disnake_paginator.ButtonPaginator(
|
||||||
prefix="```\n",
|
prefix=f"```\n",
|
||||||
suffix="```",
|
suffix="```",
|
||||||
invalid_user_function=utils.invalid_user_handler,
|
invalid_user_function=utils.invalid_user_handler,
|
||||||
color=constants.EMBED_COLOR,
|
color=constants.EMBED_COLOR,
|
||||||
@ -99,7 +92,11 @@ async def on_message(message, edited=False):
|
|||||||
elif len(output.strip()) == 0:
|
elif len(output.strip()) == 0:
|
||||||
await utils.add_check_reaction(message)
|
await utils.add_check_reaction(message)
|
||||||
else:
|
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:
|
case C.CLEAR | C.PURGE if message.author.id in constants.OWNERS:
|
||||||
await commands.tools.clear(message)
|
await commands.tools.clear(message)
|
||||||
case C.JOIN:
|
case C.JOIN:
|
||||||
@ -108,7 +105,7 @@ async def on_message(message, edited=False):
|
|||||||
await commands.voice.leave(message)
|
await commands.voice.leave(message)
|
||||||
case C.QUEUE | C.PLAY:
|
case C.QUEUE | C.PLAY:
|
||||||
async with command_locks[message.guild.id]:
|
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:
|
case C.SKIP:
|
||||||
async with command_locks[message.guild.id]:
|
async with command_locks[message.guild.id]:
|
||||||
await commands.voice.skip(message)
|
await commands.voice.skip(message)
|
||||||
@ -132,9 +129,9 @@ async def on_message(message, edited=False):
|
|||||||
|
|
||||||
|
|
||||||
async def on_voice_state_update(_, before, after):
|
async def on_voice_state_update(_, before, after):
|
||||||
def is_empty(channel):
|
is_empty = lambda channel: [m.id for m in (channel.members if channel else [])] == [
|
||||||
return [m.id for m in (channel.members if channel else [])] == [client.user.id]
|
client.user.id
|
||||||
|
]
|
||||||
c = None
|
c = None
|
||||||
if is_empty(before.channel):
|
if is_empty(before.channel):
|
||||||
c = before.channel
|
c = before.channel
|
||||||
|
47
events.py
47
events.py
@ -1,52 +1,47 @@
|
|||||||
import asyncio
|
|
||||||
import threading
|
|
||||||
|
|
||||||
import commands
|
|
||||||
import core
|
import core
|
||||||
import tasks
|
import events
|
||||||
from state import client
|
from state import client
|
||||||
|
|
||||||
|
dynamic_handlers = {}
|
||||||
|
|
||||||
async def on_ready():
|
|
||||||
threading.Thread(
|
async def trigger_dynamic_handlers(event_type: str, *data):
|
||||||
name="cleanup",
|
if event_type in dynamic_handlers:
|
||||||
target=asyncio.run_coroutine_threadsafe,
|
for dynamic_handler in dynamic_handlers[event_type]:
|
||||||
args=(
|
try:
|
||||||
tasks.cleanup(),
|
await dynamic_handler(*data)
|
||||||
client.loop,
|
except Exception as e:
|
||||||
),
|
print(
|
||||||
).start()
|
f"error in dynamic event handler {dynamic_handler} for {event_type}: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def on_message(message):
|
async def on_message(message):
|
||||||
|
await events.trigger_dynamic_handlers("on_message", message)
|
||||||
|
|
||||||
await core.on_message(message)
|
await core.on_message(message)
|
||||||
|
|
||||||
|
|
||||||
async def on_message_edit(before, after):
|
async def on_message_edit(before, after):
|
||||||
|
await events.trigger_dynamic_handlers("on_message_edit", before, after)
|
||||||
|
|
||||||
if before.content == after.content:
|
if before.content == after.content:
|
||||||
return
|
return
|
||||||
|
|
||||||
await core.on_message(after, edited=True)
|
await core.on_message(after)
|
||||||
|
|
||||||
|
|
||||||
async def on_message_delete(message):
|
|
||||||
commands.voice.delete_queued([message])
|
|
||||||
|
|
||||||
|
|
||||||
async def on_bulk_message_delete(messages):
|
|
||||||
commands.voice.delete_queued(messages)
|
|
||||||
|
|
||||||
|
|
||||||
async def on_voice_state_update(member, before, 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)
|
await core.on_voice_state_update(member, before, after)
|
||||||
|
|
||||||
|
|
||||||
for k, v in client.get_listeners().items():
|
for k, v in client.get_listeners().items():
|
||||||
for f in v:
|
for f in v:
|
||||||
client.remove_listener(f, k)
|
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, "on_message")
|
||||||
client.add_listener(on_message_delete, "on_message_delete")
|
|
||||||
client.add_listener(on_message_edit, "on_message_edit")
|
client.add_listener(on_message_edit, "on_message_edit")
|
||||||
client.add_listener(on_voice_state_update, "on_voice_state_update")
|
client.add_listener(on_voice_state_update, "on_voice_state_update")
|
||||||
|
3
main.py
3
main.py
@ -7,9 +7,8 @@ from state import client, start_time
|
|||||||
|
|
||||||
@client.event
|
@client.event
|
||||||
async def on_ready():
|
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")
|
print(f"logged in as {client.user} in {round(time.time() - start_time, 1)}s")
|
||||||
|
|
||||||
await events.on_ready()
|
|
||||||
|
|
||||||
|
|
||||||
client.run(constants.SECRETS["TOKEN"])
|
client.run(constants.SECRETS["TOKEN"])
|
||||||
|
24
state.py
24
state.py
@ -1,32 +1,14 @@
|
|||||||
import collections
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import disnake
|
import disnake
|
||||||
|
|
||||||
|
command_locks = {}
|
||||||
class LimitedSizeDict(collections.OrderedDict):
|
executed_messages = {}
|
||||||
def __init__(self, *args, **kwds):
|
players = {}
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
intents = disnake.Intents.default()
|
intents = disnake.Intents.default()
|
||||||
intents.message_content = True
|
intents.message_content = True
|
||||||
intents.members = True
|
intents.members = True
|
||||||
client = disnake.Client(intents=intents)
|
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()
|
start_time = time.time()
|
||||||
|
25
tasks.py
25
tasks.py
@ -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
|
|
29
utils.py
29
utils.py
@ -1,13 +1,10 @@
|
|||||||
import disnake
|
import disnake
|
||||||
|
|
||||||
import constants
|
import constants
|
||||||
from state import message_responses
|
|
||||||
|
|
||||||
|
|
||||||
def format_duration(duration: int):
|
def format_duration(duration: int):
|
||||||
def format_plural(noun, count):
|
format_plural = lambda noun, count: noun if count == 1 else noun + "s"
|
||||||
return noun if count == 1 else noun + "s"
|
|
||||||
|
|
||||||
segments = []
|
segments = []
|
||||||
|
|
||||||
weeks, duration = divmod(duration, 604800)
|
weeks, duration = divmod(duration, 604800)
|
||||||
@ -37,27 +34,9 @@ async def add_check_reaction(message):
|
|||||||
|
|
||||||
|
|
||||||
async def reply(message, *args, **kwargs):
|
async def reply(message, *args, **kwargs):
|
||||||
if message.id in message_responses:
|
await message.reply(
|
||||||
await message_responses[message.id].edit(
|
*args, **kwargs, allowed_mentions=disnake.AllowedMentions.none()
|
||||||
*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
|
|
||||||
|
|
||||||
|
|
||||||
async def invalid_user_handler(interaction):
|
async def invalid_user_handler(interaction):
|
||||||
|
@ -68,7 +68,7 @@ class QueuedSong:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return (
|
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 "")
|
+ (f" (<@{self.trigger_message.author.id}>)" if show_queuer else "")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user