From 94059738be088bc34b2796ce19bd96fbcf89bb8c Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 11:52:46 +0200 Subject: [PATCH 01/15] Update requerements and add python 3.10 support --- cogs/utils/dict_utils.py | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cogs/utils/dict_utils.py b/cogs/utils/dict_utils.py index eab05c4..a8ba624 100644 --- a/cogs/utils/dict_utils.py +++ b/cogs/utils/dict_utils.py @@ -11,7 +11,7 @@ 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): + if isinstance(v, collections.abc.MutableMapping): items.extend(flatten(v, new_key, sep=sep).items()) else: items.append((new_key, v)) diff --git a/requirements.txt b/requirements.txt index 1705c7f..f9ef2f5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ discord.py == 1.7.* -git+https://github.com/Devoxin/Lavalink.py@dev +lavalink asyncio pyyaml BeautifulSoup4 From b8bb2a48da814f40f03769c9adb3404835368f82 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 11:55:37 +0200 Subject: [PATCH 02/15] Move music player code its own folder --- cogs/nodemanager.py | 1 - cogs/utils/mixplayer/__init__.py | 3 + .../{mixplayer.py => mixplayer/mixqueue.py} | 180 +---------------- cogs/utils/mixplayer/player.py | 184 ++++++++++++++++++ 4 files changed, 188 insertions(+), 180 deletions(-) create mode 100644 cogs/utils/mixplayer/__init__.py rename cogs/utils/{mixplayer.py => mixplayer/mixqueue.py} (55%) create mode 100644 cogs/utils/mixplayer/player.py diff --git a/cogs/nodemanager.py b/cogs/nodemanager.py index 5adc86f..d6184ab 100644 --- a/cogs/nodemanager.py +++ b/cogs/nodemanager.py @@ -5,7 +5,6 @@ from discord.ext import commands from lavalink import Node import codecs - import yaml # Bot Utilities diff --git a/cogs/utils/mixplayer/__init__.py b/cogs/utils/mixplayer/__init__.py new file mode 100644 index 0000000..24aa7f5 --- /dev/null +++ b/cogs/utils/mixplayer/__init__.py @@ -0,0 +1,3 @@ +from .player import MixPlayer + +__all__ = ['MixPlayer'] diff --git a/cogs/utils/mixplayer.py b/cogs/utils/mixplayer/mixqueue.py similarity index 55% rename from cogs/utils/mixplayer.py rename to cogs/utils/mixplayer/mixqueue.py index eaef58c..bb64866 100644 --- a/cogs/utils/mixplayer.py +++ b/cogs/utils/mixplayer/mixqueue.py @@ -1,189 +1,11 @@ # Discord Packages -import discord -import lavalink -from lavalink import AudioTrack, DefaultPlayer, Node -from lavalink.events import QueueEndEvent, TrackEndEvent, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent +from lavalink import AudioTrack -import typing from collections import OrderedDict, deque from itertools import chain, cycle, islice from random import shuffle -class MixPlayer(DefaultPlayer): - def __init__(self, guild_id: int, node: Node): - super().__init__(guild_id, node) - - self.queue = MixQueue() - - self.listeners = set() - self.voteables = {} - self.skip_voters = set() - self.boosted = False - - def add(self, requester: int, track: typing.Union[dict, AudioTrack], pos: int = None): - """ Adds a track to the queue. """ - return self.queue.add_track(requester, track, pos) - - def add_next(self, requester: int, track: typing.Union[dict, AudioTrack], pos: int = None): - """ Adds a track to beginning of the queue """ - self.queue.add_next_track(track) - - def move_user_track(self, requester: int, initial: int, final: int): - """ Moves a track in a users queue""" - return self.queue.move_user_track(requester, initial, final) - - def remove_user_queue(self, requester: int): - self.queue.remove_user_queue(requester) - - def remove_user_track(self, requester: int, pos: int): - """ Removes the song at from the queue of requester """ - return self.queue.remove_user_track(requester, pos) - - def remove_global_track(self, pos: int): - """ Removes the song at in the global queue """ - return self.queue.remove_global_track(pos) - - def shuffle_user_queue(self, requester: int): - """ Randomly reorders the queue of requester """ - self.queue.shuffle_user_queue(requester) - - def user_queue(self, user: int, dual: bool = False): - return self.queue.get_user_queue(user, dual) - - def global_queue(self): - return self.queue.get_queue() - - def get_history(self): - return self.queue.history - - def queue_duration(self, include_current: bool = False, member: discord.Member = None, end_pos: int = None): - duration = 0 - queue = self.user_queue(member.id) if member else self.queue - - for i, track in enumerate(queue): - if i == end_pos: - break - duration += int(track.duration) - - remaining = self.current.duration - self.position - if include_current: - if self.current: - remaining = self.current.duration - self.position - return lavalink.utils.format_time(duration + remaining) - return lavalink.utils.format_time(duration) - - async def play(self, track: AudioTrack = None, start_time: int = 0): - - self.current = None - self.last_update = 0 - self.last_position = 0 - self.position_timestamp = 0 - self.paused = False - - if not track: - if self.queue.empty: - self.boosted = False - await self.stop() - await self.node._dispatch_event(QueueEndEvent(self)) - return - else: - track = self.queue.pop_first() - - self.current = track - await self.node._send(op='play', guildId=self.guild_id, - track=track.track, startTime=start_time) - await self.node._dispatch_event(TrackStartEvent(self, track)) - - async def skip(self, pos: int = 0): - """ Plays the next track in the queue, if any. """ - for i in range(pos): - _ = self.queue.pop_first() - self.clear_votes() - await self.play() - - async def stop(self): - """ Stops the player. """ - await self.node._send(op='stop', guildId=self.guild_id) - self.current = None - self.queue.looping = False - self.clear_votes() - - def update_listeners(self, member, voice_state): - if self.is_connected: - vc = int(self.channel_id) - if voice_state.channel is None or voice_state.channel.id != vc: - self.listeners.discard(member) - self.remove_member_votes(member) - else: - if voice_state.deaf or voice_state.self_deaf: - self.listeners.discard(member) - self.remove_member_votes(member) - else: - self.listeners.add(member) - - def clear_listeners(self): - self.listeners.clear() - - def add_vote(self, category, member): - if member in self.listeners: - if category not in self.voteables: - self.voteables[category] = set() - self.voteables[category].add(member) - - def remove_member_votes(self, member): - for category, votes in self.voteables.items(): - votes.discard(member) - - def get_voters(self, category): - if category not in self.voteables: - self.voteables[category] = set() - return self.voteables[category] - - def clear_votes(self): - for category, votes in self.voteables.items(): - votes.clear() - - def enable_looping(self, looping): - if (not self.queue.looping) and looping: - self.queue.enable_looping(looping) - if track := self.current: - if looping: - self.queue.add_track(track.requester, track) - elif not looping and self.queue.looping: - self.queue.enable_looping(looping) - - 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() - for category, votes in self.voteables.items(): - votes.clear() - await self.play() - - async def bassboost(self, boost: bool = False): - if boost: - gains = [ - (0, 0.15), - (1, 0.15), - (2, 0.25), - (3, 0.15), - (4, -0.15), - (5, -0.1), - (6, -0.05) - ] - self.boosted = True - await self.set_gains(*gains) - else: - self.boosted = False - await self.reset_equalizer() - - @property - def looping(self): - return self.queue.looping - - def roundrobin(*iterables): """roundrobin('ABC', 'D', 'EF') --> A D E B F C""" # Recipe credited to George Sakkis diff --git a/cogs/utils/mixplayer/player.py b/cogs/utils/mixplayer/player.py new file mode 100644 index 0000000..4a5f4ac --- /dev/null +++ b/cogs/utils/mixplayer/player.py @@ -0,0 +1,184 @@ +import typing + +# Discord Packages +import discord +import lavalink +from lavalink import AudioTrack, DefaultPlayer, Node +from lavalink.events import QueueEndEvent, TrackEndEvent, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent + + +from .mixqueue import MixQueue + + +class MixPlayer(DefaultPlayer): + def __init__(self, guild_id: int, node: Node): + super().__init__(guild_id, node) + + self.queue = MixQueue() + + self.listeners = set() + self.voteables = {} + self.skip_voters = set() + self.boosted = False + + def add(self, requester: int, track: typing.Union[dict, AudioTrack], pos: int = None): + """ Adds a track to the queue. """ + return self.queue.add_track(requester, track, pos) + + def add_next(self, requester: int, track: typing.Union[dict, AudioTrack], pos: int = None): + """ Adds a track to beginning of the queue """ + self.queue.add_next_track(track) + + def move_user_track(self, requester: int, initial: int, final: int): + """ Moves a track in a users queue""" + return self.queue.move_user_track(requester, initial, final) + + def remove_user_queue(self, requester: int): + self.queue.remove_user_queue(requester) + + def remove_user_track(self, requester: int, pos: int): + """ Removes the song at from the queue of requester """ + return self.queue.remove_user_track(requester, pos) + + def remove_global_track(self, pos: int): + """ Removes the song at in the global queue """ + return self.queue.remove_global_track(pos) + + def shuffle_user_queue(self, requester: int): + """ Randomly reorders the queue of requester """ + self.queue.shuffle_user_queue(requester) + + def user_queue(self, user: int, dual: bool = False): + return self.queue.get_user_queue(user, dual) + + def global_queue(self): + return self.queue.get_queue() + + def get_history(self): + return self.queue.history + + def queue_duration(self, include_current: bool = False, member: discord.Member = None, end_pos: int = None): + duration = 0 + queue = self.user_queue(member.id) if member else self.queue + + for i, track in enumerate(queue): + if i == end_pos: + break + duration += int(track.duration) + + remaining = self.current.duration - self.position + if include_current: + if self.current: + remaining = self.current.duration - self.position + return lavalink.utils.format_time(duration + remaining) + return lavalink.utils.format_time(duration) + + async def play(self, track: AudioTrack = None, start_time: int = 0): + + self.current = None + self.last_update = 0 + self.last_position = 0 + self.position_timestamp = 0 + self.paused = False + + if not track: + if self.queue.empty: + self.boosted = False + await self.stop() + await self.node._dispatch_event(QueueEndEvent(self)) + return + else: + track = self.queue.pop_first() + + self.current = track + await self.node._send(op='play', guildId=self.guild_id, + track=track.track, startTime=start_time) + await self.node._dispatch_event(TrackStartEvent(self, track)) + + async def skip(self, pos: int = 0): + """ Plays the next track in the queue, if any. """ + for i in range(pos): + _ = self.queue.pop_first() + self.clear_votes() + await self.play() + + async def stop(self): + """ Stops the player. """ + await self.node._send(op='stop', guildId=self.guild_id) + self.current = None + self.queue.looping = False + self.clear_votes() + + def update_listeners(self, member, voice_state): + if self.is_connected: + vc = int(self.channel_id) + if voice_state.channel is None or voice_state.channel.id != vc: + self.listeners.discard(member) + self.remove_member_votes(member) + else: + if voice_state.deaf or voice_state.self_deaf: + self.listeners.discard(member) + self.remove_member_votes(member) + else: + self.listeners.add(member) + + def clear_listeners(self): + self.listeners.clear() + + def add_vote(self, category, member): + if member in self.listeners: + if category not in self.voteables: + self.voteables[category] = set() + self.voteables[category].add(member) + + def remove_member_votes(self, member): + for category, votes in self.voteables.items(): + votes.discard(member) + + def get_voters(self, category): + if category not in self.voteables: + self.voteables[category] = set() + return self.voteables[category] + + def clear_votes(self): + for category, votes in self.voteables.items(): + votes.clear() + + def enable_looping(self, looping): + if (not self.queue.looping) and looping: + self.queue.enable_looping(looping) + if track := self.current: + if looping: + self.queue.add_track(track.requester, track) + elif not looping and self.queue.looping: + self.queue.enable_looping(looping) + + 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() + for category, votes in self.voteables.items(): + votes.clear() + await self.play() + + async def bassboost(self, boost: bool = False): + if boost: + gains = [ + (0, 0.15), + (1, 0.15), + (2, 0.25), + (3, 0.15), + (4, -0.15), + (5, -0.1), + (6, -0.05) + ] + self.boosted = True + await self.set_gains(*gains) + else: + self.boosted = False + await self.reset_equalizer() + + @property + def looping(self): + return self.queue.looping From 4c6d15e3e8cf2f7e5fe2e802a867be21a3eeba05 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 13:10:48 +0200 Subject: [PATCH 03/15] Refactor bot into smaller modules --- bot.py | 6 +- cogs/cogmanager.py | 2 +- cogs/errors.py | 2 +- cogs/helpformatter.py | 2 +- cogs/music/basic_commands.py | 3 +- cogs/music/extra_commands.py | 2 +- cogs/nodemanager.py | 2 +- cogs/settings.py | 2 +- cogs/utils/localisation/__init__.py | 5 + cogs/utils/{ => localisation}/alias.py | 0 .../localizedcontext.py} | 2 +- cogs/utils/localisation/localizer/__init__.py | 4 + .../localizer}/dict_utils.py | 0 .../{ => localisation/localizer}/localizer.py | 18 +- .../localizer/localizerwrapper.py | 14 + cogs/utils/paginator.py | 297 ------------------ cogs/utils/settingsmanager/__init__.py | 3 + cogs/utils/settingsmanager/dictmapper.py | 37 +++ .../{ => settingsmanager}/settingsmanager.py | 36 +-- cogs/utils/userinteraction/__init__.py | 6 + .../userinteraction/paginators/__init__.py | 7 + .../paginators/basepaginator.py | 37 +++ .../paginators/fieldpaginator.py | 33 ++ .../paginators/helppaginator.py | 25 ++ .../paginators/queuepaginator.py | 31 ++ .../paginators/textpaginator.py | 39 +++ cogs/utils/userinteraction/scroller.py | 141 +++++++++ cogs/utils/{ => userinteraction}/selector.py | 2 +- 28 files changed, 398 insertions(+), 360 deletions(-) create mode 100644 cogs/utils/localisation/__init__.py rename cogs/utils/{ => localisation}/alias.py (100%) rename cogs/utils/{context.py => localisation/localizedcontext.py} (88%) create mode 100644 cogs/utils/localisation/localizer/__init__.py rename cogs/utils/{ => localisation/localizer}/dict_utils.py (100%) rename cogs/utils/{ => localisation/localizer}/localizer.py (88%) create mode 100644 cogs/utils/localisation/localizer/localizerwrapper.py delete mode 100644 cogs/utils/paginator.py create mode 100644 cogs/utils/settingsmanager/__init__.py create mode 100644 cogs/utils/settingsmanager/dictmapper.py rename cogs/utils/{ => settingsmanager}/settingsmanager.py (72%) create mode 100644 cogs/utils/userinteraction/__init__.py create mode 100644 cogs/utils/userinteraction/paginators/__init__.py create mode 100644 cogs/utils/userinteraction/paginators/basepaginator.py create mode 100644 cogs/utils/userinteraction/paginators/fieldpaginator.py create mode 100644 cogs/utils/userinteraction/paginators/helppaginator.py create mode 100644 cogs/utils/userinteraction/paginators/queuepaginator.py create mode 100644 cogs/utils/userinteraction/paginators/textpaginator.py create mode 100644 cogs/utils/userinteraction/scroller.py rename cogs/utils/{ => userinteraction}/selector.py (99%) diff --git a/bot.py b/bot.py index cf2b8ac..dc586dc 100644 --- a/bot.py +++ b/bot.py @@ -13,9 +13,7 @@ import aiohttp import yaml # Bot Utilities -from cogs.utils.alias import Aliaser -from cogs.utils.context import Context -from cogs.utils.localizer import Localizer, LocalizerWrapper +from cogs.utils.localisation import Aliaser, LocalizedContext, Localizer, LocalizerWrapper from cogs.utils.logger import BotLogger from cogs.utils.settingsmanager import Settings @@ -73,7 +71,7 @@ class Bot(commands.Bot): await self.process_commands(message) async def process_commands(self, message): - ctx = await self.get_context(message, cls=Context) + ctx = await self.get_context(message, cls=LocalizedContext) # Replace aliases with commands ctx = self.aliaser.get_command(ctx) diff --git a/cogs/cogmanager.py b/cogs/cogmanager.py index f811fa0..b20eb17 100644 --- a/cogs/cogmanager.py +++ b/cogs/cogmanager.py @@ -5,7 +5,7 @@ import traceback # Bot Utilities from cogs.helpformatter import commandhelper -from cogs.utils.paginator import Scroller +from cogs.utils.userinteraction import Scroller class CogManager(commands.Cog): diff --git a/cogs/errors.py b/cogs/errors.py index 5f69570..126f395 100644 --- a/cogs/errors.py +++ b/cogs/errors.py @@ -8,7 +8,7 @@ from cogs.music.music_errors import WrongTextChannelError, WrongVoiceChannelErro # Bot Utilities from cogs.helpformatter import commandhelper -from cogs.utils.paginator import Scroller +from cogs.utils.userinteraction import Scroller class Errors(commands.Cog): diff --git a/cogs/helpformatter.py b/cogs/helpformatter.py index 8e42960..875e34b 100644 --- a/cogs/helpformatter.py +++ b/cogs/helpformatter.py @@ -4,7 +4,7 @@ from discord.ext import commands import re # Bot Utilities -from cogs.utils.paginator import HelpPaginator, Scroller +from .utils.userinteraction import HelpPaginator, Scroller usermention = r"<@!?\d{17,19}>" diff --git a/cogs/music/basic_commands.py b/cogs/music/basic_commands.py index ff5761a..5ec061a 100644 --- a/cogs/music/basic_commands.py +++ b/cogs/music/basic_commands.py @@ -10,8 +10,7 @@ import asyncio import re from ..utils import checks, timeformatter -from ..utils.paginator import QueuePaginator, Scroller -from ..utils.selector import Selector +from ..utils.userinteraction import QueuePaginator, Scroller, Selector from .decorators import require_playing, require_queue, require_voice_connection, voteable time_rx = re.compile('[0-9]+') diff --git a/cogs/music/extra_commands.py b/cogs/music/extra_commands.py index b4caebb..335c122 100644 --- a/cogs/music/extra_commands.py +++ b/cogs/music/extra_commands.py @@ -15,7 +15,7 @@ import urllib from bs4 import BeautifulSoup from ..utils import checks -from ..utils.paginator import Scroller, TextPaginator +from ..utils.userinteraction import Scroller, TextPaginator from .decorators import require_playing, require_voice_connection, voteable diff --git a/cogs/nodemanager.py b/cogs/nodemanager.py index d6184ab..075b371 100644 --- a/cogs/nodemanager.py +++ b/cogs/nodemanager.py @@ -9,7 +9,7 @@ import yaml # Bot Utilities from cogs.helpformatter import commandhelper -from cogs.utils.paginator import Scroller +from cogs.utils.userinteraction import Scroller from .utils.mixplayer import MixPlayer diff --git a/cogs/settings.py b/cogs/settings.py index 6e87c66..414e962 100644 --- a/cogs/settings.py +++ b/cogs/settings.py @@ -5,7 +5,7 @@ from discord.ext import commands # Bot Utilities from cogs.helpformatter import commandhelper from cogs.utils import checks -from cogs.utils.paginator import Scroller +from cogs.utils.userinteraction import Scroller class Settings(commands.Cog): diff --git a/cogs/utils/localisation/__init__.py b/cogs/utils/localisation/__init__.py new file mode 100644 index 0000000..696da4c --- /dev/null +++ b/cogs/utils/localisation/__init__.py @@ -0,0 +1,5 @@ +from .alias import Aliaser +from .localizer import LocalizerWrapper, Localizer +from .localizedcontext import LocalizedContext + +__all__ = ['Aliaser', 'LocalizerWrapper', 'Localizer', 'LocalizedContext'] diff --git a/cogs/utils/alias.py b/cogs/utils/localisation/alias.py similarity index 100% rename from cogs/utils/alias.py rename to cogs/utils/localisation/alias.py diff --git a/cogs/utils/context.py b/cogs/utils/localisation/localizedcontext.py similarity index 88% rename from cogs/utils/context.py rename to cogs/utils/localisation/localizedcontext.py index 3dbc92b..0071838 100644 --- a/cogs/utils/context.py +++ b/cogs/utils/localisation/localizedcontext.py @@ -2,7 +2,7 @@ from discord.ext import commands -class Context(commands.Context): +class LocalizedContext(commands.Context): def __init__(self, **kwargs): super().__init__(**kwargs) if self.message.guild: diff --git a/cogs/utils/localisation/localizer/__init__.py b/cogs/utils/localisation/localizer/__init__.py new file mode 100644 index 0000000..221b371 --- /dev/null +++ b/cogs/utils/localisation/localizer/__init__.py @@ -0,0 +1,4 @@ +from .localizer import Localizer +from .localizerwrapper import LocalizerWrapper + +__all__ = ['LocalizerWrapper', 'Localizer'] diff --git a/cogs/utils/dict_utils.py b/cogs/utils/localisation/localizer/dict_utils.py similarity index 100% rename from cogs/utils/dict_utils.py rename to cogs/utils/localisation/localizer/dict_utils.py diff --git a/cogs/utils/localizer.py b/cogs/utils/localisation/localizer/localizer.py similarity index 88% rename from cogs/utils/localizer.py rename to cogs/utils/localisation/localizer/localizer.py index c3a444e..a61beb2 100644 --- a/cogs/utils/localizer.py +++ b/cogs/utils/localisation/localizer/localizer.py @@ -9,7 +9,7 @@ from os import path import yaml # Bot Utilities -from cogs.utils.dict_utils import SafeDict, flatten +from .dict_utils import SafeDict, flatten """ Localizer for bot @@ -152,19 +152,3 @@ class Localizer: def format_embed(self, embed, lang=None, prefix=None, **kvpairs): raw = embed.to_dict() return Embed.from_dict(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) diff --git a/cogs/utils/localisation/localizer/localizerwrapper.py b/cogs/utils/localisation/localizer/localizerwrapper.py new file mode 100644 index 0000000..f1c769d --- /dev/null +++ b/cogs/utils/localisation/localizer/localizerwrapper.py @@ -0,0 +1,14 @@ +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) diff --git a/cogs/utils/paginator.py b/cogs/utils/paginator.py deleted file mode 100644 index 9872093..0000000 --- a/cogs/utils/paginator.py +++ /dev/null @@ -1,297 +0,0 @@ -# Discord Packages -import discord - -import asyncio - - -class CantScroll(Exception): - pass - - -class BasePaginator: - def __init__(self, max_size=2000, max_units=10): - self._pages = [] - self._current_page_size = 0 - self._current_units = 0 - self._max_size = max_size - self._max_units = max_units - - def close_page(self): - pass - - def add_page_indicator(self, localizer, localizer_str=None, **kvpairs): - self.close_page() - if localizer_str: - for i, page in enumerate(self._pages, start=1): - page.set_footer(text=localizer.format_str(localizer_str, _current=i, - _total=len(self._pages), **kvpairs)) - else: - for i, page in enumerate(self._pages, start=1): - page.set_footer(text=f"{i}/{len(self._pages)}") - - def append_paginator(self, paginator): - if not isinstance(paginator, BasePaginator): - raise TypeError('Paginator needs to be a subclass of BasePaginator.') - self.close_page() - for page in paginator.pages: - self.pages.append(page) - - @property - def pages(self): - if self._current_page_size > 0: - self.close_page() - return self._pages - - -class TextPaginator(BasePaginator): - def __init__(self, max_size=2000, max_lines=10, **embed_base): - super().__init__(max_size=max_size, max_units=max_lines) - self._current_page = [] - self.embed_base = embed_base - - def close_page(self): - if self._current_page_size > 0: - embed = discord.Embed(**self.embed_base) - embed.description = '\n'.join(self._current_page) - self._pages.append(embed) - - self._current_page_size = 0 - self._current_units = 0 - self._current_page = [] - - def add_line(self, line='', *, empty=False): - if len(line) > self._max_size: - raise RuntimeError(f'Line exceeds maximum page size {self._max_size}') - - if self._current_page_size + len(line) + 1 > self._max_size: - self.close_page() - - if self._current_units >= self._max_units: - self.close_page() - - self._current_page_size += len(line) + 1 - self._current_units += 1 - self._current_page.append(line) - - if empty: - self._current_page.append('') - self._current_page_size += 1 - - -class FieldPaginator(BasePaginator): - def __init__(self, max_size=5000, max_fields=8, **embed_base): - super().__init__(max_size=max_size, max_units=max_fields) - self._embed_base = embed_base - self._current_page = discord.Embed(**self._embed_base) - - def close_page(self): - if self._current_page_size > 0: - self._pages.append(self._current_page) - self._current_page_size = 0 - self._current_units = 0 - self._current_page = discord.Embed(**self._embed_base) - - def add_field(self, name, value, inline=False): - field = {"name": name, "value": value} - fieldsize = sum([len(val) for _, val in field.items()]) - if len(name) > 256 or len(value) > 1024: - raise RuntimeError('Maximum field size exceeded, max name length: 256. max value length: 1024.') - - if self._current_page_size + fieldsize > self._max_size: - self.close_page() - - if self._current_units >= self._max_units: - self.close_page() - - field["inline"] = inline - self._current_page_size += fieldsize - self._current_units += 1 - self._current_page.add_field(**field) - - -class QueuePaginator(TextPaginator): - def __init__(self, localizer, player, color, member: discord.Member = None, include_current: bool = False): - self.localizer = localizer - - queue = player.global_queue() if not member else player.user_queue(member.id, dual=True) - duration = player.queue_duration(member=member, include_current=include_current) - - if member: - title = localizer.format_str("{queue.userqueue}", _user=member.display_name, _length=len(queue), - _duration=duration) - else: - title = localizer.format_str("{queue.length}", _length=len(queue), _duration=duration) - - super().__init__(max_lines=10, **{"color": color, "title": title}) - - for index, temp in enumerate(queue): - if member is None: - track = temp - queued_track = localizer.format_str("{queue.globaltrack}", _index=index+1, _title=track.title, - _uri=track.uri, _user_id=track.requester) - else: - track, globpos = temp - queued_track = localizer.format_str("{queue.usertrack}", _index=index+1, _globalindex=globpos+1, - _title=track.title, _uri=track.uri) - - self.add_line(queued_track) - self.add_page_indicator(self.localizer, "{queue.pageindicator}") - - -class HelpPaginator(FieldPaginator): - def __init__(self, **kwargs): - super().__init__(**kwargs) - - def force_close_page(self): - self._pages.append(self._current_page) - self._current_page_size = 0 - self._current_units = 0 - self._current_page = discord.Embed(**self._embed_base) - - def add_command_field(self, cmd_dict): - if not isinstance(cmd_dict, dict): - return - aliases = cmd_dict.get('aliases', []) - args = cmd_dict.get('args', '') - description = cmd_dict.get('description', '') - - cmd = str(aliases[0]) - - cmd += ' ' + args - self.add_field(name=cmd, value=description, inline=False) - - -# Maybe slightly very copied from rdanny -# Thanks danny <3 - -class Scroller: - def __init__(self, ctx, paginator, timeout=120.0, clear_on_timeout=False, clear_on_exit=True, clear_command=True): - - if not isinstance(paginator, BasePaginator): - raise TypeError('Paginator needs to be a subclass of BasePaginator.') - - self.bot = ctx.bot - self.pages = paginator.pages - self.cmdmsg = ctx.message - self.message = ctx.message - self.channel = ctx.channel - self.author = ctx.author - - self.timeout = timeout - self.timeout_delete = clear_on_timeout - self.exit_delete = clear_on_exit - self.clear_command = clear_command - - if len(self.pages) > 1: - self.scrolling = True - else: - self.scrolling = False - self.reaction_emojis = [ - ('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.first_page), - ('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page), - ('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page), - ('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.last_page), - ('❌', self.stop_scrolling), - ] - - if ctx.guild is not None: - self.permissions = self.channel.permissions_for(ctx.guild.me) - else: - self.permissions = self.channel.permissions_for(ctx.bot.user) - - if not self.permissions.embed_links: - raise CantScroll('Bot does not have embed links permission.') - - if not self.permissions.send_messages: - raise CantScroll('Bot cannot send messages.') - - if self.scrolling: - # verify we can actually use the pagination session - if not self.permissions.add_reactions: - raise CantScroll('Bot does not have add reactions permission.') - - if not self.permissions.read_message_history: - raise CantScroll('Bot does not have Read Message History permission.') - - async def send(self): - self.current_page = 0 - # No embeds to scroll through - if not self.pages: - return - - if not self.scrolling: - return await self.channel.send(embed=self.pages[0]) - - self.message = await self.channel.send(embed=self.pages[0]) - for (reaction, _) in self.reaction_emojis: - if len(self.pages) == 2 and reaction in ('\u23ed', '\u23ee'): - continue - - await self.message.add_reaction(reaction) - - async def scroll(self, page): - if page < 0 or page >= len(self.pages): - return - self.current_page = page - await self.message.edit(embed=self.pages[page]) - - async def first_page(self): - await self.scroll(0) - - async def last_page(self): - await self.scroll(len(self.pages) - 1) - - async def next_page(self): - await self.scroll(self.current_page + 1) - - async def previous_page(self): - await self.scroll(self.current_page - 1) - - async def stop_scrolling(self): - self.scrolling = False - if self.exit_delete: - await self.message.delete() - if self.clear_command: - await self.cmdmsg.delete() - - def react_check(self, reaction, user): - if user is None or user.id != self.author.id: - return False - - if reaction.message.id != self.message.id: - return False - - for (emoji, func) in self.reaction_emojis: - if reaction.emoji == emoji: - self.match = func - return True - return False - - async def start_scrolling(self): - if not self.scrolling: - await self.send() - else: - self.bot.loop.create_task(self.send()) - - while self.scrolling: - try: - reaction, user = await self.bot.wait_for('reaction_add', check=self.react_check, timeout=self.timeout) - except asyncio.TimeoutError: - self.scrolling = False - try: - await self.message.clear_reactions() - if self.timeout_delete: - await self.message.delete() - if self.clear_command: - await self.cmdmsg.delete() - except discord.Forbidden: - pass - finally: - break - - try: - await self.message.remove_reaction(reaction, user) - except discord.Forbidden: - pass - - await self.match() diff --git a/cogs/utils/settingsmanager/__init__.py b/cogs/utils/settingsmanager/__init__.py new file mode 100644 index 0000000..fba219e --- /dev/null +++ b/cogs/utils/settingsmanager/__init__.py @@ -0,0 +1,3 @@ +from .settingsmanager import Settings + +__all__ = ['Settings'] diff --git a/cogs/utils/settingsmanager/dictmapper.py b/cogs/utils/settingsmanager/dictmapper.py new file mode 100644 index 0000000..7832c3b --- /dev/null +++ b/cogs/utils/settingsmanager/dictmapper.py @@ -0,0 +1,37 @@ + +class DictMapper: + """ + Base class for interacting with nested dictionaries through lists of keys + E.g. mapping ["a", "b", "c"] to example_dictionary["a"]["b"]["c"] + """ + + @staticmethod + def set(d, keys, val): + key = keys[0] + if len(keys) == 1: + if val is None: + try: + d.pop(key) + except KeyError: + pass + else: + d[key] = val + return + if key in d.keys(): + if not isinstance(d[key], dict): + d[key] = {} + DictMapper.set(d[key], keys[1:], val) + else: + d[key] = {} + DictMapper.set(d[key], keys[1:], val) + + @staticmethod + def get(d, keys): + key = keys[0] + try: + if len(keys) > 1 and isinstance(d[key], dict): + return DictMapper.get(d[key], keys[1:]) + else: + return d[key] + except KeyError: + return None diff --git a/cogs/utils/settingsmanager.py b/cogs/utils/settingsmanager/settingsmanager.py similarity index 72% rename from cogs/utils/settingsmanager.py rename to cogs/utils/settingsmanager/settingsmanager.py index 2b6b9f5..ddbc29a 100644 --- a/cogs/utils/settingsmanager.py +++ b/cogs/utils/settingsmanager/settingsmanager.py @@ -6,9 +6,10 @@ import locale as localee import os import yaml +from .dictmapper import DictMapper -class Settings: +class Settings(): def __init__(self, datadir, **default_settings): self._DATA_PATH = f"{datadir}/bot/" self._SETTINGS_PATH = self._DATA_PATH + 'settings.yaml' @@ -34,35 +35,6 @@ class Settings: with codecs.open(self._SETTINGS_PATH, "r", encoding='utf8') as f: self.settings = yaml.load(f, Loader=yaml.SafeLoader) - def _set(self, d, keys, val): - key = keys[0] - if len(keys) == 1: - if val is None: - try: - d.pop(key) - except KeyError: - pass - else: - d[key] = val - return - if key in d.keys(): - if not isinstance(d[key], dict): - d[key] = {} - self._set(d[key], keys[1:], val) - else: - d[key] = {} - self._set(d[key], keys[1:], val) - - def _get(self, d, keys): - key = keys[0] - try: - if len(keys) > 1 and isinstance(d[key], dict): - return self._get(d[key], keys[1:]) - else: - return d[key] - except KeyError: - return None - def set(self, identifier, setting, value): """ Set value in settings, will overwrite any existing values. """ guild_name = None @@ -75,7 +47,7 @@ class Settings: if guild_name: self.settings[identifier]["_servername"] = guild_name - self._set(self.settings[identifier], setting.split('.'), value) + DictMapper.set(self.settings[identifier], setting.split('.'), value) with codecs.open(self._SETTINGS_PATH, 'w', encoding='utf8') as f: yaml.dump(self.settings, f, indent=2) @@ -95,7 +67,7 @@ class Settings: if identifier not in self.settings.keys(): return default - value = self._get(self.settings[identifier], setting.split('.')) + value = DictMapper.get(self.settings[identifier], setting.split('.')) if value is not None: return value else: diff --git a/cogs/utils/userinteraction/__init__.py b/cogs/utils/userinteraction/__init__.py new file mode 100644 index 0000000..5397e1b --- /dev/null +++ b/cogs/utils/userinteraction/__init__.py @@ -0,0 +1,6 @@ +from .scroller import Scroller +from .selector import Selector +from .paginators import BasePaginator, TextPaginator, FieldPaginator, HelpPaginator, QueuePaginator, CantScrollException + +__all__ = ['Scroller', 'Selector', 'QueuePaginator', 'HelpPaginator', + 'TextPaginator', 'FieldPaginator', 'CantScrollException', 'BasePaginator'] diff --git a/cogs/utils/userinteraction/paginators/__init__.py b/cogs/utils/userinteraction/paginators/__init__.py new file mode 100644 index 0000000..a335ea8 --- /dev/null +++ b/cogs/utils/userinteraction/paginators/__init__.py @@ -0,0 +1,7 @@ +from .queuepaginator import QueuePaginator +from .helppaginator import HelpPaginator +from .textpaginator import TextPaginator +from .fieldpaginator import FieldPaginator +from .basepaginator import CantScrollException, BasePaginator + +__all__ = ['QueuePaginator', 'HelpPaginator', 'TextPaginator', 'FieldPaginator', 'CantScrollException', 'BasePaginator'] diff --git a/cogs/utils/userinteraction/paginators/basepaginator.py b/cogs/utils/userinteraction/paginators/basepaginator.py new file mode 100644 index 0000000..adb5fb1 --- /dev/null +++ b/cogs/utils/userinteraction/paginators/basepaginator.py @@ -0,0 +1,37 @@ +class CantScrollException(Exception): + pass + + +class BasePaginator: + def __init__(self, max_size=2000, max_units=10): + self._pages = [] + self._current_page_size = 0 + self._current_units = 0 + self._max_size = max_size + self._max_units = max_units + + def close_page(self): + pass + + def add_page_indicator(self, localizer, localizer_str=None, **kvpairs): + self.close_page() + if localizer_str: + for i, page in enumerate(self._pages, start=1): + page.set_footer(text=localizer.format_str(localizer_str, _current=i, + _total=len(self._pages), **kvpairs)) + else: + for i, page in enumerate(self._pages, start=1): + page.set_footer(text=f"{i}/{len(self._pages)}") + + def append_paginator(self, paginator): + if not isinstance(paginator, BasePaginator): + raise TypeError('Paginator needs to be a subclass of BasePaginator.') + self.close_page() + for page in paginator.pages: + self.pages.append(page) + + @property + def pages(self): + if self._current_page_size > 0: + self.close_page() + return self._pages diff --git a/cogs/utils/userinteraction/paginators/fieldpaginator.py b/cogs/utils/userinteraction/paginators/fieldpaginator.py new file mode 100644 index 0000000..979a044 --- /dev/null +++ b/cogs/utils/userinteraction/paginators/fieldpaginator.py @@ -0,0 +1,33 @@ +import discord +from .basepaginator import BasePaginator + + +class FieldPaginator(BasePaginator): + def __init__(self, max_size=5000, max_fields=8, **embed_base): + super().__init__(max_size=max_size, max_units=max_fields) + self._embed_base = embed_base + self._current_page = discord.Embed(**self._embed_base) + + def close_page(self): + if self._current_page_size > 0: + self._pages.append(self._current_page) + self._current_page_size = 0 + self._current_units = 0 + self._current_page = discord.Embed(**self._embed_base) + + def add_field(self, name, value, inline=False): + field = {"name": name, "value": value} + fieldsize = sum([len(val) for _, val in field.items()]) + if len(name) > 256 or len(value) > 1024: + raise RuntimeError('Maximum field size exceeded, max name length: 256. max value length: 1024.') + + if self._current_page_size + fieldsize > self._max_size: + self.close_page() + + if self._current_units >= self._max_units: + self.close_page() + + field["inline"] = inline + self._current_page_size += fieldsize + self._current_units += 1 + self._current_page.add_field(**field) diff --git a/cogs/utils/userinteraction/paginators/helppaginator.py b/cogs/utils/userinteraction/paginators/helppaginator.py new file mode 100644 index 0000000..67a4fab --- /dev/null +++ b/cogs/utils/userinteraction/paginators/helppaginator.py @@ -0,0 +1,25 @@ +import discord +from .fieldpaginator import FieldPaginator + + +class HelpPaginator(FieldPaginator): + def __init__(self, **kwargs): + super().__init__(**kwargs) + + def force_close_page(self): + self._pages.append(self._current_page) + self._current_page_size = 0 + self._current_units = 0 + self._current_page = discord.Embed(**self._embed_base) + + def add_command_field(self, cmd_dict): + if not isinstance(cmd_dict, dict): + return + aliases = cmd_dict.get('aliases', []) + args = cmd_dict.get('args', '') + description = cmd_dict.get('description', '') + + cmd = str(aliases[0]) + + cmd += ' ' + args + self.add_field(name=cmd, value=description, inline=False) diff --git a/cogs/utils/userinteraction/paginators/queuepaginator.py b/cogs/utils/userinteraction/paginators/queuepaginator.py new file mode 100644 index 0000000..72d1949 --- /dev/null +++ b/cogs/utils/userinteraction/paginators/queuepaginator.py @@ -0,0 +1,31 @@ +import discord +from .textpaginator import TextPaginator + + +class QueuePaginator(TextPaginator): + def __init__(self, localizer, player, color, member: discord.Member = None, include_current: bool = False): + self.localizer = localizer + + queue = player.global_queue() if not member else player.user_queue(member.id, dual=True) + duration = player.queue_duration(member=member, include_current=include_current) + + if member: + title = localizer.format_str("{queue.userqueue}", _user=member.display_name, _length=len(queue), + _duration=duration) + else: + title = localizer.format_str("{queue.length}", _length=len(queue), _duration=duration) + + super().__init__(max_lines=10, **{"color": color, "title": title}) + + for index, temp in enumerate(queue): + if member is None: + track = temp + queued_track = localizer.format_str("{queue.globaltrack}", _index=index+1, _title=track.title, + _uri=track.uri, _user_id=track.requester) + else: + track, globpos = temp + queued_track = localizer.format_str("{queue.usertrack}", _index=index+1, _globalindex=globpos+1, + _title=track.title, _uri=track.uri) + + self.add_line(queued_track) + self.add_page_indicator(self.localizer, "{queue.pageindicator}") diff --git a/cogs/utils/userinteraction/paginators/textpaginator.py b/cogs/utils/userinteraction/paginators/textpaginator.py new file mode 100644 index 0000000..a396e2c --- /dev/null +++ b/cogs/utils/userinteraction/paginators/textpaginator.py @@ -0,0 +1,39 @@ +# Discord Packages +import discord + +from .basepaginator import BasePaginator + + +class TextPaginator(BasePaginator): + def __init__(self, max_size=2000, max_lines=10, **embed_base): + super().__init__(max_size=max_size, max_units=max_lines) + self._current_page = [] + self.embed_base = embed_base + + def close_page(self): + if self._current_page_size > 0: + embed = discord.Embed(**self.embed_base) + embed.description = '\n'.join(self._current_page) + self._pages.append(embed) + + self._current_page_size = 0 + self._current_units = 0 + self._current_page = [] + + def add_line(self, line='', *, empty=False): + if len(line) > self._max_size: + raise RuntimeError(f'Line exceeds maximum page size {self._max_size}') + + if self._current_page_size + len(line) + 1 > self._max_size: + self.close_page() + + if self._current_units >= self._max_units: + self.close_page() + + self._current_page_size += len(line) + 1 + self._current_units += 1 + self._current_page.append(line) + + if empty: + self._current_page.append('') + self._current_page_size += 1 diff --git a/cogs/utils/userinteraction/scroller.py b/cogs/utils/userinteraction/scroller.py new file mode 100644 index 0000000..71ab7d5 --- /dev/null +++ b/cogs/utils/userinteraction/scroller.py @@ -0,0 +1,141 @@ + +# This was at some point *heavliy* inspired by the paginator implementation by Rapptz for r.Danny +# https://github.com/Rapptz/RoboDanny/blob/b0401e046814f42597c6e0280fef2432cc49cc5d/cogs/utils/paginator.py + +import discord +import asyncio + +from .paginators import BasePaginator, CantScrollException + + +class Scroller: + def __init__(self, ctx, paginator, timeout=120.0, clear_on_timeout=False, clear_on_exit=True, clear_command=True): + + if not isinstance(paginator, BasePaginator): + raise TypeError('Paginator needs to be a subclass of BasePaginator.') + + self.bot = ctx.bot + self.pages = paginator.pages + self.cmdmsg = ctx.message + self.message = ctx.message + self.channel = ctx.channel + self.author = ctx.author + + self.timeout = timeout + self.timeout_delete = clear_on_timeout + self.exit_delete = clear_on_exit + self.clear_command = clear_command + + if len(self.pages) > 1: + self.scrolling = True + else: + self.scrolling = False + self.reaction_emojis = [ + ('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.first_page), + ('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page), + ('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page), + ('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.last_page), + ('❌', self.stop_scrolling), + ] + + if ctx.guild is not None: + self.permissions = self.channel.permissions_for(ctx.guild.me) + else: + self.permissions = self.channel.permissions_for(ctx.bot.user) + + if not self.permissions.embed_links: + raise CantScrollException('Bot does not have embed links permission.') + + if not self.permissions.send_messages: + raise CantScrollException('Bot cannot send messages.') + + if self.scrolling: + # verify we can actually use the pagination session + if not self.permissions.add_reactions: + raise CantScrollException('Bot does not have add reactions permission.') + + if not self.permissions.read_message_history: + raise CantScrollException('Bot does not have Read Message History permission.') + + async def send(self): + self.current_page = 0 + # No embeds to scroll through + if not self.pages: + return + + if not self.scrolling: + return await self.channel.send(embed=self.pages[0]) + + self.message = await self.channel.send(embed=self.pages[0]) + for (reaction, _) in self.reaction_emojis: + if len(self.pages) == 2 and reaction in ('\u23ed', '\u23ee'): + continue + + await self.message.add_reaction(reaction) + + async def scroll(self, page): + if page < 0 or page >= len(self.pages): + return + self.current_page = page + await self.message.edit(embed=self.pages[page]) + + async def first_page(self): + await self.scroll(0) + + async def last_page(self): + await self.scroll(len(self.pages) - 1) + + async def next_page(self): + await self.scroll(self.current_page + 1) + + async def previous_page(self): + await self.scroll(self.current_page - 1) + + async def stop_scrolling(self): + self.scrolling = False + if self.exit_delete: + await self.message.delete() + if self.clear_command: + await self.cmdmsg.delete() + + def react_check(self, reaction, user): + if user is None or user.id != self.author.id: + return False + + if reaction.message.id != self.message.id: + return False + + for (emoji, func) in self.reaction_emojis: + if reaction.emoji == emoji: + self.match = func + return True + return False + + async def start_scrolling(self): + if not self.scrolling: + await self.send() + else: + self.bot.loop.create_task(self.send()) + + while self.scrolling: + try: + reaction, user = await self.bot.wait_for('reaction_add', check=self.react_check, timeout=self.timeout) + except asyncio.TimeoutError: + self.scrolling = False + try: + await self.message.clear_reactions() + if self.timeout_delete: + await self.message.delete() + if self.clear_command: + await self.cmdmsg.delete() + except discord.Forbidden: + pass + finally: + break + + try: + await self.message.remove_reaction(reaction, user) + except discord.Forbidden: + pass + + await self.match() diff --git a/cogs/utils/selector.py b/cogs/utils/userinteraction/selector.py similarity index 99% rename from cogs/utils/selector.py rename to cogs/utils/userinteraction/selector.py index db54d1c..679b7ad 100644 --- a/cogs/utils/selector.py +++ b/cogs/utils/userinteraction/selector.py @@ -4,7 +4,7 @@ import discord import asyncio import inspect -from .paginator import TextPaginator +from .paginators import TextPaginator class Selector(TextPaginator): From 7d99fea0205ad945a6dbcab60e5a37ff6ab6d07c Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 13:21:53 +0200 Subject: [PATCH 04/15] Update readme --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 09f97ec..c8db443 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,10 @@ ## Features -- Translations, get the bot in your preferred langauge! +- Translations, get the bot in your preferred langauge! Works for both commands and replies. - Round Robin style queue, you won't have to wait forever for your songs to play. -- Noice per server customization options. +- Noice per server customization options, including per server localization. - Toit embeds. -- More stuff to come? - Lyrics command that sometimes gives the correct lyrics - DJ roles @@ -17,10 +16,11 @@ 1. Change or copy data/config.yaml.example to config.yaml 2. Create or find a [lavalink](https://github.com/Frederikam/Lavalink) server you can use. -3. Add your bot token and lavalink server. +3. Add your bot token and lavalink server to the bot settings in your config.yaml. 4. Edit any other settings you want. -5. install requirements `python -m pip install -r requirements.txt` -6. run the bot :) +5. (Optional but recommended) Create a virtual environment and activate it. +6. install requirements `python -m pip install -r requirements.txt` +7. run the bot `python bot.py` :) ### Docker From 09844d8292dafa3bdc7cee6f3aad0ebbeed09fdf Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 13:43:14 +0200 Subject: [PATCH 05/15] Refactor code structure --- bot.py | 18 ++++----- {cogs => musicbot/cogs}/cogmanager.py | 4 +- {cogs => musicbot/cogs}/errors.py | 6 +-- musicbot/cogs/helpformatter/__init__.py | 8 ++++ musicbot/cogs/helpformatter/help.py | 32 ++++++++++++++++ .../cogs/helpformatter}/helpformatter.py | 37 +------------------ {cogs => musicbot/cogs}/misc.py | 2 +- {cogs => musicbot/cogs}/music/__init__.py | 2 +- .../cogs}/music/basic_commands.py | 4 +- {cogs => musicbot/cogs}/music/decorators.py | 4 +- {cogs => musicbot/cogs}/music/events.py | 0 .../cogs}/music/extra_commands.py | 4 +- {cogs => musicbot/cogs}/music/music_errors.py | 0 {cogs => musicbot/cogs}/nodemanager.py | 8 ++-- {cogs => musicbot/cogs}/settings.py | 6 +-- {cogs => musicbot}/utils/bot_version.py | 0 {cogs => musicbot}/utils/checks.py | 0 .../utils/localisation/__init__.py | 0 .../utils/localisation/alias.py | 0 .../utils/localisation/localizedcontext.py | 0 .../utils/localisation/localizer/__init__.py | 0 .../localisation/localizer/dict_utils.py | 0 .../utils/localisation/localizer/localizer.py | 0 .../localizer/localizerwrapper.py | 0 {cogs => musicbot}/utils/logger.py | 0 .../utils/mixplayer/__init__.py | 0 .../utils/mixplayer/mixqueue.py | 0 {cogs => musicbot}/utils/mixplayer/player.py | 0 .../utils/settingsmanager/__init__.py | 0 .../utils/settingsmanager/dictmapper.py | 0 .../utils/settingsmanager/settingsmanager.py | 0 {cogs => musicbot}/utils/thumbnailer.py | 0 {cogs => musicbot}/utils/timeformatter.py | 0 .../utils/userinteraction/__init__.py | 0 .../userinteraction/paginators/__init__.py | 0 .../paginators/basepaginator.py | 0 .../paginators/fieldpaginator.py | 0 .../paginators/helppaginator.py | 0 .../paginators/queuepaginator.py | 0 .../paginators/textpaginator.py | 0 .../utils/userinteraction/scroller.py | 0 .../utils/userinteraction/selector.py | 0 42 files changed, 70 insertions(+), 65 deletions(-) rename {cogs => musicbot/cogs}/cogmanager.py (96%) rename {cogs => musicbot/cogs}/errors.py (96%) create mode 100644 musicbot/cogs/helpformatter/__init__.py create mode 100644 musicbot/cogs/helpformatter/help.py rename {cogs => musicbot/cogs/helpformatter}/helpformatter.py (76%) rename {cogs => musicbot/cogs}/misc.py (99%) rename {cogs => musicbot/cogs}/music/__init__.py (99%) rename {cogs => musicbot/cogs}/music/basic_commands.py (99%) rename {cogs => musicbot/cogs}/music/decorators.py (98%) rename {cogs => musicbot/cogs}/music/events.py (100%) rename {cogs => musicbot/cogs}/music/extra_commands.py (99%) rename {cogs => musicbot/cogs}/music/music_errors.py (100%) rename {cogs => musicbot/cogs}/nodemanager.py (97%) rename {cogs => musicbot/cogs}/settings.py (98%) rename {cogs => musicbot}/utils/bot_version.py (100%) rename {cogs => musicbot}/utils/checks.py (100%) rename {cogs => musicbot}/utils/localisation/__init__.py (100%) rename {cogs => musicbot}/utils/localisation/alias.py (100%) rename {cogs => musicbot}/utils/localisation/localizedcontext.py (100%) rename {cogs => musicbot}/utils/localisation/localizer/__init__.py (100%) rename {cogs => musicbot}/utils/localisation/localizer/dict_utils.py (100%) rename {cogs => musicbot}/utils/localisation/localizer/localizer.py (100%) rename {cogs => musicbot}/utils/localisation/localizer/localizerwrapper.py (100%) rename {cogs => musicbot}/utils/logger.py (100%) rename {cogs => musicbot}/utils/mixplayer/__init__.py (100%) rename {cogs => musicbot}/utils/mixplayer/mixqueue.py (100%) rename {cogs => musicbot}/utils/mixplayer/player.py (100%) rename {cogs => musicbot}/utils/settingsmanager/__init__.py (100%) rename {cogs => musicbot}/utils/settingsmanager/dictmapper.py (100%) rename {cogs => musicbot}/utils/settingsmanager/settingsmanager.py (100%) rename {cogs => musicbot}/utils/thumbnailer.py (100%) rename {cogs => musicbot}/utils/timeformatter.py (100%) rename {cogs => musicbot}/utils/userinteraction/__init__.py (100%) rename {cogs => musicbot}/utils/userinteraction/paginators/__init__.py (100%) rename {cogs => musicbot}/utils/userinteraction/paginators/basepaginator.py (100%) rename {cogs => musicbot}/utils/userinteraction/paginators/fieldpaginator.py (100%) rename {cogs => musicbot}/utils/userinteraction/paginators/helppaginator.py (100%) rename {cogs => musicbot}/utils/userinteraction/paginators/queuepaginator.py (100%) rename {cogs => musicbot}/utils/userinteraction/paginators/textpaginator.py (100%) rename {cogs => musicbot}/utils/userinteraction/scroller.py (100%) rename {cogs => musicbot}/utils/userinteraction/selector.py (100%) diff --git a/bot.py b/bot.py index dc586dc..57f5224 100644 --- a/bot.py +++ b/bot.py @@ -13,20 +13,20 @@ import aiohttp import yaml # Bot Utilities -from cogs.utils.localisation import Aliaser, LocalizedContext, Localizer, LocalizerWrapper -from cogs.utils.logger import BotLogger -from cogs.utils.settingsmanager import Settings +from musicbot.utils.localisation import Aliaser, LocalizedContext, Localizer, LocalizerWrapper +from musicbot.utils.logger import BotLogger +from musicbot.utils.settingsmanager import Settings initial_extensions = [ - 'cogs.errors', - 'cogs.cogmanager', - 'cogs.settings', - 'cogs.misc', - 'cogs.helpformatter' + 'musicbot.cogs.errors', + 'musicbot.cogs.cogmanager', + 'musicbot.cogs.settings', + 'musicbot.cogs.misc', + 'musicbot.cogs.helpformatter' ] on_ready_extensions = [ - 'cogs.nodemanager' + 'musicbot.cogs.nodemanager' ] diff --git a/cogs/cogmanager.py b/musicbot/cogs/cogmanager.py similarity index 96% rename from cogs/cogmanager.py rename to musicbot/cogs/cogmanager.py index b20eb17..3b6dd64 100644 --- a/cogs/cogmanager.py +++ b/musicbot/cogs/cogmanager.py @@ -4,8 +4,8 @@ from discord.ext import commands import traceback # Bot Utilities -from cogs.helpformatter import commandhelper -from cogs.utils.userinteraction import Scroller +from .helpformatter import commandhelper +from ..utils.userinteraction import Scroller class CogManager(commands.Cog): diff --git a/cogs/errors.py b/musicbot/cogs/errors.py similarity index 96% rename from cogs/errors.py rename to musicbot/cogs/errors.py index 126f395..1ae13b7 100644 --- a/cogs/errors.py +++ b/musicbot/cogs/errors.py @@ -4,11 +4,11 @@ from discord.ext import commands import traceback -from cogs.music.music_errors import WrongTextChannelError, WrongVoiceChannelError +from .music.music_errors import WrongTextChannelError, WrongVoiceChannelError # Bot Utilities -from cogs.helpformatter import commandhelper -from cogs.utils.userinteraction import Scroller +from .helpformatter import commandhelper +from ..utils.userinteraction import Scroller class Errors(commands.Cog): diff --git a/musicbot/cogs/helpformatter/__init__.py b/musicbot/cogs/helpformatter/__init__.py new file mode 100644 index 0000000..e8b6d5c --- /dev/null +++ b/musicbot/cogs/helpformatter/__init__.py @@ -0,0 +1,8 @@ +from .help import Help +from .helpformatter import commandhelper + +__all__ = ['Help', 'commandHelper'] + +def setup(bot): + bot.remove_command("help") + bot.add_cog(Help(bot)) \ No newline at end of file diff --git a/musicbot/cogs/helpformatter/help.py b/musicbot/cogs/helpformatter/help.py new file mode 100644 index 0000000..aa3e313 --- /dev/null +++ b/musicbot/cogs/helpformatter/help.py @@ -0,0 +1,32 @@ +from discord.ext import commands + + +class Help(commands.Cog): + """Help command""" + def __init__(self, bot): + self.bot = bot + + @commands.command(hidden=True) + async def help(self, ctx): # Takes no args because reasons(using the view directly) + ctx.view.skip_ws() + v = ctx.view + invoker = v.buffer[v.index:v.end] + ctx = self.bot.aliaser.get_subcommand(ctx, group=None, parents=[]) + command = v.buffer[v.index:v.end] + + ctx = prefix_cleaner(ctx) + + if not command: + paginator = await helper(ctx) + + if command: + thing = ctx.bot.get_cog(command) or ctx.bot.get_command(command) + if not thing: + return await ctx.send(ctx.localizer.format_str("{notcommand}", _command=command)) + if isinstance(thing, commands.Command): + paginator = commandhelper(ctx, thing, invoker) + else: + paginator = await coghelper(ctx, thing) + + scroller = Scroller(ctx, paginator) + await scroller.start_scrolling() diff --git a/cogs/helpformatter.py b/musicbot/cogs/helpformatter/helpformatter.py similarity index 76% rename from cogs/helpformatter.py rename to musicbot/cogs/helpformatter/helpformatter.py index 875e34b..669842e 100644 --- a/cogs/helpformatter.py +++ b/musicbot/cogs/helpformatter/helpformatter.py @@ -4,7 +4,7 @@ from discord.ext import commands import re # Bot Utilities -from .utils.userinteraction import HelpPaginator, Scroller +from ...utils.userinteraction import HelpPaginator, Scroller usermention = r"<@!?\d{17,19}>" @@ -111,38 +111,3 @@ def prefix_cleaner(ctx): ctx.prefix = pref return ctx - -class Help(commands.Cog): - """Help command""" - def __init__(self, bot): - self.bot = bot - - @commands.command(hidden=True) - async def help(self, ctx): # Takes no args because reasons(using the view directly) - ctx.view.skip_ws() - v = ctx.view - invoker = v.buffer[v.index:v.end] - ctx = self.bot.aliaser.get_subcommand(ctx, group=None, parents=[]) - command = v.buffer[v.index:v.end] - - ctx = prefix_cleaner(ctx) - - if not command: - paginator = await helper(ctx) - - if command: - thing = ctx.bot.get_cog(command) or ctx.bot.get_command(command) - if not thing: - return await ctx.send(ctx.localizer.format_str("{notcommand}", _command=command)) - if isinstance(thing, commands.Command): - paginator = commandhelper(ctx, thing, invoker) - else: - paginator = await coghelper(ctx, thing) - - scroller = Scroller(ctx, paginator) - await scroller.start_scrolling() - - -def setup(bot): - bot.remove_command("help") - bot.add_cog(Help(bot)) diff --git a/cogs/misc.py b/musicbot/cogs/misc.py similarity index 99% rename from cogs/misc.py rename to musicbot/cogs/misc.py index 630f1f5..4182787 100644 --- a/cogs/misc.py +++ b/musicbot/cogs/misc.py @@ -7,7 +7,7 @@ import platform import time # Bot Utilities -from cogs.utils import bot_version +from ..utils import bot_version class Misc(commands.Cog): diff --git a/cogs/music/__init__.py b/musicbot/cogs/music/__init__.py similarity index 99% rename from cogs/music/__init__.py rename to musicbot/cogs/music/__init__.py index 4bd0ba4..21641f5 100644 --- a/cogs/music/__init__.py +++ b/musicbot/cogs/music/__init__.py @@ -3,7 +3,7 @@ import discord import lavalink from discord.ext import commands -from ..utils import thumbnailer, timeformatter +from ...utils import thumbnailer, timeformatter from .music_errors import WrongTextChannelError diff --git a/cogs/music/basic_commands.py b/musicbot/cogs/music/basic_commands.py similarity index 99% rename from cogs/music/basic_commands.py rename to musicbot/cogs/music/basic_commands.py index 5ec061a..e217c84 100644 --- a/cogs/music/basic_commands.py +++ b/musicbot/cogs/music/basic_commands.py @@ -9,8 +9,8 @@ from discord.ext import commands import asyncio import re -from ..utils import checks, timeformatter -from ..utils.userinteraction import QueuePaginator, Scroller, Selector +from ...utils import checks, timeformatter +from ...utils.userinteraction import QueuePaginator, Scroller, Selector from .decorators import require_playing, require_queue, require_voice_connection, voteable time_rx = re.compile('[0-9]+') diff --git a/cogs/music/decorators.py b/musicbot/cogs/music/decorators.py similarity index 98% rename from cogs/music/decorators.py rename to musicbot/cogs/music/decorators.py index 0b503ba..9b77471 100644 --- a/cogs/music/decorators.py +++ b/musicbot/cogs/music/decorators.py @@ -7,9 +7,9 @@ import functools import inspect import math -from cogs.music.music_errors import WrongVoiceChannelError +from .music_errors import WrongVoiceChannelError -from ..utils.checks import is_dj +from ...utils.checks import is_dj def require_voice_connection(should_connect=False): diff --git a/cogs/music/events.py b/musicbot/cogs/music/events.py similarity index 100% rename from cogs/music/events.py rename to musicbot/cogs/music/events.py diff --git a/cogs/music/extra_commands.py b/musicbot/cogs/music/extra_commands.py similarity index 99% rename from cogs/music/extra_commands.py rename to musicbot/cogs/music/extra_commands.py index 335c122..977e8b4 100644 --- a/cogs/music/extra_commands.py +++ b/musicbot/cogs/music/extra_commands.py @@ -14,8 +14,8 @@ import urllib from bs4 import BeautifulSoup -from ..utils import checks -from ..utils.userinteraction import Scroller, TextPaginator +from ...utils import checks +from ...utils.userinteraction import Scroller, TextPaginator from .decorators import require_playing, require_voice_connection, voteable diff --git a/cogs/music/music_errors.py b/musicbot/cogs/music/music_errors.py similarity index 100% rename from cogs/music/music_errors.py rename to musicbot/cogs/music/music_errors.py diff --git a/cogs/nodemanager.py b/musicbot/cogs/nodemanager.py similarity index 97% rename from cogs/nodemanager.py rename to musicbot/cogs/nodemanager.py index 075b371..9e9ea17 100644 --- a/cogs/nodemanager.py +++ b/musicbot/cogs/nodemanager.py @@ -8,9 +8,9 @@ import codecs import yaml # Bot Utilities -from cogs.helpformatter import commandhelper -from cogs.utils.userinteraction import Scroller -from .utils.mixplayer import MixPlayer +from .helpformatter import commandhelper +from ..utils.userinteraction import Scroller +from ..utils.mixplayer import MixPlayer class NodeManager(commands.Cog): @@ -20,7 +20,7 @@ class NodeManager(commands.Cog): self.logger = self.bot.main_logger.bot_logger.getChild("NodeManager") music_extensions = [ - 'cogs.music', + 'musicbot.cogs.music', ] if not hasattr(bot, 'lavalink'): diff --git a/cogs/settings.py b/musicbot/cogs/settings.py similarity index 98% rename from cogs/settings.py rename to musicbot/cogs/settings.py index 414e962..7fdf1cc 100644 --- a/cogs/settings.py +++ b/musicbot/cogs/settings.py @@ -3,9 +3,9 @@ import discord from discord.ext import commands # Bot Utilities -from cogs.helpformatter import commandhelper -from cogs.utils import checks -from cogs.utils.userinteraction import Scroller +from .helpformatter import commandhelper +from ..utils import checks +from ..utils.userinteraction import Scroller class Settings(commands.Cog): diff --git a/cogs/utils/bot_version.py b/musicbot/utils/bot_version.py similarity index 100% rename from cogs/utils/bot_version.py rename to musicbot/utils/bot_version.py diff --git a/cogs/utils/checks.py b/musicbot/utils/checks.py similarity index 100% rename from cogs/utils/checks.py rename to musicbot/utils/checks.py diff --git a/cogs/utils/localisation/__init__.py b/musicbot/utils/localisation/__init__.py similarity index 100% rename from cogs/utils/localisation/__init__.py rename to musicbot/utils/localisation/__init__.py diff --git a/cogs/utils/localisation/alias.py b/musicbot/utils/localisation/alias.py similarity index 100% rename from cogs/utils/localisation/alias.py rename to musicbot/utils/localisation/alias.py diff --git a/cogs/utils/localisation/localizedcontext.py b/musicbot/utils/localisation/localizedcontext.py similarity index 100% rename from cogs/utils/localisation/localizedcontext.py rename to musicbot/utils/localisation/localizedcontext.py diff --git a/cogs/utils/localisation/localizer/__init__.py b/musicbot/utils/localisation/localizer/__init__.py similarity index 100% rename from cogs/utils/localisation/localizer/__init__.py rename to musicbot/utils/localisation/localizer/__init__.py diff --git a/cogs/utils/localisation/localizer/dict_utils.py b/musicbot/utils/localisation/localizer/dict_utils.py similarity index 100% rename from cogs/utils/localisation/localizer/dict_utils.py rename to musicbot/utils/localisation/localizer/dict_utils.py diff --git a/cogs/utils/localisation/localizer/localizer.py b/musicbot/utils/localisation/localizer/localizer.py similarity index 100% rename from cogs/utils/localisation/localizer/localizer.py rename to musicbot/utils/localisation/localizer/localizer.py diff --git a/cogs/utils/localisation/localizer/localizerwrapper.py b/musicbot/utils/localisation/localizer/localizerwrapper.py similarity index 100% rename from cogs/utils/localisation/localizer/localizerwrapper.py rename to musicbot/utils/localisation/localizer/localizerwrapper.py diff --git a/cogs/utils/logger.py b/musicbot/utils/logger.py similarity index 100% rename from cogs/utils/logger.py rename to musicbot/utils/logger.py diff --git a/cogs/utils/mixplayer/__init__.py b/musicbot/utils/mixplayer/__init__.py similarity index 100% rename from cogs/utils/mixplayer/__init__.py rename to musicbot/utils/mixplayer/__init__.py diff --git a/cogs/utils/mixplayer/mixqueue.py b/musicbot/utils/mixplayer/mixqueue.py similarity index 100% rename from cogs/utils/mixplayer/mixqueue.py rename to musicbot/utils/mixplayer/mixqueue.py diff --git a/cogs/utils/mixplayer/player.py b/musicbot/utils/mixplayer/player.py similarity index 100% rename from cogs/utils/mixplayer/player.py rename to musicbot/utils/mixplayer/player.py diff --git a/cogs/utils/settingsmanager/__init__.py b/musicbot/utils/settingsmanager/__init__.py similarity index 100% rename from cogs/utils/settingsmanager/__init__.py rename to musicbot/utils/settingsmanager/__init__.py diff --git a/cogs/utils/settingsmanager/dictmapper.py b/musicbot/utils/settingsmanager/dictmapper.py similarity index 100% rename from cogs/utils/settingsmanager/dictmapper.py rename to musicbot/utils/settingsmanager/dictmapper.py diff --git a/cogs/utils/settingsmanager/settingsmanager.py b/musicbot/utils/settingsmanager/settingsmanager.py similarity index 100% rename from cogs/utils/settingsmanager/settingsmanager.py rename to musicbot/utils/settingsmanager/settingsmanager.py diff --git a/cogs/utils/thumbnailer.py b/musicbot/utils/thumbnailer.py similarity index 100% rename from cogs/utils/thumbnailer.py rename to musicbot/utils/thumbnailer.py diff --git a/cogs/utils/timeformatter.py b/musicbot/utils/timeformatter.py similarity index 100% rename from cogs/utils/timeformatter.py rename to musicbot/utils/timeformatter.py diff --git a/cogs/utils/userinteraction/__init__.py b/musicbot/utils/userinteraction/__init__.py similarity index 100% rename from cogs/utils/userinteraction/__init__.py rename to musicbot/utils/userinteraction/__init__.py diff --git a/cogs/utils/userinteraction/paginators/__init__.py b/musicbot/utils/userinteraction/paginators/__init__.py similarity index 100% rename from cogs/utils/userinteraction/paginators/__init__.py rename to musicbot/utils/userinteraction/paginators/__init__.py diff --git a/cogs/utils/userinteraction/paginators/basepaginator.py b/musicbot/utils/userinteraction/paginators/basepaginator.py similarity index 100% rename from cogs/utils/userinteraction/paginators/basepaginator.py rename to musicbot/utils/userinteraction/paginators/basepaginator.py diff --git a/cogs/utils/userinteraction/paginators/fieldpaginator.py b/musicbot/utils/userinteraction/paginators/fieldpaginator.py similarity index 100% rename from cogs/utils/userinteraction/paginators/fieldpaginator.py rename to musicbot/utils/userinteraction/paginators/fieldpaginator.py diff --git a/cogs/utils/userinteraction/paginators/helppaginator.py b/musicbot/utils/userinteraction/paginators/helppaginator.py similarity index 100% rename from cogs/utils/userinteraction/paginators/helppaginator.py rename to musicbot/utils/userinteraction/paginators/helppaginator.py diff --git a/cogs/utils/userinteraction/paginators/queuepaginator.py b/musicbot/utils/userinteraction/paginators/queuepaginator.py similarity index 100% rename from cogs/utils/userinteraction/paginators/queuepaginator.py rename to musicbot/utils/userinteraction/paginators/queuepaginator.py diff --git a/cogs/utils/userinteraction/paginators/textpaginator.py b/musicbot/utils/userinteraction/paginators/textpaginator.py similarity index 100% rename from cogs/utils/userinteraction/paginators/textpaginator.py rename to musicbot/utils/userinteraction/paginators/textpaginator.py diff --git a/cogs/utils/userinteraction/scroller.py b/musicbot/utils/userinteraction/scroller.py similarity index 100% rename from cogs/utils/userinteraction/scroller.py rename to musicbot/utils/userinteraction/scroller.py diff --git a/cogs/utils/userinteraction/selector.py b/musicbot/utils/userinteraction/selector.py similarity index 100% rename from cogs/utils/userinteraction/selector.py rename to musicbot/utils/userinteraction/selector.py From 10af75766d47c48199b7192f8f494ba0adb4358d Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 13:53:01 +0200 Subject: [PATCH 06/15] Fix imports --- musicbot/cogs/helpformatter/__init__.py | 5 +++-- musicbot/cogs/helpformatter/help.py | 1 + musicbot/cogs/helpformatter/helpformatter.py | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/musicbot/cogs/helpformatter/__init__.py b/musicbot/cogs/helpformatter/__init__.py index e8b6d5c..4643ce4 100644 --- a/musicbot/cogs/helpformatter/__init__.py +++ b/musicbot/cogs/helpformatter/__init__.py @@ -1,8 +1,9 @@ from .help import Help from .helpformatter import commandhelper -__all__ = ['Help', 'commandHelper'] +__all__ = ['Help', 'commandhelper'] + def setup(bot): bot.remove_command("help") - bot.add_cog(Help(bot)) \ No newline at end of file + bot.add_cog(Help(bot)) diff --git a/musicbot/cogs/helpformatter/help.py b/musicbot/cogs/helpformatter/help.py index aa3e313..5d0a6a2 100644 --- a/musicbot/cogs/helpformatter/help.py +++ b/musicbot/cogs/helpformatter/help.py @@ -1,4 +1,5 @@ from discord.ext import commands +from .helpformatter import prefix_cleaner, helper, commandhelper, coghelper, Scroller class Help(commands.Cog): diff --git a/musicbot/cogs/helpformatter/helpformatter.py b/musicbot/cogs/helpformatter/helpformatter.py index 669842e..81f28b8 100644 --- a/musicbot/cogs/helpformatter/helpformatter.py +++ b/musicbot/cogs/helpformatter/helpformatter.py @@ -4,7 +4,7 @@ from discord.ext import commands import re # Bot Utilities -from ...utils.userinteraction import HelpPaginator, Scroller +from ...utils.userinteraction import HelpPaginator usermention = r"<@!?\d{17,19}>" @@ -110,4 +110,3 @@ def prefix_cleaner(ctx): pref = pref[0] ctx.prefix = pref return ctx - From 4e6cc6a56391e55aecc21c5e9a392f218e4a4503 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 13:54:48 +0200 Subject: [PATCH 07/15] isort --- bot.py | 1 - musicbot/cogs/cogmanager.py | 3 +-- musicbot/cogs/errors.py | 6 ++---- musicbot/cogs/helpformatter/help.py | 4 +++- musicbot/cogs/helpformatter/helpformatter.py | 1 - musicbot/cogs/misc.py | 1 - musicbot/cogs/music/decorators.py | 3 +-- musicbot/cogs/nodemanager.py | 6 +++--- musicbot/cogs/settings.py | 3 +-- musicbot/utils/localisation/__init__.py | 2 +- musicbot/utils/localisation/localizer/localizer.py | 1 - musicbot/utils/mixplayer/player.py | 3 +-- musicbot/utils/settingsmanager/settingsmanager.py | 1 + musicbot/utils/userinteraction/__init__.py | 2 +- musicbot/utils/userinteraction/paginators/__init__.py | 8 ++++---- .../utils/userinteraction/paginators/fieldpaginator.py | 2 ++ .../utils/userinteraction/paginators/helppaginator.py | 2 ++ .../utils/userinteraction/paginators/queuepaginator.py | 2 ++ musicbot/utils/userinteraction/scroller.py | 2 ++ 19 files changed, 27 insertions(+), 26 deletions(-) diff --git a/bot.py b/bot.py index 57f5224..e917201 100644 --- a/bot.py +++ b/bot.py @@ -12,7 +12,6 @@ from argparse import ArgumentParser, RawTextHelpFormatter import aiohttp import yaml -# Bot Utilities from musicbot.utils.localisation import Aliaser, LocalizedContext, Localizer, LocalizerWrapper from musicbot.utils.logger import BotLogger from musicbot.utils.settingsmanager import Settings diff --git a/musicbot/cogs/cogmanager.py b/musicbot/cogs/cogmanager.py index 3b6dd64..809f393 100644 --- a/musicbot/cogs/cogmanager.py +++ b/musicbot/cogs/cogmanager.py @@ -3,9 +3,8 @@ from discord.ext import commands import traceback -# Bot Utilities -from .helpformatter import commandhelper from ..utils.userinteraction import Scroller +from .helpformatter import commandhelper class CogManager(commands.Cog): diff --git a/musicbot/cogs/errors.py b/musicbot/cogs/errors.py index 1ae13b7..1fb2719 100644 --- a/musicbot/cogs/errors.py +++ b/musicbot/cogs/errors.py @@ -4,11 +4,9 @@ from discord.ext import commands import traceback -from .music.music_errors import WrongTextChannelError, WrongVoiceChannelError - -# Bot Utilities -from .helpformatter import commandhelper from ..utils.userinteraction import Scroller +from .helpformatter import commandhelper +from .music.music_errors import WrongTextChannelError, WrongVoiceChannelError class Errors(commands.Cog): diff --git a/musicbot/cogs/helpformatter/help.py b/musicbot/cogs/helpformatter/help.py index 5d0a6a2..e049196 100644 --- a/musicbot/cogs/helpformatter/help.py +++ b/musicbot/cogs/helpformatter/help.py @@ -1,5 +1,7 @@ +# Discord Packages from discord.ext import commands -from .helpformatter import prefix_cleaner, helper, commandhelper, coghelper, Scroller + +from .helpformatter import Scroller, coghelper, commandhelper, helper, prefix_cleaner class Help(commands.Cog): diff --git a/musicbot/cogs/helpformatter/helpformatter.py b/musicbot/cogs/helpformatter/helpformatter.py index 81f28b8..62ec5b0 100644 --- a/musicbot/cogs/helpformatter/helpformatter.py +++ b/musicbot/cogs/helpformatter/helpformatter.py @@ -3,7 +3,6 @@ from discord.ext import commands import re -# Bot Utilities from ...utils.userinteraction import HelpPaginator usermention = r"<@!?\d{17,19}>" diff --git a/musicbot/cogs/misc.py b/musicbot/cogs/misc.py index 4182787..b24d968 100644 --- a/musicbot/cogs/misc.py +++ b/musicbot/cogs/misc.py @@ -6,7 +6,6 @@ from lavalink import __version__ as LavalinkVersion import platform import time -# Bot Utilities from ..utils import bot_version diff --git a/musicbot/cogs/music/decorators.py b/musicbot/cogs/music/decorators.py index 9b77471..5b573bb 100644 --- a/musicbot/cogs/music/decorators.py +++ b/musicbot/cogs/music/decorators.py @@ -7,9 +7,8 @@ import functools import inspect import math -from .music_errors import WrongVoiceChannelError - from ...utils.checks import is_dj +from .music_errors import WrongVoiceChannelError def require_voice_connection(should_connect=False): diff --git a/musicbot/cogs/nodemanager.py b/musicbot/cogs/nodemanager.py index 9e9ea17..adac193 100644 --- a/musicbot/cogs/nodemanager.py +++ b/musicbot/cogs/nodemanager.py @@ -5,12 +5,12 @@ from discord.ext import commands from lavalink import Node import codecs + import yaml -# Bot Utilities -from .helpformatter import commandhelper -from ..utils.userinteraction import Scroller from ..utils.mixplayer import MixPlayer +from ..utils.userinteraction import Scroller +from .helpformatter import commandhelper class NodeManager(commands.Cog): diff --git a/musicbot/cogs/settings.py b/musicbot/cogs/settings.py index 7fdf1cc..e4e920e 100644 --- a/musicbot/cogs/settings.py +++ b/musicbot/cogs/settings.py @@ -2,10 +2,9 @@ import discord from discord.ext import commands -# Bot Utilities -from .helpformatter import commandhelper from ..utils import checks from ..utils.userinteraction import Scroller +from .helpformatter import commandhelper class Settings(commands.Cog): diff --git a/musicbot/utils/localisation/__init__.py b/musicbot/utils/localisation/__init__.py index 696da4c..7ee3eec 100644 --- a/musicbot/utils/localisation/__init__.py +++ b/musicbot/utils/localisation/__init__.py @@ -1,5 +1,5 @@ from .alias import Aliaser -from .localizer import LocalizerWrapper, Localizer from .localizedcontext import LocalizedContext +from .localizer import Localizer, LocalizerWrapper __all__ = ['Aliaser', 'LocalizerWrapper', 'Localizer', 'LocalizedContext'] diff --git a/musicbot/utils/localisation/localizer/localizer.py b/musicbot/utils/localisation/localizer/localizer.py index a61beb2..f6237f5 100644 --- a/musicbot/utils/localisation/localizer/localizer.py +++ b/musicbot/utils/localisation/localizer/localizer.py @@ -8,7 +8,6 @@ from os import path import yaml -# Bot Utilities from .dict_utils import SafeDict, flatten """ diff --git a/musicbot/utils/mixplayer/player.py b/musicbot/utils/mixplayer/player.py index 4a5f4ac..8d051ad 100644 --- a/musicbot/utils/mixplayer/player.py +++ b/musicbot/utils/mixplayer/player.py @@ -1,11 +1,10 @@ -import typing - # Discord Packages import discord import lavalink from lavalink import AudioTrack, DefaultPlayer, Node from lavalink.events import QueueEndEvent, TrackEndEvent, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent +import typing from .mixqueue import MixQueue diff --git a/musicbot/utils/settingsmanager/settingsmanager.py b/musicbot/utils/settingsmanager/settingsmanager.py index ddbc29a..5a15165 100644 --- a/musicbot/utils/settingsmanager/settingsmanager.py +++ b/musicbot/utils/settingsmanager/settingsmanager.py @@ -6,6 +6,7 @@ import locale as localee import os import yaml + from .dictmapper import DictMapper diff --git a/musicbot/utils/userinteraction/__init__.py b/musicbot/utils/userinteraction/__init__.py index 5397e1b..80b0043 100644 --- a/musicbot/utils/userinteraction/__init__.py +++ b/musicbot/utils/userinteraction/__init__.py @@ -1,6 +1,6 @@ +from .paginators import BasePaginator, CantScrollException, FieldPaginator, HelpPaginator, QueuePaginator, TextPaginator from .scroller import Scroller from .selector import Selector -from .paginators import BasePaginator, TextPaginator, FieldPaginator, HelpPaginator, QueuePaginator, CantScrollException __all__ = ['Scroller', 'Selector', 'QueuePaginator', 'HelpPaginator', 'TextPaginator', 'FieldPaginator', 'CantScrollException', 'BasePaginator'] diff --git a/musicbot/utils/userinteraction/paginators/__init__.py b/musicbot/utils/userinteraction/paginators/__init__.py index a335ea8..c5412aa 100644 --- a/musicbot/utils/userinteraction/paginators/__init__.py +++ b/musicbot/utils/userinteraction/paginators/__init__.py @@ -1,7 +1,7 @@ -from .queuepaginator import QueuePaginator -from .helppaginator import HelpPaginator -from .textpaginator import TextPaginator +from .basepaginator import BasePaginator, CantScrollException from .fieldpaginator import FieldPaginator -from .basepaginator import CantScrollException, BasePaginator +from .helppaginator import HelpPaginator +from .queuepaginator import QueuePaginator +from .textpaginator import TextPaginator __all__ = ['QueuePaginator', 'HelpPaginator', 'TextPaginator', 'FieldPaginator', 'CantScrollException', 'BasePaginator'] diff --git a/musicbot/utils/userinteraction/paginators/fieldpaginator.py b/musicbot/utils/userinteraction/paginators/fieldpaginator.py index 979a044..0398f5d 100644 --- a/musicbot/utils/userinteraction/paginators/fieldpaginator.py +++ b/musicbot/utils/userinteraction/paginators/fieldpaginator.py @@ -1,4 +1,6 @@ +# Discord Packages import discord + from .basepaginator import BasePaginator diff --git a/musicbot/utils/userinteraction/paginators/helppaginator.py b/musicbot/utils/userinteraction/paginators/helppaginator.py index 67a4fab..026851a 100644 --- a/musicbot/utils/userinteraction/paginators/helppaginator.py +++ b/musicbot/utils/userinteraction/paginators/helppaginator.py @@ -1,4 +1,6 @@ +# Discord Packages import discord + from .fieldpaginator import FieldPaginator diff --git a/musicbot/utils/userinteraction/paginators/queuepaginator.py b/musicbot/utils/userinteraction/paginators/queuepaginator.py index 72d1949..637a7e1 100644 --- a/musicbot/utils/userinteraction/paginators/queuepaginator.py +++ b/musicbot/utils/userinteraction/paginators/queuepaginator.py @@ -1,4 +1,6 @@ +# Discord Packages import discord + from .textpaginator import TextPaginator diff --git a/musicbot/utils/userinteraction/scroller.py b/musicbot/utils/userinteraction/scroller.py index 71ab7d5..7fcdc09 100644 --- a/musicbot/utils/userinteraction/scroller.py +++ b/musicbot/utils/userinteraction/scroller.py @@ -2,7 +2,9 @@ # This was at some point *heavliy* inspired by the paginator implementation by Rapptz for r.Danny # https://github.com/Rapptz/RoboDanny/blob/b0401e046814f42597c6e0280fef2432cc49cc5d/cogs/utils/paginator.py +# Discord Packages import discord + import asyncio from .paginators import BasePaginator, CantScrollException From 11d1de79ff0e700f968172ae3338db98d068844d Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 13:59:39 +0200 Subject: [PATCH 08/15] Update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5df49ca..62a4b89 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,7 +5,7 @@ jobs: flake8: runs-on: ubuntu-latest env: - CheckFiles: "bot.py cogs/" + CheckFiles: "bot.py musicbot/" steps: - uses: actions/checkout@v2 From 5e433dfbb989206993c23851d3706f089aaa97f3 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 14:32:28 +0200 Subject: [PATCH 09/15] Fix import in help cog --- musicbot/cogs/helpformatter/help.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/musicbot/cogs/helpformatter/help.py b/musicbot/cogs/helpformatter/help.py index e049196..5040931 100644 --- a/musicbot/cogs/helpformatter/help.py +++ b/musicbot/cogs/helpformatter/help.py @@ -1,7 +1,8 @@ # Discord Packages from discord.ext import commands -from .helpformatter import Scroller, coghelper, commandhelper, helper, prefix_cleaner +from .helpformatter import coghelper, commandhelper, helper, prefix_cleaner +from ...utils.userinteraction import Scroller class Help(commands.Cog): From f06d324de20bd2e91308381ea911b5c32e435133 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 14:42:24 +0200 Subject: [PATCH 10/15] Add help for forcedisconnect --- localization/en_en/commands.yaml | 3 +++ musicbot/cogs/helpformatter/helpformatter.py | 1 + requirements.txt | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/localization/en_en/commands.yaml b/localization/en_en/commands.yaml index 03341f4..8d7db3b 100644 --- a/localization/en_en/commands.yaml +++ b/localization/en_en/commands.yaml @@ -91,6 +91,9 @@ scrub: reconnect: aliases: [rc] description: 'disconnects then reconnects the bot in case of bugged songs' +forcedisconnect: + aliases: [fd] + description: 'Forces the bot to disconnect' forceplay: aliases: [forceplay, fp] args: '' # This is just a cosmetic representation of the arguments. diff --git a/musicbot/cogs/helpformatter/helpformatter.py b/musicbot/cogs/helpformatter/helpformatter.py index 62ec5b0..81f28b8 100644 --- a/musicbot/cogs/helpformatter/helpformatter.py +++ b/musicbot/cogs/helpformatter/helpformatter.py @@ -3,6 +3,7 @@ from discord.ext import commands import re +# Bot Utilities from ...utils.userinteraction import HelpPaginator usermention = r"<@!?\d{17,19}>" diff --git a/requirements.txt b/requirements.txt index f9ef2f5..4427145 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ discord.py == 1.7.* -lavalink +lavalink = 3.*.* asyncio pyyaml BeautifulSoup4 From cadcfdeb6a77ea5c639ced81f1533a8627087738 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 14:43:46 +0200 Subject: [PATCH 11/15] Update bot version path in build workflow --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 62a4b89..d100b61 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,18 +64,18 @@ jobs: if: github.ref == 'refs/heads/master' id: tagger run: | - version=$(grep -i bot_version cogs/utils/bot_version.py | cut -d" " -f3 | tr -d \") + version=$(grep -i bot_version musicbot/cogs/utils/bot_version.py | cut -d" " -f3 | tr -d \") a=(${version//./ }) ((a[2]++)) new_version=$(echo "${a[0]}.${a[1]}.${a[2]}") - sed -i "s/${version}/${new_version}/g" cogs/utils/bot_version.py + sed -i "s/${version}/${new_version}/g" musicbot/cogs/utils/bot_version.py echo "::set-output name=tag::${new_version}" - name: Push changed files, and tags if: github.ref == 'refs/heads/master' uses: EndBug/add-and-commit@v4 with: - add: cogs/utils/bot_version.py + add: musicbot/cogs/utils/bot_version.py author_name: MarlinBotCode message: Bump Version tag: v${{ steps.tagger.outputs.tag }} From 749bac3939eaa0efd035160e223f751a69745d0c Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 14:44:52 +0200 Subject: [PATCH 12/15] isort --- musicbot/cogs/helpformatter/help.py | 2 +- musicbot/cogs/helpformatter/helpformatter.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/musicbot/cogs/helpformatter/help.py b/musicbot/cogs/helpformatter/help.py index 5040931..eff2cbe 100644 --- a/musicbot/cogs/helpformatter/help.py +++ b/musicbot/cogs/helpformatter/help.py @@ -1,8 +1,8 @@ # Discord Packages from discord.ext import commands -from .helpformatter import coghelper, commandhelper, helper, prefix_cleaner from ...utils.userinteraction import Scroller +from .helpformatter import coghelper, commandhelper, helper, prefix_cleaner class Help(commands.Cog): diff --git a/musicbot/cogs/helpformatter/helpformatter.py b/musicbot/cogs/helpformatter/helpformatter.py index 81f28b8..62ec5b0 100644 --- a/musicbot/cogs/helpformatter/helpformatter.py +++ b/musicbot/cogs/helpformatter/helpformatter.py @@ -3,7 +3,6 @@ from discord.ext import commands import re -# Bot Utilities from ...utils.userinteraction import HelpPaginator usermention = r"<@!?\d{17,19}>" From 751c164b2075d77bca035097a97b3ae7a785ac57 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 14:47:07 +0200 Subject: [PATCH 13/15] Fix requirements txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4427145..5366c0c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ discord.py == 1.7.* -lavalink = 3.*.* +lavalink == 3.1.* asyncio pyyaml BeautifulSoup4 From d8ee9e8ba22487aeaca4fe00d25408c5995b5cc1 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 14:55:18 +0200 Subject: [PATCH 14/15] Update version --- musicbot/utils/bot_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/musicbot/utils/bot_version.py b/musicbot/utils/bot_version.py index 9d9a8b5..52b9a2c 100644 --- a/musicbot/utils/bot_version.py +++ b/musicbot/utils/bot_version.py @@ -1 +1 @@ -bot_version = "0.1.12" +bot_version = "0.2.12" From 4de7c16182f0087c6c6b565336a92caa9afb54e8 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Sun, 29 May 2022 15:01:55 +0200 Subject: [PATCH 15/15] update docstring for dictmapper --- musicbot/utils/settingsmanager/dictmapper.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/musicbot/utils/settingsmanager/dictmapper.py b/musicbot/utils/settingsmanager/dictmapper.py index 7832c3b..045add5 100644 --- a/musicbot/utils/settingsmanager/dictmapper.py +++ b/musicbot/utils/settingsmanager/dictmapper.py @@ -1,8 +1,10 @@ class DictMapper: """ - Base class for interacting with nested dictionaries through lists of keys - E.g. mapping ["a", "b", "c"] to example_dictionary["a"]["b"]["c"] + Class for creating and interacting with nested dictionaries through lists of keys + E.g. mapping ["a", "b", "c"] to example_dictionary["a"]["b"]["c"]. + + DictMapper.get(d["a"], ["b", "c"]) and DictMapper.get(d, ["a", "b", "c"]) are equivalent. """ @staticmethod