mirror of
https://github.com/UiO-Gaming/ShiteMusicBot.git
synced 2026-11-07 06:44:29 +01:00
Initial selector implementation. Requires d.py 1.3
This commit is contained in:
1 parent
ab214d7428
commit
bf4d20990a
8 files changed
+303
-123
No files matched your search
+6
-6
@@ -9,14 +9,14 @@ class Cogs(commands.Cog):
|
||||
self.settings = self.bot.settings
|
||||
|
||||
@commands.group(name='cogs', hidden=True)
|
||||
@checks.is_owner()
|
||||
@commands.is_owner()
|
||||
async def _cogs(self, ctx):
|
||||
if ctx.invoked_subcommand is None:
|
||||
await ctx.invoke(self.bot.get_command('help'),
|
||||
ctx.command.qualified_name)
|
||||
|
||||
@_cogs.command()
|
||||
@checks.is_owner()
|
||||
@commands.is_owner()
|
||||
async def load(self, ctx, *, module):
|
||||
"""Loads a module."""
|
||||
try:
|
||||
@@ -26,7 +26,7 @@ class Cogs(commands.Cog):
|
||||
await ctx.send(f'```py\n{traceback.format_exc(e)}\n```')
|
||||
|
||||
@_cogs.command()
|
||||
@checks.is_owner()
|
||||
@commands.is_owner()
|
||||
async def unload(self, ctx, *, module):
|
||||
"""Unloads a module."""
|
||||
try:
|
||||
@@ -36,7 +36,7 @@ class Cogs(commands.Cog):
|
||||
await ctx.send(f'```py\n{traceback.format_exc()}\n```')
|
||||
|
||||
@_cogs.command(name='reload')
|
||||
@checks.is_owner()
|
||||
@commands.is_owner()
|
||||
async def _reload(self, ctx, *, module):
|
||||
"""Reloads a module."""
|
||||
try:
|
||||
@@ -47,7 +47,7 @@ class Cogs(commands.Cog):
|
||||
await ctx.send(f'```py\n{traceback.format_exc()}\n```')
|
||||
|
||||
@_cogs.command(name='reloadall')
|
||||
@checks.is_owner()
|
||||
@commands.is_owner()
|
||||
async def _relaod_all(self, ctx):
|
||||
"""Reloads all extensions"""
|
||||
try:
|
||||
@@ -61,7 +61,7 @@ class Cogs(commands.Cog):
|
||||
await ctx.send(f'```py\n{traceback.format_exc()}\n```')
|
||||
|
||||
@_cogs.command(name='shutdown')
|
||||
@checks.is_owner()
|
||||
@commands.is_owner()
|
||||
async def _shutdown(self, ctx):
|
||||
"""Logs out and stops."""
|
||||
self.bot.lavalink.players.clear()
|
||||
|
||||
+5
-5
@@ -31,7 +31,7 @@ class Misc(commands.Cog):
|
||||
await ctx.send(f'{days}d {hours}h {minutes}m {seconds}s')
|
||||
|
||||
@commands.command(name='guilds')
|
||||
@checks.is_owner()
|
||||
@commands.is_owner()
|
||||
async def _guilds(self, ctx):
|
||||
guilds = f"{self.bot.user.name} is in:\n"
|
||||
for guild in self.bot.guilds:
|
||||
@@ -41,7 +41,7 @@ class Misc(commands.Cog):
|
||||
@commands.command()
|
||||
async def musicinfo(self, ctx):
|
||||
"""
|
||||
Info om musikkspilleren
|
||||
Info about the music player
|
||||
"""
|
||||
embed = discord.Embed(title='{music.title}', color=ctx.me.color)
|
||||
lavalink = self.bot.lavalink
|
||||
@@ -56,14 +56,14 @@ class Misc(commands.Cog):
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command(name="reloadlocale")
|
||||
@checks.is_owner()
|
||||
@commands.is_owner()
|
||||
async def reload_locale(self, ctx):
|
||||
self.bot.localizer.index_localizations()
|
||||
self.bot.localizer.load_localizations()
|
||||
await ctx.send("Localizations reloaded.")
|
||||
|
||||
@commands.command(name="reloadalias")
|
||||
@checks.is_owner()
|
||||
@commands.is_owner()
|
||||
async def reload_alias(self, ctx):
|
||||
self.bot.aliaser.index_localizations()
|
||||
self.bot.aliaser.load_localizations()
|
||||
@@ -72,7 +72,7 @@ class Misc(commands.Cog):
|
||||
@commands.command()
|
||||
async def info(self, ctx):
|
||||
"""
|
||||
Info om Shite Music Bot
|
||||
Info about the bot
|
||||
"""
|
||||
membercount = []
|
||||
for guild in self.bot.guilds:
|
||||
|
||||
+95
-92
@@ -20,6 +20,7 @@ from .utils import checks, RoxUtils, timeformatter
|
||||
from .utils.mixplayer import MixPlayer
|
||||
from .utils.paginator import QueuePaginator, TextPaginator, Scroller
|
||||
|
||||
from .utils.selector import Selector
|
||||
|
||||
time_rx = re.compile('[0-9]+')
|
||||
url_rx = re.compile('https?:\\/\\/(?:www\\.)?.+')
|
||||
@@ -292,42 +293,91 @@ class Music(commands.Cog):
|
||||
await ctx.send(ctx.localizer.format_str("{shuffle}"))
|
||||
|
||||
@commands.command(name='move')
|
||||
async def _move(self, ctx, from_pos: int, to_pos: int):
|
||||
async def _move(self, ctx):
|
||||
""" Moves a song in your queue. """
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
|
||||
user_queue = player.user_queue(ctx.author.id)
|
||||
if not user_queue:
|
||||
return await ctx.send(ctx.localizer.format_str("{my_queue}"))
|
||||
|
||||
if not all(x in range(1, len(user_queue) + 1) for x in [from_pos, to_pos]):
|
||||
return await ctx.send(ctx.localizer.format_str("{out_of_range}", _len=len(user_queue)))
|
||||
|
||||
moved = player.move_user_track(ctx.author.id, from_pos - 1, to_pos - 1)
|
||||
if moved is None:
|
||||
return await ctx.send(ctx.localizer.format_str("{move.not_in_queue}"))
|
||||
|
||||
msg = ctx.localizer.format_str("{move.moved_to}", _title=moved.title, _from=from_pos, _to=to_pos)
|
||||
await ctx.send(msg)
|
||||
|
||||
@commands.command(name='remove')
|
||||
async def _remove(self, ctx, pos: int):
|
||||
""" Removes an item from the player's queue with the given pos. """
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
|
||||
if player.queue.empty:
|
||||
return
|
||||
|
||||
user_queue = player.user_queue(ctx.author.id)
|
||||
user_queue = player.user_queue(ctx.author.id, dual=True)
|
||||
if not user_queue:
|
||||
return await ctx.send(ctx.localizer.format_str("{my_queue}"))
|
||||
# Setup for selector
|
||||
identifiers = []
|
||||
for index, temp in enumerate(user_queue):
|
||||
track, globpos = temp
|
||||
identifiers.append(ctx.localizer.format_str("{queue.usertrack}", _index=index+1,
|
||||
_globalindex=globpos+1, _title=track.title,
|
||||
_uri=track.uri))
|
||||
|
||||
def ret_first_arg(*args):
|
||||
return args[0]
|
||||
|
||||
functions = [ret_first_arg]*len(user_queue)
|
||||
arguments = [(i,) for i in range(len(user_queue))]
|
||||
|
||||
# Set the different titles for the different selections
|
||||
round_titles = ["{moved.choose_song}","{moved.choose_pos}"]
|
||||
round_titles = [ctx.localizer.format_str(i) for i in round_titles]
|
||||
|
||||
selector = Selector(ctx, identifiers, functions, arguments, num_selections=5, round_titles=round_titles,
|
||||
color=ctx.me.color, title=ctx.localizer.format_str("{moved.choose}"))
|
||||
|
||||
# Get the initial and final position
|
||||
message, page, selections = await selector.start_scrolling()
|
||||
pos_initial, pos_final = selections[0], selections[1]
|
||||
|
||||
# Move the track
|
||||
moved = player.move_user_track(ctx.author.id, pos_initial, pos_final)
|
||||
|
||||
# Create a nice embed explaining what happened
|
||||
song = f'**[{moved.title}]({moved.uri})**'
|
||||
embed = discord.Embed(color=ctx.me.color, description=song, title='{moved.moved}')
|
||||
thumbnail_url = await RoxUtils.ThumbNailer.identify(self, moved.identifier, moved.uri)
|
||||
member = ctx.guild.get_member(moved.requester)
|
||||
if thumbnail_url:
|
||||
embed.set_thumbnail(url=thumbnail_url)
|
||||
if member.nick:
|
||||
member_identifier = member.nick
|
||||
else:
|
||||
member_identifier = member.name
|
||||
|
||||
embed.add_field(name="{moved.local}", value=f"`{pos_initial + 1} → {pos_final + 1}`", inline=True)
|
||||
embed.add_field(name="{moved.global}", value=f"`{player.queue._loc_to_glob(ctx.author.id, pos_initial) + 1}\
|
||||
→ {player.queue._loc_to_glob(ctx.author.id, pos_final) + 1}`", inline=True)
|
||||
embed.set_footer(text=f'{{requested_by}} {member_identifier}', icon_url=member.avatar_url)
|
||||
embed = ctx.localizer.format_embed(embed)
|
||||
|
||||
await message.edit(embed=embed)
|
||||
await message.clear_reactions()
|
||||
|
||||
@commands.command(name='remove')
|
||||
async def _remove(self, ctx):
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
|
||||
if player.queue.empty:
|
||||
return
|
||||
|
||||
if pos > len(user_queue) or pos < 1:
|
||||
return await ctx.send(ctx.localizer.format_str("{out_of_range}", _len=len(user_queue)))
|
||||
user_queue = player.user_queue(ctx.author.id, dual=True)
|
||||
if not user_queue:
|
||||
return await ctx.send(ctx.localizer.format_str("{my_queue}"))
|
||||
|
||||
removed = player.remove_user_track(ctx.author.id, pos - 1)
|
||||
identifiers = []
|
||||
for index, temp in enumerate(user_queue):
|
||||
track, globpos = temp
|
||||
identifiers.append(ctx.localizer.format_str("{queue.usertrack}", _index=index+1,
|
||||
_globalindex=globpos+1, _title=track.title,
|
||||
_uri=track.uri))
|
||||
|
||||
await ctx.send(ctx.localizer.format_str("{remove}", _title=removed.title))
|
||||
functions = [player.remove_user_track]*len(user_queue)
|
||||
arguments = [(ctx.author.id, i) for i in range(len(user_queue))]
|
||||
|
||||
selector = Selector(ctx, identifiers, functions, arguments, num_selections=5, color=0xFF0000,
|
||||
title='Remove song plz')
|
||||
message, page, removed = await selector.start_scrolling()
|
||||
await message.edit(content=ctx.localizer.format_str("{remove}", _title=removed.title), embed=None)
|
||||
await message.clear_reactions()
|
||||
|
||||
@commands.command(name="DJremove")
|
||||
@checks.DJ_or()
|
||||
@@ -382,8 +432,7 @@ class Music(commands.Cog):
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command(name='search')
|
||||
async def _search(self, ctx, *, query):
|
||||
""" Lists the first 10 search results from a given query. """
|
||||
async def _search(self, ctx, *, query):
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
|
||||
if not query.startswith('ytsearch:') and not query.startswith('scsearch:'):
|
||||
@@ -397,80 +446,32 @@ class Music(commands.Cog):
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
tracks = results['tracks']
|
||||
result_count = min(len(tracks), 5)
|
||||
result_count = min(len(tracks), 15)
|
||||
|
||||
# Setup for the selector
|
||||
identifiers = []
|
||||
functions = [self.enqueue]*result_count
|
||||
arguments = [(ctx, tracks[i], discord.Embed(color=ctx.me.color)) for i in range(result_count)]
|
||||
|
||||
search_results = ''
|
||||
for index, track in enumerate(tracks, start=1):
|
||||
track_title = track['info']['title']
|
||||
track_uri = track['info']['uri']
|
||||
duration = timeformatter.format(int(track['info']['length']))
|
||||
search_results += f'`{index}.` [{track_title}]({track_uri}) `{duration}`\n'
|
||||
identifiers.append(f'`{index}.` [{track_title}]({track_uri}) `{duration}`')
|
||||
if index == result_count:
|
||||
break
|
||||
|
||||
choices = [
|
||||
('1\N{combining enclosing keycap}', 1),
|
||||
('2\N{combining enclosing keycap}', 2),
|
||||
('3\N{combining enclosing keycap}', 3),
|
||||
('4\N{combining enclosing keycap}', 4),
|
||||
('5\N{combining enclosing keycap}', 5),
|
||||
]
|
||||
choice = None
|
||||
search_selector = Selector(ctx, identifiers, functions, arguments, num_selections=5,
|
||||
color=ctx.me.color, title=ctx.localizer.format_str('{results}'))
|
||||
# Let the user scroll through results
|
||||
message, current_page, result = await search_selector.start_scrolling()
|
||||
|
||||
def check(reaction, user):
|
||||
if user is None or user.id != ctx.author.id:
|
||||
return False
|
||||
result = ctx.localizer.format_embed(result)
|
||||
await message.edit(embed=result)
|
||||
await message.clear_reactions()
|
||||
|
||||
if reaction.message.id != result_msg.id:
|
||||
return False
|
||||
|
||||
if reaction.emoji == '❌':
|
||||
return True
|
||||
|
||||
for (emoji, index) in choices[:result_count]:
|
||||
if emoji == reaction.emoji:
|
||||
nonlocal choice
|
||||
choice = index
|
||||
return True
|
||||
return False
|
||||
|
||||
embed.description = '{search}'
|
||||
embed = ctx.localizer.format_embed(embed)
|
||||
result_msg = await ctx.send(embed=embed)
|
||||
|
||||
for emoji, index in choices[:result_count]:
|
||||
await result_msg.add_reaction(emoji)
|
||||
await result_msg.add_reaction('❌')
|
||||
|
||||
embed.description = search_results
|
||||
|
||||
embed.title = '{results}'
|
||||
embed.color = ctx.me.color
|
||||
embed = ctx.localizer.format_embed(embed)
|
||||
|
||||
await result_msg.edit(embed=embed)
|
||||
|
||||
try:
|
||||
reaction, user = await self.bot.wait_for('reaction_add', timeout=15.0, check=check)
|
||||
except asyncio.TimeoutError:
|
||||
await result_msg.clear_reactions()
|
||||
embed.title = ''
|
||||
embed.description = '{time_expired}'
|
||||
embed = ctx.localizer.format_embed(embed)
|
||||
await result_msg.edit(embed=embed)
|
||||
await asyncio.sleep(5)
|
||||
await result_msg.delete()
|
||||
else:
|
||||
if choice is None:
|
||||
await result_msg.delete()
|
||||
else:
|
||||
await result_msg.clear_reactions()
|
||||
track = tracks[choice - 1]
|
||||
await self.enqueue(ctx, track, embed)
|
||||
embed = ctx.localizer.format_embed(embed)
|
||||
await result_msg.edit(embed=embed)
|
||||
if not player.is_playing:
|
||||
await player.play()
|
||||
if not player.is_playing:
|
||||
await player.play()
|
||||
|
||||
@commands.command(name='disconnect')
|
||||
@checks.DJ_or(alone=True)
|
||||
@@ -718,7 +719,7 @@ class Music(commands.Cog):
|
||||
# Create returns a player if one exists, otherwise creates.
|
||||
|
||||
# Add commands that require joining voice to work.
|
||||
should_connect = ctx.command.callback.__name__ in ('_play', '_find', '_search')
|
||||
should_connect = ctx.command.callback.__name__ in ('_play', '_find', '_search', '_sk')
|
||||
|
||||
# Add commands that don't require the you being in voice.
|
||||
without_connect = ctx.command.callback.__name__ in ('_queue', '_history', '_now', '_lyrics')
|
||||
@@ -793,6 +794,8 @@ class Music(commands.Cog):
|
||||
duration = timeformatter.format(int(track.duration))
|
||||
embed.description = f'[{track.title}]({track.uri})\n**{duration}**'
|
||||
|
||||
return embed
|
||||
|
||||
def max_track_length(self, guild, player):
|
||||
is_dynamic = self.bot.settings.get(guild, 'duration.is_dynamic', 'default_duration_type')
|
||||
maxlength = self.bot.settings.get(guild, 'duration.max', None)
|
||||
|
||||
@@ -68,6 +68,7 @@ class MusicEvents(commands.Cog):
|
||||
player.update_listeners(member, after)
|
||||
await self.check_leave_voice(member.guild)
|
||||
|
||||
|
||||
async def check_leave_voice(self, guild):
|
||||
""" Checks if the bot should leave the voice channel """
|
||||
# TODO, disconnect timer?
|
||||
|
||||
@@ -184,7 +184,6 @@ class Settings(commands.Cog):
|
||||
embed.description = f'Static'
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@checks.is_admin()
|
||||
@commands.guild_only()
|
||||
@_set.command(name='current')
|
||||
async def current_settings(self, ctx):
|
||||
|
||||
@@ -28,22 +28,6 @@ def has_guild_permissions(*, check=all, **perms):
|
||||
return commands.check(pred)
|
||||
|
||||
|
||||
def is_even():
|
||||
def predicate(ctx):
|
||||
return ctx.message.author.id == 142212883512557569
|
||||
return commands.check(predicate)
|
||||
|
||||
|
||||
def is_owner():
|
||||
def predicate(ctx):
|
||||
is_owner = (ctx.message.author.id == 120970603556503552 or
|
||||
ctx.message.author.id == 142212883512557569 or
|
||||
ctx.message.author.id == 212635519706726410 or
|
||||
ctx.message.author.id == 170506717140877312)
|
||||
return is_owner
|
||||
return commands.check(predicate)
|
||||
|
||||
|
||||
def is_admin():
|
||||
async def pred(ctx):
|
||||
return await check_guild_permissions(ctx, {'administrator': True})
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
import discord
|
||||
import asyncio
|
||||
import itertools
|
||||
import inspect
|
||||
|
||||
from .paginator import *
|
||||
|
||||
|
||||
class Selector(TextPaginator):
|
||||
def __init__(self, ctx, identifiers, functions, arguments, terminate_on_select=True, num_selections=3,
|
||||
round_titles=[], max_size=2000, **embed_base):
|
||||
"""
|
||||
Selector, tool for making interactive menus.
|
||||
:param ctx: discord.py context
|
||||
:param identifiers: A list of strings, one for each menu item
|
||||
:param functions: List of functions, one for each menu item. Gets run when the corresponding
|
||||
menu item is selected
|
||||
:param arguments: List of arguments to pass to the corresponding function in functions.
|
||||
:param terminate_on_select:
|
||||
:param num_selections: the number of selectable items per page
|
||||
:param round_titles: A list of embed titles, updates each time a menu selection is made
|
||||
:param max_size: The max amount of characters per page.
|
||||
:param embed_base: Arguments that specify the look of the scroller embeds
|
||||
"""
|
||||
self.match = None
|
||||
self.current_page = 0
|
||||
self.ctx = ctx
|
||||
self.bot = ctx.bot
|
||||
self.cmdmsg = ctx.message
|
||||
self.message = ctx.message
|
||||
self.channel = ctx.channel
|
||||
self.author = ctx.author
|
||||
|
||||
self.localizer = ctx.localizer
|
||||
|
||||
self.num_selections = num_selections
|
||||
self.terminate_on_select = terminate_on_select
|
||||
self.round_titles = round_titles
|
||||
|
||||
assert len(identifiers) == len(functions) == len(arguments)
|
||||
super().__init__(max_size=max_size, max_lines=num_selections, **embed_base)
|
||||
|
||||
self.selections = list(zip(identifiers, functions, arguments))
|
||||
|
||||
self.max_selections = min(len(identifiers), num_selections)
|
||||
for i, selection in enumerate(self.selections):
|
||||
self.add_line(f"{i%num_selections+1}\N{combining enclosing keycap} {selection[0]}")
|
||||
self.close_page()
|
||||
|
||||
if len(self.pages) > 1:
|
||||
self.multipage = True
|
||||
else:
|
||||
self.multipage = False
|
||||
|
||||
assert num_selections <= 10
|
||||
self.select_emojis = [f"{i+1}\N{combining enclosing keycap}" for i in range(num_selections)]
|
||||
|
||||
self.control_emojis = [
|
||||
('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page),
|
||||
('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page),
|
||||
('❌', self.stop_scrolling),
|
||||
]
|
||||
|
||||
self.timeout = 30
|
||||
self.args = None
|
||||
self.control_input = False
|
||||
self.scrolling = True
|
||||
self.stopped = False
|
||||
|
||||
self.add_page_indicator(self.localizer, "{queue.pageindicator}")
|
||||
if self.round_titles:
|
||||
self.update_embed_title(self.round_titles.pop(0))
|
||||
|
||||
async def scroll(self, page):
|
||||
if page < 0 or page >= len(self.pages):
|
||||
return
|
||||
self.current_page = page
|
||||
await self.message.edit(embed=self.pages[page])
|
||||
|
||||
async def next_page(self):
|
||||
await self.scroll(self.current_page + 1)
|
||||
|
||||
async def previous_page(self):
|
||||
await self.scroll(self.current_page - 1)
|
||||
|
||||
async def stop_scrolling(self):
|
||||
self.scrolling = False
|
||||
await self.message.clear_reactions()
|
||||
|
||||
def update_embed_title(self, updated_title):
|
||||
for page in self.pages:
|
||||
page.title = updated_title
|
||||
|
||||
def _react_check(self, reaction, user):
|
||||
if user is None or user.id != self.author.id:
|
||||
return False
|
||||
|
||||
if reaction.message.id != self.message.id:
|
||||
return False
|
||||
|
||||
for i, emoji in enumerate(self.select_emojis):
|
||||
if emoji == reaction.emoji:
|
||||
choice = i + self.current_page * self.num_selections
|
||||
if choice >= len(self.selections):
|
||||
return True
|
||||
self.match = self.selections[choice][1]
|
||||
self.args = self.selections[choice][2]
|
||||
return True
|
||||
|
||||
for (emoji, func) in self.control_emojis:
|
||||
if reaction.emoji == emoji:
|
||||
self.match = func
|
||||
self.control_input = True
|
||||
return True
|
||||
return False
|
||||
|
||||
async def send(self):
|
||||
# No embeds to scroll through
|
||||
if not self.pages:
|
||||
return
|
||||
|
||||
self.message = await self.channel.send(embed=self.pages[0])
|
||||
|
||||
for reaction in self.select_emojis[:self.max_selections]:
|
||||
if not self.stopped:
|
||||
await self.message.add_reaction(reaction)
|
||||
|
||||
if self.multipage:
|
||||
for reaction in list(zip(*self.control_emojis))[0]:
|
||||
if not self.stopped:
|
||||
await self.message.add_reaction(reaction)
|
||||
else:
|
||||
if not self.stopped:
|
||||
await self.message.add_reaction('❌')
|
||||
|
||||
async def start_scrolling(self):
|
||||
result = None
|
||||
if not self.scrolling:
|
||||
await self.send()
|
||||
else:
|
||||
self.bot.loop.create_task(self.send())
|
||||
|
||||
current_round = 0
|
||||
results = []
|
||||
while self.scrolling:
|
||||
try:
|
||||
reaction, user = await self.bot.wait_for('reaction_add', check=self._react_check, timeout=self.timeout)
|
||||
except asyncio.TimeoutError:
|
||||
self.scrolling = False
|
||||
try:
|
||||
await self.message.clear_reactions()
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
break
|
||||
|
||||
try:
|
||||
await self.message.remove_reaction(reaction, user)
|
||||
except:
|
||||
pass
|
||||
if self.match:
|
||||
if inspect.iscoroutinefunction(self.match):
|
||||
if self.args:
|
||||
result = await self.match(*self.args)
|
||||
else:
|
||||
result = await self.match()
|
||||
else:
|
||||
if self.args:
|
||||
result = self.match(*self.args)
|
||||
else:
|
||||
result = self.match()
|
||||
else:
|
||||
continue
|
||||
|
||||
if self.terminate_on_select and not self.control_input:
|
||||
current_round += 1
|
||||
results.append(result)
|
||||
if not self.round_titles:
|
||||
self.stopped = True
|
||||
await self.message.clear_reactions()
|
||||
break
|
||||
if self.round_titles:
|
||||
self.update_embed_title(self.round_titles.pop(0))
|
||||
await self.scroll(self.current_page)
|
||||
self.args = None
|
||||
self.control_input = False
|
||||
if len(results) == 1:
|
||||
return self.message, self.pages[self.current_page], results[0]
|
||||
else:
|
||||
return self.message, self.pages[self.current_page], results
|
||||
@@ -32,9 +32,12 @@ resume:
|
||||
paused: "⏯ | Paused"
|
||||
shuffle: Your queue has been shuffled
|
||||
out_of_range: Positions must be between 1 and {_len}
|
||||
move:
|
||||
not_in_queue: Check that the positions exist in your queue
|
||||
moved_to: "{_title} moved from position {_from} to {_to} in your queue"
|
||||
moved:
|
||||
choose_song: "**Select the song to move**"
|
||||
choose_pos: "**Select where to move it**"
|
||||
moved: "**Song moved**"
|
||||
local: "User queue:"
|
||||
global: "Server queue:"
|
||||
remove: "**{_title}** removed."
|
||||
dj_removed: "**{_title}** queued by {_user} removed."
|
||||
dj_remove_user: Removed all songs queued by <@{_id}>.
|
||||
|
||||
Reference in new issue
Block a user