mirror of
https://github.com/UiO-Gaming/ShiteMusicBot.git
synced 2026-11-06 14:24:30 +01:00
Added votable decorator, reduced code duplication
Votable decorator added, makes it possible to make a command accessible through voting. Can be overwridden.
This commit is contained in:
1 parent
7a32e04820
commit
28208da262
5 files changed
+95
-60
No files matched your search
@@ -1,4 +1,5 @@
|
||||
# Discord Packages
|
||||
import discord
|
||||
import lavalink
|
||||
from discord.ext import commands
|
||||
|
||||
@@ -70,6 +71,31 @@ class Music(commands.Cog):
|
||||
|
||||
return embed, True
|
||||
|
||||
def get_current_song_embed(self, ctx, include_time=False):
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
|
||||
if include_time:
|
||||
position = timeformatter.format_ms(player.position)
|
||||
if player.current.stream:
|
||||
duration = '{live}'
|
||||
else:
|
||||
duration = timeformatter.format_ms(player.current.duration)
|
||||
song = f'**[{player.current.title}]({player.current.uri})**\n({position}/{duration})'
|
||||
else:
|
||||
song = f'**[{player.current.title}]({player.current.uri})**'
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color, description=song, title='{now}')
|
||||
thumbnail_url = player.current.extra["thumbnail_url"]
|
||||
member = ctx.guild.get_member(player.current.requester)
|
||||
|
||||
if thumbnail_url:
|
||||
embed.set_thumbnail(url=thumbnail_url)
|
||||
|
||||
embed.set_footer(text=f'{{requested_by}} {member.display_name}', icon_url=member.avatar_url)
|
||||
|
||||
embed = ctx.localizer.format_embed(embed)
|
||||
return embed
|
||||
|
||||
def max_track_length(self, guild, player):
|
||||
if maxlength := self.bot.settings.get(guild, 'duration.max', None):
|
||||
is_dynamic = self.bot.settings.get(guild, 'duration.is_dynamic', 'default_duration_type')
|
||||
|
||||
Whitespace-only changes.
@@ -7,13 +7,12 @@ import discord
|
||||
from discord.ext import commands
|
||||
|
||||
import asyncio
|
||||
import math
|
||||
import re
|
||||
|
||||
from ..utils import checks, timeformatter
|
||||
from ..utils.paginator import QueuePaginator, Scroller
|
||||
from ..utils.selector import Selector
|
||||
from .decorators import require_playing, require_queue, require_voice_connection
|
||||
from .decorators import require_playing, require_queue, require_voice_connection, voteable
|
||||
|
||||
time_rx = re.compile('[0-9]+')
|
||||
url_rx = re.compile('https?:\\/\\/(?:www\\.)?.+')
|
||||
@@ -78,38 +77,17 @@ async def _seek(self, ctx, *, time: str):
|
||||
@commands.command(name='skip')
|
||||
@require_voice_connection()
|
||||
@require_playing()
|
||||
@voteable(requester_override=True)
|
||||
async def _skip(self, ctx):
|
||||
# TODO: rework
|
||||
""" Skips the current track. """
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
|
||||
player.add_skipper(ctx.author)
|
||||
total = len(player.listeners)
|
||||
skips = len(player.skip_voters)
|
||||
threshold = self.bot.settings.get(ctx.guild, 'vote_threshold', 'default_threshold')
|
||||
|
||||
if skips/total >= threshold/100 or player.current.requester == ctx.author.id:
|
||||
await player.skip()
|
||||
if player.current:
|
||||
song = f'**[{player.current.title}]({player.current.uri})**'
|
||||
embed = discord.Embed(color=ctx.me.color, description=song, title='{now}')
|
||||
thumbnail_url = player.current.extra["thumbnail_url"]
|
||||
member = ctx.guild.get_member(player.current.requester)
|
||||
if thumbnail_url:
|
||||
embed.set_thumbnail(url=thumbnail_url)
|
||||
|
||||
embed.set_footer(text=f'{{requested_by}} {member.display_name}', icon_url=member.avatar_url)
|
||||
|
||||
embed = ctx.localizer.format_embed(embed)
|
||||
await ctx.send(ctx.localizer.format_str("{skip.skipped}"), embed=embed)
|
||||
else:
|
||||
await ctx.send(ctx.localizer.format_str("{skip.skipped}"))
|
||||
await player.skip()
|
||||
if player.current:
|
||||
embed = self.get_current_song_embed(ctx)
|
||||
await ctx.send(ctx.localizer.format_str("{skip.skipped}"), embed=embed)
|
||||
else:
|
||||
if skips != 0:
|
||||
needed = math.ceil(total*threshold/100)
|
||||
msg = ctx.localizer.format_str("{skip.require_vote}", _skips=skips, _total=needed)
|
||||
|
||||
await ctx.send(msg)
|
||||
await ctx.send(ctx.localizer.format_str("{skip.skipped}"))
|
||||
|
||||
|
||||
@commands.command(name='skipto')
|
||||
@@ -132,9 +110,9 @@ async def _skip_to(self, ctx, pos: int = 1):
|
||||
|
||||
|
||||
@commands.command(name='stop')
|
||||
@checks.dj_or(alone=True)
|
||||
@require_voice_connection()
|
||||
@require_playing(require_user_listening=True)
|
||||
@voteable(DJ_override=True)
|
||||
async def _stop(self, ctx):
|
||||
""" Stops the player and clears its queue. """
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
@@ -148,25 +126,7 @@ async def _stop(self, ctx):
|
||||
@commands.command(name='now')
|
||||
@require_playing()
|
||||
async def _now(self, ctx):
|
||||
# TODO: rework
|
||||
""" Shows some stats about the currently playing song. """
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
|
||||
position = timeformatter.format_ms(player.position)
|
||||
if player.current.stream:
|
||||
duration = '{live}'
|
||||
else:
|
||||
duration = timeformatter.format_ms(player.current.duration)
|
||||
song = f'**[{player.current.title}]({player.current.uri})**\n({position}/{duration})'
|
||||
|
||||
member = ctx.guild.get_member(player.current.requester)
|
||||
embed = discord.Embed(color=ctx.me.color, description=song, title='{now}')
|
||||
thumbnail_url = player.current.extra["thumbnail_url"]
|
||||
if thumbnail_url:
|
||||
embed.set_thumbnail(url=thumbnail_url)
|
||||
|
||||
embed.set_footer(text=f'{{requested_by}} {member.display_name}', icon_url=member.avatar_url)
|
||||
|
||||
embed = self.get_current_song_embed(ctx, include_time=True)
|
||||
embed = ctx.localizer.format_embed(embed)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@@ -195,12 +155,11 @@ async def _myqueue(self, ctx):
|
||||
async def _pause(self, ctx):
|
||||
""" Pauses/Resumes the current track. """
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
await player.set_pause(not player.paused)
|
||||
if player.paused:
|
||||
await player.set_pause(False)
|
||||
await ctx.send(ctx.localizer.format_str("{resume.resumed}"))
|
||||
else:
|
||||
await player.set_pause(True)
|
||||
await ctx.send(ctx.localizer.format_str("{resume.paused}"))
|
||||
else:
|
||||
await ctx.send(ctx.localizer.format_str("{resume.resumed}"))
|
||||
|
||||
|
||||
@commands.command(name='shuffle')
|
||||
@@ -373,8 +332,8 @@ async def _search(self, ctx, *, query):
|
||||
|
||||
|
||||
@commands.command(name='disconnect')
|
||||
@checks.dj_or(alone=True)
|
||||
@require_voice_connection()
|
||||
@voteable(DJ_override=True)
|
||||
async def _disconnect(self, ctx):
|
||||
""" Disconnects the player from the voice channel and clears its queue. """
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
@@ -388,8 +347,8 @@ async def _disconnect(self, ctx):
|
||||
|
||||
|
||||
@commands.command(name='reconnect')
|
||||
@checks.dj_or(alone=True)
|
||||
@require_voice_connection()
|
||||
@voteable(DJ_override=True)
|
||||
async def _reconnect(self, ctx):
|
||||
""" Tries to disconnect then reconnect the player in case the bot gets stuck on a song """
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
|
||||
@@ -4,9 +4,12 @@ from discord.ext import commands
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
import math
|
||||
|
||||
from cogs.music.music_errors import WrongVoiceChannelError
|
||||
|
||||
from ..utils.checks import is_dj
|
||||
|
||||
|
||||
def require_voice_connection(should_connect=False):
|
||||
"""
|
||||
@@ -122,3 +125,32 @@ def require_queue(require_member_queue=False, require_author_queue=False):
|
||||
await func(self, ctx, *command_args, **kwargs)
|
||||
return ensure_queue_inner
|
||||
return ensure_queue
|
||||
|
||||
|
||||
def voteable(requester_override=False, DJ_override=False):
|
||||
def make_voteable(func):
|
||||
@functools.wraps(func)
|
||||
async def voteable_inner(self, ctx, *command_args, **kwargs):
|
||||
player = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
player.add_vote(func.__name__, ctx.author)
|
||||
|
||||
total = len(player.listeners)
|
||||
votes = len(player.get_voters(func.__name__))
|
||||
threshold = self.bot.settings.get(ctx.guild, 'vote_threshold', 'default_threshold')
|
||||
|
||||
enough_votes = votes/total >= threshold/100
|
||||
DJ = DJ_override and is_dj(ctx)
|
||||
requester = player.current.requester == ctx.author.id and requester_override
|
||||
|
||||
if enough_votes or requester or DJ:
|
||||
await func(self, ctx, *command_args, **kwargs)
|
||||
player.clear_votes()
|
||||
else:
|
||||
if votes != 0:
|
||||
needed = math.ceil(total*threshold/100)
|
||||
# TODO: redo this message to allow for other vote types
|
||||
msg = ctx.localizer.format_str("{skip.require_vote}", _skips=votes, _total=needed)
|
||||
await ctx.send(msg)
|
||||
|
||||
return voteable_inner
|
||||
return make_voteable
|
||||
+23
-5
@@ -17,6 +17,7 @@ class MixPlayer(DefaultPlayer):
|
||||
self.queue = MixQueue()
|
||||
|
||||
self.listeners = set()
|
||||
self.voteables = {}
|
||||
self.skip_voters = set()
|
||||
self.boosted = False
|
||||
|
||||
@@ -98,7 +99,7 @@ class MixPlayer(DefaultPlayer):
|
||||
""" Plays the next track in the queue, if any. """
|
||||
for i in range(pos):
|
||||
_ = self.queue.pop_first()
|
||||
self.skip_voters.clear()
|
||||
self.clear_votes()
|
||||
await self.play()
|
||||
|
||||
def update_listeners(self, member, voice_state):
|
||||
@@ -106,26 +107,43 @@ class MixPlayer(DefaultPlayer):
|
||||
vc = int(self.channel_id)
|
||||
if voice_state.channel is None or voice_state.channel.id != vc:
|
||||
self.listeners.discard(member)
|
||||
self.skip_voters.discard(member)
|
||||
self.remove_member_votes(member)
|
||||
else:
|
||||
if voice_state.deaf or voice_state.self_deaf:
|
||||
self.listeners.discard(member)
|
||||
self.skip_voters.discard(member)
|
||||
self.remove_member_votes(member)
|
||||
else:
|
||||
self.listeners.add(member)
|
||||
|
||||
def clear_listeners(self):
|
||||
self.listeners.clear()
|
||||
|
||||
def add_skipper(self, member):
|
||||
def add_vote(self, category, member):
|
||||
if member in self.listeners:
|
||||
self.skip_voters.add(member)
|
||||
if category not in self.voteables:
|
||||
self.voteables[category] = set()
|
||||
self.voteables[category].add(member)
|
||||
|
||||
def remove_member_votes(self, member):
|
||||
for category, votes in self.voteables.items():
|
||||
votes.discard(member)
|
||||
|
||||
def get_voters(self, category):
|
||||
if category not in self.voteables:
|
||||
self.voteables[category] = set()
|
||||
return self.voteables[category]
|
||||
|
||||
def clear_votes(self):
|
||||
for category, votes in self.voteables.items():
|
||||
votes.clear()
|
||||
|
||||
async def handle_event(self, event):
|
||||
""" Handles the given event as necessary. """
|
||||
if isinstance(event, (TrackStuckEvent, TrackExceptionEvent)) or \
|
||||
isinstance(event, TrackEndEvent) and event.reason == 'FINISHED':
|
||||
self.skip_voters.clear()
|
||||
for category, votes in self.voteables.items():
|
||||
votes.clear()
|
||||
await self.play()
|
||||
|
||||
async def bassboost(self, boost: bool = False):
|
||||
|
||||
Reference in new issue
Block a user