mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-21 18:27:59 -05:00
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:
@@ -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"""
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import asyncio
|
||||
import contextlib
|
||||
import logging
|
||||
|
||||
from typing import List
|
||||
|
||||
import discord
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 []
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
35
redbot/cogs/audio/core/utilities/parsers.py
Normal file
35
redbot/cogs/audio/core/utilities/parsers.py
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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."
|
||||
),
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user