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

@@ -2,6 +2,7 @@ import asyncio
import datetime
import logging
import time
from typing import Optional
import discord
@@ -130,6 +131,13 @@ class AudioEvents(MixinMeta, metaclass=CompositeMetaClass):
)
except Exception as err:
debug_exc_log(log, err, f"Failed to delete global daily playlist ID: {too_old_id}")
persist_cache = self._persist_queue_cache.setdefault(
guild.id, await self.config.guild(guild).persist_queue()
)
if persist_cache:
await self.api_interface.persistent_queue_api.played(
guild_id=guild.id, track_id=track_identifier
)
@commands.Cog.listener()
async def on_red_audio_queue_end(
@@ -141,6 +149,21 @@ class AudioEvents(MixinMeta, metaclass=CompositeMetaClass):
await self.api_interface.local_cache_api.youtube.clean_up_old_entries()
await asyncio.sleep(5)
await self.playlist_api.delete_scheduled()
await self.api_interface.persistent_queue_api.drop(guild.id)
await asyncio.sleep(5)
await self.api_interface.persistent_queue_api.delete_scheduled()
@commands.Cog.listener()
async def on_red_audio_track_enqueue(self, guild: discord.Guild, track, requester):
if not (track and guild):
return
persist_cache = self._persist_queue_cache.setdefault(
guild.id, await self.config.guild(guild).persist_queue()
)
if persist_cache:
await self.api_interface.persistent_queue_api.enqueued(
guild_id=guild.id, room_id=track.extras["vc"], track=track
)
@commands.Cog.listener()
async def on_red_audio_track_end(
@@ -152,3 +175,6 @@ class AudioEvents(MixinMeta, metaclass=CompositeMetaClass):
await self.api_interface.local_cache_api.youtube.clean_up_old_entries()
await asyncio.sleep(5)
await self.playlist_api.delete_scheduled()
await self.api_interface.persistent_queue_api.drop(guild.id)
await asyncio.sleep(5)
await self.api_interface.persistent_queue_api.delete_scheduled()

View File

@@ -1,19 +1,24 @@
import asyncio
import contextlib
import logging
import re
from collections import OrderedDict
from pathlib import Path
from typing import Final, Pattern
import discord
import lavalink
from aiohttp import ClientConnectorError
from discord.ext.commands import CheckFailure
from redbot.core import commands
from redbot.core.utils.chat_formatting import box, humanize_list
from ..abc import MixinMeta
from ..cog_utils import CompositeMetaClass, _
from ...audio_logging import debug_exc_log
from ...errors import TrackEnqueueError
from ..abc import MixinMeta
from ..cog_utils import HUMANIZED_PERM, CompositeMetaClass, _
log = logging.getLogger("red.cogs.Audio.cog.Events.dpy")
@@ -39,11 +44,55 @@ class DpyEvents(MixinMeta, metaclass=CompositeMetaClass):
raise RuntimeError(
"Not running audio command due to invalid machine architecture for Lavalink."
)
# with contextlib.suppress(Exception):
# player = lavalink.get_player(ctx.guild.id)
# notify_channel = player.fetch("channel")
# if not notify_channel:
# player.store("channel", ctx.channel.id)
current_perms = ctx.channel.permissions_for(ctx.me)
surpass_ignore = (
isinstance(ctx.channel, discord.abc.PrivateChannel)
or await ctx.bot.is_owner(ctx.author)
or await ctx.bot.is_admin(ctx.author)
)
guild = ctx.guild
if guild and not current_perms.is_superset(self.permission_cache):
current_perms_set = set(iter(current_perms))
expected_perms_set = set(iter(self.permission_cache))
diff = expected_perms_set - current_perms_set
missing_perms = dict((i for i in diff if i[-1] is not False))
missing_perms = OrderedDict(sorted(missing_perms.items()))
missing_permissions = missing_perms.keys()
log.debug(
"Missing the following perms in %d, Owner ID: %d: %s",
ctx.guild.id,
ctx.guild.owner.id,
humanize_list(list(missing_permissions)),
)
if not surpass_ignore:
text = _(
"I'm missing permissions in this server, "
"Please address this as soon as possible.\n\n"
"Expected Permissions:\n"
)
for perm, value in missing_perms.items():
text += "{perm}: [{status}]\n".format(
status=_("Enabled") if value else _("Disabled"),
perm=HUMANIZED_PERM.get(perm),
)
text = text.strip()
if current_perms.send_messages and current_perms.read_messages:
await ctx.send(box(text=text, lang="ini"))
else:
log.info(
"Missing write permission in %d, Owner ID: %d",
ctx.guild.id,
ctx.guild.owner.id,
)
raise CheckFailure(message=text)
with contextlib.suppress(Exception):
player = lavalink.get_player(ctx.guild.id)
notify_channel = player.fetch("channel")
if not notify_channel:
player.store("channel", ctx.channel.id)
self._daily_global_playlist_cache.setdefault(
self.bot.user.id, await self.config.daily_playlists()
)
@@ -51,12 +100,16 @@ class DpyEvents(MixinMeta, metaclass=CompositeMetaClass):
self.local_folder_current_path = Path(await self.config.localpath())
if not ctx.guild:
return
dj_enabled = self._dj_status_cache.setdefault(
ctx.guild.id, await self.config.guild(ctx.guild).dj_enabled()
)
self._daily_playlist_cache.setdefault(
ctx.guild.id, await self.config.guild(ctx.guild).daily_playlists()
)
self._persist_queue_cache.setdefault(
ctx.guild.id, await self.config.guild(ctx.guild).persist_queue()
)
if dj_enabled:
dj_role = self._dj_role_cache.setdefault(
ctx.guild.id, await self.config.guild(ctx.guild).dj_role()
@@ -78,12 +131,16 @@ class DpyEvents(MixinMeta, metaclass=CompositeMetaClass):
if isinstance(error, commands.ArgParserFailure):
handled = True
msg = _("`{user_input}` is not a valid value for `{command}`").format(
user_input=error.user_input, command=error.cmd
user_input=error.user_input,
command=error.cmd,
)
if error.custom_help_msg:
msg += f"\n{error.custom_help_msg}"
await self.send_embed_msg(
ctx, title=_("Unable To Parse Argument"), description=msg, error=True
ctx,
title=_("Unable To Parse Argument"),
description=msg,
error=True,
)
if error.send_cmd_help:
await ctx.send_help()
@@ -101,7 +158,10 @@ class DpyEvents(MixinMeta, metaclass=CompositeMetaClass):
)
else:
await self.send_embed_msg(
ctx, title=_("Invalid Argument"), description=error.args[0], error=True
ctx,
title=_("Invalid Argument"),
description=error.args[0],
error=True,
)
else:
await ctx.send_help()
@@ -137,6 +197,17 @@ class DpyEvents(MixinMeta, metaclass=CompositeMetaClass):
error=True,
)
debug_exc_log(log, error, "This is a handled error")
elif isinstance(error, discord.errors.HTTPException):
handled = True
await self.send_embed_msg(
ctx,
title=_("There was an issue communicating with Discord."),
description=_("This error has been reported to the bot owner."),
error=True,
)
log.exception(
"This is not handled in the core Audio cog, please report it.", exc_info=error
)
if not isinstance(
error,
(
@@ -186,3 +257,13 @@ class DpyEvents(MixinMeta, metaclass=CompositeMetaClass):
self.skip_votes[before.channel.guild].remove(member.id)
except (ValueError, KeyError, AttributeError):
pass
channel = self.rgetattr(member, "voice.channel", None)
bot_voice_state = self.rgetattr(member, "guild.me.voice.self_deaf", None)
if channel and bot_voice_state is False:
try:
player = lavalink.get_player(channel.guild.id)
except (KeyError, AttributeError):
pass
else:
if player.channel.id == channel.id:
await self.self_deafen(player)

View File

@@ -18,6 +18,8 @@ class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
) -> None:
current_track = player.current
current_channel = player.channel
if not current_channel:
return
guild = self.rgetattr(current_channel, "guild", None)
if await self.bot.cog_disabled_in_guild(self, guild):
await player.stop()
@@ -31,12 +33,15 @@ class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
current_length = self.rgetattr(current_track, "length", None)
current_thumbnail = self.rgetattr(current_track, "thumbnail", None)
current_extras = self.rgetattr(current_track, "extras", {})
current_id = self.rgetattr(current_track, "_info", {}).get("identifier")
guild_data = await self.config.guild(guild).all()
repeat = guild_data["repeat"]
notify = guild_data["notify"]
disconnect = guild_data["disconnect"]
autoplay = guild_data["auto_play"]
description = self.get_track_description(current_track, self.local_folder_current_path)
description = await self.get_track_description(
current_track, self.local_folder_current_path
)
status = await self.config.status()
log.debug(f"Received a new lavalink event for {guild_id}: {event_type}: {extra}")
prev_song: lavalink.Track = player.fetch("prev_song")
@@ -51,12 +56,18 @@ class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
player.store("playing_song", current_track)
player.store("requester", current_requester)
self.bot.dispatch("red_audio_track_start", guild, current_track, current_requester)
if guild_id and current_track:
await self.api_interface.persistent_queue_api.played(
guild_id=guild_id, track_id=current_track.track_identifier
)
if event_type == lavalink.LavalinkEvents.TRACK_END:
prev_requester = player.fetch("prev_requester")
self.bot.dispatch("red_audio_track_end", guild, prev_song, prev_requester)
if event_type == lavalink.LavalinkEvents.QUEUE_END:
prev_requester = player.fetch("prev_requester")
self.bot.dispatch("red_audio_queue_end", guild, prev_song, prev_requester)
if guild_id:
await self.api_interface.persistent_queue_api.drop(guild_id)
if (
autoplay
and not player.queue
@@ -82,7 +93,7 @@ class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
notify_channel,
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."
),
)
@@ -127,13 +138,13 @@ class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
)
player.store("notify_message", notify_message)
if event_type == lavalink.LavalinkEvents.TRACK_START and status:
player_check = self.get_active_player_count()
player_check = await self.get_active_player_count()
await self.update_bot_presence(*player_check)
if event_type == lavalink.LavalinkEvents.TRACK_END and status:
await asyncio.sleep(1)
if not player.is_playing:
player_check = self.get_active_player_count()
player_check = await self.get_active_player_count()
await self.update_bot_presence(*player_check)
if event_type == lavalink.LavalinkEvents.QUEUE_END:
@@ -146,7 +157,7 @@ class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
self.bot.dispatch("red_audio_audio_disconnect", guild)
await player.disconnect()
if status:
player_check = self.get_active_player_count()
player_check = await self.get_active_player_count()
await self.update_bot_presence(*player_check)
if event_type in [
@@ -209,5 +220,9 @@ class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
colour=await self.bot.get_embed_color(message_channel),
description="{}\n{}".format(extra.replace("\n", ""), description),
)
if current_id:
asyncio.create_task(
self.api_interface.global_cache_api.report_invalid(current_id)
)
await message_channel.send(embed=embed)
await player.skip()