From 3b7038954d16e5da2bde404bf348818af73f2645 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 15:30:56 +0200 Subject: [PATCH 01/25] isort and flake fixes --- bot.py | 25 ++++++++++++++----------- cogs/cogs.py | 4 +++- cogs/helpformatter.py | 4 +++- cogs/misc.py | 11 +++++++---- cogs/music.py | 24 ++++++++++++------------ cogs/musicevents.py | 9 ++++++--- cogs/settings.py | 8 +++++--- cogs/utils/RoxUtils.py | 6 +++--- cogs/utils/alias.py | 6 ++++-- cogs/utils/checks.py | 1 + cogs/utils/context.py | 1 + cogs/utils/localizer.py | 14 ++++++++------ cogs/utils/logger.py | 2 +- cogs/utils/mixplayer.py | 8 ++++---- cogs/utils/paginator.py | 4 +++- cogs/utils/selector.py | 3 +++ cogs/utils/settingsmanager.py | 3 ++- setup.cfg | 14 ++++++++++++++ 18 files changed, 94 insertions(+), 53 deletions(-) create mode 100644 setup.cfg diff --git a/bot.py b/bot.py index c07e3a6..f0bdc0e 100644 --- a/bot.py +++ b/bot.py @@ -1,21 +1,24 @@ +# Discord Packages import discord -import codecs -import time -import os -import traceback -import yaml -import aiohttp - from discord.ext import commands + +import codecs +import os +import time +import traceback from argparse import ArgumentParser, RawTextHelpFormatter -from cogs.utils.settingsmanager import Settings -from cogs.utils.localizer import Localizer -from cogs.utils.localizer import LocalizerWrapper + +import aiohttp +import yaml + +# Bot Utilities +from cogs.helpformatter import commandhelper from cogs.utils.alias import Aliaser from cogs.utils.context import Context +from cogs.utils.localizer import Localizer, LocalizerWrapper from cogs.utils.logger import BotLogger -from cogs.helpformatter import commandhelper from cogs.utils.paginator import Scroller +from cogs.utils.settingsmanager import Settings initial_extensions = [ 'cogs.cogs', diff --git a/cogs/cogs.py b/cogs/cogs.py index e07b7cd..4606381 100644 --- a/cogs/cogs.py +++ b/cogs/cogs.py @@ -1,6 +1,8 @@ -import traceback +# Discord Packages from discord.ext import commands +import traceback + class Cogs(commands.Cog): def __init__(self, bot): diff --git a/cogs/helpformatter.py b/cogs/helpformatter.py index 8347125..2f77feb 100644 --- a/cogs/helpformatter.py +++ b/cogs/helpformatter.py @@ -1,9 +1,11 @@ +# Discord Packages from discord.ext import commands + import re +# Bot Utilities from cogs.utils.paginator import HelpPaginator, Scroller - usermention = r"<@!?\d{17,19}>" diff --git a/cogs/misc.py b/cogs/misc.py index 1d600a0..b51707b 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -1,11 +1,14 @@ +# Discord Packages import discord -import time -import platform - from discord.ext import commands -from cogs.utils import bot_version from lavalink import __version__ as LavalinkVersion +import platform +import time + +# Bot Utilities +from cogs.utils import bot_version + class Misc(commands.Cog): def __init__(self, bot): diff --git a/cogs/music.py b/cogs/music.py index 8fb9446..22e8ea7 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -1,25 +1,25 @@ """ Music commands """ +# Discord Packages +import discord +import lavalink +from discord.ext import commands + +import asyncio +import codecs +import json import math import re -import asyncio -import yaml -import codecs - -import lavalink -import discord -from discord.ext import commands +import urllib from typing import Optional -import urllib -import json +import yaml from bs4 import BeautifulSoup -from .utils import checks, RoxUtils, timeformatter +from .utils import RoxUtils, checks, timeformatter from .utils.mixplayer import MixPlayer -from .utils.paginator import QueuePaginator, TextPaginator, Scroller - +from .utils.paginator import QueuePaginator, Scroller, TextPaginator from .utils.selector import Selector time_rx = re.compile('[0-9]+') diff --git a/cogs/musicevents.py b/cogs/musicevents.py index 5f5ecc9..7110505 100644 --- a/cogs/musicevents.py +++ b/cogs/musicevents.py @@ -2,13 +2,16 @@ A cog to separate events from regular music commands """ -import codecs -import yaml +# Discord Packages import lavalink +import lavalink.events from discord.ext import commands +import codecs + +import yaml + from .utils.mixplayer import MixPlayer -import lavalink.events class MusicEvents(commands.Cog): diff --git a/cogs/settings.py b/cogs/settings.py index a813e08..22c5285 100644 --- a/cogs/settings.py +++ b/cogs/settings.py @@ -1,6 +1,8 @@ +# Discord Packages import discord - from discord.ext import commands + +# Bot Utilities from cogs.utils import checks @@ -188,9 +190,9 @@ class Settings(commands.Cog): embed = discord.Embed(title='Max duration type set to', color=ctx.me.color) if is_dynamic: - embed.description = f'Dynamic' + embed.description = 'Dynamic' else: - embed.description = f'Static' + embed.description = 'Static' await ctx.send(embed=embed) @commands.guild_only() diff --git a/cogs/utils/RoxUtils.py b/cogs/utils/RoxUtils.py index 858e748..cbc88ea 100644 --- a/cogs/utils/RoxUtils.py +++ b/cogs/utils/RoxUtils.py @@ -19,7 +19,7 @@ class ThumbNailer(object): img = soup.find("meta", property="twitter:image") return img["content"] except Exception as e: - self.logger.exception("%s".format(e)) + self.logger.exception("%s" % e) async def _bandcamp(self, url): html = await ThumbNailer.get_html(self, url) @@ -28,7 +28,7 @@ class ThumbNailer(object): img = soup.find(class_="popupImage").get("href") return img except Exception as e: - self.logger.exception("%s".format(e)) + self.logger.exception("%s" % e) async def _vimeo(self, url): html = await ThumbNailer.get_html(self, url) @@ -37,7 +37,7 @@ class ThumbNailer(object): img = soup.find("meta", property="og:image") return img["content"] except Exception as e: - self.logger.exception("%s".format(e)) + self.logger.exception("%s" % e) @staticmethod async def identify(self, identifier, uri): diff --git a/cogs/utils/alias.py b/cogs/utils/alias.py index 21f63eb..d7a0f2a 100644 --- a/cogs/utils/alias.py +++ b/cogs/utils/alias.py @@ -1,9 +1,11 @@ -import yaml +# Discord Packages +from discord.ext import commands from glob import glob from os import path -from discord.ext import commands +import yaml + """ Not the prettiest this, works by replacing any found aliases in a command string with the actual command names. diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py index 3925184..3798eac 100644 --- a/cogs/utils/checks.py +++ b/cogs/utils/checks.py @@ -1,3 +1,4 @@ +# Discord Packages import discord from discord.ext import commands diff --git a/cogs/utils/context.py b/cogs/utils/context.py index 61da689..3dbc92b 100644 --- a/cogs/utils/context.py +++ b/cogs/utils/context.py @@ -1,3 +1,4 @@ +# Discord Packages from discord.ext import commands diff --git a/cogs/utils/localizer.py b/cogs/utils/localizer.py index 8706df1..c3a444e 100644 --- a/cogs/utils/localizer.py +++ b/cogs/utils/localizer.py @@ -1,14 +1,15 @@ +# Discord Packages +from discord import Embed + +import copy +import re from glob import glob from os import path -import re - -from cogs.utils.dict_utils import flatten, SafeDict - import yaml -import copy -from discord import Embed +# Bot Utilities +from cogs.utils.dict_utils import SafeDict, flatten """ Localizer for bot @@ -95,6 +96,7 @@ class Localizer: nstr = nstr.replace(".", "/") value = value.replace(outer, nstr) return value + # parses and interpolates strings @staticmethod def _parse_localization_string(value, d, prefix=None): diff --git a/cogs/utils/logger.py b/cogs/utils/logger.py index 207f7ff..9a921b0 100644 --- a/cogs/utils/logger.py +++ b/cogs/utils/logger.py @@ -1,5 +1,5 @@ -import logging.handlers import logging +import logging.handlers import os diff --git a/cogs/utils/mixplayer.py b/cogs/utils/mixplayer.py index 9d9dae0..f6cf2fa 100644 --- a/cogs/utils/mixplayer.py +++ b/cogs/utils/mixplayer.py @@ -1,12 +1,12 @@ +# Discord Packages import lavalink +from lavalink import AudioTrack, DefaultPlayer, Node +from lavalink.events import QueueEndEvent, TrackEndEvent, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent from collections import OrderedDict, deque -from itertools import cycle, islice, chain +from itertools import chain, cycle, islice from random import shuffle -from lavalink.events import TrackStartEvent, TrackStuckEvent, TrackExceptionEvent, TrackEndEvent, QueueEndEvent -from lavalink import Node, DefaultPlayer, AudioTrack - class MixPlayer(DefaultPlayer): def __init__(self, guild_id: int, node: Node): diff --git a/cogs/utils/paginator.py b/cogs/utils/paginator.py index 4300ff1..70a5bb3 100644 --- a/cogs/utils/paginator.py +++ b/cogs/utils/paginator.py @@ -1,4 +1,6 @@ +# Discord Packages import discord + import asyncio @@ -93,7 +95,7 @@ class FieldPaginator(BasePaginator): field = {"name": name, "value": value} fieldsize = sum([len(val) for _, val in field.items()]) if len(name) > 256 or len(value) > 1024: - raise RuntimeError(f'Maximum field size exceeded, max name length: 256. max value length: 1024.') + 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() diff --git a/cogs/utils/selector.py b/cogs/utils/selector.py index 22fc41c..3e93e60 100644 --- a/cogs/utils/selector.py +++ b/cogs/utils/selector.py @@ -1,6 +1,9 @@ +# Discord Packages import discord + import asyncio import inspect + from .paginator import TextPaginator diff --git a/cogs/utils/settingsmanager.py b/cogs/utils/settingsmanager.py index 2a25a22..f361446 100644 --- a/cogs/utils/settingsmanager.py +++ b/cogs/utils/settingsmanager.py @@ -1,6 +1,7 @@ -import os import codecs import locale as localee +import os + import yaml diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..fce66fb --- /dev/null +++ b/setup.cfg @@ -0,0 +1,14 @@ +[pycodestyle] +max_line_length = 120 + +[isort] +known_discord = discord,lavalink +known_utils = cogs.utils,cogs.helpformatter +import_heading_discord = Discord Packages +import_heading_utils = Bot Utilities +sections = DISCORD,FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,UTILS,LOCALFOLDER +no_lines_before = LOCALFOLDER +indent = " " +line_length = 120 +balanced_wrapping = True +multi_line_output = 4 \ No newline at end of file From 6353dbd4637f7fe3db5a59df70fc68e2407f3a23 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 15:32:21 +0200 Subject: [PATCH 02/25] Fix deprecation warning --- bot.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bot.py b/bot.py index f0bdc0e..e70b4df 100644 --- a/bot.py +++ b/bot.py @@ -52,8 +52,6 @@ class Bot(commands.Bot): self.localizer = Localizer(conf.get('locale path', "./localization"), conf.get('locale', 'en_en')) self.aliaser = Aliaser(conf.get('locale path', "./localization"), conf.get('locale', 'en_en')) - self.session = aiohttp.ClientSession(loop=self.loop) - self.datadir = datadir self.debug = debug self.main_logger = logger @@ -136,8 +134,9 @@ class Bot(commands.Bot): print(f'Version: {discord.__version__}\n') self.logger.debug("Bot Ready\n\n\n") + self.session = aiohttp.ClientSession(loop=self.loop) await self.change_presence(activity=discord.Game(type=0, - name=conf["bot"]["playing status"]), + name=conf["bot"]["playing status"]), status=discord.Status.online) def run(self): From 66303b04ff040aa2f394cc073a1390f7048a1eab Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 15:35:12 +0200 Subject: [PATCH 03/25] Fix potential breaking unload. --- cogs/cogs.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cogs/cogs.py b/cogs/cogs.py index 4606381..fd78a2c 100644 --- a/cogs/cogs.py +++ b/cogs/cogs.py @@ -30,6 +30,8 @@ class Cogs(commands.Cog): @commands.is_owner() async def unload(self, ctx, *, module): """Unloads a module.""" + if module == "cogs": + return await ctx.send('Unloading this cog is not allowed') try: self.bot.unload_extension(f'cogs.{module}') await ctx.send(f'{module} unloaded') From 83611d9f1a05c0c47a005df5024d55eeb1132971 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 15:41:07 +0200 Subject: [PATCH 04/25] Update requirements, adapt changes --- cogs/music.py | 3 +++ cogs/utils/checks.py | 2 +- cogs/utils/mixplayer.py | 9 +++++---- requirements.txt | 6 +++--- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/cogs/music.py b/cogs/music.py index 22e8ea7..f64d053 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -81,11 +81,13 @@ class Music(commands.Cog): numtracks = 0 for track in tracks: if track['info']['length'] <= maxlength: + track = lavalink.models.AudioTrack(track, ctx.author.id) player.add(requester=ctx.author.id, track=track) numtracks += 1 else: numtracks = len(tracks) for track in tracks: + track = lavalink.models.AudioTrack(track, ctx.author.id) player.add(requester=ctx.author.id, track=track) embed.title = '{playlist_enqued}' @@ -94,6 +96,7 @@ class Music(commands.Cog): await ctx.send(embed=embed) else: track = results['tracks'][0] + track = lavalink.models.AudioTrack(track, ctx.author.id) await self.enqueue(ctx, track, embed) embed = ctx.localizer.format_embed(embed) await ctx.send(embed=embed) diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py index 3798eac..75e22db 100644 --- a/cogs/utils/checks.py +++ b/cogs/utils/checks.py @@ -61,7 +61,7 @@ def is_dj(ctx): def dj_or(alone: bool = False, track_requester: bool = False): async def predicate(ctx): try: - player = ctx.bot.lavalink.players.get(ctx.guild.id) + player = ctx.bot.lavalink.player_manager.get(ctx.guild.id) is_alone = (ctx.author in player.listeners and len(player.listeners) == 1) and alone requester = (player.current.requester == ctx.author.id) and track_requester diff --git a/cogs/utils/mixplayer.py b/cogs/utils/mixplayer.py index f6cf2fa..116f0cd 100644 --- a/cogs/utils/mixplayer.py +++ b/cogs/utils/mixplayer.py @@ -3,6 +3,7 @@ import lavalink from lavalink import AudioTrack, DefaultPlayer, Node from lavalink.events import QueueEndEvent, TrackEndEvent, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent +import typing from collections import OrderedDict, deque from itertools import chain, cycle, islice from random import shuffle @@ -18,13 +19,13 @@ class MixPlayer(DefaultPlayer): self.skip_voters = set() self.boosted = False - def add(self, requester: int, track: dict, pos: int = None): + 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, AudioTrack(track, requester), pos) + return self.queue.add_track(requester, track, pos) - def add_next(self, requester: int, track: dict): + 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(AudioTrack(track, requester)) + self.queue.add_next_track(track) def move_user_track(self, requester: int, initial: int, final: int): """ Moves a track in a users queue""" diff --git a/requirements.txt b/requirements.txt index 58c9768..d65fede 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ -discord.py >= 1.3 -git+https://github.com/Devoxin/Lavalink.py@b614a5389e3cf5ea7c444041428a05b084ca15ec +discord.py >= 1.3.3 +git+https://github.com/Devoxin/Lavalink.py@7a93b5b50d324f9dfd073bd8a3c835261a98a50b asyncio pyyaml BeautifulSoup4 -aiohttp<3.5.0,>=3.3.0 \ No newline at end of file +aiohttp>=3.6.0,<3.7.0 \ No newline at end of file From eb8159f8e26919e1c1874429d5d1f2bba1720983 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 15:46:57 +0200 Subject: [PATCH 05/25] Build stuff Jenkins will most likely fail --- .github/workflows/build.yml-wait | 52 ++++++++++++++++++++++++++++++++ Dockerfile | 4 +-- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build.yml-wait diff --git a/.github/workflows/build.yml-wait b/.github/workflows/build.yml-wait new file mode 100644 index 0000000..a49fd18 --- /dev/null +++ b/.github/workflows/build.yml-wait @@ -0,0 +1,52 @@ +name: Test And Build BOT +on: [push, pull_request] + +jobs: + flake8: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python 3.8 + uses: actions/setup-python@v1 + with: + python-version: 3.8 + - name: Lint with flake8 + run: | + pip install flake8 + flake8 --max-line-length 120 --statistics ${FLAKE_FILES} + + build-and-push: + needs: flake8 + runs-on: ubuntu-latest + env: + repo: rnorge/music + ref: ${{github.ref}} + DOCKER_USERNAME: roxedus + DOCKER_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} + steps: + - uses: actions/checkout@v1 + - name: Build the Docker image + run: | + branch="${ref##*/}" + docker build -t $repo:$branch -t $repo:$branch-${{github.sha}} . + + - name: Master tag + if: github.ref == 'refs/heads/master' + run: | + branch="${ref##*/}" + bot_ver=$(grep -i bot_version cogs/utils/bot_version.py | cut -d" " -f3 | tr -d \") + docker tag $repo:$branch $repo:$bot_ver + + - name: Bump version and push tag + if: github.ref == 'refs/heads/master' + uses: mathieudutour/github-tag-action@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to registry + if: github.event.pull_request == false + run: echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin + + - name: Pushes the Docker image + if: github.event.pull_request == false + run: docker push $repo diff --git a/Dockerfile b/Dockerfile index 112d5c0..4ab1572 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ -FROM amd64/python:3.7.3-alpine +FROM amd64/python:3.8.3-alpine -LABEL maintainer="Roxedus" jekins="dorli" +LABEL maintainer="Roxedus" COPY / /app From b16b1258f9d24a647f01528bd5907564e9e55746 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 17:29:45 +0200 Subject: [PATCH 06/25] Add node_manager --- bot.py | 3 +- cogs/music.py | 12 --- cogs/musicevents.py | 17 +--- cogs/nodemanager.py | 153 +++++++++++++++++++++++++++++++ localization/en_en/commands.yaml | 18 ++++ 5 files changed, 173 insertions(+), 30 deletions(-) create mode 100644 cogs/nodemanager.py diff --git a/bot.py b/bot.py index e70b4df..c6762ce 100644 --- a/bot.py +++ b/bot.py @@ -28,8 +28,7 @@ initial_extensions = [ ] on_ready_extensions = [ - 'cogs.music', - 'cogs.musicevents' + 'cogs.nodemanager' ] diff --git a/cogs/music.py b/cogs/music.py index f64d053..7f04ca4 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -7,18 +7,15 @@ import lavalink from discord.ext import commands import asyncio -import codecs import json import math import re import urllib from typing import Optional -import yaml from bs4 import BeautifulSoup from .utils import RoxUtils, checks, timeformatter -from .utils.mixplayer import MixPlayer from .utils.paginator import QueuePaginator, Scroller, TextPaginator from .utils.selector import Selector @@ -30,15 +27,6 @@ class Music(commands.Cog): def __init__(self, bot): self.bot = bot self.logger = self.bot.main_logger.bot_logger.getChild("Music") - if not hasattr(bot, 'lavalink'): # This ensures the client isn't overwritten during cog reloads. - bot.lavalink = lavalink.Client(bot.user.id, player=MixPlayer) - - with codecs.open(f"{self.bot.datadir}/config.yaml", 'r', encoding='utf8') as f: - conf = yaml.load(f, Loader=yaml.SafeLoader) - - bot.lavalink.add_node(**conf['lavalink nodes']['main']) - self.logger.debug("Adding Lavalink node") - bot.add_listener(bot.lavalink.voice_update_handler, 'on_socket_response') async def cog_check(self, ctx): if not ctx.guild: diff --git a/cogs/musicevents.py b/cogs/musicevents.py index 7110505..2c40e74 100644 --- a/cogs/musicevents.py +++ b/cogs/musicevents.py @@ -7,27 +7,12 @@ import lavalink import lavalink.events from discord.ext import commands -import codecs - -import yaml - -from .utils.mixplayer import MixPlayer - class MusicEvents(commands.Cog): 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) - with codecs.open(f"{self.bot.datadir}/config.yaml", 'r', encoding='utf8') as f: - conf = yaml.load(f, Loader=yaml.SafeLoader) - - bot.lavalink.add_node(**conf['lavalink nodes']['main']) - bot.add_listener(bot.lavalink.voice_update_handler, 'on_socket_response') - - lavalink.add_event_hook(self.track_hook) + bot.lavalink.add_event_hook(self.track_hook) def cog_unload(self): self.bot.lavalink._event_hooks.clear() diff --git a/cogs/nodemanager.py b/cogs/nodemanager.py new file mode 100644 index 0000000..6aa29cc --- /dev/null +++ b/cogs/nodemanager.py @@ -0,0 +1,153 @@ +# Discord Packages +import discord +import lavalink +from discord.ext import commands +from lavalink import Node + +import codecs + +import yaml + +from .utils.mixplayer import MixPlayer + + +class NodeManager(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.settings = self.bot.settings + self.logger = self.bot.main_logger.bot_logger.getChild("NodeManager") + + music_extensions = [ + 'cogs.music', + 'cogs.musicevents' + ] + + if not hasattr(bot, 'lavalink'): + bot.lavalink = lavalink.Client(bot.user.id, player=MixPlayer) + + self.load_nodes_from_file() + + bot.add_listener(bot.lavalink.voice_update_handler, 'on_socket_response') + + for extension in music_extensions: + try: + self.logger.debug("Loading extension %s" % extension) + self.bot.load_extension(extension) + except Exception: + self.logger.exception("Loading of extension %s failed" % extension) + + def load_nodes_from_file(self): + with codecs.open(f"{self.bot.datadir}/config.yaml", 'r', encoding='utf8') as f: + conf = yaml.load(f, Loader=yaml.SafeLoader) + + name_cache = [] + new_nodes = [] + + for node in self.bot.lavalink.node_manager.nodes: + name_cache.append(node.name) + + for node in conf['lavalink nodes']: + if conf['lavalink nodes'][node]['name'] in name_cache: + continue + + self.bot.lavalink.add_node(**conf['lavalink nodes'][node]) + self.logger.debug("Adding Lavalink node: %s on %s with the port %s in %s" % ( + conf['lavalink nodes'][node]['name'], conf['lavalink nodes'][node]['host'], + conf['lavalink nodes'][node]['port'], conf['lavalink nodes'][node]['region'],)) + new_nodes.append({**conf['lavalink nodes'][node]}) + return new_nodes + + async def _regioner(self, region): + flags = { + 'us': ':flag_us:', + 'eu': ':flag_eu:', + 'singapore': ':flag_sg:', + 'london': ':flag_gb:', + 'sydeny': ':flag_au:', + 'amsterdam': ':flag_nl:', + 'frankfurt': ':flag_de:', + 'brazil': ':flag_br:', + 'japan': ':flag_jp:', + 'russia': ':flag_ru:', + 'southafrica': ':flag_za:', + 'hongkong': ':flag_hk:', + 'india': ':flag_in:' + } + try: + return flags[region] + except KeyError: + return ':question:' + + async def _node_presenter(self, ctx, node): + embed = discord.Embed(color=ctx.me.color) + embed.title = 'Added new node!' + + if isinstance(node, list): + for n in node: + embed.add_field(name=f'{await self._regioner(n.region)} **Name:** {n.name}', + value=f'**Host:** {n.host}\n **Port:** {n.port}') + + if isinstance(node, Node): + embed.add_field(name=f'{await self._regioner(node.region)} **Name:** {node.name}', + value=f'**Host:** {node.host}\n **Port:** {node.port}') + + if isinstance(node, dict): + embed.description = f'**Name:** {node.get("name")}\n **Host:** {node.get("host")}\n ' \ + f'**Port:** {node.get("port")}\n **Region:** {await self._regioner(node.get("region"))}' + + return embed + + @commands.group(name='node', hidden=True) + @commands.is_owner() + async def _node(self, ctx): + # TODO: @Even help + if ctx.invoked_subcommand is None: + await ctx.invoke(self.bot.get_command('help'), ctx.command.qualified_name) + + @_node.command(name='reload_file') + @commands.is_owner() + async def reload_file(self, ctx): + for node in self.load_nodes_from_file(): + embed = await self._node_presenter(ctx, node) + embed.title = 'Added new node from file!' + await ctx.send(embed=embed) + + @_node.command(name='add') + @commands.is_owner() + async def _add(self, ctx, host, port, password, region, name=None): + self.bot.lavalink.add_node(host, port, password, region, name) + self.logger.debug("Adding Lavalink node: %s on %s with the port %s in %s" % (host, port, region, name,)) + embed = await self._node_presenter(ctx, {'host': host, 'port': port, 'password': password, + 'region': region, 'name': name}) + embed.title = 'Added new node!' + await ctx.send(embed=embed) + + @_node.command(name='list') + @commands.is_owner() + async def list_nodes(self, ctx): + embed = await self._node_presenter(ctx, self.bot.lavalink.node_manager.nodes) + embed.title = 'Lavalink nodes attatched to this bot:' + await ctx.send(embed=embed) + + @_node.command(name='remove') + @commands.is_owner() + async def _remove(self, ctx, node): + sent_feedback = False + for _node in self.bot.lavalink.node_manager.nodes: + if len(self.bot.lavalink.node_manager.nodes) <= 1: + await ctx.send('Cannot remove the last node') + sent_feedback = True + break + if (_node.name or _node.host) == node: + sent_feedback = True + embed = await self._node_presenter(ctx, _node) + embed.title = 'Removed node from bot' + await ctx.send(embed=embed) + self.bot.lavalink.node_manager.remove_node(_node) + self.logger.info("Removed Lavalink node: %s" % _node.host) + if not sent_feedback: + await ctx.send('No node found') + + +def setup(bot): + bot.add_cog(NodeManager(bot)) diff --git a/localization/en_en/commands.yaml b/localization/en_en/commands.yaml index 14fe1e7..99a396b 100644 --- a/localization/en_en/commands.yaml +++ b/localization/en_en/commands.yaml @@ -112,6 +112,24 @@ reloadalias: aliases: [reloadalias] description: 'Reload all aliases and help information.' +# NodeManager +node: + aliases: [node] + description: 'Manage server nodes.' + sub_commands: + add: + aliases: [add] + description: 'Adds node to pool.' + list: + aliases: [list, nodes] + description: 'Lists nodes in the pool.' + remove: + aliases: [remove] + description: 'Removes nodes in the pool.' + reload_file: + aliases: [reload_file, reload] + description: 'Reads the settings and adds newly added nodes.' + # Settings settings: aliases: [settings, set] From 245431bf1d5e30836493bf2ebe3d10ad3588f4c5 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 17:34:33 +0200 Subject: [PATCH 07/25] Add leavetimer? Hard to test, as the bug it is intended to fix is hard to reproduce --- cogs/musicevents.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cogs/musicevents.py b/cogs/musicevents.py index 7110505..a5efda4 100644 --- a/cogs/musicevents.py +++ b/cogs/musicevents.py @@ -5,8 +5,9 @@ A cog to separate events from regular music commands # Discord Packages import lavalink import lavalink.events -from discord.ext import commands +from discord.ext import commands, tasks +import asyncio import codecs import yaml @@ -17,6 +18,7 @@ from .utils.mixplayer import MixPlayer class MusicEvents(commands.Cog): def __init__(self, bot): self.bot = bot + self.leave_timer.start() # 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) @@ -80,6 +82,18 @@ class MusicEvents(commands.Cog): await player.stop() await self.connect_to(guild.id, None) + async def leave_check(self): + if len(self.bot.lavalink.player_manager.players) != 0: + for player_id in self.bot.lavalink.player_manager.players: + await self.check_leave_voice(player_id) + return + return + + @tasks.loop(seconds=10.0) + async def leave_timer(self): + await self.leave_check() + await asyncio.sleep(10) + def setup(bot): bot.add_cog(MusicEvents(bot)) From 1f15abba6ae78571ce2e4e650670908ea4084ba3 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 17:43:06 +0200 Subject: [PATCH 08/25] Add error handling to give feedback to the user --- bot.py | 39 +------------------- cogs/errors.py | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 38 deletions(-) create mode 100644 cogs/errors.py diff --git a/bot.py b/bot.py index e70b4df..5ac7611 100644 --- a/bot.py +++ b/bot.py @@ -12,15 +12,14 @@ import aiohttp import yaml # Bot Utilities -from cogs.helpformatter import commandhelper from cogs.utils.alias import Aliaser from cogs.utils.context import Context from cogs.utils.localizer import Localizer, LocalizerWrapper from cogs.utils.logger import BotLogger -from cogs.utils.paginator import Scroller from cogs.utils.settingsmanager import Settings initial_extensions = [ + 'cogs.errors', 'cogs.cogs', 'cogs.settings', 'cogs.misc', @@ -64,42 +63,6 @@ class Bot(commands.Bot): except Exception: self.logger.exception("Loading of extension %s failed" % extension) - async def on_command_error(self, ctx, err): - if not self.debug: - if (isinstance(err, commands.MissingRequiredArgument) or - isinstance(err, commands.BadArgument)): - paginator = commandhelper(ctx, ctx.command, ctx.invoker, include_subcmd=False) - scroller = Scroller(ctx, paginator) - await scroller.start_scrolling() - - if isinstance(err, commands.CommandInvokeError): - self.logger.debug("Error running command: %s\n Traceback: %s" % (ctx.command, err)) - pass - - elif isinstance(err, commands.NoPrivateMessage): - self.logger.debug("Error running command: %s\n Traceback: %s" % (ctx.command, err)) - await ctx.send('That command is not available in DMs') - - elif isinstance(err, commands.CommandOnCooldown): - await ctx.send(f"{ctx.message.author.mention} Command is on cooldown. " - f"Try again in `{err.retry_after:.1f}` seconds.") - - elif isinstance(err, RuntimeError): - self.logger.debug("Error running command: %s\n Traceback: %s" % (ctx.command, err)) - pass - - elif isinstance(err, commands.CheckFailure): - self.logger.debug("Error running command: %s\n Traceback: %s" % (ctx.command, err)) - pass - - elif isinstance(err, commands.CommandNotFound): - pass - else: - tb = err.__traceback__ - traceback.print_tb(tb) - print(err) - self.logger.debug("Error running command: %s\n Traceback: %s" % (ctx.command, err)) - async def on_message(self, message): if message.author.bot: return diff --git a/cogs/errors.py b/cogs/errors.py new file mode 100644 index 0000000..7403955 --- /dev/null +++ b/cogs/errors.py @@ -0,0 +1,96 @@ +# Discord Packages +import discord +from discord.ext import commands + +import traceback + +# Bot Utilities +from cogs.helpformatter import commandhelper +from cogs.utils.paginator import Scroller + + +class Errors(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.logger = self.bot.main_logger.bot_logger.getChild("Errors") + + async def base_msg(self, ctx, state: int = 0xFCBA03): + embed = discord.Embed(color=state) + embed.title = '{errors.error_occurred}' + embed.set_footer(icon_url=ctx.author.avatar_url, + text=f'{ctx.author.name}#{ctx.author.discriminator}') + return embed + + @commands.Cog.listener() + async def on_command_error(self, ctx, err): + ignored = (commands.CommandNotFound) + + if isinstance(err, ignored): + return + + if isinstance(err, commands.CommandInvokeError) and (err.original == 'Join a voicechannel first.'): + embed = await self.base_msg(ctx, state=0xFC0303) + embed.description = '{errors.join_voice_first}' + embed = ctx.localizer.format_embed(embed) + return await ctx.send(embed=embed) + elif isinstance(err, commands.CommandInvokeError) and (err.original == 'Not connected.'): + embed = await self.base_msg(ctx, state=0xFC0303) + embed.description = '{errors.not_connected}' + embed = ctx.localizer.format_embed(embed) + return await ctx.send(embed=embed) + elif isinstance(err, commands.CommandInvokeError) and (err.original == + 'I need the `CONNECT` and `SPEAK` permissions.'): + embed = await self.base_msg(ctx, state=0xFC0303) + embed.description = '{errors.need_permission}' + embed = ctx.localizer.format_embed(embed) + return await ctx.send(embed=embed) + elif isinstance(err, commands.CommandInvokeError) and (err.original == + 'You need to be in the right voice channel'): + embed = await self.base_msg(ctx, state=0xFC0303) + embed.description = '{errors.right_channel}' + embed = ctx.localizer.format_embed(embed) + return await ctx.send(embed=embed) + elif isinstance(err, commands.CommandInvokeError) and (err.original == 'You need to be in my voicechannel.'): + embed = await self.base_msg(ctx, state=0xFC0303) + embed.description = '{errors.my_channel}' + embed = ctx.localizer.format_embed(embed) + return await ctx.send(embed=embed) + if not self.bot.debug: + if (isinstance(err, commands.MissingRequiredArgument) or + isinstance(err, commands.BadArgument)): + paginator = commandhelper(ctx, ctx.command, ctx.invoker, include_subcmd=False) + scroller = Scroller(ctx, paginator) + await scroller.start_scrolling() + + if isinstance(err, commands.CommandInvokeError): + self.logger.debug( + "Error running command: %s\nTraceback: %s" % (ctx.command, err)) + pass + + elif isinstance(err, commands.NoPrivateMessage): + self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) + await ctx.send('That command is not available in DMs') + + elif isinstance(err, commands.CommandOnCooldown): + await ctx.send(f"{ctx.message.author.mention} Command is on cooldown. " + f"Try again in `{err.retry_after:.1f}` seconds.") + + elif isinstance(err, RuntimeError): + self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) + pass + + elif isinstance(err, commands.CheckFailure): + self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) + pass + + elif isinstance(err, commands.CommandNotFound): + pass + else: + tb = err.__traceback__ + traceback.print_tb(tb) + print(err) + self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) + + +def setup(bot): + bot.add_cog(Errors(bot)) From 0133a34f9e3f9f682d683e85ce711b0253713f3a Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 17:43:18 +0200 Subject: [PATCH 09/25] Properly catch error --- cogs/cogs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cogs/cogs.py b/cogs/cogs.py index fd78a2c..cc3bbff 100644 --- a/cogs/cogs.py +++ b/cogs/cogs.py @@ -23,8 +23,8 @@ class Cogs(commands.Cog): try: self.bot.load_extension(f'cogs.{module}') await ctx.send(f'{module} loaded') - except Exception as e: - await ctx.send(f'```py\n{traceback.format_exc(e)}\n```') + except Exception: + await ctx.send(f'```py\n{traceback.format_exc()}\n```') @_cogs.command() @commands.is_owner() From a2db13611d77b15042a0c85c767b210efd2c9ee1 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 17:43:37 +0200 Subject: [PATCH 10/25] Add localizations --- localization/en_en/music.yaml | 7 +++++++ localization/nb_no/music.yaml | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/localization/en_en/music.yaml b/localization/en_en/music.yaml index 2afafbb..d13dedf 100644 --- a/localization/en_en/music.yaml +++ b/localization/en_en/music.yaml @@ -74,3 +74,10 @@ history: settings_check: textchannel: "You can't use music commands in this channel.\nTry in: " voicechannel: 'I can only play music in: ' +errors: + error_occurred: An error occurred + join_voice_first: You need to join a voicechannel first + not_connected: Not connected + need_permission: I need the `CONNECT` and `SPEAK` permissions + right_channel: You need to be in the right voice channel + my_channel: You need to be in my voicechannel diff --git a/localization/nb_no/music.yaml b/localization/nb_no/music.yaml index 42c6c61..d91492f 100644 --- a/localization/nb_no/music.yaml +++ b/localization/nb_no/music.yaml @@ -74,3 +74,10 @@ history: settings_check: textchannel: "Du kan ikke bruke musikkommandoer i denne kanalen.\nPrøv i: " voicechannel: 'Jeg kan bare spille musikk i: ' +errors: + error_occurred: En feil oppstod + join_voice_first: Du må være i en stemmekanal + not_connected: Ikke tilkoblet + need_permission: Jeg trenger tillgang til `CONNECT` og `SPEAK` + right_channel: Du må være i riktig kanal + my_channel: Du må være i samme stemmekanal som meg From f5b6a17d9d0cf92b5f220e7e8056db3b0de73356 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 17:47:21 +0200 Subject: [PATCH 11/25] Rename module --- cogs/music.py | 12 ++++++------ cogs/utils/{RoxUtils.py => thumbnailer.py} | 0 2 files changed, 6 insertions(+), 6 deletions(-) rename cogs/utils/{RoxUtils.py => thumbnailer.py} (100%) diff --git a/cogs/music.py b/cogs/music.py index f64d053..6aa0e0a 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -17,7 +17,7 @@ from typing import Optional import yaml from bs4 import BeautifulSoup -from .utils import RoxUtils, checks, timeformatter +from .utils import checks, thumbnailer, timeformatter from .utils.mixplayer import MixPlayer from .utils.paginator import QueuePaginator, Scroller, TextPaginator from .utils.selector import Selector @@ -147,7 +147,7 @@ class Music(commands.Cog): if player.current: song = f'**[{player.current.title}]({player.current.uri})**' embed = discord.Embed(color=ctx.me.color, description=song, title='{now}') - thumbnail_url = await RoxUtils.ThumbNailer.identify(self, player.current.identifier, player.current.uri) + thumbnail_url = await thumbnailer.ThumbNailer.identify(self, player.current.identifier, player.current.uri) member = ctx.guild.get_member(player.current.requester) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) @@ -217,7 +217,7 @@ class Music(commands.Cog): member = ctx.guild.get_member(player.current.requester) embed = discord.Embed(color=ctx.me.color, description=song, title='{now}') - thumbnail_url = await RoxUtils.ThumbNailer.identify(self, player.current.identifier, player.current.uri) + thumbnail_url = await thumbnailer.ThumbNailer.identify(self, player.current.identifier, player.current.uri) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) @@ -337,7 +337,7 @@ class Music(commands.Cog): # Create a nice embed explaining what happened song = f'**[{moved.title}]({moved.uri})**' embed = discord.Embed(color=ctx.me.color, description=song, title='{moved.moved}') - thumbnail_url = await RoxUtils.ThumbNailer.identify(self, moved.identifier, moved.uri) + thumbnail_url = await thumbnailer.ThumbNailer.identify(self, moved.identifier, moved.uri) member = ctx.guild.get_member(moved.requester) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) @@ -563,7 +563,7 @@ class Music(commands.Cog): description = ctx.localizer.format_str("{history.current}", _title=track.title, _uri=track.uri, _id=track.requester) + '\n\n' description += ctx.localizer.format_str("{history.previous}", _len=len(history)-1) + '\n' - thumb_url = await RoxUtils.ThumbNailer.identify(self, track.identifier, track.uri) + thumb_url = await thumbnailer.ThumbNailer.identify(self, track.identifier, track.uri) for index, track in enumerate(history[1:], start=1): description += ctx.localizer.format_str("{history.track}", _index=-index, _title=track.title, _uri=track.uri, _id=track.requester) + '\n' @@ -796,7 +796,7 @@ class Music(commands.Cog): embed.add_field(name="{enqueue.playing_in}", value=f"`{until_play} ({{enqueue.estimated}})`", inline=True) embed.title = '{enqueue.enqueued}' - thumb_url = await RoxUtils.ThumbNailer.identify(self, track.identifier, track.uri) + thumb_url = await thumbnailer.ThumbNailer.identify(self, track.identifier, track.uri) if thumb_url: embed.set_thumbnail(url=thumb_url) diff --git a/cogs/utils/RoxUtils.py b/cogs/utils/thumbnailer.py similarity index 100% rename from cogs/utils/RoxUtils.py rename to cogs/utils/thumbnailer.py From 0b0210b8bbb1b96b0448633b559f458d5b847aaf Mon Sep 17 00:00:00 2001 From: Roxedus Date: Sun, 14 Jun 2020 18:06:04 +0200 Subject: [PATCH 12/25] Add thumbnail url to extra less lookups overall --- cogs/music.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/cogs/music.py b/cogs/music.py index 6aa0e0a..81670ae 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -81,13 +81,17 @@ class Music(commands.Cog): numtracks = 0 for track in tracks: if track['info']['length'] <= maxlength: - track = lavalink.models.AudioTrack(track, ctx.author.id) + thumbnail_url = await thumbnailer.ThumbNailer.identify( + self, track['info']['identifier'], track['info']['uri']) + track = lavalink.models.AudioTrack(track, ctx.author.id, thumbnail_url=thumbnail_url) player.add(requester=ctx.author.id, track=track) numtracks += 1 else: numtracks = len(tracks) for track in tracks: - track = lavalink.models.AudioTrack(track, ctx.author.id) + thumbnail_url = await thumbnailer.ThumbNailer.identify( + self, track['info']['identifier'], track['info']['uri']) + track = lavalink.models.AudioTrack(track, ctx.author.id, thumbnail_url=thumbnail_url) player.add(requester=ctx.author.id, track=track) embed.title = '{playlist_enqued}' @@ -96,7 +100,9 @@ class Music(commands.Cog): await ctx.send(embed=embed) else: track = results['tracks'][0] - track = lavalink.models.AudioTrack(track, ctx.author.id) + thumbnail_url = await thumbnailer.ThumbNailer.identify( + self, track['info']['identifier'], track['info']['uri']) + track = lavalink.models.AudioTrack(track, ctx.author.id, thumbnail_url=thumbnail_url) await self.enqueue(ctx, track, embed) embed = ctx.localizer.format_embed(embed) await ctx.send(embed=embed) @@ -147,7 +153,7 @@ class Music(commands.Cog): if player.current: song = f'**[{player.current.title}]({player.current.uri})**' embed = discord.Embed(color=ctx.me.color, description=song, title='{now}') - thumbnail_url = await thumbnailer.ThumbNailer.identify(self, player.current.identifier, player.current.uri) + thumbnail_url = player.current.extra["thumbnail_url"] member = ctx.guild.get_member(player.current.requester) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) @@ -217,7 +223,7 @@ class Music(commands.Cog): member = ctx.guild.get_member(player.current.requester) embed = discord.Embed(color=ctx.me.color, description=song, title='{now}') - thumbnail_url = await thumbnailer.ThumbNailer.identify(self, player.current.identifier, player.current.uri) + thumbnail_url = player.current.extra["thumbnail_url"] if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) @@ -337,7 +343,7 @@ class Music(commands.Cog): # Create a nice embed explaining what happened song = f'**[{moved.title}]({moved.uri})**' embed = discord.Embed(color=ctx.me.color, description=song, title='{moved.moved}') - thumbnail_url = await thumbnailer.ThumbNailer.identify(self, moved.identifier, moved.uri) + thumbnail_url = moved.extra["thumbnail_url"] member = ctx.guild.get_member(moved.requester) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) @@ -563,7 +569,7 @@ class Music(commands.Cog): description = ctx.localizer.format_str("{history.current}", _title=track.title, _uri=track.uri, _id=track.requester) + '\n\n' description += ctx.localizer.format_str("{history.previous}", _len=len(history)-1) + '\n' - thumb_url = await thumbnailer.ThumbNailer.identify(self, track.identifier, track.uri) + thumbnail_url = track.extra["thumbnail_url"] for index, track in enumerate(history[1:], start=1): description += ctx.localizer.format_str("{history.track}", _index=-index, _title=track.title, _uri=track.uri, _id=track.requester) + '\n' @@ -571,8 +577,8 @@ class Music(commands.Cog): embed = discord.Embed(title=ctx.localizer.format_str('{history.title}'), color=ctx.me.color, description=description) - if thumb_url: - embed.set_thumbnail(url=thumb_url) + if thumbnail_url: + embed.set_thumbnail(url=thumbnail_url) await ctx.send(embed=embed) @commands.cooldown(1, 5, commands.BucketType.guild) @@ -796,10 +802,10 @@ class Music(commands.Cog): embed.add_field(name="{enqueue.playing_in}", value=f"`{until_play} ({{enqueue.estimated}})`", inline=True) embed.title = '{enqueue.enqueued}' - thumb_url = await thumbnailer.ThumbNailer.identify(self, track.identifier, track.uri) + thumbnail_url = track.extra["thumbnail_url"] - if thumb_url: - embed.set_thumbnail(url=thumb_url) + if thumbnail_url: + embed.set_thumbnail(url=thumbnail_url) duration = timeformatter.format_ms(int(track.duration)) embed.description = f'[{track.title}]({track.uri})\n**{duration}**' From 9599254cf02d49e4c3572131db8a09459177c1a9 Mon Sep 17 00:00:00 2001 From: LBlend <24893890+LBlend@users.noreply.github.com> Date: Wed, 17 Jun 2020 22:47:06 +0200 Subject: [PATCH 13/25] fixed typo sydeny -> sydney --- cogs/nodemanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cogs/nodemanager.py b/cogs/nodemanager.py index 6aa29cc..c6e2603 100644 --- a/cogs/nodemanager.py +++ b/cogs/nodemanager.py @@ -63,7 +63,7 @@ class NodeManager(commands.Cog): 'eu': ':flag_eu:', 'singapore': ':flag_sg:', 'london': ':flag_gb:', - 'sydeny': ':flag_au:', + 'sydney': ':flag_au:', 'amsterdam': ':flag_nl:', 'frankfurt': ':flag_de:', 'brazil': ':flag_br:', From 00b6d110410c0b9eb69d5e293a07908df488698f Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Wed, 26 Aug 2020 23:12:30 +0200 Subject: [PATCH 14/25] update to new d.py and lavalink --- bot.py | 5 +++-- cogs/cogs.py | 2 +- cogs/misc.py | 2 +- cogs/music.py | 3 ++- cogs/utils/checks.py | 2 +- localization/en_en/music.yaml | 2 +- requirements.txt | 5 ++--- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/bot.py b/bot.py index c07e3a6..d6b3035 100644 --- a/bot.py +++ b/bot.py @@ -49,8 +49,6 @@ class Bot(commands.Bot): self.localizer = Localizer(conf.get('locale path', "./localization"), conf.get('locale', 'en_en')) self.aliaser = Aliaser(conf.get('locale path', "./localization"), conf.get('locale', 'en_en')) - self.session = aiohttp.ClientSession(loop=self.loop) - self.datadir = datadir self.debug = debug self.main_logger = logger @@ -121,6 +119,9 @@ class Bot(commands.Bot): async def on_ready(self): if not hasattr(self, 'uptime'): self.uptime = time.time() + + self.session = aiohttp.ClientSession(loop=self.loop) + for extension in on_ready_extensions: try: self.logger.debug("Loading extension %s" % extension) diff --git a/cogs/cogs.py b/cogs/cogs.py index e07b7cd..a5b9fac 100644 --- a/cogs/cogs.py +++ b/cogs/cogs.py @@ -63,7 +63,7 @@ class Cogs(commands.Cog): @commands.is_owner() async def _shutdown(self, ctx): """Logs out and stops.""" - self.bot.lavalink.players.clear() + self.bot.lavalink.player_manager.players.clear() await self.bot.logout() diff --git a/cogs/misc.py b/cogs/misc.py index 1d600a0..7de75c7 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -51,7 +51,7 @@ class Misc(commands.Cog): lavalink = self.bot.lavalink listeners = 0 - for guild, player in lavalink.player_manager.players: + for guild, player in lavalink.player_manager.players.items(): listeners += len(player.listeners) embed.add_field(name='{music.players}', value=f'{len(lavalink.player_manager.players)}') diff --git a/cogs/music.py b/cogs/music.py index 8fb9446..19e997d 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -195,7 +195,8 @@ class Music(commands.Cog): player.queue.clear() await player.stop() - await ctx.send(ctx.localizer.format_str("{stop}")) + embed = discord.Embed(color=ctx.me.color, title='{stop}') + await ctx.send(embed=ctx.localizer.format_embed(embed)) @commands.command(name='now') async def _now(self, ctx): diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py index 3925184..1358097 100644 --- a/cogs/utils/checks.py +++ b/cogs/utils/checks.py @@ -60,7 +60,7 @@ def is_dj(ctx): def dj_or(alone: bool = False, track_requester: bool = False): async def predicate(ctx): try: - player = ctx.bot.lavalink.players.get(ctx.guild.id) + player = ctx.bot.lavalink.player_manager.get(ctx.guild.id) is_alone = (ctx.author in player.listeners and len(player.listeners) == 1) and alone requester = (player.current.requester == ctx.author.id) and track_requester diff --git a/localization/en_en/music.yaml b/localization/en_en/music.yaml index 2afafbb..97d0797 100644 --- a/localization/en_en/music.yaml +++ b/localization/en_en/music.yaml @@ -15,7 +15,7 @@ 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." +stop: "Stopped." live: "\U0001F534 LIVE" now: Now Playing queue: diff --git a/requirements.txt b/requirements.txt index 58c9768..9f1d579 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ -discord.py >= 1.3 -git+https://github.com/Devoxin/Lavalink.py@b614a5389e3cf5ea7c444041428a05b084ca15ec +discord.py +git+https://github.com/Devoxin/Lavalink.py@dev asyncio pyyaml BeautifulSoup4 -aiohttp<3.5.0,>=3.3.0 \ No newline at end of file From 1336a3ed4ff1494d696bf9ffa32fc41641824f27 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Thu, 27 Aug 2020 12:48:01 +0200 Subject: [PATCH 15/25] Added working help invoker, changed config structure --- cogs/nodemanager.py | 8 +++++--- data/config.yaml.example | 17 +++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/cogs/nodemanager.py b/cogs/nodemanager.py index c6e2603..7dc8767 100644 --- a/cogs/nodemanager.py +++ b/cogs/nodemanager.py @@ -9,7 +9,8 @@ import codecs import yaml from .utils.mixplayer import MixPlayer - +from cogs.helpformatter import commandhelper +from cogs.utils.paginator import Scroller class NodeManager(commands.Cog): def __init__(self, bot): @@ -100,9 +101,10 @@ class NodeManager(commands.Cog): @commands.group(name='node', hidden=True) @commands.is_owner() async def _node(self, ctx): - # TODO: @Even help if ctx.invoked_subcommand is None: - await ctx.invoke(self.bot.get_command('help'), ctx.command.qualified_name) + paginator = commandhelper(ctx, ctx.command, ctx.invoker, include_subcmd=True) + scroller = Scroller(ctx, paginator) + await scroller.start_scrolling() @_node.command(name='reload_file') @commands.is_owner() diff --git a/data/config.yaml.example b/data/config.yaml.example index f1f4f8b..281354f 100644 --- a/data/config.yaml.example +++ b/data/config.yaml.example @@ -19,20 +19,17 @@ default server settings: dynamic max duration: Yes lavalink nodes: - main: # The preferred lavalink node for your music bot - host: localhost + - host: localhost port: 2333 password: youshallnotpass region: eu - name: default-node + name: main - # Backup nodes for your music bot - backup: - - host: localhost - port: 2333 - password: youshallnotpass - region: eu - name: backup-1 + - host: localhost + port: 2333 + password: youshallnotpass + region: eu + name: backup-1 APIkeys: genius: From 16035f739357ff04fb4abb0778257e7e3037a070 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Thu, 27 Aug 2020 13:42:56 +0200 Subject: [PATCH 16/25] Update to match new config format --- cogs/nodemanager.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cogs/nodemanager.py b/cogs/nodemanager.py index 7dc8767..81f8530 100644 --- a/cogs/nodemanager.py +++ b/cogs/nodemanager.py @@ -48,14 +48,14 @@ class NodeManager(commands.Cog): name_cache.append(node.name) for node in conf['lavalink nodes']: - if conf['lavalink nodes'][node]['name'] in name_cache: + if node['name'] in name_cache: continue - self.bot.lavalink.add_node(**conf['lavalink nodes'][node]) + self.bot.lavalink.add_node(**node) self.logger.debug("Adding Lavalink node: %s on %s with the port %s in %s" % ( - conf['lavalink nodes'][node]['name'], conf['lavalink nodes'][node]['host'], - conf['lavalink nodes'][node]['port'], conf['lavalink nodes'][node]['region'],)) - new_nodes.append({**conf['lavalink nodes'][node]}) + node['name'], node['host'], + node['port'], node['region'],)) + new_nodes.append({**node}) return new_nodes async def _regioner(self, region): From ffa9e5e1a99146ce28addce81e850a5c1b7ddc33 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Thu, 27 Aug 2020 15:09:49 +0200 Subject: [PATCH 17/25] Fix logic error, move repeated code to function. --- cogs/errors.py | 96 ++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 54 deletions(-) diff --git a/cogs/errors.py b/cogs/errors.py index 7403955..f0ea6da 100644 --- a/cogs/errors.py +++ b/cogs/errors.py @@ -23,73 +23,61 @@ class Errors(commands.Cog): @commands.Cog.listener() async def on_command_error(self, ctx, err): - ignored = (commands.CommandNotFound) - if isinstance(err, ignored): + # Help commands + if (isinstance(err, commands.MissingRequiredArgument) or + isinstance(err, commands.BadArgument)): + paginator = commandhelper(ctx, ctx.command, ctx.invoker, include_subcmd=False) + scroller = Scroller(ctx, paginator) + await scroller.start_scrolling() + + if isinstance(err, (commands.CommandNotFound)): return - if isinstance(err, commands.CommandInvokeError) and (err.original == 'Join a voicechannel first.'): + async def send_error_embed(description): embed = await self.base_msg(ctx, state=0xFC0303) - embed.description = '{errors.join_voice_first}' + embed.description = description embed = ctx.localizer.format_embed(embed) return await ctx.send(embed=embed) - elif isinstance(err, commands.CommandInvokeError) and (err.original == 'Not connected.'): - embed = await self.base_msg(ctx, state=0xFC0303) - embed.description = '{errors.not_connected}' - embed = ctx.localizer.format_embed(embed) - return await ctx.send(embed=embed) - elif isinstance(err, commands.CommandInvokeError) and (err.original == - 'I need the `CONNECT` and `SPEAK` permissions.'): - embed = await self.base_msg(ctx, state=0xFC0303) - embed.description = '{errors.need_permission}' - embed = ctx.localizer.format_embed(embed) - return await ctx.send(embed=embed) - elif isinstance(err, commands.CommandInvokeError) and (err.original == - 'You need to be in the right voice channel'): - embed = await self.base_msg(ctx, state=0xFC0303) - embed.description = '{errors.right_channel}' - embed = ctx.localizer.format_embed(embed) - return await ctx.send(embed=embed) - elif isinstance(err, commands.CommandInvokeError) and (err.original == 'You need to be in my voicechannel.'): - embed = await self.base_msg(ctx, state=0xFC0303) - embed.description = '{errors.my_channel}' - embed = ctx.localizer.format_embed(embed) - return await ctx.send(embed=embed) - if not self.bot.debug: - if (isinstance(err, commands.MissingRequiredArgument) or - isinstance(err, commands.BadArgument)): - paginator = commandhelper(ctx, ctx.command, ctx.invoker, include_subcmd=False) - scroller = Scroller(ctx, paginator) - await scroller.start_scrolling() - if isinstance(err, commands.CommandInvokeError): - self.logger.debug( - "Error running command: %s\nTraceback: %s" % (ctx.command, err)) - pass + # Music related errors + if isinstance(err, commands.CommandInvokeError): + if (err.original == 'Join a voicechannel first.'): + return await send_error_embed('{errors.join_voice_first}') - elif isinstance(err, commands.NoPrivateMessage): - self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) - await ctx.send('That command is not available in DMs') + elif (err.original == 'Not connected.'): + return await send_error_embed('{errors.not_connected}') - elif isinstance(err, commands.CommandOnCooldown): - await ctx.send(f"{ctx.message.author.mention} Command is on cooldown. " - f"Try again in `{err.retry_after:.1f}` seconds.") + elif (err.original == 'I need the `CONNECT` and `SPEAK` permissions.'): + return await send_error_embed('{errors.need_permission}') - elif isinstance(err, RuntimeError): - self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) - pass + elif (err.original == 'You need to be in the right voice channel'): + return await send_error_embed('{errors.right_channel}') - elif isinstance(err, commands.CheckFailure): - self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) - pass + elif (err.original == 'You need to be in my voicechannel.'): + return await send_error_embed('{errors.my_channel}') + + + if isinstance(err, commands.CommandOnCooldown): + await ctx.send(f"{ctx.message.author.mention} Command is on cooldown. " + f"Try again in `{err.retry_after:.1f}` seconds.") + + elif isinstance(err, commands.NoPrivateMessage): + await ctx.send('That command is not available in DMs') - elif isinstance(err, commands.CommandNotFound): - pass else: - tb = err.__traceback__ - traceback.print_tb(tb) - print(err) - self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) + # Log all exceptions if the bot is in debug mode + if self.bot.debug: + tb = err.__traceback__ + traceback.print_tb(tb) + self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) + + else: + to_log = (RuntimeError, commands.CheckFailure, commands.CommandInvokeError, + commands.NoPrivateMessage) + + if isinstance(err, to_log): + self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) def setup(bot): From 231d4bd813993e1d66e4192564dd10f87adf0f15 Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Thu, 27 Aug 2020 15:12:42 +0200 Subject: [PATCH 18/25] Fixed search not queueing songs --- cogs/music.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cogs/music.py b/cogs/music.py index 4bb21d4..2e111e4 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -772,9 +772,11 @@ class Music(commands.Cog): raise commands.CommandInvokeError('You need to be in my voicechannel.') async def enqueue(self, ctx, track, embed): - player = self.bot.lavalink.player_manager.get(ctx.guild.id) + if isinstance(track, dict): + track = lavalink.models.AudioTrack(track, ctx.author.id) + maxlength = self.max_track_length(ctx.guild, player) if maxlength and track['info']['length'] > maxlength: embed.description = ctx.localizer.format_str("{enqueue.toolong}", From 3a776eba1487fd467524e858e332ab76271064da Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Thu, 27 Aug 2020 16:22:27 +0200 Subject: [PATCH 19/25] Fix bug in check_leave_voice call This is why statically typed languages are nice sometimes. --- cogs/musicevents.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cogs/musicevents.py b/cogs/musicevents.py index a5efda4..e7de29c 100644 --- a/cogs/musicevents.py +++ b/cogs/musicevents.py @@ -19,6 +19,8 @@ class MusicEvents(commands.Cog): def __init__(self, bot): self.bot = bot self.leave_timer.start() + self.logger = self.bot.main_logger.bot_logger.getChild("Errors") + # 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) @@ -83,16 +85,15 @@ class MusicEvents(commands.Cog): await self.connect_to(guild.id, None) async def leave_check(self): - if len(self.bot.lavalink.player_manager.players) != 0: - for player_id in self.bot.lavalink.player_manager.players: - await self.check_leave_voice(player_id) - return - return + for player_id in self.bot.lavalink.player_manager.players: + await self.check_leave_voice(self.bot.get_guild(player_id)) @tasks.loop(seconds=10.0) async def leave_timer(self): - await self.leave_check() - await asyncio.sleep(10) + try: + await self.leave_check() + except Exception as err: + self.logger.debug("Error in leave_timer loop.\nTraceback: %s" % (err)) def setup(bot): From bd1af47c0c1fc34e57c9864afb3642bac3fe73b3 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Thu, 27 Aug 2020 19:37:19 +0200 Subject: [PATCH 20/25] Test linter --- .github/workflows/build.yml | 47 +++++++++++++++++++++++++++++ .github/workflows/build.yml-wait | 52 -------------------------------- 2 files changed, 47 insertions(+), 52 deletions(-) create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/build.yml-wait diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..7a46fb5 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,47 @@ +name: Test And Build BOT +on: [push, pull_request] + +jobs: + flake8: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Lint Code Base + uses: github/super-linter@v3 + env: + VALIDATE_ALL_CODEBASE: true + VALIDATE_PYTHON_BLACK: false + DEFAULT_BRANCH: master + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # build-and-push: + # needs: flake8 + # runs-on: ubuntu-latest + # env: + # repo: rnorge/music + # ref: ${{github.ref}} + # DOCKER_USERNAME: roxedus + # DOCKER_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} + # steps: + # - uses: actions/checkout@v2 + # - name: Build the Docker image + # run: | + # branch="${ref##*/}" + # docker build -t $repo:$branch -t $repo:$branch-${{github.sha}} . + # - name: Master tag + # if: github.ref == 'refs/heads/master' + # run: | + # branch="${ref##*/}" + # bot_ver=$(grep -i bot_version cogs/utils/bot_version.py | cut -d" " -f3 | tr -d \") + # docker tag $repo:$branch $repo:$bot_ver + # - name: Bump version and push tag + # if: github.ref == 'refs/heads/master' + # uses: mathieudutour/github-tag-action@v3 + # with: + # github_token: ${{ secrets.GITHUB_TOKEN }} + # - name: Login to registry + # if: github.event.pull_request == false + # run: echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin + # - name: Pushes the Docker image + # if: github.event.pull_request == false + # run: docker push $repo diff --git a/.github/workflows/build.yml-wait b/.github/workflows/build.yml-wait deleted file mode 100644 index a49fd18..0000000 --- a/.github/workflows/build.yml-wait +++ /dev/null @@ -1,52 +0,0 @@ -name: Test And Build BOT -on: [push, pull_request] - -jobs: - flake8: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: Set up Python 3.8 - uses: actions/setup-python@v1 - with: - python-version: 3.8 - - name: Lint with flake8 - run: | - pip install flake8 - flake8 --max-line-length 120 --statistics ${FLAKE_FILES} - - build-and-push: - needs: flake8 - runs-on: ubuntu-latest - env: - repo: rnorge/music - ref: ${{github.ref}} - DOCKER_USERNAME: roxedus - DOCKER_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} - steps: - - uses: actions/checkout@v1 - - name: Build the Docker image - run: | - branch="${ref##*/}" - docker build -t $repo:$branch -t $repo:$branch-${{github.sha}} . - - - name: Master tag - if: github.ref == 'refs/heads/master' - run: | - branch="${ref##*/}" - bot_ver=$(grep -i bot_version cogs/utils/bot_version.py | cut -d" " -f3 | tr -d \") - docker tag $repo:$branch $repo:$bot_ver - - - name: Bump version and push tag - if: github.ref == 'refs/heads/master' - uses: mathieudutour/github-tag-action@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Login to registry - if: github.event.pull_request == false - run: echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin - - - name: Pushes the Docker image - if: github.event.pull_request == false - run: docker push $repo From 17eed890baab6d59937fb98fbcbe12a237bc9b8a Mon Sep 17 00:00:00 2001 From: Roxedus Date: Thu, 27 Aug 2020 20:32:02 +0200 Subject: [PATCH 21/25] More rules! --- setup.cfg | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index fce66fb..92598fc 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,7 @@ -[pycodestyle] -max_line_length = 120 +[flake8] +max-line-length = 120 +count = True +statistics = True [isort] known_discord = discord,lavalink @@ -11,4 +13,14 @@ no_lines_before = LOCALFOLDER indent = " " line_length = 120 balanced_wrapping = True -multi_line_output = 4 \ No newline at end of file +multi_line_output = 4 + +[pycodestyle] +max_line_length = 120 + +[pylint.FORMAT] +max-line-length=120 + +[pylint.BASIC] +variable-naming-style=camelCase +constant-naming-style=camelCase From e5684d3789397b950e81fe4f8d9cc70578f47965 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Thu, 27 Aug 2020 20:32:27 +0200 Subject: [PATCH 22/25] I Love VSCode --- .vscode/extensions.json | 7 +++++++ .vscode/launch.json | 15 +++++++++++++++ .vscode/settings.json | 15 +++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..aacd762 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "oderwat.indent-rainbow", + "ms-python.python", + "ms-python.vscode-pylance" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..958f4d6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [{ + "name": "Debug Bot", + "type": "python", + "request": "launch", + "program": "bot.py", + "console": "integratedTerminal", + "args": ["-D", "-d", "data"], + "host": "localhost" + }] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3f76c37 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "python.languageSever": "Pylance", + "python.linting.enabled": true, + "python.linting.pylintEnabled": true, + "python.linting.flake8Enabled": true, + "python.linting.pycodestyleEnabled": true, + "[python]": { + "editor.rulers": [120], + }, + "[Dockerfile]": { + "editor.formatOnSave": false + }, + "editor.tabSize": 4 + +} \ No newline at end of file From d33bf1f72319cd02d77cd8472c23d97a536127c8 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Thu, 27 Aug 2020 20:33:27 +0200 Subject: [PATCH 23/25] Fix linter errors --- README.md | 20 +++++++++++--------- cogs/errors.py | 7 +++---- cogs/music.py | 1 - cogs/nodemanager.py | 6 ++++-- cogs/utils/alias.py | 1 - 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index a7a965f..09f97ec 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # WIP - Shite Music Bot [![Build Status](https://jenkins.roxedus.net/buildStatus/icon?job=MusicBot%2Fdev)](https://jenkins.roxedus.net/job/MusicBot/job/dev/) -[![](https://images.microbadger.com/badges/image/rnorge/music:dev-amd64.svg)](https://microbadger.com/images/rnorge/music:dev-amd64 "Get your own image badge on microbadger.com") +[![MicroBadger](https://images.microbadger.com/badges/image/rnorge/music:dev-amd64.svg)](https://microbadger.com/images/rnorge/music:dev-amd64 "Get your own image badge on microbadger.com") + +## Features -### Features: - Translations, get the bot in your preferred langauge! - Round Robin style queue, you won't have to wait forever for your songs to play. - Noice per server customization options. @@ -12,18 +13,19 @@ - Lyrics command that sometimes gives the correct lyrics - DJ roles +### Setup -#### Setup 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. 4. Edit any other settings you want. -5. install requirements -> python -m pip install -r requirements.txt +5. install requirements `python -m pip install -r requirements.txt` 6. run the bot :) -#### Docker -#### Compose Example: +### Docker + +### Compose Example + ````yaml version: '3' networks: @@ -42,7 +44,7 @@ services: - lavalink volumes: - /compose/BottStack/lavalink/application.yml:/opt/Lavalink/application.yml - bot: + bot: container_name: ProdMaster image: rnorge/music networks: @@ -51,4 +53,4 @@ services: volumes: - /compose/BottStack/ProdBetaMaster/script:/diks - /compose/BottStack/ProdBetaMaster/data:/app/data -```` \ No newline at end of file +```` diff --git a/cogs/errors.py b/cogs/errors.py index f0ea6da..92117d7 100644 --- a/cogs/errors.py +++ b/cogs/errors.py @@ -57,10 +57,9 @@ class Errors(commands.Cog): elif (err.original == 'You need to be in my voicechannel.'): return await send_error_embed('{errors.my_channel}') - if isinstance(err, commands.CommandOnCooldown): await ctx.send(f"{ctx.message.author.mention} Command is on cooldown. " - f"Try again in `{err.retry_after:.1f}` seconds.") + f"Try again in `{err.retry_after:.1f}` seconds.") elif isinstance(err, commands.NoPrivateMessage): await ctx.send('That command is not available in DMs') @@ -70,11 +69,11 @@ class Errors(commands.Cog): if self.bot.debug: tb = err.__traceback__ traceback.print_tb(tb) - self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) + self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) else: to_log = (RuntimeError, commands.CheckFailure, commands.CommandInvokeError, - commands.NoPrivateMessage) + commands.NoPrivateMessage) if isinstance(err, to_log): self.logger.debug("Error running command: %s\nTraceback: %s" % (ctx.command, err)) diff --git a/cogs/music.py b/cogs/music.py index 3742dce..9720aad 100644 --- a/cogs/music.py +++ b/cogs/music.py @@ -16,7 +16,6 @@ from typing import Optional from bs4 import BeautifulSoup from .utils import checks, thumbnailer, timeformatter -from .utils.mixplayer import MixPlayer from .utils.paginator import QueuePaginator, Scroller, TextPaginator from .utils.selector import Selector diff --git a/cogs/nodemanager.py b/cogs/nodemanager.py index 81f8530..ef08c9b 100644 --- a/cogs/nodemanager.py +++ b/cogs/nodemanager.py @@ -8,9 +8,11 @@ import codecs import yaml -from .utils.mixplayer import MixPlayer +# Bot Utilities from cogs.helpformatter import commandhelper from cogs.utils.paginator import Scroller +from .utils.mixplayer import MixPlayer + class NodeManager(commands.Cog): def __init__(self, bot): @@ -51,7 +53,7 @@ class NodeManager(commands.Cog): if node['name'] in name_cache: continue - self.bot.lavalink.add_node(**node) + self.bot.lavalink.add_node(**node) self.logger.debug("Adding Lavalink node: %s on %s with the port %s in %s" % ( node['name'], node['host'], node['port'], node['region'],)) diff --git a/cogs/utils/alias.py b/cogs/utils/alias.py index d7a0f2a..8a68d61 100644 --- a/cogs/utils/alias.py +++ b/cogs/utils/alias.py @@ -6,7 +6,6 @@ from os import path import yaml - """ Not the prettiest this, works by replacing any found aliases in a command string with the actual command names. Allows per guild aliases of subcommands without doing anything to discord.py itself. Suggestions of better/correct From 93224cdc279e929f8f1024a0c98eacd22ed24820 Mon Sep 17 00:00:00 2001 From: Roxedus Date: Thu, 27 Aug 2020 20:33:51 +0200 Subject: [PATCH 24/25] Test Workflow --- .github/workflows/build.yml | 102 ++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 38 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7a46fb5..d92a696 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,44 +4,70 @@ on: [push, pull_request] jobs: flake8: runs-on: ubuntu-latest + env: + CheckFiles: "bot.py cogs/" steps: - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v1 + with: + python-version: 3.8 + - name: Lint with flake8 + run: | + pip install flake8 + flake8 ${CheckFiles} - - name: Lint Code Base - uses: github/super-linter@v3 - env: - VALIDATE_ALL_CODEBASE: true - VALIDATE_PYTHON_BLACK: false - DEFAULT_BRANCH: master - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # build-and-push: - # needs: flake8 - # runs-on: ubuntu-latest - # env: - # repo: rnorge/music - # ref: ${{github.ref}} - # DOCKER_USERNAME: roxedus - # DOCKER_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} - # steps: - # - uses: actions/checkout@v2 - # - name: Build the Docker image - # run: | - # branch="${ref##*/}" - # docker build -t $repo:$branch -t $repo:$branch-${{github.sha}} . - # - name: Master tag - # if: github.ref == 'refs/heads/master' - # run: | - # branch="${ref##*/}" - # bot_ver=$(grep -i bot_version cogs/utils/bot_version.py | cut -d" " -f3 | tr -d \") - # docker tag $repo:$branch $repo:$bot_ver - # - name: Bump version and push tag - # if: github.ref == 'refs/heads/master' - # uses: mathieudutour/github-tag-action@v3 - # with: - # github_token: ${{ secrets.GITHUB_TOKEN }} - # - name: Login to registry - # if: github.event.pull_request == false - # run: echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin - # - name: Pushes the Docker image - # if: github.event.pull_request == false - # run: docker push $repo + - name: Check with Isort + run: | + pip install isort + isort --check --sp setup.cfg ${CheckFiles} + - name: Sort with Isort + if: failure() + run: | + isort --sp setup.cfg ${CheckFiles} + - name: Create Pull Request + if: failure() + uses: peter-evans/create-pull-request@v2 + with: + token: ${{ secrets.GH_TOKEN }} + branch: actions/auto + commit-message: Changes done by tests + committer: Roxedus + title: Linter changed files + + build-and-push: + needs: flake8 + runs-on: ubuntu-latest + env: + repo: rnorge/music + ref: ${{github.ref}} + DOCKER_USERNAME: roxedus + DOCKER_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} + + steps: + - uses: actions/checkout@v2 + - name: Build the Docker image + run: | + branch="${ref##*/}" + docker build -t $repo:$branch -t $repo:$branch-${{github.sha}} . + + - name: Master tag + if: github.ref == 'refs/heads/master' + run: | + branch="${ref##*/}" + bot_ver=$(grep -i bot_version cogs/utils/bot_version.py | cut -d" " -f3 | tr -d \") + docker tag $repo:$branch $repo:$bot_ver + + - name: Bump version and push tag + if: github.ref == 'refs/heads/master' + uses: mathieudutour/github-tag-action@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to registry + if: github.event.pull_request == false + run: echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin + + - name: Pushes the Docker image + if: github.event.pull_request == false + run: docker push $repo From 12e6ebb0d4f856028acd9712700089b4db8e1c1a Mon Sep 17 00:00:00 2001 From: Ev-1 <33662061+Ev-1@users.noreply.github.com> Date: Fri, 28 Aug 2020 16:08:08 +0200 Subject: [PATCH 25/25] Fixed some translations --- bot.py | 2 -- localization/en_en/nodemanager.yaml | 2 ++ localization/nb_no/nodemanager.yaml | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 localization/en_en/nodemanager.yaml create mode 100644 localization/nb_no/nodemanager.yaml diff --git a/bot.py b/bot.py index 47f93b9..9b3d0e0 100644 --- a/bot.py +++ b/bot.py @@ -85,8 +85,6 @@ class Bot(commands.Bot): if not hasattr(self, 'uptime'): self.uptime = time.time() - self.session = aiohttp.ClientSession(loop=self.loop) - for extension in on_ready_extensions: try: self.logger.debug("Loading extension %s" % extension) diff --git a/localization/en_en/nodemanager.yaml b/localization/en_en/nodemanager.yaml new file mode 100644 index 0000000..7ec4f85 --- /dev/null +++ b/localization/en_en/nodemanager.yaml @@ -0,0 +1,2 @@ +pageindicator: Viewing page {_current}/{_total} | Type "{_prefix}help " for more information +notcommand: Looks like "{_command}" is not a command or category. \ No newline at end of file diff --git a/localization/nb_no/nodemanager.yaml b/localization/nb_no/nodemanager.yaml new file mode 100644 index 0000000..ffa8294 --- /dev/null +++ b/localization/nb_no/nodemanager.yaml @@ -0,0 +1,2 @@ +pageindicator: Viser side {_current}/{_total} | Skriv "{_prefix}hjelp " for mer informasjon +notcommand: Ser ut som "{_command}" ikke er en kategori eller en kommando. \ No newline at end of file