mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
[Audio] Fix Attribute error raised by is_alone method when channel was None (#3122)
* Fix attribute Fixes #3120 Signed-off-by: Drapersniper <27962761+drapersniper@users.noreply.github.com> * Chore Signed-off-by: Drapersniper <27962761+drapersniper@users.noreply.github.com>
This commit is contained in:
parent
61f467a323
commit
0b042532fd
1
changelog.d/3120.bugfix.rst
Normal file
1
changelog.d/3120.bugfix.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
Fixed an issue when calling audio commands when not in a voice channel could result in a crash.
|
||||||
@ -5,7 +5,7 @@ import datetime
|
|||||||
import heapq
|
import heapq
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import math
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
@ -17,7 +17,6 @@ from typing import List, Optional, Tuple, Union, cast
|
|||||||
import aiohttp
|
import aiohttp
|
||||||
import discord
|
import discord
|
||||||
import lavalink
|
import lavalink
|
||||||
import math
|
|
||||||
from fuzzywuzzy import process
|
from fuzzywuzzy import process
|
||||||
|
|
||||||
import redbot.core
|
import redbot.core
|
||||||
@ -34,8 +33,9 @@ from redbot.core.utils.menus import (
|
|||||||
start_adding_reactions,
|
start_adding_reactions,
|
||||||
)
|
)
|
||||||
from redbot.core.utils.predicates import MessagePredicate, ReactionPredicate
|
from redbot.core.utils.predicates import MessagePredicate, ReactionPredicate
|
||||||
|
|
||||||
from . import audio_dataclasses
|
from . import audio_dataclasses
|
||||||
from .apis import MusicCache, HAS_SQL, _ERROR
|
from .apis import _ERROR, HAS_SQL, MusicCache
|
||||||
from .checks import can_have_caching
|
from .checks import can_have_caching
|
||||||
from .converters import ComplexScopeParser, ScopeParser, get_lazy_converter, get_playlist_converter
|
from .converters import ComplexScopeParser, ScopeParser, get_lazy_converter, get_playlist_converter
|
||||||
from .equalizer import Equalizer
|
from .equalizer import Equalizer
|
||||||
@ -57,8 +57,26 @@ from .playlists import (
|
|||||||
get_playlist,
|
get_playlist,
|
||||||
humanize_scope,
|
humanize_scope,
|
||||||
)
|
)
|
||||||
from .utils import *
|
from .utils import (
|
||||||
|
CacheLevel,
|
||||||
|
Notifier,
|
||||||
|
clear_react,
|
||||||
|
draw_time,
|
||||||
|
dynamic_time,
|
||||||
|
get_description,
|
||||||
|
is_allowed,
|
||||||
|
match_url,
|
||||||
|
match_yt_playlist,
|
||||||
|
pass_config_to_dependencies,
|
||||||
|
queue_duration,
|
||||||
|
remove_react,
|
||||||
|
rgetattr,
|
||||||
|
time_convert,
|
||||||
|
track_creator,
|
||||||
|
track_limit,
|
||||||
|
url_check,
|
||||||
|
userlimit,
|
||||||
|
)
|
||||||
|
|
||||||
_ = Translator("Audio", __file__)
|
_ = Translator("Audio", __file__)
|
||||||
|
|
||||||
@ -1669,9 +1687,7 @@ class Audio(commands.Cog):
|
|||||||
if dj_enabled:
|
if dj_enabled:
|
||||||
if not await self._can_instaskip(ctx, ctx.author):
|
if not await self._can_instaskip(ctx, ctx.author):
|
||||||
return await self._embed_msg(ctx, _("You need the DJ role to disconnect."))
|
return await self._embed_msg(ctx, _("You need the DJ role to disconnect."))
|
||||||
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(
|
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(ctx):
|
||||||
ctx, ctx.author
|
|
||||||
):
|
|
||||||
return await self._embed_msg(ctx, _("There are other people listening to music."))
|
return await self._embed_msg(ctx, _("There are other people listening to music."))
|
||||||
else:
|
else:
|
||||||
await self._embed_msg(ctx, _("Disconnecting..."))
|
await self._embed_msg(ctx, _("Disconnecting..."))
|
||||||
@ -2270,9 +2286,7 @@ class Audio(commands.Cog):
|
|||||||
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
||||||
vote_enabled = await self.config.guild(ctx.guild).vote_enabled()
|
vote_enabled = await self.config.guild(ctx.guild).vote_enabled()
|
||||||
if dj_enabled or vote_enabled:
|
if dj_enabled or vote_enabled:
|
||||||
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(
|
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(ctx):
|
||||||
ctx, ctx.author
|
|
||||||
):
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if player.current:
|
if player.current:
|
||||||
@ -2322,9 +2336,7 @@ class Audio(commands.Cog):
|
|||||||
ctx, _("You must be in the voice channel pause or resume.")
|
ctx, _("You must be in the voice channel pause or resume.")
|
||||||
)
|
)
|
||||||
if dj_enabled:
|
if dj_enabled:
|
||||||
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(
|
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(ctx):
|
||||||
ctx, ctx.author
|
|
||||||
):
|
|
||||||
return await self._embed_msg(
|
return await self._embed_msg(
|
||||||
ctx, _("You need the DJ role to pause or resume tracks.")
|
ctx, _("You need the DJ role to pause or resume tracks.")
|
||||||
)
|
)
|
||||||
@ -5202,9 +5214,7 @@ class Audio(commands.Cog):
|
|||||||
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
||||||
player = lavalink.get_player(ctx.guild.id)
|
player = lavalink.get_player(ctx.guild.id)
|
||||||
if dj_enabled:
|
if dj_enabled:
|
||||||
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(
|
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(ctx):
|
||||||
ctx, ctx.author
|
|
||||||
):
|
|
||||||
return await self._embed_msg(ctx, _("You need the DJ role to skip tracks."))
|
return await self._embed_msg(ctx, _("You need the DJ role to skip tracks."))
|
||||||
if (
|
if (
|
||||||
not ctx.author.voice or ctx.author.voice.channel != player.channel
|
not ctx.author.voice or ctx.author.voice.channel != player.channel
|
||||||
@ -5522,10 +5532,9 @@ class Audio(commands.Cog):
|
|||||||
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
||||||
if not self._player_check(ctx) or not player.queue:
|
if not self._player_check(ctx) or not player.queue:
|
||||||
return await self._embed_msg(ctx, _("There's nothing in the queue."))
|
return await self._embed_msg(ctx, _("There's nothing in the queue."))
|
||||||
|
|
||||||
if dj_enabled:
|
if dj_enabled:
|
||||||
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(
|
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(ctx):
|
||||||
ctx, ctx.author
|
|
||||||
):
|
|
||||||
return await self._embed_msg(ctx, _("You need the DJ role to clear the queue."))
|
return await self._embed_msg(ctx, _("You need the DJ role to clear the queue."))
|
||||||
player.queue.clear()
|
player.queue.clear()
|
||||||
await self._embed_msg(ctx, _("The queue has been cleared."))
|
await self._embed_msg(ctx, _("The queue has been cleared."))
|
||||||
@ -5542,9 +5551,7 @@ class Audio(commands.Cog):
|
|||||||
if not self._player_check(ctx) or not player.queue:
|
if not self._player_check(ctx) or not player.queue:
|
||||||
return await self._embed_msg(ctx, _("There's nothing in the queue."))
|
return await self._embed_msg(ctx, _("There's nothing in the queue."))
|
||||||
if dj_enabled:
|
if dj_enabled:
|
||||||
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(
|
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(ctx):
|
||||||
ctx, ctx.author
|
|
||||||
):
|
|
||||||
return await self._embed_msg(ctx, _("You need the DJ role to clean the queue."))
|
return await self._embed_msg(ctx, _("You need the DJ role to clean the queue."))
|
||||||
clean_tracks = []
|
clean_tracks = []
|
||||||
removed_tracks = 0
|
removed_tracks = 0
|
||||||
@ -5624,10 +5631,8 @@ class Audio(commands.Cog):
|
|||||||
"""Shuffles the queue."""
|
"""Shuffles the queue."""
|
||||||
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
||||||
if dj_enabled:
|
if dj_enabled:
|
||||||
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(
|
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(ctx):
|
||||||
ctx, ctx.author
|
return await self._embed_msg(ctx, _("You need the DJ role to shuffle the queue."))
|
||||||
):
|
|
||||||
return await self._embed_msg(ctx, _("You need the DJ role to clean the queue."))
|
|
||||||
if not self._player_check(ctx):
|
if not self._player_check(ctx):
|
||||||
return await self._embed_msg(ctx, _("There's nothing in the queue."))
|
return await self._embed_msg(ctx, _("There's nothing in the queue."))
|
||||||
try:
|
try:
|
||||||
@ -6090,7 +6095,7 @@ class Audio(commands.Cog):
|
|||||||
Accepts seconds or a value formatted like 00:00:00 (`hh:mm:ss`) or 00:00 (`mm:ss`)."""
|
Accepts seconds or a value formatted like 00:00:00 (`hh:mm:ss`) or 00:00 (`mm:ss`)."""
|
||||||
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
||||||
vote_enabled = await self.config.guild(ctx.guild).vote_enabled()
|
vote_enabled = await self.config.guild(ctx.guild).vote_enabled()
|
||||||
is_alone = await self._is_alone(ctx, ctx.author)
|
is_alone = await self._is_alone(ctx)
|
||||||
is_requester = await self.is_requester(ctx, ctx.author)
|
is_requester = await self.is_requester(ctx, ctx.author)
|
||||||
can_skip = await self._can_instaskip(ctx, ctx.author)
|
can_skip = await self._can_instaskip(ctx, ctx.author)
|
||||||
|
|
||||||
@ -6212,10 +6217,9 @@ class Audio(commands.Cog):
|
|||||||
return await self._embed_msg(ctx, _("Nothing playing."))
|
return await self._embed_msg(ctx, _("Nothing playing."))
|
||||||
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
dj_enabled = await self.config.guild(ctx.guild).dj_enabled()
|
||||||
vote_enabled = await self.config.guild(ctx.guild).vote_enabled()
|
vote_enabled = await self.config.guild(ctx.guild).vote_enabled()
|
||||||
is_alone = await self._is_alone(ctx, ctx.author)
|
is_alone = await self._is_alone(ctx)
|
||||||
is_requester = await self.is_requester(ctx, ctx.author)
|
is_requester = await self.is_requester(ctx, ctx.author)
|
||||||
can_skip = await self._can_instaskip(ctx, ctx.author)
|
can_skip = await self._can_instaskip(ctx, ctx.author)
|
||||||
|
|
||||||
if dj_enabled and not vote_enabled:
|
if dj_enabled and not vote_enabled:
|
||||||
if not (can_skip or is_requester) and not is_alone:
|
if not (can_skip or is_requester) and not is_alone:
|
||||||
return await self._embed_msg(
|
return await self._embed_msg(
|
||||||
@ -6228,7 +6232,6 @@ class Audio(commands.Cog):
|
|||||||
and skip_to_track > 1
|
and skip_to_track > 1
|
||||||
):
|
):
|
||||||
return await self._embed_msg(ctx, _("You can only skip the current track."))
|
return await self._embed_msg(ctx, _("You can only skip the current track."))
|
||||||
|
|
||||||
if vote_enabled:
|
if vote_enabled:
|
||||||
if not can_skip:
|
if not can_skip:
|
||||||
if skip_to_track is not None:
|
if skip_to_track is not None:
|
||||||
@ -6296,40 +6299,21 @@ class Audio(commands.Cog):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def _is_alone(self, ctx: commands.Context, member: discord.Member):
|
async def _is_alone(self, ctx: commands.Context):
|
||||||
try:
|
channel_members = rgetattr(ctx, "guild.me.voice.channel.members", [])
|
||||||
user_voice = ctx.guild.get_member(member.id).voice
|
nonbots = sum(m.id != ctx.author.id for m in channel_members if not m.bot)
|
||||||
bot_voice = ctx.guild.get_member(self.bot.user.id).voice
|
return nonbots < 1
|
||||||
nonbots = sum(not m.bot for m in user_voice.channel.members)
|
|
||||||
if user_voice.channel != bot_voice.channel:
|
|
||||||
nonbots = nonbots + 1
|
|
||||||
except AttributeError:
|
|
||||||
if ctx.guild.get_member(self.bot.user.id).voice is not None:
|
|
||||||
nonbots = sum(
|
|
||||||
not m.bot for m in ctx.guild.get_member(self.bot.user.id).voice.channel.members
|
|
||||||
)
|
|
||||||
if nonbots == 1:
|
|
||||||
nonbots = 2
|
|
||||||
elif ctx.guild.get_member(member.id).voice.channel.members == 1:
|
|
||||||
nonbots = 1
|
|
||||||
else:
|
|
||||||
nonbots = 0
|
|
||||||
return nonbots <= 1
|
|
||||||
|
|
||||||
async def _has_dj_role(self, ctx: commands.Context, member: discord.Member):
|
async def _has_dj_role(self, ctx: commands.Context, member: discord.Member):
|
||||||
dj_role_obj = ctx.guild.get_role(await self.config.guild(ctx.guild).dj_role())
|
dj_role_obj = ctx.guild.get_role(await self.config.guild(ctx.guild).dj_role())
|
||||||
if dj_role_obj in ctx.guild.get_member(member.id).roles:
|
return dj_role_obj in ctx.guild.get_member(member.id).roles
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def is_requester(ctx: commands.Context, member: discord.Member):
|
async def is_requester(ctx: commands.Context, member: discord.Member):
|
||||||
try:
|
try:
|
||||||
player = lavalink.get_player(ctx.guild.id)
|
player = lavalink.get_player(ctx.guild.id)
|
||||||
log.debug(f"Current requester is {player.current}")
|
log.debug(f"Current requester is {player.current}")
|
||||||
if player.current.requester.id == member.id:
|
return player.current.requester.id == member.id
|
||||||
return True
|
|
||||||
return False
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(e)
|
log.error(e)
|
||||||
return False
|
return False
|
||||||
@ -6422,9 +6406,7 @@ class Audio(commands.Cog):
|
|||||||
ctx, _("You must be in the voice channel to stop the music.")
|
ctx, _("You must be in the voice channel to stop the music.")
|
||||||
)
|
)
|
||||||
if vote_enabled or vote_enabled and dj_enabled:
|
if vote_enabled or vote_enabled and dj_enabled:
|
||||||
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(
|
if not await self._can_instaskip(ctx, ctx.author) and not await self._is_alone(ctx):
|
||||||
ctx, ctx.author
|
|
||||||
):
|
|
||||||
return await self._embed_msg(
|
return await self._embed_msg(
|
||||||
ctx, _("There are other people listening - vote to skip instead.")
|
ctx, _("There are other people listening - vote to skip instead.")
|
||||||
)
|
)
|
||||||
@ -6754,10 +6736,7 @@ class Audio(commands.Cog):
|
|||||||
log.error(
|
log.error(
|
||||||
"Exception raised in Audio's emptypause_timer.", exc_info=True
|
"Exception raised in Audio's emptypause_timer.", exc_info=True
|
||||||
)
|
)
|
||||||
finally:
|
pause_times.pop(server.id, None)
|
||||||
pause_times.pop(server.id, None)
|
|
||||||
else:
|
|
||||||
pause_times.pop(server.id, None)
|
|
||||||
servers = stop_times.copy()
|
servers = stop_times.copy()
|
||||||
servers.update(pause_times)
|
servers.update(pause_times)
|
||||||
for sid in servers:
|
for sid in servers:
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import functools
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
@ -10,10 +11,9 @@ import lavalink
|
|||||||
|
|
||||||
from redbot.core import Config, commands
|
from redbot.core import Config, commands
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
|
|
||||||
from . import audio_dataclasses
|
from . import audio_dataclasses
|
||||||
|
|
||||||
from .converters import _pass_config_to_converters
|
from .converters import _pass_config_to_converters
|
||||||
|
|
||||||
from .playlists import _pass_config_to_playlist
|
from .playlists import _pass_config_to_playlist
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@ -32,6 +32,7 @@ __all__ = [
|
|||||||
"url_check",
|
"url_check",
|
||||||
"userlimit",
|
"userlimit",
|
||||||
"is_allowed",
|
"is_allowed",
|
||||||
|
"rgetattr",
|
||||||
"CacheLevel",
|
"CacheLevel",
|
||||||
"Notifier",
|
"Notifier",
|
||||||
]
|
]
|
||||||
@ -240,6 +241,18 @@ def userlimit(channel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def rsetattr(obj, attr, val):
|
||||||
|
pre, _, post = attr.rpartition(".")
|
||||||
|
return setattr(rgetattr(obj, pre) if pre else obj, post, val)
|
||||||
|
|
||||||
|
|
||||||
|
def rgetattr(obj, attr, *args):
|
||||||
|
def _getattr(obj2, attr2):
|
||||||
|
return getattr(obj2, attr2, *args)
|
||||||
|
|
||||||
|
return functools.reduce(_getattr, [obj] + attr.split("."))
|
||||||
|
|
||||||
|
|
||||||
class CacheLevel:
|
class CacheLevel:
|
||||||
__slots__ = ("value",)
|
__slots__ = ("value",)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user