Moved decorators added node change command

This commit is contained in:
Ev-1 committed 2020-09-12 18:16:51 +02:00
1 parent 80d1cdc184
commit acbad1a61a
7 files changed
+271 -215

No files matched your search

+10 -2
View File
@@ -10,6 +10,14 @@
"[Dockerfile]": { "[Dockerfile]": {
"editor.formatOnSave": false "editor.formatOnSave": false
}, },
"editor.tabSize": 4 "editor.tabSize": 4,
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/*.pyc": {"when": "$(basename).py"},
"**/__pycache__": true,
},
} }
+4 -2
View File
@@ -94,10 +94,12 @@ class Music(commands.Cog):
# commands # commands
from .basic_commands import ( from .basic_commands import (
_boost, _disconnect, _djremove, _history, _lyrics, _move, _myqueue, _normalize, _now, _pause, _play, _queue, _disconnect, _djremove, _move, _myqueue, _now, _pause, _play, _queue, _reconnect, _remove, _search, _seek,
_reconnect, _remove, _scrub, _search, _seek, _shuffle, _skip, _skip_to, _stop, _user_queue_remove, _volume) _shuffle, _skip, _skip_to, _stop, _user_queue_remove, _volume)
# events # events
from .events import check_leave_voice, cog_unload, leave_check, leave_timer, on_voice_state_update, track_hook from .events import check_leave_voice, cog_unload, leave_check, leave_timer, on_voice_state_update, track_hook
# commands
from .extra_commands import _boost, _history, _lyrics, _normalize, _scrub
def setup(bot): def setup(bot):
+21 -210
View File
@@ -1,20 +1,20 @@
"""
Commands that interacti with just discord and lavalink and only present the basic commands needed for a music bot
"""
# Discord Packages # Discord Packages
import discord import discord
import lavalink import lavalink
from discord.ext import commands from discord.ext import commands
import asyncio import asyncio
import json
import math import math
import re import re
import urllib
from bs4 import BeautifulSoup
from ..utils import checks, thumbnailer, timeformatter from ..utils import checks, thumbnailer, timeformatter
from ..utils.decorators import require_playing, require_queue, require_voice_connection from ..utils.paginator import QueuePaginator, Scroller
from ..utils.paginator import QueuePaginator, Scroller, TextPaginator
from ..utils.selector import Selector from ..utils.selector import Selector
from .decorators import require_playing, require_queue, require_voice_connection
time_rx = re.compile('[0-9]+') time_rx = re.compile('[0-9]+')
url_rx = re.compile('https?:\\/\\/(?:www\\.)?.+') url_rx = re.compile('https?:\\/\\/(?:www\\.)?.+')
@@ -340,7 +340,7 @@ async def _djremove(self, ctx, pos: int, member: discord.Member = None):
removed = player.remove_user_track(member.id, pos - 1) removed = player.remove_user_track(member.id, pos - 1)
requester = self.bot.get_user(removed.requester) requester = self.bot.get_user(removed.requester)
await ctx.send(ctx.localizer.format_str("{dj_removed}", _title=removed.title, _user=requester.name)) await ctx.send(ctx.localizer.format_str("{dj_removed}", _title=removed.title, _user=requester.display_name))
else: else:
await ctx.send(ctx.localizer.format_str("{out_of_range}", _len=len(queue))) await ctx.send(ctx.localizer.format_str("{out_of_range}", _len=len(queue)))
@@ -426,11 +426,20 @@ async def _reconnect(self, ctx):
player = self.bot.lavalink.player_manager.get(ctx.guild.id) player = self.bot.lavalink.player_manager.get(ctx.guild.id)
current_channel = player.channel_id current_channel = player.channel_id
await player.stop() async def recon():
await self.connect_to(ctx.guild.id, None) await player.stop()
await asyncio.sleep(1) # Pretend stuff is happening/give everything some time to reset. await self.connect_to(ctx.guild.id, None)
await self.connect_to(ctx.guild.id, current_channel) await asyncio.sleep(1) # Pretend stuff is happening/give everything some time to reset.
await player.play() await self.connect_to(ctx.guild.id, current_channel)
if player.current:
track = player.current
start_time = player.position
await recon()
if track:
await player.play(track, start_time=start_time)
else:
recon()
@commands.command(name='volume') @commands.command(name='volume')
@@ -453,201 +462,3 @@ async def _volume(self, ctx, volume: int = None):
embed = discord.Embed(description="{volume.set_to}", color=ctx.me.color) embed = discord.Embed(description="{volume.set_to}", color=ctx.me.color)
embed = ctx.localizer.format_embed(embed, _volume=player.volume) embed = ctx.localizer.format_embed(embed, _volume=player.volume)
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name='normalize')
@checks.dj_or(alone=True)
@require_voice_connection()
async def _normalize(self, ctx):
""" Reset the equalizer and volume """
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
await player.set_volume(100)
await player.bassboost(False)
embed = discord.Embed(description='{volume.reset}', color=ctx.me.color)
embed = ctx.localizer.format_embed(embed)
await ctx.send(embed=embed)
@commands.command(name='boost')
@checks.dj_or(alone=True)
async def _boost(self, ctx, boost: bool = None):
""" Set the equalizer to bass boost the music """
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
if boost:
await player.bassboost(boost)
embed = discord.Embed(color=ctx.me.color)
embed.description = '{boost.on}' if player.boosted else '{boost.off}'
embed = ctx.localizer.format_embed(embed)
await ctx.send(embed=embed)
@commands.command(name='history')
async def _history(self, ctx):
""" Show the last 10 songs played """
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
history = player.get_history()
if not history:
embed = discord.Embed(description='{history.empty}', color=ctx.me.color)
embed = ctx.localizer.format_embed(embed)
return await ctx.send(embed=embed)
track = history[0]
description = 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'
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'
embed = discord.Embed(title=ctx.localizer.format_str('{history.title}'), color=ctx.me.color,
description=description)
if thumbnail_url:
embed.set_thumbnail(url=thumbnail_url)
await ctx.send(embed=embed)
@commands.cooldown(1, 5, commands.BucketType.guild)
@commands.command(name='lyrics')
async def _lyrics(self, ctx, *query: str):
# TODO:
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
genius_access_token = self.bot.APIkeys.get('genius', None)
if genius_access_token is None:
return await ctx.send('Missing API key')
excluded_words = ['music', 'video', 'version', 'original', 'lyrics', 'lyric',
'official', 'live', 'instrumental', 'audio', 'hd']
query = ' '.join(query)
if not query and player.is_playing:
query = player.current.title
query = re.sub(r'[-()_\[\]]', '', query)
filtered_words = [word for word in query.split() if word.lower() not in excluded_words]
query = ' '.join(filtered_words)
async def get_site_content(url):
async with self.bot.session.get(url) as resp:
response = await resp.read()
return response.decode('utf-8')
embed = discord.Embed(description=':mag_right:')
status_msg = await ctx.send(embed=embed)
try:
url = 'https://api.genius.com/search?' + urllib.parse.urlencode(
{'access_token': genius_access_token, 'q': query})
result = await get_site_content(url)
response = json.loads(result)
song_id = response['response']['hits'][0]['result']['id']
except Exception:
embed = discord.Embed(description=':x:', color=0xFF0000)
return await status_msg.edit(embed=embed)
result = await get_site_content(f'https://api.genius.com/songs/{song_id}?access_token={genius_access_token}')
song = json.loads(result)['response']['song']
response = await get_site_content(song['url'])
scraped_data = BeautifulSoup(response, 'html.parser')
lyrics = scraped_data.find(class_='lyrics').get_text()
paginator = TextPaginator(max_size=2000, max_lines=50, color=0xFFFF64)
for line in lyrics.split('\n'):
paginator.add_line(line)
await status_msg.delete()
paginator.pages[0].url = song['url']
paginator.pages[0].title = song['full_title']
paginator.pages[0].set_thumbnail(url=song['header_image_thumbnail_url'])
paginator.pages[0].set_author(name='Genius', icon_url='https://i.imgur.com/NmCTsoF.png')
if len(paginator.pages) < 4:
for page in paginator.pages:
await ctx.send(embed=page)
else:
paginator.add_page_indicator(ctx.localizer)
await Scroller(ctx, paginator).start_scrolling()
@commands.command(name='scrub')
@checks.dj_or(alone=True)
@require_voice_connection()
@require_playing(require_user_listening=True)
async def _scrub(self, ctx):
""" Lists the first 10 search results from a given query. """
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
controls = '{scrub.controls}'
scrubber = [
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', player.seek, -1000),
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE}', player.seek, -15),
('\N{DOUBLE VERTICAL BAR}', player.set_pause, True),
('\N{BLACK RIGHT-POINTING TRIANGLE}', player.set_pause, False),
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE}', player.seek, 15),
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', player.seek, 1000),
]
selection = None
arg = None
def check(reaction, user):
if user is None or user.id != ctx.author.id:
return False
if reaction.message.id != msg.id:
return False
for (emoji, func, _arg) in scrubber:
if emoji == reaction.emoji:
nonlocal selection
nonlocal arg
selection = func
arg = _arg
return True
return False
embed = discord.Embed(description='{scrub.add}', color=ctx.me.color)
embed = ctx.localizer.format_embed(embed)
msg = await ctx.send(embed=embed)
for (emoji, _, _) in scrubber:
await msg.add_reaction(emoji)
embed.description = controls
embed = ctx.localizer.format_embed(embed)
await msg.edit(embed=embed)
scrubbing = True
while scrubbing:
try:
reaction, user = await self.bot.wait_for('reaction_add', timeout=15.0, check=check)
except asyncio.TimeoutError:
# PEP8EDIT scrolling = False
try:
await msg.delete()
await ctx.message.delete()
except discord.Forbidden:
pass
except discord.HTTPException:
pass
finally:
break
try:
await msg.remove_reaction(reaction, user)
except discord.Forbidden:
pass
if selection is not None:
if not isinstance(arg, bool):
arg = player.position + arg * 1000
await selection(arg)
File renamed without changes.
+2
View File
@@ -28,6 +28,8 @@ async def track_hook(self, event):
pass pass
if isinstance(event, lavalink.events.NodeChangedEvent): if isinstance(event, lavalink.events.NodeChangedEvent):
pass pass
if isinstance(event, lavalink.events.TrackStuckEvent):
print(event)
@commands.Cog.listener() @commands.Cog.listener()
+215
View File
@@ -0,0 +1,215 @@
"""
Commands that add to the music bot experience, like equalizers, commands that access the web, like lyrics, and
commands that are complex and mostly for show, like scrubber.
"""
# Discord Packages
import discord
from discord.ext import commands
import asyncio
import json
import re
import urllib
from bs4 import BeautifulSoup
from ..utils import checks
from ..utils.paginator import Scroller, TextPaginator
from .decorators import require_playing, require_voice_connection
@commands.command(name='normalize')
@checks.dj_or(alone=True)
@require_voice_connection()
async def _normalize(self, ctx):
""" Reset the equalizer and volume """
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
await player.set_volume(100)
await player.bassboost(False)
embed = discord.Embed(description='{volume.reset}', color=ctx.me.color)
embed = ctx.localizer.format_embed(embed)
await ctx.send(embed=embed)
@commands.command(name='boost')
@checks.dj_or(alone=True)
async def _boost(self, ctx, boost: bool = None):
""" Set the equalizer to bass boost the music """
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
if boost:
await player.bassboost(boost)
embed = discord.Embed(color=ctx.me.color)
embed.description = '{boost.on}' if player.boosted else '{boost.off}'
embed = ctx.localizer.format_embed(embed)
await ctx.send(embed=embed)
@commands.command(name='history')
async def _history(self, ctx):
""" Show the last 10 songs played """
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
history = player.get_history()
if not history:
embed = discord.Embed(description='{history.empty}', color=ctx.me.color)
embed = ctx.localizer.format_embed(embed)
return await ctx.send(embed=embed)
track = history[0]
description = 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'
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'
embed = discord.Embed(title=ctx.localizer.format_str('{history.title}'), color=ctx.me.color,
description=description)
if thumbnail_url:
embed.set_thumbnail(url=thumbnail_url)
await ctx.send(embed=embed)
@commands.cooldown(1, 5, commands.BucketType.guild)
@commands.command(name='lyrics')
async def _lyrics(self, ctx, *query: str):
# TODO:
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
genius_access_token = self.bot.APIkeys.get('genius', None)
if genius_access_token is None:
return await ctx.send('Missing API key')
excluded_words = ['music', 'video', 'version', 'original', 'lyrics', 'lyric',
'official', 'live', 'instrumental', 'audio', 'hd']
query = ' '.join(query)
if not query and player.is_playing:
query = player.current.title
query = re.sub(r'[-()_\[\]]', '', query)
filtered_words = [word for word in query.split() if word.lower() not in excluded_words]
query = ' '.join(filtered_words)
async def get_site_content(url):
async with self.bot.session.get(url) as resp:
response = await resp.read()
return response.decode('utf-8')
embed = discord.Embed(description=':mag_right:')
status_msg = await ctx.send(embed=embed)
try:
url = 'https://api.genius.com/search?' + urllib.parse.urlencode(
{'access_token': genius_access_token, 'q': query})
result = await get_site_content(url)
response = json.loads(result)
song_id = response['response']['hits'][0]['result']['id']
except Exception:
embed = discord.Embed(description=':x:', color=0xFF0000)
return await status_msg.edit(embed=embed)
result = await get_site_content(f'https://api.genius.com/songs/{song_id}?access_token={genius_access_token}')
song = json.loads(result)['response']['song']
response = await get_site_content(song['url'])
scraped_data = BeautifulSoup(response, 'html.parser')
lyrics = scraped_data.find(class_='lyrics').get_text()
paginator = TextPaginator(max_size=2000, max_lines=50, color=0xFFFF64)
for line in lyrics.split('\n'):
paginator.add_line(line)
await status_msg.delete()
paginator.pages[0].url = song['url']
paginator.pages[0].title = song['full_title']
paginator.pages[0].set_thumbnail(url=song['header_image_thumbnail_url'])
paginator.pages[0].set_author(name='Genius', icon_url='https://i.imgur.com/NmCTsoF.png')
if len(paginator.pages) < 4:
for page in paginator.pages:
await ctx.send(embed=page)
else:
paginator.add_page_indicator(ctx.localizer)
await Scroller(ctx, paginator).start_scrolling()
@commands.command(name='scrub')
@checks.dj_or(alone=True)
@require_voice_connection()
@require_playing(require_user_listening=True)
async def _scrub(self, ctx):
""" Lists the first 10 search results from a given query. """
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
controls = '{scrub.controls}'
scrubber = [
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', player.seek, -1000),
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE}', player.seek, -15),
('\N{DOUBLE VERTICAL BAR}', player.set_pause, True),
('\N{BLACK RIGHT-POINTING TRIANGLE}', player.set_pause, False),
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE}', player.seek, 15),
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', player.seek, 1000),
]
selection = None
arg = None
def check(reaction, user):
if user is None or user.id != ctx.author.id:
return False
if reaction.message.id != msg.id:
return False
for (emoji, func, _arg) in scrubber:
if emoji == reaction.emoji:
nonlocal selection
nonlocal arg
selection = func
arg = _arg
return True
return False
embed = discord.Embed(description='{scrub.add}', color=ctx.me.color)
embed = ctx.localizer.format_embed(embed)
msg = await ctx.send(embed=embed)
for (emoji, _, _) in scrubber:
await msg.add_reaction(emoji)
embed.description = controls
embed = ctx.localizer.format_embed(embed)
await msg.edit(embed=embed)
scrubbing = True
while scrubbing:
try:
reaction, user = await self.bot.wait_for('reaction_add', timeout=15.0, check=check)
except asyncio.TimeoutError:
# PEP8EDIT scrolling = False
try:
await msg.delete()
await ctx.message.delete()
except (discord.Forbidden, discord.HTTPException):
pass
finally:
break
try:
await msg.remove_reaction(reaction, user)
except discord.Forbidden:
pass
if selection is not None:
if not isinstance(arg, bool):
arg = player.position + arg * 1000
await selection(arg)
+19 -1
View File
@@ -119,7 +119,7 @@ class NodeManager(commands.Cog):
@_node.command(name='add') @_node.command(name='add')
@commands.is_owner() @commands.is_owner()
async def _add(self, ctx, host, port, password, region, name=None): async def _add(self, ctx, host, port, password, region, name=None):
self.bot.lavalink.add_node(host, port, password, region, name) self.bot.lavalink.add_node(host, port, password, region, name=name)
self.logger.debug("Adding Lavalink node: %s on %s with the port %s in %s" % (host, port, 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, embed = await self._node_presenter(ctx, {'host': host, 'port': port, 'password': password,
'region': region, 'name': name}) 'region': region, 'name': name})
@@ -152,6 +152,24 @@ class NodeManager(commands.Cog):
if not sent_feedback: if not sent_feedback:
await ctx.send('No node found') await ctx.send('No node found')
@_node.command(name='change')
@commands.is_owner()
async def _nodechange(self, ctx, node=None):
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
if node is None:
await player.change_node(player.node)
else:
newnode = None
for _node in self.bot.lavalink.node_manager.nodes:
if (_node.name or _node.host) == node:
newnode = _node
if not newnode:
return
await player.change_node(newnode)
def setup(bot): def setup(bot):
bot.add_cog(NodeManager(bot)) bot.add_cog(NodeManager(bot))