From e0ea8cba9535b37a0850b34644cb9fab5e32fc82 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Thu, 24 Jan 2019 18:59:49 +0100 Subject: [PATCH 01/37] Faster position conversion, clear skip votes. --- cogs/utils/mixplayer.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/cogs/utils/mixplayer.py b/cogs/utils/mixplayer.py index 7eccea7..2a95651 100644 --- a/cogs/utils/mixplayer.py +++ b/cogs/utils/mixplayer.py @@ -112,6 +112,13 @@ class MixPlayer(DefaultPlayer): if member in self.listeners: self.skip_voters.add(member) + async def handle_event(self, event): + """ Handles the given event as necessary. """ + if isinstance(event, (TrackStuckEvent, TrackExceptionEvent)) or \ + isinstance(event, TrackEndEvent) and event.reason == 'FINISHED': + self.skip_voters.clear() + await self.play() + async def bassboost(self, boost: bool=False): if boost: gains = [ @@ -264,18 +271,19 @@ class MixQueue: for i in to_remove: self.queues.pop(i) - # Convert between global and local queue positions - # Pretty shit atm, todo: implement algorithm thing I made. - def _loc_to_glob(self, requester: int, pos: int): - queue = self.queues.get(requester, []) - if queue: - try: - track = queue[pos] - for i, t in enumerate(self): - if t == track: - return i - except IndexError: - pass + def _loc_to_glob(self, requester, pos): + globpos = len(self.priority_queue) + passed = False + for key, queue in self.queues.items(): + if len(queue) < pos: + globpos += len(queue) + else: + globpos += pos + if key == requester: + passed = True + if not passed: + globpos += 1 + return globpos def _glob_to_loc(self, pos: int): track = None From fb763a05493c76b521e404646cca7aefd76686e0 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Thu, 24 Jan 2019 19:14:05 +0100 Subject: [PATCH 02/37] Updated DJ check, show requester in 'now' commands --- cogs/music.py | 42 +++++++++++++++++++++++------------------- cogs/utils/checks.py | 29 ++++++----------------------- 2 files changed, 29 insertions(+), 42 deletions(-) diff --git a/cogs/music.py b/cogs/music.py index f6099e0..57f83f4 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -94,7 +94,7 @@ class Music: await player.play() @commands.command() - @checks.DJ_or_alone() + @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) @@ -118,7 +118,7 @@ class Music: await ctx.send(f'Moved track to **{lavalink.utils.format_time(track_time)}**') - @commands.command(aliases=['forceskip']) + @commands.command() async def skip(self, ctx): """ Skips the current track. """ player = self.bot.lavalink.players.get(ctx.guild.id) @@ -136,9 +136,9 @@ class Music: if skips != 0: await ctx.send(f'{skips} out of {math.ceil(total/2)} required haters have voted to skip.') - @commands.command(name='skipto', aliases=['st','skip_to']) - @checks.DJ_or_alone() - async def skip_to(self, ctx, pos: int): + @commands.command(name='skipto', aliases=['st','skip_to','forceskip']) + @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) @@ -153,7 +153,7 @@ class Music: await ctx.send(f'skipped to `{player.current.title}` at position `{pos}`') @commands.command() - @checks.DJ_or_alone() + @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) @@ -168,7 +168,7 @@ class Music: await player.stop() await ctx.send('⏹ | Stopped.') - @commands.command(aliases=['np', 'n', 'playing']) + @commands.command(aliases=['np', 'n', 'playing','current']) async def now(self, ctx): """ Shows some stats about the currently playing song. """ player = self.bot.lavalink.players.get(ctx.guild.id) @@ -183,12 +183,13 @@ class Music: duration = lavalink.utils.format_time(player.current.duration) song = f'**[{player.current.title}]({player.current.uri})**\n({position}/{duration})' - embed = discord.Embed(color=0xEFD26C, - title='Now Playing', description=song) + member = ctx.guild.get_member(player.current.requester) + embed = discord.Embed(color=0xEFD26C, description=song, title='Now playing') thumbnail_url = await RoxUtils.ThumbNailer.identify(self,player.current.identifier, player.current.uri) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) + embed.set_footer(text=f'Requested by {member.nick}', icon_url=member.avatar_url) await ctx.send(embed=embed) @commands.command(aliases=['q']) @@ -225,7 +226,7 @@ class Music: await scroller.start_scrolling() @commands.command(aliases=['resume']) - @checks.is_DJ() + @checks.DJ_or(alone=True) async def pause(self, ctx): """ Pauses/Resumes the current track. """ player = self.bot.lavalink.players.get(ctx.guild.id) @@ -290,7 +291,7 @@ class Music: await ctx.send(f'**{removed.title}** removed.') @commands.command(name="DJremove") - @checks.is_DJ() + @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) @@ -321,7 +322,7 @@ class Music: await ctx.send(f'**{removed.title}** queued by {user.name} removed.') @commands.command(name="removeuser") - @checks.DJ_or_alone() + @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) @@ -398,6 +399,7 @@ class Music: embed.description = search_results embed.title = 'Results' + embed.color = 0xEFD26C await result_msg.edit(embed=embed) try: @@ -423,7 +425,7 @@ class Music: await player.play() @commands.command(aliases=['dc']) - @checks.DJ_or_alone() + @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) @@ -441,23 +443,25 @@ class Music: await ctx.send(embed=embed) @commands.command(aliases=['vol']) - @checks.DJ_or_current() + @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) - # todo: limit to 50%-125% if user has current song. - if not volume: return await ctx.send(f'🔈 | {player.volume}%') + if int(player.current.requester) == ctx.author.id: + if volume not in list(range(50,125)): + return await ctx.send(f'you can only set the volume between 50 and 125') + await player.set_volume(volume) embed = discord.Embed(color=0x36393F) embed.description = f'Volume set to {player.volume}' await ctx.send(embed=embed) @commands.command(aliases=['normal','nl']) - @checks.DJ_or_alone() + @checks.DJ_or(alone=True) async def normalize(self, ctx): """ Reset the equalizer and """ player = self.bot.lavalink.players.get(ctx.guild.id) @@ -469,7 +473,7 @@ class Music: await ctx.send(embed=embed) @commands.command(name='boost', aliases=['boo']) - @checks.DJ_or_alone() + @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) @@ -487,7 +491,7 @@ class Music: await ctx.send(embed=embed) @commands.command() - @checks.DJ_or_alone() + @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) diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py index b771fb1..c503ec8 100644 --- a/cogs/utils/checks.py +++ b/cogs/utils/checks.py @@ -55,35 +55,18 @@ def is_mod(): return commands.check(pred) -def is_DJ(): - async def predicate(ctx): - is_dj = has_role(ctx, 'DJ') or has_role(ctx, 'dj') or has_role(ctx, 'Dj') - is_admin = await check_guild_permissions(ctx, {'administrator': True}) - return is_dj or is_admin - return commands.check(predicate) - - -def DJ_or_current(): +def DJ_or(alone: bool=False, current: bool=False): async def predicate(ctx): try: player = ctx.bot.lavalink.players.get(ctx.guild.id) - requester = player.current.requester + is_alone = (ctx.author in player.listeners and len(player.listeners) == 1) and alone + print(alone, is_alone, (ctx.author in player.listeners and len(player.listeners) == 1)) + requester = (player.current.requester == ctx.author.id) and current + is_dj = has_role(ctx, 'DJ') or has_role(ctx, 'dj') or has_role(ctx, 'Dj') is_admin = await check_guild_permissions(ctx, {'administrator': True}) - return is_dj or is_admin or requester == ctx.author.id - except AttributeError: - return False - return commands.check(predicate) - -def DJ_or_alone(): - async def predicate(ctx): - try: - player = ctx.bot.lavalink.players.get(ctx.guild.id) - alone = ctx.author in player.listeners and len(player.listeners) == 1 - is_dj = has_role(ctx, 'DJ') or has_role(ctx, 'dj') or has_role(ctx, 'Dj') - is_admin = await check_guild_permissions(ctx, {'administrator': True}) - return is_dj or is_admin or alone + return is_dj or is_admin or is_alone or requester except AttributeError: return False return commands.check(predicate) From 9e1c5d720c047d59a0cdd5c89e78aec8b7b15400 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Thu, 24 Jan 2019 20:31:44 +0100 Subject: [PATCH 03/37] Added history, Improved global_to_local position conversion --- cogs/music.py | 23 +++++++++++++++++++++++ cogs/utils/checks.py | 2 +- cogs/utils/mixplayer.py | 34 ++++++++++++++++++++++++---------- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/cogs/music.py b/cogs/music.py index 57f83f4..095039b 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -38,6 +38,7 @@ class Music: async def track_hook(self, event): if isinstance(event, lavalink.events.TrackEndEvent): + print('AGA') pass # Send track ended message to channel. if isinstance(event, lavalink.events.QueueEndEvent): channel = self.bot.get_channel(event.player.fetch('channel')) @@ -490,6 +491,28 @@ class Music: embed.description = 'Bass boost is off' await ctx.send(embed=embed) + @commands.command(name='history', aliases=['h','hist']) + async def _history(self, ctx): + """ Show the last 10 songs played """ + player = self.bot.lavalink.players.get(ctx.guild.id) + + history = player.get_history() + track = history[0] + description = f'`Current` **[{track.title}]({track.uri})** _by <@{track.requester}>_\n\n' + description += f'**{len(history)-1} Previous songs:**\n' + thumb_url = await RoxUtils.ThumbNailer.identify(self, + track.identifier, + track.uri) + for index, track in enumerate(history[1:], start=1): + description += f'`{-index}.` **[{track.title}]({track.uri})** _by <@{track.requester}>_\n' + + embed = discord.Embed(title='Track history', color=0xEFD26C, description=description) + + if thumb_url: + embed.set_thumbnail(url=thumb_url) + await ctx.send(embed=embed) + + @commands.command() @checks.DJ_or(alone=True) async def scrub(self, ctx): diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py index c503ec8..3bd2dd5 100644 --- a/cogs/utils/checks.py +++ b/cogs/utils/checks.py @@ -60,7 +60,7 @@ def DJ_or(alone: bool=False, current: bool=False): try: player = ctx.bot.lavalink.players.get(ctx.guild.id) is_alone = (ctx.author in player.listeners and len(player.listeners) == 1) and alone - print(alone, is_alone, (ctx.author in player.listeners and len(player.listeners) == 1)) + requester = (player.current.requester == ctx.author.id) and current is_dj = has_role(ctx, 'DJ') or has_role(ctx, 'dj') or has_role(ctx, 'Dj') diff --git a/cogs/utils/mixplayer.py b/cogs/utils/mixplayer.py index 2a95651..3bc6dea 100644 --- a/cogs/utils/mixplayer.py +++ b/cogs/utils/mixplayer.py @@ -1,7 +1,7 @@ import time import lavalink -from collections import OrderedDict +from collections import OrderedDict, deque from itertools import cycle, islice, chain from random import shuffle @@ -57,6 +57,9 @@ class MixPlayer(DefaultPlayer): def global_queue(self): return self.queue.get_queue() + def get_history(self): + return self.queue.history + def queue_duration(self, include_current: bool=True): duration = 0 for track in self.queue: @@ -155,6 +158,7 @@ class MixQueue: def __init__(self): self.queues = OrderedDict() self.priority_queue = [] + self._history = deque(maxlen=11) # 10 + current def __str__(self): tmp = '' @@ -197,11 +201,13 @@ class MixQueue: def pop_first(self): if self.priority_queue: next_track = self.priority_queue.pop(0) + self._history.append(next_track) return next_track try: next_track = self.queues[self.first_queue].pop(0) self._shuffle() self._clear_empty() + self._history.append(next_track) return next_track except KeyError: pass @@ -286,16 +292,19 @@ class MixQueue: return globpos def _glob_to_loc(self, pos: int): - track = None - for i, t in enumerate(self): - if i == pos: - track = t - if track is None: + try: + song = next(islice(self, pos, pos + 1)) + except (ValueError, StopIteration): return None, None - for requester, q in self.queues.items(): - for i, t in enumerate(q): - if t == track: - return requester, i + user_queue = self.queues.get(song.requester, []) + + # In case song is in the priority queue + if not user_queue or song not in user_queue: + return None, pos + + for i, s in enumerate(user_queue): + if s == song: + return song.requester, i @property def first_queue(self): @@ -307,3 +316,8 @@ class MixQueue: @property def empty(self): return len(self) == 0 + + @property + def history(self): + return list(reversed(self._history)) + From ea7a800468f4e3add407f05fd23fa8dafc5a946c Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Thu, 24 Jan 2019 20:43:20 +0100 Subject: [PATCH 04/37] remove print --- cogs/music.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cogs/music.py b/cogs/music.py index 095039b..7c58776 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -38,7 +38,6 @@ class Music: async def track_hook(self, event): if isinstance(event, lavalink.events.TrackEndEvent): - print('AGA') pass # Send track ended message to channel. if isinstance(event, lavalink.events.QueueEndEvent): channel = self.bot.get_channel(event.player.fetch('channel')) From 2073c6b167aeb016b1e30d95f8759e304d1d8c9f Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Thu, 24 Jan 2019 22:24:34 +0100 Subject: [PATCH 05/37] Various fixes position convertion error, volume limiter simplified, use name if nick isn't set. --- cogs/music.py | 9 +++++++-- cogs/utils/mixplayer.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cogs/music.py b/cogs/music.py index 7c58776..93253b6 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -189,7 +189,12 @@ class Music: thumbnail_url = await RoxUtils.ThumbNailer.identify(self,player.current.identifier, player.current.uri) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) - embed.set_footer(text=f'Requested by {member.nick}', icon_url=member.avatar_url) + + if member.nick: + member_identifier = member.nick + else: + member_identifier = member.name + embed.set_footer(text=f'Requested by {member_identifier}', icon_url=member.avatar_url) await ctx.send(embed=embed) @commands.command(aliases=['q']) @@ -452,7 +457,7 @@ class Music: return await ctx.send(f'🔈 | {player.volume}%') if int(player.current.requester) == ctx.author.id: - if volume not in list(range(50,125)): + if not 50 <= volume <= 125: return await ctx.send(f'you can only set the volume between 50 and 125') await player.set_volume(volume) diff --git a/cogs/utils/mixplayer.py b/cogs/utils/mixplayer.py index 3bc6dea..bba731c 100644 --- a/cogs/utils/mixplayer.py +++ b/cogs/utils/mixplayer.py @@ -281,7 +281,7 @@ class MixQueue: globpos = len(self.priority_queue) passed = False for key, queue in self.queues.items(): - if len(queue) < pos: + if len(queue) <= pos: globpos += len(queue) else: globpos += pos From 0fa2314ec268402396104bb730ef7ece6e8ff176 Mon Sep 17 00:00:00 2001 From: LBlend <3142367-LBlend@users.noreply.gitlab.com> Date: Fri, 25 Jan 2019 03:46:58 +0000 Subject: [PATCH 06/37] added more info to the info commands --- cogs/misc.py | 59 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/cogs/misc.py b/cogs/misc.py index 19572b2..ca562d1 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -3,9 +3,11 @@ import os import asyncio import time import random +import platform from discord.ext import commands from cogs.utils import checks +from lavalink import __version__ as LavalinkVersion class Misc: def __init__(self, bot): @@ -38,24 +40,47 @@ class Misc: for guild in self.bot.guilds: guilds += f"{guild.name}\n" await ctx.send(guilds) - + @commands.command() - async def info(self, ctx, *, channel: str=None): - """ - Info om LovherkBot - """ - avatar = self.bot.user.avatar_url_as(format=None, - static_format='png', - size=1024) - infotext = f'Shite Music Bot' - embed = discord.Embed(color=0xD9C04D) - embed.set_author(name=self.bot.user.name, icon_url=avatar) - embed.set_thumbnail(url=avatar) - embed.add_field(name="Hva?", - value=infotext, inline=False) - embed.set_footer(icon_url="https://i.imgur.com/dE6JaeT.gif", - text="Laget av /r/Norge") - await ctx.send(embed=embed) + async def info(self, ctx): + """ + Info om Shite Music Bot + """ + membercount = [] + for guild in self.bot.guilds: + for member in guild.members: + if member.id in membercount: + pass + else: + membercount.append(member.id) + guilds = len(self.bot.guilds) + members = len(membercount) + now = time.time() + diff = int(now - self.bot.uptime) + days, remainder = divmod(diff, 24 * 60 * 60) + hours, remainder = divmod(remainder, 60 * 60) + minutes, seconds = divmod(remainder, 60) + avatar = self.bot.user.avatar_url_as(format=None, + static_format='png', + size=1024) + infotext = f'Musikkbot skrevet for bruk på /r/Norge sine Discord Servere. Kildekoden er åpen! Den kan du finne [HER](https://gitlab.com/Ev-1/shite-music-bot)' + spectext = f'**Python:** [{platform.python_version()}](https://www.python.org/)\n**Discord.py:** [{discord.__version__}](https://github.com/Rapptz/discord.py/tree/rewrite)\n**Lavalink:** [{LavalinkVersion}](https://github.com/Devoxin/Lavalink.py)' + stattext = f'**Guilder:** {guilds}\n**Brukere:** {members}' + uptimetext = f'{days}d {hours}t {minutes}m {seconds}s' + embed = discord.Embed(color=0xD9C04D) + embed.set_author(name=self.bot.user.name, icon_url=avatar) + embed.set_thumbnail(url=avatar) + embed.add_field(name="Hva?", + value=infotext, inline=False) + embed.set_footer(icon_url="https://cdn.discordapp.com/icons/297798952538079233/0198dc7b01ccf288b985b8a394cb1d44.jpg?size=64", + text="Laget av /r/Norge, for /r/Norge") + embed.add_field(name="Hvordan?", + value=spectext) + embed.add_field(name="Hvor mange?", + value=stattext) + embed.add_field(name="Hvor lenge?", + value=uptimetext) + await ctx.send(embed=embed) @commands.command() @checks.is_even() From 17a0723d19708e0e3827376d20ef08c2298e4026 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Fri, 25 Jan 2019 15:42:44 +0000 Subject: [PATCH 07/37] Fixed indentation error --- cogs/misc.py | 84 ++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/cogs/misc.py b/cogs/misc.py index ca562d1..1bf8203 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -43,49 +43,49 @@ class Misc: @commands.command() async def info(self, ctx): - """ - Info om Shite Music Bot - """ - membercount = [] - for guild in self.bot.guilds: - for member in guild.members: - if member.id in membercount: - pass - else: - membercount.append(member.id) - guilds = len(self.bot.guilds) - members = len(membercount) - now = time.time() - diff = int(now - self.bot.uptime) - days, remainder = divmod(diff, 24 * 60 * 60) - hours, remainder = divmod(remainder, 60 * 60) - minutes, seconds = divmod(remainder, 60) - avatar = self.bot.user.avatar_url_as(format=None, - static_format='png', - size=1024) - infotext = f'Musikkbot skrevet for bruk på /r/Norge sine Discord Servere. Kildekoden er åpen! Den kan du finne [HER](https://gitlab.com/Ev-1/shite-music-bot)' - spectext = f'**Python:** [{platform.python_version()}](https://www.python.org/)\n**Discord.py:** [{discord.__version__}](https://github.com/Rapptz/discord.py/tree/rewrite)\n**Lavalink:** [{LavalinkVersion}](https://github.com/Devoxin/Lavalink.py)' - stattext = f'**Guilder:** {guilds}\n**Brukere:** {members}' - uptimetext = f'{days}d {hours}t {minutes}m {seconds}s' - embed = discord.Embed(color=0xD9C04D) - embed.set_author(name=self.bot.user.name, icon_url=avatar) - embed.set_thumbnail(url=avatar) - embed.add_field(name="Hva?", - value=infotext, inline=False) - embed.set_footer(icon_url="https://cdn.discordapp.com/icons/297798952538079233/0198dc7b01ccf288b985b8a394cb1d44.jpg?size=64", - text="Laget av /r/Norge, for /r/Norge") - embed.add_field(name="Hvordan?", - value=spectext) - embed.add_field(name="Hvor mange?", - value=stattext) - embed.add_field(name="Hvor lenge?", - value=uptimetext) - await ctx.send(embed=embed) + """ + Info om Shite Music Bot + """ + membercount = [] + for guild in self.bot.guilds: + for member in guild.members: + if member.id in membercount: + pass + else: + membercount.append(member.id) + guilds = len(self.bot.guilds) + members = len(membercount) + now = time.time() + diff = int(now - self.bot.uptime) + days, remainder = divmod(diff, 24 * 60 * 60) + hours, remainder = divmod(remainder, 60 * 60) + minutes, seconds = divmod(remainder, 60) + avatar = self.bot.user.avatar_url_as(format=None, + static_format='png', + size=1024) + infotext = f'Musikkbot skrevet for bruk på /r/Norge sine Discord Servere. Kildekoden er åpen! Den kan du finne [HER](https://gitlab.com/Ev-1/shite-music-bot)' + spectext = f'**Python:** [{platform.python_version()}](https://www.python.org/)\n**Discord.py:** [{discord.__version__}](https://github.com/Rapptz/discord.py/tree/rewrite)\n**Lavalink:** [{LavalinkVersion}](https://github.com/Devoxin/Lavalink.py)' + stattext = f'**Guilder:** {guilds}\n**Brukere:** {members}' + uptimetext = f'{days}d {hours}t {minutes}m {seconds}s' + embed = discord.Embed(color=0xD9C04D) + embed.set_author(name=self.bot.user.name, icon_url=avatar) + embed.set_thumbnail(url=avatar) + embed.add_field(name="Hva?", + value=infotext, inline=False) + embed.set_footer(icon_url="https://cdn.discordapp.com/icons/297798952538079233/0198dc7b01ccf288b985b8a394cb1d44.jpg?size=64", + text="Laget av /r/Norge, for /r/Norge") + embed.add_field(name="Hvordan?", + value=spectext) + embed.add_field(name="Hvor mange?", + value=stattext) + embed.add_field(name="Hvor lenge?", + value=uptimetext) + await ctx.send(embed=embed) - @commands.command() - @checks.is_even() - async def only_me(self, ctx): - await ctx.send('Only you!') + @commands.command() + @checks.is_even() + async def only_me(self, ctx): + await ctx.send('Only you!') def setup(bot): From 5a299b6c59e6a66e2f0138dab737b7f775684b57 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2019 03:26:52 +0100 Subject: [PATCH 08/37] Created a utility module dict_utils, containing a SafeDict and a dictionary flattener Created a localization module localizer.py that can load localization files and return various translations of strings --- cogs/utils/dict_utils.py | 17 +++++++ cogs/utils/localizer.py | 104 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 cogs/utils/dict_utils.py create mode 100644 cogs/utils/localizer.py diff --git a/cogs/utils/dict_utils.py b/cogs/utils/dict_utils.py new file mode 100644 index 0000000..b3e6439 --- /dev/null +++ b/cogs/utils/dict_utils.py @@ -0,0 +1,17 @@ +import collections + +class SafeDict(dict): + def __missing__(self, key): + return '{' + key + '}' + + +# from https://stackoverflow.com/questions/6027558/flatten-nested-python-dictionaries-compressing-keys +def flatten(d, parent_key='', sep='/'): + items = [] + for k, v in d.items(): + new_key = parent_key + sep + k if parent_key else k + if isinstance(v, collections.MutableMapping): + items.extend(flatten(v, new_key, sep=sep).items()) + else: + items.append((new_key, v)) + return dict(items) diff --git a/cogs/utils/localizer.py b/cogs/utils/localizer.py new file mode 100644 index 0000000..f569ef2 --- /dev/null +++ b/cogs/utils/localizer.py @@ -0,0 +1,104 @@ +from glob import glob +from os import path + +import re + +from cogs.utils.dict_utils import flatten, SafeDict + +import json + + + +""" +Localizer for bot +""" + +kmatch = re.compile('({[^{}]+})') + +class Localizer: + def __init__(self, localization_folder, default_lang): + self.localization_folder = path.realpath(localization_folder) + self.default_lang = default_lang + # look for localization folders + self.index_localizations() + # load localizations + self.load_localizations() + + # indexes localization folder + def index_localizations(self): + self.localization_table = {} + for folder in glob(path.join(self.localization_folder, "*/")): + folder_base = path.basename(path.dirname(folder)) + self.localization_table[folder_base] = False + + + # loads all localizations + def load_localizations(self): + for lang in self.localization_table.keys(): + self.localization_table[lang] = False + self._load_localization(lang) + + tmp_d = flatten(self.localization_table) + print(tmp_d) + for lang, d in self.localization_table.items(): + self.localization_table[lang] = Localizer._parse_localization_dictionary(self.localization_table[lang], tmp_d) + + # internal function for loading a localization + def _load_localization(self, lang): + localization = self.localization_table.get(lang) + if localization is None: + raise Exception(f'Localization for {lang} does not exist') + elif localization is False: + print(f'Loading {lang}') + self.localization_table[lang] = {} + l_table = self.localization_table[lang] + for file in glob(path.join(self.localization_folder, lang, "*.json")): + file_base = path.basename(file).split(".")[0] + print(f'{file_base} -> {file}') + with open(file) as f: + data = json.load(f) + + l_table[file_base] = data + + l_table = flatten(l_table) + self.localization_table[lang] = Localizer._parse_localization_dictionary(l_table, l_table) + for file in glob(path.join(self.localization_folder, lang, "*.txt")): + file_base = path.basename(file).split(".")[0] + print(f'{file_base} -> {file}') + with open(file) as f: + content = Localizer._parse_localization_string(f.read(), self.localization_table[lang]) + self.localization_table[lang][file_base] = content + + # parses and interpolates translation dictionary + @staticmethod + def _parse_localization_dictionary(d, lookup): + n_dict = {} + for k, v in d.items(): + if type(v) is str: + n_dict[k] = Localizer._parse_localization_string(v, lookup) + else: + n_dict[k] = v + return n_dict + + # parses and interpolates strings + @staticmethod + def _parse_localization_string(value, d): + d = SafeDict(d) + for match in kmatch.findall(value): + nstr = match.replace(".", "/") + value = value.replace(match, nstr) + return value.format_map(d) + + # returns true if localization is currently loaded + def isLoaded(self, lang): + return self.localization_table.get(lang, False) + + # returns translation string from a key + def get(self, key, lang=None): + lang = lang or self.default_lang + if not self.isLoaded(lang): + self._load_localization(lang) + + return self.localization_table.get(lang, {}).get(key.replace(".", "/")) + + \ No newline at end of file From 73d04b942da13694e79081c0516bbc81058dc2ed Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2019 03:38:19 +0100 Subject: [PATCH 09/37] Exampel localization --- localization/en_en/block_example.txt | 4 ++++ localization/en_en/example.json | 6 ++++++ localization/global/vars.json | 3 +++ localization/nb_no/block_example.txt | 4 ++++ localization/nb_no/example.json | 6 ++++++ 5 files changed, 23 insertions(+) create mode 100644 localization/en_en/block_example.txt create mode 100644 localization/en_en/example.json create mode 100644 localization/global/vars.json create mode 100644 localization/nb_no/block_example.txt create mode 100644 localization/nb_no/example.json diff --git a/localization/en_en/block_example.txt b/localization/en_en/block_example.txt new file mode 100644 index 0000000..15769e9 --- /dev/null +++ b/localization/en_en/block_example.txt @@ -0,0 +1,4 @@ +Example file +title: {example.title} +Repo: {global.vars.repo} +Some Norwegian: {nb_no.example.title} \ No newline at end of file diff --git a/localization/en_en/example.json b/localization/en_en/example.json new file mode 100644 index 0000000..12a4e6e --- /dev/null +++ b/localization/en_en/example.json @@ -0,0 +1,6 @@ +{ + "title": "Hello World {example.misc.var}", + "misc": { + "var": "4321" + } +} \ No newline at end of file diff --git a/localization/global/vars.json b/localization/global/vars.json new file mode 100644 index 0000000..d2ab2e3 --- /dev/null +++ b/localization/global/vars.json @@ -0,0 +1,3 @@ +{ + "repo": "https://gitlab.com/Ev-1/shite-music-bot" +} \ No newline at end of file diff --git a/localization/nb_no/block_example.txt b/localization/nb_no/block_example.txt new file mode 100644 index 0000000..fcb1ea2 --- /dev/null +++ b/localization/nb_no/block_example.txt @@ -0,0 +1,4 @@ +Eksempel fil +Tittel: {example.title} +Repo: {global.vars.repo} +Noe engelsk: {en_en.example.title} \ No newline at end of file diff --git a/localization/nb_no/example.json b/localization/nb_no/example.json new file mode 100644 index 0000000..b38f780 --- /dev/null +++ b/localization/nb_no/example.json @@ -0,0 +1,6 @@ +{ + "title": "Hallo Verden {example.misc.var}", + "misc": { + "var": "1234" + } +} \ No newline at end of file From 2ced7905ea7572311c0cb37e2c104b22850e4bfb Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2019 05:44:42 +0100 Subject: [PATCH 10/37] Added formating options for strings, dictionaries and embeds --- cogs/utils/localizer.py | 45 ++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/cogs/utils/localizer.py b/cogs/utils/localizer.py index f569ef2..f704790 100644 --- a/cogs/utils/localizer.py +++ b/cogs/utils/localizer.py @@ -7,7 +7,9 @@ from cogs.utils.dict_utils import flatten, SafeDict import json +import copy +from discord import Embed """ Localizer for bot @@ -38,10 +40,9 @@ class Localizer: self.localization_table[lang] = False self._load_localization(lang) - tmp_d = flatten(self.localization_table) - print(tmp_d) + self.all_localizations = flatten(self.localization_table) for lang, d in self.localization_table.items(): - self.localization_table[lang] = Localizer._parse_localization_dictionary(self.localization_table[lang], tmp_d) + self.localization_table[lang] = Localizer._parse_localization_dictionary(self.localization_table[lang], self.all_localizations) # internal function for loading a localization def _load_localization(self, lang): @@ -49,12 +50,10 @@ class Localizer: if localization is None: raise Exception(f'Localization for {lang} does not exist') elif localization is False: - print(f'Loading {lang}') self.localization_table[lang] = {} l_table = self.localization_table[lang] for file in glob(path.join(self.localization_folder, lang, "*.json")): file_base = path.basename(file).split(".")[0] - print(f'{file_base} -> {file}') with open(file) as f: data = json.load(f) @@ -64,7 +63,6 @@ class Localizer: self.localization_table[lang] = Localizer._parse_localization_dictionary(l_table, l_table) for file in glob(path.join(self.localization_folder, lang, "*.txt")): file_base = path.basename(file).split(".")[0] - print(f'{file_base} -> {file}') with open(file) as f: content = Localizer._parse_localization_string(f.read(), self.localization_table[lang]) self.localization_table[lang][file_base] = content @@ -101,4 +99,37 @@ class Localizer: return self.localization_table.get(lang, {}).get(key.replace(".", "/")) - \ No newline at end of file + # inserts translations into a string + def format_str(self, s, lang=None): + lang = lang or self.default_lang + if not self.isLoaded(lang): + self._load_localization(lang) + + ns = Localization._parse_localization_string(s, self.localization_table.get(lang, {})) + return Localization._parse_localization_string(s, self.all_localizations) + + # inserts translations into a values of a dictionary + def format_dict(self, d, lang=None): + lang = lang or self.default_lang + if not self.isLoaded(lang): + self._load_localization(lang) + + nd = copy.deepcopy(d) + cursorQueue = [nd] + while cursorQueue: + cursor = cursorQueue.pop() + for k, v in (cursor.items() if type(cursor) == dict else enumerate(cursor)): + if type(v) == str: + # insert translations based on lang + v = Localizer._parse_localization_string(v, self.localization_table.get(lang, {})) + # insert translations based on key prefix, e.g 'global.', 'en_en.' + cursor[k] = Localizer._parse_localization_string(v, self.all_localizations) + elif type(v) == dict or type(v) == list: + cursorQueue.append(v) + + return nd + + # inserts translations into a values of a embed + def format_embed(self, embed, lang=None): + raw = embed.to_dict() + return Embed.from_data(self.format_dict(raw, lang)) \ No newline at end of file From bcfbd249ddd4ed7b7762b039b49f0d34a9bd19ae Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2019 05:45:33 +0100 Subject: [PATCH 11/37] Example info localization files --- localization/en_en/info.json | 5 +++++ localization/nb_no/info.json | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 localization/en_en/info.json create mode 100644 localization/nb_no/info.json diff --git a/localization/en_en/info.json b/localization/en_en/info.json new file mode 100644 index 0000000..d781101 --- /dev/null +++ b/localization/en_en/info.json @@ -0,0 +1,5 @@ +{ + "what": "what?", + "description": "Made by /r/Norge", + "infotext": "Shite Music Bot" +} \ No newline at end of file diff --git a/localization/nb_no/info.json b/localization/nb_no/info.json new file mode 100644 index 0000000..432262b --- /dev/null +++ b/localization/nb_no/info.json @@ -0,0 +1,5 @@ +{ + "what": "hva?", + "description": "Laget av /r/Norge", + "infotext": "Dorli Musikk Bot" +} \ No newline at end of file From d3b05a147847edaed686b988f188da23b990e846 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2019 05:54:32 +0100 Subject: [PATCH 12/37] Added method for getting available localizations --- cogs/utils/localizer.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cogs/utils/localizer.py b/cogs/utils/localizer.py index f704790..c40a480 100644 --- a/cogs/utils/localizer.py +++ b/cogs/utils/localizer.py @@ -91,6 +91,9 @@ class Localizer: def isLoaded(self, lang): return self.localization_table.get(lang, False) + def getAvaliableLocalizations(self): + return self.localization_table.keys() + # returns translation string from a key def get(self, key, lang=None): lang = lang or self.default_lang From 5f4ca8a8001a30952ee4043f14a39e2ad492d795 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2019 10:22:01 +0100 Subject: [PATCH 13/37] Updated localizations, added localization for music responses --- localization/en_en/block_example.txt | 4 -- localization/en_en/commands.json | 3 ++ localization/en_en/example.json | 6 --- localization/en_en/info.json | 8 +-- localization/en_en/music.json | 70 +++++++++++++++++++++++++++ localization/en_en/music_controls.txt | 10 ++++ localization/nb_no/block_example.txt | 4 -- localization/nb_no/commands.json | 3 ++ localization/nb_no/example.json | 6 --- localization/nb_no/info.json | 8 +-- localization/nb_no/music.json | 70 +++++++++++++++++++++++++++ localization/nb_no/music_controls.txt | 10 ++++ 12 files changed, 176 insertions(+), 26 deletions(-) delete mode 100644 localization/en_en/block_example.txt create mode 100644 localization/en_en/commands.json delete mode 100644 localization/en_en/example.json create mode 100644 localization/en_en/music.json create mode 100644 localization/en_en/music_controls.txt delete mode 100644 localization/nb_no/block_example.txt create mode 100644 localization/nb_no/commands.json delete mode 100644 localization/nb_no/example.json create mode 100644 localization/nb_no/music.json create mode 100644 localization/nb_no/music_controls.txt diff --git a/localization/en_en/block_example.txt b/localization/en_en/block_example.txt deleted file mode 100644 index 15769e9..0000000 --- a/localization/en_en/block_example.txt +++ /dev/null @@ -1,4 +0,0 @@ -Example file -title: {example.title} -Repo: {global.vars.repo} -Some Norwegian: {nb_no.example.title} \ No newline at end of file diff --git a/localization/en_en/commands.json b/localization/en_en/commands.json new file mode 100644 index 0000000..0f031d3 --- /dev/null +++ b/localization/en_en/commands.json @@ -0,0 +1,3 @@ +{ + "not_available_dm": "This command is not available in DMs" +} \ No newline at end of file diff --git a/localization/en_en/example.json b/localization/en_en/example.json deleted file mode 100644 index 12a4e6e..0000000 --- a/localization/en_en/example.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "title": "Hello World {example.misc.var}", - "misc": { - "var": "4321" - } -} \ No newline at end of file diff --git a/localization/en_en/info.json b/localization/en_en/info.json index d781101..57a2a1f 100644 --- a/localization/en_en/info.json +++ b/localization/en_en/info.json @@ -1,5 +1,7 @@ { - "what": "what?", - "description": "Made by /r/Norge", - "infotext": "Shite Music Bot" + "name": "what?", + "infotext": "Made by /r/Norge", + "footer": { + "text": "Shite Music Bot" + } } \ No newline at end of file diff --git a/localization/en_en/music.json b/localization/en_en/music.json new file mode 100644 index 0000000..6cf2819 --- /dev/null +++ b/localization/en_en/music.json @@ -0,0 +1,70 @@ +{ + "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!", + "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" + }, + "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" + }, + "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" + } + } +} \ No newline at end of file diff --git a/localization/en_en/music_controls.txt b/localization/en_en/music_controls.txt new file mode 100644 index 0000000..45a22f9 --- /dev/null +++ b/localization/en_en/music_controls.txt @@ -0,0 +1,10 @@ +**Controls** +Play/pause: +{BLACK RIGHT-POINTING TRIANGLE} +{DOUBLE VERTICAL BAR} +skip 15 seconds forward/backward: +{BLACK LEFT-POINTING DOUBLE TRIANGLE} +{BLACK RIGHT-POINTING DOUBLE TRIANGLE} +Skip to beginning/end of song: +{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} +{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} \ No newline at end of file diff --git a/localization/nb_no/block_example.txt b/localization/nb_no/block_example.txt deleted file mode 100644 index fcb1ea2..0000000 --- a/localization/nb_no/block_example.txt +++ /dev/null @@ -1,4 +0,0 @@ -Eksempel fil -Tittel: {example.title} -Repo: {global.vars.repo} -Noe engelsk: {en_en.example.title} \ No newline at end of file diff --git a/localization/nb_no/commands.json b/localization/nb_no/commands.json new file mode 100644 index 0000000..ee4ff4a --- /dev/null +++ b/localization/nb_no/commands.json @@ -0,0 +1,3 @@ +{ + "not_available_dm": "Denne kommandoen er ikke tilgjengelig i DMs" +} \ No newline at end of file diff --git a/localization/nb_no/example.json b/localization/nb_no/example.json deleted file mode 100644 index b38f780..0000000 --- a/localization/nb_no/example.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "title": "Hallo Verden {example.misc.var}", - "misc": { - "var": "1234" - } -} \ No newline at end of file diff --git a/localization/nb_no/info.json b/localization/nb_no/info.json index 432262b..2a56812 100644 --- a/localization/nb_no/info.json +++ b/localization/nb_no/info.json @@ -1,5 +1,7 @@ { - "what": "hva?", - "description": "Laget av /r/Norge", - "infotext": "Dorli Musikk Bot" + "name": "hva?", + "infotext": "Laget av /r/Norge", + "footer": { + "text": "Dorli Musikk Bot" + } } \ No newline at end of file diff --git a/localization/nb_no/music.json b/localization/nb_no/music.json new file mode 100644 index 0000000..6cf2819 --- /dev/null +++ b/localization/nb_no/music.json @@ -0,0 +1,70 @@ +{ + "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!", + "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" + }, + "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" + }, + "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" + } + } +} \ No newline at end of file diff --git a/localization/nb_no/music_controls.txt b/localization/nb_no/music_controls.txt new file mode 100644 index 0000000..45a22f9 --- /dev/null +++ b/localization/nb_no/music_controls.txt @@ -0,0 +1,10 @@ +**Controls** +Play/pause: +{BLACK RIGHT-POINTING TRIANGLE} +{DOUBLE VERTICAL BAR} +skip 15 seconds forward/backward: +{BLACK LEFT-POINTING DOUBLE TRIANGLE} +{BLACK RIGHT-POINTING DOUBLE TRIANGLE} +Skip to beginning/end of song: +{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} +{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} \ No newline at end of file From b5b84c4c454fb2b29cc787390e3abe2140a0eae7 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2019 10:23:00 +0100 Subject: [PATCH 14/37] utf-8 support --- cogs/utils/localizer.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/cogs/utils/localizer.py b/cogs/utils/localizer.py index c40a480..c846576 100644 --- a/cogs/utils/localizer.py +++ b/cogs/utils/localizer.py @@ -54,19 +54,25 @@ class Localizer: l_table = self.localization_table[lang] for file in glob(path.join(self.localization_folder, lang, "*.json")): file_base = path.basename(file).split(".")[0] - with open(file) as f: + with open(file, "r", encoding='utf-8') as f: data = json.load(f) l_table[file_base] = data - - l_table = flatten(l_table) - self.localization_table[lang] = Localizer._parse_localization_dictionary(l_table, l_table) + for file in glob(path.join(self.localization_folder, lang, "*.txt")): file_base = path.basename(file).split(".")[0] - with open(file) as f: - content = Localizer._parse_localization_string(f.read(), self.localization_table[lang]) - self.localization_table[lang][file_base] = content + with open(file, "r", encoding='utf-8') as f: + content = f.read() + l_table[file_base] = content + + l_table = flatten(l_table) + # parsing a few times to resolve all values + for i in range(0, 5): + l_table = Localizer._parse_localization_dictionary(l_table, l_table) + + self.localization_table[lang] = Localizer._parse_localization_dictionary(l_table, l_table) + # parses and interpolates translation dictionary @staticmethod def _parse_localization_dictionary(d, lookup): From 64824f11870ad5f842bf9e493a938b267eb1871e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2019 10:23:48 +0100 Subject: [PATCH 15/37] Added setting for localization Added translation code for music, bot info and one other bot command --- bot.py | 4 +- cogs/misc.py | 18 ++-- cogs/music.py | 172 ++++++++++++++++++++-------------- cogs/utils/settings.py | 13 ++- localization/en_en/info.json | 14 ++- localization/nb_no/info.json | 12 ++- localization/nb_no/music.json | 1 + 7 files changed, 144 insertions(+), 90 deletions(-) diff --git a/bot.py b/bot.py index 42dab77..d2e70f5 100644 --- a/bot.py +++ b/bot.py @@ -8,6 +8,7 @@ import traceback from discord.ext import commands from cogs.utils.settings import Settings +from cogs.utils.localizer import Localizer initial_extension = [ 'cogs.cogs', @@ -35,6 +36,7 @@ class Bot(commands.Bot): description=config["description"]) self.settings = Settings(**config) + self.localizer = Localizer("./localization", "en_en") self.debug = debug for extension in initial_extension: @@ -61,7 +63,7 @@ class Bot(commands.Bot): pass elif isinstance(err, commands.NoPrivateMessage): - await ctx.send("Denne kommandoen er ikke tilgjengelig i DMs") + await ctx.send(self.localizer.format_string("{commands.not_available_dm}", setting.get_locale(ctx.guild.id))) elif isinstance(err, commands.CheckFailure): pass diff --git a/cogs/misc.py b/cogs/misc.py index 1bf8203..435b7a0 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -63,23 +63,25 @@ class Misc: avatar = self.bot.user.avatar_url_as(format=None, static_format='png', size=1024) - infotext = f'Musikkbot skrevet for bruk på /r/Norge sine Discord Servere. Kildekoden er åpen! Den kan du finne [HER](https://gitlab.com/Ev-1/shite-music-bot)' - spectext = f'**Python:** [{platform.python_version()}](https://www.python.org/)\n**Discord.py:** [{discord.__version__}](https://github.com/Rapptz/discord.py/tree/rewrite)\n**Lavalink:** [{LavalinkVersion}](https://github.com/Devoxin/Lavalink.py)' - stattext = f'**Guilder:** {guilds}\n**Brukere:** {members}' + infotext = '{info.infotext}' + spectext = self.bot.localizer.get("info.spectext").format(_python_v=platform.python_version, _discord_v=discord.__version__, _lavalink_v=LavalinkVersion) + stattext = self.bot.localizer.get("info.stattext").format(_guilds=guilds, _members=members) uptimetext = f'{days}d {hours}t {minutes}m {seconds}s' embed = discord.Embed(color=0xD9C04D) embed.set_author(name=self.bot.user.name, icon_url=avatar) embed.set_thumbnail(url=avatar) - embed.add_field(name="Hva?", + embed.add_field(name="{info.what}", value=infotext, inline=False) embed.set_footer(icon_url="https://cdn.discordapp.com/icons/297798952538079233/0198dc7b01ccf288b985b8a394cb1d44.jpg?size=64", - text="Laget av /r/Norge, for /r/Norge") - embed.add_field(name="Hvordan?", + text="{info.footer_text}") + embed.add_field(name="{info.how}", value=spectext) - embed.add_field(name="Hvor mange?", + embed.add_field(name="{info.how_many}", value=stattext) - embed.add_field(name="Hvor lenge?", + embed.add_field(name="{info.how_long}", value=uptimetext) + + embed = self.bot.localizer.format_embed(embed, self.bot.settings.get_locale(ctx.guild.id)) await ctx.send(embed=embed) @commands.command() diff --git a/cogs/music.py b/cogs/music.py index 93253b6..6f68bc0 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -63,7 +63,7 @@ class Music: 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) - + lang = self.bot.settings.get_locale(ctx.guild.id) query = query.strip('<>') if not url_rx.match(query): @@ -72,7 +72,7 @@ class Music: results = await player.node.get_tracks(query) if not results or not results['tracks']: - return await ctx.send('Nothing found!') + return await ctx.send(self.bot.localizer.get("music.response.nothing_found", lang)) embed = discord.Embed(color=0xEFD26C) @@ -82,8 +82,9 @@ class Music: for track in tracks: player.add(requester=ctx.author.id, track=track) - embed.title = 'Playlist Enqueued!' - embed.description = f'{results["playlistInfo"]["name"]} - {len(tracks)} tracks' + embed.title = '{music.response.playlist_enqued}' + embed.description = f'{results["playlistInfo"]["name"]} - {len(tracks)} {{music.response.tracks}}' + embed = self.bot.localizer.format_embed(embed, lang) await ctx.send(embed=embed) else: track = results['tracks'][0] @@ -98,16 +99,17 @@ class Music: async def seek(self, ctx, *, time: str): """ Seeks to a given position in a track. """ player = self.bot.lavalink.players.get(ctx.guild.id) - + lang = self.bot.settings.get_locale(ctx.guild.id) + if not player.is_playing: - return await ctx.send('Not playing.') + return await ctx.send(self.bot.localizer.get("music.response.not_playing", lang)) if ctx.author not in player.listeners: - return await ctx.send('You have to be listening to the bot') + return await ctx.send(self.bot.localizer.get("music.response.have_to_listen", lang)) seconds = time_rx.search(time) if not seconds: - return await ctx.send('You need to specify the amount of seconds to skip!') + return await ctx.send(self.bot.localizer.get("music.response.seek.missing_amount", lang)) seconds = int(seconds.group()) * 1000 if time.startswith('-'): @@ -115,77 +117,82 @@ class Music: track_time = player.position + seconds await player.seek(track_time) - - await ctx.send(f'Moved track to **{lavalink.utils.format_time(track_time)}**') + msg = self.bot.localizer.get("music.response.seek.track_moved", lang).format(_position=lavalink.utils.format_time(track_time)) + await ctx.send(msg) @commands.command() async def skip(self, ctx): """ Skips the current track. """ player = self.bot.lavalink.players.get(ctx.guild.id) + lang = self.bot.settings.get_locale(ctx.guild.id) if not player.is_playing: - return await ctx.send('Not playing.') + return await ctx.send(self.bot.localizer.get("music.response.not_playing", lang)) player.add_skipper(ctx.author) total = len(player.listeners) skips = len(player.skip_voters) if skips >= math.ceil(total/2) or player.current.requester == ctx.author.id: await player.skip() - await ctx.send('Skipped.') + await ctx.send(self.bot.localizer.get("music.response.skip.skipped", lang)) else: if skips != 0: - await ctx.send(f'{skips} out of {math.ceil(total/2)} required haters have voted to skip.') + msg = self.bot.localizer.get("music.response.skip.require_vote", lang).format(_skips=skips, _total=math.ceil(total/2)) + await ctx.send(msg) @commands.command(name='skipto', aliases=['st','skip_to','forceskip']) @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) + lang = self.bot.settings.get_locale(ctx.guild.id) if ctx.author not in player.listeners: - return await ctx.send('You have to be listening to the bot') + return await ctx.send(self.bot.localizer.get("music.response.have_to_listen", lang)) if pos < 1: - return await ctx.send('Invalid specified position.') + return await ctx.send(self.bot.localizer.get("music.response.skip_to.invalid_pos", lang)) if len(player.queue) < pos: - return await ctx.send('The position exceeds the queue\'s length.') + return await ctx.send(self.bot.localizer.get("music.response.skip_to.exceeds_queue", lang)) await player.skip(pos - 1) - await ctx.send(f'skipped to `{player.current.title}` at position `{pos}`') + msg = self.bot.localizer.get("music.response.skipped_to", lang).format(_title=player.current.title,_pos=pos) + await ctx.send(msg) @commands.command() @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) + lang = self.bot.settings.get_locale(ctx.guild.id) if ctx.author not in player.listeners: - return await ctx.send('You have to be listening to the bot') + return await ctx.send(self.bot.localizer.get("music.response.have_to_listen", lang)) if not player.is_playing: - return await ctx.send('Not playing.') + return await ctx.send(self.bot.localizer.get("music.response.not_playing", lang)) player.queue.clear() await player.stop() - await ctx.send('⏹ | Stopped.') + await ctx.send(self.bot.localizer.get("music.response.stop", lang)) @commands.command(aliases=['np', 'n', 'playing','current']) async def now(self, ctx): """ Shows some stats about the currently playing song. """ player = self.bot.lavalink.players.get(ctx.guild.id) + lang = self.bot.settings.get_locale(ctx.guild.id) if not player.current: - return await ctx.send('Nothing playing.') + return await ctx.send(self.bot.localizer.get("music.response.not_playing", lang)) position = lavalink.utils.format_time(player.position) if player.current.stream: - duration = '🔴 LIVE' + duration = '{music.response.live}' else: duration = lavalink.utils.format_time(player.current.duration) song = f'**[{player.current.title}]({player.current.uri})**\n({position}/{duration})' member = ctx.guild.get_member(player.current.requester) - - embed = discord.Embed(color=0xEFD26C, description=song, title='Now playing') + embed = discord.Embed(color=0xEFD26C, description=song, title='{music.response.now}') thumbnail_url = await RoxUtils.ThumbNailer.identify(self,player.current.identifier, player.current.uri) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) @@ -194,16 +201,19 @@ class Music: member_identifier = member.nick else: member_identifier = member.name - embed.set_footer(text=f'Requested by {member_identifier}', icon_url=member.avatar_url) + embed.set_footer(text=f'{{music.response.requested_by}} {member_identifier}', icon_url=member.avatar_url) + + embed = self.bot.localizer.format_embed(embed, lang) await ctx.send(embed=embed) @commands.command(aliases=['q']) async def queue(self, ctx, user: discord.Member=None): """ Shows the player's queue. """ player = self.bot.lavalink.players.get(ctx.guild.id) + lang = self.bot.settings.get_locale(ctx.guild.id) if player.queue.empty: - return await ctx.send('The queue is empty') + return await ctx.send(self.bot.localizer.get("music.respone.queue.empty", lang)) if user is None: queue = player.global_queue() @@ -213,7 +223,7 @@ class Music: else: user_queue = player.user_queue(user.id, dual=True) if not user_queue: - return await ctx.send(f'{user.name}\'s queue is empty') + return await ctx.send(self.bot.localizer.get("music.respone.queue.empty", lang).format(_user=user.name)) scroller = QueueScroller(ctx, user_queue, lines_per_page=10, user_name=user.name) await scroller.start_scrolling() @@ -222,10 +232,11 @@ class Music: async def _myqueue(self, ctx): """ Shows your queue. """ player = self.bot.lavalink.players.get(ctx.guild.id) + lang = self.bot.settings.get_locale(ctx.guild.id) user_queue = player.user_queue(ctx.author.id, dual=True) if not user_queue: - return await ctx.send('Your queue is empty') + return await ctx.send(self.bot.localizer.get("music.respone.my_queue", lang)) scroller = QueueScroller(ctx, user_queue, lines_per_page=10, user_name=ctx.author.name) await scroller.start_scrolling() @@ -235,51 +246,57 @@ class Music: async def pause(self, ctx): """ Pauses/Resumes the current track. """ player = self.bot.lavalink.players.get(ctx.guild.id) + lang = self.bot.settings.get_locale(ctx.guild.id) if not player.is_playing: - return await ctx.send('Not playing.') + return await ctx.send(self.bot.localizer.get("music.respone.not_playing", lang)) if player.paused: await player.set_pause(False) - await ctx.send('⏯ | Resumed') + await ctx.send(self.bot.localizer.get("music.respone.resume.resumed", lang)) else: await player.set_pause(True) - await ctx.send('⏯ | Paused') + await ctx.send(self.bot.localizer.get("music.respone.resume.paused", lang)) @commands.command(name='shuffle') async def _shuffle(self, ctx): """ Shuffles your queue. """ player = self.bot.lavalink.players.get(ctx.guild.id) + lang = self.bot.settings.get_locale(ctx.guild.id) + user_queue = player.user_queue(ctx.author.id) if not user_queue: - return await ctx.send('Your queue is empty') + return await ctx.send(self.bot.localizer.get("music.respone.my_queue", lang)) player.shuffle_user_queue(ctx.author.id) - await ctx.send('Your queue has been shuffled') + await ctx.send(self.bot.localizer.get("music.respone.shuffle", lang)) @commands.command(name='move', aliases=["m"]) 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) + lang = self.bot.settings.get_locale(ctx.guild.id) user_queue = player.user_queue(ctx.author.id) if not user_queue: - return await ctx.send('Your queue is empty') + return await ctx.send(self.bot.localizer.get("music.respone.my_queue", lang)) if not all(x in range(1,len(user_queue)+1) for x in [from_pos, to_pos]): - return await ctx.send(f'Positions must be between 1 and {len(user_queue)}') + return await ctx.send(self.bot.localizer.get("music.respone.my_queue", lang).format(_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('Check that the positions exist in your queue') + return await ctx.send(self.bot.localizer.get("music.respone.move.not_in_queue", lang)) - await ctx.send(f'{moved.title} moved from position {from_pos} to {to_pos} in your queue') + msg = self.bot.localizer.get("music.respone.move.moved_to", lang).format(_title=moved.title, _from=from_pos, _to=to_pos) + await ctx.send(msg) @commands.command() 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) + lang = self.bot.settings.get_locale(ctx.guild.id) if player.queue.empty: return @@ -289,28 +306,29 @@ class Music: return if pos > len(user_queue) or pos < 1: - return await ctx.send(f'Position has to be between 1 and {len(user_queue)}') + return await ctx.send(self.bot.localizer.get("music.respone.out_of_range", lang).format(_len=len(user_queue))) removed = player.remove_user_track(ctx.author.id, pos - 1) - await ctx.send(f'**{removed.title}** removed.') + await ctx.send(self.bot.localizer.get("music.respone.remove", lang).format(_title=removed.title)) @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) + lang = self.bot.settings.get_locale(ctx.guild.id) if user is None: if player.queue.empty: return if pos > len(player.queue) or pos < 1: - return await ctx.send(f'Position has to be between 1 and {len(player.queue)}') + return await ctx.send(self.bot.localizer.get("music.respone.out_of_range", lang).format(_len=len(player.queue))) removed = player.remove_global_track(pos - 1) requester = self.bot.get_user(removed.requester) - await ctx.send(f'**{removed.title}** queued by {requester.name} removed.') + await ctx.send(self.bot.localizer.get("music.respone.dj_removed", lang).format(_title=removed.title, _user=requester.name)) else: if player.queue.empty: @@ -321,16 +339,17 @@ class Music: return if pos > len(user_queue) or pos < 1: - return await ctx.send(f'Position has to be between 1 and {len(user_queue)}') + return await ctx.send(self.bot.localizer.get("music.respone.out_of_range", lang).format(_len=len(user_queue))) removed = player.remove_user_track(user.id, pos - 1) - await ctx.send(f'**{removed.title}** queued by {user.name} removed.') + await ctx.send(self.bot.localizer.get("music.respone.dj_removed", lang).format(_title=removed.title, _user=requester.name)) @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) + lang = self.bot.settings.get_locale(ctx.guild.id) if player.queue.empty: return @@ -341,21 +360,23 @@ class Music: player.remove_user_queue(user.id) embed = discord.Embed(color=0x36393F) - embed.description = f'Removed all songs queued by <@{user.id}>.' + embed.description = self.bot.localizer.get("music.respone.dj_remove_user", lang).format(_id=user.id) await ctx.send(embed=embed) @commands.command() 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) + lang = self.bot.settings.get_locale(ctx.guild.id) if not query.startswith('ytsearch:') and not query.startswith('scsearch:'): query = 'ytsearch:' + query results = await player.node.get_tracks(query) - embed = discord.Embed(description='Nothing found', color=0x36393F) + embed = discord.Embed(description='{music.respone.nothing_found}', color=0x36393F) if not results or not results['tracks']: + embed = self.bot.localizer.format_embed(embed, lang) return await ctx.send(embed=embed) tracks = results['tracks'] @@ -395,7 +416,8 @@ class Music: return True return False - embed.description = 'searching' + embed.description = '{music.response.search}' + embed = self.bot.localizer.format_embed(embed, lang) result_msg = await ctx.send(embed=embed) for emoji, index in choices[:result_count]: @@ -403,8 +425,9 @@ class Music: await result_msg.add_reaction('❌') embed.description = search_results - embed.title = 'Results' + embed.title = '{music.response.results}' embed.color = 0xEFD26C + embed = self.bot.localizer.format_embed(embed, lang) await result_msg.edit(embed=embed) try: @@ -414,7 +437,8 @@ class Music: except asyncio.TimeoutError: await result_msg.clear_reactions() embed.title = '' - embed.description='Timer Expired' + embed.description='{music.respone.time_expired}' + embed = self.bot.localizer.format_embed(embed, lang) await result_msg.edit(embed=embed) await asyncio.sleep(5) await result_msg.delete() @@ -434,17 +458,19 @@ class Music: 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) + lang = self.bot.settings.get_locale(ctx.guild.id) if not player.is_connected: - return await ctx.send('Not connected.') + return await ctx.send(self.bot.localizer.get("music.response.not_connected", lang)) if not ctx.author.voice or (player.is_connected and ctx.author.voice.channel.id != int(player.channel_id)): - return await ctx.send('You\'re not in my voicechannel!') + return await ctx.send(self.bot.localizer.get("music.response.disconnect.not_in_voice", lang)) player.queue.clear() await player.stop() await self.connect_to(ctx.guild.id, None) - embed = discord.Embed(description='Disconnected', color=0x36393F) + embed = discord.Embed(description='{music.response.disconnect.disconnected}', color=0x36393F) + embed = self.bot.localizer.format_embed(embed, lang) await ctx.send(embed=embed) @commands.command(aliases=['vol']) @@ -452,6 +478,7 @@ class Music: 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) + lang = self.bot.settings.get_locale(ctx.guild.id) if not volume: return await ctx.send(f'🔈 | {player.volume}%') @@ -462,7 +489,7 @@ class Music: await player.set_volume(volume) embed = discord.Embed(color=0x36393F) - embed.description = f'Volume set to {player.volume}' + embed.description = self.bot.localizer.get("music.response.volume.set_to", lang).format(_volume=player.volume)' await ctx.send(embed=embed) @commands.command(aliases=['normal','nl']) @@ -470,11 +497,13 @@ class Music: async def normalize(self, ctx): """ Reset the equalizer and """ player = self.bot.lavalink.players.get(ctx.guild.id) + lang = self.bot.settings.get_locale(ctx.guild.id) await player.set_volume(100) await player.bassboost(False) embed = discord.Embed(color=0x36393F) - embed.description = 'Volume and equalizer reset' + embed.description = '{music.response.volume.reset}' + embed = self.bot.localizer.format_embed(embed, lang) await ctx.send(embed=embed) @commands.command(name='boost', aliases=['boo']) @@ -482,18 +511,20 @@ class Music: 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) - + lang = self.bot.settings.get_locale(ctx.guild.id) + if boost is not None: await player.bassboost(boost) embed = discord.Embed(color=0x36393F) if player.boosted: - embed.description = 'Bass boost is on' - await ctx.send(embed=embed) + embed.description = '{music.response.boost.on}' else: - embed.description = 'Bass boost is off' - await ctx.send(embed=embed) + embed.description = '{music.response.boost.off}' + + embed = self.bot.localizer.format_embed(embed, lang) + await ctx.send(embed=embed) @commands.command(name='history', aliases=['h','hist']) async def _history(self, ctx): @@ -522,15 +553,11 @@ class Music: async def scrub(self, ctx): """ Lists the first 10 search results from a given query. """ player = self.bot.lavalink.players.get(ctx.guild.id) + lang = self.bot.settings.get_locale(ctx.guild.id) - controls = ''' - **Controls** - Play/pause: \N{BLACK RIGHT-POINTING TRIANGLE} \N{DOUBLE VERTICAL BAR} - skip 15 seconds forward/backward: \N{BLACK LEFT-POINTING DOUBLE TRIANGLE} \N{BLACK RIGHT-POINTING DOUBLE TRIANGLE} - Skip to beginning/end of song: \N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} \N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} - - ''' - embed = discord.Embed(description='Nothing playing', color=0x36393F) + controls = '{music.response.scrub.controls}' + embed = discord.Embed(description='{music.response.nothing_playing}', color=0x36393F) + embed = self.bot.localizer.format_embed(embed, lang) if player.current is None: return await ctx.send(embed=embed) @@ -562,13 +589,15 @@ class Music: return True return False - embed.description = 'Adding controls' + embed.description = '{music.response.scrub.add}' + embed = self.bot.localizer.format_embed(embed, lang) msg = await ctx.send(embed=embed) for (emoji, _, _) in scrubber: await msg.add_reaction(emoji) embed.description = controls + embed = self.bot.localizer.format_embed(embed, lang) await msg.edit(embed=embed) scrubbing = True while scrubbing: @@ -657,6 +686,7 @@ class Music: player = self.bot.lavalink.players.get(ctx.guild.id) track, pos_global, pos_local = player.add(requester=ctx.author.id, track=track) + lang = self.bot.settings.get_locale(ctx.guild.id) if player.current is not None: queue_duration = 0 @@ -667,10 +697,10 @@ class Music: until_play = queue_duration + player.current.duration - player.position until_play = lavalink.utils.format_time(until_play) - embed.add_field(name="Position", value=f"`{pos_local + 1}({pos_global + 1})`", inline=True) - embed.add_field(name="Playing in", value=f"`{until_play} (estimated)`", inline=True) + embed.add_field(name="{music.response.enqueue.position}", value=f"`{pos_local + 1}({pos_global + 1})`", inline=True) + embed.add_field(name="{music.response.enqueue.playing_in}", value=f"`{until_play} ({{music.response.enqueue.estimated}})`", inline=True) - embed.title = 'Song enqueued' + embed.title = '{music.response.enqueue.enqueued}' thumb_url = await RoxUtils.ThumbNailer.identify(self, track.identifier, track.uri) @@ -680,7 +710,7 @@ class Music: duration = lavalink.utils.format_time(int(track.duration)) embed.description = f'[{track.title}]({track.uri})\n**{duration}**' - + embed = self.bot.localizer.format_embed(embed, lang) def setup(bot): bot.add_cog(Music(bot)) diff --git a/cogs/utils/settings.py b/cogs/utils/settings.py index 1ebc762..5971775 100644 --- a/cogs/utils/settings.py +++ b/cogs/utils/settings.py @@ -1,7 +1,7 @@ import os import json import codecs - +import locale class Settings: def __init__(self, **default_settings): @@ -10,6 +10,12 @@ class Settings: self.default_prefix = default_settings["default_prefix"] self.default_admin = default_settings["default_admin"] self.default_mod = default_settings["default_mod"] + self.default_locale = default_settings["default_locale"] + + if not self.default_locale: + locale, codepage = locale.getlocale() + default_locale, default_codepage = locale.getdefaultlocale() + self.default_locale = locale or default_locale if not os.path.exists(self.DATA_PATH): os.makedirs(self.DATA_PATH) @@ -60,3 +66,8 @@ class Settings: with codecs.open(self.SETTINGS_PATH, "w", encoding='utf8') as f: json.dump(self.settings, f, indent=4) + + def get_locale(self, guild_id): + guild_id = str(guild_id) + return self.settings.get("locale", {}).get(guild_id, self.default_locale).lower() + diff --git a/localization/en_en/info.json b/localization/en_en/info.json index 57a2a1f..4677eec 100644 --- a/localization/en_en/info.json +++ b/localization/en_en/info.json @@ -1,7 +1,11 @@ { - "name": "what?", - "infotext": "Made by /r/Norge", - "footer": { - "text": "Shite Music 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": "**Guilder:** {_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" } \ No newline at end of file diff --git a/localization/nb_no/info.json b/localization/nb_no/info.json index 2a56812..4677eec 100644 --- a/localization/nb_no/info.json +++ b/localization/nb_no/info.json @@ -1,7 +1,11 @@ { "name": "hva?", - "infotext": "Laget av /r/Norge", - "footer": { - "text": "Dorli Musikk Bot" - } + "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": "**Guilder:** {_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" } \ No newline at end of file diff --git a/localization/nb_no/music.json b/localization/nb_no/music.json index 6cf2819..67da832 100644 --- a/localization/nb_no/music.json +++ b/localization/nb_no/music.json @@ -5,6 +5,7 @@ "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!", From 629bb8ae9688871c4d9a356bcaada73846294b43 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2019 10:27:42 +0100 Subject: [PATCH 16/37] Fixed syntax error --- cogs/music.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cogs/music.py b/cogs/music.py index 6f68bc0..4f7998a 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -489,7 +489,7 @@ class Music: await player.set_volume(volume) embed = discord.Embed(color=0x36393F) - embed.description = self.bot.localizer.get("music.response.volume.set_to", lang).format(_volume=player.volume)' + embed.description = self.bot.localizer.get("music.response.volume.set_to", lang).format(_volume=player.volume) await ctx.send(embed=embed) @commands.command(aliases=['normal','nl']) From 6d65a76c8004b5225493a762da21759562d78c34 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2019 10:27:57 +0100 Subject: [PATCH 17/37] Added missing field --- localization/en_en/music.json | 3 ++- localization/nb_no/music.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/localization/en_en/music.json b/localization/en_en/music.json index 6cf2819..532f9be 100644 --- a/localization/en_en/music.json +++ b/localization/en_en/music.json @@ -64,7 +64,8 @@ "enqueue": { "position": "position", "playing_in": "Playing in", - "enqueued": "Song enqueued" + "enqueued": "Song enqueued", + "estimated": "estimated" } } } \ No newline at end of file diff --git a/localization/nb_no/music.json b/localization/nb_no/music.json index 67da832..4d9dc6c 100644 --- a/localization/nb_no/music.json +++ b/localization/nb_no/music.json @@ -65,7 +65,8 @@ "enqueue": { "position": "position", "playing_in": "Playing in", - "enqueued": "Song enqueued" + "enqueued": "Song enqueued", + "estimated": "estimated" } } } \ No newline at end of file From a0a8c96ab490e9ef05bb5f87b2236096448ef61e Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 26 Jan 2019 13:57:24 +0100 Subject: [PATCH 18/37] Added config path for localization folder --- bot.py | 2 +- cogs/utils/settings.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bot.py b/bot.py index d2e70f5..ed5b359 100644 --- a/bot.py +++ b/bot.py @@ -36,7 +36,7 @@ class Bot(commands.Bot): description=config["description"]) self.settings = Settings(**config) - self.localizer = Localizer("./localization", "en_en") + self.localizer = Localizer(self.settings.get_language_path(), "en_en") self.debug = debug for extension in initial_extension: diff --git a/cogs/utils/settings.py b/cogs/utils/settings.py index 5971775..b0b355d 100644 --- a/cogs/utils/settings.py +++ b/cogs/utils/settings.py @@ -11,7 +11,7 @@ class Settings: self.default_admin = default_settings["default_admin"] self.default_mod = default_settings["default_mod"] self.default_locale = default_settings["default_locale"] - + self.default_lang_path = default_settings["default_lang_path"] or "./localization" if not self.default_locale: locale, codepage = locale.getlocale() default_locale, default_codepage = locale.getdefaultlocale() @@ -71,3 +71,5 @@ class Settings: guild_id = str(guild_id) return self.settings.get("locale", {}).get(guild_id, self.default_locale).lower() + def get_language_path(self): + return self.settings.get("language_path", self.default_lang_path) \ No newline at end of file From 2f1cfe9f5a2eeaf706bbf4a96ff703f5a52d74de Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sat, 26 Jan 2019 14:38:15 +0100 Subject: [PATCH 19/37] Separated out events --- bot.py | 1 + cogs/cogs.py | 2 ++ cogs/misc.py | 25 +++++++++++++--- cogs/music.py | 53 +++++++++------------------------ cogs/musicevents.py | 72 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 43 deletions(-) create mode 100644 cogs/musicevents.py diff --git a/bot.py b/bot.py index 42dab77..f3f5117 100644 --- a/bot.py +++ b/bot.py @@ -84,6 +84,7 @@ class Bot(commands.Bot): 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=config["playing"]), diff --git a/cogs/cogs.py b/cogs/cogs.py index 7b104c8..2ad85ce 100644 --- a/cogs/cogs.py +++ b/cogs/cogs.py @@ -2,6 +2,7 @@ import discord import os import json import codecs +import traceback from discord.ext import commands from cogs.utils import checks @@ -66,6 +67,7 @@ class Cogs: @checks.is_owner() async def _shutdown(self, ctx): """Logs out and stops.""" + self.bot.lavalink.players.clear() await self.bot.logout() diff --git a/cogs/misc.py b/cogs/misc.py index 1bf8203..68baf34 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -14,7 +14,6 @@ class Misc: self.bot = bot @commands.command(name='ping', hidden=True) - @checks.is_mod() async def _ping(self, ctx): start = time.perf_counter() message = await ctx.send('Ping...') @@ -40,6 +39,23 @@ class Misc: for guild in self.bot.guilds: guilds += f"{guild.name}\n" await ctx.send(guilds) + + @commands.command() + async def musicinfo(self, ctx): + """ + Info om musikkspilleren + """ + embed = discord.Embed(title='Music info', color=ctx.me.color) + lavalink = self.bot.lavalink + + listeners = 0 + for guild, player in lavalink.players: + listeners += len(player.listeners) + + embed.add_field(name='Players', value=f'{len(lavalink.players)}') + embed.add_field(name='Listeners', value=f'{listeners}') + await ctx.send(embed=embed) + @commands.command() async def info(self, ctx): @@ -65,14 +81,15 @@ class Misc: size=1024) infotext = f'Musikkbot skrevet for bruk på /r/Norge sine Discord Servere. Kildekoden er åpen! Den kan du finne [HER](https://gitlab.com/Ev-1/shite-music-bot)' spectext = f'**Python:** [{platform.python_version()}](https://www.python.org/)\n**Discord.py:** [{discord.__version__}](https://github.com/Rapptz/discord.py/tree/rewrite)\n**Lavalink:** [{LavalinkVersion}](https://github.com/Devoxin/Lavalink.py)' - stattext = f'**Guilder:** {guilds}\n**Brukere:** {members}' + stattext = f'**Tenarar:** {guilds}\n**Brukere:** {members}' uptimetext = f'{days}d {hours}t {minutes}m {seconds}s' - embed = discord.Embed(color=0xD9C04D) + embed = discord.Embed(color=ctx.me.color) 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="Hva?", value=infotext, inline=False) - embed.set_footer(icon_url="https://cdn.discordapp.com/icons/297798952538079233/0198dc7b01ccf288b985b8a394cb1d44.jpg?size=64", + embed.set_footer(icon_url="https://cdn.discordapp.com/icons/532176350019321917/92f43a1f67308a99a30c169db4b671dd.png?size=64", text="Laget av /r/Norge, for /r/Norge") embed.add_field(name="Hvordan?", value=spectext) diff --git a/cogs/music.py b/cogs/music.py index 93253b6..fb58a5f 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -1,6 +1,5 @@ """ -This is an example cog that shows how you would make use of Lavalink.py. -This example cog requires that you have python 3.6 or higher due to the f-strings. +Music commands """ import math import re @@ -31,19 +30,9 @@ class Music: bot.lavalink.add_node(host, port, password, region, 'default-node') # Host, Port, Password, Region, Name bot.add_listener(bot.lavalink.voice_update_handler, 'on_socket_response') - bot.lavalink.add_event_hook(self.track_hook) - - def __unload(self): - self.bot.lavalink._event_hooks.clear() - - async def track_hook(self, event): - if isinstance(event, lavalink.events.TrackEndEvent): - pass # Send track ended message to channel. - if isinstance(event, lavalink.events.QueueEndEvent): - channel = self.bot.get_channel(event.player.fetch('channel')) - await self.check_leave_voice(channel.guild) - 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). @@ -74,7 +63,7 @@ class Music: if not results or not results['tracks']: return await ctx.send('Nothing found!') - embed = discord.Embed(color=0xEFD26C) + embed = discord.Embed(color=ctx.me.color) if results['loadType'] == 'PLAYLIST_LOADED': tracks = results['tracks'] @@ -185,7 +174,7 @@ class Music: member = ctx.guild.get_member(player.current.requester) - embed = discord.Embed(color=0xEFD26C, description=song, title='Now playing') + embed = discord.Embed(color=ctx.me.color, description=song, title='Now playing') thumbnail_url = await RoxUtils.ThumbNailer.identify(self,player.current.identifier, player.current.uri) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) @@ -267,7 +256,7 @@ class Music: if not user_queue: return await ctx.send('Your queue is empty') - if not all(x in range(1,len(user_queue)+1) for x in [from_pos, to_pos]): + if not all(x in range(1, len(user_queue) + 1) for x in [from_pos, to_pos]): return await ctx.send(f'Positions must be between 1 and {len(user_queue)}') moved = player.move_user_track(ctx.author.id, from_pos - 1, to_pos - 1) @@ -340,7 +329,7 @@ class Music: return player.remove_user_queue(user.id) - embed = discord.Embed(color=0x36393F) + embed = discord.Embed(color=ctx.me.color) embed.description = f'Removed all songs queued by <@{user.id}>.' await ctx.send(embed=embed) @@ -404,7 +393,7 @@ class Music: embed.description = search_results embed.title = 'Results' - embed.color = 0xEFD26C + embed.color = ctx.me.color await result_msg.edit(embed=embed) try: @@ -444,7 +433,7 @@ class Music: player.queue.clear() await player.stop() await self.connect_to(ctx.guild.id, None) - embed = discord.Embed(description='Disconnected', color=0x36393F) + embed = discord.Embed(description='Disconnected', color=ctx.me.color) await ctx.send(embed=embed) @commands.command(aliases=['vol']) @@ -461,7 +450,7 @@ class Music: return await ctx.send(f'you can only set the volume between 50 and 125') await player.set_volume(volume) - embed = discord.Embed(color=0x36393F) + embed = discord.Embed(color=ctx.me.color) embed.description = f'Volume set to {player.volume}' await ctx.send(embed=embed) @@ -473,7 +462,7 @@ class Music: await player.set_volume(100) await player.bassboost(False) - embed = discord.Embed(color=0x36393F) + embed = discord.Embed(color=ctx.me.color) embed.description = 'Volume and equalizer reset' await ctx.send(embed=embed) @@ -486,7 +475,7 @@ class Music: if boost is not None: await player.bassboost(boost) - embed = discord.Embed(color=0x36393F) + embed = discord.Embed(color=ctx.me.color) if player.boosted: embed.description = 'Bass boost is on' @@ -510,7 +499,7 @@ class Music: for index, track in enumerate(history[1:], start=1): description += f'`{-index}.` **[{track.title}]({track.uri})** _by <@{track.requester}>_\n' - embed = discord.Embed(title='Track history', color=0xEFD26C, description=description) + embed = discord.Embed(title='Track history', color=ctx.me.color, description=description) if thumb_url: embed.set_thumbnail(url=thumb_url) @@ -530,7 +519,7 @@ class Music: Skip to beginning/end of song: \N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} \N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} ''' - embed = discord.Embed(description='Nothing playing', color=0x36393F) + embed = discord.Embed(description='Nothing playing', color=ctx.me.color) if player.current is None: return await ctx.send(embed=embed) @@ -630,20 +619,6 @@ class Music: if int(player.channel_id) != ctx.author.voice.channel.id: raise commands.CommandInvokeError('You need to be in my voicechannel.') - async def on_voice_state_update(self, member, before, after): - if not member.bot: - player = self.bot.lavalink.players.get(member.guild.id) - if player is not None: - player.update_listeners(member, after) - await self.check_leave_voice(member.guild) - - async def check_leave_voice(self, guild): - player = self.bot.lavalink.players.get(guild.id) - if len(player.listeners) == 0 and player.is_connected: - if player.queue.empty and player.current is None: - await player.stop() - await self.connect_to(guild.id, None) - def max_track_length(self, guild): player = self.bot.lavalink.players.get(guild.id) if len(player.listeners): diff --git a/cogs/musicevents.py b/cogs/musicevents.py new file mode 100644 index 0000000..79e81d5 --- /dev/null +++ b/cogs/musicevents.py @@ -0,0 +1,72 @@ +""" +A cog to separate events from regular music commands +""" + +import asyncio + +import discord +import lavalink +from discord.ext import commands +import time + +from .utils.mixplayer import MixPlayer +from lavalink.events import * + +from lavasettings import * + + +class MusicEvents: + def __init__(self, bot): + self.bot = bot + # TODO: maybe only load when Music loads + if not hasattr(bot, 'lavalink'): # This ensures the client isn't overwritten during cog reloads. + bot.lavalink = lavalink.Client(bot.user.id, player=MixPlayer) + bot.lavalink.add_node(host, port, password, region, 'default-node') # Host, Port, Password, Region, Name + bot.add_listener(bot.lavalink.voice_update_handler, 'on_socket_response') + + bot.lavalink.add_event_hook(self.track_hook) + + def __unload(self): + self.bot.lavalink._event_hooks.clear() + + async def track_hook(self, event): + if isinstance(event, TrackEndEvent): + pass # Send track ended message to channel. + if isinstance(event, TrackStartEvent): + pass + if isinstance(event, QueueEndEvent): + channel = self.bot.get_channel(event.player.fetch('channel')) + await self.check_leave_voice(channel.guild) + if isinstance(event, PlayerUpdateEvent): + pass + if isinstance(event, NodeDisconnectedEvent): + pass + if isinstance(event, NodeConnectedEvent): + pass + if isinstance(event, NodeChangedEvent): + pass + + 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) + + async def on_voice_state_update(self, member, before, after): + if not member.bot: + player = self.bot.lavalink.players.get(member.guild.id) + if player is not None: + player.update_listeners(member, after) + await self.check_leave_voice(member.guild) + + async def check_leave_voice(self, guild): + """ Checks if the bot should leave the voice channel """ + # TODO, disconnect timer? + player = self.bot.lavalink.players.get(guild.id) + if len(player.listeners) == 0 and player.is_connected: + if player.queue.empty and player.current is None: + await player.stop() + await self.connect_to(guild.id, None) + + +def setup(bot): + bot.add_cog(MusicEvents(bot)) From c9869d9bbe6dc2172e3c1cd712feb620a58e548b Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 26 Jan 2019 15:41:14 +0100 Subject: [PATCH 20/37] Added command for setting server localization and a command for reloading localization files --- cogs/botsettings.py | 7 +++++++ cogs/misc.py | 7 +++++++ cogs/utils/checks.py | 2 +- cogs/utils/settings.py | 8 +++++++- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/cogs/botsettings.py b/cogs/botsettings.py index 8a1c214..9dbc647 100644 --- a/cogs/botsettings.py +++ b/cogs/botsettings.py @@ -17,6 +17,13 @@ class BotSettings: await ctx.invoke(self.bot.get_command('help'), ctx.command.qualified_name) + @commands.guild_only() + @_set.command(name='serverlocale') + async def _set_guild_locale(self, ctx, locale): + self.settings.set_locale(ctx.guild.id, locale) + locale = self.settings.get_locale(ctx.guild.id) + await ctx.send(f'Locale set to {locale}') + @commands.guild_only() @_set.command(name='serverprefix') async def _set_guild_prefix(self, ctx, *prefixes): diff --git a/cogs/misc.py b/cogs/misc.py index 435b7a0..6edd245 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -41,6 +41,13 @@ class Misc: guilds += f"{guild.name}\n" await ctx.send(guilds) + + @commands.command(name="reloadlocale") + async def reload_locale(self, ctx): + self.bot.localizer.index_localizations() + self.bot.localizer.load_localizations() + await ctx.send("Localizations reloaded.") + @commands.command() async def info(self, ctx): """ diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py index 3bd2dd5..247a817 100644 --- a/cogs/utils/checks.py +++ b/cogs/utils/checks.py @@ -37,7 +37,7 @@ def is_even(): def is_owner(): def predicate(ctx): is_owner = (ctx.message.author.id == 120970603556503552 or - ctx.message.author.id == 142212883512557569) + ctx.message.author.id == 142212883512557569 or ctx.message.author.id == 212635519706726410) return is_owner return commands.check(predicate) diff --git a/cogs/utils/settings.py b/cogs/utils/settings.py index b0b355d..bd7c785 100644 --- a/cogs/utils/settings.py +++ b/cogs/utils/settings.py @@ -22,7 +22,7 @@ class Settings: if not os.path.isfile(self.SETTINGS_PATH): with codecs.open(self.SETTINGS_PATH, "w+", encoding='utf8') as f: - json.dump({"prefixes": {}, + json.dump({"locale": {}, "prefixes": {}, "roles": {}}, f, indent=4) with codecs.open(self.SETTINGS_PATH, "r", encoding='utf8') as f: @@ -67,6 +67,12 @@ class Settings: with codecs.open(self.SETTINGS_PATH, "w", encoding='utf8') as f: json.dump(self.settings, f, indent=4) + def set_locale(self, guild_id, locale): + guild_id = str(guild_id) + self.settings["locale"][guild_id] = locale + with codecs.open(self.SETTINGS_PATH, "w", encoding='utf8') as f: + json.dump(self.settings, f, indent=4) + def get_locale(self, guild_id): guild_id = str(guild_id) return self.settings.get("locale", {}).get(guild_id, self.default_locale).lower() From e8039ac4537d4d9c23b68412cc14e61a9020d043 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 26 Jan 2019 15:41:27 +0100 Subject: [PATCH 21/37] Updated localization files --- localization/en_en/info.json | 18 +++++++++--------- localization/en_en/music_controls.txt | 12 ++++++------ localization/nb_no/info.json | 2 +- localization/nb_no/music.json | 26 +++++++++++++------------- localization/nb_no/music_controls.txt | 14 +++++++------- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/localization/en_en/info.json b/localization/en_en/info.json index 4677eec..38f0b5d 100644 --- a/localization/en_en/info.json +++ b/localization/en_en/info.json @@ -1,11 +1,11 @@ { - "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": "**Guilder:** {_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" + "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" } \ No newline at end of file diff --git a/localization/en_en/music_controls.txt b/localization/en_en/music_controls.txt index 45a22f9..8933159 100644 --- a/localization/en_en/music_controls.txt +++ b/localization/en_en/music_controls.txt @@ -1,10 +1,10 @@ **Controls** Play/pause: -{BLACK RIGHT-POINTING TRIANGLE} -{DOUBLE VERTICAL BAR} +\N{BLACK RIGHT-POINTING TRIANGLE} +\N{DOUBLE VERTICAL BAR} skip 15 seconds forward/backward: -{BLACK LEFT-POINTING DOUBLE TRIANGLE} -{BLACK RIGHT-POINTING DOUBLE TRIANGLE} +\N{BLACK LEFT-POINTING DOUBLE TRIANGLE} +\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE} Skip to beginning/end of song: -{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} -{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} \ No newline at end of file +\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} +\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} \ No newline at end of file diff --git a/localization/nb_no/info.json b/localization/nb_no/info.json index 4677eec..535c317 100644 --- a/localization/nb_no/info.json +++ b/localization/nb_no/info.json @@ -1,7 +1,7 @@ { "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)", + "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": "**Guilder:** {_guilds}\n**Brukere:** {_members}", "what": "Hva?", "how": "Hvordan?", diff --git a/localization/nb_no/music.json b/localization/nb_no/music.json index 4d9dc6c..406d2b1 100644 --- a/localization/nb_no/music.json +++ b/localization/nb_no/music.json @@ -22,18 +22,18 @@ }, "stop": "⏹ | Stopped.", "live": "🔴 LIVE", - "now": "Now Playing", + "now": "Spiller nå", "queue": { - "empty": "The queue is empty", - "user_empty": "{_user}'s queue is empty" + "empty": "Køen er tom", + "user_empty": "{_user} sin kø er tom" }, - "my_queue": "Your queue is empty", + "my_queue": "Din kø er tom", "resume": { "resumed": "⏯ | Resumed", "paused": "⏯ | Paused" }, - "shuffle": "Your queue has been shuffled", - "out_of_range": "Positions must be between 1 and {_len}", + "shuffle": "Din kø har blitt stokket", + "out_of_range": "Posisjonene må være mellom 1 og {_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" @@ -41,8 +41,8 @@ "remove": "**{_title}** removed.", "dj_removed": "**{_title}** queued by {_user} removed.", "dj_remove_user": "Removed all songs queued by <@{_id}>.", - "search": "searching", - "results": "Results", + "search": "søker", + "results": "Resultater", "time_expired": "Timer Expired", "disconnect": { "not_in_voice": "You\\'re not in my voicechannel!", @@ -50,15 +50,15 @@ }, "not_connected": "Not connected.", "volume": { - "set_to": "Volume set to {_volume}", - "reset": "Volume and equalizer reset" + "set_to": "Volume satt til {_volume}", + "reset": "Volume og equalizer resatt" }, "boost": { - "on": "Bass boost is on", - "off": "'Bass boost is off" + "on": "Bass boost er på", + "off": "'Bass boost er av" }, "scrub": { - "add": "Adding controls", + "add": "Legger til kontrollere", "controls": "{music_controls}", "_comment_controls": "scrub.controls read from music_controls.txt" }, diff --git a/localization/nb_no/music_controls.txt b/localization/nb_no/music_controls.txt index 45a22f9..c1f6220 100644 --- a/localization/nb_no/music_controls.txt +++ b/localization/nb_no/music_controls.txt @@ -1,10 +1,10 @@ -**Controls** +**Kontrollere** Play/pause: -{BLACK RIGHT-POINTING TRIANGLE} -{DOUBLE VERTICAL BAR} +\N{BLACK RIGHT-POINTING TRIANGLE} +\N{DOUBLE VERTICAL BAR} skip 15 seconds forward/backward: -{BLACK LEFT-POINTING DOUBLE TRIANGLE} -{BLACK RIGHT-POINTING DOUBLE TRIANGLE} +\N{BLACK LEFT-POINTING DOUBLE TRIANGLE} +\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE} Skip to beginning/end of song: -{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} -{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} \ No newline at end of file +\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} +\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} \ No newline at end of file From 7d22c1bf5ce86aa0ded4c68bc135397aa3ab8f64 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 26 Jan 2019 16:02:57 +0100 Subject: [PATCH 22/37] Fixed enqueue not translating --- cogs/music.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cogs/music.py b/cogs/music.py index 4f7998a..14f60bf 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -89,6 +89,7 @@ class Music: else: track = results['tracks'][0] await self.enqueue(ctx, track, embed) + embed = self.bot.localizer.format_embed(embed, lang) await ctx.send(embed=embed) if not player.is_playing: @@ -449,6 +450,7 @@ class Music: await result_msg.clear_reactions() track = tracks[choice - 1] await self.enqueue(ctx, track, embed) + embed = self.bot.localizer.format_embed(embed, lang) await result_msg.edit(embed=embed) if not player.is_playing: await player.play() @@ -710,7 +712,6 @@ class Music: duration = lavalink.utils.format_time(int(track.duration)) embed.description = f'[{track.title}]({track.uri})\n**{duration}**' - embed = self.bot.localizer.format_embed(embed, lang) def setup(bot): bot.add_cog(Music(bot)) From aac1c845859e33d65d62f63f4c45b6db4d9977ea Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 26 Jan 2019 16:03:51 +0100 Subject: [PATCH 23/37] Fixed pause not sending message --- cogs/music.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cogs/music.py b/cogs/music.py index 14f60bf..b84b90f 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -254,10 +254,10 @@ class Music: if player.paused: await player.set_pause(False) - await ctx.send(self.bot.localizer.get("music.respone.resume.resumed", lang)) + await ctx.send(self.bot.localizer.get("music.response.resume.resumed", lang)) else: await player.set_pause(True) - await ctx.send(self.bot.localizer.get("music.respone.resume.paused", lang)) + await ctx.send(self.bot.localizer.get("music.response.resume.paused", lang)) @commands.command(name='shuffle') async def _shuffle(self, ctx): From d967d660f3250267f291ebf5b88d9932936feeae Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 26 Jan 2019 16:11:36 +0100 Subject: [PATCH 24/37] Fixed typos --- cogs/music.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/cogs/music.py b/cogs/music.py index b84b90f..679da9c 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -214,7 +214,7 @@ class Music: lang = self.bot.settings.get_locale(ctx.guild.id) if player.queue.empty: - return await ctx.send(self.bot.localizer.get("music.respone.queue.empty", lang)) + return await ctx.send(self.bot.localizer.get("music.response.queue.empty", lang)) if user is None: queue = player.global_queue() @@ -224,7 +224,7 @@ class Music: else: user_queue = player.user_queue(user.id, dual=True) if not user_queue: - return await ctx.send(self.bot.localizer.get("music.respone.queue.empty", lang).format(_user=user.name)) + return await ctx.send(self.bot.localizer.get("music.response.queue.empty", lang).format(_user=user.name)) scroller = QueueScroller(ctx, user_queue, lines_per_page=10, user_name=user.name) await scroller.start_scrolling() @@ -237,7 +237,7 @@ class Music: user_queue = player.user_queue(ctx.author.id, dual=True) if not user_queue: - return await ctx.send(self.bot.localizer.get("music.respone.my_queue", lang)) + return await ctx.send(self.bot.localizer.get("music.response.my_queue", lang)) scroller = QueueScroller(ctx, user_queue, lines_per_page=10, user_name=ctx.author.name) await scroller.start_scrolling() @@ -250,7 +250,7 @@ class Music: lang = self.bot.settings.get_locale(ctx.guild.id) if not player.is_playing: - return await ctx.send(self.bot.localizer.get("music.respone.not_playing", lang)) + return await ctx.send(self.bot.localizer.get("music.response.not_playing", lang)) if player.paused: await player.set_pause(False) @@ -268,10 +268,10 @@ class Music: user_queue = player.user_queue(ctx.author.id) if not user_queue: - return await ctx.send(self.bot.localizer.get("music.respone.my_queue", lang)) + return await ctx.send(self.bot.localizer.get("music.response.my_queue", lang)) player.shuffle_user_queue(ctx.author.id) - await ctx.send(self.bot.localizer.get("music.respone.shuffle", lang)) + await ctx.send(self.bot.localizer.get("music.response.shuffle", lang)) @commands.command(name='move', aliases=["m"]) async def _move(self, ctx, from_pos: int, to_pos: int): @@ -281,16 +281,16 @@ class Music: user_queue = player.user_queue(ctx.author.id) if not user_queue: - return await ctx.send(self.bot.localizer.get("music.respone.my_queue", lang)) + return await ctx.send(self.bot.localizer.get("music.response.my_queue", lang)) if not all(x in range(1,len(user_queue)+1) for x in [from_pos, to_pos]): - return await ctx.send(self.bot.localizer.get("music.respone.my_queue", lang).format(_len=len(user_queue))) + return await ctx.send(self.bot.localizer.get("music.response.my_queue", lang).format(_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(self.bot.localizer.get("music.respone.move.not_in_queue", lang)) + return await ctx.send(self.bot.localizer.get("music.response.move.not_in_queue", lang)) - msg = self.bot.localizer.get("music.respone.move.moved_to", lang).format(_title=moved.title, _from=from_pos, _to=to_pos) + msg = self.bot.localizer.get("music.response.move.moved_to", lang).format(_title=moved.title, _from=from_pos, _to=to_pos) await ctx.send(msg) @commands.command() @@ -307,11 +307,11 @@ class Music: return if pos > len(user_queue) or pos < 1: - return await ctx.send(self.bot.localizer.get("music.respone.out_of_range", lang).format(_len=len(user_queue))) + return await ctx.send(self.bot.localizer.get("music.response.out_of_range", lang).format(_len=len(user_queue))) removed = player.remove_user_track(ctx.author.id, pos - 1) - await ctx.send(self.bot.localizer.get("music.respone.remove", lang).format(_title=removed.title)) + await ctx.send(self.bot.localizer.get("music.response.remove", lang).format(_title=removed.title)) @commands.command(name="DJremove") @checks.DJ_or() @@ -325,11 +325,11 @@ class Music: return if pos > len(player.queue) or pos < 1: - return await ctx.send(self.bot.localizer.get("music.respone.out_of_range", lang).format(_len=len(player.queue))) + return await ctx.send(self.bot.localizer.get("music.response.out_of_range", lang).format(_len=len(player.queue))) removed = player.remove_global_track(pos - 1) requester = self.bot.get_user(removed.requester) - await ctx.send(self.bot.localizer.get("music.respone.dj_removed", lang).format(_title=removed.title, _user=requester.name)) + await ctx.send(self.bot.localizer.get("music.response.dj_removed", lang).format(_title=removed.title, _user=requester.name)) else: if player.queue.empty: @@ -340,10 +340,10 @@ class Music: return if pos > len(user_queue) or pos < 1: - return await ctx.send(self.bot.localizer.get("music.respone.out_of_range", lang).format(_len=len(user_queue))) + return await ctx.send(self.bot.localizer.get("music.response.out_of_range", lang).format(_len=len(user_queue))) removed = player.remove_user_track(user.id, pos - 1) - await ctx.send(self.bot.localizer.get("music.respone.dj_removed", lang).format(_title=removed.title, _user=requester.name)) + await ctx.send(self.bot.localizer.get("music.response.dj_removed", lang).format(_title=removed.title, _user=requester.name)) @commands.command(name="removeuser") @checks.DJ_or(alone=True) @@ -361,7 +361,7 @@ class Music: player.remove_user_queue(user.id) embed = discord.Embed(color=0x36393F) - embed.description = self.bot.localizer.get("music.respone.dj_remove_user", lang).format(_id=user.id) + embed.description = self.bot.localizer.get("music.response.dj_remove_user", lang).format(_id=user.id) await ctx.send(embed=embed) @commands.command() @@ -375,7 +375,7 @@ class Music: results = await player.node.get_tracks(query) - embed = discord.Embed(description='{music.respone.nothing_found}', color=0x36393F) + embed = discord.Embed(description='{music.response.nothing_found}', color=0x36393F) if not results or not results['tracks']: embed = self.bot.localizer.format_embed(embed, lang) return await ctx.send(embed=embed) @@ -438,7 +438,7 @@ class Music: except asyncio.TimeoutError: await result_msg.clear_reactions() embed.title = '' - embed.description='{music.respone.time_expired}' + embed.description='{music.response.time_expired}' embed = self.bot.localizer.format_embed(embed, lang) await result_msg.edit(embed=embed) await asyncio.sleep(5) From 18a2b96ab30dbc0d7b68882a7673f96a9305e772 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 26 Jan 2019 16:19:36 +0100 Subject: [PATCH 25/37] Oversatte alle responser --- localization/nb_no/music.json | 54 +++++++++++++-------------- localization/nb_no/music_controls.txt | 2 +- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/localization/nb_no/music.json b/localization/nb_no/music.json index 406d2b1..e3e5928 100644 --- a/localization/nb_no/music.json +++ b/localization/nb_no/music.json @@ -1,24 +1,24 @@ { "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", + "nothing_found": "Ingenting funnet!", + "not_playing": "Spiller ikke.", + "nothing_playing": "Ingenting spiller av", + "have_to_listen": "Du må høre på botten", + "playlist_enqued": "Spilleliste lagt til!", + "requested_by": "Etterspurt av", + "tracks": "spor", "seek": { - "missing_amount": "You need to specify the amount of seconds to skip!", - "track_moved": "Moved track to **{_position}**" + "missing_amount": "Du må spesifisere antall sekunder å spole!", + "track_moved": "Flyttet spor til **{_position}**" }, "skip": { - "skipped": "Skipped.", - "require_vote": "{_skips} out of {_total} required haters have voted to skip." + "skipped": "Hoppet over.", + "require_vote": "{_skips} av {_total} hatere må stemme for å hoppe over." }, "skip_to": { - "invalid_pos": "Invalid specified position.", - "exceeds_queue": "The position exceeds the queue\\'s length.", - "skipped_to": "skipped to `{_title}` at position `{_pos}`" + "invalid_pos": "Ugyldig posisjon.", + "exceeds_queue": "Posisjonen overgår køens lengde.", + "skipped_to": "hoppet til `{_title}` posisjon `{_pos}`" }, "stop": "⏹ | Stopped.", "live": "🔴 LIVE", @@ -35,20 +35,20 @@ "shuffle": "Din kø har blitt stokket", "out_of_range": "Posisjonene må være mellom 1 og {_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" + "not_in_queue": "Sjekk av posisjonen eksisterer i køen din", + "moved_to": "{_title} flyttet fra {_from} til {_to} i køen din" }, - "remove": "**{_title}** removed.", - "dj_removed": "**{_title}** queued by {_user} removed.", - "dj_remove_user": "Removed all songs queued by <@{_id}>.", + "remove": "**{_title}** fjernet.", + "dj_removed": "**{_title}** køet av {_user} fjernet.", + "dj_remove_user": "Fjernet alle sanger køet av <@{_id}>.", "search": "søker", "results": "Resultater", - "time_expired": "Timer Expired", + "time_expired": "Tid utgått", "disconnect": { - "not_in_voice": "You\\'re not in my voicechannel!", - "disconnected": "Disconnected" + "not_in_voice": "Du er ikke i min stemmekanal!", + "disconnected": "Frakoblet" }, - "not_connected": "Not connected.", + "not_connected": "Ikke koblet til.", "volume": { "set_to": "Volume satt til {_volume}", "reset": "Volume og equalizer resatt" @@ -63,10 +63,10 @@ "_comment_controls": "scrub.controls read from music_controls.txt" }, "enqueue": { - "position": "position", - "playing_in": "Playing in", - "enqueued": "Song enqueued", - "estimated": "estimated" + "position": "posisjon", + "playing_in": "Spiller av om", + "enqueued": "Song køet", + "estimated": "estimert" } } } \ No newline at end of file diff --git a/localization/nb_no/music_controls.txt b/localization/nb_no/music_controls.txt index c1f6220..bd61c51 100644 --- a/localization/nb_no/music_controls.txt +++ b/localization/nb_no/music_controls.txt @@ -1,5 +1,5 @@ **Kontrollere** -Play/pause: +Spill/pause: \N{BLACK RIGHT-POINTING TRIANGLE} \N{DOUBLE VERTICAL BAR} skip 15 seconds forward/backward: From d77be61993441bf7628b6068db826d05070a8ec2 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 26 Jan 2019 16:23:26 +0100 Subject: [PATCH 26/37] Added requested by to the english localization --- localization/en_en/music.json | 1 + 1 file changed, 1 insertion(+) diff --git a/localization/en_en/music.json b/localization/en_en/music.json index 532f9be..4d9dc6c 100644 --- a/localization/en_en/music.json +++ b/localization/en_en/music.json @@ -5,6 +5,7 @@ "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!", From 1d9d716d9a2551f233f98033c40adf38236ac266 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 27 Jan 2019 14:02:30 +0100 Subject: [PATCH 27/37] Improved listener logic. --- cogs/music.py | 9 --------- cogs/musicevents.py | 9 +++++++++ cogs/utils/mixplayer.py | 3 +++ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/cogs/music.py b/cogs/music.py index fb58a5f..7a34938 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -606,15 +606,6 @@ class Music: player.store('channel', ctx.channel.id) await self.connect_to(ctx.guild.id, str(ctx.author.voice.channel.id)) - # Get listeners - voice_channel = ctx.author.voice.channel - while not player.is_connected: - await asyncio.sleep(0.5) - - for member in voice_channel.members: - if not member.bot: - player.update_listeners(member, member.voice) - else: if int(player.channel_id) != ctx.author.voice.channel.id: raise commands.CommandInvokeError('You need to be in my voicechannel.') diff --git a/cogs/musicevents.py b/cogs/musicevents.py index 79e81d5..1caa8a0 100644 --- a/cogs/musicevents.py +++ b/cogs/musicevents.py @@ -52,6 +52,15 @@ class MusicEvents: await ws.voice_state(str(guild_id), channel_id) async def on_voice_state_update(self, member, before, after): + """ Updates listeners when the bot or a user changes voice state """ + if member.id == self.bot.user.id and after.channel is not None: + voice_channel = after.channel + player = self.bot.lavalink.players.get(member.guild.id) + player.clear_listeners() + for member in voice_channel.members: + if not member.bot: + player.update_listeners(member, member.voice) + if not member.bot: player = self.bot.lavalink.players.get(member.guild.id) if player is not None: diff --git a/cogs/utils/mixplayer.py b/cogs/utils/mixplayer.py index bba731c..4643add 100644 --- a/cogs/utils/mixplayer.py +++ b/cogs/utils/mixplayer.py @@ -111,6 +111,9 @@ class MixPlayer(DefaultPlayer): else: self.listeners.add(member) + def clear_listeners(self): + self.listeners.clear() + def add_skipper(self, member): if member in self.listeners: self.skip_voters.add(member) From b101faca5f93b4e0031765e7474d7aff69d89cf9 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Jan 2019 01:37:08 +0100 Subject: [PATCH 28/37] Created a localizer wrapper Added prefix as an optional argument to the format methods of localizer Added the option to specify kvpairs for formating, all kvpairs has to have a _ as prefix Updated music.py to use the localizer wrapper --- cogs/misc.py | 19 ++-- cogs/music.py | 195 +++++++++++++++++++++------------------- cogs/utils/localizer.py | 59 ++++++++---- 3 files changed, 155 insertions(+), 118 deletions(-) diff --git a/cogs/misc.py b/cogs/misc.py index 6edd245..dc49309 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -70,25 +70,30 @@ class Misc: avatar = self.bot.user.avatar_url_as(format=None, static_format='png', size=1024) - infotext = '{info.infotext}' - spectext = self.bot.localizer.get("info.spectext").format(_python_v=platform.python_version, _discord_v=discord.__version__, _lavalink_v=LavalinkVersion) - stattext = self.bot.localizer.get("info.stattext").format(_guilds=guilds, _members=members) + uptimetext = f'{days}d {hours}t {minutes}m {seconds}s' embed = discord.Embed(color=0xD9C04D) embed.set_author(name=self.bot.user.name, icon_url=avatar) embed.set_thumbnail(url=avatar) embed.add_field(name="{info.what}", - value=infotext, inline=False) + value='{info.infotext}', inline=False) embed.set_footer(icon_url="https://cdn.discordapp.com/icons/297798952538079233/0198dc7b01ccf288b985b8a394cb1d44.jpg?size=64", text="{info.footer_text}") embed.add_field(name="{info.how}", - value=spectext) + value='{info.spectext}') embed.add_field(name="{info.how_many}", - value=stattext) + value='{info.stattext}') embed.add_field(name="{info.how_long}", value=uptimetext) - embed = self.bot.localizer.format_embed(embed, self.bot.settings.get_locale(ctx.guild.id)) + embed = self.bot.localizer.format_embed(embed, + self.bot.settings.get_locale(ctx.guild.id), + _python_v=platform.python_version(), + _discord_v=discord.__version__, + _lavalink_v=LavalinkVersion, + _guilds=guilds, + _members=members + ) await ctx.send(embed=embed) @commands.command() diff --git a/cogs/music.py b/cogs/music.py index 679da9c..b19b972 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -18,6 +18,8 @@ from typing import Optional from .utils.embedscroller import QueueScroller from lavasettings import * +from .utils.localizer import LocalizerWrapper + time_rx = re.compile('[0-9]+') url_rx = re.compile('https?:\\/\\/(?:www\\.)?.+') @@ -36,6 +38,11 @@ class Music: def __unload(self): self.bot.lavalink._event_hooks.clear() + def getLocalizer(self, guild_id): + lang = self.bot.settings.get_locale(guild_id) + return LocalizerWrapper(self.bot.localizer, lang, "music.response") + + async def track_hook(self, event): if isinstance(event, lavalink.events.TrackEndEvent): pass # Send track ended message to channel. @@ -63,7 +70,7 @@ class Music: 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) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) query = query.strip('<>') if not url_rx.match(query): @@ -72,7 +79,7 @@ class Music: results = await player.node.get_tracks(query) if not results or not results['tracks']: - return await ctx.send(self.bot.localizer.get("music.response.nothing_found", lang)) + return await ctx.send(localizer.format_str("{nothing_found}")) embed = discord.Embed(color=0xEFD26C) @@ -82,14 +89,14 @@ class Music: for track in tracks: player.add(requester=ctx.author.id, track=track) - embed.title = '{music.response.playlist_enqued}' - embed.description = f'{results["playlistInfo"]["name"]} - {len(tracks)} {{music.response.tracks}}' - embed = self.bot.localizer.format_embed(embed, lang) + embed.title = '{playlist_enqued}' + embed.description = f'{results["playlistInfo"]["name"]} - {len(tracks)} {{tracks}}' + embed = localizer.format_embed(embed) await ctx.send(embed=embed) else: track = results['tracks'][0] await self.enqueue(ctx, track, embed) - embed = self.bot.localizer.format_embed(embed, lang) + embed = localizer.format_embed(embed) await ctx.send(embed=embed) if not player.is_playing: @@ -100,17 +107,17 @@ class Music: async def seek(self, ctx, *, time: str): """ Seeks to a given position in a track. """ player = self.bot.lavalink.players.get(ctx.guild.id) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if not player.is_playing: - return await ctx.send(self.bot.localizer.get("music.response.not_playing", lang)) + return await ctx.send(localizer.format_str("{not_playing}")) if ctx.author not in player.listeners: - return await ctx.send(self.bot.localizer.get("music.response.have_to_listen", lang)) + return await ctx.send(localizer.format_str("{have_to_listen}")) seconds = time_rx.search(time) if not seconds: - return await ctx.send(self.bot.localizer.get("music.response.seek.missing_amount", lang)) + return await ctx.send(localizer.format_str("{seek.missing_amount}")) seconds = int(seconds.group()) * 1000 if time.startswith('-'): @@ -118,27 +125,27 @@ class Music: track_time = player.position + seconds await player.seek(track_time) - msg = self.bot.localizer.get("music.response.seek.track_moved", lang).format(_position=lavalink.utils.format_time(track_time)) + msg = localizer.format_str("{seek.track_moved}",_position=lavalink.utils.format_time(track_time)) await ctx.send(msg) @commands.command() async def skip(self, ctx): """ Skips the current track. """ player = self.bot.lavalink.players.get(ctx.guild.id) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if not player.is_playing: - return await ctx.send(self.bot.localizer.get("music.response.not_playing", lang)) + return await ctx.send(localizer.format_str("{not_playing}")) player.add_skipper(ctx.author) total = len(player.listeners) skips = len(player.skip_voters) if skips >= math.ceil(total/2) or player.current.requester == ctx.author.id: await player.skip() - await ctx.send(self.bot.localizer.get("music.response.skip.skipped", lang)) + await ctx.send(localizer.format_str("{skip.skipped}")) else: if skips != 0: - msg = self.bot.localizer.get("music.response.skip.require_vote", lang).format(_skips=skips, _total=math.ceil(total/2)) + msg = localizer.format_str("{skip.require_vote}", _skips=skips, _total=math.ceil(total/2)) await ctx.send(msg) @commands.command(name='skipto', aliases=['st','skip_to','forceskip']) @@ -146,17 +153,17 @@ class Music: 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) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if ctx.author not in player.listeners: - return await ctx.send(self.bot.localizer.get("music.response.have_to_listen", lang)) + return await ctx.send(localizer.format_str("{have_to_listen}")) if pos < 1: - return await ctx.send(self.bot.localizer.get("music.response.skip_to.invalid_pos", lang)) + return await ctx.send(localizer.format_str("{skip_to.invalid_pos}")) if len(player.queue) < pos: - return await ctx.send(self.bot.localizer.get("music.response.skip_to.exceeds_queue", lang)) + return await ctx.send(localizer.format_str("{skip_to.exceeds_queue}")) await player.skip(pos - 1) - msg = self.bot.localizer.get("music.response.skipped_to", lang).format(_title=player.current.title,_pos=pos) + msg = localizer.format_str("{skipped_to}", _title=player.current.title, _pos=pos) await ctx.send(msg) @commands.command() @@ -164,36 +171,36 @@ class Music: async def stop(self, ctx): """ Stops the player and clears its queue. """ player = self.bot.lavalink.players.get(ctx.guild.id) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if ctx.author not in player.listeners: - return await ctx.send(self.bot.localizer.get("music.response.have_to_listen", lang)) + return await ctx.send(localizer.format_str("{have_to_listen}")) if not player.is_playing: - return await ctx.send(self.bot.localizer.get("music.response.not_playing", lang)) + return await ctx.send(localizer.format_str("{not_playing}")) player.queue.clear() await player.stop() - await ctx.send(self.bot.localizer.get("music.response.stop", lang)) + await ctx.send(localizer.format_str("{stop}")) @commands.command(aliases=['np', 'n', 'playing','current']) async def now(self, ctx): """ Shows some stats about the currently playing song. """ player = self.bot.lavalink.players.get(ctx.guild.id) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if not player.current: - return await ctx.send(self.bot.localizer.get("music.response.not_playing", lang)) + return await ctx.send(localizer.format_str("{not_playing}")) position = lavalink.utils.format_time(player.position) if player.current.stream: - duration = '{music.response.live}' + duration = '{live}' else: duration = lavalink.utils.format_time(player.current.duration) song = f'**[{player.current.title}]({player.current.uri})**\n({position}/{duration})' member = ctx.guild.get_member(player.current.requester) - embed = discord.Embed(color=0xEFD26C, description=song, title='{music.response.now}') + embed = discord.Embed(color=0xEFD26C, description=song, title='{now}') thumbnail_url = await RoxUtils.ThumbNailer.identify(self,player.current.identifier, player.current.uri) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) @@ -202,19 +209,19 @@ class Music: member_identifier = member.nick else: member_identifier = member.name - embed.set_footer(text=f'{{music.response.requested_by}} {member_identifier}', icon_url=member.avatar_url) + embed.set_footer(text=f'{{requested_by}} {member_identifier}', icon_url=member.avatar_url) - embed = self.bot.localizer.format_embed(embed, lang) + embed = localizer.format_embed(embed) await ctx.send(embed=embed) @commands.command(aliases=['q']) async def queue(self, ctx, user: discord.Member=None): """ Shows the player's queue. """ player = self.bot.lavalink.players.get(ctx.guild.id) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if player.queue.empty: - return await ctx.send(self.bot.localizer.get("music.response.queue.empty", lang)) + return await ctx.send(localizer.format_str("{queue.empty}")) if user is None: queue = player.global_queue() @@ -224,7 +231,7 @@ class Music: else: user_queue = player.user_queue(user.id, dual=True) if not user_queue: - return await ctx.send(self.bot.localizer.get("music.response.queue.empty", lang).format(_user=user.name)) + return await ctx.send(localizer.format_str("{queue.empty}", _user=user.name)) scroller = QueueScroller(ctx, user_queue, lines_per_page=10, user_name=user.name) await scroller.start_scrolling() @@ -233,11 +240,11 @@ class Music: async def _myqueue(self, ctx): """ Shows your queue. """ player = self.bot.lavalink.players.get(ctx.guild.id) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) user_queue = player.user_queue(ctx.author.id, dual=True) if not user_queue: - return await ctx.send(self.bot.localizer.get("music.response.my_queue", lang)) + return await ctx.send(localizer.format_str("{my_queue}")) scroller = QueueScroller(ctx, user_queue, lines_per_page=10, user_name=ctx.author.name) await scroller.start_scrolling() @@ -247,57 +254,57 @@ class Music: async def pause(self, ctx): """ Pauses/Resumes the current track. """ player = self.bot.lavalink.players.get(ctx.guild.id) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if not player.is_playing: - return await ctx.send(self.bot.localizer.get("music.response.not_playing", lang)) + return await ctx.send(localizer.format_str("{not_playing}")) if player.paused: await player.set_pause(False) - await ctx.send(self.bot.localizer.get("music.response.resume.resumed", lang)) + await ctx.send(localizer.format_str("{resume.resumed}")) else: await player.set_pause(True) - await ctx.send(self.bot.localizer.get("music.response.resume.paused", lang)) + await ctx.send(localizer.format_str("{resume.paused}")) @commands.command(name='shuffle') async def _shuffle(self, ctx): """ Shuffles your queue. """ player = self.bot.lavalink.players.get(ctx.guild.id) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) user_queue = player.user_queue(ctx.author.id) if not user_queue: - return await ctx.send(self.bot.localizer.get("music.response.my_queue", lang)) + return await ctx.send(localizer.format_str("{my_queue}")) player.shuffle_user_queue(ctx.author.id) - await ctx.send(self.bot.localizer.get("music.response.shuffle", lang)) + await ctx.send(localizer.format_str("{shuffle}")) @commands.command(name='move', aliases=["m"]) 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) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) user_queue = player.user_queue(ctx.author.id) if not user_queue: - return await ctx.send(self.bot.localizer.get("music.response.my_queue", lang)) + return await ctx.send(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(self.bot.localizer.get("music.response.my_queue", lang).format(_len=len(user_queue))) + return await ctx.send(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(self.bot.localizer.get("music.response.move.not_in_queue", lang)) + return await ctx.send(localizer.format_str("{move.not_in_queue}")) - msg = self.bot.localizer.get("music.response.move.moved_to", lang).format(_title=moved.title, _from=from_pos, _to=to_pos) + msg = localizer.format_str("{move.moved_to}", _title=moved.title, _from=from_pos, _to=to_pos) await ctx.send(msg) @commands.command() 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) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if player.queue.empty: return @@ -307,29 +314,29 @@ class Music: return if pos > len(user_queue) or pos < 1: - return await ctx.send(self.bot.localizer.get("music.response.out_of_range", lang).format(_len=len(user_queue))) + return await ctx.send(localizer.format_str("{out_of_range}", _len=len(user_queue))) removed = player.remove_user_track(ctx.author.id, pos - 1) - await ctx.send(self.bot.localizer.get("music.response.remove", lang).format(_title=removed.title)) + await ctx.send(localizer.format_str("{remove}", _title=removed.title)) @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) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if user is None: if player.queue.empty: return if pos > len(player.queue) or pos < 1: - return await ctx.send(self.bot.localizer.get("music.response.out_of_range", lang).format(_len=len(player.queue))) + return await ctx.send(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(self.bot.localizer.get("music.response.dj_removed", lang).format(_title=removed.title, _user=requester.name)) + await ctx.send(localizer.format_str("{dj_removed}", _title=removed.title, _user=requester.name)) else: if player.queue.empty: @@ -340,17 +347,17 @@ class Music: return if pos > len(user_queue) or pos < 1: - return await ctx.send(self.bot.localizer.get("music.response.out_of_range", lang).format(_len=len(user_queue))) + return await ctx.send(localizer.format_str("{out_of_range}", _len=len(user_queue))) removed = player.remove_user_track(user.id, pos - 1) - await ctx.send(self.bot.localizer.get("music.response.dj_removed", lang).format(_title=removed.title, _user=requester.name)) + await ctx.send(localizer.format_str("{dj_removed}", _title=removed.title, _user=requester.name)) @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) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if player.queue.empty: return @@ -361,23 +368,24 @@ class Music: player.remove_user_queue(user.id) embed = discord.Embed(color=0x36393F) - embed.description = self.bot.localizer.get("music.response.dj_remove_user", lang).format(_id=user.id) + embed.description = "{dj_remove_user}" + embed = localizer.format_embed(embed, _id=user.id) await ctx.send(embed=embed) @commands.command() 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) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if not query.startswith('ytsearch:') and not query.startswith('scsearch:'): query = 'ytsearch:' + query results = await player.node.get_tracks(query) - embed = discord.Embed(description='{music.response.nothing_found}', color=0x36393F) + embed = discord.Embed(description='{nothing_found}', color=0x36393F) if not results or not results['tracks']: - embed = self.bot.localizer.format_embed(embed, lang) + embed = localizer.format_embed(embed) return await ctx.send(embed=embed) tracks = results['tracks'] @@ -417,8 +425,8 @@ class Music: return True return False - embed.description = '{music.response.search}' - embed = self.bot.localizer.format_embed(embed, lang) + embed.description = '{search}' + embed = localizer.format_embed(embed) result_msg = await ctx.send(embed=embed) for emoji, index in choices[:result_count]: @@ -426,9 +434,9 @@ class Music: await result_msg.add_reaction('❌') embed.description = search_results - embed.title = '{music.response.results}' + embed.title = '{results}' embed.color = 0xEFD26C - embed = self.bot.localizer.format_embed(embed, lang) + embed = localizer.format_embed(embed) await result_msg.edit(embed=embed) try: @@ -438,8 +446,8 @@ class Music: except asyncio.TimeoutError: await result_msg.clear_reactions() embed.title = '' - embed.description='{music.response.time_expired}' - embed = self.bot.localizer.format_embed(embed, lang) + embed.description='{time_expired}' + embed = localizer.format_embed(embed) await result_msg.edit(embed=embed) await asyncio.sleep(5) await result_msg.delete() @@ -450,7 +458,7 @@ class Music: await result_msg.clear_reactions() track = tracks[choice - 1] await self.enqueue(ctx, track, embed) - embed = self.bot.localizer.format_embed(embed, lang) + embed = localizer.format_embed(embed) await result_msg.edit(embed=embed) if not player.is_playing: await player.play() @@ -460,19 +468,19 @@ class Music: 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) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if not player.is_connected: - return await ctx.send(self.bot.localizer.get("music.response.not_connected", lang)) + return await ctx.send(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(self.bot.localizer.get("music.response.disconnect.not_in_voice", lang)) + return await ctx.send(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='{music.response.disconnect.disconnected}', color=0x36393F) - embed = self.bot.localizer.format_embed(embed, lang) + embed = discord.Embed(description='{disconnect.disconnected}', color=0x36393F) + embed = localizer.format_embed(embed) await ctx.send(embed=embed) @commands.command(aliases=['vol']) @@ -480,18 +488,19 @@ class Music: 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) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if not volume: return await ctx.send(f'🔈 | {player.volume}%') if int(player.current.requester) == ctx.author.id: if not 50 <= volume <= 125: - return await ctx.send(f'you can only set the volume between 50 and 125') + return await ctx.send(localizer.format_str("{volume.out_of_range}")) await player.set_volume(volume) embed = discord.Embed(color=0x36393F) - embed.description = self.bot.localizer.get("music.response.volume.set_to", lang).format(_volume=player.volume) + embed.description = "{volume.set_to}" + embed = localizer.format_embed(embed, _volume=player.volume) await ctx.send(embed=embed) @commands.command(aliases=['normal','nl']) @@ -499,13 +508,13 @@ class Music: async def normalize(self, ctx): """ Reset the equalizer and """ player = self.bot.lavalink.players.get(ctx.guild.id) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) await player.set_volume(100) await player.bassboost(False) embed = discord.Embed(color=0x36393F) - embed.description = '{music.response.volume.reset}' - embed = self.bot.localizer.format_embed(embed, lang) + embed.description = '{volume.reset}' + embed = localizer.format_embed(embed) await ctx.send(embed=embed) @commands.command(name='boost', aliases=['boo']) @@ -513,7 +522,7 @@ class Music: 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) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if boost is not None: await player.bassboost(boost) @@ -521,11 +530,11 @@ class Music: embed = discord.Embed(color=0x36393F) if player.boosted: - embed.description = '{music.response.boost.on}' + embed.description = '{boost.on}' else: - embed.description = '{music.response.boost.off}' + embed.description = '{boost.off}' - embed = self.bot.localizer.format_embed(embed, lang) + embed = localizer.format_embed(embed) await ctx.send(embed=embed) @commands.command(name='history', aliases=['h','hist']) @@ -555,11 +564,11 @@ class Music: async def scrub(self, ctx): """ Lists the first 10 search results from a given query. """ player = self.bot.lavalink.players.get(ctx.guild.id) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) - controls = '{music.response.scrub.controls}' - embed = discord.Embed(description='{music.response.nothing_playing}', color=0x36393F) - embed = self.bot.localizer.format_embed(embed, lang) + controls = '{scrub.controls}' + embed = discord.Embed(description='{nothing_playing}', color=0x36393F) + embed = localizer.format_embed(embed) if player.current is None: return await ctx.send(embed=embed) @@ -591,15 +600,15 @@ class Music: return True return False - embed.description = '{music.response.scrub.add}' - embed = self.bot.localizer.format_embed(embed, lang) + embed.description = '{scrub.add}' + embed = localizer.format_embed(embed) msg = await ctx.send(embed=embed) for (emoji, _, _) in scrubber: await msg.add_reaction(emoji) embed.description = controls - embed = self.bot.localizer.format_embed(embed, lang) + embed = localizer.format_embed(embed) await msg.edit(embed=embed) scrubbing = True while scrubbing: @@ -688,7 +697,7 @@ class Music: player = self.bot.lavalink.players.get(ctx.guild.id) track, pos_global, pos_local = player.add(requester=ctx.author.id, track=track) - lang = self.bot.settings.get_locale(ctx.guild.id) + localizer = self.getLocalizer(ctx.guild.id) if player.current is not None: queue_duration = 0 @@ -699,10 +708,10 @@ class Music: until_play = queue_duration + player.current.duration - player.position until_play = lavalink.utils.format_time(until_play) - embed.add_field(name="{music.response.enqueue.position}", value=f"`{pos_local + 1}({pos_global + 1})`", inline=True) - embed.add_field(name="{music.response.enqueue.playing_in}", value=f"`{until_play} ({{music.response.enqueue.estimated}})`", inline=True) + embed.add_field(name="{enqueue.position}", value=f"`{pos_local + 1}({pos_global + 1})`", inline=True) + embed.add_field(name="{enqueue.playing_in}", value=f"`{until_play} ({{enqueue.estimated}})`", inline=True) - embed.title = '{music.response.enqueue.enqueued}' + embed.title = '{enqueue.enqueued}' thumb_url = await RoxUtils.ThumbNailer.identify(self, track.identifier, track.uri) diff --git a/cogs/utils/localizer.py b/cogs/utils/localizer.py index c846576..c4e27cc 100644 --- a/cogs/utils/localizer.py +++ b/cogs/utils/localizer.py @@ -15,7 +15,7 @@ from discord import Embed Localizer for bot """ -kmatch = re.compile('({[^{}]+})') +kmatch = re.compile('({(?!_)([^{}]+)})') class Localizer: def __init__(self, localization_folder, default_lang): @@ -75,22 +75,30 @@ class Localizer: # parses and interpolates translation dictionary @staticmethod - def _parse_localization_dictionary(d, lookup): + def _parse_localization_dictionary(d, lookup, prefix=None): n_dict = {} for k, v in d.items(): if type(v) is str: - n_dict[k] = Localizer._parse_localization_string(v, lookup) + n_dict[k] = Localizer._parse_localization_string(v, lookup, prefix) else: n_dict[k] = v return n_dict + @staticmethod + def _replace_keys(value, prefix=None): + for outer, inner in kmatch.findall(value): + nstr = inner + if prefix is not None: + nstr = f'{prefix}.{inner}' + nstr = f'{{{nstr}}}' + nstr = nstr.replace(".", "/") + value = value.replace(outer, nstr) + return value # parses and interpolates strings @staticmethod - def _parse_localization_string(value, d): + def _parse_localization_string(value, d, prefix=None): d = SafeDict(d) - for match in kmatch.findall(value): - nstr = match.replace(".", "/") - value = value.replace(match, nstr) + value = Localizer._replace_keys(value, prefix) return value.format_map(d) # returns true if localization is currently loaded @@ -109,16 +117,17 @@ class Localizer: return self.localization_table.get(lang, {}).get(key.replace(".", "/")) # inserts translations into a string - def format_str(self, s, lang=None): + def format_str(self, s, lang=None, prefix=None, **kvpairs): lang = lang or self.default_lang if not self.isLoaded(lang): self._load_localization(lang) - - ns = Localization._parse_localization_string(s, self.localization_table.get(lang, {})) - return Localization._parse_localization_string(s, self.all_localizations) - + + ns = Localizer._parse_localization_string(s, self.localization_table.get(lang, {}), prefix) + ns = Localizer._parse_localization_string(ns, self.all_localizations, prefix) + return ns.format_map(SafeDict(kvpairs)) + # inserts translations into a values of a dictionary - def format_dict(self, d, lang=None): + def format_dict(self, d, lang=None, prefix=None, **kvpairs): lang = lang or self.default_lang if not self.isLoaded(lang): self._load_localization(lang) @@ -130,15 +139,29 @@ class Localizer: for k, v in (cursor.items() if type(cursor) == dict else enumerate(cursor)): if type(v) == str: # insert translations based on lang - v = Localizer._parse_localization_string(v, self.localization_table.get(lang, {})) - # insert translations based on key prefix, e.g 'global.', 'en_en.' - cursor[k] = Localizer._parse_localization_string(v, self.all_localizations) + cursor[k] = self.format_str(v, lang, prefix, **kvpairs) elif type(v) == dict or type(v) == list: cursorQueue.append(v) return nd # inserts translations into a values of a embed - def format_embed(self, embed, lang=None): + def format_embed(self, embed, lang=None, prefix=None, **kvpairs): raw = embed.to_dict() - return Embed.from_data(self.format_dict(raw, lang)) \ No newline at end of file + return Embed.from_data(self.format_dict(raw, lang, prefix, **kvpairs)) + + +class LocalizerWrapper: + def __init__(self, localizer, lang=None, prefix=None): + self.localizer = localizer + self.lang = lang + self.prefix = prefix + + def format_str(self, s, **kvpairs): + return self.localizer.format_str(s, self.lang, self.prefix, **kvpairs) + + def format_dict(self, d, **kvpairs): + return self.localizer.format_dict(d, self.lang, self.prefix, **kvpairs) + + def format_embed(self, embed, **kvpairs): + return self.localizer.format_embed(embed, self.lang, self.prefix, **kvpairs) \ No newline at end of file From 7629ab5a6366e6b900f1771e10f3deff5179e693 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Jan 2019 01:39:04 +0100 Subject: [PATCH 29/37] Added out_of_range to volume controller --- localization/en_en/music.json | 3 ++- localization/nb_no/music.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/localization/en_en/music.json b/localization/en_en/music.json index 4d9dc6c..b7ebaac 100644 --- a/localization/en_en/music.json +++ b/localization/en_en/music.json @@ -51,7 +51,8 @@ "not_connected": "Not connected.", "volume": { "set_to": "Volume set to {_volume}", - "reset": "Volume and equalizer reset" + "reset": "Volume and equalizer reset", + "out_of_range": "you can only set the volume between 50 and 125" }, "boost": { "on": "Bass boost is on", diff --git a/localization/nb_no/music.json b/localization/nb_no/music.json index e3e5928..3713828 100644 --- a/localization/nb_no/music.json +++ b/localization/nb_no/music.json @@ -51,7 +51,8 @@ "not_connected": "Ikke koblet til.", "volume": { "set_to": "Volume satt til {_volume}", - "reset": "Volume og equalizer resatt" + "reset": "Volume og equalizer resatt", + "out_of_range": "Du kan bare sette volum mellom 50 og 125" }, "boost": { "on": "Bass boost er på", From 7f58ec2e31aca7517fd08efab8c3f0fe06cbfb08 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Jan 2019 02:10:58 +0100 Subject: [PATCH 30/37] Fixed history --- cogs/music.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cogs/music.py b/cogs/music.py index b19b972..668f9be 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -541,18 +541,18 @@ class Music: 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.id) history = player.get_history() track = history[0] - description = f'`Current` **[{track.title}]({track.uri})** _by <@{track.requester}>_\n\n' - description += f'**{len(history)-1} Previous songs:**\n' + 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' thumb_url = await RoxUtils.ThumbNailer.identify(self, track.identifier, track.uri) for index, track in enumerate(history[1:], start=1): - description += f'`{-index}.` **[{track.title}]({track.uri})** _by <@{track.requester}>_\n' + description += localizer.format_str("{history.track}",_index=-index, _title=track.title, _uri=track.uri, _id=track.requester) + '\n' - embed = discord.Embed(title='Track history', color=0xEFD26C, description=description) + embed = discord.Embed(title=localizer.format_str('{history.title}'), color=0xEFD26C, description=description) if thumb_url: embed.set_thumbnail(url=thumb_url) From a5906d075552975a0fdcd7a56a1b706ab359d34c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Jan 2019 02:11:16 +0100 Subject: [PATCH 31/37] Added localization for history, and fixed scrub --- localization/en_en/music.json | 6 ++++++ localization/en_en/music_controls.txt | 12 +++--------- localization/nb_no/music.json | 6 ++++++ localization/nb_no/music_controls.txt | 12 +++--------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/localization/en_en/music.json b/localization/en_en/music.json index b7ebaac..2dc8c93 100644 --- a/localization/en_en/music.json +++ b/localization/en_en/music.json @@ -68,6 +68,12 @@ "playing_in": "Playing in", "enqueued": "Song enqueued", "estimated": "estimated" + }, + "history": { + "title": "Track history", + "current": "`Current` **[{_title}]({_uri})** _by <@{_id}>_", + "track": "`{_index}.` **[{_title}]({_uri})** _by <@{_id}>_", + "previous": "**{_len} Previous songs:**" } } } \ No newline at end of file diff --git a/localization/en_en/music_controls.txt b/localization/en_en/music_controls.txt index 8933159..88c47c3 100644 --- a/localization/en_en/music_controls.txt +++ b/localization/en_en/music_controls.txt @@ -1,10 +1,4 @@ **Controls** -Play/pause: -\N{BLACK RIGHT-POINTING TRIANGLE} -\N{DOUBLE VERTICAL BAR} -skip 15 seconds forward/backward: -\N{BLACK LEFT-POINTING DOUBLE TRIANGLE} -\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE} -Skip to beginning/end of song: -\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} -\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} \ No newline at end of file +Play/pause: ▶ ⏸ +skip 15 seconds forward/backward: ⏪ ⏩ +Skip to beginning/end of song: ⏮ ⏭ \ No newline at end of file diff --git a/localization/nb_no/music.json b/localization/nb_no/music.json index 3713828..cadf28a 100644 --- a/localization/nb_no/music.json +++ b/localization/nb_no/music.json @@ -68,6 +68,12 @@ "playing_in": "Spiller av om", "enqueued": "Song køet", "estimated": "estimert" + }, + "history": { + "title": "Sporhistorie", + "current": "`Nåværende` **[{_title}]({_uri})** _av <@{_id}>_", + "track": "`{_index}.` **[{_title}]({_uri})** _av <@{_id}>_", + "previous": "**{_len} Tidligere sanger:**" } } } \ No newline at end of file diff --git a/localization/nb_no/music_controls.txt b/localization/nb_no/music_controls.txt index bd61c51..fd89789 100644 --- a/localization/nb_no/music_controls.txt +++ b/localization/nb_no/music_controls.txt @@ -1,10 +1,4 @@ **Kontrollere** -Spill/pause: -\N{BLACK RIGHT-POINTING TRIANGLE} -\N{DOUBLE VERTICAL BAR} -skip 15 seconds forward/backward: -\N{BLACK LEFT-POINTING DOUBLE TRIANGLE} -\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE} -Skip to beginning/end of song: -\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} -\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR} \ No newline at end of file +Spill/pause: ▶ ⏸ +Hopp 15 sekunder fremover/bakover: ⏪ ⏩ +Hopp til starten/slutten av sangen: ⏮ ⏭ \ No newline at end of file From b1d79f77191faa8c5cb8f3e1f9afb458d4c2c02d Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Jan 2019 02:14:38 +0100 Subject: [PATCH 32/37] Updated config example --- config.json.example | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config.json.example b/config.json.example index ad2d1eb..cdeae9f 100644 --- a/config.json.example +++ b/config.json.example @@ -3,6 +3,8 @@ "default_prefix": [""], "default_admin": "Admin", "default_mod": "Moderator", + "default_locale": "en_en", + "default_lang_path": "./localization", "playing": "", "description": "" } \ No newline at end of file From e997f71f1f71a05da3e9ff5d975e70843a57af48 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Jan 2019 09:31:59 +0100 Subject: [PATCH 33/37] Added localization for music info --- cogs/misc.py | 23 ++++++++++++----------- localization/en_en/info.json | 25 ++++++++++++++++--------- localization/nb_no/info.json | 25 ++++++++++++++++--------- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/cogs/misc.py b/cogs/misc.py index fb8201a..453a47a 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -45,15 +45,16 @@ class Misc: """ Info om musikkspilleren """ - embed = discord.Embed(title='Music info', color=ctx.me.color) + embed = discord.Embed(title='{info.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='Players', value=f'{len(lavalink.players)}') - embed.add_field(name='Listeners', value=f'{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_locale(ctx.guild.id)) await ctx.send(embed=embed) @@ -92,15 +93,15 @@ 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.what}", - value='{info.infotext}', inline=False) + embed.add_field(name="{info.bot.what}", + value='{info.bot.infotext}', inline=False) embed.set_footer(icon_url="https://cdn.discordapp.com/icons/532176350019321917/92f43a1f67308a99a30c169db4b671dd.png?size=64", - text="{info.footer_text}") - embed.add_field(name="{info.how}", - value='{info.spectext}') - embed.add_field(name="{info.how_many}", - value='{info.stattext}') - embed.add_field(name="{info.how_long}", + 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}", value=uptimetext) embed = self.bot.localizer.format_embed(embed, diff --git a/localization/en_en/info.json b/localization/en_en/info.json index 38f0b5d..401507f 100644 --- a/localization/en_en/info.json +++ b/localization/en_en/info.json @@ -1,11 +1,18 @@ { - "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" + "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" + } } \ No newline at end of file diff --git a/localization/nb_no/info.json b/localization/nb_no/info.json index 59dcc40..ee6a065 100644 --- a/localization/nb_no/info.json +++ b/localization/nb_no/info.json @@ -1,11 +1,18 @@ { - "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" + "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": "Musikk info", + "players": "Spillere", + "listeners": "Lyttere" + } } \ No newline at end of file From c469db6d8c87567ea113d70283cdd2e22e908433 Mon Sep 17 00:00:00 2001 From: LBlend <3142367-LBlend@users.noreply.gitlab.com> Date: Mon, 28 Jan 2019 10:43:30 +0000 Subject: [PATCH 34/37] Improved translation --- localization/nb_no/music.json | 156 +++++++++++++++++----------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/localization/nb_no/music.json b/localization/nb_no/music.json index cadf28a..321bfba 100644 --- a/localization/nb_no/music.json +++ b/localization/nb_no/music.json @@ -1,79 +1,79 @@ -{ - "response": { - "nothing_found": "Ingenting funnet!", - "not_playing": "Spiller ikke.", - "nothing_playing": "Ingenting spiller av", - "have_to_listen": "Du må høre på botten", - "playlist_enqued": "Spilleliste lagt til!", - "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 posisjon.", - "exceeds_queue": "Posisjonen overgår køens lengde.", - "skipped_to": "hoppet til `{_title}` posisjon `{_pos}`" - }, - "stop": "⏹ | Stopped.", - "live": "🔴 LIVE", - "now": "Spiller nå", - "queue": { - "empty": "Køen er tom", - "user_empty": "{_user} sin kø er tom" - }, - "my_queue": "Din kø er tom", - "resume": { - "resumed": "⏯ | Resumed", - "paused": "⏯ | Paused" - }, - "shuffle": "Din kø har blitt stokket", - "out_of_range": "Posisjonene må være mellom 1 og {_len}", - "move": { - "not_in_queue": "Sjekk av posisjonen eksisterer i køen din", - "moved_to": "{_title} flyttet fra {_from} til {_to} i køen din" - }, - "remove": "**{_title}** fjernet.", - "dj_removed": "**{_title}** køet av {_user} fjernet.", - "dj_remove_user": "Fjernet alle sanger køet av <@{_id}>.", - "search": "søker", - "results": "Resultater", - "time_expired": "Tid utgått", - "disconnect": { - "not_in_voice": "Du er ikke i min stemmekanal!", - "disconnected": "Frakoblet" - }, - "not_connected": "Ikke koblet til.", - "volume": { - "set_to": "Volume satt til {_volume}", - "reset": "Volume og equalizer resatt", - "out_of_range": "Du kan bare sette volum mellom 50 og 125" - }, - "boost": { - "on": "Bass boost er på", - "off": "'Bass boost er av" - }, - "scrub": { - "add": "Legger til kontrollere", - "controls": "{music_controls}", - "_comment_controls": "scrub.controls read from music_controls.txt" - }, - "enqueue": { - "position": "posisjon", - "playing_in": "Spiller av om", - "enqueued": "Song køet", - "estimated": "estimert" - }, - "history": { - "title": "Sporhistorie", - "current": "`Nåværende` **[{_title}]({_uri})** _av <@{_id}>_", - "track": "`{_index}.` **[{_title}]({_uri})** _av <@{_id}>_", - "previous": "**{_len} Tidligere sanger:**" - } - } +{ + "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}` posisjon `{_pos}`" + }, + "stop": "⏹ | Stoppet avspillingen.", + "live": "🔴 DIREKTE", + "now": "Spiller nå", + "queue": { + "empty": "Køen er tom", + "user_empty": "{_user} sin kø er tom" + }, + "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 {_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 tid" + }, + "history": { + "title": "Avspillingshistorikk", + "current": "`Spiller nå` **[{_title}]({_uri})** _av <@{_id}>_", + "track": "`{_index}.` **[{_title}]({_uri})** _av <@{_id}>_", + "previous": "**Tidligere sanger ({_len}):**" + } + } } \ No newline at end of file From a50df6eef87db7cee7e9ec1fb2d1994f9abd7007 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Mon, 28 Jan 2019 19:58:49 +0100 Subject: [PATCH 35/37] Norwegian aliases(temp) and skipto fix. --- cogs/music.py | 73 ++++++++++++++++++----------------- localization/nb_no/music.json | 4 +- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/cogs/music.py b/cogs/music.py index 7b115fd..af31ff6 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -55,8 +55,8 @@ class Music: ws = self.bot._connection._get_websocket(guild_id) await ws.voice_state(str(guild_id), channel_id) - @commands.command(aliases=['p']) - async def play(self, ctx, *, query: str): + @commands.command(name='play', aliases=['p','spill','s']) + 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.id) @@ -91,9 +91,9 @@ class Music: if not player.is_playing: await player.play() - @commands.command() + @commands.command(name='seek', aliases=['spol']) @checks.DJ_or(alone=True) - async def seek(self, ctx, *, time: str): + 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.id) @@ -117,8 +117,8 @@ class Music: msg = localizer.format_str("{seek.track_moved}",_position=lavalink.utils.format_time(track_time)) await ctx.send(msg) - @commands.command() - async def skip(self, ctx): + @commands.command(name='skip', aliases=['hopp']) + async def _skip(self, ctx): """ Skips the current track. """ player = self.bot.lavalink.players.get(ctx.guild.id) localizer = self.getLocalizer(ctx.guild.id) @@ -137,9 +137,9 @@ class Music: msg = localizer.format_str("{skip.require_vote}", _skips=skips, _total=math.ceil(total/2)) await ctx.send(msg) - @commands.command(name='skipto', aliases=['st','skip_to','forceskip']) + @commands.command(name='skipto', aliases=['forceskip','hopptil','tvinghopp']) @checks.DJ_or(alone=True) - async def skip_to(self, ctx, pos: int=1): + 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.id) @@ -152,12 +152,13 @@ class Music: if len(player.queue) < pos: return await ctx.send(localizer.format_str("{skip_to.exceeds_queue}")) await player.skip(pos - 1) - msg = localizer.format_str("{skipped_to}", _title=player.current.title, _pos=pos) + msg = localizer.format_str("{skip_to.skipped_to}", _title=player.current.title, _pos=pos) + print(msg, player.current.title, pos) await ctx.send(msg) - @commands.command() + @commands.command(name='stop', aliases=['stopp']) @checks.DJ_or(alone=True) - async def stop(self, ctx): + 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.id) @@ -172,8 +173,8 @@ class Music: await player.stop() await ctx.send(localizer.format_str("{stop}")) - @commands.command(aliases=['np', 'n', 'playing','current']) - async def now(self, ctx): + @commands.command(name='now', aliases=['np','current', 'nå', 'nåspilles', 'gjeldende', 'spillernå']) + 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.id) @@ -203,8 +204,8 @@ class Music: embed = localizer.format_embed(embed) await ctx.send(embed=embed) - @commands.command(aliases=['q']) - async def queue(self, ctx, user: discord.Member=None): + @commands.command(name='queue', aliases=['q', 'kø']) + 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.id) @@ -225,7 +226,7 @@ class Music: scroller = QueueScroller(ctx, user_queue, lines_per_page=10, user_name=user.name) await scroller.start_scrolling() - @commands.command(name='myqueue', aliases=['mq']) + @commands.command(name='myqueue', aliases=['mq','minkø','mk']) async def _myqueue(self, ctx): """ Shows your queue. """ player = self.bot.lavalink.players.get(ctx.guild.id) @@ -238,9 +239,9 @@ class Music: scroller = QueueScroller(ctx, user_queue, lines_per_page=10, user_name=ctx.author.name) await scroller.start_scrolling() - @commands.command(aliases=['resume']) + @commands.command(name='pause', aliases=['resume','gjenoppta']) @checks.DJ_or(alone=True) - async def pause(self, ctx): + async def _pause(self, ctx): """ Pauses/Resumes the current track. """ player = self.bot.lavalink.players.get(ctx.guild.id) localizer = self.getLocalizer(ctx.guild.id) @@ -255,7 +256,7 @@ class Music: await player.set_pause(True) await ctx.send(localizer.format_str("{resume.paused}")) - @commands.command(name='shuffle') + @commands.command(name='shuffle', aliases=['stokk']) async def _shuffle(self, ctx): """ Shuffles your queue. """ player = self.bot.lavalink.players.get(ctx.guild.id) @@ -269,7 +270,7 @@ class Music: player.shuffle_user_queue(ctx.author.id) await ctx.send(localizer.format_str("{shuffle}")) - @commands.command(name='move', aliases=["m"]) + @commands.command(name='move', aliases=['m', 'flytt','f']) 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) @@ -289,8 +290,8 @@ class Music: msg = localizer.format_str("{move.moved_to}", _title=moved.title, _from=from_pos, _to=to_pos) await ctx.send(msg) - @commands.command() - async def remove(self, ctx, pos: int): + @commands.command(name='remove', aliases=['rem', 'fjern']) + 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.id) @@ -309,7 +310,7 @@ class Music: await ctx.send(localizer.format_str("{remove}", _title=removed.title)) - @commands.command(name="DJremove") + @commands.command(name="DJremove", aliases=['DJfjern','djfjern']) @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""" @@ -341,7 +342,7 @@ class Music: removed = player.remove_user_track(user.id, pos - 1) await ctx.send(localizer.format_str("{dj_removed}", _title=removed.title, _user=requester.name)) - @commands.command(name="removeuser") + @commands.command(name='removeuser', aliases=['fjernbruker']) @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""" @@ -363,8 +364,8 @@ class Music: await ctx.send(embed=embed) - @commands.command() - async def search(self, ctx, *, query): + @commands.command(name='search', aliases=['søk']) + 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.id) @@ -456,9 +457,9 @@ class Music: if not player.is_playing: await player.play() - @commands.command(aliases=['dc']) + @commands.command(name='disconnect', aliases=['dc','kf','koblefra']) @checks.DJ_or(alone=True) - async def disconnect(self, ctx): + 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.id) @@ -476,9 +477,9 @@ class Music: embed = localizer.format_embed(embed) await ctx.send(embed=embed) - @commands.command(aliases=['vol']) + @commands.command(name='volume', aliases=['vol', 'volum', 'lydstyrke']) @checks.DJ_or(alone=True, current=True) - async def volume(self, ctx, volume: int = None): + 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.id) @@ -496,9 +497,9 @@ class Music: embed = localizer.format_embed(embed, _volume=player.volume) await ctx.send(embed=embed) - @commands.command(aliases=['normal','nl']) + @commands.command(name='nomalize', aliases=['normal','nl','normaliser']) @checks.DJ_or(alone=True) - async def normalize(self, ctx): + async def _normalize(self, ctx): """ Reset the equalizer and """ player = self.bot.lavalink.players.get(ctx.guild.id) localizer = self.getLocalizer(ctx.guild.id) @@ -512,7 +513,7 @@ class Music: await ctx.send(embed=embed) - @commands.command(name='boost', aliases=['boo']) + @commands.command(name='boost', aliases=['boo','bassforsterker']) @checks.DJ_or(alone=True) async def _boost(self, ctx, boost: bool=None): """ Set the equalizer to bass boost the music """ @@ -532,7 +533,7 @@ class Music: embed = localizer.format_embed(embed) await ctx.send(embed=embed) - @commands.command(name='history', aliases=['h','hist']) + @commands.command(name='history', aliases=['h','hist','historie']) async def _history(self, ctx): """ Show the last 10 songs played """ player = self.bot.lavalink.players.get(ctx.guild.id) @@ -554,9 +555,9 @@ class Music: await ctx.send(embed=embed) - @commands.command() + @commands.command(name='scrub', aliases=['kontrol','konsoll']) @checks.DJ_or(alone=True) - async def scrub(self, ctx): + 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.id) diff --git a/localization/nb_no/music.json b/localization/nb_no/music.json index 321bfba..f4086ef 100644 --- a/localization/nb_no/music.json +++ b/localization/nb_no/music.json @@ -18,7 +18,7 @@ "skip_to": { "invalid_pos": "Ugyldig køposisjon.", "exceeds_queue": "Posisjonen overgår køens lengde.", - "skipped_to": "hoppet til `{_title}` posisjon `{_pos}`" + "skipped_to": "hoppet til `{_title}` i posisjon `{_pos}`" }, "stop": "⏹ | Stoppet avspillingen.", "live": "🔴 DIREKTE", @@ -36,7 +36,7 @@ "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 {_from} til {_to} 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.", From 6bb96914b8ca57fb33742f84318fa1fea02e9dd3 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Mon, 28 Jan 2019 20:06:34 +0100 Subject: [PATCH 36/37] Fixed LBlend's typo ;) --- localization/nb_no/music.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/localization/nb_no/music.json b/localization/nb_no/music.json index f4086ef..ba0dc8f 100644 --- a/localization/nb_no/music.json +++ b/localization/nb_no/music.json @@ -56,7 +56,7 @@ }, "boost": { "on": "Bassforsterkeren er på", - "off": "'Bassforsterkeren er av" + "off": "Bassforsterkeren er av" }, "scrub": { "add": "Legger til kontrollere", From 204f405c75f581e6e5931e9b77a6ee39920342e7 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Tue, 29 Jan 2019 17:52:20 +0100 Subject: [PATCH 37/37] Added locale: Nynorsk, nn_no. --- cogs/music.py | 12 ++-- localization/nb_no/music.json | 2 +- localization/nb_no/music_controls.txt | 2 +- localization/nn_no/commands.json | 3 + localization/nn_no/info.json | 18 ++++++ localization/nn_no/music.json | 79 +++++++++++++++++++++++++++ localization/nn_no/music_controls.txt | 4 ++ 7 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 localization/nn_no/commands.json create mode 100644 localization/nn_no/info.json create mode 100644 localization/nn_no/music.json create mode 100644 localization/nn_no/music_controls.txt diff --git a/cogs/music.py b/cogs/music.py index af31ff6..df98106 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -55,7 +55,7 @@ class Music: 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']) + @commands.command(name='play', aliases=['p','spill','s','spel']) 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) @@ -173,7 +173,7 @@ class Music: await player.stop() await ctx.send(localizer.format_str("{stop}")) - @commands.command(name='now', aliases=['np','current', 'nå', 'nåspilles', 'gjeldende', 'spillernå']) + @commands.command(name='now', aliases=['np','current', 'nå', 'nåspilles', 'gjeldende', 'spillernå','spelarno','nospelar']) async def _now(self, ctx): """ Shows some stats about the currently playing song. """ player = self.bot.lavalink.players.get(ctx.guild.id) @@ -342,7 +342,7 @@ class Music: removed = player.remove_user_track(user.id, pos - 1) await ctx.send(localizer.format_str("{dj_removed}", _title=removed.title, _user=requester.name)) - @commands.command(name='removeuser', aliases=['fjernbruker']) + @commands.command(name='removeuser', aliases=['fjernbruker','fjernbrukar']) @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""" @@ -364,7 +364,7 @@ class Music: await ctx.send(embed=embed) - @commands.command(name='search', aliases=['søk']) + @commands.command(name='search', aliases=['søk','finn']) 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) @@ -457,7 +457,7 @@ class Music: if not player.is_playing: await player.play() - @commands.command(name='disconnect', aliases=['dc','kf','koblefra']) + @commands.command(name='disconnect', aliases=['dc','kf','koblefra','koblefrå']) @checks.DJ_or(alone=True) async def _disconnect(self, ctx): """ Disconnects the player from the voice channel and clears its queue. """ @@ -513,7 +513,7 @@ class Music: await ctx.send(embed=embed) - @commands.command(name='boost', aliases=['boo','bassforsterker']) + @commands.command(name='boost', aliases=['boo','bassforsterker','bassforsterkar']) @checks.DJ_or(alone=True) async def _boost(self, ctx, boost: bool=None): """ Set the equalizer to bass boost the music """ diff --git a/localization/nb_no/music.json b/localization/nb_no/music.json index ba0dc8f..72ab78a 100644 --- a/localization/nb_no/music.json +++ b/localization/nb_no/music.json @@ -67,7 +67,7 @@ "position": "Køposisjon", "playing_in": "Spiller av om", "enqueued": "Ny sang lagt til i køen", - "estimated": "estimert tid" + "estimated": "estimert" }, "history": { "title": "Avspillingshistorikk", diff --git a/localization/nb_no/music_controls.txt b/localization/nb_no/music_controls.txt index fd89789..c625045 100644 --- a/localization/nb_no/music_controls.txt +++ b/localization/nb_no/music_controls.txt @@ -1,4 +1,4 @@ -**Kontrollere** +**Kontroller** Spill/pause: ▶ ⏸ Hopp 15 sekunder fremover/bakover: ⏪ ⏩ Hopp til starten/slutten av sangen: ⏮ ⏭ \ No newline at end of file diff --git a/localization/nn_no/commands.json b/localization/nn_no/commands.json new file mode 100644 index 0000000..1a2c83c --- /dev/null +++ b/localization/nn_no/commands.json @@ -0,0 +1,3 @@ +{ + "not_available_dm": "Denna kommandoa er ikkje tilgjengeleg i direkte meldingar DMs" +} \ No newline at end of file diff --git a/localization/nn_no/info.json b/localization/nn_no/info.json new file mode 100644 index 0000000..ade527f --- /dev/null +++ b/localization/nn_no/info.json @@ -0,0 +1,18 @@ +{ + "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": "Musikk informasjon", + "players": "Spelarar", + "listeners": "Lyttarar" + } +} \ No newline at end of file diff --git a/localization/nn_no/music.json b/localization/nn_no/music.json new file mode 100644 index 0000000..7a469d5 --- /dev/null +++ b/localization/nn_no/music.json @@ -0,0 +1,79 @@ +{ + "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" + }, + "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" + }, + "history": { + "title": "Avspelingshistorikk", + "current": "`Spelar no` **[{_title}]({_uri})** _av <@{_id}>_", + "track": "`{_index}.` **[{_title}]({_uri})** _av <@{_id}>_", + "previous": "**Tidlegare songar ({_len}):**" + } + } +} \ No newline at end of file diff --git a/localization/nn_no/music_controls.txt b/localization/nn_no/music_controls.txt new file mode 100644 index 0000000..225d830 --- /dev/null +++ b/localization/nn_no/music_controls.txt @@ -0,0 +1,4 @@ +**Kontrollar** +Spel/pause: ▶ ⏸ +Hopp 15 sekundar framover/bakover: ⏪ ⏩ +Hopp til byrjinga/slutten av songen: ⏮ ⏭ \ No newline at end of file