Merge branch 'feature/cmdaliases' into 'dev'

Per locale/server aliases for commands and subcommands. Move to YAML.

See merge request Ev-1/shite-music-bot!14
This commit is contained in:
Ev-1 committed 2019-02-24 11:50:46 +00:00
commit eb0e0889ec
29 files changed
+755 -518

No files matched your search

+46 -13
View File
@@ -6,21 +6,31 @@ import traceback
import yaml
from discord.ext import commands
from cogs.utils.settings import Settings
from discord.ext.commands.view import StringView
from cogs.utils.settingsmanager import Settings
from cogs.utils.localizer import Localizer
initial_extensions = [
'cogs.cogs',
'cogs.botsettings',
'cogs.misc'
]
from cogs.utils.localizer import LocalizerWrapper
from cogs.utils.alias import Aliaser
from cogs.utils.context import Context
with codecs.open("data/config.yaml", 'r', encoding='utf8') as f:
conf = yaml.safe_load(f)
initial_extensions = [
'cogs.cogs',
'cogs.settings',
'cogs.misc'
]
on_ready_extensions = [
'cogs.music',
'cogs.musicevents'
]
def _get_prefix(bot, message):
if not message.guild:
return bot.settings.default_prefix
@@ -35,6 +45,7 @@ class Bot(commands.Bot):
self.settings = Settings(**conf['default server settings'])
self.localizer = Localizer(conf.get('locale path', "./localization"), conf.get('locale', 'en_en'))
self.aliaser = Aliaser(conf.get('locale path', "./localization"), conf.get('locale', 'en_en'))
self.debug = debug
for extension in initial_extensions:
@@ -61,9 +72,7 @@ class Bot(commands.Bot):
pass
elif isinstance(err, commands.NoPrivateMessage):
# Todo, fix, use default bot lang.
await ctx.send('That command is not available in DMs')
#await ctx.send(self.localizer.format_str("{commands.not_available_dm}", self.settings.get(ctx.guild, 'locale', 'default_locale')))
elif isinstance(err, commands.CheckFailure):
pass
@@ -75,19 +84,43 @@ class Bot(commands.Bot):
traceback.print_tb(tb)
print(err)
async def on_message(self, message):
if message.author.bot:
return
await self.process_commands(message)
async def process_commands(self, message):
ctx = await self.get_context(message, cls=Context)
# 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:
ctx.localizer = LocalizerWrapper(self.localizer, ctx.locale, ctx.command.cog_name.lower())
else:
ctx.localizer = LocalizerWrapper(self.localizer, ctx.locale, None)
await self.invoke(ctx)
async def on_ready(self):
if not hasattr(self, 'uptime'):
self.uptime = time.time()
if self.debug:
print('\n\nDebug mode')
for extension in on_ready_extensions:
try:
self.load_extension(extension)
except Exception as e:
print(e)
print(f'\nLogged in as: {self.user.name}' +
f' in {len(self.guilds)} servers.')
print(f'Version: {discord.__version__}\n')
self.load_extension('cogs.music')
self.load_extension('cogs.musicevents')
await self.change_presence(activity=discord.Game(type=0,
name=conf["bot"]["playing status"]),
status=discord.Status.online)
+19 -20
View File
@@ -45,18 +45,17 @@ class Misc:
"""
Info om musikkspilleren
"""
embed = discord.Embed(title='{info.music.title}', color=ctx.me.color)
embed = discord.Embed(title='{music.title}', color=ctx.me.color)
lavalink = self.bot.lavalink
listeners = 0
for guild, player in lavalink.players:
listeners += len(player.listeners)
embed.add_field(name='{info.music.players}', value=f'{len(lavalink.players)}')
embed.add_field(name='{info.music.listeners}', value=f'{listeners}')
embed = self.bot.localizer.format_embed(embed, self.bot.settings.get(ctx.guild, 'locale', 'default_locale'))
embed.add_field(name='{music.players}', value=f'{len(lavalink.players)}')
embed.add_field(name='{music.listeners}', value=f'{listeners}')
embed = ctx.localizer.format_embed(embed)
await ctx.send(embed=embed)
@commands.command(name="reloadlocale")
@@ -65,6 +64,12 @@ class Misc:
self.bot.localizer.load_localizations()
await ctx.send("Localizations reloaded.")
@commands.command(name="reloadalias")
async def reload_alias(self, ctx):
self.bot.aliaser.index_localizations()
self.bot.aliaser.load_localizations()
await ctx.send("Aliases reloaded.")
@commands.command()
async def info(self, ctx):
"""
@@ -93,19 +98,18 @@ class Misc:
embed.set_author(name=self.bot.user.name, icon_url=avatar)
embed.set_thumbnail(url=avatar)
embed.set_image(url='https://cdn.discordapp.com/attachments/298524946454282250/368118192251469835/vintage1turntable.png')
embed.add_field(name="{info.bot.what}",
value='{info.bot.infotext}', inline=False)
embed.add_field(name="{bot.what}",
value='{bot.infotext}', inline=False)
embed.set_footer(icon_url="https://cdn.discordapp.com/icons/532176350019321917/92f43a1f67308a99a30c169db4b671dd.png?size=64",
text="{info.bot.footer_text}")
embed.add_field(name="{info.bot.how}",
value='{info.bot.spectext}')
embed.add_field(name="{info.bot.how_many}",
value='{info.bot.stattext}')
embed.add_field(name="{info.bot.how_long}",
text="{bot.footer_text}")
embed.add_field(name="{bot.how}",
value='{bot.spectext}')
embed.add_field(name="{bot.how_many}",
value='{bot.stattext}')
embed.add_field(name="{bot.how_long}",
value=uptimetext)
embed = self.bot.localizer.format_embed(embed,
self.bot.settings.get(ctx.guild, 'locale', 'default_locale'),
embed = ctx.localizer.format_embed(embed,
_python_v=platform.python_version(),
_discord_v=discord.__version__,
_lavalink_v=LavalinkVersion,
@@ -114,11 +118,6 @@ class Misc:
)
await ctx.send(embed=embed)
@commands.command()
@checks.is_even()
async def only_me(self, ctx):
await ctx.send('Only you!')
def setup(bot):
bot.add_cog(Misc(bot))
+97 -134
View File
@@ -16,7 +16,7 @@ from typing import Optional
from .utils import checks, RoxUtils, timeformatter
from .utils.mixplayer import MixPlayer
from .utils.embedscroller import QueueScroller
from .utils.localizer import LocalizerWrapper
time_rx = re.compile('[0-9]+')
url_rx = re.compile('https?:\\/\\/(?:www\\.)?.+')
@@ -35,48 +35,29 @@ class Music:
bot.lavalink.add_node(**conf['lavalink nodes']['main'])
bot.add_listener(bot.lavalink.voice_update_handler, 'on_socket_response')
def getLocalizer(self, guild):
lang = self.bot.settings.get(guild, 'locale', 'default_locale')
return LocalizerWrapper(self.bot.localizer, lang, "music.response")
async def __local_check(self, ctx):
""" Ensures the commands are used in the correct channels """
async def __before_invoke(self, ctx):
if not ctx.guild:
raise commands.NoPrivateMessage
textchannels = self.bot.settings.get(ctx.guild, 'channels.text', [])
if textchannels:
if ctx.channel.id not in textchannels:
localizer = self.getLocalizer(ctx.guild)
response = localizer.format_str('{settings_check.textchannel}')
response = ctx.localizer.format_str('{settings_check.textchannel}')
for channel_id in textchannels:
response += f'<#{channel_id}>, '
await ctx.send(response[:-2])
return False
return await ctx.send(response[:-2])
await self.ensure_voice(ctx)
return True
async def __before_invoke(self, ctx):
# TODO: rewrite this thing. Probably remove ensure_voice.
guild_check = ctx.guild is not None
# This is essentially the same as `@commands.guild_only()`
# except it saves us repeating ourselves (and also a few lines).
if guild_check:
await self.ensure_voice(ctx)
# Ensure that the bot and command author share a mutual voicechannel.
else:
raise commands.NoPrivateMessage
return guild_check
async def connect_to(self, guild_id: int, channel_id: str):
""" Connects to the given voicechannel ID. A channel_id of `None` means disconnect. """
ws = self.bot._connection._get_websocket(guild_id)
await ws.voice_state(str(guild_id), channel_id)
@commands.command(name='play', aliases=['p','spill','s','spel'])
@commands.command(name='play')
async def _play(self, ctx, *, query: str):
""" Searches and plays a song from a given query. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
query = query.strip('<>')
if not url_rx.match(query):
@@ -85,7 +66,7 @@ class Music:
results = await player.node.get_tracks(query)
if not results or not results['tracks']:
return await ctx.send(localizer.format_str("{nothing_found}"))
return await ctx.send(ctx.localizer.format_str("{nothing_found}"))
embed = discord.Embed(color=ctx.me.color)
@@ -106,33 +87,32 @@ class Music:
embed.title = '{playlist_enqued}'
embed.description = f'{results["playlistInfo"]["name"]} - {numtracks} {{tracks}}'
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
await ctx.send(embed=embed)
else:
track = results['tracks'][0]
await self.enqueue(ctx, track, embed)
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
await ctx.send(embed=embed)
if not player.is_playing:
await player.play()
@commands.command(name='seek', aliases=['spol'])
@commands.command(name='seek')
@checks.DJ_or(alone=True)
async def _seek(self, ctx, *, time: str):
""" Seeks to a given position in a track. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if not player.is_playing:
return await ctx.send(localizer.format_str("{not_playing}"))
return await ctx.send(ctx.localizer.format_str("{not_playing}"))
if ctx.author not in player.listeners:
return await ctx.send(localizer.format_str("{have_to_listen}"))
return await ctx.send(ctx.localizer.format_str("{have_to_listen}"))
seconds = time_rx.search(time)
if not seconds:
return await ctx.send(localizer.format_str("{seek.missing_amount}"))
return await ctx.send(ctx.localizer.format_str("{seek.missing_amount}"))
seconds = int(seconds.group()) * 1000
if time.startswith('-'):
@@ -140,17 +120,16 @@ class Music:
track_time = player.position + seconds
await player.seek(track_time)
msg = localizer.format_str("{seek.track_moved}", _position=timeformatter.format(track_time))
msg = ctx.localizer.format_str("{seek.track_moved}", _position=timeformatter.format(track_time))
await ctx.send(msg)
@commands.command(name='skip', aliases=['hopp'])
@commands.command(name='skip')
async def _skip(self, ctx):
""" Skips the current track. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if not player.is_playing:
return await ctx.send(localizer.format_str("{not_playing}"))
return await ctx.send(ctx.localizer.format_str("{not_playing}"))
player.add_skipper(ctx.author)
total = len(player.listeners)
@@ -159,56 +138,53 @@ class Music:
if skips/total >= threshold/100 or player.current.requester == ctx.author.id:
await player.skip()
await ctx.send(localizer.format_str("{skip.skipped}"))
await ctx.send(ctx.localizer.format_str("{skip.skipped}"))
else:
if skips != 0:
needed = math.ceil(total*threshold/100)
msg = localizer.format_str("{skip.require_vote}", _skips=skips, _total=needed)
msg = ctx.localizer.format_str("{skip.require_vote}", _skips=skips, _total=needed)
await ctx.send(msg)
@commands.command(name='skipto', aliases=['forceskip','hopptil','tvinghopp'])
@commands.command(name='skipto')
@checks.DJ_or(alone=True)
async def _skip_to(self, ctx, pos: int=1):
""" Plays the queue from a specific point. Disregards tracks before the pos. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if ctx.author not in player.listeners:
return await ctx.send(localizer.format_str("{have_to_listen}"))
return await ctx.send(ctx.localizer.format_str("{have_to_listen}"))
if pos < 1:
return await ctx.send(localizer.format_str("{skip_to.invalid_pos}"))
return await ctx.send(ctx.localizer.format_str("{skip_to.invalid_pos}"))
if len(player.queue) < pos:
return await ctx.send(localizer.format_str("{skip_to.exceeds_queue}"))
return await ctx.send(ctx.localizer.format_str("{skip_to.exceeds_queue}"))
await player.skip(pos - 1)
msg = localizer.format_str("{skip_to.skipped_to}", _title=player.current.title, _pos=pos)
msg = ctx.localizer.format_str("{skip_to.skipped_to}", _title=player.current.title, _pos=pos)
await ctx.send(msg)
@commands.command(name='stop', aliases=['stopp'])
@commands.command(name='stop')
@checks.DJ_or(alone=True)
async def _stop(self, ctx):
""" Stops the player and clears its queue. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if ctx.author not in player.listeners:
return await ctx.send(localizer.format_str("{have_to_listen}"))
return await ctx.send(ctx.localizer.format_str("{have_to_listen}"))
if not player.is_playing:
return await ctx.send(localizer.format_str("{not_playing}"))
return await ctx.send(ctx.localizer.format_str("{not_playing}"))
player.queue.clear()
await player.stop()
await ctx.send(localizer.format_str("{stop}"))
await ctx.send(ctx.localizer.format_str("{stop}"))
@commands.command(name='now', aliases=['np','current', 'nå', 'nåspilles', 'gjeldende', 'spillernå','spelarno','nospelar'])
@commands.command(name='now')
async def _now(self, ctx):
""" Shows some stats about the currently playing song. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if not player.current:
return await ctx.send(localizer.format_str("{not_playing}"))
return await ctx.send(ctx.localizer.format_str("{not_playing}"))
position = timeformatter.format(player.position)
if player.current.stream:
@@ -219,7 +195,7 @@ class Music:
member = ctx.guild.get_member(player.current.requester)
embed = discord.Embed(color=ctx.me.color, description=song, title='{now}')
thumbnail_url = await RoxUtils.ThumbNailer.identify(self,player.current.identifier, player.current.uri)
thumbnail_url = await RoxUtils.ThumbNailer.identify(self, player.current.identifier, player.current.uri)
if thumbnail_url:
embed.set_thumbnail(url=thumbnail_url)
@@ -229,100 +205,96 @@ class Music:
member_identifier = member.name
embed.set_footer(text=f'{{requested_by}} {member_identifier}', icon_url=member.avatar_url)
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
await ctx.send(embed=embed)
@commands.command(name='queue', aliases=['q', 'kø'])
@commands.command(name='queue')
async def _queue(self, ctx, user: discord.Member=None):
""" Shows the player's queue. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if player.queue.empty:
return await ctx.send(localizer.format_str("{queue.empty}"))
embed = discord.Embed(description='{queue.empty}', color=ctx.me.color)
embed = ctx.localizer.format_embed(embed)
return await ctx.send(embed=embed)
if user is None:
queue = player.global_queue()
scroller = QueueScroller(ctx, queue, localizer, lines_per_page=10)
scroller = QueueScroller(ctx, queue, ctx.localizer, lines_per_page=10)
await scroller.start_scrolling()
else:
user_queue = player.user_queue(user.id, dual=True)
if not user_queue:
return await ctx.send(localizer.format_str("{queue.empty}", _user=user.name))
return await ctx.send(ctx.localizer.format_str("{queue.empty}", _user=user.name))
scroller = QueueScroller(ctx, user_queue, localizer, lines_per_page=10, user_name=user.name)
scroller = QueueScroller(ctx, user_queue, ctx.localizer, lines_per_page=10, user_name=user.name)
await scroller.start_scrolling()
@commands.command(name='myqueue', aliases=['mq','minkø','mk'])
@commands.command(name='myqueue')
async def _myqueue(self, ctx):
""" Shows your queue. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
user_queue = player.user_queue(ctx.author.id, dual=True)
if not user_queue:
return await ctx.send(localizer.format_str("{my_queue}"))
return await ctx.send(ctx.localizer.format_str("{my_queue}"))
scroller = QueueScroller(ctx, user_queue, localizer, lines_per_page=10, user_name=ctx.author.name)
scroller = QueueScroller(ctx, user_queue, ctx.localizer, lines_per_page=10, user_name=ctx.author.name)
await scroller.start_scrolling()
@commands.command(name='pause', aliases=['resume','gjenoppta'])
@commands.command(name='pause')
@checks.DJ_or(alone=True)
async def _pause(self, ctx):
""" Pauses/Resumes the current track. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if not player.is_playing:
return await ctx.send(localizer.format_str("{not_playing}"))
return await ctx.send(ctx.localizer.format_str("{not_playing}"))
if player.paused:
await player.set_pause(False)
await ctx.send(localizer.format_str("{resume.resumed}"))
await ctx.send(ctx.localizer.format_str("{resume.resumed}"))
else:
await player.set_pause(True)
await ctx.send(localizer.format_str("{resume.paused}"))
await ctx.send(ctx.localizer.format_str("{resume.paused}"))
@commands.command(name='shuffle', aliases=['stokk'])
@commands.command(name='shuffle')
async def _shuffle(self, ctx):
""" Shuffles your queue. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
user_queue = player.user_queue(ctx.author.id)
if not user_queue:
return await ctx.send(localizer.format_str("{my_queue}"))
return await ctx.send(ctx.localizer.format_str("{my_queue}"))
player.shuffle_user_queue(ctx.author.id)
await ctx.send(localizer.format_str("{shuffle}"))
await ctx.send(ctx.localizer.format_str("{shuffle}"))
@commands.command(name='move', aliases=['m', 'flytt','f'])
@commands.command(name='move')
async def _move(self, ctx, from_pos: int, to_pos: int):
""" Moves a song in your queue. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
user_queue = player.user_queue(ctx.author.id)
if not user_queue:
return await ctx.send(localizer.format_str("{my_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(localizer.format_str("{out_of_range}", _len=len(user_queue)))
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(localizer.format_str("{move.not_in_queue}"))
return await ctx.send(ctx.localizer.format_str("{move.not_in_queue}"))
msg = localizer.format_str("{move.moved_to}", _title=moved.title, _from=from_pos, _to=to_pos)
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', aliases=['rem', 'fjern'])
@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.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if player.queue.empty:
return
@@ -332,29 +304,28 @@ class Music:
return
if pos > len(user_queue) or pos < 1:
return await ctx.send(localizer.format_str("{out_of_range}", _len=len(user_queue)))
return await ctx.send(ctx.localizer.format_str("{out_of_range}", _len=len(user_queue)))
removed = player.remove_user_track(ctx.author.id, pos - 1)
await ctx.send(localizer.format_str("{remove}", _title=removed.title))
await ctx.send(ctx.localizer.format_str("{remove}", _title=removed.title))
@commands.command(name="DJremove", aliases=['DJfjern','djfjern'])
@commands.command(name="DJremove")
@checks.DJ_or()
async def _djremove(self, ctx, pos: int, user: discord.Member=None):
""" Remove a song from either the global queue or a users queue"""
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if user is None:
if player.queue.empty:
return
if pos > len(player.queue) or pos < 1:
return await ctx.send(localizer.format_str("{out_of_range}", _len=len(player.queue)))
return await ctx.send(ctx.localizer.format_str("{out_of_range}", _len=len(player.queue)))
removed = player.remove_global_track(pos - 1)
requester = self.bot.get_user(removed.requester)
await ctx.send(localizer.format_str("{dj_removed}", _title=removed.title, _user=requester.name))
await ctx.send(ctx.localizer.format_str("{dj_removed}", _title=removed.title, _user=requester.name))
else:
if player.queue.empty:
@@ -365,17 +336,16 @@ class Music:
return
if pos > len(user_queue) or pos < 1:
return await ctx.send(localizer.format_str("{out_of_range}", _len=len(user_queue)))
return await ctx.send(ctx.localizer.format_str("{out_of_range}", _len=len(user_queue)))
removed = player.remove_user_track(user.id, pos - 1)
await ctx.send(localizer.format_str("{dj_removed}", _title=removed.title, _user=requester.name))
await ctx.send(ctx.localizer.format_str("{dj_removed}", _title=removed.title, _user=requester.name))
@commands.command(name='removeuser', aliases=['fjernbruker','fjernbrukar'])
@commands.command(name='removeuser')
@checks.DJ_or(alone=True)
async def _user_queue_remove(self, ctx, user: discord.Member):
""" Remove a song from either the global queue or a users queue"""
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if player.queue.empty:
return
@@ -388,15 +358,14 @@ class Music:
embed = discord.Embed(color=ctx.me.color)
embed.description = "{dj_remove_user}"
embed = localizer.format_embed(embed, _id=user.id)
embed = ctx.localizer.format_embed(embed, _id=user.id)
await ctx.send(embed=embed)
@commands.command(name='search', aliases=['søk','finn'])
@commands.command(name='search')
async def _search(self, ctx, *, query):
""" Lists the first 10 search results from a given query. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if not query.startswith('ytsearch:') and not query.startswith('scsearch:'):
query = 'ytsearch:' + query
@@ -405,7 +374,7 @@ class Music:
embed = discord.Embed(description='{nothing_found}', color=0x36393F)
if not results or not results['tracks']:
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
return await ctx.send(embed=embed)
tracks = results['tracks']
@@ -447,7 +416,7 @@ class Music:
return False
embed.description = '{search}'
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
result_msg = await ctx.send(embed=embed)
for emoji, index in choices[:result_count]:
@@ -458,7 +427,7 @@ class Music:
embed.title = '{results}'
embed.color = ctx.me.color
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
await result_msg.edit(embed=embed)
@@ -470,7 +439,7 @@ class Music:
await result_msg.clear_reactions()
embed.title = ''
embed.description='{time_expired}'
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
await result_msg.edit(embed=embed)
await asyncio.sleep(5)
await result_msg.delete()
@@ -481,37 +450,35 @@ class Music:
await result_msg.clear_reactions()
track = tracks[choice - 1]
await self.enqueue(ctx, track, embed)
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
await result_msg.edit(embed=embed)
if not player.is_playing:
await player.play()
@commands.command(name='disconnect', aliases=['dc','kf','koblefra','koblefrå'])
@commands.command(name='disconnect')
@checks.DJ_or(alone=True)
async def _disconnect(self, ctx):
""" Disconnects the player from the voice channel and clears its queue. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if not player.is_connected:
return await ctx.send(localizer.format_str("{not_connected}"))
return await ctx.send(ctx.localizer.format_str("{not_connected}"))
if not ctx.author.voice or (player.is_connected and ctx.author.voice.channel.id != int(player.channel_id)):
return await ctx.send(localizer.format_str("{disconnect.not_in_voice}"))
return await ctx.send(ctx.localizer.format_str("{disconnect.not_in_voice}"))
player.queue.clear()
await player.stop()
await self.connect_to(ctx.guild.id, None)
embed = discord.Embed(description='{disconnect.disconnected}', color=ctx.me.color)
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
await ctx.send(embed=embed)
@commands.command(name='volume', aliases=['vol', 'volum', 'lydstyrke'])
@commands.command(name='volume')
@checks.DJ_or(alone=True, current=True)
async def _volume(self, ctx, volume: int = None):
""" Changes the player's volume. Must be between 0 and 1000. Error Handling for that is done by Lavalink. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if not volume:
return await ctx.send(f'🔈 | {player.volume}%')
@@ -520,36 +487,34 @@ class Music:
is_admin = getattr(ctx.author.guild_permissions, 'administrator', None) == True
if int(player.current.requester) == ctx.author.id and not is_dj and not is_admin:
if not 50 <= volume <= 125:
return await ctx.send(localizer.format_str("{volume.out_of_range}"))
return await ctx.send(ctx.localizer.format_str("{volume.out_of_range}"))
await player.set_volume(volume)
embed = discord.Embed(color=ctx.me.color)
embed.description = "{volume.set_to}"
embed = localizer.format_embed(embed, _volume=player.volume)
embed = ctx.localizer.format_embed(embed, _volume=player.volume)
await ctx.send(embed=embed)
@commands.command(name='normalize', aliases=['normal','nl','normaliser'])
@commands.command(name='normalize')
@checks.DJ_or(alone=True)
async def _normalize(self, ctx):
""" Reset the equalizer and """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
await player.set_volume(100)
await player.bassboost(False)
embed = discord.Embed(color=ctx.me.color)
embed.description = '{volume.reset}'
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
await ctx.send(embed=embed)
@commands.command(name='boost', aliases=['boo','bassforsterker','bassforsterkar'])
@commands.command(name='boost')
@checks.DJ_or(alone=True)
async def _boost(self, ctx, boost: bool=None):
""" Set the equalizer to bass boost the music """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
if boost is not None:
await player.bassboost(boost)
@@ -561,43 +526,43 @@ class Music:
else:
embed.description = '{boost.off}'
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
await ctx.send(embed=embed)
@commands.command(name='history', aliases=['h','hist','historie'])
@commands.command(name='history')
async def _history(self, ctx):
""" Show the last 10 songs played """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
history = player.get_history()
if not history:
return await ctx.send(localizer.format_str("{history.empty}"))
embed = discord.Embed(description='{history.empty}', color=ctx.me.color)
embed = ctx.localizer.format_embed(embed)
return await ctx.send(embed=embed)
track = history[0]
description = localizer.format_str("{history.current}", _title=track.title, _uri=track.uri,_id=track.requester) + '\n\n'
description += localizer.format_str("{history.previous}", _len=len(history)-1) + '\n'
description = ctx.localizer.format_str("{history.current}", _title=track.title, _uri=track.uri,_id=track.requester) + '\n\n'
description += ctx.localizer.format_str("{history.previous}", _len=len(history)-1) + '\n'
thumb_url = await RoxUtils.ThumbNailer.identify(self,
track.identifier,
track.uri)
for index, track in enumerate(history[1:], start=1):
description += localizer.format_str("{history.track}",_index=-index, _title=track.title, _uri=track.uri, _id=track.requester) + '\n'
description += ctx.localizer.format_str("{history.track}",_index=-index, _title=track.title, _uri=track.uri, _id=track.requester) + '\n'
embed = discord.Embed(title=localizer.format_str('{history.title}'), color=ctx.me.color, description=description)
embed = discord.Embed(title=ctx.localizer.format_str('{history.title}'), color=ctx.me.color, description=description)
if thumb_url:
embed.set_thumbnail(url=thumb_url)
await ctx.send(embed=embed)
@commands.command(name='scrub', aliases=['kontrol','konsoll'])
@commands.command(name='scrub')
@checks.DJ_or(alone=True)
async def _scrub(self, ctx):
""" Lists the first 10 search results from a given query. """
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
controls = '{scrub.controls}'
embed = discord.Embed(description='{nothing_playing}', color=ctx.me.color)
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
if player.current is None:
return await ctx.send(embed=embed)
@@ -631,14 +596,14 @@ class Music:
return False
embed.description = '{scrub.add}'
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
msg = await ctx.send(embed=embed)
for (emoji, _, _) in scrubber:
await msg.add_reaction(emoji)
embed.description = controls
embed = localizer.format_embed(embed)
embed = ctx.localizer.format_embed(embed)
await msg.edit(embed=embed)
scrubbing = True
while scrubbing:
@@ -694,8 +659,7 @@ class Music:
if voice_channels:
if voice_channel.id not in voice_channels:
localizer = self.getLocalizer(ctx.guild)
response = localizer.format_str('{settings_check.voicechannel}')
response = ctx.localizer.format_str('{settings_check.voicechannel}')
for channel_id in voice_channels:
channel = ctx.guild.get_channel(channel_id)
if channel is not None:
@@ -713,11 +677,10 @@ class Music:
async def enqueue(self, ctx, track, embed):
player = self.bot.lavalink.players.get(ctx.guild.id)
localizer = self.getLocalizer(ctx.guild)
maxlength = self.max_track_length(ctx.guild, player)
if maxlength and track['info']['length'] > maxlength:
embed.description = localizer.format_str("{enqueue.toolong}",
embed.description = ctx.localizer.format_str("{enqueue.toolong}",
_length=timeformatter.format(track['info']['length']),
_max=timeformatter.format(maxlength))
return
+15 -14
View File
@@ -5,7 +5,7 @@ import codecs
from discord.ext import commands
from cogs.utils import checks
class BotSettings:
class Settings:
def __init__(self, bot):
self.bot = bot
self.settings = self.bot.settings
@@ -19,7 +19,7 @@ class BotSettings:
return formatted[:-2]
@checks.is_admin()
@commands.group(name='set', hidden=True)
@commands.group(name='settings', hidden=True)
async def _set(self, ctx):
if ctx.invoked_subcommand is None:
await self.current_settings.invoke(ctx)
@@ -178,53 +178,54 @@ class BotSettings:
@commands.guild_only()
@_set.command(name='current')
async def current_settings(self, ctx):
embed = discord.Embed(title='Settings', color=ctx.me.color)
embed.description = f'Current settings for {ctx.guild.name}'
embed = discord.Embed(title='{current.title}', color=ctx.me.color)
embed.description = '{current.description}'
embed.set_thumbnail(url=ctx.guild.icon_url)
prefixes = self.bot.settings.get(ctx.guild, 'prefixes', 'default_prefix')
embed.add_field(name='Prefix', value=self.format_prefixes(prefixes))
embed.add_field(name='{current.prefix}', value=self.format_prefixes(prefixes))
locale = f"{self.bot.settings.get(ctx.guild, 'locale', 'default_locale')}"
embed.add_field(name='Locale', value=locale)
embed.add_field(name='{current.locale}', value=locale)
threshold = self.bot.settings.get(ctx.guild, 'vote_threshold', 50)
embed.add_field(name='Vote threshold', value=f'{threshold}%')
embed.add_field(name='{current.threshold}', value=f'{threshold}%')
is_dynamic = self.bot.settings.get(ctx.guild, 'duration.is_dynamic', 'default_is_dynamic')
embed.add_field(name='Dynamic max duration', value=is_dynamic)
embed.add_field(name='{current.dynamicmax}', value=is_dynamic)
duration = self.bot.settings.get(ctx.guild, 'maxduration')
if duration:
embed.add_field(name='Max track duration', value=f'{duration} minutes')
embed.add_field(name='{current.maxduration}', value=f'{duration} minutes')
textchannels = self.bot.settings.get(ctx.guild, 'channels.text')
if textchannels:
channels = [ctx.guild.get_channel(channel) for channel in textchannels]
mentioned = [channel.mention for channel in channels if channel is not None]
embed.add_field(name='Text channels', value='\n'.join(mentioned))
embed.add_field(name='{current.textchannels}', value='\n'.join(mentioned))
voicechannels = self.bot.settings.get(ctx.guild, 'channels.music')
if voicechannels:
channels = [ctx.guild.get_channel(channel) for channel in voicechannels]
mentioned = [channel.name for channel in channels if channel is not None]
embed.add_field(name='Music channels', value='\n'.join(mentioned))
embed.add_field(name='{current.musicchannels}', value='\n'.join(mentioned))
listenchannels = self.bot.settings.get(ctx.guild, 'channels.listen_only')
if listenchannels:
channels = [ctx.guild.get_channel(channel) for channel in listenchannels]
mentioned = [channel.name for channel in channels if channel is not None]
embed.add_field(name='Listen only channels', value='\n'.join(mentioned))
embed.add_field(name='{current.listenchannels}', value='\n'.join(mentioned))
djroles = self.bot.settings.get(ctx.guild, 'roles.dj')
if djroles:
roles = [ctx.guild.get_role(role) for role in djroles]
mentioned = [role.name for role in roles if role is not None]
embed.add_field(name='Dj roles', value=', '.join(mentioned))
embed.add_field(name='{current.djroles}', value=', '.join(mentioned))
embed = ctx.localizer.format_embed(embed, _guild=ctx.guild.name)
msg = await ctx.send(embed=embed)
return msg
def setup(bot):
bot.add_cog(BotSettings(bot))
bot.add_cog(Settings(bot))
+116
View File
@@ -0,0 +1,116 @@
import discord
import yaml
from glob import glob
from os import path
from discord.ext import commands
class Aliaser:
def __init__(self, localization_folder, default_lang):
self.localization_folder = path.realpath(localization_folder)
self.default_lang = default_lang
self.index_localizations()
self.load_localizations()
def _gen_alias_dict(self, commands):
""" Reverses the direction of a dict of commans→aliases to be alias→command. """
inverted = {}
subcommands = {}
for cmd, properties in commands.items():
if isinstance(properties, list):
for alias in properties:
inverted[alias] = cmd
else:
for alias in properties['aliases']:
inverted[alias] = cmd
if properties.get('sub_commands', None):
subcommands[cmd] = self._gen_alias_dict(properties['sub_commands'])
inverted['sub_commands'] = subcommands
return inverted
def index_localizations(self):
self.localization_table = {}
for folder in glob(path.join(self.localization_folder, "*/")):
if 'global' in folder:
continue
folder_base = path.basename(path.dirname(folder))
self.localization_table[folder_base] = False
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:
data = yaml.load(f)
self.localization_table[lang] = {'aliases': data, 'commands': self._gen_alias_dict(data)}
def convert_alias(self, locale, alias, default=None, parents=[]):
locale = self.localization_table[locale]
# Traverse through the alias tree as dictated by the parents list
def traverse(alias_tree, parents, alias):
# Return the command when no more parents exist
if not parents:
return alias_tree.get(alias, None)
parent = parents.pop(0)
sub_commands = alias_tree.get('sub_commands', None)
if not sub_commands:
return None
alias_tree = sub_commands.get(parent, None)
if not alias_tree:
return None
return traverse(alias_tree, parents, alias)
alias_tree = locale['commands']
command = traverse(alias_tree, parents, default)
if command:
return command
return default
def get_alias(self, locale, command):
locale = self.localization_table[locale]
return locale['aliases'].get(command, [])
def get_command(self, ctx):
""" Get a top level command. """
if not ctx.prefix:
ctx.command = None
return ctx
ctx.view.undo()
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)
return ctx
def get_subcommand(self, ctx, group, parents=[]):
""" Recursicely replaces all subcommand aliases with subcommands."""
view = ctx.view
prev = view.previous
idx = view.index
# get the alias used
view.skip_ws()
alias = view.get_word()
subcmd = self.convert_alias(ctx.locale, alias, alias, parents.copy())
parents.append(subcmd)
# Replace the alias in the command
view.buffer = view.buffer.replace(alias, subcmd)
# Update the view to account for difference in length
strdiff = len(subcmd) - len(alias)
view.end += strdiff
view.index += strdiff
# Get the subcommand
sub = group.all_commands.get(subcmd, None)
# Translate any subsubcommands
if sub and isinstance(sub, commands.GroupMixin):
self.get_subcommand(ctx, sub, parents)
# Reset the view indexes
view.index = idx
view.previous = prev
return ctx
+9
View File
@@ -0,0 +1,9 @@
from discord.ext import commands
class Context(commands.Context):
def __init__(self, **kwargs):
super().__init__(**kwargs)
if self.message.guild:
self.locale = self.bot.settings.get(self.message.guild, 'locale', 'default_locale')
else:
self.locale = self.bot.settings.default_locale
+5 -4
View File
@@ -5,10 +5,9 @@ import re
from cogs.utils.dict_utils import flatten, SafeDict
import json
import yaml
import copy
from discord import Embed
"""
@@ -52,10 +51,12 @@ class Localizer:
elif localization is False:
self.localization_table[lang] = {}
l_table = self.localization_table[lang]
for file in glob(path.join(self.localization_folder, lang, "*.json")):
for file in glob(path.join(self.localization_folder, lang, "*.yaml")):
if 'aliases' in file:
continue
file_base = path.basename(file).split(".")[0]
with open(file, "r", encoding='utf-8') as f:
data = json.load(f)
data = yaml.load(f)
l_table[file_base] = data
File renamed without changes.
+63
View File
@@ -0,0 +1,63 @@
# 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: []
-3
View File
@@ -1,3 +0,0 @@
{
"not_available_dm": "This command is not available in DMs"
}
-18
View File
@@ -1,18 +0,0 @@
{
"bot": {
"name": "What?",
"infotext": "Music bot written for use on /r/Norge's Discord Servers. It's open source! You can find it [HERE]({global.vars.repo})",
"spectext": "**Python:** [{_python_v}](https://www.python.org/)\n**Discord.py:** [{_discord_v}](https://github.com/Rapptz/discord.py/tree/rewrite)\n**Lavalink:** [{_lavalink_v}](https://github.com/Devoxin/Lavalink.py)",
"stattext": "**Guilds:** {_guilds}\n**Users:** {_members}",
"what": "What?",
"how": "How?",
"how_many": "How many?",
"how_long": "How long?",
"footer_text": "Made by /r/Norge, for /r/Norge"
},
"music": {
"title": "Music info",
"players": "Players",
"listeners": "Listeners"
}
}
+20
View File
@@ -0,0 +1,20 @@
bot:
name: What?
infotext: Music bot written for use on /r/Norge's Discord Servers. It's open source!
You can find it [HERE]({global.vars.repo})
spectext: |-
**Python:** [{_python_v}](https://www.python.org/)
**Discord.py:** [{_discord_v}](https://github.com/Rapptz/discord.py/tree/rewrite)
**Lavalink:** [{_lavalink_v}](https://github.com/Devoxin/Lavalink.py)
stattext: |-
**Guilds:** {_guilds}
**Users:** {_members}
what: What?
how: How?
how_many: How many?
how_long: How long?
footer_text: Made by /r/Norge
music:
title: Music info
players: Players
listeners: Listeners
-90
View File
@@ -1,90 +0,0 @@
{
"response": {
"nothing_found": "Nothing found!",
"not_playing": "Not playing.",
"nothing_playing": "Nothing playing",
"have_to_listen": "You have to be listening to the bot",
"playlist_enqued": "Playlist Enqueued!",
"requested_by": "Requested by",
"tracks": "tracks",
"seek": {
"missing_amount": "You need to specify the amount of seconds to skip!",
"track_moved": "Moved track to **{_position}**"
},
"skip": {
"skipped": "Skipped.",
"require_vote": "{_skips} out of {_total} required haters have voted to skip."
},
"skip_to": {
"invalid_pos": "Invalid specified position.",
"exceeds_queue": "The position exceeds the queue\\'s length.",
"skipped_to": "skipped to `{_title}` at position `{_pos}`"
},
"stop": "⏹ | Stopped.",
"live": "🔴 LIVE",
"now": "Now Playing",
"queue": {
"empty": "The queue is empty",
"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",
"pageindicator":"Viewing page {_current}/{_total}"
},
"my_queue": "Your queue is empty",
"resume": {
"resumed": "⏯ | Resumed",
"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"
},
"remove": "**{_title}** removed.",
"dj_removed": "**{_title}** queued by {_user} removed.",
"dj_remove_user": "Removed all songs queued by <@{_id}>.",
"search": "searching",
"results": "Results",
"time_expired": "Timer Expired",
"disconnect": {
"not_in_voice": "You\\'re not in my voicechannel!",
"disconnected": "Disconnected"
},
"not_connected": "Not connected.",
"volume": {
"set_to": "Volume set to {_volume}",
"reset": "Volume and equalizer reset",
"out_of_range": "you can only set the volume between 50 and 125"
},
"boost": {
"on": "Bass boost is on",
"off": "'Bass boost is off"
},
"scrub": {
"add": "Adding controls",
"controls": "{music_controls}",
"_comment_controls": "scrub.controls read from music_controls.txt"
},
"enqueue": {
"position": "position",
"playing_in": "Playing in",
"enqueued": "Song enqueued",
"estimated": "estimated",
"toolong": "Track too long. `{_length}>{_max}`"
},
"history": {
"title": "Track history",
"current": "`Current` **[{_title}]({_uri})** _by <@{_id}>_",
"track": "`{_index}.` **[{_title}]({_uri})** _by <@{_id}>_",
"previous": "**{_len} Previous songs:**",
"empty": "There are no tracks in the history"
},
"settings_check": {
"textchannel": "You can't use music commands in this channel.\nTry in: ",
"voicechannel": "I can only play music in: "
}
}
}
+73
View File
@@ -0,0 +1,73 @@
nothing_found: Nothing found!
not_playing: Not playing.
nothing_playing: Nothing playing
have_to_listen: You have to be listening to the bot
playlist_enqued: Playlist Enqueued!
requested_by: Requested by
tracks: tracks
seek:
missing_amount: You need to specify the amount of seconds to skip!
track_moved: Moved track to **{_position}**
skip:
skipped: Skipped.
require_vote: "{_skips} out of {_total} required haters have voted to skip."
skip_to:
invalid_pos: Invalid specified position.
exceeds_queue: The position exceeds the queue\'s length.
skipped_to: skipped to `{_title}` at position `{_pos}`
stop: "⏹ | Stopped."
live: "\U0001F534 LIVE"
now: Now Playing
queue:
empty: The queue is empty
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"
pageindicator: Viewing page {_current}/{_total}
my_queue: Your queue is empty
resume:
resumed: "⏯ | Resumed"
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"
remove: "**{_title}** removed."
dj_removed: "**{_title}** queued by {_user} removed."
dj_remove_user: Removed all songs queued by <@{_id}>.
search: searching
results: Results
time_expired: Timer Expired
disconnect:
not_in_voice: You\'re not in my voicechannel!
disconnected: Disconnected
not_connected: Not connected.
volume:
set_to: Volume set to {_volume}
reset: Volume and equalizer reset
out_of_range: you can only set the volume between 50 and 125
boost:
'on': Bass boost is on
'off': Bass boost is off
scrub:
add: Adding controls
controls: "{music_controls}"
_comment_controls: scrub.controls read from music_controls.txt
enqueue:
position: position
playing_in: Playing in
enqueued: Song enqueued
estimated: estimated
toolong: Track too long. `{_length}>{_max}`
history:
title: Track history
current: "`Current` **[{_title}]({_uri})** _by <@{_id}>_"
track: "`{_index}.` **[{_title}]({_uri})** _by <@{_id}>_"
previous: "**{_len} Previous songs:**"
empty: There are no tracks in the history
settings_check:
textchannel: "You can't use music commands in this channel.\nTry in: "
voicechannel: 'I can only play music in: '
+12
View File
@@ -0,0 +1,12 @@
current:
title: Settings
description: Current settings for {_guild}
prefix: Prefix
locale: Locale
threshold: Vote threshold
dynamicmax: Dynamic max duration
maxduration: Max track duration
textchannels: Text channels
musicchannels: Music channels
listenchannels: Listen only channels
djroles: DJ roles
+43
View File
@@ -0,0 +1,43 @@
# 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]
-3
View File
@@ -1,3 +0,0 @@
{
"not_available_dm": "Denne kommandoen er ikke tilgjengelig i DMs"
}
-18
View File
@@ -1,18 +0,0 @@
{
"bot": {
"name": "hva?",
"infotext": "Musikkbot skrevet for bruk på /r/Norge sine Discord Servere. Kildekoden er åpen! Den kan du finne [HER]({global.vars.repo})",
"spectext": "**Python:** [{_python_v}](https://www.python.org/)\n**Discord.py:** [{_discord_v}](https://github.com/Rapptz/discord.py/tree/rewrite)\n**Lavalink:** [{_lavalink_v}](https://github.com/Devoxin/Lavalink.py)",
"stattext": "**Tenarar:** {_guilds}\n**Brukere:** {_members}",
"what": "Hva?",
"how": "Hvordan?",
"how_many": "Hvor mange?",
"how_long": "Hvor lenge?",
"footer_text": "Laget av /r/Norge, for /r/Norge"
},
"music": {
"title": "Musikkinfo",
"players": "Spillere",
"listeners": "Lyttere"
}
}
+20
View File
@@ -0,0 +1,20 @@
bot:
name: hva?
infotext: Musikkbot skrevet for bruk på /r/Norge sine Discord Servere. Kildekoden
er åpen! Den kan du finne [HER]({global.vars.repo})
spectext: |-
**Python:** [{_python_v}](https://www.python.org/)
**Discord.py:** [{_discord_v}](https://github.com/Rapptz/discord.py/tree/rewrite)
**Lavalink:** [{_lavalink_v}](https://github.com/Devoxin/Lavalink.py)
stattext: |-
**Tenarar:** {_guilds}
**Brukere:** {_members}
what: Hva?
how: Hvordan?
how_many: Hvor mange?
how_long: Hvor lenge?
footer_text: Laget av /r/Norge, for /r/Norge
music:
title: Musikkinfo
players: Spillere
listeners: Lyttere
-90
View File
@@ -1,90 +0,0 @@
{
"response": {
"nothing_found": "Kunne ikke finne sangen!",
"not_playing": "Spiller ikke av noe.",
"nothing_playing": "Ingenting spiller av",
"have_to_listen": "Du må høre på botten",
"playlist_enqued": "Spilleliste ble lagt til i køen!",
"requested_by": "Etterspurt av",
"tracks": "spor",
"seek": {
"missing_amount": "Du må spesifisere antall sekunder å spole!",
"track_moved": "Flyttet spor til **{_position}**"
},
"skip": {
"skipped": "Hoppet over.",
"require_vote": "{_skips} av {_total} hatere må stemme for å hoppe over."
},
"skip_to": {
"invalid_pos": "Ugyldig køposisjon.",
"exceeds_queue": "Posisjonen overgår køens lengde.",
"skipped_to": "hoppet til `{_title}` i posisjon `{_pos}`"
},
"stop": "⏹ | Stoppet avspillingen.",
"live": "🔴 DIREKTE",
"now": "Spiller nå",
"queue": {
"empty": "Køen er tom",
"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",
"pageindicator":"Viser side {_current}/{_total}"
},
"my_queue": "Din kø er tom",
"resume": {
"resumed": "⏯ | Avspilling gjenopptatt",
"paused": "⏯ | Pauset avspillingen"
},
"shuffle": "Køen din har blitt omstokket",
"out_of_range": "Posisjonene må være mellom 1 og {_len}",
"move": {
"not_in_queue": "Sjekk at posisjonen eksisterer i køen din",
"moved_to": "`{_title}` flyttet fra plass `{_from}` til `{_to}` i køen din"
},
"remove": "**{_title}** ble fjernet fra køen.",
"dj_removed": "**{_title}** som ble lagt til i køen av {_user}, ble fjernet.",
"dj_remove_user": "Fjernet alle sanger lagt til i køen av <@{_id}>.",
"search": "søker",
"results": "Resultater",
"time_expired": "Tid utgått",
"disconnect": {
"not_in_voice": "Du må være koblet til samme talekanal som meg!",
"disconnected": "Frakoblet"
},
"not_connected": "Du er ikke koblet til en talekanal.",
"volume": {
"set_to": "Volum satt til {_volume}",
"reset": "Volum og equalizer resatt!",
"out_of_range": "Du må sette volumet til et tall mellom 50 og 125"
},
"boost": {
"on": "Bassforsterkeren er på",
"off": "Bassforsterkeren er av"
},
"scrub": {
"add": "Legger til kontrollere",
"controls": "{music_controls}",
"_comment_controls": "scrub.controls read from music_controls.txt"
},
"enqueue": {
"position": "Køposisjon",
"playing_in": "Spiller av om",
"enqueued": "Ny sang lagt til i køen",
"estimated": "estimert",
"toolong": "Sang for lang. `{_length}>{_max}`"
},
"history": {
"title": "Avspillingshistorikk",
"current": "`Spiller nå` **[{_title}]({_uri})** _av <@{_id}>_",
"track": "`{_index}.` **[{_title}]({_uri})** _av <@{_id}>_",
"previous": "**Tidligere sanger ({_len}):**",
"empty": "Ingen tidligere spilte sanger"
},
"settings_check": {
"textchannel": "Du kan ikke bruke musikkommandoer i denne kanalen.\nPrøv i: ",
"voicechannel": "Jeg kan bare spille musikk i: "
}
}
}
+73
View File
@@ -0,0 +1,73 @@
nothing_found: Kunne ikke finne sangen!
not_playing: Spiller ikke av noe.
nothing_playing: Ingenting spiller av
have_to_listen: Du må høre på botten
playlist_enqued: Spilleliste ble lagt til i køen!
requested_by: Etterspurt av
tracks: spor
seek:
missing_amount: Du må spesifisere antall sekunder å spole!
track_moved: Flyttet spor til **{_position}**
skip:
skipped: Hoppet over.
require_vote: "{_skips} av {_total} hatere må stemme for å hoppe over."
skip_to:
invalid_pos: Ugyldig køposisjon.
exceeds_queue: Posisjonen overgår køens lengde.
skipped_to: hoppet til `{_title}` i posisjon `{_pos}`
stop: "⏹ | Stoppet avspillingen."
live: "\U0001F534 DIREKTE"
now: Spiller nå
queue:
empty: Køen er tom
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"
pageindicator: Viser side {_current}/{_total}
my_queue: Din kø er tom
resume:
resumed: "⏯ | Avspilling gjenopptatt"
paused: "⏯ | Pauset avspillingen"
shuffle: Køen din har blitt omstokket
out_of_range: Posisjonene må være mellom 1 og {_len}
move:
not_in_queue: Sjekk at posisjonen eksisterer i køen din
moved_to: "`{_title}` flyttet fra plass `{_from}` til `{_to}` i køen din"
remove: "**{_title}** ble fjernet fra køen."
dj_removed: "**{_title}** som ble lagt til i køen av {_user}, ble fjernet."
dj_remove_user: Fjernet alle sanger lagt til i køen av <@{_id}>.
search: søker
results: Resultater
time_expired: Tid utgått
disconnect:
not_in_voice: Du må være koblet til samme talekanal som meg!
disconnected: Frakoblet
not_connected: Du er ikke koblet til en talekanal.
volume:
set_to: Volum satt til {_volume}
reset: Volum og equalizer resatt!
out_of_range: Du må sette volumet til et tall mellom 50 og 125
boost:
'on': Bassforsterkeren er på
'off': Bassforsterkeren er av
scrub:
add: Legger til kontrollere
controls: "{music_controls}"
_comment_controls: scrub.controls read from music_controls.txt
enqueue:
position: Køposisjon
playing_in: Spiller av om
enqueued: Ny sang lagt til i køen
estimated: estimert
toolong: Sang for lang. `{_length}>{_max}`
history:
title: Avspillingshistorikk
current: "`Spiller nå` **[{_title}]({_uri})** _av <@{_id}>_"
track: "`{_index}.` **[{_title}]({_uri})** _av <@{_id}>_"
previous: "**Tidligere sanger ({_len}):**"
empty: Ingen tidligere spilte sanger
settings_check:
textchannel: "Du kan ikke bruke musikkommandoer i denne kanalen.\nPrøv i: "
voicechannel: 'Jeg kan bare spille musikk i: '
+12
View File
@@ -0,0 +1,12 @@
current:
title: Innstillinger
description: Gjeldende innstillinger for {_guild}
prefix: Prefiks
locale: Språk
threshold: Stemmegrense
dynamicmax: Dynamisk maksvarighet
maxduration: Maks sanglengde
textchannels: Tekstkanaler
musicchannels: Musikkanaler
listenchannels: '"Kun lyd"-kanaler'
djroles: DJroller
+27
View File
@@ -0,0 +1,27 @@
# Music aliases
play: [p, spel, s]
now: [np, 'no']
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, koblefrå]
volume: [vol, volum, lydstyrke, lyd]
normalize: [normal, nl, normaliser]
boost: [bassboost, bassforsterkar]
history: [h, hist, historie]
scrub: [kontroller, konsoll]
# Other
info: [informasjon]
musicinfo: [musikkinfo, musikkinformasjon]
-3
View File
@@ -1,3 +0,0 @@
{
"not_available_dm": "Denna kommandoa er ikkje tilgjengeleg i direkte meldingar DMs"
}
-18
View File
@@ -1,18 +0,0 @@
{
"bot": {
"name": "Kva?",
"infotext": "Musikkbot skreve til bruk på /r/Norge sine Discord Serverar. Kjeldekoda er ope! Dei kan du finna [HER]({global.vars.repo})",
"spectext": "**Python:** [{_python_v}](https://www.python.org/)\n**Discord.py:** [{_discord_v}](https://github.com/Rapptz/discord.py/tree/rewrite)\n**Lavalink:** [{_lavalink_v}](https://github.com/Devoxin/Lavalink.py)",
"stattext": "**Tenarar:** {_guilds}\n**Brukarar:** {_members}",
"what": "Kva?",
"how": "Korleis?",
"how_many": "Kor mange?",
"how_long": "Kor lengje?",
"footer_text": "Laga av /r/Norge, for /r/Norge"
},
"music": {
"title": "Musikkinformasjon",
"players": "Spelarar",
"listeners": "Lyttarar"
}
}
+20
View File
@@ -0,0 +1,20 @@
bot:
name: Kva?
infotext: Musikkbot skreve til bruk på /r/Norge sine Discord Serverar. Kjeldekoda
er ope! Dei kan du finna [HER]({global.vars.repo})
spectext: |-
**Python:** [{_python_v}](https://www.python.org/)
**Discord.py:** [{_discord_v}](https://github.com/Rapptz/discord.py/tree/rewrite)
**Lavalink:** [{_lavalink_v}](https://github.com/Devoxin/Lavalink.py)
stattext: |-
**Tenarar:** {_guilds}
**Brukarar:** {_members}
what: Kva?
how: Korleis?
how_many: Kor mange?
how_long: Kor lengje?
footer_text: Laga av /r/Norge, for /r/Norge
music:
title: Musikkinformasjon
players: Spelarar
listeners: Lyttarar
-90
View File
@@ -1,90 +0,0 @@
{
"response": {
"nothing_found": "Orsak, kunne ikkje finna songen!",
"not_playing": "Spelar ikkje noko.",
"nothing_playing": "Ingenting speles av",
"have_to_listen": "Dykk må høyra på botten",
"playlist_enqued": "Spellista vart lagt til i køen!",
"requested_by": "Etterspurd av",
"tracks": "spor",
"seek": {
"missing_amount": "Dykk må klargjera antal sekundar å spola!",
"track_moved": "Flytta spor til **{_position}**"
},
"skip": {
"skipped": "Hoppa over.",
"require_vote": "{_skips} av {_total} hatarar må stemma for å hoppa over."
},
"skip_to": {
"invalid_pos": "Ugild køposisjon.",
"exceeds_queue": "Posisjona overgår køas lengde.",
"skipped_to": "hoppa til `{_title}` i posisjon `{_pos}`"
},
"stop": "⏹ | Stoppa avspelinga.",
"live": "🔴 DIREKTE",
"now": "Spelar no",
"queue": {
"empty": "Køa er tom",
"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",
"pageindicator":"Viser side {_current}/{_total}"
},
"my_queue": "Din kø er tom",
"resume": {
"resumed": "⏯ | Avspeling oppattatt",
"paused": "⏯ | Pauset avspeling"
},
"shuffle": "Køa di har vorte omstokka",
"out_of_range": "Posisjonane må væra millom 1 og {_len}",
"move": {
"not_in_queue": "Kontrollar at posisjona eksisterar i køa di",
"moved_to": "`{_title}` flytta frå plass `{_from}` til `{_to}` i køa di"
},
"remove": "**{_title}** vart fjerna frå køa.",
"dj_removed": "**{_title}** som vart lagt til i køa av {_user}, vart fjerna.",
"dj_remove_user": "Fjerna alle songar lagt til i køa av <@{_id}>.",
"search": "søkjar",
"results": "Resultatar",
"time_expired": "Tid utgått",
"disconnect": {
"not_in_voice": "Dykk må være tilkopla same talekanal som meg!",
"disconnected": "Fråkopla"
},
"not_connected": "Dykk er ikkje kopla til ein talekanal.",
"volume": {
"set_to": "Volum satt til {_volume}",
"reset": "Volum og utjevnar igjensatt!",
"out_of_range": "Du må setja volumet til eit tal mellom femti og hundreogtjuefem"
},
"boost": {
"on": "Bassforsterkaren er på",
"off": "Bassforsterkaren er av"
},
"scrub": {
"add": "Legjar til kontrollera",
"controls": "{music_controls}",
"_comment_controls": "scrub.controls read from music_controls.txt"
},
"enqueue": {
"position": "Køposisjon",
"playing_in": "Spelar av om",
"enqueued": "Ny song lagt til i køa",
"estimated": "estimert",
"toolong": "Song for lang. `{_length}>{_max}`"
},
"history": {
"title": "Avspelingshistorikk",
"current": "`Spelar no` **[{_title}]({_uri})** _av <@{_id}>_",
"track": "`{_index}.` **[{_title}]({_uri})** _av <@{_id}>_",
"previous": "**Tidlegare songar ({_len}):**",
"empty": "Ingen tidlegare spelte songar"
},
"settings_check": {
"textchannel": "Du kan ikkje bruke musikkommandoar i denne kanalen.\nPrøv i: ",
"voicechannel": "Eg kan berre spele musikk i: "
}
}
}
+73
View File
@@ -0,0 +1,73 @@
nothing_found: Orsak, kunne ikkje finna songen!
not_playing: Spelar ikkje noko.
nothing_playing: Ingenting speles av
have_to_listen: Dykk må høyra på botten
playlist_enqued: Spellista vart lagt til i køen!
requested_by: Etterspurd av
tracks: spor
seek:
missing_amount: Dykk må klargjera antal sekundar å spola!
track_moved: Flytta spor til **{_position}**
skip:
skipped: Hoppa over.
require_vote: "{_skips} av {_total} hatarar må stemma for å hoppa over."
skip_to:
invalid_pos: Ugild køposisjon.
exceeds_queue: Posisjona overgår køens lengde.
skipped_to: hoppa til `{_title}` i posisjon `{_pos}`
stop: "⏹ | Stoppa avspelinga."
live: "\U0001F534 DIREKTE"
now: Spelar no
queue:
empty: Køa er tom
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"
pageindicator: Viser side {_current}/{_total}
my_queue: Din kø er tom
resume:
resumed: "⏯ | Avspeling oppattatt"
paused: "⏯ | Pauset avspeling"
shuffle: Køa di har vorte omstokka
out_of_range: Posisjonane må væra millom 1 og {_len}
move:
not_in_queue: Kontrollar at posisjona eksisterar i køen din
moved_to: "`{_title}` flytta frå plass `{_from}` til `{_to}` i køen din"
remove: "**{_title}** vart fjerna frå køen."
dj_removed: "**{_title}** som vart lagt til i køen av {_user}, vart fjerna."
dj_remove_user: Fjerna alle songar lagt til i køen av <@{_id}>.
search: søkjar
results: Resultatar
time_expired: Tid utgått
disconnect:
not_in_voice: Dykk må være tilkopla same talekanal som meg!
disconnected: Fråkopla
not_connected: Dykk er ikkje kopla til ein talekanal.
volume:
set_to: Volum satt til {_volume}
reset: Volum og utjevnar igjensatt!
out_of_range: Du må setja volumet til eit tal mellom femti og hundreogtjuefem
boost:
'on': Bassforsterkaren er på
'off': Bassforsterkaren er av
scrub:
add: Legjar til kontrollera
controls: "{music_controls}"
_comment_controls: scrub.controls read from music_controls.txt
enqueue:
position: Køposisjon
playing_in: Spelar av om
enqueued: Ny song lagt til i køen
estimated: estimert
toolong: Song for lang. `{_length}>{_max}`
history:
title: Avspelingshistorikk
current: "`Spelar no` **[{_title}]({_uri})** _av <@{_id}>_"
track: "`{_index}.` **[{_title}]({_uri})** _av <@{_id}>_"
previous: "**Tidlegare songar ({_len}):**"
empty: Ingen tidlegare spelte songar
settings_check:
textchannel: "Du kan ikkje bruke musikkommandoar i denne kanalen.\nPrøv i: "
voicechannel: 'Eg kan berre spele musikk i: '
+12
View File
@@ -0,0 +1,12 @@
current:
title: Innstillingar
description: Gjeldande innstillingar for {_guild}
prefix: Prefiks
locale: Språk
threshold: Stemmegrense
dynamicmax: Dynamisk maksvarigskap
maxduration: Maks songlengde
textchannels: Tekstkanalar
musicchannels: Musikkanalar
listenchannels: '"Kun lyd"-kanalar'
djroles: DJroller