I promise I'm not doing this on purpose (#4565)

* Prep for 0.7.2

* So What di i do here? I done Magic, magic only found in the tales of old.

* turns out formatting is something important

* fixes

* improved Error handling when Global API is enabled

* further improve resuming logic

* more of dat dark voodoo blood magic

* major tweaks to auto restore when auto play is enabled 👀

* fix duplicated "Auto play stated." message + Auto play restart :feelsgoodman:

* missed these

* fix the new duplicated fucking message bitch.

* Let discord handle player reconnects

* eh

* `Requires force install`, utilize new Exponential Backoff object on player and safer reconnect logic, emulating d.py and WL.

* hmmmmm gotta monitor

* mother fucking brackets

* Why didnt i consider this the first time?????????????

* new error code to handle?

* soooooooooooooooo these are import so why arent we ensuring they are set.

* improved logging

* improved logging

* aaaaaaaaaaaaaaa

* We need our own error and special handling to not conflict with dpy

* (Last Known Bug) Fix the infinite loop of 4006 that sometimes could happen as an edge case after a successful resume.

* This will require a force reinstall to install `RLL 0.8.0`, this properly fixes the bug mentioned on the previous commit.

* address "Localtrack names/paths need to be escaped." comment

* address Fixators crash mentioned in #AT

* style

* fix preda's crash mentioned in PR

* add a thing here add a thing there add a thing everywhere

* style

* fixes here, fixes there, and backbone for curated playlist.

* bypass aiohttp and githubs and cloudflare and yo mammas cache

* I propose the new style is no style.

* allow curated playlist to be updated it `[p]playlist update` and show the diff

* fix `[p]summon` not resuming playback until next track.

* Hopefully handle predas rate limits.

* what else did i break now

* Update Lavalink.jar build

* lets try this

* reset the queue

* Bring Edge commits over fix a bunch of shiz again

* Bring Edge commits over fix a bunch of shiz again

* Handle 4014 OPs, Change `skip_votes` key to be an int rather than guild object

* aaaaaaaaaaaaaaa im dumb

* ...

* Simplify some shiz + use a set instead of a list for votes.

Co-authored-by: aikaterna <20862007+aikaterna@users.noreply.github.com>
This commit is contained in:
Draper
2021-04-05 20:02:24 +01:00
committed by GitHub
parent 1199f160d0
commit b7d8b0552e
27 changed files with 890 additions and 113 deletions

View File

@@ -99,7 +99,6 @@ class LavalinkTasks(MixinMeta, metaclass=CompositeMetaClass):
bot=self.bot,
host=host,
password=password,
rest_port=ws_port,
ws_port=ws_port,
timeout=timeout,
resume_key=f"Red-Core-Audio-{self.bot.user.id}-{data_manager.instance_name}",

View File

@@ -47,15 +47,36 @@ class PlayerTasks(MixinMeta, metaclass=CompositeMetaClass):
servers.update(pause_times)
async for sid in AsyncIter(servers, steps=5):
server_obj = self.bot.get_guild(sid)
if sid in stop_times and await self.config.guild(server_obj).emptydc_enabled():
if not server_obj:
stop_times.pop(sid, None)
pause_times.pop(sid, None)
try:
player = lavalink.get_player(sid)
await self.api_interface.persistent_queue_api.drop(sid)
player.store("autoplay_notified", False)
await player.stop()
await player.disconnect()
await self.config.guild_from_id(
guild_id=sid
).currently_auto_playing_in.set([])
except Exception as err:
debug_exc_log(
log, err, f"Exception raised in Audio's emptydc_timer for {sid}."
)
elif sid in stop_times and await self.config.guild(server_obj).emptydc_enabled():
emptydc_timer = await self.config.guild(server_obj).emptydc_timer()
if (time.time() - stop_times[sid]) >= emptydc_timer:
stop_times.pop(sid)
try:
player = lavalink.get_player(sid)
await self.api_interface.persistent_queue_api.drop(sid)
player.store("autoplay_notified", False)
await player.stop()
await player.disconnect()
await self.config.guild_from_id(
guild_id=sid
).currently_auto_playing_in.set([])
except Exception as err:
if "No such player for that guild" in str(err):
stop_times.pop(sid, None)

View File

