mirror of
https://github.com/Matthww/TuneBot.git
synced 2026-09-21 22:57:48 +00:00
WIP Cleaning up the code base + impl slash commands
This commit is contained in:
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"python.formatting.provider": "yapf"
|
"python.formatting.provider": "black"
|
||||||
}
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
[[source]]
|
|
||||||
name = "pypi"
|
|
||||||
url = "https://pypi.org/simple"
|
|
||||||
verify_ssl = true
|
|
||||||
|
|
||||||
[dev-packages]
|
|
||||||
yapf = "*"
|
|
||||||
|
|
||||||
[packages]
|
|
||||||
humanize = "*"
|
|
||||||
"discord.py" = {extras = ["voice"], version = "*"}
|
|
||||||
sqlalchemy = "*"
|
|
||||||
aiomysql = "*"
|
|
||||||
lavalink = "*"
|
|
||||||
|
|
||||||
[requires]
|
|
||||||
python_version = "3.8"
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
# CloudKid
|
# ChristmasBot
|
||||||
CloudKid Music Bot
|
Christmas Music Bot
|
||||||
|
|||||||
@@ -1,68 +1,55 @@
|
|||||||
import discord
|
import discord
|
||||||
|
from discord.colour import Color
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import asyncio
|
import asyncio
|
||||||
import sqlalchemy as sa
|
from typing import Any, Dict, Sequence
|
||||||
from aiomysql.sa import Engine
|
from discord import Message
|
||||||
from tables import get_tables
|
|
||||||
from typing import Sequence
|
|
||||||
from aiomysql.sa import create_engine
|
|
||||||
from discord import ActivityType
|
|
||||||
from discord import Status
|
|
||||||
from typing import Mapping
|
|
||||||
|
|
||||||
|
|
||||||
class Database():
|
class Database:
|
||||||
def __init__(self, engine: Engine):
|
def __init__(self):
|
||||||
self.loop = asyncio.get_event_loop()
|
self.loop = asyncio.get_event_loop()
|
||||||
self.metadata = sa.MetaData()
|
|
||||||
self.tables = get_tables(self.metadata)
|
|
||||||
self.engine = engine
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def init(dbconf: dict):
|
|
||||||
engine = await create_engine(**dbconf, autocommit=True)
|
|
||||||
return Database(engine)
|
|
||||||
|
|
||||||
|
|
||||||
class CloudKid(commands.Bot):
|
class ChristmasBot(commands.Bot):
|
||||||
INITIAL_EXTENSIONS = [
|
INITIAL_EXTENSIONS = [
|
||||||
'cogs.owner', 'cogs.settings', 'cogs.information', 'cogs.music'
|
"cogs.owner",
|
||||||
|
"cogs.settings",
|
||||||
|
"cogs.information",
|
||||||
|
"cogs.music",
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, config: dict):
|
def __init__(self, config: Dict[Any, Any]):
|
||||||
intents: discord.Intents = discord.Intents.none()
|
intents: discord.Intents = discord.Intents.none()
|
||||||
intents.voice_states = True
|
intents.voice_states = True
|
||||||
intents.guild_messages = True
|
intents.guild_messages = True
|
||||||
|
intents.guilds = True
|
||||||
|
intents.messages = True
|
||||||
|
|
||||||
self.config = config
|
self.config = config
|
||||||
self.colors = self.process_colors(config["colors"])
|
self.colors: Dict[str, Color] = self.process_colours(config.get("colors", []))
|
||||||
|
|
||||||
super().__init__(command_prefix=self.prefix_callable,
|
super().__init__(
|
||||||
description='CloudKid Radio',
|
command_prefix=self.prefix_callable,
|
||||||
case_insensitive=True,
|
description=self.config["info"].get("description"),
|
||||||
fetch_offline_members=False,
|
case_insensitive=False,
|
||||||
intents=intents)
|
fetch_offline_members=False,
|
||||||
|
intents=intents,
|
||||||
|
slash_command_guilds=[227431704426446848],
|
||||||
|
)
|
||||||
|
|
||||||
self.database = None
|
async def prefix_callable(self, _, msg: Message):
|
||||||
self.loop.create_task(self.async_init())
|
|
||||||
|
|
||||||
async def async_init(self):
|
|
||||||
dbconf = self.config["database"]
|
|
||||||
self.database = await Database.init(dbconf)
|
|
||||||
|
|
||||||
async def prefix_callable(self, _, msg):
|
|
||||||
return commands.when_mentioned_or(*self.config["prefixes"])(self, msg)
|
return commands.when_mentioned_or(*self.config["prefixes"])(self, msg)
|
||||||
|
|
||||||
async def load_cogs(self, cog_names: Sequence[str]):
|
async def load_cogs(self, cog_names: Sequence[str]):
|
||||||
for cog in cog_names:
|
for cog in cog_names:
|
||||||
try:
|
try:
|
||||||
self.load_extension(cog)
|
self.load_extension(cog)
|
||||||
print(f'Succesfully loaded extension {cog}.')
|
print(f"Succesfully loaded extension {cog}.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f'Failed to load extension {cog}.\n\t{e}',
|
print(f"Failed to load extension {cog}.\n\t{e}", file=sys.stderr)
|
||||||
file=sys.stderr)
|
|
||||||
|
|
||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
print(f"Logged in as: {self.user}")
|
print(f"Logged in as: {self.user}")
|
||||||
@@ -74,14 +61,15 @@ class CloudKid(commands.Bot):
|
|||||||
await self.change_presence(activity=discord.Game(text))
|
await self.change_presence(activity=discord.Game(text))
|
||||||
await self.load_cogs(self.INITIAL_EXTENSIONS)
|
await self.load_cogs(self.INITIAL_EXTENSIONS)
|
||||||
|
|
||||||
def process_colors(
|
def process_colours(self, colors: Dict[str, str]) -> Dict[str, Color]:
|
||||||
self, colors: Mapping[str, str]) -> Mapping[str, discord.Color]:
|
colour_dict: Dict[str, Color] = {}
|
||||||
for name, color in colors.items():
|
for name, color in colors.items():
|
||||||
colors[name] = discord.Color(int(color, 16))
|
colour_dict[name] = Color(int(color, 16))
|
||||||
return colors
|
return colour_dict
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
config = json.load(open('config.json', 'r', encoding='utf-8'))
|
config = json.load(open("config.json", "r", encoding="utf-8"))
|
||||||
token = config.pop("token")
|
token = config.pop("token")
|
||||||
CloudKid(config).run(token, reconnect=True)
|
bot = ChristmasBot(config)
|
||||||
|
bot.run(token, reconnect=True)
|
||||||
|
|||||||
+48
-49
@@ -2,12 +2,12 @@ import discord
|
|||||||
from discord.ext import tasks, commands
|
from discord.ext import tasks, commands
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
from discord.ext.commands import Context
|
||||||
import humanize
|
import humanize
|
||||||
import datetime
|
import datetime
|
||||||
import lavalink
|
import lavalink
|
||||||
from utils import metadata
|
from utils.EmbedGenerator import EmbedGenerator
|
||||||
from utils.paginator import HelpPaginator
|
from utils.paginator import HelpPaginator
|
||||||
from discord import Status
|
|
||||||
|
|
||||||
|
|
||||||
class InformationCog(commands.Cog, name="Information"):
|
class InformationCog(commands.Cog, name="Information"):
|
||||||
@@ -21,49 +21,49 @@ class InformationCog(commands.Cog, name="Information"):
|
|||||||
await self.bot.wait_until_ready()
|
await self.bot.wait_until_ready()
|
||||||
title = "ck!connect | ck!help"
|
title = "ck!connect | ck!help"
|
||||||
if self.is_help_msg:
|
if self.is_help_msg:
|
||||||
title = (await metadata.fetch_metadata())["name"]
|
title = "Tfoe broer"
|
||||||
self.is_help_msg = not self.is_help_msg
|
self.is_help_msg = not self.is_help_msg
|
||||||
await self.bot.change_presence(activity=discord.Game(title))
|
await self.bot.change_presence(activity=discord.Game(title))
|
||||||
|
|
||||||
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
||||||
@commands.command(description='PONG!', aliases=['pong'])
|
@commands.command(description="PONG!", aliases=["pong"])
|
||||||
async def ping(self, ctx):
|
async def ping(self, ctx: Context):
|
||||||
"""Test the latency"""
|
"""Test the latency"""
|
||||||
avatar = ctx.author.avatar_url_as(static_format='jpeg')
|
avatar = ctx.author.avatar.with_static_format("jpeg")
|
||||||
emoji = discord.utils.get(ctx.bot.emojis, name='loading')
|
emoji = discord.utils.get(ctx.bot.emojis, name="loading")
|
||||||
start = time.monotonic()
|
start = time.monotonic()
|
||||||
msg = await ctx.send(embed=discord.Embed(
|
msg = await ctx.send(
|
||||||
description=f'{emoji} Calculating ping'))
|
embed=discord.Embed(description=f"{emoji} Calculating ping")
|
||||||
|
)
|
||||||
millis = (time.monotonic() - start) * 1000
|
millis = (time.monotonic() - start) * 1000
|
||||||
heartbeat = ctx.bot.latency * 1000
|
heartbeat = ctx.bot.latency * 1000
|
||||||
embed = discord.Embed(color=discord.Color.blue())
|
embed = discord.Embed(color=discord.Color.blue())
|
||||||
embed.add_field(name=':heartbeat: Heartbeat',
|
embed.add_field(
|
||||||
value=f'`{heartbeat:,.2f}ms`',
|
name=":heartbeat: Heartbeat", value=f"`{heartbeat:,.2f}ms`", inline=True
|
||||||
inline=True)
|
)
|
||||||
embed.add_field(name=':file_cabinet: ACK',
|
embed.add_field(
|
||||||
value=f'`{millis:,.2f}ms`',
|
name=":file_cabinet: ACK", value=f"`{millis:,.2f}ms`", inline=True
|
||||||
inline=True)
|
)
|
||||||
embed.set_footer(text=f"Requested by: {ctx.author}",
|
embed.set_footer(text=f"Requested by: {ctx.author}", icon_url=f"{avatar}")
|
||||||
icon_url=f"{avatar}")
|
|
||||||
await msg.edit(embed=embed)
|
await msg.edit(embed=embed)
|
||||||
|
|
||||||
@commands.command(name='invite')
|
@commands.command(
|
||||||
|
name="invite", description="Gets the invite link!", slash_commands=True
|
||||||
|
)
|
||||||
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
||||||
async def invite(self, ctx):
|
async def invite(self, ctx: Context):
|
||||||
"""Gets the invite link!"""
|
"""Gets the invite link!"""
|
||||||
color = self.bot.colors["embed"]
|
link = f"https://discord.com/oauth2/authorize?client_id=643555373814382593&permissions=3230720&scope=bot%20applications.commands"
|
||||||
avatar = ctx.author.avatar_url_as(static_format='jpeg')
|
embed = await EmbedGenerator.Message(ctx, "Add our bot to your server:", link)
|
||||||
client_id = ctx.bot.user.id
|
|
||||||
link = f"https://discord.com/oauth2/authorize?scope=bot&client_id={client_id}&permissions=70642768"
|
|
||||||
embed = discord.Embed(color=color)
|
|
||||||
embed.add_field(name='Add our bot to your server:', value=link)
|
|
||||||
embed.set_footer(text=f"Requested by: {ctx.author}",
|
|
||||||
icon_url=f"{avatar}")
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.command(
|
||||||
|
name="wlinfo",
|
||||||
|
description="Retrieve various Node/Server/Player information.",
|
||||||
|
slash_commands=True,
|
||||||
|
)
|
||||||
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
||||||
@commands.command()
|
async def wlinfo(self, ctx: Context):
|
||||||
async def wlinfo(self, ctx):
|
|
||||||
"""Retrieve various Node/Server/Player information."""
|
"""Retrieve various Node/Server/Player information."""
|
||||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||||
node = player.node
|
node = player.node
|
||||||
@@ -73,28 +73,29 @@ class InformationCog(commands.Cog, name="Information"):
|
|||||||
free = humanize.naturalsize(node.stats.memory_free)
|
free = humanize.naturalsize(node.stats.memory_free)
|
||||||
cpu = node.stats.cpu_cores
|
cpu = node.stats.cpu_cores
|
||||||
|
|
||||||
fmt = f'**WaveLink:** `{lavalink.__version__}`\n\n' \
|
fmt = (
|
||||||
f'Connected to `{len(self.bot.lavalink.nodes)}` nodes.\n' \
|
f"**WaveLink:** `{lavalink.__version__}`\n\n"
|
||||||
f'Best available Node `{self.bot.lavalink.get_best_node().__repr__()}`\n' \
|
f"Connected to `{len(self.bot.lavalink.nodes)}` nodes.\n"
|
||||||
f'`{len(self.bot.lavalink.players)}` players are distributed on nodes.\n' \
|
f"Best available Node `{self.bot.lavalink.get_best_node().__repr__()}`\n"
|
||||||
f'`{node.stats.players}` players are distributed on server.\n' \
|
f"`{len(self.bot.lavalink.players)}` players are distributed on nodes.\n"
|
||||||
f'`{node.stats.playing_players}` players are playing on server.\n\n' \
|
f"`{node.stats.players}` players are distributed on server.\n"
|
||||||
f'Server Memory: `{used}/{total}` | `({free} free)`\n' \
|
f"`{node.stats.playing_players}` players are playing on server.\n\n"
|
||||||
f'Server CPU: `{cpu}`\n\n' \
|
f"Server Memory: `{used}/{total}` | `({free} free)`\n"
|
||||||
f'Server Uptime: `{datetime.timedelta(milliseconds=node.stats.uptime)}`'
|
f"Server CPU: `{cpu}`\n\n"
|
||||||
|
f"Server Uptime: `{datetime.timedelta(milliseconds=node.stats.uptime)}`"
|
||||||
|
)
|
||||||
await ctx.send(fmt)
|
await ctx.send(fmt)
|
||||||
|
|
||||||
@commands.command(name="help", aliases=["about", "info"])
|
@commands.command(name="help", aliases=["about", "info"], slash_command=True)
|
||||||
@commands.cooldown(1, 1, commands.BucketType.user)
|
@commands.cooldown(1, 1, commands.BucketType.user)
|
||||||
async def about(self, ctx, command: str = None):
|
async def about(self, ctx: Context):
|
||||||
"""Exobot command list"""
|
"""Exobot command list"""
|
||||||
if command:
|
if None:
|
||||||
entity = self.bot.get_cog(command) or self.bot.get_command(command)
|
entity = self.bot.get_cog(command) or self.bot.get_command(command)
|
||||||
|
|
||||||
if entity is None:
|
if entity is None:
|
||||||
clean = command.replace('@', '@\u200b')
|
clean = command.replace("@", "@\u200b")
|
||||||
return await ctx.send(
|
return await ctx.send(f'Command or category "{clean}" not found.')
|
||||||
f'Command or category "{clean}" not found.')
|
|
||||||
elif isinstance(entity, discord.ext.commands.Command):
|
elif isinstance(entity, discord.ext.commands.Command):
|
||||||
p = await HelpPaginator.from_command(ctx, entity)
|
p = await HelpPaginator.from_command(ctx, entity)
|
||||||
else:
|
else:
|
||||||
@@ -111,7 +112,7 @@ class InformationCog(commands.Cog, name="Information"):
|
|||||||
display_cogs = {
|
display_cogs = {
|
||||||
"Information": ":information_source:",
|
"Information": ":information_source:",
|
||||||
"Music": ":musical_note:",
|
"Music": ":musical_note:",
|
||||||
"Settings": ":gear:"
|
"Settings": ":gear:",
|
||||||
}
|
}
|
||||||
|
|
||||||
for cog_name, cog_icon in display_cogs.items():
|
for cog_name, cog_icon in display_cogs.items():
|
||||||
@@ -119,13 +120,11 @@ class InformationCog(commands.Cog, name="Information"):
|
|||||||
if not cog:
|
if not cog:
|
||||||
continue
|
continue
|
||||||
cogname_str = f"{cog_icon} {cog_name}"
|
cogname_str = f"{cog_icon} {cog_name}"
|
||||||
commands = [
|
commands = [f"`{cmd.name}`" for cmd in cog.get_commands() if not cmd.hidden]
|
||||||
f"`{cmd.name}`" for cmd in cog.get_commands() if not cmd.hidden
|
|
||||||
]
|
|
||||||
commands_str = ", ".join(commands)
|
commands_str = ", ".join(commands)
|
||||||
embed.add_field(name=cogname_str, value=commands_str, inline=False)
|
embed.add_field(name=cogname_str, value=commands_str, inline=False)
|
||||||
|
|
||||||
avatar = ctx.author.avatar_url_as(static_format='jpeg')
|
avatar = ctx.author.avatar.with_static_format("jpeg")
|
||||||
embed.set_footer(text=f"Requested by: {ctx.author}", icon_url=avatar)
|
embed.set_footer(text=f"Requested by: {ctx.author}", icon_url=avatar)
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|||||||
+51
-54
@@ -1,13 +1,10 @@
|
|||||||
import discord
|
import discord
|
||||||
|
from discord import channel
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
import time
|
|
||||||
import lavalink
|
import lavalink
|
||||||
import re
|
|
||||||
import random
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from utils.database import AutoJoin
|
from bot import ChristmasBot
|
||||||
from utils import metadata
|
|
||||||
from utils.EmbedGenerator import EmbedGenerator
|
from utils.EmbedGenerator import EmbedGenerator
|
||||||
|
|
||||||
|
|
||||||
@@ -16,12 +13,12 @@ class MusicCog(commands.Cog, name="Music"):
|
|||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.stream = "https://azuracast.exobot.site/radio/8000/radio.opus"
|
self.stream = "https://azuracast.exobot.site/radio/8000/radio.opus"
|
||||||
|
|
||||||
if not hasattr(bot, 'lavalink'):
|
if not hasattr(bot, "lavalink"):
|
||||||
bot.lavalink = lavalink.Client(bot.user.id)
|
bot.lavalink = lavalink.Client(bot.user.id)
|
||||||
bot.lavalink.add_node('de-1.rivalmc.net', 2333, '12345', 'eu',
|
bot.lavalink.add_node("de-1.rivalmc.net", 2333, "12345", "eu", "poggers")
|
||||||
'poggers')
|
bot.add_listener(
|
||||||
bot.add_listener(self.bot.lavalink.voice_update_handler,
|
self.bot.lavalink.voice_update_handler, "on_socket_response"
|
||||||
'on_socket_response')
|
)
|
||||||
|
|
||||||
lavalink.add_event_hook(self.track_hook)
|
lavalink.add_event_hook(self.track_hook)
|
||||||
|
|
||||||
@@ -29,58 +26,60 @@ class MusicCog(commands.Cog, name="Music"):
|
|||||||
|
|
||||||
async def async_init(self):
|
async def async_init(self):
|
||||||
await self.bot.wait_until_ready()
|
await self.bot.wait_until_ready()
|
||||||
channels = await AutoJoin.get_channels(self.bot)
|
|
||||||
|
channels = []
|
||||||
|
|
||||||
# We startup to fast #NOTPOGGERS
|
# We startup to fast #NOTPOGGERS
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
for x in channels:
|
for channel in channels:
|
||||||
guild = self.bot.get_guild(x[0])
|
guild = self.bot.get_guild(channel[0])
|
||||||
player = self.bot.lavalink.player_manager.create(x[0],
|
player = self.bot.lavalink.player_manager.create(
|
||||||
endpoint=str(
|
channel[0], endpoint=str(guild.region)
|
||||||
guild.region))
|
)
|
||||||
track = await player.node.get_tracks(self.stream)
|
track = await player.node.get_tracks(self.stream)
|
||||||
if not player.is_playing:
|
if not player.is_playing:
|
||||||
await player.play(track["tracks"][0])
|
await player.play(track["tracks"][0])
|
||||||
await self.connect_to(x[0], x[1])
|
await self.connect_to(channel[0], channel[1])
|
||||||
|
|
||||||
def cog_unload(self):
|
def cog_unload(self):
|
||||||
""" Cog unload handler. This removes any event hooks that were registered. """
|
"""Cog unload handler. This removes any event hooks that were registered."""
|
||||||
self.bot.lavalink._event_hooks.clear()
|
self.bot.lavalink._event_hooks.clear()
|
||||||
|
|
||||||
async def cog_before_invoke(self, ctx):
|
async def cog_before_invoke(self, ctx):
|
||||||
""" Command before-invoke handler. """
|
"""Command before-invoke handler."""
|
||||||
guild_check = ctx.guild is not None
|
guild_check = ctx.guild is not None
|
||||||
if guild_check:
|
if guild_check:
|
||||||
await self.ensure_voice(ctx)
|
await self.ensure_voice(ctx)
|
||||||
return guild_check
|
return guild_check
|
||||||
|
|
||||||
async def ensure_voice(self, ctx):
|
async def ensure_voice(self, ctx):
|
||||||
""" This check ensures that the bot and command author are in the same voicechannel. """
|
"""This check ensures that the bot and command author are in the same voicechannel."""
|
||||||
player = self.bot.lavalink.player_manager.create(ctx.guild.id,
|
player = self.bot.lavalink.player_manager.create(
|
||||||
endpoint=str(
|
ctx.guild.id, endpoint=str(ctx.guild.region)
|
||||||
ctx.guild.region))
|
)
|
||||||
should_connect = ctx.command.name in ('connect', )
|
should_connect = ctx.command.name in ("connect",)
|
||||||
|
|
||||||
if not ctx.author.voice or not ctx.author.voice.channel:
|
if not ctx.author.voice or not ctx.author.voice.channel:
|
||||||
raise commands.CommandInvokeError('Join a voicechannel first.')
|
raise commands.CommandInvokeError("Join a voicechannel first.")
|
||||||
|
|
||||||
if not player.is_connected:
|
if not player.is_connected:
|
||||||
if not should_connect:
|
if not should_connect:
|
||||||
raise commands.CommandInvokeError('Not connected.')
|
raise commands.CommandInvokeError("Not connected.")
|
||||||
|
|
||||||
permissions = ctx.author.voice.channel.permissions_for(ctx.me)
|
permissions = ctx.author.voice.channel.permissions_for(ctx.me)
|
||||||
|
|
||||||
if not permissions.connect or not permissions.speak: # Check user limit too?
|
if (
|
||||||
|
not permissions.connect or not permissions.speak
|
||||||
|
): # Check user limit too?
|
||||||
raise commands.CommandInvokeError(
|
raise commands.CommandInvokeError(
|
||||||
'I need the `CONNECT` and `SPEAK` permissions.')
|
"I need the `CONNECT` and `SPEAK` permissions."
|
||||||
|
)
|
||||||
|
|
||||||
player.store('channel', ctx.channel.id)
|
player.store("channel", ctx.channel.id)
|
||||||
await self.connect_to(ctx.guild.id,
|
await self.connect_to(ctx.guild.id, str(ctx.author.voice.channel.id))
|
||||||
str(ctx.author.voice.channel.id))
|
|
||||||
else:
|
else:
|
||||||
if int(player.channel_id) != ctx.author.voice.channel.id:
|
if int(player.channel_id) != ctx.author.voice.channel.id:
|
||||||
raise commands.CommandInvokeError(
|
raise commands.CommandInvokeError("You need to be in my voicechannel.")
|
||||||
'You need to be in my voicechannel.')
|
|
||||||
|
|
||||||
async def track_hook(self, event):
|
async def track_hook(self, event):
|
||||||
if isinstance(event, lavalink.events.QueueEndEvent):
|
if isinstance(event, lavalink.events.QueueEndEvent):
|
||||||
@@ -88,60 +87,58 @@ class MusicCog(commands.Cog, name="Music"):
|
|||||||
await self.connect_to(guild_id, None)
|
await self.connect_to(guild_id, None)
|
||||||
|
|
||||||
async def connect_to(self, guild_id: int, channel_id: str):
|
async def connect_to(self, guild_id: int, channel_id: str):
|
||||||
""" Connects to the given voicechannel ID. A channel_id of `None` means disconnect. """
|
"""Connects to the given voicechannel ID. A channel_id of `None` means disconnect."""
|
||||||
ws = self.bot._connection._get_websocket(guild_id)
|
ws = self.bot._connection._get_websocket(guild_id)
|
||||||
await ws.voice_state(str(guild_id), channel_id)
|
await ws.voice_state(str(guild_id), channel_id)
|
||||||
|
|
||||||
@commands.command(name='connect')
|
@commands.command(name="connect")
|
||||||
async def connect(self, ctx):
|
async def connect(self, ctx):
|
||||||
"""Starts vibing."""
|
"""Starts vibing."""
|
||||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||||
results = await player.node.get_tracks(self.stream)
|
results = await player.node.get_tracks(self.stream)
|
||||||
|
|
||||||
if not results or not results['tracks']:
|
if not results or not results["tracks"]:
|
||||||
return await ctx.send('Nothing found!')
|
return await ctx.send("Nothing found!")
|
||||||
|
|
||||||
if results['loadType'] == 'PLAYLIST_LOADED':
|
if results["loadType"] == "PLAYLIST_LOADED":
|
||||||
tracks = results['tracks']
|
tracks = results["tracks"]
|
||||||
|
|
||||||
for track in tracks:
|
for track in tracks:
|
||||||
player.add(requester=ctx.author.id, track=track)
|
player.add(requester=ctx.author.id, track=track)
|
||||||
else:
|
else:
|
||||||
track = results['tracks'][0]
|
track = results["tracks"][0]
|
||||||
track = lavalink.models.AudioTrack(track,
|
track = lavalink.models.AudioTrack(track, ctx.author.id, recommended=True)
|
||||||
ctx.author.id,
|
|
||||||
recommended=True)
|
|
||||||
player.add(requester=ctx.author.id, track=track)
|
player.add(requester=ctx.author.id, track=track)
|
||||||
|
|
||||||
if not player.is_playing:
|
if not player.is_playing:
|
||||||
await player.play()
|
await player.play()
|
||||||
|
|
||||||
@commands.command(aliases=['dc'])
|
@commands.command(aliases=["dc"])
|
||||||
async def disconnect(self, ctx):
|
async def disconnect(self, ctx):
|
||||||
""" Disconnects the player from the voice channel and clears its queue. """
|
"""Disconnects the player from the voice channel and clears its queue."""
|
||||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||||
|
|
||||||
if not player.is_connected:
|
if not player.is_connected:
|
||||||
return await ctx.send('Not connected.')
|
return await ctx.send("Not connected.")
|
||||||
|
|
||||||
if not ctx.author.voice or (
|
if not ctx.author.voice or (
|
||||||
player.is_connected
|
player.is_connected
|
||||||
and ctx.author.voice.channel.id != int(player.channel_id)):
|
and ctx.author.voice.channel.id != int(player.channel_id)
|
||||||
return await ctx.send('You\'re not in my voicechannel!')
|
):
|
||||||
|
return await ctx.send("You're not in my voicechannel!")
|
||||||
|
|
||||||
player.queue.clear()
|
player.queue.clear()
|
||||||
await player.stop()
|
await player.stop()
|
||||||
await self.connect_to(ctx.guild.id, None)
|
await self.connect_to(ctx.guild.id, None)
|
||||||
|
|
||||||
@commands.command(name='now', aliases=['playing'])
|
@commands.command(name="now", aliases=["playing"])
|
||||||
async def now_playing(self, ctx):
|
async def now_playing(self, ctx):
|
||||||
"""Stop and disconnect the player and controller."""
|
"""Stop and disconnect the player and controller."""
|
||||||
np = await metadata.fetch_metadata()
|
|
||||||
em = discord.Embed(color=self.bot.colors["embed"])
|
em = discord.Embed(color=self.bot.colors["embed"])
|
||||||
em.set_thumbnail(url=np["thumbnail"])
|
# em.set_thumbnail(url=np["thumbnail"])
|
||||||
em.add_field(name="Currently playing:", value=np["name"])
|
em.add_field(name="Currently playing:", value="Some song")
|
||||||
await EmbedGenerator.SendWithFooter(ctx, em)
|
await EmbedGenerator.SendWithFooter(ctx, em)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: ChristmasBot):
|
||||||
bot.add_cog(MusicCog(bot))
|
bot.add_cog(MusicCog(bot))
|
||||||
|
|||||||
+74
-62
@@ -11,32 +11,36 @@ from io import BytesIO
|
|||||||
from platform import python_version
|
from platform import python_version
|
||||||
from contextlib import redirect_stdout
|
from contextlib import redirect_stdout
|
||||||
|
|
||||||
|
from discord.ext.commands.context import Context
|
||||||
|
|
||||||
|
from bot import ChristmasBot
|
||||||
|
|
||||||
|
|
||||||
class OwnerCog(commands.Cog):
|
class OwnerCog(commands.Cog):
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: ChristmasBot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self._last_result = None
|
self._last_result = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def cleanup_code(content):
|
def cleanup_code(content):
|
||||||
if content.startswith('```') and content.endswith('```'):
|
if content.startswith("```") and content.endswith("```"):
|
||||||
return '\n'.join(content.split('\n')[1:-1])
|
return "\n".join(content.split("\n")[1:-1])
|
||||||
return content.strip('` \n')
|
return content.strip("` \n")
|
||||||
|
|
||||||
# Hidden means it won't show up on the default help.
|
# Hidden means it won't show up on the default help.
|
||||||
@commands.command(name='load', hidden=True)
|
@commands.command(name="load", hidden=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def _cog_load(self, ctx, *, cog: str):
|
async def _cog_load(self, ctx: Context, *, cog: str):
|
||||||
"""Command which Loads a Module."""
|
"""Command which Loads a Module."""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.bot.load_extension(cog)
|
self.bot.load_extension(cog)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await ctx.send(f'**`ERROR:`** {type(e).__name__} - {e}')
|
await ctx.send(f"**`ERROR:`** {type(e).__name__} - {e}")
|
||||||
else:
|
else:
|
||||||
await ctx.send('**`SUCCESS`**')
|
await ctx.send("**`SUCCESS`**")
|
||||||
|
|
||||||
@commands.command(name='unload', hidden=True)
|
@commands.command(name="unload", hidden=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def _cog_unload(self, ctx, *, cog: str):
|
async def _cog_unload(self, ctx, *, cog: str):
|
||||||
"""Command which Unloads a Module."""
|
"""Command which Unloads a Module."""
|
||||||
@@ -44,11 +48,11 @@ class OwnerCog(commands.Cog):
|
|||||||
try:
|
try:
|
||||||
self.bot.unload_extension(cog)
|
self.bot.unload_extension(cog)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await ctx.send(f'**`ERROR:`** {type(e).__name__} - {e}')
|
await ctx.send(f"**`ERROR:`** {type(e).__name__} - {e}")
|
||||||
else:
|
else:
|
||||||
await ctx.send('**`SUCCESS`**')
|
await ctx.send("**`SUCCESS`**")
|
||||||
|
|
||||||
@commands.command(name='reload', hidden=True)
|
@commands.command(name="reload", hidden=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def _cog_reload(self, ctx, *, cog: str):
|
async def _cog_reload(self, ctx, *, cog: str):
|
||||||
"""Command which Reloads a Module."""
|
"""Command which Reloads a Module."""
|
||||||
@@ -57,35 +61,29 @@ class OwnerCog(commands.Cog):
|
|||||||
self.bot.unload_extension(cog)
|
self.bot.unload_extension(cog)
|
||||||
self.bot.load_extension(cog)
|
self.bot.load_extension(cog)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await ctx.send(f'**`ERROR:`** {type(e).__name__} - {e}')
|
await ctx.send(f"**`ERROR:`** {type(e).__name__} - {e}")
|
||||||
else:
|
else:
|
||||||
await ctx.send('**`SUCCESS`**')
|
await ctx.send("**`SUCCESS`**")
|
||||||
|
|
||||||
@commands.command(name='shutdown', hidden=True)
|
@commands.command(name="shutdown", hidden=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def shutdown(self, ctx):
|
async def shutdown(self, ctx):
|
||||||
"""Command which shutdowns the bot."""
|
"""Command which shutdowns the bot."""
|
||||||
await ctx.bot.logout()
|
await ctx.bot.logout()
|
||||||
|
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
@commands.command(pass_context=True,
|
@commands.command(pass_context=True, hidden=True, name="eval", aliases=["evaluate"])
|
||||||
hidden=True,
|
|
||||||
name='eval',
|
|
||||||
aliases=['evaluate'])
|
|
||||||
async def _eval(self, ctx, *, body: str):
|
async def _eval(self, ctx, *, body: str):
|
||||||
env = {
|
env = {
|
||||||
'bot': self.bot,
|
"bot": self.bot,
|
||||||
'ctx': ctx,
|
"ctx": ctx,
|
||||||
'channel': ctx.channel,
|
"channel": ctx.channel,
|
||||||
'author': ctx.author,
|
"author": ctx.author,
|
||||||
'guild': ctx.guild,
|
"guild": ctx.guild,
|
||||||
'message': ctx.message,
|
"message": ctx.message,
|
||||||
'_': self._last_result
|
"_": self._last_result,
|
||||||
}
|
}
|
||||||
|
|
||||||
if "import os" in body and ctx.author.id == 190875175460405249:
|
|
||||||
return await ctx.send("Ah ah ah, you didn't say the magic word.")
|
|
||||||
|
|
||||||
env.update(globals())
|
env.update(globals())
|
||||||
|
|
||||||
body = self.cleanup_code(body)
|
body = self.cleanup_code(body)
|
||||||
@@ -98,26 +96,34 @@ class OwnerCog(commands.Cog):
|
|||||||
exec(to_compile, env)
|
exec(to_compile, env)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# await ctx.message.add_reaction('naokoerror:447495055603662849')
|
# await ctx.message.add_reaction('naokoerror:447495055603662849')
|
||||||
fooem = discord.Embed(color=0xff0000)
|
fooem = discord.Embed(color=0xFF0000)
|
||||||
fooem.add_field(name="Code evaluation was not successful.",
|
fooem.add_field(
|
||||||
value=f'```\n{e.__class__.__name__}: {e}\n```')
|
name="Code evaluation was not successful.",
|
||||||
fooem.set_footer(text=f"Evaluated using Python {python_version()}",
|
value=f"```\n{e.__class__.__name__}: {e}\n```",
|
||||||
icon_url="http://i.imgur.com/9EftiVK.png")
|
)
|
||||||
|
fooem.set_footer(
|
||||||
|
text=f"Evaluated using Python {python_version()}",
|
||||||
|
icon_url="http://i.imgur.com/9EftiVK.png",
|
||||||
|
)
|
||||||
await ctx.send(embed=fooem)
|
await ctx.send(embed=fooem)
|
||||||
# await ctx.message.remove_reaction('a:loading:452489773396000778', member=ctx.me)
|
# await ctx.message.remove_reaction('a:loading:452489773396000778', member=ctx.me)
|
||||||
|
|
||||||
func = env['func']
|
func = env["func"]
|
||||||
try:
|
try:
|
||||||
with redirect_stdout(stdout):
|
with redirect_stdout(stdout):
|
||||||
ret = await func()
|
ret = await func()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
value = stdout.getvalue()
|
value = stdout.getvalue()
|
||||||
# await ctx.message.add_reaction('naokoerror:447495055603662849')
|
# await ctx.message.add_reaction('naokoerror:447495055603662849')
|
||||||
fooem = discord.Embed(color=0xff0000)
|
fooem = discord.Embed(color=0xFF0000)
|
||||||
fooem.add_field(name="Code evaluation was not successful.",
|
fooem.add_field(
|
||||||
value=f'```\n{value}{traceback.format_exc()}\n```')
|
name="Code evaluation was not successful.",
|
||||||
fooem.set_footer(text=f"Evaluated using Python {python_version()}",
|
value=f"```\n{value}{traceback.format_exc()}\n```",
|
||||||
icon_url="http://i.imgur.com/9EftiVK.png")
|
)
|
||||||
|
fooem.set_footer(
|
||||||
|
text=f"Evaluated using Python {python_version()}",
|
||||||
|
icon_url="http://i.imgur.com/9EftiVK.png",
|
||||||
|
)
|
||||||
await ctx.send(embed=fooem)
|
await ctx.send(embed=fooem)
|
||||||
try:
|
try:
|
||||||
# await ctx.message.remove_reaction('a:loading:452489773396000778', member=ctx.me)
|
# await ctx.message.remove_reaction('a:loading:452489773396000778', member=ctx.me)
|
||||||
@@ -129,7 +135,8 @@ class OwnerCog(commands.Cog):
|
|||||||
value = stdout.getvalue()
|
value = stdout.getvalue()
|
||||||
try:
|
try:
|
||||||
await ctx.message.remove_reaction(
|
await ctx.message.remove_reaction(
|
||||||
'a:loading:452489773396000778', member=ctx.me)
|
"a:loading:452489773396000778", member=ctx.me
|
||||||
|
)
|
||||||
# await ctx.message.add_reaction('naokotick:447494238872141827')
|
# await ctx.message.add_reaction('naokotick:447494238872141827')
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
@@ -137,37 +144,42 @@ class OwnerCog(commands.Cog):
|
|||||||
if ret is None:
|
if ret is None:
|
||||||
if value:
|
if value:
|
||||||
sfooem = discord.Embed(color=0x170041)
|
sfooem = discord.Embed(color=0x170041)
|
||||||
sfooem.add_field(name="Code evaluation was successful!",
|
sfooem.add_field(
|
||||||
value=f'```\n{value}\n```')
|
name="Code evaluation was successful!",
|
||||||
|
value=f"```\n{value}\n```",
|
||||||
|
)
|
||||||
sfooem.set_footer(
|
sfooem.set_footer(
|
||||||
text=f"Evaluated using Python {python_version()}",
|
text=f"Evaluated using Python {python_version()}",
|
||||||
icon_url="http://i.imgur.com/9EftiVK.png")
|
icon_url="http://i.imgur.com/9EftiVK.png",
|
||||||
|
)
|
||||||
await ctx.send(embed=sfooem)
|
await ctx.send(embed=sfooem)
|
||||||
else:
|
else:
|
||||||
self._last_result = ret
|
self._last_result = ret
|
||||||
ssfooem = discord.Embed(color=0x170041)
|
ssfooem = discord.Embed(color=0x170041)
|
||||||
ssfooem.add_field(name="Code evaluation was successful!",
|
ssfooem.add_field(
|
||||||
value=f'```\n{value}{ret}\n```')
|
name="Code evaluation was successful!",
|
||||||
|
value=f"```\n{value}{ret}\n```",
|
||||||
|
)
|
||||||
ssfooem.set_footer(
|
ssfooem.set_footer(
|
||||||
text=f"Evaluated using Python {python_version()}",
|
text=f"Evaluated using Python {python_version()}",
|
||||||
icon_url="http://i.imgur.com/9EftiVK.png")
|
icon_url="http://i.imgur.com/9EftiVK.png",
|
||||||
|
)
|
||||||
await ctx.send(embed=ssfooem)
|
await ctx.send(embed=ssfooem)
|
||||||
|
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
@commands.command(hidden=True, aliases=['exec'])
|
@commands.command(hidden=True, aliases=["exec"])
|
||||||
async def execute(self, ctx, *, text: str):
|
async def execute(self, ctx, *, text: str):
|
||||||
""" Do a shell command. """
|
"""Do a shell command."""
|
||||||
message = await ctx.send(f"Loading...")
|
message = await ctx.send(f"Loading...")
|
||||||
proc = await asyncio.create_subprocess_shell(text,
|
proc = await asyncio.create_subprocess_shell(
|
||||||
stdin=None,
|
text, stdin=None, stderr=PIPE, stdout=PIPE
|
||||||
stderr=PIPE,
|
)
|
||||||
stdout=PIPE)
|
out = (await proc.stdout.read()).decode("utf-8").strip()
|
||||||
out = (await proc.stdout.read()).decode('utf-8').strip()
|
err = (await proc.stderr.read()).decode("utf-8").strip()
|
||||||
err = (await proc.stderr.read()).decode('utf-8').strip()
|
|
||||||
|
|
||||||
if not out and not err:
|
if not out and not err:
|
||||||
await message.delete()
|
await message.delete()
|
||||||
return await ctx.message.add_reaction('👌')
|
return await ctx.message.add_reaction("👌")
|
||||||
|
|
||||||
content = ""
|
content = ""
|
||||||
|
|
||||||
@@ -178,12 +190,12 @@ class OwnerCog(commands.Cog):
|
|||||||
|
|
||||||
if len(content) > 1500:
|
if len(content) > 1500:
|
||||||
try:
|
try:
|
||||||
data = BytesIO(content.encode('utf-8'))
|
data = BytesIO(content.encode("utf-8"))
|
||||||
await message.delete()
|
await message.delete()
|
||||||
await ctx.send(content=f"The result was a bit too long..",
|
await ctx.send(
|
||||||
file=discord.File(
|
content=f"The result was a bit too long..",
|
||||||
data,
|
file=discord.File(data, filename=f"result_{int(time.time())}.txt"),
|
||||||
filename=f"result_{int(time.time())}.txt"))
|
)
|
||||||
except asyncio.TimeoutError as e:
|
except asyncio.TimeoutError as e:
|
||||||
await message.delete()
|
await message.delete()
|
||||||
return await ctx.send(e)
|
return await ctx.send(e)
|
||||||
@@ -191,5 +203,5 @@ class OwnerCog(commands.Cog):
|
|||||||
await message.edit(content=f"```fix\n{content}\n```")
|
await message.edit(content=f"```fix\n{content}\n```")
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: ChristmasBot):
|
||||||
bot.add_cog(OwnerCog(bot))
|
bot.add_cog(OwnerCog(bot))
|
||||||
|
|||||||
+9
-16
@@ -1,33 +1,26 @@
|
|||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from utils.database import AutoJoin
|
|
||||||
import discord
|
|
||||||
from utils.EmbedGenerator import EmbedGenerator
|
from utils.EmbedGenerator import EmbedGenerator
|
||||||
|
from bot import ChristmasBot
|
||||||
from discord.ext.commands import Context
|
from discord.ext.commands import Context
|
||||||
|
|
||||||
|
|
||||||
class SettingsCog(commands.Cog, name="Settings"):
|
class SettingsCog(commands.Cog, name="Settings"):
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: ChristmasBot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
@commands.command(name='placeholder', hidden=True)
|
|
||||||
@commands.is_owner()
|
|
||||||
async def placeholder(self, ctx):
|
|
||||||
"""Placeholder Command"""
|
|
||||||
|
|
||||||
await ctx.send("Pong!")
|
|
||||||
|
|
||||||
@commands.group(aliases=["aj"], invoke_without_command=True)
|
@commands.group(aliases=["aj"], invoke_without_command=True)
|
||||||
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
||||||
async def autojoin(self, ctx):
|
async def autojoin(self, ctx: Context):
|
||||||
await EmbedGenerator.Message(
|
await EmbedGenerator.Message(
|
||||||
ctx, "Autojoin",
|
ctx,
|
||||||
f"Usage:\n\n`{ctx.prefix}autojoin set`\n`{ctx.prefix}autojoin unset`"
|
"Autojoin",
|
||||||
|
f"Usage:\n\n`{ctx.prefix}autojoin set`\n`{ctx.prefix}autojoin unset`",
|
||||||
)
|
)
|
||||||
|
|
||||||
@autojoin.command(name="set")
|
@autojoin.command(name="set")
|
||||||
@commands.has_permissions(manage_channels=True)
|
@commands.has_permissions(manage_channels=True)
|
||||||
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
||||||
async def autojoin_set(self, ctx):
|
async def autojoin_set(self, ctx: Context):
|
||||||
vc = ctx.author.voice.channel
|
vc = ctx.author.voice.channel
|
||||||
await AutoJoin.update_channel(self.bot, ctx.guild.id, vc.id)
|
await AutoJoin.update_channel(self.bot, ctx.guild.id, vc.id)
|
||||||
await EmbedGenerator.Message(ctx, "Autojoin", "`enabled`")
|
await EmbedGenerator.Message(ctx, "Autojoin", "`enabled`")
|
||||||
@@ -35,11 +28,11 @@ class SettingsCog(commands.Cog, name="Settings"):
|
|||||||
@autojoin.command(name="unset")
|
@autojoin.command(name="unset")
|
||||||
@commands.has_permissions(manage_channels=True)
|
@commands.has_permissions(manage_channels=True)
|
||||||
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
@commands.cooldown(rate=1, per=5, type=commands.BucketType.user)
|
||||||
async def autojoin_del(self, ctx):
|
async def autojoin_del(self, ctx: Context):
|
||||||
vc = ctx.author.voice.channel
|
vc = ctx.author.voice.channel
|
||||||
await AutoJoin.del_channel(self.bot, ctx.guild.id)
|
await AutoJoin.del_channel(self.bot, ctx.guild.id)
|
||||||
await EmbedGenerator.Message(ctx, "Autojoin", "`disabled`")
|
await EmbedGenerator.Message(ctx, "Autojoin", "`disabled`")
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot: ChristmasBot):
|
||||||
bot.add_cog(SettingsCog(bot))
|
bot.add_cog(SettingsCog(bot))
|
||||||
|
|||||||
Generated
+535
@@ -0,0 +1,535 @@
|
|||||||
|
[[package]]
|
||||||
|
name = "aiohttp"
|
||||||
|
version = "3.6.3"
|
||||||
|
description = "Async http client/server framework (asyncio)"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5.3"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
async-timeout = ">=3.0,<4.0"
|
||||||
|
attrs = ">=17.3.0"
|
||||||
|
chardet = ">=2.0,<4.0"
|
||||||
|
multidict = ">=4.5,<5.0"
|
||||||
|
yarl = ">=1.0,<1.6.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
speedups = ["aiodns", "brotlipy", "cchardet"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-timeout"
|
||||||
|
version = "3.0.1"
|
||||||
|
description = "Timeout context manager for asyncio programs"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5.3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "attrs"
|
||||||
|
version = "21.2.0"
|
||||||
|
description = "Classes Without Boilerplate"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
|
||||||
|
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
|
||||||
|
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
|
||||||
|
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "black"
|
||||||
|
version = "21.9b0"
|
||||||
|
description = "The uncompromising code formatter."
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6.2"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
click = ">=7.1.2"
|
||||||
|
mypy-extensions = ">=0.4.3"
|
||||||
|
pathspec = ">=0.9.0,<1"
|
||||||
|
platformdirs = ">=2"
|
||||||
|
regex = ">=2020.1.8"
|
||||||
|
tomli = ">=0.2.6,<2.0.0"
|
||||||
|
typing-extensions = [
|
||||||
|
{version = ">=3.10.0.0", markers = "python_version < \"3.10\""},
|
||||||
|
{version = "!=3.10.0.1", markers = "python_version >= \"3.10\""},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
colorama = ["colorama (>=0.4.3)"]
|
||||||
|
d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"]
|
||||||
|
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||||
|
python2 = ["typed-ast (>=1.4.2)"]
|
||||||
|
uvloop = ["uvloop (>=0.15.2)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cffi"
|
||||||
|
version = "1.15.0"
|
||||||
|
description = "Foreign Function Interface for Python calling C code."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pycparser = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chardet"
|
||||||
|
version = "3.0.4"
|
||||||
|
description = "Universal encoding detector for Python 2 and 3"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "8.0.3"
|
||||||
|
description = "Composable command line interface toolkit"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.4"
|
||||||
|
description = "Cross-platform colored terminal text."
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "discord.py"
|
||||||
|
version = "2.0.0a3661+g96153bb1"
|
||||||
|
description = "A Python wrapper for the Discord API"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8.0"
|
||||||
|
develop = false
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
aiohttp = ">=3.6.0,<3.8.0"
|
||||||
|
orjson = {version = ">=3.5.4", optional = true, markers = "extra == \"speed\""}
|
||||||
|
PyNaCl = {version = ">=1.3.0,<1.5", optional = true, markers = "extra == \"voice\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["sphinx (==4.0.2)", "sphinxcontrib-trio (==1.1.2)", "sphinxcontrib-websupport"]
|
||||||
|
speed = ["orjson (>=3.5.4)"]
|
||||||
|
voice = ["PyNaCl (>=1.3.0,<1.5)"]
|
||||||
|
|
||||||
|
[package.source]
|
||||||
|
type = "git"
|
||||||
|
url = "https://github.com/iDevision/enhanced-discord.py"
|
||||||
|
reference = "2.0"
|
||||||
|
resolved_reference = "96153bb177d5a9e0be81f8c05e57d8777f4cd926"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humanize"
|
||||||
|
version = "3.12.0"
|
||||||
|
description = "Python humanize utilities"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
tests = ["freezegun", "pytest", "pytest-cov"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "3.3"
|
||||||
|
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lavalink"
|
||||||
|
version = "3.1.4"
|
||||||
|
description = "A lavalink interface built for discord.py"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
aiohttp = ">=3.6.0,<3.7.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
development = ["pylint", "flake8"]
|
||||||
|
docs = ["sphinx", "pygments", "guzzle-sphinx-theme"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multidict"
|
||||||
|
version = "4.7.6"
|
||||||
|
description = "multidict implementation"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mypy-extensions"
|
||||||
|
version = "0.4.3"
|
||||||
|
description = "Experimental type system extensions for programs checked with the mypy typechecker."
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "orjson"
|
||||||
|
version = "3.6.4"
|
||||||
|
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pathspec"
|
||||||
|
version = "0.9.0"
|
||||||
|
description = "Utility library for gitignore style pattern matching of file paths."
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "platformdirs"
|
||||||
|
version = "2.4.0"
|
||||||
|
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"]
|
||||||
|
test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycparser"
|
||||||
|
version = "2.20"
|
||||||
|
description = "C parser in Python"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pynacl"
|
||||||
|
version = "1.4.0"
|
||||||
|
description = "Python binding to the Networking and Cryptography (NaCl) library"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
cffi = ">=1.4.1"
|
||||||
|
six = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"]
|
||||||
|
tests = ["pytest (>=3.2.1,!=3.3.0)", "hypothesis (>=3.27.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "2021.10.23"
|
||||||
|
description = "Alternative regular expression module, to replace re."
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "six"
|
||||||
|
version = "1.16.0"
|
||||||
|
description = "Python 2 and 3 compatibility utilities"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomli"
|
||||||
|
version = "1.2.2"
|
||||||
|
description = "A lil' TOML parser"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-extensions"
|
||||||
|
version = "3.10.0.2"
|
||||||
|
description = "Backported and Experimental Type Hints for Python 3.5+"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yarl"
|
||||||
|
version = "1.5.1"
|
||||||
|
description = "Yet another URL library"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
idna = ">=2.0"
|
||||||
|
multidict = ">=4.0"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
lock-version = "1.1"
|
||||||
|
python-versions = "^3.8"
|
||||||
|
content-hash = "fc38f4742a2189475a175fe2ec93ca9fe6509ddec3d64bc6f5dfbd53ef9816c7"
|
||||||
|
|
||||||
|
[metadata.files]
|
||||||
|
aiohttp = [
|
||||||
|
{file = "aiohttp-3.6.3-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:1a4160579ffbc1b69e88cb6ca8bb0fbd4947dfcbf9fb1e2a4fc4c7a4a986c1fe"},
|
||||||
|
{file = "aiohttp-3.6.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:fb83326d8295e8840e4ba774edf346e87eca78ba8a89c55d2690352842c15ba5"},
|
||||||
|
{file = "aiohttp-3.6.3-cp35-cp35m-win32.whl", hash = "sha256:470e4c90da36b601676fe50c49a60d34eb8c6593780930b1aa4eea6f508dfa37"},
|
||||||
|
{file = "aiohttp-3.6.3-cp35-cp35m-win_amd64.whl", hash = "sha256:a885432d3cabc1287bcf88ea94e1826d3aec57fd5da4a586afae4591b061d40d"},
|
||||||
|
{file = "aiohttp-3.6.3-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:c506853ba52e516b264b106321c424d03f3ddef2813246432fa9d1cefd361c81"},
|
||||||
|
{file = "aiohttp-3.6.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:797456399ffeef73172945708810f3277f794965eb6ec9bd3a0c007c0476be98"},
|
||||||
|
{file = "aiohttp-3.6.3-cp36-cp36m-win32.whl", hash = "sha256:60f4caa3b7f7a477f66ccdd158e06901e1d235d572283906276e3803f6b098f5"},
|
||||||
|
{file = "aiohttp-3.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:2ad493de47a8f926386fa6d256832de3095ba285f325db917c7deae0b54a9fc8"},
|
||||||
|
{file = "aiohttp-3.6.3-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:319b490a5e2beaf06891f6711856ea10591cfe84fe9f3e71a721aa8f20a0872a"},
|
||||||
|
{file = "aiohttp-3.6.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:66d64486172b032db19ea8522328b19cfb78a3e1e5b62ab6a0567f93f073dea0"},
|
||||||
|
{file = "aiohttp-3.6.3-cp37-cp37m-win32.whl", hash = "sha256:206c0ccfcea46e1bddc91162449c20c72f308aebdcef4977420ef329c8fcc599"},
|
||||||
|
{file = "aiohttp-3.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:687461cd974722110d1763b45c5db4d2cdee8d50f57b00c43c7590d1dd77fc5c"},
|
||||||
|
{file = "aiohttp-3.6.3.tar.gz", hash = "sha256:698cd7bc3c7d1b82bb728bae835724a486a8c376647aec336aa21a60113c3645"},
|
||||||
|
]
|
||||||
|
async-timeout = [
|
||||||
|
{file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"},
|
||||||
|
{file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"},
|
||||||
|
]
|
||||||
|
attrs = [
|
||||||
|
{file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
|
||||||
|
{file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
|
||||||
|
]
|
||||||
|
black = [
|
||||||
|
{file = "black-21.9b0-py3-none-any.whl", hash = "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115"},
|
||||||
|
{file = "black-21.9b0.tar.gz", hash = "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"},
|
||||||
|
]
|
||||||
|
cffi = [
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"},
|
||||||
|
{file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"},
|
||||||
|
]
|
||||||
|
chardet = [
|
||||||
|
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
|
||||||
|
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
|
||||||
|
]
|
||||||
|
click = [
|
||||||
|
{file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"},
|
||||||
|
{file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"},
|
||||||
|
]
|
||||||
|
colorama = [
|
||||||
|
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
||||||
|
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
|
||||||
|
]
|
||||||
|
"discord.py" = []
|
||||||
|
humanize = [
|
||||||
|
{file = "humanize-3.12.0-py3-none-any.whl", hash = "sha256:4c71c4381f0209715cd993058e717c1b74d58ae2f8c6da7bdb59ab66473b9ab0"},
|
||||||
|
{file = "humanize-3.12.0.tar.gz", hash = "sha256:5ec1a66e230a3e31fb3f184aab9436ea13d4e37c168e0ffc345ae5bb57e58be6"},
|
||||||
|
]
|
||||||
|
idna = [
|
||||||
|
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
|
||||||
|
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
|
||||||
|
]
|
||||||
|
lavalink = [
|
||||||
|
{file = "lavalink-3.1.4.tar.gz", hash = "sha256:c030488391e27cdc1e3ee3093817c38848ebd0d1c7bcf0d6cd0f40b9b00a4e0c"},
|
||||||
|
]
|
||||||
|
multidict = [
|
||||||
|
{file = "multidict-4.7.6-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:275ca32383bc5d1894b6975bb4ca6a7ff16ab76fa622967625baeebcf8079000"},
|
||||||
|
{file = "multidict-4.7.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1ece5a3369835c20ed57adadc663400b5525904e53bae59ec854a5d36b39b21a"},
|
||||||
|
{file = "multidict-4.7.6-cp35-cp35m-win32.whl", hash = "sha256:5141c13374e6b25fe6bf092052ab55c0c03d21bd66c94a0e3ae371d3e4d865a5"},
|
||||||
|
{file = "multidict-4.7.6-cp35-cp35m-win_amd64.whl", hash = "sha256:9456e90649005ad40558f4cf51dbb842e32807df75146c6d940b6f5abb4a78f3"},
|
||||||
|
{file = "multidict-4.7.6-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:e0d072ae0f2a179c375f67e3da300b47e1a83293c554450b29c900e50afaae87"},
|
||||||
|
{file = "multidict-4.7.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3750f2205b800aac4bb03b5ae48025a64e474d2c6cc79547988ba1d4122a09e2"},
|
||||||
|
{file = "multidict-4.7.6-cp36-cp36m-win32.whl", hash = "sha256:f07acae137b71af3bb548bd8da720956a3bc9f9a0b87733e0899226a2317aeb7"},
|
||||||
|
{file = "multidict-4.7.6-cp36-cp36m-win_amd64.whl", hash = "sha256:6513728873f4326999429a8b00fc7ceddb2509b01d5fd3f3be7881a257b8d463"},
|
||||||
|
{file = "multidict-4.7.6-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:feed85993dbdb1dbc29102f50bca65bdc68f2c0c8d352468c25b54874f23c39d"},
|
||||||
|
{file = "multidict-4.7.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fcfbb44c59af3f8ea984de67ec7c306f618a3ec771c2843804069917a8f2e255"},
|
||||||
|
{file = "multidict-4.7.6-cp37-cp37m-win32.whl", hash = "sha256:4538273208e7294b2659b1602490f4ed3ab1c8cf9dbdd817e0e9db8e64be2507"},
|
||||||
|
{file = "multidict-4.7.6-cp37-cp37m-win_amd64.whl", hash = "sha256:d14842362ed4cf63751648e7672f7174c9818459d169231d03c56e84daf90b7c"},
|
||||||
|
{file = "multidict-4.7.6-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:c026fe9a05130e44157b98fea3ab12969e5b60691a276150db9eda71710cd10b"},
|
||||||
|
{file = "multidict-4.7.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:51a4d210404ac61d32dada00a50ea7ba412e6ea945bbe992e4d7a595276d2ec7"},
|
||||||
|
{file = "multidict-4.7.6-cp38-cp38-win32.whl", hash = "sha256:5cf311a0f5ef80fe73e4f4c0f0998ec08f954a6ec72b746f3c179e37de1d210d"},
|
||||||
|
{file = "multidict-4.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:7388d2ef3c55a8ba80da62ecfafa06a1c097c18032a501ffd4cabbc52d7f2b19"},
|
||||||
|
{file = "multidict-4.7.6.tar.gz", hash = "sha256:fbb77a75e529021e7c4a8d4e823d88ef4d23674a202be4f5addffc72cbb91430"},
|
||||||
|
]
|
||||||
|
mypy-extensions = [
|
||||||
|
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
|
||||||
|
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
|
||||||
|
]
|
||||||
|
orjson = [
|
||||||
|
{file = "orjson-3.6.4-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:fc01a15f3101628fd619158daec79b30d7461149735e73542ca8c13be6b835be"},
|
||||||
|
{file = "orjson-3.6.4-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:48a69fed90f551bf9e9bb7a63e363fed4f67fc7c6e6bfb057054dc78f6721e9e"},
|
||||||
|
{file = "orjson-3.6.4-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:3722f02f50861d5e2a6be9d50bfe8da27a5155bb60043118a4e1ceb8c7040cf7"},
|
||||||
|
{file = "orjson-3.6.4-cp310-none-win_amd64.whl", hash = "sha256:231a99a728322d0271e970b149c57deb67315e6837e6cd4166cf51d30161700c"},
|
||||||
|
{file = "orjson-3.6.4-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:6cd300421b41f7e84e388b1792a18c3fc4c440ae3039434b9320956be05f0102"},
|
||||||
|
{file = "orjson-3.6.4-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e55ef66ee1d35b1c43db275aff3a1ba7e0408b31e624912a612bd799df14e73e"},
|
||||||
|
{file = "orjson-3.6.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef8d332af8e6f7d6d2c1f3b5384c8d239800c1405b136da5f1710e802918d57"},
|
||||||
|
{file = "orjson-3.6.4-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:8896e242a92733e454378e22711bd43a55fda4e80604fcefcc064ca977623673"},
|
||||||
|
{file = "orjson-3.6.4-cp37-cp37m-manylinux_2_24_x86_64.whl", hash = "sha256:bdfa6f29f7b6aad70ce14591b99fba651008afa6bc3759f158887bcdc568b452"},
|
||||||
|
{file = "orjson-3.6.4-cp37-none-win_amd64.whl", hash = "sha256:7c16c44872d33da0b97050a9ea8f7bc04e930c56e8185657bc200e1875a671da"},
|
||||||
|
{file = "orjson-3.6.4-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:b467551f3be1dd08aff70c261cc883b63483eb0e31861ffe2cd8dac4fec7cfa9"},
|
||||||
|
{file = "orjson-3.6.4-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:7bf61afef12f6416db3ea377f3491ca8ac677d3cac6db1ebffb7a5fe92cce3ca"},
|
||||||
|
{file = "orjson-3.6.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:014ea74d4a5dd6a7e98540768072d5bd8c2fedbcbbedcbbaecbb614e66080e81"},
|
||||||
|
{file = "orjson-3.6.4-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:705cb90c536b4b9336c06b4a62c3c62e50354ddf20a2e48eb62bf34fb93d5b1f"},
|
||||||
|
{file = "orjson-3.6.4-cp38-cp38-manylinux_2_24_x86_64.whl", hash = "sha256:159e2240fc36720a5cb51a1cbc9905dcb8758aad50b3e7f14f6178ce2e842004"},
|
||||||
|
{file = "orjson-3.6.4-cp38-none-win_amd64.whl", hash = "sha256:d2ae087866a1050de83c2a28490850badb41aeeb8a4605c84dd6004d4e58b5a4"},
|
||||||
|
{file = "orjson-3.6.4-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:b4a7efe039b1154b23e5df8787ac01e4621213aed303b6304a5f8ad89c01455d"},
|
||||||
|
{file = "orjson-3.6.4-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:7b24f97ed76005f447e152b0e493abce8c60f010131998295175446312a71caf"},
|
||||||
|
{file = "orjson-3.6.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1121187e2a721864b52e5dbb3cf8dd4a4546519a5fef1e13fa777347fb8884a2"},
|
||||||
|
{file = "orjson-3.6.4-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:4edffd9e2298ff4f4f939aa67248eba043dc65c9e7d940c28a62c5502c6f2aa8"},
|
||||||
|
{file = "orjson-3.6.4-cp39-cp39-manylinux_2_24_x86_64.whl", hash = "sha256:e236fe94d8a77532f0065870fe265bd53e229012f39af99f79f5f1d4a8b0067c"},
|
||||||
|
{file = "orjson-3.6.4-cp39-none-win_amd64.whl", hash = "sha256:5448cc1edd4c4bafc968404f92f0e9a582b4326ca442346bd1d1179a6faf52d9"},
|
||||||
|
{file = "orjson-3.6.4.tar.gz", hash = "sha256:f8dbc428fc6d7420f231a7133d8dff4c882e64acb585dcf2fda74bdcfe1a6d9d"},
|
||||||
|
]
|
||||||
|
pathspec = [
|
||||||
|
{file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
|
||||||
|
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
|
||||||
|
]
|
||||||
|
platformdirs = [
|
||||||
|
{file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"},
|
||||||
|
{file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"},
|
||||||
|
]
|
||||||
|
pycparser = [
|
||||||
|
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
|
||||||
|
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
|
||||||
|
]
|
||||||
|
pynacl = [
|
||||||
|
{file = "PyNaCl-1.4.0-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp27-cp27m-win32.whl", hash = "sha256:2fe0fc5a2480361dcaf4e6e7cea00e078fcda07ba45f811b167e3f99e8cff574"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp27-cp27m-win_amd64.whl", hash = "sha256:f8851ab9041756003119368c1e6cd0b9c631f46d686b3904b18c0139f4419f80"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:7757ae33dae81c300487591c68790dfb5145c7d03324000433d9a2c141f82af7"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp35-abi3-macosx_10_10_x86_64.whl", hash = "sha256:757250ddb3bff1eecd7e41e65f7f833a8405fede0194319f87899690624f2122"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:30f9b96db44e09b3304f9ea95079b1b7316b2b4f3744fe3aaecccd95d547063d"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp35-abi3-win32.whl", hash = "sha256:4e10569f8cbed81cb7526ae137049759d2a8d57726d52c1a000a3ce366779634"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp35-abi3-win_amd64.whl", hash = "sha256:c914f78da4953b33d4685e3cdc7ce63401247a21425c16a39760e282075ac4a6"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp35-cp35m-win32.whl", hash = "sha256:06cbb4d9b2c4bd3c8dc0d267416aaed79906e7b33f114ddbf0911969794b1cc4"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:511d269ee845037b95c9781aa702f90ccc36036f95d0f31373a6a79bd8242e25"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp36-cp36m-win32.whl", hash = "sha256:11335f09060af52c97137d4ac54285bcb7df0cef29014a1a4efe64ac065434c4"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:cd401ccbc2a249a47a3a1724c2918fcd04be1f7b54eb2a5a71ff915db0ac51c6"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp37-cp37m-win32.whl", hash = "sha256:8122ba5f2a2169ca5da936b2e5a511740ffb73979381b4229d9188f6dcb22f1f"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:537a7ccbea22905a0ab36ea58577b39d1fa9b1884869d173b5cf111f006f689f"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp38-cp38-win32.whl", hash = "sha256:9c4a7ea4fb81536c1b1f5cc44d54a296f96ae78c1ebd2311bd0b60be45a48d96"},
|
||||||
|
{file = "PyNaCl-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7c6092102219f59ff29788860ccb021e80fffd953920c4a8653889c029b2d420"},
|
||||||
|
{file = "PyNaCl-1.4.0.tar.gz", hash = "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505"},
|
||||||
|
]
|
||||||
|
regex = [
|
||||||
|
{file = "regex-2021.10.23-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:45b65d6a275a478ac2cbd7fdbf7cc93c1982d613de4574b56fd6972ceadb8395"},
|
||||||
|
{file = "regex-2021.10.23-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74d071dbe4b53c602edd87a7476ab23015a991374ddb228d941929ad7c8c922e"},
|
||||||
|
{file = "regex-2021.10.23-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34d870f9f27f2161709054d73646fc9aca49480617a65533fc2b4611c518e455"},
|
||||||
|
{file = "regex-2021.10.23-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fb698037c35109d3c2e30f2beb499e5ebae6e4bb8ff2e60c50b9a805a716f79"},
|
||||||
|
{file = "regex-2021.10.23-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cb46b542133999580ffb691baf67410306833ee1e4f58ed06b6a7aaf4e046952"},
|
||||||
|
{file = "regex-2021.10.23-cp310-cp310-win32.whl", hash = "sha256:5e9c9e0ce92f27cef79e28e877c6b6988c48b16942258f3bc55d39b5f911df4f"},
|
||||||
|
{file = "regex-2021.10.23-cp310-cp310-win_amd64.whl", hash = "sha256:ab7c5684ff3538b67df3f93d66bd3369b749087871ae3786e70ef39e601345b0"},
|
||||||
|
{file = "regex-2021.10.23-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:de557502c3bec8e634246588a94e82f1ee1b9dfcfdc453267c4fb652ff531570"},
|
||||||
|
{file = "regex-2021.10.23-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee684f139c91e69fe09b8e83d18b4d63bf87d9440c1eb2eeb52ee851883b1b29"},
|
||||||
|
{file = "regex-2021.10.23-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5095a411c8479e715784a0c9236568ae72509450ee2226b649083730f3fadfc6"},
|
||||||
|
{file = "regex-2021.10.23-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b568809dca44cb75c8ebb260844ea98252c8c88396f9d203f5094e50a70355f"},
|
||||||
|
{file = "regex-2021.10.23-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eb672217f7bd640411cfc69756ce721d00ae600814708d35c930930f18e8029f"},
|
||||||
|
{file = "regex-2021.10.23-cp36-cp36m-win32.whl", hash = "sha256:a7a986c45d1099a5de766a15de7bee3840b1e0e1a344430926af08e5297cf666"},
|
||||||
|
{file = "regex-2021.10.23-cp36-cp36m-win_amd64.whl", hash = "sha256:6d7722136c6ed75caf84e1788df36397efdc5dbadab95e59c2bba82d4d808a4c"},
|
||||||
|
{file = "regex-2021.10.23-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9f665677e46c5a4d288ece12fdedf4f4204a422bb28ff05f0e6b08b7447796d1"},
|
||||||
|
{file = "regex-2021.10.23-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:450dc27483548214314640c89a0f275dbc557968ed088da40bde7ef8fb52829e"},
|
||||||
|
{file = "regex-2021.10.23-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:129472cd06062fb13e7b4670a102951a3e655e9b91634432cfbdb7810af9d710"},
|
||||||
|
{file = "regex-2021.10.23-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a940ca7e7189d23da2bfbb38973832813eab6bd83f3bf89a977668c2f813deae"},
|
||||||
|
{file = "regex-2021.10.23-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:530fc2bbb3dc1ebb17f70f7b234f90a1dd43b1b489ea38cea7be95fb21cdb5c7"},
|
||||||
|
{file = "regex-2021.10.23-cp37-cp37m-win32.whl", hash = "sha256:ded0c4a3eee56b57fcb2315e40812b173cafe79d2f992d50015f4387445737fa"},
|
||||||
|
{file = "regex-2021.10.23-cp37-cp37m-win_amd64.whl", hash = "sha256:391703a2abf8013d95bae39145d26b4e21531ab82e22f26cd3a181ee2644c234"},
|
||||||
|
{file = "regex-2021.10.23-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be04739a27be55631069b348dda0c81d8ea9822b5da10b8019b789e42d1fe452"},
|
||||||
|
{file = "regex-2021.10.23-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13ec99df95003f56edcd307db44f06fbeb708c4ccdcf940478067dd62353181e"},
|
||||||
|
{file = "regex-2021.10.23-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d1cdcda6bd16268316d5db1038965acf948f2a6f43acc2e0b1641ceab443623"},
|
||||||
|
{file = "regex-2021.10.23-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c186691a7995ef1db61205e00545bf161fb7b59cdb8c1201c89b333141c438a"},
|
||||||
|
{file = "regex-2021.10.23-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b20f544cbbeffe171911f6ce90388ad36fe3fad26b7c7a35d4762817e9ea69c"},
|
||||||
|
{file = "regex-2021.10.23-cp38-cp38-win32.whl", hash = "sha256:c0938ddd60cc04e8f1faf7a14a166ac939aac703745bfcd8e8f20322a7373019"},
|
||||||
|
{file = "regex-2021.10.23-cp38-cp38-win_amd64.whl", hash = "sha256:56f0c81c44638dfd0e2367df1a331b4ddf2e771366c4b9c5d9a473de75e3e1c7"},
|
||||||
|
{file = "regex-2021.10.23-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80bb5d2e92b2258188e7dcae5b188c7bf868eafdf800ea6edd0fbfc029984a88"},
|
||||||
|
{file = "regex-2021.10.23-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1dae12321b31059a1a72aaa0e6ba30156fe7e633355e445451e4021b8e122b6"},
|
||||||
|
{file = "regex-2021.10.23-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1f2b59c28afc53973d22e7bc18428721ee8ca6079becf1b36571c42627321c65"},
|
||||||
|
{file = "regex-2021.10.23-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d134757a37d8640f3c0abb41f5e68b7cf66c644f54ef1cb0573b7ea1c63e1509"},
|
||||||
|
{file = "regex-2021.10.23-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0dcc0e71118be8c69252c207630faf13ca5e1b8583d57012aae191e7d6d28b84"},
|
||||||
|
{file = "regex-2021.10.23-cp39-cp39-win32.whl", hash = "sha256:a30513828180264294953cecd942202dfda64e85195ae36c265daf4052af0464"},
|
||||||
|
{file = "regex-2021.10.23-cp39-cp39-win_amd64.whl", hash = "sha256:0f7552429dd39f70057ac5d0e897e5bfe211629652399a21671e53f2a9693a4e"},
|
||||||
|
{file = "regex-2021.10.23.tar.gz", hash = "sha256:f3f9a91d3cc5e5b0ddf1043c0ae5fa4852f18a1c0050318baf5fc7930ecc1f9c"},
|
||||||
|
]
|
||||||
|
six = [
|
||||||
|
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||||
|
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||||
|
]
|
||||||
|
tomli = [
|
||||||
|
{file = "tomli-1.2.2-py3-none-any.whl", hash = "sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade"},
|
||||||
|
{file = "tomli-1.2.2.tar.gz", hash = "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee"},
|
||||||
|
]
|
||||||
|
typing-extensions = [
|
||||||
|
{file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"},
|
||||||
|
{file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"},
|
||||||
|
{file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"},
|
||||||
|
]
|
||||||
|
yarl = [
|
||||||
|
{file = "yarl-1.5.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:db6db0f45d2c63ddb1a9d18d1b9b22f308e52c83638c26b422d520a815c4b3fb"},
|
||||||
|
{file = "yarl-1.5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:17668ec6722b1b7a3a05cc0167659f6c95b436d25a36c2d52db0eca7d3f72593"},
|
||||||
|
{file = "yarl-1.5.1-cp35-cp35m-win32.whl", hash = "sha256:040b237f58ff7d800e6e0fd89c8439b841f777dd99b4a9cca04d6935564b9409"},
|
||||||
|
{file = "yarl-1.5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:f18d68f2be6bf0e89f1521af2b1bb46e66ab0018faafa81d70f358153170a317"},
|
||||||
|
{file = "yarl-1.5.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:c52ce2883dc193824989a9b97a76ca86ecd1fa7955b14f87bf367a61b6232511"},
|
||||||
|
{file = "yarl-1.5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ce584af5de8830d8701b8979b18fcf450cef9a382b1a3c8ef189bedc408faf1e"},
|
||||||
|
{file = "yarl-1.5.1-cp36-cp36m-win32.whl", hash = "sha256:df89642981b94e7db5596818499c4b2219028f2a528c9c37cc1de45bf2fd3a3f"},
|
||||||
|
{file = "yarl-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:3a584b28086bc93c888a6c2aa5c92ed1ae20932f078c46509a66dce9ea5533f2"},
|
||||||
|
{file = "yarl-1.5.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:da456eeec17fa8aa4594d9a9f27c0b1060b6a75f2419fe0c00609587b2695f4a"},
|
||||||
|
{file = "yarl-1.5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bc2f976c0e918659f723401c4f834deb8a8e7798a71be4382e024bcc3f7e23a8"},
|
||||||
|
{file = "yarl-1.5.1-cp37-cp37m-win32.whl", hash = "sha256:4439be27e4eee76c7632c2427ca5e73703151b22cae23e64adb243a9c2f565d8"},
|
||||||
|
{file = "yarl-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:48e918b05850fffb070a496d2b5f97fc31d15d94ca33d3d08a4f86e26d4e7c5d"},
|
||||||
|
{file = "yarl-1.5.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9b930776c0ae0c691776f4d2891ebc5362af86f152dd0da463a6614074cb1b02"},
|
||||||
|
{file = "yarl-1.5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b3b9ad80f8b68519cc3372a6ca85ae02cc5a8807723ac366b53c0f089db19e4a"},
|
||||||
|
{file = "yarl-1.5.1-cp38-cp38-win32.whl", hash = "sha256:f379b7f83f23fe12823085cd6b906edc49df969eb99757f58ff382349a3303c6"},
|
||||||
|
{file = "yarl-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:9102b59e8337f9874638fcfc9ac3734a0cfadb100e47d55c20d0dc6087fb4692"},
|
||||||
|
{file = "yarl-1.5.1.tar.gz", hash = "sha256:c22c75b5f394f3d47105045ea551e08a3e804dc7e01b37800ca35b58f856c3d6"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "christmasbot"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["Your Name <you@example.com>"]
|
||||||
|
license = "GPL-v3.0"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.8"
|
||||||
|
lavalink = "^3.1.4"
|
||||||
|
humanize = "^3.12.0"
|
||||||
|
"discord.py" = { git = "https://github.com/iDevision/enhanced-discord.py", branch = "2.0", extras = ["voice", "speed"] }
|
||||||
|
|
||||||
|
[tool.poetry.dev-dependencies]
|
||||||
|
black = {version = "^21.9b0", allow-prereleases = true}
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core>=1.0.0"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import sqlalchemy as sa
|
|
||||||
from .autojoin import table as autojoin
|
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
|
|
||||||
def get_tables(metadata: sa.MetaData) -> Dict[str, sa.Table]:
|
|
||||||
return {name: table for name, table in [autojoin(metadata)]}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
def table(metadata: sa.MetaData) -> sa.Table:
|
|
||||||
tablename = 'autojoin'
|
|
||||||
|
|
||||||
tableobject = sa.Table(
|
|
||||||
tablename, metadata,
|
|
||||||
sa.Column('guild_id', sa.BigInteger, primary_key=True),
|
|
||||||
sa.Column('channel_id', sa.BigInteger))
|
|
||||||
|
|
||||||
return (tablename, tableobject)
|
|
||||||
+10
-16
@@ -7,26 +7,21 @@ from discord.ext.commands import Context
|
|||||||
|
|
||||||
class EmbedGenerator:
|
class EmbedGenerator:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def Error(ctx: Context, message: str, **kwargs):
|
async def Error(ctx: Context, message: str, **kwargs) -> Embed:
|
||||||
color = ctx.bot.colors["embed"]
|
color = ctx.bot.colors["embed"]
|
||||||
em = Embed(title='Error:', description=message, color=color)
|
em = Embed(title="Error:", description=message, color=color)
|
||||||
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def Message(ctx: Context,
|
async def Message(ctx: Context, title: str, message: Optional[str] = "", **kwargs):
|
||||||
title: str,
|
|
||||||
message: Optional[str] = '',
|
|
||||||
**kwargs):
|
|
||||||
color = ctx.bot.colors["embed"]
|
color = ctx.bot.colors["embed"]
|
||||||
em = Embed(title=title, description=message, color=color)
|
em = Embed(title=title, description=message, color=color)
|
||||||
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def Image(ctx: Context,
|
async def Image(
|
||||||
title: str,
|
ctx: Context, title: str, url: str, message: Optional[str] = "", **kwargs
|
||||||
url: str,
|
):
|
||||||
message: Optional[str] = '',
|
|
||||||
**kwargs):
|
|
||||||
color = ctx.bot.colors["embed"]
|
color = ctx.bot.colors["embed"]
|
||||||
em = Embed(title=title, description=message, url=url, color=color)
|
em = Embed(title=title, description=message, url=url, color=color)
|
||||||
em.set_image(url=url)
|
em.set_image(url=url)
|
||||||
@@ -39,10 +34,9 @@ class EmbedGenerator:
|
|||||||
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def SendWithFooter(ctx: Context, em: Embed,
|
async def SendWithFooter(ctx: Context, em: Embed, **kwargs) -> discord.Message:
|
||||||
**kwargs) -> discord.Message:
|
avatar = ctx.author.avatar.with_static_format("jpeg")
|
||||||
avatar = ctx.author.avatar_url_as()
|
em.set_footer(text=f"Requested by: {ctx.author}", icon_url=avatar)
|
||||||
em.set_footer(text=f'Requested by: {ctx.author}', icon_url=avatar)
|
if kwargs.get("no_send", False):
|
||||||
if kwargs.get('no_send', False):
|
|
||||||
return em
|
return em
|
||||||
return await ctx.send(embed=em, **kwargs)
|
return await ctx.send(embed=em, **kwargs)
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import aiomysql
|
|
||||||
import asyncio
|
|
||||||
from bot import CloudKid
|
|
||||||
from aiomysql.sa import SAConnection
|
|
||||||
from sqlalchemy import Table
|
|
||||||
from typing import Sequence
|
|
||||||
|
|
||||||
|
|
||||||
class AutoJoin:
|
|
||||||
@staticmethod
|
|
||||||
async def get_channels(bot: CloudKid) -> Sequence[tuple]:
|
|
||||||
autojoin: Table = bot.database.tables["autojoin"]
|
|
||||||
conn: SAConnection = await bot.database.engine.acquire()
|
|
||||||
result = await conn.execute(autojoin.select())
|
|
||||||
channels: Sequence[tuple] = await result.fetchall()
|
|
||||||
return channels
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def update_channel(bot, guild_id, channel_id):
|
|
||||||
autojoin: Table = bot.database.tables["autojoin"]
|
|
||||||
conn: SAConnection = await bot.database.engine.acquire()
|
|
||||||
await conn.execute(autojoin.insert().values({
|
|
||||||
"guild_id": guild_id,
|
|
||||||
"channel_id": channel_id
|
|
||||||
}))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def del_channel(bot, guild_id):
|
|
||||||
autojoin: Table = bot.database.tables["autojoin"]
|
|
||||||
conn: SAConnection = await bot.database.engine.acquire()
|
|
||||||
await conn.execute(
|
|
||||||
autojoin.delete().where(autojoin.c.guild_id == guild_id))
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
import re
|
|
||||||
import struct
|
|
||||||
import sys
|
|
||||||
import urllib.request as urllib2
|
|
||||||
import aiohttp
|
|
||||||
|
|
||||||
key = "b9803d262fab977f:04c791f69496359d638fc634e60c08d0"
|
|
||||||
|
|
||||||
|
|
||||||
def hasNumbers(inputString):
|
|
||||||
return any(char.isdigit() for char in inputString)
|
|
||||||
|
|
||||||
|
|
||||||
def process_stream_title(title: str) -> list:
|
|
||||||
l = title.split(' - ', 1)
|
|
||||||
if l[0].isdigit():
|
|
||||||
return l[1].rsplit(" - ", 1)
|
|
||||||
return title.rsplit(" - ", 1)
|
|
||||||
|
|
||||||
|
|
||||||
async def fetch_metadata():
|
|
||||||
url = "https://azuracast.exobot.site/api/nowplaying"
|
|
||||||
async with aiohttp.ClientSession() as session:
|
|
||||||
async with session.get(url) as response:
|
|
||||||
data = await response.json()
|
|
||||||
source = data["playing_next"]["text"]
|
|
||||||
name, vid = process_stream_title(source["title"])
|
|
||||||
return {"name": name, "thumbnail": data["playing_next"]["art"]}
|
|
||||||
|
|
||||||
|
|
||||||
async def get_metadata():
|
|
||||||
"""Deprecated: use fetch_metadata()"""
|
|
||||||
url = 'https://icecast.exobot.site/stream' # radio stream
|
|
||||||
encoding = 'iso-8859-1' # default: iso-8859-1 for mp3 and utf-8 for ogg streams
|
|
||||||
request = urllib2.Request(url, headers={'Icy-MetaData':
|
|
||||||
1}) # request metadata
|
|
||||||
response = urllib2.urlopen(request)
|
|
||||||
# print(response.headers, file=sys.stderr)
|
|
||||||
metaint = int(response.headers['icy-metaint'])
|
|
||||||
for _ in range(10): # title may be empty initially, try several times
|
|
||||||
response.read(metaint) # skip to metadata
|
|
||||||
metadata_length = struct.unpack(
|
|
||||||
'B', response.read(1))[0] * 16 # length byte
|
|
||||||
metadata = response.read(metadata_length).rstrip(b'\0')
|
|
||||||
# print(metadata, file=sys.stderr)
|
|
||||||
# extract title from the metadata
|
|
||||||
m = re.search(br"StreamTitle='([^']*)';", metadata)
|
|
||||||
if m:
|
|
||||||
title = m.group(1)
|
|
||||||
if title:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
sys.exit('no title found')
|
|
||||||
|
|
||||||
title = title.decode(encoding, errors='replace')
|
|
||||||
#print(f"DEBUG: {title}")
|
|
||||||
if hasNumbers(str(title[:4])):
|
|
||||||
return title[7:][:-14]
|
|
||||||
else:
|
|
||||||
return title[:-14]
|
|
||||||
+192
-169
@@ -43,13 +43,10 @@ class Pages:
|
|||||||
permissions: discord.Permissions
|
permissions: discord.Permissions
|
||||||
Our permissions for the channel.
|
Our permissions for the channel.
|
||||||
"""
|
"""
|
||||||
def __init__(self,
|
|
||||||
ctx,
|
def __init__(
|
||||||
*,
|
self, ctx, *, entries, per_page=12, show_entry_count=True, hide_no_results=False
|
||||||
entries,
|
):
|
||||||
per_page=12,
|
|
||||||
show_entry_count=True,
|
|
||||||
hide_no_results=False):
|
|
||||||
self.hide_no_results = hide_no_results
|
self.hide_no_results = hide_no_results
|
||||||
self.bot = ctx.bot
|
self.bot = ctx.bot
|
||||||
self.entries = entries
|
self.entries = entries
|
||||||
@@ -65,15 +62,19 @@ class Pages:
|
|||||||
self.paginating = len(entries) > per_page
|
self.paginating = len(entries) > per_page
|
||||||
self.show_entry_count = show_entry_count
|
self.show_entry_count = show_entry_count
|
||||||
self.reaction_emojis = [
|
self.reaction_emojis = [
|
||||||
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}',
|
(
|
||||||
self.first_page),
|
"\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}",
|
||||||
('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page),
|
self.first_page,
|
||||||
('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page),
|
),
|
||||||
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}',
|
("\N{BLACK LEFT-POINTING TRIANGLE}", self.previous_page),
|
||||||
self.last_page),
|
("\N{BLACK RIGHT-POINTING TRIANGLE}", self.next_page),
|
||||||
('\N{INPUT SYMBOL FOR NUMBERS}', self.numbered_page),
|
(
|
||||||
('\N{BLACK SQUARE FOR STOP}', self.stop_pages),
|
"\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}",
|
||||||
('\N{INFORMATION SOURCE}', self.show_help),
|
self.last_page,
|
||||||
|
),
|
||||||
|
("\N{INPUT SYMBOL FOR NUMBERS}", self.numbered_page),
|
||||||
|
("\N{BLACK SQUARE FOR STOP}", self.stop_pages),
|
||||||
|
("\N{INFORMATION SOURCE}", self.show_help),
|
||||||
]
|
]
|
||||||
|
|
||||||
if ctx.guild is not None:
|
if ctx.guild is not None:
|
||||||
@@ -82,63 +83,64 @@ class Pages:
|
|||||||
self.permissions = self.channel.permissions_for(ctx.bot.user)
|
self.permissions = self.channel.permissions_for(ctx.bot.user)
|
||||||
|
|
||||||
if not self.permissions.embed_links:
|
if not self.permissions.embed_links:
|
||||||
raise CannotPaginate('Bot does not have embed links permission.')
|
raise CannotPaginate("Bot does not have embed links permission.")
|
||||||
|
|
||||||
if not self.permissions.send_messages:
|
if not self.permissions.send_messages:
|
||||||
raise CannotPaginate('Bot cannot send messages.')
|
raise CannotPaginate("Bot cannot send messages.")
|
||||||
|
|
||||||
if self.paginating:
|
if self.paginating:
|
||||||
# verify we can actually use the pagination session
|
# verify we can actually use the pagination session
|
||||||
if not self.permissions.add_reactions:
|
if not self.permissions.add_reactions:
|
||||||
raise CannotPaginate(
|
raise CannotPaginate("Bot does not have add reactions permission.")
|
||||||
'Bot does not have add reactions permission.')
|
|
||||||
|
|
||||||
if not self.permissions.read_message_history:
|
if not self.permissions.read_message_history:
|
||||||
raise CannotPaginate(
|
raise CannotPaginate(
|
||||||
'Bot does not have Read Message History permission.')
|
"Bot does not have Read Message History permission."
|
||||||
|
)
|
||||||
|
|
||||||
def get_page(self, page):
|
def get_page(self, page):
|
||||||
base = (page - 1) * self.per_page
|
base = (page - 1) * self.per_page
|
||||||
return self.entries[base:base + self.per_page]
|
return self.entries[base : base + self.per_page]
|
||||||
|
|
||||||
async def show_page(self, page, *, first=False):
|
async def show_page(self, page, *, first=False):
|
||||||
# noinspection PyAttributeOutsideInit
|
# noinspection PyAttributeOutsideInit
|
||||||
self.current_page = page
|
self.current_page = page
|
||||||
entries = self.get_page(page)
|
entries = self.get_page(page)
|
||||||
p = []
|
p = []
|
||||||
for index, entry in enumerate(entries,
|
for index, entry in enumerate(entries, 1 + ((page - 1) * self.per_page)):
|
||||||
1 + ((page - 1) * self.per_page)):
|
p.append(f"{index}. {entry}")
|
||||||
p.append(f'{index}. {entry}')
|
|
||||||
|
|
||||||
if self.maximum_pages > 1:
|
if self.maximum_pages > 1:
|
||||||
if self.show_entry_count:
|
if self.show_entry_count:
|
||||||
text = f'Page {page}/{self.maximum_pages}' \
|
text = (
|
||||||
f' ({len(self.entries)} entries)'
|
f"Page {page}/{self.maximum_pages}"
|
||||||
|
f" ({len(self.entries)} entries)"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
text = f'Page {page}/{self.maximum_pages}'
|
text = f"Page {page}/{self.maximum_pages}"
|
||||||
|
|
||||||
self.embed.set_footer(text=text)
|
self.embed.set_footer(text=text)
|
||||||
|
|
||||||
if not self.paginating:
|
if not self.paginating:
|
||||||
self.embed.description = '\n'.join(p)
|
self.embed.description = "\n".join(p)
|
||||||
return await self.channel.send(embed=self.embed)
|
return await self.channel.send(embed=self.embed)
|
||||||
|
|
||||||
if not first:
|
if not first:
|
||||||
self.embed.description = '\n'.join(p)
|
self.embed.description = "\n".join(p)
|
||||||
await self.message.edit(embed=self.embed)
|
await self.message.edit(embed=self.embed)
|
||||||
return
|
return
|
||||||
|
|
||||||
p.append('')
|
p.append("")
|
||||||
p.append('Confused? React with \N{INFORMATION SOURCE} for more info.')
|
p.append("Confused? React with \N{INFORMATION SOURCE} for more info.")
|
||||||
self.embed.description = '\n'.join(p)
|
self.embed.description = "\n".join(p)
|
||||||
self.message = await self.channel.send(embed=self.embed)
|
self.message = await self.channel.send(embed=self.embed)
|
||||||
|
|
||||||
await self.message.add_reaction('🔣')
|
await self.message.add_reaction("🔣")
|
||||||
|
|
||||||
async def add_rest_reactions(self):
|
async def add_rest_reactions(self):
|
||||||
await self.message.remove_reaction('🔣', self.message.guild.me)
|
await self.message.remove_reaction("🔣", self.message.guild.me)
|
||||||
for (reaction, _) in self.reaction_emojis:
|
for (reaction, _) in self.reaction_emojis:
|
||||||
if self.maximum_pages == 2 and reaction in ('\u23ed', '\u23ee'):
|
if self.maximum_pages == 2 and reaction in ("\u23ed", "\u23ee"):
|
||||||
# no |<< or >>| buttons if we only have two pages
|
# no |<< or >>| buttons if we only have two pages
|
||||||
# we can't forbid it if someone ends up using it but remove
|
# we can't forbid it if someone ends up using it but remove
|
||||||
# it from the default set
|
# it from the default set
|
||||||
@@ -174,20 +176,19 @@ class Pages:
|
|||||||
"""lets you type a page number to go to"""
|
"""lets you type a page number to go to"""
|
||||||
# noinspection PyListCreation
|
# noinspection PyListCreation
|
||||||
to_delete = []
|
to_delete = []
|
||||||
to_delete.append(await
|
to_delete.append(await self.channel.send("What page do you want to go to?"))
|
||||||
self.channel.send('What page do you want to go to?'))
|
|
||||||
|
|
||||||
def message_check(m):
|
def message_check(m):
|
||||||
return m.author == self.author and \
|
return (
|
||||||
self.channel == m.channel and \
|
m.author == self.author
|
||||||
m.content.isdigit()
|
and self.channel == m.channel
|
||||||
|
and m.content.isdigit()
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
msg = await self.bot.wait_for('message',
|
msg = await self.bot.wait_for("message", check=message_check, timeout=30.0)
|
||||||
check=message_check,
|
|
||||||
timeout=30.0)
|
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
to_delete.append(await self.channel.send('Took too long.'))
|
to_delete.append(await self.channel.send("Took too long."))
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
else:
|
else:
|
||||||
page = int(msg.content)
|
page = int(msg.content)
|
||||||
@@ -195,8 +196,11 @@ class Pages:
|
|||||||
if page != 0 and page <= self.maximum_pages:
|
if page != 0 and page <= self.maximum_pages:
|
||||||
await self.show_page(page)
|
await self.show_page(page)
|
||||||
else:
|
else:
|
||||||
to_delete.append(await self.channel.send(
|
to_delete.append(
|
||||||
f'Invalid page given. ({page}/{self.maximum_pages})'))
|
await self.channel.send(
|
||||||
|
f"Invalid page given. ({page}/{self.maximum_pages})"
|
||||||
|
)
|
||||||
|
)
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
# noinspection PyBroadException
|
# noinspection PyBroadException
|
||||||
@@ -208,19 +212,20 @@ class Pages:
|
|||||||
async def show_help(self):
|
async def show_help(self):
|
||||||
"""shows this message"""
|
"""shows this message"""
|
||||||
messages = [
|
messages = [
|
||||||
'Welcome to the interactive paginator!\n',
|
"Welcome to the interactive paginator!\n",
|
||||||
'This interactively allows you to see pages '
|
"This interactively allows you to see pages "
|
||||||
'of text by navigating with '
|
"of text by navigating with "
|
||||||
'reactions. They are as follows:\n'
|
"reactions. They are as follows:\n",
|
||||||
]
|
]
|
||||||
|
|
||||||
for (emoji, func) in self.reaction_emojis:
|
for (emoji, func) in self.reaction_emojis:
|
||||||
messages.append(f'{emoji} {func.__doc__}')
|
messages.append(f"{emoji} {func.__doc__}")
|
||||||
|
|
||||||
self.embed.description = '\n'.join(messages)
|
self.embed.description = "\n".join(messages)
|
||||||
self.embed.clear_fields()
|
self.embed.clear_fields()
|
||||||
self.embed.set_footer(
|
self.embed.set_footer(
|
||||||
text=f'We were on page {self.current_page} before this message.')
|
text=f"We were on page {self.current_page} before this message."
|
||||||
|
)
|
||||||
await self.message.edit(embed=self.embed)
|
await self.message.edit(embed=self.embed)
|
||||||
|
|
||||||
async def go_back_to_current_page():
|
async def go_back_to_current_page():
|
||||||
@@ -241,7 +246,7 @@ class Pages:
|
|||||||
if reaction.message.id != self.message.id:
|
if reaction.message.id != self.message.id:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if reaction.emoji == '🔣':
|
if reaction.emoji == "🔣":
|
||||||
self.match = self.add_rest_reactions
|
self.match = self.add_rest_reactions
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -258,7 +263,7 @@ class Pages:
|
|||||||
if not self.entries and not self.hide_no_results:
|
if not self.entries and not self.hide_no_results:
|
||||||
# I just say no results found because that's my most common use
|
# I just say no results found because that's my most common use
|
||||||
# case.
|
# case.
|
||||||
return await self.channel.send('No results found.')
|
return await self.channel.send("No results found.")
|
||||||
|
|
||||||
first_page = self.show_page(1, first=True)
|
first_page = self.show_page(1, first=True)
|
||||||
if not self.paginating:
|
if not self.paginating:
|
||||||
@@ -270,7 +275,8 @@ class Pages:
|
|||||||
while self.paginating:
|
while self.paginating:
|
||||||
try:
|
try:
|
||||||
reaction, user = await self.bot.wait_for(
|
reaction, user = await self.bot.wait_for(
|
||||||
'reaction_add', check=self.react_check, timeout=120.0)
|
"reaction_add", check=self.react_check, timeout=120.0
|
||||||
|
)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
self.paginating = False
|
self.paginating = False
|
||||||
# noinspection PyBroadException
|
# noinspection PyBroadException
|
||||||
@@ -285,13 +291,14 @@ class Pages:
|
|||||||
try:
|
try:
|
||||||
await self.message.remove_reaction(reaction, user)
|
await self.message.remove_reaction(reaction, user)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # can't remove it so don't bother doing so
|
pass # can't remove it so don't bother doing so
|
||||||
|
|
||||||
await self.match()
|
await self.match()
|
||||||
|
|
||||||
|
|
||||||
class EmbedPages:
|
class EmbedPages:
|
||||||
"""Similar to Pages, but you use [`discord.Embed`]"""
|
"""Similar to Pages, but you use [`discord.Embed`]"""
|
||||||
|
|
||||||
def __init__(self, ctx, *, embeds):
|
def __init__(self, ctx, *, embeds):
|
||||||
self.bot = ctx.bot
|
self.bot = ctx.bot
|
||||||
self.embeds = embeds
|
self.embeds = embeds
|
||||||
@@ -302,15 +309,19 @@ class EmbedPages:
|
|||||||
self.maximum_pages = pages
|
self.maximum_pages = pages
|
||||||
self.paginating = len(embeds) > 1
|
self.paginating = len(embeds) > 1
|
||||||
self.reaction_emojis = [
|
self.reaction_emojis = [
|
||||||
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}',
|
(
|
||||||
self.first_page),
|
"\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}",
|
||||||
('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page),
|
self.first_page,
|
||||||
('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page),
|
),
|
||||||
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}',
|
("\N{BLACK LEFT-POINTING TRIANGLE}", self.previous_page),
|
||||||
self.last_page),
|
("\N{BLACK RIGHT-POINTING TRIANGLE}", self.next_page),
|
||||||
('\N{INPUT SYMBOL FOR NUMBERS}', self.numbered_page),
|
(
|
||||||
('\N{BLACK SQUARE FOR STOP}', self.stop_pages),
|
"\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}",
|
||||||
('\N{INFORMATION SOURCE}', self.show_help),
|
self.last_page,
|
||||||
|
),
|
||||||
|
("\N{INPUT SYMBOL FOR NUMBERS}", self.numbered_page),
|
||||||
|
("\N{BLACK SQUARE FOR STOP}", self.stop_pages),
|
||||||
|
("\N{INFORMATION SOURCE}", self.show_help),
|
||||||
]
|
]
|
||||||
|
|
||||||
if ctx.guild is not None:
|
if ctx.guild is not None:
|
||||||
@@ -319,20 +330,20 @@ class EmbedPages:
|
|||||||
self.permissions = self.channel.permissions_for(ctx.bot.user)
|
self.permissions = self.channel.permissions_for(ctx.bot.user)
|
||||||
|
|
||||||
if not self.permissions.embed_links:
|
if not self.permissions.embed_links:
|
||||||
raise CannotPaginate('Bot does not have embed links permission.')
|
raise CannotPaginate("Bot does not have embed links permission.")
|
||||||
|
|
||||||
if not self.permissions.send_messages:
|
if not self.permissions.send_messages:
|
||||||
raise CannotPaginate('Bot cannot send messages.')
|
raise CannotPaginate("Bot cannot send messages.")
|
||||||
|
|
||||||
if self.paginating:
|
if self.paginating:
|
||||||
# verify we can actually use the pagination session
|
# verify we can actually use the pagination session
|
||||||
if not self.permissions.add_reactions:
|
if not self.permissions.add_reactions:
|
||||||
raise CannotPaginate(
|
raise CannotPaginate("Bot does not have add reactions permission.")
|
||||||
'Bot does not have add reactions permission.')
|
|
||||||
|
|
||||||
if not self.permissions.read_message_history:
|
if not self.permissions.read_message_history:
|
||||||
raise CannotPaginate(
|
raise CannotPaginate(
|
||||||
'Bot does not have Read Message History permission.')
|
"Bot does not have Read Message History permission."
|
||||||
|
)
|
||||||
|
|
||||||
async def show_page(self, page, *, first=False):
|
async def show_page(self, page, *, first=False):
|
||||||
# noinspection PyAttributeOutsideInit
|
# noinspection PyAttributeOutsideInit
|
||||||
@@ -341,7 +352,7 @@ class EmbedPages:
|
|||||||
p = []
|
p = []
|
||||||
|
|
||||||
if self.maximum_pages > 1:
|
if self.maximum_pages > 1:
|
||||||
text = f'Page {page}/{self.maximum_pages}'
|
text = f"Page {page}/{self.maximum_pages}"
|
||||||
|
|
||||||
embed.set_footer(text=text)
|
embed.set_footer(text=text)
|
||||||
|
|
||||||
@@ -351,19 +362,20 @@ class EmbedPages:
|
|||||||
if not first:
|
if not first:
|
||||||
return await self.message.edit(embed=embed)
|
return await self.message.edit(embed=embed)
|
||||||
|
|
||||||
p.append('')
|
p.append("")
|
||||||
p.append('Confused? React with \N{INFORMATION SOURCE} for more info.')
|
p.append("Confused? React with \N{INFORMATION SOURCE} for more info.")
|
||||||
embed.description = '' if embed.description == discord.Embed.Empty \
|
embed.description = (
|
||||||
else embed.description
|
"" if embed.description == discord.Embed.Empty else embed.description
|
||||||
embed.description += '\n'.join(p)
|
)
|
||||||
|
embed.description += "\n".join(p)
|
||||||
self.message = await self.channel.send(embed=embed)
|
self.message = await self.channel.send(embed=embed)
|
||||||
|
|
||||||
await self.message.add_reaction('🔣')
|
await self.message.add_reaction("🔣")
|
||||||
|
|
||||||
async def add_rest_reactions(self):
|
async def add_rest_reactions(self):
|
||||||
await self.message.remove_reaction('🔣', self.message.guild.me)
|
await self.message.remove_reaction("🔣", self.message.guild.me)
|
||||||
for (reaction, _) in self.reaction_emojis:
|
for (reaction, _) in self.reaction_emojis:
|
||||||
if self.maximum_pages == 2 and reaction in ('\u23ed', '\u23ee'):
|
if self.maximum_pages == 2 and reaction in ("\u23ed", "\u23ee"):
|
||||||
# no |<< or >>| buttons if we only have two pages
|
# no |<< or >>| buttons if we only have two pages
|
||||||
# we can't forbid it if someone ends up using it but remove
|
# we can't forbid it if someone ends up using it but remove
|
||||||
# it from the default set
|
# it from the default set
|
||||||
@@ -399,20 +411,19 @@ class EmbedPages:
|
|||||||
"""lets you type a page number to go to"""
|
"""lets you type a page number to go to"""
|
||||||
# noinspection PyListCreation
|
# noinspection PyListCreation
|
||||||
to_delete = []
|
to_delete = []
|
||||||
to_delete.append(await
|
to_delete.append(await self.channel.send("What page do you want to go to?"))
|
||||||
self.channel.send('What page do you want to go to?'))
|
|
||||||
|
|
||||||
def message_check(m):
|
def message_check(m):
|
||||||
return m.author == self.author and \
|
return (
|
||||||
self.channel == m.channel and \
|
m.author == self.author
|
||||||
m.content.isdigit()
|
and self.channel == m.channel
|
||||||
|
and m.content.isdigit()
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
msg = await self.bot.wait_for('message',
|
msg = await self.bot.wait_for("message", check=message_check, timeout=30.0)
|
||||||
check=message_check,
|
|
||||||
timeout=30.0)
|
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
to_delete.append(await self.channel.send('Took too long.'))
|
to_delete.append(await self.channel.send("Took too long."))
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
else:
|
else:
|
||||||
page = int(msg.content)
|
page = int(msg.content)
|
||||||
@@ -420,8 +431,11 @@ class EmbedPages:
|
|||||||
if page != 0 and page <= self.maximum_pages:
|
if page != 0 and page <= self.maximum_pages:
|
||||||
await self.show_page(page)
|
await self.show_page(page)
|
||||||
else:
|
else:
|
||||||
to_delete.append(await self.channel.send(
|
to_delete.append(
|
||||||
f'Invalid page given. ({page}/{self.maximum_pages})'))
|
await self.channel.send(
|
||||||
|
f"Invalid page given. ({page}/{self.maximum_pages})"
|
||||||
|
)
|
||||||
|
)
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
# noinspection PyBroadException
|
# noinspection PyBroadException
|
||||||
@@ -433,21 +447,22 @@ class EmbedPages:
|
|||||||
async def show_help(self):
|
async def show_help(self):
|
||||||
"""shows this message"""
|
"""shows this message"""
|
||||||
messages = [
|
messages = [
|
||||||
'Welcome to the interactive paginator!\n',
|
"Welcome to the interactive paginator!\n",
|
||||||
'This interactively allows you to see pages '
|
"This interactively allows you to see pages "
|
||||||
'of text by navigating with '
|
"of text by navigating with "
|
||||||
'reactions. They are as follows:\n'
|
"reactions. They are as follows:\n",
|
||||||
]
|
]
|
||||||
|
|
||||||
for (emoji, func) in self.reaction_emojis:
|
for (emoji, func) in self.reaction_emojis:
|
||||||
messages.append(f'{emoji} {func.__doc__}')
|
messages.append(f"{emoji} {func.__doc__}")
|
||||||
|
|
||||||
embed = discord.Embed()
|
embed = discord.Embed()
|
||||||
|
|
||||||
embed.description = '\n'.join(messages)
|
embed.description = "\n".join(messages)
|
||||||
embed.clear_fields()
|
embed.clear_fields()
|
||||||
embed.set_footer(
|
embed.set_footer(
|
||||||
text=f'We were on page {self.current_page} before this message.')
|
text=f"We were on page {self.current_page} before this message."
|
||||||
|
)
|
||||||
await self.message.edit(embed=embed)
|
await self.message.edit(embed=embed)
|
||||||
|
|
||||||
async def go_back_to_current_page():
|
async def go_back_to_current_page():
|
||||||
@@ -468,7 +483,7 @@ class EmbedPages:
|
|||||||
if reaction.message.id != self.message.id:
|
if reaction.message.id != self.message.id:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if reaction.emoji == '🔣':
|
if reaction.emoji == "🔣":
|
||||||
self.match = self.add_rest_reactions
|
self.match = self.add_rest_reactions
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -492,7 +507,8 @@ class EmbedPages:
|
|||||||
while self.paginating:
|
while self.paginating:
|
||||||
try:
|
try:
|
||||||
reaction, user = await self.bot.wait_for(
|
reaction, user = await self.bot.wait_for(
|
||||||
'reaction_add', check=self.react_check, timeout=120.0)
|
"reaction_add", check=self.react_check, timeout=120.0
|
||||||
|
)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
self.paginating = False
|
self.paginating = False
|
||||||
# noinspection PyBroadException
|
# noinspection PyBroadException
|
||||||
@@ -507,7 +523,7 @@ class EmbedPages:
|
|||||||
try:
|
try:
|
||||||
await self.message.remove_reaction(reaction, user)
|
await self.message.remove_reaction(reaction, user)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # can't remove it so don't bother doing so
|
pass # can't remove it so don't bother doing so
|
||||||
|
|
||||||
await self.match()
|
await self.match()
|
||||||
|
|
||||||
@@ -516,6 +532,7 @@ class FieldPages(Pages):
|
|||||||
"""Similar to Pages except entries should be a list of
|
"""Similar to Pages except entries should be a list of
|
||||||
tuples having (key, value) to show as embed fields instead.
|
tuples having (key, value) to show as embed fields instead.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
async def show_page(self, page, *, first=False):
|
async def show_page(self, page, *, first=False):
|
||||||
# noinspection PyAttributeOutsideInit
|
# noinspection PyAttributeOutsideInit
|
||||||
self.current_page = page
|
self.current_page = page
|
||||||
@@ -529,10 +546,12 @@ class FieldPages(Pages):
|
|||||||
|
|
||||||
if self.maximum_pages > 1:
|
if self.maximum_pages > 1:
|
||||||
if self.show_entry_count:
|
if self.show_entry_count:
|
||||||
text = f'Page {page}/{self.maximum_pages} ' \
|
text = (
|
||||||
f'({len(self.entries)} entries)'
|
f"Page {page}/{self.maximum_pages} "
|
||||||
|
f"({len(self.entries)} entries)"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
text = f'Page {page}/{self.maximum_pages}'
|
text = f"Page {page}/{self.maximum_pages}"
|
||||||
|
|
||||||
self.embed.set_footer(text=text)
|
self.embed.set_footer(text=text)
|
||||||
|
|
||||||
@@ -545,7 +564,7 @@ class FieldPages(Pages):
|
|||||||
|
|
||||||
self.message = await self.channel.send(embed=self.embed)
|
self.message = await self.channel.send(embed=self.embed)
|
||||||
for (reaction, _) in self.reaction_emojis:
|
for (reaction, _) in self.reaction_emojis:
|
||||||
if self.maximum_pages == 2 and reaction in ('\u23ed', '\u23ee'):
|
if self.maximum_pages == 2 and reaction in ("\u23ed", "\u23ee"):
|
||||||
# no |<< or >>| buttons if we only have two pages
|
# no |<< or >>| buttons if we only have two pages
|
||||||
# we can't forbid it if someone ends up using it but remove
|
# we can't forbid it if someone ends up using it but remove
|
||||||
# it from the default set
|
# it from the default set
|
||||||
@@ -559,7 +578,7 @@ class FieldPages(Pages):
|
|||||||
# ?help command
|
# ?help command
|
||||||
# -> could be a subcommand
|
# -> could be a subcommand
|
||||||
|
|
||||||
_mention = re.compile(r'<@!?([0-9]{1,19})>')
|
_mention = re.compile(r"<@!?([0-9]{1,19})>")
|
||||||
|
|
||||||
|
|
||||||
def cleanup_prefix(bot, prefix):
|
def cleanup_prefix(bot, prefix):
|
||||||
@@ -567,7 +586,7 @@ def cleanup_prefix(bot, prefix):
|
|||||||
if m:
|
if m:
|
||||||
user = bot.get_user(int(m.group(1)))
|
user = bot.get_user(int(m.group(1)))
|
||||||
if user:
|
if user:
|
||||||
return f'@{user.name} '
|
return f"@{user.name} "
|
||||||
return prefix
|
return prefix
|
||||||
|
|
||||||
|
|
||||||
@@ -586,39 +605,40 @@ def _command_signature(cmd):
|
|||||||
result = [cmd.qualified_name]
|
result = [cmd.qualified_name]
|
||||||
if cmd.usage:
|
if cmd.usage:
|
||||||
result.append(cmd.usage)
|
result.append(cmd.usage)
|
||||||
return ' '.join(result)
|
return " ".join(result)
|
||||||
|
|
||||||
params = cmd.clean_params
|
params = cmd.clean_params
|
||||||
if not params:
|
if not params:
|
||||||
return ' '.join(result)
|
return " ".join(result)
|
||||||
|
|
||||||
for name, param in params.items():
|
for name, param in params.items():
|
||||||
if param.default is not param.empty:
|
if param.default is not param.empty:
|
||||||
# We don't want None or '' to trigger the [name=value] case and
|
# We don't want None or '' to trigger the [name=value] case and
|
||||||
# instead it should do [name] since [name=None] or [name=] are
|
# instead it should do [name] since [name=None] or [name=] are
|
||||||
# not exactly useful for the user.
|
# not exactly useful for the user.
|
||||||
should_print = param.default if isinstance(
|
should_print = (
|
||||||
param.default, str) else param.default is not None
|
param.default
|
||||||
|
if isinstance(param.default, str)
|
||||||
|
else param.default is not None
|
||||||
|
)
|
||||||
if should_print:
|
if should_print:
|
||||||
result.append(f'[{name}={param.default!r}]')
|
result.append(f"[{name}={param.default!r}]")
|
||||||
else:
|
else:
|
||||||
result.append(f'[{name}]')
|
result.append(f"[{name}]")
|
||||||
elif param.kind == param.VAR_POSITIONAL:
|
elif param.kind == param.VAR_POSITIONAL:
|
||||||
result.append(f'[{name}...]')
|
result.append(f"[{name}...]")
|
||||||
else:
|
else:
|
||||||
result.append(f'<{name}>')
|
result.append(f"<{name}>")
|
||||||
|
|
||||||
return ' '.join(result)
|
return " ".join(result)
|
||||||
|
|
||||||
|
|
||||||
class HelpPaginator(Pages):
|
class HelpPaginator(Pages):
|
||||||
def __init__(self, ctx, entries, *, per_page=4):
|
def __init__(self, ctx, entries, *, per_page=4):
|
||||||
super().__init__(ctx,
|
super().__init__(ctx, entries=entries, per_page=per_page, hide_no_results=True)
|
||||||
entries=entries,
|
|
||||||
per_page=per_page,
|
|
||||||
hide_no_results=True)
|
|
||||||
self.reaction_emojis.append(
|
self.reaction_emojis.append(
|
||||||
('\N{WHITE QUESTION MARK ORNAMENT}', self.show_bot_help))
|
("\N{WHITE QUESTION MARK ORNAMENT}", self.show_bot_help)
|
||||||
|
)
|
||||||
self.total = len(entries)
|
self.total = len(entries)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -630,12 +650,11 @@ class HelpPaginator(Pages):
|
|||||||
|
|
||||||
# remove the ones we can't run
|
# remove the ones we can't run
|
||||||
entries = [
|
entries = [
|
||||||
cmd for cmd in entries
|
cmd for cmd in entries if (await _can_run(cmd, ctx)) and not cmd.hidden
|
||||||
if (await _can_run(cmd, ctx)) and not cmd.hidden
|
|
||||||
]
|
]
|
||||||
|
|
||||||
self = cls(ctx, entries)
|
self = cls(ctx, entries)
|
||||||
self.title = f'{cog_name} Commands'.upper()
|
self.title = f"{cog_name} Commands".upper()
|
||||||
self.description = inspect.getdoc(cog)
|
self.description = inspect.getdoc(cog)
|
||||||
self.prefix = cleanup_prefix(ctx.bot, ctx.prefix)
|
self.prefix = cleanup_prefix(ctx.bot, ctx.prefix)
|
||||||
|
|
||||||
@@ -651,17 +670,16 @@ class HelpPaginator(Pages):
|
|||||||
entries = []
|
entries = []
|
||||||
else:
|
else:
|
||||||
entries = [
|
entries = [
|
||||||
cmd for cmd in entries
|
cmd for cmd in entries if (await _can_run(cmd, ctx)) and not cmd.hidden
|
||||||
if (await _can_run(cmd, ctx)) and not cmd.hidden
|
|
||||||
]
|
]
|
||||||
|
|
||||||
self = cls(ctx, entries)
|
self = cls(ctx, entries)
|
||||||
self.title = command.signature
|
self.title = command.signature
|
||||||
|
|
||||||
if command.description:
|
if command.description:
|
||||||
self.description = f'{command.description}\n\n{command.help}'
|
self.description = f"{command.description}\n\n{command.help}"
|
||||||
else:
|
else:
|
||||||
self.description = command.help or 'No help given.'
|
self.description = command.help or "No help given."
|
||||||
|
|
||||||
self.prefix = cleanup_prefix(ctx.bot, ctx.prefix)
|
self.prefix = cleanup_prefix(ctx.bot, ctx.prefix)
|
||||||
return self
|
return self
|
||||||
@@ -669,7 +687,7 @@ class HelpPaginator(Pages):
|
|||||||
@classmethod
|
@classmethod
|
||||||
async def from_bot(cls, ctx):
|
async def from_bot(cls, ctx):
|
||||||
def key(c):
|
def key(c):
|
||||||
return c.cog_name or '\u200bMisc'
|
return c.cog_name or "\u200bMisc"
|
||||||
|
|
||||||
entries = sorted(ctx.bot.commands, key=key)
|
entries = sorted(ctx.bot.commands, key=key)
|
||||||
nested_pages = []
|
nested_pages = []
|
||||||
@@ -681,8 +699,7 @@ class HelpPaginator(Pages):
|
|||||||
|
|
||||||
for cog, commands in itertools.groupby(entries, key=key):
|
for cog, commands in itertools.groupby(entries, key=key):
|
||||||
plausible = [
|
plausible = [
|
||||||
cmd for cmd in commands
|
cmd for cmd in commands if (await _can_run(cmd, ctx)) and not cmd.hidden
|
||||||
if (await _can_run(cmd, ctx)) and not cmd.hidden
|
|
||||||
]
|
]
|
||||||
if len(plausible) == 0:
|
if len(plausible) == 0:
|
||||||
continue
|
continue
|
||||||
@@ -691,14 +708,14 @@ class HelpPaginator(Pages):
|
|||||||
if description is None:
|
if description is None:
|
||||||
description = discord.Embed.Empty
|
description = discord.Embed.Empty
|
||||||
else:
|
else:
|
||||||
description = inspect.getdoc(
|
description = inspect.getdoc(description) or discord.Embed.Empty
|
||||||
description) or discord.Embed.Empty
|
|
||||||
|
|
||||||
nested_pages.extend((cog, description, plausible[i:i + per_page])
|
nested_pages.extend(
|
||||||
for i in range(0, len(plausible), per_page))
|
(cog, description, plausible[i : i + per_page])
|
||||||
|
for i in range(0, len(plausible), per_page)
|
||||||
|
)
|
||||||
|
|
||||||
self = cls(ctx, nested_pages,
|
self = cls(ctx, nested_pages, per_page=1) # this forces the pagination session
|
||||||
per_page=1) # this forces the pagination session
|
|
||||||
self.prefix = cleanup_prefix(ctx.bot, ctx.prefix)
|
self.prefix = cleanup_prefix(ctx.bot, ctx.prefix)
|
||||||
|
|
||||||
# swap the get_page implementation with
|
# swap the get_page implementation with
|
||||||
@@ -713,7 +730,7 @@ class HelpPaginator(Pages):
|
|||||||
# noinspection PyAttributeOutsideInit
|
# noinspection PyAttributeOutsideInit
|
||||||
def get_bot_page(self, page):
|
def get_bot_page(self, page):
|
||||||
cog, description, commands = self.entries[page - 1]
|
cog, description, commands = self.entries[page - 1]
|
||||||
self.title = f'{cog} Commands'
|
self.title = f"{cog} Commands"
|
||||||
self.description = description
|
self.description = description
|
||||||
return commands
|
return commands
|
||||||
|
|
||||||
@@ -734,13 +751,15 @@ class HelpPaginator(Pages):
|
|||||||
signature = _command_signature
|
signature = _command_signature
|
||||||
|
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
self.embed.add_field(name=signature(entry),
|
self.embed.add_field(
|
||||||
value=entry.short_doc or "No help given",
|
name=signature(entry),
|
||||||
inline=False)
|
value=entry.short_doc or "No help given",
|
||||||
|
inline=False,
|
||||||
|
)
|
||||||
|
|
||||||
if self.maximum_pages:
|
if self.maximum_pages:
|
||||||
self.embed.set_author(
|
self.embed.set_author(
|
||||||
name=f'Page {page}/{self.maximum_pages} ({self.total} commands)'
|
name=f"Page {page}/{self.maximum_pages} ({self.total} commands)"
|
||||||
)
|
)
|
||||||
|
|
||||||
if not self.paginating:
|
if not self.paginating:
|
||||||
@@ -752,7 +771,7 @@ class HelpPaginator(Pages):
|
|||||||
|
|
||||||
self.message = await self.channel.send(embed=self.embed)
|
self.message = await self.channel.send(embed=self.embed)
|
||||||
for (reaction, _) in self.reaction_emojis:
|
for (reaction, _) in self.reaction_emojis:
|
||||||
if self.maximum_pages == 2 and reaction in ('\u23ed', '\u23ee'):
|
if self.maximum_pages == 2 and reaction in ("\u23ed", "\u23ee"):
|
||||||
# no |<< or >>| buttons if we only have two pages
|
# no |<< or >>| buttons if we only have two pages
|
||||||
# we can't forbid it if someone ends up using it but remove
|
# we can't forbid it if someone ends up using it but remove
|
||||||
# it from the default set
|
# it from the default set
|
||||||
@@ -763,19 +782,20 @@ class HelpPaginator(Pages):
|
|||||||
async def show_help(self):
|
async def show_help(self):
|
||||||
"""shows this message"""
|
"""shows this message"""
|
||||||
|
|
||||||
self.embed.title = 'Paginator help'
|
self.embed.title = "Paginator help"
|
||||||
self.embed.description = 'Hello! Welcome to the help page.'
|
self.embed.description = "Hello! Welcome to the help page."
|
||||||
|
|
||||||
messages = [
|
messages = [f"{emoji} {func.__doc__}" for emoji, func in self.reaction_emojis]
|
||||||
f'{emoji} {func.__doc__}' for emoji, func in self.reaction_emojis
|
|
||||||
]
|
|
||||||
self.embed.clear_fields()
|
self.embed.clear_fields()
|
||||||
self.embed.add_field(name='What are these reactions for?',
|
self.embed.add_field(
|
||||||
value='\n'.join(messages),
|
name="What are these reactions for?",
|
||||||
inline=False)
|
value="\n".join(messages),
|
||||||
|
inline=False,
|
||||||
|
)
|
||||||
|
|
||||||
self.embed.set_footer(
|
self.embed.set_footer(
|
||||||
text=f'We were on page {self.current_page} before this message.')
|
text=f"We were on page {self.current_page} before this message."
|
||||||
|
)
|
||||||
await self.message.edit(embed=self.embed)
|
await self.message.edit(embed=self.embed)
|
||||||
|
|
||||||
async def go_back_to_current_page():
|
async def go_back_to_current_page():
|
||||||
@@ -787,31 +807,34 @@ class HelpPaginator(Pages):
|
|||||||
async def show_bot_help(self):
|
async def show_bot_help(self):
|
||||||
"""shows how to use the bot"""
|
"""shows how to use the bot"""
|
||||||
|
|
||||||
self.embed.title = 'Using the bot'
|
self.embed.title = "Using the bot"
|
||||||
self.embed.description = 'Hello! Welcome to the help page.'
|
self.embed.description = "Hello! Welcome to the help page."
|
||||||
self.embed.clear_fields()
|
self.embed.clear_fields()
|
||||||
|
|
||||||
entries = (('<argument>',
|
entries = (
|
||||||
'This means the argument is __**required**__.'),
|
("<argument>", "This means the argument is __**required**__."),
|
||||||
('[argument]',
|
("[argument]", "This means the argument is __**optional**__."),
|
||||||
'This means the argument is __**optional**__.'),
|
("[A|B]", "This means the it can be __**either A or B**__."),
|
||||||
('[A|B]',
|
(
|
||||||
'This means the it can be __**either A or B**__.'),
|
"[argument...]",
|
||||||
('[argument...]',
|
"This means you can have multiple arguments.\n"
|
||||||
'This means you can have multiple arguments.\n'
|
"Now that you know the basics, it should be "
|
||||||
'Now that you know the basics, it should be '
|
"noted that...\n"
|
||||||
'noted that...\n'
|
"__**You do not type in the brackets!**__",
|
||||||
'__**You do not type in the brackets!**__'))
|
),
|
||||||
|
)
|
||||||
|
|
||||||
self.embed.add_field(
|
self.embed.add_field(
|
||||||
name='How do I use this bot?',
|
name="How do I use this bot?",
|
||||||
value='Reading the bot signature is pretty simple.')
|
value="Reading the bot signature is pretty simple.",
|
||||||
|
)
|
||||||
|
|
||||||
for name, value in entries:
|
for name, value in entries:
|
||||||
self.embed.add_field(name=name, value=value, inline=False)
|
self.embed.add_field(name=name, value=value, inline=False)
|
||||||
|
|
||||||
self.embed.set_footer(
|
self.embed.set_footer(
|
||||||
text=f'We were on page {self.current_page} before this message.')
|
text=f"We were on page {self.current_page} before this message."
|
||||||
|
)
|
||||||
await self.message.edit(embed=self.embed)
|
await self.message.edit(embed=self.embed)
|
||||||
|
|
||||||
async def go_back_to_current_page():
|
async def go_back_to_current_page():
|
||||||
|
|||||||
Reference in New Issue
Block a user