mirror of
https://github.com/UiO-Gaming/ShiteMusicBot.git
synced 2026-11-05 13:56:51 +01:00
Merge branch 'helpformatter' into 'dev'
Helpformatter See merge request Ev-1/shite-music-bot!16
This commit is contained in:
commit
23f0f093aa
20 files changed
+900
-357
No files matched your search
@@ -12,6 +12,8 @@ from cogs.utils.localizer import Localizer
|
||||
from cogs.utils.localizer import LocalizerWrapper
|
||||
from cogs.utils.alias import Aliaser
|
||||
from cogs.utils.context import Context
|
||||
from cogs.helpformatter import commandhelper
|
||||
from cogs.utils.paginator import Scroller
|
||||
|
||||
|
||||
with codecs.open("data/config.yaml", 'r', encoding='utf8') as f:
|
||||
@@ -21,7 +23,8 @@ with codecs.open("data/config.yaml", 'r', encoding='utf8') as f:
|
||||
initial_extensions = [
|
||||
'cogs.cogs',
|
||||
'cogs.settings',
|
||||
'cogs.misc'
|
||||
'cogs.misc',
|
||||
'cogs.helpformatter'
|
||||
]
|
||||
|
||||
|
||||
@@ -58,15 +61,9 @@ class Bot(commands.Bot):
|
||||
if not self.debug:
|
||||
if (isinstance(err, commands.MissingRequiredArgument) or
|
||||
isinstance(err, commands.BadArgument)):
|
||||
formatter = ctx.bot.formatter
|
||||
if ctx.invoked_subcommand is None:
|
||||
_help = await formatter.format_help_for(ctx, ctx.command)
|
||||
else:
|
||||
_help = await formatter.format_help_for(ctx,
|
||||
ctx.invoked_subcommand)
|
||||
|
||||
for message in _help:
|
||||
await ctx.send(message)
|
||||
paginator = commandhelper(ctx, ctx.command, ctx.invoker)
|
||||
scroller = Scroller(ctx, paginator)
|
||||
await scroller.start_scrolling()
|
||||
|
||||
if isinstance(err, commands.CommandInvokeError):
|
||||
pass
|
||||
@@ -94,8 +91,6 @@ class Bot(commands.Bot):
|
||||
|
||||
# Replace aliases with commands
|
||||
ctx = self.aliaser.get_command(ctx)
|
||||
if ctx.command and isinstance(ctx.command, commands.GroupMixin):
|
||||
ctx = self.aliaser.get_subcommand(ctx, ctx.command, [str(ctx.command)])
|
||||
|
||||
# Add the localizer
|
||||
if ctx.command and ctx.command.cog_name:
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ class Cogs(commands.Cog):
|
||||
self.bot = bot
|
||||
self.settings = self.bot.settings
|
||||
|
||||
@commands.group(name='cogs')
|
||||
@commands.group(name='cogs', hidden=True)
|
||||
@checks.is_owner()
|
||||
async def _cogs(self, ctx):
|
||||
if ctx.invoked_subcommand is None:
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
# NOTICE: Before you copy this example, be sure you understand what all this does. Remember: This is a gist, not a github file meaning
|
||||
# you can't pip install this, you would need to put this into a new file and add it to your cog list.
|
||||
|
||||
import pprint
|
||||
|
||||
import discord
|
||||
import asyncio
|
||||
from discord.ext import commands
|
||||
|
||||
from cogs.utils.paginator import HelpPaginator, Scroller
|
||||
|
||||
|
||||
def get_cmd_dict(ctx, qualified_name):
|
||||
split = qualified_name.split()
|
||||
cmd_dict = ctx.bot.aliaser.get_cmd_help(ctx.locale, split[-1], split[:-1])
|
||||
return cmd_dict
|
||||
|
||||
|
||||
def helper(ctx):
|
||||
bot = ctx.bot
|
||||
# Display music commands first
|
||||
music = bot.get_cog('Music')
|
||||
paginator = coghelper(ctx, music)
|
||||
|
||||
for cog in bot.cogs.copy().values():
|
||||
if cog.__cog_name__ is 'Music':
|
||||
continue
|
||||
cogpaignator = coghelper(ctx, cog)
|
||||
paginator.append_paginator(cogpaignator)
|
||||
|
||||
paginator.add_page_indicator(ctx.localizer, "{pageindicator}", ctx.prefix)
|
||||
return paginator
|
||||
|
||||
|
||||
def coghelper(ctx, cog, ignore_subcommands=True):
|
||||
paginator = HelpPaginator(max_size=5000, max_fields=5, color=ctx.me.color, title=cog.__cog_name__)
|
||||
for cmd in cog.walk_commands():
|
||||
if ignore_subcommands:
|
||||
if len(cmd.qualified_name.split()) > 1:
|
||||
continue
|
||||
if cmd.hidden:
|
||||
continue
|
||||
cmd_dict = get_cmd_dict(ctx, cmd.qualified_name)
|
||||
paginator.add_command_field(cmd_dict)
|
||||
paginator.add_page_indicator(ctx.localizer, "{paginator}", ctx.prefix)
|
||||
return paginator
|
||||
|
||||
|
||||
def commandhelper(ctx, command, invoker, include_subcmd=True):
|
||||
cmd_dict = get_cmd_dict(ctx, command.qualified_name)
|
||||
prefix = ctx.prefix
|
||||
if invoker.split()[:-1]:
|
||||
prefix += ' '.join(invoker.split()[:-1]) + ' '
|
||||
|
||||
aliases = cmd_dict.get('aliases', [])
|
||||
args = cmd_dict.get('args', '')
|
||||
description = cmd_dict.get('description', '')
|
||||
sub_commands = cmd_dict.get('sub_commands', [])
|
||||
|
||||
if len(aliases) > 1:
|
||||
cmd = prefix + '[' + '|'.join([str(a) for a in aliases]) + '] '
|
||||
else:
|
||||
cmd = prefix + '|'.join([str(a) for a in aliases]) + ' '
|
||||
|
||||
cmd += args
|
||||
if not sub_commands:
|
||||
paginator = HelpPaginator(max_size=5000, max_fields=5, color=ctx.me.color, title=cmd, description=description)
|
||||
paginator.force_close_page()
|
||||
return paginator
|
||||
|
||||
description = f"```{description}```"
|
||||
paginator = HelpPaginator(max_size=5000, max_fields=5, color=ctx.me.color, title=cmd, description=description)
|
||||
|
||||
for sub_command, sub_cmd_dict in sub_commands.items():
|
||||
paginator.add_command_field(sub_cmd_dict)
|
||||
paginator.add_page_indicator(ctx.localizer, "{pageindicator}", ctx.prefix)
|
||||
return paginator
|
||||
|
||||
|
||||
class Help(commands.Cog):
|
||||
"""Help command"""
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.command(hidden=True)
|
||||
async def help(self, ctx): # Takes no args because reasons(using the view directly)
|
||||
ctx.view.skip_ws()
|
||||
v = ctx.view
|
||||
invoker = v.buffer[v.index:v.end]
|
||||
ctx = self.bot.aliaser.get_subcommand(ctx, group=None, parents=[])
|
||||
command = v.buffer[v.index:v.end]
|
||||
|
||||
if not command:
|
||||
scroller = Scroller(ctx, helper(ctx))
|
||||
await scroller.start_scrolling()
|
||||
|
||||
if command:
|
||||
thing = ctx.bot.get_cog(command) or ctx.bot.get_command(command)
|
||||
if not thing:
|
||||
return await ctx.send(f'Looks like "{command}" is not a command or category.')
|
||||
if isinstance(thing, commands.Command):
|
||||
paginator = commandhelper(ctx, thing, invoker)
|
||||
scroller = Scroller(ctx, paginator)
|
||||
await scroller.start_scrolling()
|
||||
else:
|
||||
scroller = Scroller(ctx, coghelper(ctx, thing))
|
||||
await scroller.start_scrolling()
|
||||
|
||||
def setup(bot):
|
||||
bot.remove_command("help")
|
||||
bot.add_cog(Help(bot))
|
||||
@@ -9,6 +9,7 @@ from discord.ext import commands
|
||||
from cogs.utils import checks
|
||||
from lavalink import __version__ as LavalinkVersion
|
||||
|
||||
|
||||
class Misc(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
+7
-4
@@ -15,7 +15,7 @@ from typing import Optional
|
||||
|
||||
from .utils import checks, RoxUtils, timeformatter
|
||||
from .utils.mixplayer import MixPlayer
|
||||
from .utils.embedscroller import QueueScroller
|
||||
from .utils.paginator import QueuePaginator, Scroller
|
||||
|
||||
|
||||
time_rx = re.compile('[0-9]+')
|
||||
@@ -220,7 +220,8 @@ class Music(commands.Cog):
|
||||
|
||||
if user is None:
|
||||
queue = player.global_queue()
|
||||
scroller = QueueScroller(ctx, queue, ctx.localizer, lines_per_page=10)
|
||||
pagified_queue = QueuePaginator(ctx.localizer, queue, color=ctx.me.color)
|
||||
scroller = Scroller(ctx, pagified_queue)
|
||||
await scroller.start_scrolling()
|
||||
|
||||
else:
|
||||
@@ -228,7 +229,8 @@ class Music(commands.Cog):
|
||||
if not user_queue:
|
||||
return await ctx.send(ctx.localizer.format_str("{queue.empty}", _user=user.name))
|
||||
|
||||
scroller = QueueScroller(ctx, user_queue, ctx.localizer, lines_per_page=10, user_name=user.name)
|
||||
pagified_queue = QueuePaginator(ctx.localizer, user_queue, color=ctx.me.color, user_name=ctx.author.name)
|
||||
scroller = Scroller(ctx, pagified_queue)
|
||||
await scroller.start_scrolling()
|
||||
|
||||
@commands.command(name='myqueue')
|
||||
@@ -240,7 +242,8 @@ class Music(commands.Cog):
|
||||
if not user_queue:
|
||||
return await ctx.send(ctx.localizer.format_str("{my_queue}"))
|
||||
|
||||
scroller = QueueScroller(ctx, user_queue, ctx.localizer, lines_per_page=10, user_name=ctx.author.name)
|
||||
pagified_queue = QueuePaginator(ctx.localizer, user_queue, color=ctx.me.color, user_name=ctx.author.name)
|
||||
scroller = Scroller(ctx, pagified_queue)
|
||||
await scroller.start_scrolling()
|
||||
|
||||
@commands.command(name='pause')
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ class Settings(commands.Cog):
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.guild_only()
|
||||
@_set.command(name='listenchannels')
|
||||
@_set.command(name='listenchannels', hidden=True)
|
||||
async def set_listen_voice(self, ctx, *channels: discord.VoiceChannel):
|
||||
if channels:
|
||||
channel_ids = [channel.id for channel in channels]
|
||||
|
||||
+42
-6
@@ -6,6 +6,12 @@ from os import path
|
||||
|
||||
from discord.ext import commands
|
||||
|
||||
"""
|
||||
Not the prettiest this, works by replacing any found aliases in a command string with the actual command names.
|
||||
Allows per guild aliases of subcommands without doing anything to discord.py itself. Suggestions of better/correct
|
||||
ways of doing this appreciated.
|
||||
"""
|
||||
|
||||
class Aliaser:
|
||||
def __init__(self, localization_folder, default_lang):
|
||||
self.localization_folder = path.realpath(localization_folder)
|
||||
@@ -39,7 +45,7 @@ class Aliaser:
|
||||
|
||||
def load_localizations(self):
|
||||
for lang in self.localization_table.keys():
|
||||
with open(path.join(self.localization_folder, lang, "aliases.yaml"), "r", encoding='utf-8') as f:
|
||||
with open(path.join(self.localization_folder, lang, "commands.yaml"), "r", encoding='utf-8') as f:
|
||||
data = yaml.load(f)
|
||||
self.localization_table[lang] = {'aliases': data, 'commands': self._gen_alias_dict(data)}
|
||||
|
||||
@@ -66,9 +72,27 @@ class Aliaser:
|
||||
return command
|
||||
return default
|
||||
|
||||
def get_alias(self, locale, command):
|
||||
def get_cmd_help(self, locale, command=None, parents=[]):
|
||||
""" Fetches the command info dictionary """
|
||||
locale = self.localization_table[locale]
|
||||
return locale['aliases'].get(command, [])
|
||||
|
||||
def traverse(command_tree, parents, command):
|
||||
# Return the command when no more parents exist
|
||||
if not parents:
|
||||
return command_tree.get(command, [])
|
||||
|
||||
parent = command_tree.get(parents.pop(0), None)
|
||||
if not parent:
|
||||
return []
|
||||
command_tree = parent.get('sub_commands', [])
|
||||
if not command_tree:
|
||||
return None
|
||||
return traverse(command_tree, parents, command)
|
||||
|
||||
command_tree = locale['aliases']
|
||||
if command:
|
||||
return traverse(command_tree, parents, command)
|
||||
return command_tree
|
||||
|
||||
def get_command(self, ctx):
|
||||
""" Get a top level command. """
|
||||
@@ -76,13 +100,22 @@ class Aliaser:
|
||||
ctx.command = None
|
||||
return ctx
|
||||
ctx.view.undo()
|
||||
ctx.invoker = invoker = ctx.view.buffer[ctx.view.index:ctx.view.end]
|
||||
alias = ctx.view.get_word()
|
||||
command = self.convert_alias(ctx.locale, alias, alias)
|
||||
ctx.invoked_with = command
|
||||
ctx.command = ctx.bot.all_commands.get(command)
|
||||
if ctx.command and isinstance(ctx.command, commands.GroupMixin):
|
||||
ctx = self.get_subcommand(ctx, ctx.command, [str(ctx.command)])
|
||||
return ctx
|
||||
|
||||
def get_subcommand(self, ctx, group, parents=[]):
|
||||
def _replace_command(self, view, index, alias, command):
|
||||
buf = view.buffer
|
||||
changed = buf[index:]
|
||||
view.buffer = buf[:index] + changed.replace(alias, command, 1)
|
||||
return view
|
||||
|
||||
def get_subcommand(self, ctx, group=None, parents=[]):
|
||||
""" Recursicely replaces all subcommand aliases with subcommands."""
|
||||
view = ctx.view
|
||||
prev = view.previous
|
||||
@@ -96,7 +129,7 @@ class Aliaser:
|
||||
parents.append(subcmd)
|
||||
|
||||
# Replace the alias in the command
|
||||
view.buffer = view.buffer.replace(alias, subcmd)
|
||||
self._replace_command(view, idx, alias, subcmd)
|
||||
|
||||
# Update the view to account for difference in length
|
||||
strdiff = len(subcmd) - len(alias)
|
||||
@@ -104,7 +137,10 @@ class Aliaser:
|
||||
view.index += strdiff
|
||||
|
||||
# Get the subcommand
|
||||
sub = group.all_commands.get(subcmd, None)
|
||||
if group:
|
||||
sub = group.all_commands.get(subcmd, None)
|
||||
else:
|
||||
sub = ctx.bot.all_commands.get(subcmd, None)
|
||||
|
||||
# Translate any subsubcommands
|
||||
if sub and isinstance(sub, commands.GroupMixin):
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
import asyncio
|
||||
import discord
|
||||
import math
|
||||
import lavalink
|
||||
|
||||
|
||||
class CantScroll(Exception):
|
||||
pass
|
||||
|
||||
# Maybe slightly very copied from rdanny
|
||||
# Thanks danny <3
|
||||
|
||||
|
||||
class EmbedScroller:
|
||||
def __init__(self, ctx, pages):
|
||||
|
||||
self.bot = ctx.bot
|
||||
self.pages = pages
|
||||
self.cmdmsg = ctx.message
|
||||
self.message = ctx.message
|
||||
self.channel = ctx.channel
|
||||
self.author = ctx.author
|
||||
|
||||
if len(self.pages) > 1:
|
||||
self.scrolling = True
|
||||
else:
|
||||
self.scrolling = False
|
||||
self.reaction_emojis = [
|
||||
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.first_page),
|
||||
('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page),
|
||||
('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page),
|
||||
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.last_page),
|
||||
('❌', self.stop_scrolling),
|
||||
]
|
||||
|
||||
if ctx.guild is not None:
|
||||
self.permissions = self.channel.permissions_for(ctx.guild.me)
|
||||
else:
|
||||
self.permissions = self.channel.permissions_for(ctx.bot.user)
|
||||
|
||||
if not self.permissions.embed_links:
|
||||
raise CantScroll('Bot does not have embed links permission.')
|
||||
|
||||
if not self.permissions.send_messages:
|
||||
raise CantScroll('Bot cannot send messages.')
|
||||
|
||||
if self.scrolling:
|
||||
# verify we can actually use the pagination session
|
||||
if not self.permissions.add_reactions:
|
||||
raise CantScroll('Bot does not have add reactions permission.')
|
||||
|
||||
if not self.permissions.read_message_history:
|
||||
raise CantScroll('Bot does not have Read Message History permission.')
|
||||
|
||||
async def send(self):
|
||||
self.current_page = 0
|
||||
# No embeds to scroll through
|
||||
if not self.pages:
|
||||
return
|
||||
|
||||
if not self.scrolling:
|
||||
return await self.channel.send(embed=self.pages[0])
|
||||
|
||||
self.message = await self.channel.send(embed=self.pages[0])
|
||||
for (reaction, _) in self.reaction_emojis:
|
||||
if len(self.pages) == 2 and reaction in ('\u23ed', '\u23ee'):
|
||||
continue
|
||||
|
||||
await self.message.add_reaction(reaction)
|
||||
|
||||
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 first_page(self):
|
||||
await self.scroll(0)
|
||||
|
||||
async def last_page(self):
|
||||
await self.scroll(len(self.pages) - 1)
|
||||
|
||||
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.delete()
|
||||
await self.cmdmsg.delete()
|
||||
|
||||
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 (emoji, func) in self.reaction_emojis:
|
||||
if reaction.emoji == emoji:
|
||||
self.match = func
|
||||
return True
|
||||
return False
|
||||
|
||||
async def start_scrolling(self):
|
||||
if not self.scrolling:
|
||||
await self.send()
|
||||
else:
|
||||
self.bot.loop.create_task(self.send())
|
||||
|
||||
while self.scrolling:
|
||||
try:
|
||||
reaction, user = await self.bot.wait_for('reaction_add', check=self.react_check, timeout=120.0)
|
||||
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
|
||||
|
||||
await self.match()
|
||||
|
||||
|
||||
class ScrollerFromLines(EmbedScroller):
|
||||
def __init__(self, ctx, description, lines, lines_per_page=10):
|
||||
pagecount = math.ceil(len(lines) / lines_per_page)
|
||||
pages = []
|
||||
page = ''
|
||||
for index, line in enumerate(lines):
|
||||
page += line + '\n'
|
||||
if index % lines_per_page == lines_per_page - 1:
|
||||
embed = discord.Embed(color=0xEFD26C,
|
||||
title=description,
|
||||
description=page)
|
||||
embed.set_footer(text=localizer.format_str("{queue.pageindicator}",
|
||||
_current=index//lines_per_page + 1,
|
||||
_total=pagecount))
|
||||
pages.append(embed)
|
||||
page = ''
|
||||
|
||||
if page != '':
|
||||
embed = discord.Embed(color=0xEFD26C,
|
||||
description=page)
|
||||
|
||||
embed.set_footer(text=localizer.format_str("{queue.pageindicator}",
|
||||
_current=pagecount,
|
||||
_total=pagecount))
|
||||
pages.append(embed)
|
||||
|
||||
super().__init__(ctx=ctx, pages=pages)
|
||||
|
||||
|
||||
class QueueScroller(EmbedScroller):
|
||||
""" Fugly, but works for now """
|
||||
def __init__(self, ctx, queue, localizer, lines_per_page=10, user_name: str=None):
|
||||
|
||||
pagecount = math.ceil(len(queue) / lines_per_page)
|
||||
self.queue = queue
|
||||
|
||||
if user_name is None:
|
||||
title = localizer.format_str("{queue.length}",
|
||||
_length=len(queue))
|
||||
else:
|
||||
title = localizer.format_str("{queue.userqueue}",
|
||||
_user=user_name,
|
||||
_length=len(queue))
|
||||
pages = []
|
||||
page = ''
|
||||
for index, temp in enumerate(queue):
|
||||
if user_name is None:
|
||||
track = temp
|
||||
page += localizer.format_str("{queue.globaltrack}",
|
||||
_index=index+1,
|
||||
_title=track.title,
|
||||
_uri=track.uri,
|
||||
_user_id=track.requester)
|
||||
else:
|
||||
track, globpos = temp
|
||||
page += localizer.format_str("{queue.usertrack}",
|
||||
_index=index+1,
|
||||
_globalindex=globpos+1,
|
||||
_title=track.title,
|
||||
_uri=track.uri)
|
||||
|
||||
if index % lines_per_page == lines_per_page - 1:
|
||||
embed = discord.Embed(color=0xEFD26C,
|
||||
title=title,
|
||||
description=page)
|
||||
embed.set_footer(text=localizer.format_str("{queue.pageindicator}",
|
||||
_current=index//lines_per_page + 1,
|
||||
_total=pagecount))
|
||||
pages.append(embed)
|
||||
page = ''
|
||||
|
||||
if page != '':
|
||||
embed = discord.Embed(color=0xEFD26C,
|
||||
title=title,
|
||||
description=page)
|
||||
embed.set_footer(text=localizer.format_str("{queue.pageindicator}",
|
||||
_current=pagecount,
|
||||
_total=pagecount))
|
||||
pages.append(embed)
|
||||
|
||||
super().__init__(ctx=ctx, pages=pages)
|
||||
|
||||
async def scroll(self, page):
|
||||
# overwrite to add ability to update queue length/add scrubber.
|
||||
if page < 0 or page >= len(self.pages):
|
||||
return
|
||||
self.current_page = page
|
||||
await self.message.edit(embed=self.pages[page])
|
||||
@@ -52,7 +52,7 @@ class Localizer:
|
||||
self.localization_table[lang] = {}
|
||||
l_table = self.localization_table[lang]
|
||||
for file in glob(path.join(self.localization_folder, lang, "*.yaml")):
|
||||
if 'aliases' in file:
|
||||
if 'aliases' in file or 'commands' in file:
|
||||
continue
|
||||
file_base = path.basename(file).split(".")[0]
|
||||
with open(file, "r", encoding='utf-8') as f:
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
import discord
|
||||
import asyncio
|
||||
|
||||
|
||||
class CantScroll(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BasePaginator:
|
||||
def __init__(self, max_size=2000, max_units=10):
|
||||
self._pages = []
|
||||
self._current_page_size = 0
|
||||
self._current_units = 0
|
||||
self._max_size = max_size
|
||||
self._max_units = max_units
|
||||
|
||||
def close_page(self):
|
||||
pass
|
||||
|
||||
def add_page_indicator(self, localizer, localizer_str=None, prefix=None):
|
||||
self.close_page()
|
||||
if localizer_str:
|
||||
for i, page in enumerate(self._pages, start=1):
|
||||
page.set_footer(text=localizer.format_str(localizer_str,
|
||||
_current=i,
|
||||
_total=len(self._pages),
|
||||
_prefix=prefix))
|
||||
else:
|
||||
for i, page in enumerate(self._pages, start=1):
|
||||
page.set_footer(text=f"{i}/{len(self._pages)}")
|
||||
|
||||
def append_paginator(self, paginator):
|
||||
if not isinstance(paginator, BasePaginator):
|
||||
raise TypeError('Pageinator needs to be a subclass of BasePaginator.')
|
||||
self.close_page()
|
||||
for page in paginator.pages:
|
||||
self.pages.append(page)
|
||||
|
||||
@property
|
||||
def pages(self):
|
||||
if self._current_page_size > 0:
|
||||
self.close_page()
|
||||
return self._pages
|
||||
|
||||
|
||||
class TextPaginator(BasePaginator):
|
||||
def __init__(self, max_size=2000, max_lines=10, **embed_base):
|
||||
super().__init__(max_size=max_size, max_units=max_lines)
|
||||
self._current_page = []
|
||||
self.embed_base = embed_base
|
||||
|
||||
def close_page(self):
|
||||
if self._current_page_size > 0:
|
||||
embed = discord.Embed(**self.embed_base)
|
||||
embed.description = '\n'.join(self._current_page)
|
||||
self._pages.append(embed)
|
||||
|
||||
self._current_page_size = 0
|
||||
self._current_units = 0
|
||||
self._current_page = []
|
||||
|
||||
def add_line(self, line='', *, empty=False):
|
||||
if len(line) > self._max_size:
|
||||
raise RuntimeError(f'Line exceeds maximum page size {self._max_size}')
|
||||
|
||||
if self._current_page_size + len(line) + 1 > self._max_size:
|
||||
self.close_page()
|
||||
|
||||
if self._current_units >= self._max_units:
|
||||
self.close_page()
|
||||
|
||||
self._current_page_size += len(line) + 1
|
||||
self._current_units += 1
|
||||
self._current_page.append(line)
|
||||
|
||||
if empty:
|
||||
self._current_page.append('')
|
||||
self._current_page_size += 1
|
||||
|
||||
|
||||
class FieldPaginator(BasePaginator):
|
||||
def __init__(self, max_size=5000, max_fields=8, **embed_base):
|
||||
super().__init__(max_size=max_size, max_units=max_fields)
|
||||
self._embed_base = embed_base
|
||||
self._current_page = discord.Embed(**self._embed_base)
|
||||
|
||||
def close_page(self):
|
||||
if self._current_page_size > 0:
|
||||
self._pages.append(self._current_page)
|
||||
self._current_page_size = 0
|
||||
self._current_units = 0
|
||||
self._current_page = discord.Embed(**self._embed_base)
|
||||
|
||||
def add_field(self, name, value, inline=False):
|
||||
field = {"name": name, "value": value}
|
||||
fieldsize = sum([len(val) for _, val in field.items()])
|
||||
if len(name) > 256 or len(value) > 1024:
|
||||
raise RuntimeError(f'Maximum field size exceeded, max name length: 256. max value length: 1024.')
|
||||
|
||||
if self._current_page_size + fieldsize > self._max_size:
|
||||
self.close_page()
|
||||
|
||||
if self._current_units >= self._max_units:
|
||||
self.close_page()
|
||||
|
||||
field["inline"] = inline
|
||||
self._current_page_size += fieldsize
|
||||
self._current_units += 1
|
||||
self._current_page.add_field(**field)
|
||||
|
||||
|
||||
class QueuePaginator(TextPaginator):
|
||||
def __init__(self, localizer, queue, color, user_name: str=None):
|
||||
self.localizer = localizer
|
||||
self.queue = queue
|
||||
|
||||
if user_name is None:
|
||||
title = localizer.format_str("{queue.length}",
|
||||
_length=len(queue))
|
||||
else:
|
||||
title = localizer.format_str("{queue.userqueue}",
|
||||
_user=user_name,
|
||||
_length=len(queue))
|
||||
|
||||
super().__init__(max_lines=10, **{"color": color, "title": title})
|
||||
|
||||
for index, temp in enumerate(queue):
|
||||
if user_name is None:
|
||||
track = temp
|
||||
queued_track = localizer.format_str("{queue.globaltrack}", _index=index+1,
|
||||
_title=track.title, _uri=track.uri,
|
||||
_user_id=track.requester)
|
||||
else:
|
||||
track, globpos = temp
|
||||
queued_track = localizer.format_str("{queue.usertrack}", _index=index+1,
|
||||
_globalindex=globpos+1, _title=track.title,
|
||||
_uri=track.uri)
|
||||
|
||||
self.add_line(queued_track)
|
||||
self.add_page_indicator(self.localizer, "{queue.pageindicator}")
|
||||
|
||||
|
||||
class HelpPaginator(FieldPaginator):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def force_close_page(self):
|
||||
self._pages.append(self._current_page)
|
||||
self._current_page_size = 0
|
||||
self._current_units = 0
|
||||
self._current_page = discord.Embed(**self._embed_base)
|
||||
|
||||
def add_command_field(self, cmd_dict):
|
||||
if not isinstance(cmd_dict, dict):
|
||||
return
|
||||
aliases = cmd_dict.get('aliases', [])
|
||||
args = cmd_dict.get('args', '')
|
||||
description = cmd_dict.get('description', '')
|
||||
|
||||
cmd = str(aliases[0])
|
||||
|
||||
cmd += ' ' + args
|
||||
self.add_field(name=cmd, value=description, inline=False)
|
||||
|
||||
|
||||
# Maybe slightly very copied from rdanny
|
||||
# Thanks danny <3
|
||||
|
||||
class Scroller:
|
||||
def __init__(self, ctx, paginator):
|
||||
|
||||
self.bot = ctx.bot
|
||||
self.pages = paginator.pages
|
||||
self.cmdmsg = ctx.message
|
||||
self.message = ctx.message
|
||||
self.channel = ctx.channel
|
||||
self.author = ctx.author
|
||||
|
||||
if len(self.pages) > 1:
|
||||
self.scrolling = True
|
||||
else:
|
||||
self.scrolling = False
|
||||
self.reaction_emojis = [
|
||||
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.first_page),
|
||||
('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page),
|
||||
('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page),
|
||||
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.last_page),
|
||||
('❌', self.stop_scrolling),
|
||||
]
|
||||
|
||||
if ctx.guild is not None:
|
||||
self.permissions = self.channel.permissions_for(ctx.guild.me)
|
||||
else:
|
||||
self.permissions = self.channel.permissions_for(ctx.bot.user)
|
||||
|
||||
if not self.permissions.embed_links:
|
||||
raise CantScroll('Bot does not have embed links permission.')
|
||||
|
||||
if not self.permissions.send_messages:
|
||||
raise CantScroll('Bot cannot send messages.')
|
||||
|
||||
if self.scrolling:
|
||||
# verify we can actually use the pagination session
|
||||
if not self.permissions.add_reactions:
|
||||
raise CantScroll('Bot does not have add reactions permission.')
|
||||
|
||||
if not self.permissions.read_message_history:
|
||||
raise CantScroll('Bot does not have Read Message History permission.')
|
||||
|
||||
async def send(self):
|
||||
self.current_page = 0
|
||||
# No embeds to scroll through
|
||||
if not self.pages:
|
||||
return
|
||||
|
||||
if not self.scrolling:
|
||||
return await self.channel.send(embed=self.pages[0])
|
||||
|
||||
self.message = await self.channel.send(embed=self.pages[0])
|
||||
for (reaction, _) in self.reaction_emojis:
|
||||
if len(self.pages) == 2 and reaction in ('\u23ed', '\u23ee'):
|
||||
continue
|
||||
|
||||
await self.message.add_reaction(reaction)
|
||||
|
||||
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 first_page(self):
|
||||
await self.scroll(0)
|
||||
|
||||
async def last_page(self):
|
||||
await self.scroll(len(self.pages) - 1)
|
||||
|
||||
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.delete()
|
||||
await self.cmdmsg.delete()
|
||||
|
||||
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 (emoji, func) in self.reaction_emojis:
|
||||
if reaction.emoji == emoji:
|
||||
self.match = func
|
||||
return True
|
||||
return False
|
||||
|
||||
async def start_scrolling(self):
|
||||
if not self.scrolling:
|
||||
await self.send()
|
||||
else:
|
||||
self.bot.loop.create_task(self.send())
|
||||
|
||||
while self.scrolling:
|
||||
try:
|
||||
reaction, user = await self.bot.wait_for('reaction_add', check=self.react_check, timeout=120.0)
|
||||
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
|
||||
|
||||
await self.match()
|
||||
@@ -1,63 +0,0 @@
|
||||
# Aliases for each of the commands in the the bot(except the forgotten onces.)
|
||||
# Aliases without subcommands don't need to have "aliases:", specified.
|
||||
# For commands with subcommands you need to have one subcategory called aliases and one called subcommands.
|
||||
|
||||
|
||||
# Music
|
||||
play: [p]
|
||||
now: [np, nowplaying]
|
||||
queue: [q]
|
||||
myqueue: [mq]
|
||||
seek: []
|
||||
skip: []
|
||||
skipto: [forceskip]
|
||||
stop: []
|
||||
pause: [resume]
|
||||
shuffle: []
|
||||
move: [m]
|
||||
remove: [rem]
|
||||
DJremove: [djremove]
|
||||
removeuser: []
|
||||
search: [s]
|
||||
disconnect: [dc]
|
||||
volume: [v, vol]
|
||||
normalize: [normal]
|
||||
boost: [bassboost]
|
||||
history: [h]
|
||||
scrub: []
|
||||
|
||||
# Misc
|
||||
info: []
|
||||
musicinfo: []
|
||||
uptime: []
|
||||
ping: []
|
||||
guilds: []
|
||||
reloadlocale: []
|
||||
reloadalias: []
|
||||
|
||||
# Settings
|
||||
settings:
|
||||
aliases: [set]
|
||||
sub_commands:
|
||||
current: [show]
|
||||
serverlocale: [lang]
|
||||
djroles: []
|
||||
dynamicmax: []
|
||||
musicchannels: [vc]
|
||||
listenchannels: []
|
||||
textchannels: [tc]
|
||||
maxduration: []
|
||||
modrole: []
|
||||
resetprefix: []
|
||||
serverprefix: []
|
||||
threshold: []
|
||||
|
||||
# Cogs
|
||||
cogs:
|
||||
aliases: []
|
||||
sub_commands:
|
||||
load: []
|
||||
unload: []
|
||||
reload: []
|
||||
reloadall: []
|
||||
shutdown: []
|
||||
@@ -0,0 +1,185 @@
|
||||
# Aliases and translated versions of help messages and arguments
|
||||
# for each of the commands in the the bot(except the forgotten onces.)
|
||||
# Currently no fallback so everything has to be translated.
|
||||
|
||||
# Help
|
||||
help:
|
||||
aliases: [help]
|
||||
args: '<commands>'
|
||||
description: 'Shows a help message.'
|
||||
|
||||
|
||||
# Music
|
||||
play:
|
||||
aliases: [play, p]
|
||||
args: '<query>' # This is just a cosmetic representation of the arguments.
|
||||
description: 'Searches and plays a song from a given query.'
|
||||
now:
|
||||
aliases: [now, np, nowplaying]
|
||||
description: 'Show the song currently playing.'
|
||||
queue:
|
||||
aliases: [queue, q]
|
||||
args: '[user]'
|
||||
description: 'Shows the queue. Shows a user queue if user is specified.'
|
||||
myqueue:
|
||||
aliases: [myqueue, mq]
|
||||
description: 'Shows your queue.'
|
||||
seek:
|
||||
aliases: [seek]
|
||||
args: '<seconds>'
|
||||
description: 'Seek forward or backwards in the song.'
|
||||
skip:
|
||||
aliases: [skip]
|
||||
description: 'Vote to skip the current song.'
|
||||
skipto:
|
||||
aliases: [skipto, forceskip]
|
||||
args: '<queue position>'
|
||||
description: 'Skips to the specified position in the queue.'
|
||||
stop:
|
||||
aliases: [stop]
|
||||
description: 'Stops playing and clears the queue.'
|
||||
pause:
|
||||
aliases: [pause, resume]
|
||||
description: 'Pause/resume the current song.'
|
||||
shuffle:
|
||||
aliases: [shuffle]
|
||||
description: 'Shuffles your queue'
|
||||
move:
|
||||
aliases: [move, m]
|
||||
args: '<start_pos> <end_pos>'
|
||||
description: 'Moves a track in your queue.'
|
||||
remove:
|
||||
aliases: [rem]
|
||||
args: '<pos>'
|
||||
description: 'Removes a song from your queue.'
|
||||
DJremove:
|
||||
aliases: [DJremove, djremove]
|
||||
args: '<pos>'
|
||||
description: 'Removes a song from the global queue.'
|
||||
removeuser:
|
||||
aliases: [removeuser]
|
||||
args: '<user>'
|
||||
description: 'Removes all songs queued by <user>.'
|
||||
search:
|
||||
aliases: [search, s]
|
||||
args: '<query>'
|
||||
description: 'Returns a list of possible songs.'
|
||||
disconnect:
|
||||
aliases: [disconnect, dc]
|
||||
description: 'Clears the queue, stops playing and leaves the current voice channel.'
|
||||
volume:
|
||||
aliases: [volume, v, vol]
|
||||
args: '<vol>'
|
||||
description: 'Sets the volume of the music.'
|
||||
normalize:
|
||||
aliases: [nomralize, normal]
|
||||
description: 'Resets the volume and the equalizer.'
|
||||
boost:
|
||||
aliases: [boost, bassboost]
|
||||
args: <True/False>
|
||||
description: 'Turns on or off bass boost'
|
||||
history:
|
||||
aliases: [history, h]
|
||||
description: 'Shows the last 10 songs played.'
|
||||
scrub:
|
||||
aliases: [scrub]
|
||||
description: 'Shows a temporary controller/scrubber.'
|
||||
|
||||
# Misc
|
||||
info:
|
||||
aliases: [info]
|
||||
description: 'Shows info about the bot.'
|
||||
musicinfo:
|
||||
aliases: [musicinfo]
|
||||
description: 'Shows music related info about the bot.'
|
||||
uptime:
|
||||
aliases: [uptime]
|
||||
description: 'Shows how long the bot has been running.'
|
||||
ping:
|
||||
aliases: [ping]
|
||||
description: 'Get the current latency of the bot.'
|
||||
guilds:
|
||||
aliases: [guilds]
|
||||
description: 'Show the guilds the bot is in'
|
||||
reloadlocale:
|
||||
aliases: [reloadlocale]
|
||||
description: 'Reload all response translations'
|
||||
reloadalias:
|
||||
aliases: [reloadalias]
|
||||
description: 'Reload all aliases and help information.'
|
||||
|
||||
# Settings
|
||||
settings:
|
||||
aliases: [settings, set]
|
||||
description: 'Manage server settings.'
|
||||
sub_commands:
|
||||
current:
|
||||
aliases: [current, show]
|
||||
description: 'Show current settings.'
|
||||
serverlocale:
|
||||
aliases: [serverlocale, lang]
|
||||
args: '<locale>'
|
||||
description: 'Set the server language.'
|
||||
djroles:
|
||||
aliases: [djroles]
|
||||
args: '[roles...]'
|
||||
description: 'Set the DJ roles for the server.'
|
||||
dynamicmax:
|
||||
aliases: [dynamicmax]
|
||||
args: '<True/false>'
|
||||
description: 'Choose if the max song duration is dynamic.'
|
||||
musicchannels:
|
||||
aliases: [musicchannels, vc]
|
||||
args: '[voicechannels...]'
|
||||
description: 'Set the channels where the bot will play music.'
|
||||
listenchannels:
|
||||
aliases: [listenchannels]
|
||||
args: '[voicechannels...]'
|
||||
description: 'Set the channels where the bot will mute people who join.'
|
||||
textchannels:
|
||||
aliases: [textchannels, tc]
|
||||
args: '[textchannels...]'
|
||||
description: 'Set the channels where the bot will accept music commands.'
|
||||
maxduration:
|
||||
aliases: [maxduration]
|
||||
args: '<duration>'
|
||||
description: 'Max song length that can be queued in minutes.'
|
||||
modrole:
|
||||
aliases: [modrole]
|
||||
args: '[roles...]'
|
||||
description: 'Set the modroles for the server.'
|
||||
resetprefix:
|
||||
aliases: [resetprefix]
|
||||
description: 'reset the prefixes on the server to the bots default.'
|
||||
serverprefix:
|
||||
aliases: [serverprefix]
|
||||
args: '[prefixes...]'
|
||||
description: 'Set serverprefixes. Not listing any prefixes will show the current ones.'
|
||||
threshold:
|
||||
aliases: [threshold]
|
||||
args: '<threshold>'
|
||||
description: 'Set the vote threshold required to skip a song.'
|
||||
|
||||
# Cogs
|
||||
cogs:
|
||||
aliases: [cogs]
|
||||
description: 'cog management'
|
||||
sub_commands:
|
||||
load:
|
||||
aliases: [load]
|
||||
args: '<cog>'
|
||||
description: 'Loads a cog'
|
||||
unload:
|
||||
aliases: [unload]
|
||||
args: '<cog>'
|
||||
description: 'Unloads a cog'
|
||||
reload:
|
||||
aliases: [reload]
|
||||
args: '<cog>'
|
||||
description: 'Reloads a cog'
|
||||
reloadall:
|
||||
aliases: [reloadall]
|
||||
description: 'Reload all cogs'
|
||||
shutdown:
|
||||
aliases: [shutdown]
|
||||
description: 'Shuts down the bot'
|
||||
@@ -0,0 +1 @@
|
||||
pageindicator: Viewing page {_current}/{_total} | Type "{_prefix}help <command>" for more information
|
||||
@@ -23,8 +23,8 @@ queue:
|
||||
user_empty: "{_user}'s queue is empty"
|
||||
length: "**Queue** `{_length} songs`"
|
||||
userqueue: "**{_user}\\'s queue** `{_length}`"
|
||||
globaltrack: "`{_index}.` **[{_title}]({_uri})** _by <@{_user_id}>_\n"
|
||||
usertrack: "`{_index}({_globalindex}).` **[{_title}]({_uri})**\n"
|
||||
globaltrack: "`{_index}.` **[{_title}]({_uri})** _by <@{_user_id}>_"
|
||||
usertrack: "`{_index}({_globalindex}).` **[{_title}]({_uri})**"
|
||||
pageindicator: Viewing page {_current}/{_total}
|
||||
my_queue: Your queue is empty
|
||||
resume:
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
|
||||
# Music aliases
|
||||
play: [p, spill, s]
|
||||
now: [np, nå]
|
||||
queue: [q, kø, k]
|
||||
myqueue: [mq, minkø, mk]
|
||||
seek: [spol]
|
||||
skip: [hopp]
|
||||
skipto: [forceskip, hopptil, tvinghopp]
|
||||
stop: [stopp]
|
||||
pause: [resume, gjenoppta]
|
||||
shuffle: [stokk]
|
||||
move: [m, flytt, f]
|
||||
remove: [rem, fjern]
|
||||
DJremove: [DJfjern, djfjern]
|
||||
removeuser: [fjernbruker]
|
||||
search: [søk, finn]
|
||||
disconnect: [dc, kf, koblefra]
|
||||
volume: [vol, volum, lydstyrke, lyd]
|
||||
normalize: [normal, nl, normaliser]
|
||||
boost: [bassboost, bassforsterker]
|
||||
history: [h, hist, historie]
|
||||
scrub: [kontroller, konsoll]
|
||||
|
||||
# Other
|
||||
info: [informasjon]
|
||||
musicinfo: [musikkinfo, musikkinformasjon]
|
||||
|
||||
settings:
|
||||
aliases: [innstillinger]
|
||||
sub_commands:
|
||||
serverlocale: [språk]
|
||||
current: [gjeldende]
|
||||
djroles: [djroller]
|
||||
dynamicmax: [dynamiskmaks]
|
||||
listenchannels: []
|
||||
maxduration: [maksvarighet]
|
||||
modrole: [modrolle]
|
||||
musicchannels: [musikkanaler]
|
||||
resetprefix: []
|
||||
serverprefix: [serverprefiks]
|
||||
textchannels: [tekstkanaler]
|
||||
threshold: [grense]
|
||||
@@ -0,0 +1,185 @@
|
||||
# Aliases for each of the commands in the the bot(except the forgotten onces.)
|
||||
# Aliases without subcommands don't need to have "aliases:", specified.
|
||||
# For commands with subcommands you need to have one subcategory called aliases and one called subcommands.
|
||||
|
||||
# Help
|
||||
help:
|
||||
aliases: [hjelp]
|
||||
args: '<kommandoer>'
|
||||
description: 'Viser en hjelp-melding.'
|
||||
|
||||
|
||||
# Music
|
||||
play:
|
||||
aliases: [spill, s]
|
||||
args: '<sang>' # This is just a cosmetic representation of the arguments.
|
||||
description: 'Søker opp og spiller av en sang.'
|
||||
now:
|
||||
aliases: [nå, spillernå]
|
||||
description: 'Viser hvilken sang som spilles.'
|
||||
queue:
|
||||
aliases: [kø, k]
|
||||
args: '[bruker]'
|
||||
description: 'Viser køen. Viser en brukerkø om bruker er spesifisert.'
|
||||
myqueue:
|
||||
aliases: [minkø, mk]
|
||||
description: 'Viser din personlige kø.'
|
||||
seek:
|
||||
aliases: [spol]
|
||||
args: '<sekunder>'
|
||||
description: 'Spol frem eller tilbake i sangen.'
|
||||
skip:
|
||||
aliases: [hopp]
|
||||
description: 'Stem for å hoppe over sangen som spilles.'
|
||||
skipto:
|
||||
aliases: [hopptil, tvinghopp]
|
||||
args: '<køposisjon>'
|
||||
description: 'Hopper over til sangen i den spesifiserte køposisjonen.'
|
||||
stop:
|
||||
aliases: [stopp]
|
||||
description: 'Stopper avspillingen og tømmer køen.'
|
||||
pause:
|
||||
aliases: [pause, fortsett]
|
||||
description: 'Pauser/fortsetter den nåværende sangen.'
|
||||
shuffle:
|
||||
aliases: [omstokk, stokkom, bland]
|
||||
description: 'Stokker om rekkefølgen til den personlige køen din.'
|
||||
move:
|
||||
aliases: [flytt, f]
|
||||
args: '<fra_posisjon> <til_posisjon>'
|
||||
description: 'Flytter en sang i den personlige køen din.'
|
||||
remove:
|
||||
aliases: [fjern]
|
||||
args: '<posisjon>'
|
||||
description: 'Fjerner en sang fra personlige køen din.'
|
||||
DJremove:
|
||||
aliases: [DJfjern, djfjern]
|
||||
args: '<posisjon>'
|
||||
description: 'Fjerner en sang fra køen.'
|
||||
removeuser:
|
||||
aliases: [fjernbruker]
|
||||
args: '<bruker>'
|
||||
description: 'Fjerner alle sangene i køen som er lagt til av en spesifisert bruker.'
|
||||
search:
|
||||
aliases: [søk, finn]
|
||||
args: '<sang>'
|
||||
description: 'Søker opp og viser en liste med mulige sanger.'
|
||||
disconnect:
|
||||
aliases: [koblefra, kf]
|
||||
description: 'Tømmer køen, stopper avspillingen og forlater talekanalen.'
|
||||
volume:
|
||||
aliases: [volum, v, vol, lydnivå]
|
||||
args: '<vol>'
|
||||
description: 'Setter volumet på musikken.'
|
||||
normalize:
|
||||
aliases: [normaliser, normal]
|
||||
description: 'Tilbakestiller volumet og equalizer til standardinnstillinger.'
|
||||
boost:
|
||||
aliases: [bassforsterker, forsterkbass]
|
||||
args: ''
|
||||
description: 'Skrur av/på bassforsterkeren'
|
||||
history:
|
||||
aliases: [historikk, avspillingshistorikk, h]
|
||||
description: 'Viser en liste over de 10 siste avspilte sangene.'
|
||||
scrub:
|
||||
aliases: [kontroller]
|
||||
description: 'Gir deg en kontroller som du kan styre musikken med.'
|
||||
|
||||
# Misc
|
||||
info:
|
||||
aliases: [info, botinfo, båttinfo]
|
||||
description: 'Gir deg informasjon om båtten.'
|
||||
musicinfo:
|
||||
aliases: [musikkinfo]
|
||||
description: 'Gir deg informasjon om musikkspilleren til båtten.'
|
||||
uptime:
|
||||
aliases: [oppetid]
|
||||
description: 'Viser hvor lenge båtten har kjørt.'
|
||||
ping:
|
||||
aliases: [ping]
|
||||
description: 'Sjekker responstiden til båtten.'
|
||||
guilds:
|
||||
aliases: [tenarar]
|
||||
description: 'Sender en liste over tenarane som båtten er medlem av'
|
||||
reloadlocale:
|
||||
aliases: [reloadlocale]
|
||||
description: 'Laser inn alle oversetningsfilene på nytt'
|
||||
reloadalias:
|
||||
aliases: [reloadalias]
|
||||
description: 'Laster inn aliaser og hjelp på nytt.'
|
||||
|
||||
# Settings
|
||||
settings:
|
||||
aliases: [innstillinger, oppsett]
|
||||
description: 'Behandle serverinnstillinger.'
|
||||
sub_commands:
|
||||
current:
|
||||
aliases: [vis, gjeldende]
|
||||
description: 'Viser gjeldende innstillinger.'
|
||||
serverlocale:
|
||||
aliases: [språk]
|
||||
args: '<språk>'
|
||||
description: 'Endrer serverspråket.'
|
||||
djroles:
|
||||
aliases: [djroller, DJroller]
|
||||
args: '[roller...]'
|
||||
description: 'Setter DJ-rollene på serveren.'
|
||||
dynamicmax:
|
||||
aliases: [dynamiskmaks]
|
||||
args: '<True/false>'
|
||||
description: 'Velg om maks sanglengde skal være dynamisk eller ikke.'
|
||||
musicchannels:
|
||||
aliases: [musikk-kanal]
|
||||
args: '[talekanaler...]'
|
||||
description: 'Setter kanalene som båtten kan spille musikk i.'
|
||||
listenchannels:
|
||||
aliases: [lyttekanaler, lk]
|
||||
args: '[talekanaler...]'
|
||||
description: 'Setter kanalene hvor båtten vil automatisk dempe alle som kobler seg til den.'
|
||||
textchannels:
|
||||
aliases: [tekstkanaler, tk]
|
||||
args: '[tekstkanaler...]'
|
||||
description: 'Setter kanalene hvor man kan bruke musikk-kommandoer.'
|
||||
maxduration:
|
||||
aliases: [makslengde]
|
||||
args: '<lengde_i_minutter>'
|
||||
description: 'Setter makslengden på sanger som kan bli lagt til i køen.'
|
||||
modrole:
|
||||
aliases: [modrolle]
|
||||
args: '[roller...]'
|
||||
description: 'Setter serverens modrolle.'
|
||||
resetprefix:
|
||||
aliases: [resetprefiks]
|
||||
description: 'Tilbakestiller serverprefiksen til båtten sin standardprefiks.'
|
||||
serverprefix:
|
||||
aliases: [serverprefiks]
|
||||
args: '[prefikser...]'
|
||||
description: 'Setter serverprefiksen. Om ingen prefiks blir gitt, vil den vise serverens foreløpige satte prefikser.'
|
||||
threshold:
|
||||
aliases: [stemmegrense]
|
||||
args: '<grense>'
|
||||
description: 'Setter grensen for hvor mange prosent som må stemme for å hoppe over en sang.'
|
||||
|
||||
# Cogs
|
||||
cogs:
|
||||
aliases: [cogs]
|
||||
description: 'behandle cogs'
|
||||
sub_commands:
|
||||
load:
|
||||
aliases: [load]
|
||||
args: '<cog>'
|
||||
description: 'Laster inn en cog'
|
||||
unload:
|
||||
aliases: [unload]
|
||||
args: '<cog>'
|
||||
description: 'Unloads a cog'
|
||||
reload:
|
||||
aliases: [reload]
|
||||
args: '<cog>'
|
||||
description: 'Laster en cog inn på nytt.'
|
||||
reloadall:
|
||||
aliases: [reloadall]
|
||||
description: 'Laser inn alle cogs på nytt.'
|
||||
shutdown:
|
||||
aliases: [shutdown]
|
||||
description: 'Stopper båtten.'
|
||||
@@ -0,0 +1 @@
|
||||
pageindicator: Viser side {_current}/{_total} | Skriv "{_prefix}hjelp <kommando>" for mer informasjon
|
||||
@@ -23,8 +23,8 @@ queue:
|
||||
user_empty: "{_user} sin kø er tom"
|
||||
length: "**Kø** `{_length} sanger`"
|
||||
userqueue: "**{_user} sin kø** `{_length}` sanger"
|
||||
globaltrack: "`{_index}.` **[{_title}]({_uri})** _av <@{_user_id}>_\n"
|
||||
usertrack: "`{_index}({_globalindex}).` **[{_title}]({_uri})**\n"
|
||||
globaltrack: "`{_index}.` **[{_title}]({_uri})** _av <@{_user_id}>_"
|
||||
usertrack: "`{_index}({_globalindex}).` **[{_title}]({_uri})**"
|
||||
pageindicator: Viser side {_current}/{_total}
|
||||
my_queue: Din kø er tom
|
||||
resume:
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# Aliases for each of the commands in the the bot(except the forgotten onces.)
|
||||
# Aliases without subcommands don't need to have "aliases:", specified.
|
||||
# For commands with subcommands you need to have one subcategory called aliases and one called subcommands.
|
||||
|
||||
|
||||
# Music
|
||||
play:
|
||||
aliases: [play, p]
|
||||
args: <query>
|
||||
description: Searches and plays a song from a given query.
|
||||
now: [now, np, nowplaying]
|
||||
queue: [queue, q]
|
||||
myqueue: [myqueue, mq]
|
||||
seek: [seek]
|
||||
skip: [skip]
|
||||
skipto: [skipto, forceskip]
|
||||
stop: [stop]
|
||||
pause: [pause, resume]
|
||||
shuffle: [shuffle]
|
||||
move: [move, m]
|
||||
remove: [rem]
|
||||
DJremove: [DJremove, djremove]
|
||||
removeuser: [removeuser]
|
||||
search: [search, s]
|
||||
disconnect: [disconnect, dc]
|
||||
volume: [volume, v, vol]
|
||||
normalize: [nomralize, normal]
|
||||
boost: [boost, bassboost]
|
||||
history: [history, h]
|
||||
scrub: [scrub]
|
||||
|
||||
# Misc
|
||||
info: [info]
|
||||
musicinfo: [musicinfo]
|
||||
uptime: [uptime]
|
||||
ping: [ping]
|
||||
guilds: [guilds]
|
||||
reloadlocale: [reloadlocale]
|
||||
reloadalias: [reloadalias]
|
||||
|
||||
# Settings
|
||||
settings:
|
||||
aliases: [settings, set]
|
||||
sub_commands:
|
||||
current: [current, show]
|
||||
serverlocale: [serverlocale, lang]
|
||||
djroles: [djroles]
|
||||
dynamicmax: [dynamicmax]
|
||||
musicchannels: [musicchannels, vc]
|
||||
listenchannels: [listenchannels]
|
||||
textchannels: [textchannels, tc]
|
||||
maxduration: [maxduration]
|
||||
modrole: [modrole]
|
||||
resetprefix: [resetprefix]
|
||||
serverprefix: [serverprefix]
|
||||
threshold: [threshold]
|
||||
|
||||
# Cogs
|
||||
cogs:
|
||||
aliases: [cogs]
|
||||
sub_commands:
|
||||
load: [load]
|
||||
unload: [unload]
|
||||
reload: [reload]
|
||||
reloadall: [reloadall]
|
||||
shutdown: [shutdown]
|
||||
@@ -23,8 +23,8 @@ queue:
|
||||
user_empty: "{_user} sin kø er tom"
|
||||
length: "**Kø** `{_length} songar`"
|
||||
userqueue: Køen til **{_user}** `{_length}` songar
|
||||
globaltrack: "`{_index}.` **[{_title}]({_uri})** _av <@{_user_id}>_\n"
|
||||
usertrack: "`{_index}({_globalindex}).` **[{_title}]({_uri})**\n"
|
||||
globaltrack: "`{_index}.` **[{_title}]({_uri})** _av <@{_user_id}>_"
|
||||
usertrack: "`{_index}({_globalindex}).` **[{_title}]({_uri})**"
|
||||
pageindicator: Viser side {_current}/{_total}
|
||||
my_queue: Din kø er tom
|
||||
resume:
|
||||
|
||||
Reference in new issue
Block a user