@@ -10,12 +10,14 @@ import lavalink
from redbot.core.data_manager import cog_data_path
from redbot.core.i18n import Translator
from redbot.core.utils import AsyncIter
from redbot.core.utils._internal_utils import send_to_owners_with_prefix_replaced
from redbot.core.utils.dbtools import APSWConnectionWrapper
from ...apis.interface import AudioAPIInterface
from ...apis.playlist_wrapper import PlaylistWrapper
from ...audio_logging import debug_exc_log
from ...errors import DatabaseError, TrackEnqueueError
from ...utils import task_callback
from ..abc import MixinMeta
from ..cog_utils import _OWNER_NOTIFICATION, _SCHEMA_VERSION, CompositeMetaClass
@@ -52,6 +54,7 @@ class StartUpTasks(MixinMeta, metaclass=CompositeMetaClass):
)
await self.playlist_api.delete_scheduled()
await self.api_interface.persistent_queue_api.delete_scheduled()
await self._build_bundled_playlist()
self.lavalink_restart_connect()
self.player_automated_timer_task = self.bot.loop.create_task(
self.player_automated_timer()
@@ -66,13 +69,29 @@ class StartUpTasks(MixinMeta, metaclass=CompositeMetaClass):
async def restore_players(self):
tries = 0
tracks_to_restore = await self.api_interface.persistent_queue_api.fetch_all()
await asyncio.sleep(10)
while not lavalink.node._nodes:
await asyncio.sleep(1)
tries += 1
if tries > 60:
log.exception("Unable to restore players, couldn't connect to Lavalink.")
return
metadata = {}
all_guilds = await self.config.all_guilds()
async for guild_id, guild_data in AsyncIter(all_guilds.items(), steps=100):
if guild_data["auto_play"]:
if guild_data["currently_auto_playing_in"]:
notify_channel, vc_id = guild_data["currently_auto_playing_in"]
metadata[guild_id] = (notify_channel, vc_id)
for guild_id, track_data in itertools.groupby(tracks_to_restore, key=lambda x: x.guild_id):
await asyncio.sleep(0)
tries = 0
try:
player: Optional[lavalink.Player]
player: Optional[lavalink.Player] = None
track_data = list(track_data)
guild = self.bot.get_guild(guild_id)
if not guild:
continue
persist_cache = self._persist_queue_cache.setdefault(
guild_id, await self.config.guild(guild).persist_queue()
)
@@ -88,40 +107,48 @@ class StartUpTasks(MixinMeta, metaclass=CompositeMetaClass):
player = None
except KeyError:
player = None
vc = 0
guild_data = await self.config.guild_from_id(guild.id).all()
shuffle = guild_data["shuffle"]
repeat = guild_data["repeat"]
volume = guild_data["volume"]
shuffle_bumped = guild_data["shuffle_bumped"]
auto_deafen = guild_data["auto_deafen"]
if player is None:
while tries < 25 and vc is not None:
while tries < 5 and vc is not None:
try:
vc = guild.get_channel(track_data[-1].room_id)
notify_channel_id, vc_id = metadata.pop(
guild_id, (None, track_data[-1].room_id)
)
vc = guild.get_channel(vc_id)
if not vc:
break
perms = vc.permissions_for(guild.me)
if not (perms.connect and perms.speak):
vc = None
break
await lavalink.connect(vc)
await lavalink.connect(vc, deafen=auto_deafen)
player = lavalink.get_player(guild.id)
player.store("connect", datetime.datetime.utcnow())
player.store("guild", guild_id)
await self.self_deafen(player)
player.store("channel", notify_channel_id)
break
except IndexError:
await asyncio.sleep(5)
tries += 1
except Exception as exc:
tries += 1
debug_exc_log(log, exc, "Failed to restore music voice channel")
if vc is None:
break
else:
await asyncio.sleep(1)
if tries >= 25 or guild is None or vc is None:
if tries >= 5 or guild is None or vc is None or player is None:
await self.api_interface.persistent_queue_api.drop(guild_id)
continue
shuffle = await self.config.guild(guild).shuffle()
repeat = await self.config.guild(guild).repeat()
volume = await self.config.guild(guild).volume()
shuffle_bumped = await self.config.guild(guild).shuffle_bumped()
player.repeat = repeat
player.shuffle = shuffle
player.shuffle_bumped = shuffle_bumped
@@ -137,6 +164,90 @@ class StartUpTasks(MixinMeta, metaclass=CompositeMetaClass):
debug_exc_log(log, err, f"Error restoring player in {guild_id}")
await self.api_interface.persistent_queue_api.drop(guild_id)
for guild_id, (notify_channel_id, vc_id) in metadata.items():
guild = self.bot.get_guild(guild_id)
player: Optional[lavalink.Player] = None
vc = 0
tries = 0
if not guild:
continue
if self.lavalink_connection_aborted:
player = None
else:
try:
player = lavalink.get_player(guild_id)
except IndexError:
player = None
except KeyError:
player = None
if player is None:
guild_data = await self.config.guild_from_id(guild.id).all()
shuffle = guild_data["shuffle"]
repeat = guild_data["repeat"]
volume = guild_data["volume"]
shuffle_bumped = guild_data["shuffle_bumped"]
auto_deafen = guild_data["auto_deafen"]
while tries < 5 and vc is not None:
try:
vc = guild.get_channel(vc_id)
if not vc:
break
perms = vc.permissions_for(guild.me)
if not (perms.connect and perms.speak):
vc = None
break
await lavalink.connect(vc, deafen=auto_deafen)
player = lavalink.get_player(guild.id)
player.store("connect", datetime.datetime.utcnow())
player.store("guild", guild_id)
player.store("channel", notify_channel_id)
break
except IndexError:
await asyncio.sleep(5)
tries += 1
except Exception as exc:
tries += 1
debug_exc_log(log, exc, "Failed to restore music voice channel")
if vc is None:
break
else:
await asyncio.sleep(1)
if tries >= 5 or guild is None or vc is None or player is None:
continue
player.repeat = repeat
player.shuffle = shuffle
player.shuffle_bumped = shuffle_bumped
if player.volume != volume:
await player.set_volume(volume)
player.maybe_shuffle()
if not player.is_playing:
notify_channel = player.fetch("channel")
try:
await self.api_interface.autoplay(player, self.playlist_api)
except DatabaseError:
notify_channel = self.bot.get_channel(notify_channel)
if notify_channel:
await self.send_embed_msg(
notify_channel, title=_("Couldn't get a valid track.")
)
return
except TrackEnqueueError:
notify_channel = self.bot.get_channel(notify_channel)
if notify_channel:
await self.send_embed_msg(
notify_channel,
title=_("Unable to Get Track"),
description=_(
"I'm unable to get a track from Lavalink at the moment, "
"try again in a few minutes."
),
)
return
del metadata
del all_guilds
async def maybe_message_all_owners(self):
current_notification = await self.config.owner_notification()
if current_notification == _OWNER_NOTIFICATION: