Audio Cog - v2.3.0 (#4446)

* First commit - Bring everything from dev cog minus NSFW support

* Add a toggle for auto deafen

* Add a one off Send to Owners

* aaaaaaa

* Update this to ensure `get_perms` is not called if the API is disabled

* Apply suggestions from code review

Co-authored-by: Vuks <51289041+Vuks69@users.noreply.github.com>

* silence any errors here (in case API is down so it doesnt affect audio)

* update the message to tell the mto join the Official Red server.

* remove useless sutff, and change dj check order to ensure bot doesnt join VC for non DJ's

* ffs

* Update redbot/cogs/audio/core/tasks/startup.py

Co-authored-by: Twentysix <Twentysix26@users.noreply.github.com>

* Aikas Review

* Add #3995 in here

* update

* *sigh*

* lock behind owner

* to help with debugging

* Revert "to help with debugging"

This reverts commit 8cbf17be

* resolve last review

Co-authored-by: Vuks <51289041+Vuks69@users.noreply.github.com>
Co-authored-by: Twentysix <Twentysix26@users.noreply.github.com>
This commit is contained in:
Draper
2020-10-12 19:39:39 +01:00
committed by GitHub
parent 29ebf0f060
commit 2da9b502d8
41 changed files with 1553 additions and 331 deletions

View File

@@ -3,6 +3,7 @@ from .equalizer import EqualizerUtilities
from .formatting import FormattingUtilities
from .local_tracks import LocalTrackUtilities
from .miscellaneous import MiscellaneousUtilities
from .parsers import ParsingUtilities
from .player import PlayerUtilities
from .playlists import PlaylistUtilities
from .queue import QueueUtilities
@@ -18,6 +19,7 @@ class Utilities(
PlaylistUtilities,
QueueUtilities,
ValidationUtilities,
ParsingUtilities,
metaclass=CompositeMetaClass,
):
"""Class joining all utility subclasses"""

View File

@@ -1,6 +1,7 @@
import asyncio
import contextlib
import logging
from typing import List
import discord

View File

@@ -2,14 +2,16 @@ import datetime
import logging
import math
import re
import time
from typing import List, Optional
import discord
import lavalink
from discord.embeds import EmptyEmbed
from redbot.core.utils import AsyncIter
from discord.embeds import EmptyEmbed
from redbot.core import commands
from redbot.core.utils import AsyncIter
from redbot.core.utils.chat_formatting import box, escape
from ...audio_dataclasses import LocalPath, Query
@@ -98,6 +100,7 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
await lavalink.connect(ctx.author.voice.channel)
player = lavalink.get_player(ctx.guild.id)
player.store("connect", datetime.datetime.utcnow())
await self.self_deafen(player)
except AttributeError:
return await self.send_embed_msg(ctx, title=_("Connect to a voice channel first."))
except IndexError:
@@ -128,7 +131,9 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
except IndexError:
search_choice = tracks[-1]
if not hasattr(search_choice, "is_local") and getattr(search_choice, "uri", None):
description = self.get_track_description(search_choice, self.local_folder_current_path)
description = await self.get_track_description(
search_choice, self.local_folder_current_path
)
else:
search_choice = Query.process_input(search_choice, self.local_folder_current_path)
if search_choice.is_local:
@@ -148,14 +153,12 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
queue_dur = await self.queue_duration(ctx)
queue_total_duration = self.format_time(queue_dur)
before_queue_length = len(player.queue)
query = Query.process_input(search_choice, self.local_folder_current_path)
if not await self.is_query_allowed(
self.config,
ctx.guild,
(
f"{search_choice.title} {search_choice.author} {search_choice.uri} "
f"{str(Query.process_input(search_choice, self.local_folder_current_path))}"
),
ctx,
f"{search_choice.title} {search_choice.author} {search_choice.uri} " f"{str(query)}",
query_obj=query,
):
if IS_DEBUG:
log.debug(f"Query is not allowed in {ctx.guild} ({ctx.guild.id})")
@@ -166,6 +169,13 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
elif guild_data["maxlength"] > 0:
if self.is_track_length_allowed(search_choice, guild_data["maxlength"]):
search_choice.extras.update(
{
"enqueue_time": int(time.time()),
"vc": player.channel.id,
"requester": ctx.author.id,
}
)
player.add(ctx.author, search_choice)
player.maybe_shuffle()
self.bot.dispatch(
@@ -174,6 +184,13 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
else:
return await self.send_embed_msg(ctx, title=_("Track exceeds maximum length."))
else:
search_choice.extras.update(
{
"enqueue_time": int(time.time()),
"vc": player.channel.id,
"requester": ctx.author.id,
}
)
player.add(ctx.author, search_choice)
player.maybe_shuffle()
self.bot.dispatch(
@@ -191,9 +208,11 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
await player.play()
return await self.send_embed_msg(ctx, embed=songembed)
def _format_search_options(self, search_choice):
async def _format_search_options(self, search_choice):
query = Query.process_input(search_choice, self.local_folder_current_path)
description = self.get_track_description(search_choice, self.local_folder_current_path)
description = await self.get_track_description(
search_choice, self.local_folder_current_path
)
return description, query
async def _build_search_page(
@@ -259,10 +278,10 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
)
return embed
def get_track_description(
async def get_track_description(
self, track, local_folder_current_path, shorten=False
) -> Optional[str]:
"""Get the user facing formatted track name"""
"""Get the user facing formatted track name."""
string = None
if track and getattr(track, "uri", None):
query = Query.process_input(track.uri, local_folder_current_path)
@@ -299,7 +318,13 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
string = "{}...".format((string[:40]).rstrip(" "))
string = f'**{escape(f"{string}", formatting=True)}**'
else:
if track.author.lower() not in track.title.lower():
if track.is_stream:
icy = await self.icyparser(track.uri)
if icy:
title = icy
else:
title = f"{track.title} - {track.author}"
elif track.author.lower() not in track.title.lower():
title = f"{track.title} - {track.author}"
else:
title = track.title
@@ -315,8 +340,10 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
string = f'**{escape(f"{string}", formatting=True)}**'
return string
def get_track_description_unformatted(self, track, local_folder_current_path) -> Optional[str]:
"""Get the user facing unformatted track name"""
async def get_track_description_unformatted(
self, track, local_folder_current_path
) -> Optional[str]:
"""Get the user facing unformatted track name."""
if track and hasattr(track, "uri"):
query = Query.process_input(track.uri, local_folder_current_path)
if query.is_local or "localtracks/" in track.uri:
@@ -332,7 +359,13 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
else:
return query.to_string_user()
else:
if track.author.lower() not in track.title.lower():
if track.is_stream:
icy = await self.icyparser(track.uri)
if icy:
title = icy
else:
title = f"{track.title} - {track.author}"
elif track.author.lower() not in track.title.lower():
title = f"{track.title} - {track.author}"
else:
title = track.title
@@ -342,7 +375,7 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
return None
def format_playlist_picker_data(self, pid, pname, ptracks, pauthor, scope) -> str:
"""Format the values into a pretified codeblock"""
"""Format the values into a prettified codeblock."""
author = self.bot.get_user(pauthor) or pauthor or _("Unknown")
line = _(
" - Name: <{pname}>\n"
@@ -359,9 +392,9 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
player = lavalink.get_player(ctx.guild.id)
paused = player.paused
pos = player.position
dur = player.current.length
dur = getattr(player.current, "length", player.position or 1)
sections = 12
loc_time = round((pos / dur) * sections)
loc_time = round((pos / dur if dur != 0 else pos) * sections)
bar = "\N{BOX DRAWINGS HEAVY HORIZONTAL}"
seek = "\N{RADIO BUTTON}"
if paused:

View File

@@ -1,16 +1,17 @@
import contextlib
import logging
from pathlib import Path
from typing import List, Union
import lavalink
from fuzzywuzzy import process
from redbot.core.utils import AsyncIter
from redbot.core import commands
from redbot.core.utils import AsyncIter
from ...errors import TrackEnqueueError
from ...audio_dataclasses import LocalPath, Query
from ...errors import TrackEnqueueError
from ..abc import MixinMeta
from ..cog_utils import CompositeMetaClass, _
@@ -32,7 +33,7 @@ class LocalTrackUtilities(MixinMeta, metaclass=CompositeMetaClass):
)
async def get_localtrack_folder_list(self, ctx: commands.Context, query: Query) -> List[Query]:
"""Return a list of folders per the provided query"""
"""Return a list of folders per the provided query."""
if not await self.localtracks_folder_exists(ctx):
return []
query = Query.process_input(query, self.local_folder_current_path)
@@ -49,7 +50,7 @@ class LocalTrackUtilities(MixinMeta, metaclass=CompositeMetaClass):
async def get_localtrack_folder_tracks(
self, ctx, player: lavalink.player_manager.Player, query: Query
) -> List[lavalink.rest_api.Track]:
"""Return a list of tracks per the provided query"""
"""Return a list of tracks per the provided query."""
if not await self.localtracks_folder_exists(ctx) or self.api_interface is None:
return []

View File

@@ -5,21 +5,22 @@ import functools
import json
import logging
import re
from typing import Any, Final, MutableMapping, Union, cast, Mapping, Pattern
from typing import Any, Final, Mapping, MutableMapping, Pattern, Union, cast
import discord
import lavalink
from discord.embeds import EmptyEmbed
from redbot.core.utils import AsyncIter
from discord.embeds import EmptyEmbed
from redbot.core import bank, commands
from redbot.core.commands import Context
from redbot.core.utils import AsyncIter
from redbot.core.utils.chat_formatting import humanize_number
from ..abc import MixinMeta
from ..cog_utils import CompositeMetaClass, _, _SCHEMA_VERSION
from ...apis.playlist_interface import get_all_playlist_for_migration23
from ...utils import PlaylistScope
from ...utils import PlaylistScope, task_callback
from ..abc import MixinMeta
from ..cog_utils import CompositeMetaClass, _
log = logging.getLogger("red.cogs.Audio.cog.Utilities.miscellaneous")
@@ -32,7 +33,9 @@ class MiscellaneousUtilities(MixinMeta, metaclass=CompositeMetaClass):
self, message: discord.Message, emoji: MutableMapping = None
) -> asyncio.Task:
"""Non blocking version of clear_react."""
return self.bot.loop.create_task(self.clear_react(message, emoji))
task = self.bot.loop.create_task(self.clear_react(message, emoji))
task.add_done_callback(task_callback)
return task
async def maybe_charge_requester(self, ctx: commands.Context, jukebox_price: int) -> bool:
jukebox = await self.config.guild(ctx.guild).jukebox()

View File

@@ -0,0 +1,35 @@
import logging
import re
import struct
from typing import Final, Optional
import aiohttp
from ..abc import MixinMeta
from ..cog_utils import CompositeMetaClass
log = logging.getLogger("red.cogs.Audio.cog.Utilities.Parsing")
STREAM_TITLE: Final[re.Pattern] = re.compile(br"StreamTitle='([^']*)';")
class ParsingUtilities(MixinMeta, metaclass=CompositeMetaClass):
async def icyparser(self, url: str) -> Optional[str]:
try:
async with self.session.get(url, headers={"Icy-MetaData": "1"}) as resp:
metaint = int(resp.headers["icy-metaint"])
for _ in range(5):
await resp.content.readexactly(metaint)
metadata_length = struct.unpack("B", await resp.content.readexactly(1))[0] * 16
metadata = await resp.content.readexactly(metadata_length)
m = re.search(STREAM_TITLE, metadata.rstrip(b"\0"))
if m:
title = m.group(1)
if title:
title = title.decode("utf-8", errors="replace")
return title
else:
return None
except (KeyError, aiohttp.ClientConnectionError, aiohttp.ClientResponseError):
return None

View File

@@ -1,14 +1,15 @@
import logging
import time
from typing import List, Optional, Tuple, Union
import aiohttp
import discord
import lavalink
from discord.embeds import EmptyEmbed
from redbot.core.utils import AsyncIter
from discord.embeds import EmptyEmbed
from redbot.core import commands
from redbot.core.utils import AsyncIter
from redbot.core.utils.chat_formatting import bold, escape
from ...audio_dataclasses import _PARTIALLY_SUPPORTED_MUSIC_EXT, Query
@@ -42,7 +43,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
self._error_timer[guild] = now
return self._error_counter[guild] >= 5
def get_active_player_count(self) -> Tuple[Optional[str], int]:
async def get_active_player_count(self) -> Tuple[Optional[str], int]:
try:
current = next(
(
@@ -52,7 +53,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
),
None,
)
get_single_title = self.get_track_description_unformatted(
get_single_title = await self.get_track_description_unformatted(
current, self.local_folder_current_path
)
playing_servers = len(lavalink.active_players())
@@ -149,7 +150,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
elif autoplay and not player.queue:
embed = discord.Embed(
title=_("Track Skipped"),
description=self.get_track_description(
description=await self.get_track_description(
player.current, self.local_folder_current_path
),
)
@@ -184,7 +185,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
else:
embed = discord.Embed(
title=_("Track Skipped"),
description=self.get_track_description(
description=await self.get_track_description(
player.current, self.local_folder_current_path
),
)
@@ -208,6 +209,17 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
except (IndexError, KeyError):
return False
async def self_deafen(self, player: lavalink.Player) -> None:
guild_id = self.rgetattr(player, "channel.guild.id", None)
if not guild_id:
return
if not await self.config.guild_from_id(guild_id).auto_deafen():
return
channel_id = player.channel.id
node = player.manager.node
voice_ws = node.get_voice_ws(guild_id)
await voice_ws.voice_state(guild_id, channel_id, self_deaf=True)
async def _get_spotify_tracks(
self, ctx: commands.Context, query: Query, forced: bool = False
) -> Union[discord.Message, List[lavalink.Track], lavalink.Track]:
@@ -285,7 +297,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
ctx,
title=_("Unable to Get Track"),
description=_(
"I'm unable get a track from Lavalink at the moment, "
"I'm unable to get a track from Lavalink at the moment, "
"try again in a few minutes."
),
)
@@ -354,9 +366,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
playlist_url = None
seek = 0
if type(query) is not list:
if not await self.is_query_allowed(
self.config, ctx.guild, f"{query}", query_obj=query
):
if not await self.is_query_allowed(self.config, ctx, f"{query}", query_obj=query):
raise QueryUnauthorized(
_("{query} is not an allowed query.").format(query=query.to_string_user())
)
@@ -373,7 +383,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
ctx,
title=_("Unable to Get Track"),
description=_(
"I'm unable get a track from Lavalink at the moment, "
"I'm unable to get a track from Lavalink at the moment, "
"try again in a few minutes."
),
)
@@ -423,13 +433,12 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
async for track in AsyncIter(tracks):
if len(player.queue) >= 10000:
continue
query = Query.process_input(track, self.local_folder_current_path)
if not await self.is_query_allowed(
self.config,
ctx.guild,
(
f"{track.title} {track.author} {track.uri} "
f"{str(Query.process_input(track, self.local_folder_current_path))}"
),
ctx,
f"{track.title} {track.author} {track.uri} " f"{str(query)}",
query_obj=query,
):
if IS_DEBUG:
log.debug(f"Query is not allowed in {ctx.guild} ({ctx.guild.id})")
@@ -437,6 +446,13 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
elif guild_data["maxlength"] > 0:
if self.is_track_length_allowed(track, guild_data["maxlength"]):
track_len += 1
track.extras.update(
{
"enqueue_time": int(time.time()),
"vc": player.channel.id,
"requester": ctx.author.id,
}
)
player.add(ctx.author, track)
self.bot.dispatch(
"red_audio_track_enqueue", player.channel.guild, track, ctx.author
@@ -444,6 +460,13 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
else:
track_len += 1
track.extras.update(
{
"enqueue_time": int(time.time()),
"vc": player.channel.id,
"requester": ctx.author.id,
}
)
player.add(ctx.author, track)
self.bot.dispatch(
"red_audio_track_enqueue", player.channel.guild, track, ctx.author
@@ -499,13 +522,15 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
)
if seek and seek > 0:
single_track.start_timestamp = seek * 1000
query = Query.process_input(single_track, self.local_folder_current_path)
if not await self.is_query_allowed(
self.config,
ctx.guild,
ctx,
(
f"{single_track.title} {single_track.author} {single_track.uri} "
f"{str(Query.process_input(single_track, self.local_folder_current_path))}"
f"{str(query)}"
),
query_obj=query,
):
if IS_DEBUG:
log.debug(f"Query is not allowed in {ctx.guild} ({ctx.guild.id})")
@@ -515,6 +540,13 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
)
elif guild_data["maxlength"] > 0:
if self.is_track_length_allowed(single_track, guild_data["maxlength"]):
single_track.extras.update(
{
"enqueue_time": int(time.time()),
"vc": player.channel.id,
"requester": ctx.author.id,
}
)
player.add(ctx.author, single_track)
player.maybe_shuffle()
self.bot.dispatch(
@@ -530,6 +562,13 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
)
else:
single_track.extras.update(
{
"enqueue_time": int(time.time()),
"vc": player.channel.id,
"requester": ctx.author.id,
}
)
player.add(ctx.author, single_track)
player.maybe_shuffle()
self.bot.dispatch(
@@ -542,7 +581,9 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
if await self.bot.is_owner(ctx.author):
desc = _("Please check your console or logs for details.")
return await self.send_embed_msg(ctx, title=title, description=desc)
description = self.get_track_description(single_track, self.local_folder_current_path)
description = await self.get_track_description(
single_track, self.local_folder_current_path
)
embed = discord.Embed(title=_("Track Enqueued"), description=description)
if not guild_data["shuffle"] and queue_dur > 0:
embed.set_footer(
@@ -588,6 +629,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
lock=self.update_player_lock,
notifier=notifier,
forced=forced,
query_global=await self.config.global_db_enabled(),
)
except SpotifyFetchError as error:
self.update_player_lock(ctx, False)
@@ -602,7 +644,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
ctx,
title=_("Unable to Get Track"),
description=_(
"I'm unable get a track from Lavalink at the moment,"
"I'm unable to get a track from Lavalink at the moment, "
"try again in a few minutes."
),
error=True,
@@ -657,6 +699,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
and len(player.queue) == 0
):
await player.move_to(user_channel)
await self.self_deafen(player)
return True
else:
return False

View File

@@ -4,14 +4,15 @@ import datetime
import json
import logging
import math
from typing import List, MutableMapping, Optional, Tuple, Union
import discord
import lavalink
from discord.embeds import EmptyEmbed
from redbot.core.utils import AsyncIter
from discord.embeds import EmptyEmbed
from redbot.core import commands
from redbot.core.utils import AsyncIter
from redbot.core.utils.chat_formatting import box
from redbot.core.utils.menus import start_adding_reactions
from redbot.core.utils.predicates import ReactionPredicate
@@ -408,7 +409,7 @@ class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
ctx,
title=_("Unable to Get Track"),
description=_(
"I'm unable get a track from Lavalink at the moment, "
"I'm unable to get a track from Lavalink at the moment, "
"try again in a few minutes."
),
)
@@ -513,6 +514,7 @@ class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
await lavalink.connect(ctx.author.voice.channel)
player = lavalink.get_player(ctx.guild.id)
player.store("connect", datetime.datetime.utcnow())
await self.self_deafen(player)
except IndexError:
await self.send_embed_msg(
ctx,
@@ -593,7 +595,7 @@ class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
ctx,
title=_("Unable to Get Track"),
description=_(
"I'm unable get a track from Lavalink at the moment, try again in a few "
"I'm unable to get a track from Lavalink at the moment, try again in a few "
"minutes."
),
)
@@ -619,7 +621,7 @@ class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
ctx,
title=_("Unable to Get Track"),
description=_(
"I'm unable get a track from Lavalink at the moment, try again in a few "
"I'm unable to get a track from Lavalink at the moment, try again in a few "
"minutes."
),
)

View File

@@ -1,13 +1,14 @@
import logging
import math
from typing import List, Tuple
import discord
import lavalink
from fuzzywuzzy import process
from redbot.core.utils import AsyncIter
from fuzzywuzzy import process
from redbot.core import commands
from redbot.core.utils import AsyncIter
from redbot.core.utils.chat_formatting import humanize_number
from ...audio_dataclasses import LocalPath, Query
@@ -46,7 +47,7 @@ class QueueUtilities(MixinMeta, metaclass=CompositeMetaClass):
dur = self.format_time(player.current.length)
query = Query.process_input(player.current, self.local_folder_current_path)
current_track_description = self.get_track_description(
current_track_description = await self.get_track_description(
player.current, self.local_folder_current_path
)
if query.is_stream:
@@ -65,7 +66,7 @@ class QueueUtilities(MixinMeta, metaclass=CompositeMetaClass):
):
req_user = track.requester
track_idx = i + 1
track_description = self.get_track_description(
track_description = await self.get_track_description(
track, self.local_folder_current_path, shorten=True
)
queue_list += f"`{track_idx}.` {track_description}, "
@@ -76,6 +77,7 @@ class QueueUtilities(MixinMeta, metaclass=CompositeMetaClass):
title=_("Queue for __{guild_name}__").format(guild_name=ctx.guild.name),
description=queue_list,
)
if await self.config.guild(ctx.guild).thumbnail() and player.current.thumbnail:
embed.set_thumbnail(url=player.current.thumbnail)
queue_dur = await self.queue_duration(ctx)

View File

@@ -1,11 +1,13 @@
import logging
import re
from typing import Final, List, Set, Pattern
from typing import Final, List, Optional, Pattern, Set, Union
from urllib.parse import urlparse
import discord
from redbot.core import Config
from redbot.core.commands import Context
from ...audio_dataclasses import Query
from ..abc import MixinMeta
@@ -54,11 +56,21 @@ class ValidationUtilities(MixinMeta, metaclass=CompositeMetaClass):
return not (channel.user_limit == 0 or channel.user_limit > len(channel.members))
async def is_query_allowed(
self, config: Config, guild: discord.Guild, query: str, query_obj: Query = None
self,
config: Config,
ctx_or_channel: Optional[Union[Context, discord.TextChannel]],
query: str,
query_obj: Query,
) -> bool:
"""Checks if the query is allowed in this server or globally"""
query = query.lower().strip()
"""Checks if the query is allowed in this server or globally."""
if ctx_or_channel:
guild = ctx_or_channel.guild
channel = (
ctx_or_channel.channel if isinstance(ctx_or_channel, Context) else ctx_or_channel
)
query = query.lower().strip()
else:
guild = None
if query_obj is not None:
query = query_obj.lavalink_query.replace("ytsearch:", "youtubesearch").replace(
"scsearch:", "soundcloudsearch"