mirror of
https://github.com/UiO-Gaming/ShiteMusicBot.git
synced 2026-11-07 14:54:29 +01:00
Vote skipping, commands locked behind DJ.
This commit is contained in:
1 parent
e3f9642e32
commit
d473be5d21
5 files changed
+176
-75
No files matched your search
@@ -10,22 +10,24 @@ from cogs.utils.settings import Settings
|
||||
|
||||
|
||||
initial_extension = [
|
||||
'cogs.cogs',
|
||||
'cogs.botsettings',
|
||||
'cogs.misc',
|
||||
'cogs.music'
|
||||
'cogs.cogs',
|
||||
'cogs.botsettings',
|
||||
'cogs.misc',
|
||||
'cogs.music'
|
||||
]
|
||||
|
||||
|
||||
with codecs.open("config.json", 'r', encoding='utf8') as f:
|
||||
config = json.load(f)
|
||||
config = json.load(f)
|
||||
|
||||
default_prefix = config["default_prefix"]
|
||||
|
||||
|
||||
def _get_prefix(bot, message):
|
||||
if not message.guild:
|
||||
return default_prefix
|
||||
prefixes = bot.settings.get_prefix(message.guild.id)
|
||||
return commands.when_mentioned_or(*prefixes)(bot, message)
|
||||
if not message.guild:
|
||||
return default_prefix
|
||||
prefixes = bot.settings.get_prefix(message.guild.id)
|
||||
return commands.when_mentioned_or(*prefixes)(bot, message)
|
||||
|
||||
|
||||
class Bot(commands.Bot):
|
||||
@@ -101,6 +103,6 @@ def run_bot(debug: bool=False):
|
||||
|
||||
if __name__ == '__main__':
|
||||
if 'debug' in sys.argv:
|
||||
run_bot(debug=True)
|
||||
run_bot(debug=True)
|
||||
else:
|
||||
run_bot(debug=False)
|
||||
+68
-31
@@ -28,6 +28,7 @@ url_rx = re.compile('https?:\/\/(?:www\.)?.+')
|
||||
|
||||
class Music:
|
||||
def __init__(self, bot):
|
||||
|
||||
self.bot = bot
|
||||
|
||||
if not hasattr(bot, 'lavalink'):
|
||||
@@ -46,6 +47,10 @@ class Music:
|
||||
self.bot.lavalink.players.clear()
|
||||
self.bot.lavalink.unregister_hook(self._track_hook)
|
||||
|
||||
async def __local_check(self, ctx):
|
||||
is_guild = ctx.guild is not None
|
||||
return is_guild
|
||||
|
||||
async def _track_hook(self, event):
|
||||
if isinstance(event, lavalink.Events.StatsUpdateEvent):
|
||||
return
|
||||
@@ -63,7 +68,6 @@ class Music:
|
||||
await channel.send('Queue ended.')
|
||||
|
||||
@commands.command(name='play', aliases=['p'])
|
||||
@commands.guild_only()
|
||||
async def _play(self, ctx, *, query: str):
|
||||
""" Searches and plays a song from a given query. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -103,19 +107,7 @@ class Music:
|
||||
if not player.is_playing:
|
||||
await player.play()
|
||||
|
||||
@commands.command(name='previous', aliases=['pv'])
|
||||
@commands.guild_only()
|
||||
async def _previous(self, ctx):
|
||||
""" Plays the previous song. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
|
||||
try:
|
||||
await player.play_previous()
|
||||
except lavalink.NoPreviousTrack:
|
||||
await ctx.send('There is no previous song to play.')
|
||||
|
||||
@commands.command(name='playnow', aliases=['pn'])
|
||||
@commands.guild_only()
|
||||
async def _playnow(self, ctx, *, query: str):
|
||||
""" Plays immediately a song. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -143,11 +135,14 @@ class Music:
|
||||
await player.play_now(requester=ctx.author.id, track=track)
|
||||
|
||||
@commands.command(name='skipto', aliases=['st'])
|
||||
@commands.guild_only()
|
||||
@checks.is_DJ()
|
||||
async def _skip_to(self, ctx, index: int):
|
||||
""" Plays the queue from a specific point. Disregards tracks before the index. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
|
||||
if ctx.author not in player.listeners:
|
||||
return await ctx.send('You have to be listening to the bot')
|
||||
|
||||
if index < 1:
|
||||
return await ctx.send('Invalid specified index.')
|
||||
if len(player.queue) < index:
|
||||
@@ -155,7 +150,7 @@ class Music:
|
||||
await player.skip_to(index - 1)
|
||||
|
||||
@commands.command(name='seek')
|
||||
@commands.guild_only()
|
||||
@checks.is_DJ()
|
||||
async def _seek(self, ctx, *, time: str):
|
||||
""" Seeks to a given position in a track. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -163,6 +158,9 @@ class Music:
|
||||
if not player.is_playing:
|
||||
return await ctx.send('Not playing.')
|
||||
|
||||
if ctx.author not in player.listeners:
|
||||
return await ctx.send('You have to be listening to the bot')
|
||||
|
||||
seconds = time_rx.search(time)
|
||||
if not seconds:
|
||||
return await ctx.send('You need to specify the amount of seconds to skip!')
|
||||
@@ -177,7 +175,6 @@ class Music:
|
||||
await ctx.send(f'Moved track to **{lavalink.Utils.format_time(track_time)}**')
|
||||
|
||||
@commands.command(name='skip', aliases=['forceskip', 'fs'])
|
||||
@commands.guild_only()
|
||||
async def _skip(self, ctx):
|
||||
""" Skips the current track. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -185,15 +182,25 @@ class Music:
|
||||
if not player.is_playing:
|
||||
return await ctx.send('Not playing.')
|
||||
|
||||
await player.skip()
|
||||
await ctx.send('⏭ | Skipped.')
|
||||
player.add_skipper(ctx.author)
|
||||
total = len(player.listeners)
|
||||
skips = len(player.skip_voters)
|
||||
if skips >= math.ceil(total/2) or player.current.requester == ctx.author.id:
|
||||
await player.skip()
|
||||
await ctx.send('Skipped.')
|
||||
else:
|
||||
if skips != 0:
|
||||
await ctx.send(f'{skips} out of {math.ceil(total/2)} required haters have voted to skip.')
|
||||
|
||||
@commands.command(name='stop')
|
||||
@commands.guild_only()
|
||||
@checks.is_DJ()
|
||||
async def _stop(self, ctx):
|
||||
""" Stops the player and clears its queue. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
|
||||
if ctx.author not in player.listeners:
|
||||
return await ctx.send('You have to be listening to the bot')
|
||||
|
||||
if not player.is_playing:
|
||||
return await ctx.send('Not playing.')
|
||||
|
||||
@@ -202,9 +209,12 @@ class Music:
|
||||
await ctx.send('⏹ | Stopped.')
|
||||
|
||||
@commands.command(name='now', aliases=['np', 'n', 'playing'])
|
||||
@commands.guild_only()
|
||||
async def _now(self, ctx):
|
||||
""" Shows some stats about the currently playing song. """
|
||||
|
||||
#def scrubber(song, length):
|
||||
|
||||
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
song = 'Nothing'
|
||||
|
||||
@@ -225,7 +235,6 @@ class Music:
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command(name='queue', aliases=['q'])
|
||||
@commands.guild_only()
|
||||
async def _queue(self, ctx, user: discord.Member=None):
|
||||
""" Shows the global queue or another users queue. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -246,7 +255,6 @@ class Music:
|
||||
await scroller.start_scrolling()
|
||||
|
||||
@commands.command(name='myqueue', aliases=['mq'])
|
||||
@commands.guild_only()
|
||||
async def _myqueue(self, ctx):
|
||||
""" Shows your queue. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -259,7 +267,6 @@ class Music:
|
||||
await scroller.start_scrolling()
|
||||
|
||||
@commands.command(name='pause', aliases=['resume'])
|
||||
@commands.guild_only()
|
||||
async def _pause(self, ctx):
|
||||
""" Pauses/Resumes the current track. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -275,7 +282,7 @@ class Music:
|
||||
await ctx.send('⏯ | Paused')
|
||||
|
||||
@commands.command(name='volume', aliases=['vol'])
|
||||
@commands.guild_only()
|
||||
@checks.is_DJ()
|
||||
async def _volume(self, ctx, volume: int = None):
|
||||
""" Changes the player's volume. Must be between 0 and 1000. Error Handling for that is done by Lavalink. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -286,8 +293,23 @@ class Music:
|
||||
await player.set_volume(volume)
|
||||
await ctx.send(f'🔈 | Set to {player.volume}%')
|
||||
|
||||
@commands.command(name='boost', aliases=['boo'])
|
||||
async def _boost(self, ctx, boost: bool=None):
|
||||
""" Changes the player's volume. Must be between 0 and 1000. Error Handling for that is done by Lavalink. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
if boost is None:
|
||||
if player.boosted:
|
||||
await ctx.send('Bass boost is on')
|
||||
else:
|
||||
await ctx.send('Bass boost is off')
|
||||
else:
|
||||
await player.bassboost(boost)
|
||||
if boost:
|
||||
await ctx.send('Bass boost turned on')
|
||||
else:
|
||||
await ctx.send('Bass boost turned off')
|
||||
|
||||
@commands.command(name='shuffle')
|
||||
@commands.guild_only()
|
||||
async def _shuffle(self, ctx):
|
||||
""" Shuffles your queue. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -300,7 +322,6 @@ class Music:
|
||||
await ctx.send('Your queue has been shuffled')
|
||||
|
||||
@commands.command(name='move', aliases=["m"])
|
||||
@commands.guild_only()
|
||||
async def _move(self, ctx, from_pos: int, to_pos: int):
|
||||
""" Moves a song in your queue. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -319,7 +340,6 @@ class Music:
|
||||
await ctx.send(f'{moved.title} moved from position {from_pos} to {to_pos} in your queue')
|
||||
|
||||
@commands.command(name='remove')
|
||||
@commands.guild_only()
|
||||
async def _remove(self, ctx, pos: int):
|
||||
""" Removes the song at pos from your queue. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -339,7 +359,6 @@ class Music:
|
||||
await ctx.send(f'**{removed.title}** removed.')
|
||||
|
||||
@commands.command(name="DJremove")
|
||||
@commands.guild_only()
|
||||
@checks.is_DJ()
|
||||
async def _djremove(self, ctx, pos: int, user: discord.Member=None):
|
||||
""" Remove a song from either the global queue or a users queue"""
|
||||
@@ -372,7 +391,6 @@ class Music:
|
||||
|
||||
|
||||
@commands.command(name='find')
|
||||
@commands.guild_only()
|
||||
async def _find(self, ctx, *, query):
|
||||
""" Lists the first 10 search results from a given query. """
|
||||
await ctx.trigger_typing()
|
||||
@@ -453,7 +471,6 @@ class Music:
|
||||
break
|
||||
|
||||
@commands.command(name='disconnect', aliases=['dc'])
|
||||
@commands.guild_only()
|
||||
async def _disconnect(self, ctx):
|
||||
""" Disconnects the player from the voice channel and clears its queue. """
|
||||
player = self.bot.lavalink.players.get(ctx.guild.id)
|
||||
@@ -476,7 +493,6 @@ class Music:
|
||||
await player.play()
|
||||
|
||||
@_playnow.before_invoke
|
||||
@_previous.before_invoke
|
||||
@_play.before_invoke
|
||||
async def ensure_voice(self, ctx):
|
||||
await self.ensure_voice_real(ctx)
|
||||
@@ -500,10 +516,31 @@ class Music:
|
||||
|
||||
player.store('channel', ctx.channel.id)
|
||||
await player.connect(ctx.author.voice.channel.id)
|
||||
|
||||
# Get listeners
|
||||
voice_channel = ctx.author.voice.channel
|
||||
while not player.is_connected:
|
||||
await asyncio.sleep(1)
|
||||
|
||||
for member in voice_channel.members:
|
||||
if not member.bot:
|
||||
player.update_listeners(member, member.voice)
|
||||
|
||||
|
||||
else:
|
||||
if player.connected_channel.id != ctx.author.voice.channel.id:
|
||||
return await ctx.send('Join my voice channel!')
|
||||
|
||||
|
||||
async def on_voice_state_update(self, member, before, after):
|
||||
if not member.bot:
|
||||
if after.channel is not None:
|
||||
player = self.bot.lavalink.players.get(after.channel.guild.id)
|
||||
player.update_listeners(member, after)
|
||||
else:
|
||||
player = self.bot.lavalink.players.get(before.channel.guild.id)
|
||||
player.update_listeners(member)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Music(bot))
|
||||
+34
-34
@@ -5,44 +5,44 @@ from bs4 import BeautifulSoup as BS
|
||||
|
||||
class ThumbNailer(object):
|
||||
|
||||
def __init__(self):
|
||||
self.url = self
|
||||
def __init__(self):
|
||||
self.url = self
|
||||
|
||||
async def connection(self, url):
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, timeout=30) as response:
|
||||
assert response.status == 200
|
||||
html = await response.read()
|
||||
return ThumbNailer.__parse_result(html)
|
||||
async def connection(self, url):
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, timeout=30) as response:
|
||||
assert response.status == 200
|
||||
html = await response.read()
|
||||
return ThumbNailer.__parse_result(html)
|
||||
|
||||
def __parse_result(html):
|
||||
try:
|
||||
soup = BS(html, 'html.parser')
|
||||
img = soup.find("meta", property="twitter:image")["content"]
|
||||
return img
|
||||
except Exception as e:
|
||||
raise e
|
||||
def __parse_result(html):
|
||||
try:
|
||||
soup = BS(html, 'html.parser')
|
||||
img = soup.find("meta", property="twitter:image")["content"]
|
||||
return img
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
async def identify(self, identifier, uri):
|
||||
thumbnail_url = ""
|
||||
if "youtube" in uri:
|
||||
thumbnail_url = f"https://img.youtube.com/vi/{identifier}/0.jpg"
|
||||
return thumbnail_url
|
||||
elif "soundcloud" in uri:
|
||||
thumbnail_url = await ThumbNailer.connection(ThumbNailer, url=uri)
|
||||
return thumbnail_url
|
||||
else:
|
||||
return None
|
||||
async def identify(self, identifier, uri):
|
||||
thumbnail_url = ""
|
||||
if "youtube" in uri:
|
||||
thumbnail_url = f"https://img.youtube.com/vi/{identifier}/0.jpg"
|
||||
return thumbnail_url
|
||||
elif "soundcloud" in uri:
|
||||
thumbnail_url = await ThumbNailer.connection(ThumbNailer, url=uri)
|
||||
return thumbnail_url
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def thumbnailer(self, identifier, uri):
|
||||
thumbnail_url = ""
|
||||
if "youtube" in uri:
|
||||
thumbnail_url = f"https://img.youtube.com/vi/{identifier}/0.jpg"
|
||||
return thumbnail_url
|
||||
elif "soundcloud" in uri:
|
||||
thumbnail_url = BS(requests.get(uri).text, "html.parser").find("meta", property="twitter:image")["content"]
|
||||
return thumbnail_url
|
||||
else:
|
||||
return None
|
||||
thumbnail_url = ""
|
||||
if "youtube" in uri:
|
||||
thumbnail_url = f"https://img.youtube.com/vi/{identifier}/0.jpg"
|
||||
return thumbnail_url
|
||||
elif "soundcloud" in uri:
|
||||
thumbnail_url = BS(requests.get(uri).text, "html.parser").find("meta", property="twitter:image")["content"]
|
||||
return thumbnail_url
|
||||
else:
|
||||
return None
|
||||
@@ -3,6 +3,7 @@ from .mixqueue import MixQueue
|
||||
from abc import ABC, abstractmethod
|
||||
from random import randrange
|
||||
|
||||
import lavalink
|
||||
from lavalink import BasePlayer
|
||||
from lavalink.AudioTrack import AudioTrack
|
||||
from lavalink.Events import QueueEndEvent, TrackExceptionEvent, TrackEndEvent, TrackStartEvent, TrackStuckEvent
|
||||
@@ -29,6 +30,10 @@ class MixPlayer(BasePlayer):
|
||||
self.queue = MixQueue()
|
||||
self.current = None
|
||||
|
||||
self.listeners = set()
|
||||
self.skip_voters = set()
|
||||
self.boosted = False
|
||||
|
||||
@property
|
||||
def is_playing(self):
|
||||
""" Returns the player's track state. """
|
||||
@@ -111,6 +116,18 @@ class MixPlayer(BasePlayer):
|
||||
def global_queue(self):
|
||||
return self.queue.get_queue()
|
||||
|
||||
def queue_duration(self, include_current: bool=True):
|
||||
duration = 0
|
||||
for track in self.queue:
|
||||
duration += track.duration
|
||||
remaining = self.current.duration - self.position
|
||||
if include_current:
|
||||
return lavalink.Utils.format_time(duration + remaining)
|
||||
return lavalink.Utils.format_time(duration)
|
||||
|
||||
def current_pos(self):
|
||||
return lavalink.Utils.format_time(self.position)
|
||||
|
||||
async def play(self, track_index: int = 0):
|
||||
""" Plays the first track in the queue, if any or plays a track from the specified index in the queue. """
|
||||
|
||||
@@ -146,6 +163,7 @@ class MixPlayer(BasePlayer):
|
||||
|
||||
async def skip(self):
|
||||
""" Plays the next track in the queue, if any. """
|
||||
self.skip_voters.clear()
|
||||
await self.play()
|
||||
|
||||
async def set_pause(self, pause: bool):
|
||||
@@ -170,3 +188,46 @@ class MixPlayer(BasePlayer):
|
||||
if isinstance(event, (TrackStuckEvent, TrackExceptionEvent)) or \
|
||||
isinstance(event, TrackEndEvent) and event.reason == 'FINISHED':
|
||||
await self.play()
|
||||
|
||||
def update_listeners(self, member, voice_state=None):
|
||||
if self.is_connected:
|
||||
vc = self.connected_channel
|
||||
if voice_state is None or vc != voice_state.channel:
|
||||
self.listeners.discard(member)
|
||||
self.skip_voters.discard(member)
|
||||
else:
|
||||
if voice_state.deaf or voice_state.self_deaf:
|
||||
self.listeners.discard(member)
|
||||
self.skip_voters.discard(member)
|
||||
else:
|
||||
self.listeners.add(member)
|
||||
|
||||
|
||||
def add_skipper(self, member):
|
||||
if member in self.listeners:
|
||||
self.skip_voters.add(member)
|
||||
|
||||
|
||||
async def bassboost(self, boost: bool=False):
|
||||
if boost:
|
||||
boostval = 1
|
||||
else:
|
||||
boostval = 0
|
||||
|
||||
bands = [
|
||||
{"band": 0, "gain": boostval * 0.15}, # 25Hz
|
||||
{"band": 1, "gain": boostval * 0.15}, # 40Hz
|
||||
{"band": 2, "gain": boostval * 0.25}, # 63Hz
|
||||
{"band": 3, "gain": boostval * 0.15}, #100Hz
|
||||
{"band": 4, "gain": boostval * -0.15}, #160Hz
|
||||
{"band": 5, "gain": boostval * -0.1}, #250Hz
|
||||
{"band": 6, "gain": boostval * -0.05}, #400Hz
|
||||
]
|
||||
|
||||
if boost:
|
||||
await self._lavalink.ws.send(op="equalizer", guildId=self.guild_id, bands=bands)
|
||||
self.boosted = True
|
||||
else:
|
||||
await self._lavalink.ws.send(op="equalizer", guildId=self.guild_id, bands=bands)
|
||||
self.boosted = False
|
||||
|
||||
@@ -3,6 +3,7 @@ from itertools import cycle, islice, chain
|
||||
from random import shuffle
|
||||
from lavalink import AudioTrack
|
||||
|
||||
|
||||
def roundrobin(*iterables):
|
||||
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
|
||||
# Recipe credited to George Sakkis
|
||||
|
||||
Reference in new issue
Block a user