mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-07 03:38:53 -05:00
[Audio] New stuff from RLL 0.7.0 (#4529)
* New stuff from RLL 0.7.0 * discard here * formatting * do this properly * make it more unique * bump RLL * nuke `[p]llset restport`, only `[p]llset wsport` matters * Update setup.cfg * properly deprecate Rest port and Ensure Nodes are properly closed upon running LLSET commands * restore player on a attempt reconnect * restore player as a task * ensure we send the signal only if not playing. * register events a little earlier * hmmm * ffs * update application.yml * fix permissions edge case
This commit is contained in:
parent
af8af1934c
commit
d421c1c240
@ -1,4 +1,5 @@
|
||||
import asyncio
|
||||
import datetime
|
||||
import json
|
||||
|
||||
from collections import Counter
|
||||
@ -62,6 +63,7 @@ class Audio(
|
||||
self.play_lock = {}
|
||||
|
||||
self.lavalink_connect_task = None
|
||||
self._restore_task = None
|
||||
self.player_automated_timer_task = None
|
||||
self.cog_cleaned_up = False
|
||||
self.lavalink_connection_aborted = False
|
||||
@ -82,6 +84,8 @@ class Audio(
|
||||
"can_post": False,
|
||||
"can_delete": False,
|
||||
}
|
||||
self._ll_guild_updates = set()
|
||||
self._last_ll_update = datetime.datetime.now(datetime.timezone.utc)
|
||||
|
||||
default_global = dict(
|
||||
schema_version=1,
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import datetime
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, List, Mapping, MutableMapping, Optional, Tuple, Union
|
||||
from typing import Set, TYPE_CHECKING, Any, List, Mapping, MutableMapping, Optional, Tuple, Union
|
||||
|
||||
import aiohttp
|
||||
import discord
|
||||
@ -57,6 +58,7 @@ class MixinMeta(ABC):
|
||||
_error_counter: Counter
|
||||
|
||||
lavalink_connect_task: Optional[asyncio.Task]
|
||||
_restore_task: Optional[asyncio.Task]
|
||||
player_automated_timer_task: Optional[asyncio.Task]
|
||||
cog_init_task: Optional[asyncio.Task]
|
||||
cog_ready_event: asyncio.Event
|
||||
@ -64,6 +66,9 @@ class MixinMeta(ABC):
|
||||
_default_lavalink_settings: Mapping
|
||||
permission_cache = discord.Permissions
|
||||
|
||||
_last_ll_update: datetime.datetime
|
||||
_ll_guild_updates: Set[int]
|
||||
|
||||
@abstractmethod
|
||||
async def command_llsetup(self, ctx: commands.Context):
|
||||
raise NotImplementedError()
|
||||
@ -122,6 +127,12 @@ class MixinMeta(ABC):
|
||||
) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
@abstractmethod
|
||||
async def lavalink_update_handler(
|
||||
self, player: lavalink.Player, event_type: lavalink.enums.PlayerState, extra
|
||||
) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
@abstractmethod
|
||||
async def _clear_react(
|
||||
self, message: discord.Message, emoji: MutableMapping = None
|
||||
|
||||
@ -1472,14 +1472,12 @@ class AudioSetCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||
async def command_audioset_restart(self, ctx: commands.Context):
|
||||
"""Restarts the lavalink connection."""
|
||||
async with ctx.typing():
|
||||
lavalink.unregister_event_listener(self.lavalink_event_handler)
|
||||
await lavalink.close()
|
||||
if self.player_manager is not None:
|
||||
await self.player_manager.shutdown()
|
||||
|
||||
self.lavalink_restart_connect()
|
||||
lavalink.register_event_listener(self.lavalink_event_handler)
|
||||
await self.restore_players()
|
||||
|
||||
await self.send_embed_msg(
|
||||
ctx,
|
||||
title=_("Restarting Lavalink"),
|
||||
|
||||
@ -72,6 +72,7 @@ class PlayerControllerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||
await self.config.custom("EQUALIZER", ctx.guild.id).eq_bands.set(eq.bands)
|
||||
await player.stop()
|
||||
await player.disconnect()
|
||||
self._ll_guild_updates.discard(ctx.guild.id)
|
||||
await self.api_interface.persistent_queue_api.drop(ctx.guild.id)
|
||||
|
||||
@commands.command(name="now")
|
||||
|
||||
@ -72,7 +72,7 @@ class LavalinkSetupCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||
ctx,
|
||||
title=_("Failed To Shutdown Lavalink"),
|
||||
description=_(
|
||||
"For it to take effect please reload " "Audio (`{prefix}reload audio`)."
|
||||
"For it to take effect please reload Audio (`{prefix}reload audio`)."
|
||||
).format(
|
||||
prefix=ctx.prefix,
|
||||
),
|
||||
@ -188,31 +188,6 @@ class LavalinkSetupCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||
),
|
||||
)
|
||||
|
||||
@command_llsetup.command(name="restport")
|
||||
async def command_llsetup_restport(self, ctx: commands.Context, rest_port: int):
|
||||
"""Set the Lavalink REST server port."""
|
||||
await self.config.rest_port.set(rest_port)
|
||||
footer = None
|
||||
if await self.update_external_status():
|
||||
footer = _("External Lavalink server set to True.")
|
||||
await self.send_embed_msg(
|
||||
ctx,
|
||||
title=_("Setting Changed"),
|
||||
description=_("REST port set to {port}.").format(port=rest_port),
|
||||
footer=footer,
|
||||
)
|
||||
|
||||
try:
|
||||
self.lavalink_restart_connect()
|
||||
except ProcessLookupError:
|
||||
await self.send_embed_msg(
|
||||
ctx,
|
||||
title=_("Failed To Shutdown Lavalink"),
|
||||
description=_("Please reload Audio (`{prefix}reload audio`).").format(
|
||||
prefix=ctx.prefix
|
||||
),
|
||||
)
|
||||
|
||||
@command_llsetup.command(name="wsport")
|
||||
async def command_llsetup_wsport(self, ctx: commands.Context, ws_port: int):
|
||||
"""Set the Lavalink websocket server port."""
|
||||
@ -248,8 +223,9 @@ class LavalinkSetupCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||
ws_port = configs["ws_port"]
|
||||
msg = "----" + _("Connection Settings") + "---- \n"
|
||||
msg += _("Host: [{host}]\n").format(host=host)
|
||||
msg += _("Rest Port: [{port}]\n").format(port=rest_port)
|
||||
msg += _("WS Port: [{port}]\n").format(port=ws_port)
|
||||
if ws_port != rest_port:
|
||||
msg += _("Rest Port: [{port}]\n").format(port=rest_port)
|
||||
msg += _("Password: [{password}]\n").format(password=password)
|
||||
try:
|
||||
await self.send_embed_msg(ctx.author, description=box(msg, lang="ini"))
|
||||
|
||||
@ -278,7 +278,7 @@ class PlayerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||
if not await self.is_query_allowed(
|
||||
self.config,
|
||||
ctx,
|
||||
f"{single_track.title} {single_track.author} {single_track.uri} " f"{str(query)}",
|
||||
f"{single_track.title} {single_track.author} {single_track.uri} {str(query)}",
|
||||
query_obj=query,
|
||||
):
|
||||
if IS_DEBUG:
|
||||
|
||||
@ -239,7 +239,11 @@ class DpyEvents(MixinMeta, metaclass=CompositeMetaClass):
|
||||
if self.cog_init_task:
|
||||
self.cog_init_task.cancel()
|
||||
|
||||
if self._restore_task:
|
||||
self._restore_task.cancel()
|
||||
|
||||
lavalink.unregister_event_listener(self.lavalink_event_handler)
|
||||
lavalink.unregister_update_listener(self.lavalink_update_handler)
|
||||
self.bot.loop.create_task(lavalink.close())
|
||||
if self.player_manager is not None:
|
||||
self.bot.loop.create_task(self.player_manager.shutdown())
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import asyncio
|
||||
import contextlib
|
||||
import datetime
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
@ -16,6 +17,12 @@ _ = Translator("Audio", Path(__file__))
|
||||
|
||||
|
||||
class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
|
||||
async def lavalink_update_handler(
|
||||
self, player: lavalink.Player, event_type: lavalink.enums.PlayerState, extra
|
||||
):
|
||||
self._last_ll_update = datetime.datetime.now(datetime.timezone.utc)
|
||||
self._ll_guild_updates.add(int(extra.get("guildId", 0)))
|
||||
|
||||
async def lavalink_event_handler(
|
||||
self, player: lavalink.Player, event_type: lavalink.LavalinkEvents, extra
|
||||
) -> None:
|
||||
@ -160,6 +167,7 @@ class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
|
||||
if disconnect:
|
||||
self.bot.dispatch("red_audio_audio_disconnect", guild)
|
||||
await player.disconnect()
|
||||
self._ll_guild_updates.discard(guild.id)
|
||||
if status:
|
||||
player_check = await self.get_active_player_count()
|
||||
await self.update_bot_presence(*player_check)
|
||||
@ -193,6 +201,7 @@ class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
|
||||
await self.config.custom("EQUALIZER", guild_id).eq_bands.set(eq.bands)
|
||||
await player.stop()
|
||||
await player.disconnect()
|
||||
self._ll_guild_updates.discard(guild_id)
|
||||
self.bot.dispatch("red_audio_audio_disconnect", guild)
|
||||
if message_channel:
|
||||
message_channel = self.bot.get_channel(message_channel)
|
||||
|
||||
@ -4,6 +4,7 @@ from pathlib import Path
|
||||
|
||||
import lavalink
|
||||
|
||||
from redbot.core import data_manager
|
||||
from redbot.core.i18n import Translator
|
||||
from ...errors import LavalinkDownloadFailed
|
||||
from ...manager import ServerManager
|
||||
@ -16,9 +17,16 @@ _ = Translator("Audio", Path(__file__))
|
||||
|
||||
class LavalinkTasks(MixinMeta, metaclass=CompositeMetaClass):
|
||||
def lavalink_restart_connect(self) -> None:
|
||||
lavalink.unregister_event_listener(self.lavalink_event_handler)
|
||||
lavalink.unregister_update_listener(self.lavalink_update_handler)
|
||||
if self.lavalink_connect_task:
|
||||
self.lavalink_connect_task.cancel()
|
||||
if self._restore_task:
|
||||
self._restore_task.cancel()
|
||||
|
||||
self._restore_task = None
|
||||
lavalink.register_event_listener(self.lavalink_event_handler)
|
||||
lavalink.register_update_listener(self.lavalink_update_handler)
|
||||
self.lavalink_connect_task = self.bot.loop.create_task(self.lavalink_attempt_connect())
|
||||
|
||||
async def lavalink_attempt_connect(self, timeout: int = 50) -> None:
|
||||
@ -33,7 +41,6 @@ class LavalinkTasks(MixinMeta, metaclass=CompositeMetaClass):
|
||||
settings = self._default_lavalink_settings
|
||||
host = settings["host"]
|
||||
password = settings["password"]
|
||||
rest_port = settings["rest_port"]
|
||||
ws_port = settings["ws_port"]
|
||||
if self.player_manager is not None:
|
||||
await self.player_manager.shutdown()
|
||||
@ -73,7 +80,6 @@ class LavalinkTasks(MixinMeta, metaclass=CompositeMetaClass):
|
||||
else:
|
||||
host = configs["host"]
|
||||
password = configs["password"]
|
||||
rest_port = configs["rest_port"]
|
||||
ws_port = configs["ws_port"]
|
||||
break
|
||||
else:
|
||||
@ -86,14 +92,17 @@ class LavalinkTasks(MixinMeta, metaclass=CompositeMetaClass):
|
||||
|
||||
retry_count = 0
|
||||
while retry_count < max_retries:
|
||||
if lavalink.node._nodes:
|
||||
await lavalink.node.disconnect()
|
||||
try:
|
||||
await lavalink.initialize(
|
||||
bot=self.bot,
|
||||
host=host,
|
||||
password=password,
|
||||
rest_port=rest_port,
|
||||
rest_port=ws_port,
|
||||
ws_port=ws_port,
|
||||
timeout=timeout,
|
||||
resume_key=f"Red-Core-Audio-{self.bot.user.id}-{data_manager.instance_name}",
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
log.error("Connecting to Lavalink server timed out, retrying...")
|
||||
@ -115,3 +124,5 @@ class LavalinkTasks(MixinMeta, metaclass=CompositeMetaClass):
|
||||
"Connecting to the Lavalink server failed after multiple attempts. "
|
||||
"See above tracebacks for details."
|
||||
)
|
||||
return
|
||||
self._restore_task = asyncio.create_task(self.restore_players())
|
||||
|
||||
@ -57,8 +57,6 @@ class StartUpTasks(MixinMeta, metaclass=CompositeMetaClass):
|
||||
self.player_automated_timer()
|
||||
)
|
||||
self.player_automated_timer_task.add_done_callback(task_callback)
|
||||
lavalink.register_event_listener(self.lavalink_event_handler)
|
||||
await self.restore_players()
|
||||
except Exception as err:
|
||||
log.exception("Audio failed to start up, please report this issue.", exc_info=err)
|
||||
raise err
|
||||
@ -68,6 +66,7 @@ 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)
|
||||
for guild_id, track_data in itertools.groupby(tracks_to_restore, key=lambda x: x.guild_id):
|
||||
await asyncio.sleep(0)
|
||||
try:
|
||||
@ -95,6 +94,12 @@ class StartUpTasks(MixinMeta, metaclass=CompositeMetaClass):
|
||||
while tries < 25 and vc is not None:
|
||||
try:
|
||||
vc = guild.get_channel(track_data[-1].room_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)
|
||||
player = lavalink.get_player(guild.id)
|
||||
player.store("connect", datetime.datetime.utcnow())
|
||||
@ -126,8 +131,8 @@ class StartUpTasks(MixinMeta, metaclass=CompositeMetaClass):
|
||||
track = track.track_object
|
||||
player.add(guild.get_member(track.extras.get("requester")) or guild.me, track)
|
||||
player.maybe_shuffle()
|
||||
|
||||
await player.play()
|
||||
if not player.is_playing:
|
||||
await player.play()
|
||||
except Exception as err:
|
||||
debug_exc_log(log, err, f"Error restoring player in {guild_id}")
|
||||
await self.api_interface.persistent_queue_api.drop(guild_id)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
server:
|
||||
host: "localhost"
|
||||
port: 2333 # REST server
|
||||
port: 2333 # WS port
|
||||
lavalink:
|
||||
server:
|
||||
password: "youshallnotpass"
|
||||
@ -18,7 +18,7 @@ lavalink:
|
||||
youtubePlaylistLoadLimit: 10000
|
||||
logging:
|
||||
file:
|
||||
max-history: 30
|
||||
max-history: 7
|
||||
max-size: 1GB
|
||||
path: ./logs/
|
||||
level:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user