diff --git a/royalgames.py b/royalgames.py index e9fc4423..5a0ed69e 100644 --- a/royalgames.py +++ b/royalgames.py @@ -21,7 +21,7 @@ logging.getLogger("royalnet.bots.telegram").setLevel(logging.DEBUG) commands = [PingCommand, ShipCommand, SmecdsCommand, ColorCommand, CiaoruoziCommand, DebugCreateCommand, SyncCommand, AuthorCommand, DiarioCommand, RageCommand, DateparserCommand, ReminderCommand, KvactiveCommand, KvCommand, - KvrollCommand, VideoinfoCommand, SummonCommand, PlayCommand] + KvrollCommand, VideoinfoCommand, SummonCommand, PlayCommand, SkipCommand] address, port = "localhost", 1234 diff --git a/royalnet/audio/royalpcmfile.py b/royalnet/audio/royalpcmfile.py index c112d5d2..b230e53b 100644 --- a/royalnet/audio/royalpcmfile.py +++ b/royalnet/audio/royalpcmfile.py @@ -16,6 +16,9 @@ class RoyalPCMFile(YtdlFile): def __init__(self, info: "YtdlInfo", **ytdl_args): # Preemptively initialize info to be able to generate the filename self.info = info + # Ensure the file doesn't already exist + if os.path.exists(self._ytdl_filename) or os.path.exists(self.audio_filename): + raise FileExistsError("Can't overwrite file") # Overwrite the new ytdl_args self.ytdl_args = {**self.ytdl_args, **ytdl_args} log.info(f"Now downloading {info.webpage_url}") diff --git a/royalnet/bots/discord.py b/royalnet/bots/discord.py index 3356598c..98dfcfc5 100644 --- a/royalnet/bots/discord.py +++ b/royalnet/bots/discord.py @@ -201,7 +201,7 @@ class DiscordBot(GenericBot): """Add a file to the corresponding music_data object.""" log.debug(f"Adding {url} to music_data of {guild}") guild_music_data = self.music_data[guild] - audio_sources = RoyalPCMAudio.create_from_url(url) + audio_sources = await asyncify(RoyalPCMAudio.create_from_url, url) for audio_source in audio_sources: log.debug(f"Adding {audio_source} to music_data") guild_music_data.add(audio_source) diff --git a/royalnet/bots/generic.py b/royalnet/bots/generic.py index 411d4d2d..20b3b2ae 100644 --- a/royalnet/bots/generic.py +++ b/royalnet/bots/generic.py @@ -112,7 +112,7 @@ class GenericBot: except Exception as exc: log.debug(f"Calling error_command because of an error in {command_name}") await self._Call(channel, self.error_command, - exception_info=sys.exc_info(), + exception=exc, previous_command=command, **kwargs).run() async def run(self): diff --git a/royalnet/commands/__init__.py b/royalnet/commands/__init__.py index 0cb6834c..27219687 100644 --- a/royalnet/commands/__init__.py +++ b/royalnet/commands/__init__.py @@ -16,8 +16,10 @@ from .kvroll import KvrollCommand from .videoinfo import VideoinfoCommand from .summon import SummonCommand from .play import PlayCommand +from .skip import SkipCommand __all__ = ["NullCommand", "PingCommand", "ShipCommand", "SmecdsCommand", "CiaoruoziCommand", "ColorCommand", "SyncCommand", "DiarioCommand", "RageCommand", "DateparserCommand", "AuthorCommand", "ReminderCommand", - "KvactiveCommand", "KvCommand", "KvrollCommand", "VideoinfoCommand", "SummonCommand", "PlayCommand"] + "KvactiveCommand", "KvCommand", "KvrollCommand", "VideoinfoCommand", "SummonCommand", "PlayCommand", + "SkipCommand"] diff --git a/royalnet/commands/error_handler.py b/royalnet/commands/error_handler.py index 27bfd3e2..2b50d95d 100644 --- a/royalnet/commands/error_handler.py +++ b/royalnet/commands/error_handler.py @@ -6,6 +6,7 @@ from ..error import NoneFoundError, \ UnsupportedError, \ InvalidInputError, \ InvalidConfigError, \ + RoyalnetError, \ ExternalError @@ -40,6 +41,9 @@ class ErrorHandlerCommand(Command): if isinstance(exception, InvalidConfigError): await call.reply("⚠️ Il bot non è stato configurato correttamente, quindi questo comando non può essere eseguito. L'errore è stato segnalato all'amministratore.") return + if isinstance(exception, RoyalnetError): + await call.reply(f"⚠️ La richiesta a Royalnet ha restituito un errore: {exception.exc}") + return if isinstance(exception, ExternalError): await call.reply("⚠️ Una risorsa esterna necessaria per l'esecuzione del comando non ha funzionato correttamente, quindi il comando è stato annullato.") return diff --git a/royalnet/commands/play.py b/royalnet/commands/play.py index 8bad9313..4bc7fdb8 100644 --- a/royalnet/commands/play.py +++ b/royalnet/commands/play.py @@ -1,8 +1,7 @@ import typing -import discord import asyncio from ..utils import Command, Call, NetworkHandler -from ..network import Message, RequestSuccessful, RequestError +from ..network import Message, RequestSuccessful from ..error import TooManyFoundError if typing.TYPE_CHECKING: from ..bots import DiscordBot @@ -12,9 +11,9 @@ loop = asyncio.get_event_loop() class PlayMessage(Message): - def __init__(self, url: str, guild_identifier: typing.Optional[str] = None): + def __init__(self, url: str, guild_name: typing.Optional[str] = None): self.url: str = url - self.guild_identifier: typing.Optional[str] = guild_identifier + self.guild_name: typing.Optional[str] = guild_name class PlayNH(NetworkHandler): @@ -24,8 +23,8 @@ class PlayNH(NetworkHandler): async def discord(cls, bot: "DiscordBot", message: PlayMessage): """Handle a play Royalnet request. That is, add audio to a PlayMode.""" # Find the matching guild - if message.guild_identifier: - guild = bot.client.find_guild(message.guild_identifier) + if message.guild_name: + guild = bot.client.find_guild(message.guild_name) else: if len(bot.music_data) != 1: raise TooManyFoundError("Multiple guilds found") diff --git a/royalnet/commands/skip.py b/royalnet/commands/skip.py new file mode 100644 index 00000000..206f4bd4 --- /dev/null +++ b/royalnet/commands/skip.py @@ -0,0 +1,48 @@ +import typing +import discord +from ..network import Message, RequestSuccessful +from ..utils import Command, Call, NetworkHandler +from ..error import TooManyFoundError, NoneFoundError +from ..audio import RoyalPCMAudio +if typing.TYPE_CHECKING: + from ..bots import DiscordBot + + +class SkipMessage(Message): + def __init__(self, guild_name: typing.Optional[str] = None): + self.guild_name: typing.Optional[str] = guild_name + + +class SkipNH(NetworkHandler): + message_type = SkipMessage + + @classmethod + async def discord(cls, bot: "DiscordBot", message: SkipMessage): + # Find the matching guild + if message.guild_name: + guild = bot.client.find_guild(message.guild_name) + else: + if len(bot.music_data) != 1: + raise TooManyFoundError("Multiple guilds found") + guild = list(bot.music_data)[0] + # Set the currently playing source as ended + voice_client: discord.VoiceClient = bot.client.find_voice_client_by_guild(guild) + if not voice_client.is_playing(): + raise NoneFoundError("Nothing to skip") + # noinspection PyProtectedMember + voice_client._player.stop() + + +class SkipCommand(Command): + + command_name = "skip" + command_description = "Salta la canzone attualmente in riproduzione in chat vocale." + command_syntax = "[ [guild] ]" + + network_handlers = [SkipNH] + + @classmethod + async def common(cls, call: Call): + guild = call.args.match(r"(?:\[(.+)])?") + response: RequestSuccessful = await call.net_request(SkipMessage(guild), "discord") + await call.reply(f"✅ Richiesta lo skip della canzone attuale..")