mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-23 19:44:20 +00:00
Do some more stuff
This commit is contained in:
parent
90f566107f
commit
3e27e3b183
4 changed files with 97 additions and 63 deletions
|
@ -4,11 +4,9 @@ import typing
|
||||||
import logging as _logging
|
import logging as _logging
|
||||||
import sys
|
import sys
|
||||||
from ..commands import NullCommand
|
from ..commands import NullCommand
|
||||||
from ..commands.summon import SummonMessage
|
|
||||||
from ..commands.play import PlayMessage
|
|
||||||
from ..utils import asyncify, Call, Command
|
from ..utils import asyncify, Call, Command
|
||||||
from royalnet.error import UnregisteredError
|
from ..error import UnregisteredError, NoneFoundError, TooManyFoundError
|
||||||
from ..network import RoyalnetLink, Message, RequestSuccessful, RequestError
|
from ..network import RoyalnetLink, Message, RequestSuccessful
|
||||||
from ..database import Alchemy, relationshiplinkchain
|
from ..database import Alchemy, relationshiplinkchain
|
||||||
from ..audio import RoyalAudioFile
|
from ..audio import RoyalAudioFile
|
||||||
|
|
||||||
|
@ -20,6 +18,19 @@ if not discord.opus.is_loaded():
|
||||||
log.error("Opus is not loaded. Weird behaviour might emerge.")
|
log.error("Opus is not loaded. Weird behaviour might emerge.")
|
||||||
|
|
||||||
|
|
||||||
|
class PlayMessage(Message):
|
||||||
|
def __init__(self, url: str, channel_identifier: typing.Optional[typing.Union[int, str]] = None):
|
||||||
|
self.url: str = url
|
||||||
|
self.channel_identifier: typing.Optional[typing.Union[int, str]] = channel_identifier
|
||||||
|
|
||||||
|
|
||||||
|
class SummonMessage(Message):
|
||||||
|
def __init__(self, channel_identifier: typing.Union[int, str],
|
||||||
|
guild_identifier: typing.Optional[typing.Union[int, str]]):
|
||||||
|
self.channel_identifier = channel_identifier
|
||||||
|
self.guild_identifier = guild_identifier
|
||||||
|
|
||||||
|
|
||||||
class DiscordBot:
|
class DiscordBot:
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
token: str,
|
token: str,
|
||||||
|
@ -33,9 +44,9 @@ class DiscordBot:
|
||||||
missing_command: typing.Type[Command] = NullCommand,
|
missing_command: typing.Type[Command] = NullCommand,
|
||||||
error_command: typing.Type[Command] = NullCommand):
|
error_command: typing.Type[Command] = NullCommand):
|
||||||
self.token = token
|
self.token = token
|
||||||
|
# Generate commands
|
||||||
self.missing_command = missing_command
|
self.missing_command = missing_command
|
||||||
self.error_command = error_command
|
self.error_command = error_command
|
||||||
# Generate commands
|
|
||||||
self.commands = {}
|
self.commands = {}
|
||||||
required_tables = set()
|
required_tables = set()
|
||||||
for command in commands:
|
for command in commands:
|
||||||
|
@ -47,8 +58,9 @@ class DiscordBot:
|
||||||
self.identity_table = self.alchemy.__getattribute__(identity_table.__name__)
|
self.identity_table = self.alchemy.__getattribute__(identity_table.__name__)
|
||||||
self.identity_column = self.identity_table.__getattribute__(self.identity_table, identity_column_name)
|
self.identity_column = self.identity_table.__getattribute__(self.identity_table, identity_column_name)
|
||||||
self.identity_chain = relationshiplinkchain(self.master_table, self.identity_table)
|
self.identity_chain = relationshiplinkchain(self.master_table, self.identity_table)
|
||||||
|
# Connect to Royalnet
|
||||||
self.network: RoyalnetLink = RoyalnetLink(master_server_uri, master_server_secret, "discord", self.network_handler)
|
self.network: RoyalnetLink = RoyalnetLink(master_server_uri, master_server_secret, "discord",
|
||||||
|
self.network_handler)
|
||||||
loop.create_task(self.network.run())
|
loop.create_task(self.network.run())
|
||||||
|
|
||||||
# noinspection PyMethodParameters
|
# noinspection PyMethodParameters
|
||||||
|
@ -60,16 +72,16 @@ class DiscordBot:
|
||||||
|
|
||||||
async def reply(call, text: str):
|
async def reply(call, text: str):
|
||||||
escaped_text = text.replace("*", "\\*") \
|
escaped_text = text.replace("*", "\\*") \
|
||||||
.replace("_", "\\_") \
|
.replace("_", "\\_") \
|
||||||
.replace("`", "\\`") \
|
.replace("`", "\\`") \
|
||||||
.replace("[b]", "**") \
|
.replace("[b]", "**") \
|
||||||
.replace("[/b]", "**") \
|
.replace("[/b]", "**") \
|
||||||
.replace("[i]", "_") \
|
.replace("[i]", "_") \
|
||||||
.replace("[/i]", "_") \
|
.replace("[/i]", "_") \
|
||||||
.replace("[u]", "__") \
|
.replace("[u]", "__") \
|
||||||
.replace("[/u]", "__") \
|
.replace("[/u]", "__") \
|
||||||
.replace("[c]", "`") \
|
.replace("[c]", "`") \
|
||||||
.replace("[/c]", "`")
|
.replace("[/c]", "`")
|
||||||
await call.channel.send(escaped_text)
|
await call.channel.send(escaped_text)
|
||||||
|
|
||||||
async def net_request(call, message: Message, destination: str):
|
async def net_request(call, message: Message, destination: str):
|
||||||
|
@ -98,6 +110,7 @@ class DiscordBot:
|
||||||
await channel.connect()
|
await channel.connect()
|
||||||
except discord.errors.ClientException:
|
except discord.errors.ClientException:
|
||||||
# Move to the selected channel, instead of connecting
|
# Move to the selected channel, instead of connecting
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
for voice_client in self.bot.voice_clients:
|
for voice_client in self.bot.voice_clients:
|
||||||
voice_client: discord.VoiceClient
|
voice_client: discord.VoiceClient
|
||||||
if voice_client.guild != channel.guild:
|
if voice_client.guild != channel.guild:
|
||||||
|
@ -133,38 +146,71 @@ class DiscordBot:
|
||||||
self.DiscordClient = DiscordClient
|
self.DiscordClient = DiscordClient
|
||||||
self.bot = self.DiscordClient()
|
self.bot = self.DiscordClient()
|
||||||
|
|
||||||
|
def find_guild(self, identifier: typing.Union[str, int]):
|
||||||
|
"""Find the Guild with the specified identifier. Names are case-insensitive."""
|
||||||
|
if isinstance(identifier, str):
|
||||||
|
all_guilds: typing.List[discord.Guild] = self.bot.guilds
|
||||||
|
matching_channels: typing.List[discord.Guild] = []
|
||||||
|
for guild in all_guilds:
|
||||||
|
if guild.name.lower() == identifier.lower():
|
||||||
|
matching_channels.append(guild)
|
||||||
|
if len(matching_channels) == 0:
|
||||||
|
raise NoneFoundError("No channels were found")
|
||||||
|
elif len(matching_channels) > 1:
|
||||||
|
raise TooManyFoundError("Too many channels were found")
|
||||||
|
return matching_channels[0]
|
||||||
|
elif isinstance(identifier, int):
|
||||||
|
return self.bot.get_guild(identifier)
|
||||||
|
raise TypeError("Invalid identifier type, should be str or int")
|
||||||
|
|
||||||
|
def find_channel(self, identifier: typing.Union[str, int], guild: typing.Optional[discord.Guild] = None):
|
||||||
|
"""Find the GuildChannel with the specified identifier. Names are case-insensitive."""
|
||||||
|
if isinstance(identifier, str):
|
||||||
|
if guild is not None:
|
||||||
|
all_channels = guild.channels
|
||||||
|
else:
|
||||||
|
all_channels: typing.List[discord.abc.GuildChannel] = self.bot.get_all_channels()
|
||||||
|
matching_channels: typing.List[discord.abc.GuildChannel] = []
|
||||||
|
for channel in all_channels:
|
||||||
|
if not (isinstance(channel, discord.TextChannel)
|
||||||
|
or isinstance(channel, discord.VoiceChannel)
|
||||||
|
or isinstance(channel, discord.CategoryChannel)):
|
||||||
|
continue
|
||||||
|
if channel.name.lower() == identifier.lower():
|
||||||
|
matching_channels.append(channel)
|
||||||
|
if len(matching_channels) == 0:
|
||||||
|
raise NoneFoundError("No channels were found")
|
||||||
|
elif len(matching_channels) > 1:
|
||||||
|
raise TooManyFoundError("Too many channels were found")
|
||||||
|
return matching_channels[0]
|
||||||
|
elif isinstance(identifier, int):
|
||||||
|
channel: typing.List[discord.abc.GuildChannel] = self.bot.get_channel(identifier)
|
||||||
|
if ((isinstance(channel, discord.TextChannel)
|
||||||
|
or isinstance(channel, discord.VoiceChannel)
|
||||||
|
or isinstance(channel, discord.CategoryChannel))
|
||||||
|
and guild):
|
||||||
|
assert channel.guild == guild
|
||||||
|
return channel
|
||||||
|
raise TypeError("Invalid identifier type, should be str or int")
|
||||||
|
|
||||||
async def network_handler(self, message: Message) -> Message:
|
async def network_handler(self, message: Message) -> Message:
|
||||||
|
"""Handle a Royalnet request."""
|
||||||
if isinstance(message, SummonMessage):
|
if isinstance(message, SummonMessage):
|
||||||
return await self.nh_summon(message)
|
return await self.nh_summon(message)
|
||||||
elif isinstance(message, PlayMessage):
|
elif isinstance(message, PlayMessage):
|
||||||
return await self.nh_play(message)
|
return await self.nh_play(message)
|
||||||
|
|
||||||
async def nh_summon(self, message: SummonMessage):
|
async def nh_summon(self, message: SummonMessage):
|
||||||
channels: typing.List[discord.abc.GuildChannel] = self.bot.get_all_channels()
|
"""Handle a summon Royalnet request. That is, join a voice channel, or move to a different one if that is not possible."""
|
||||||
matching_channels: typing.List[discord.VoiceChannel] = []
|
channel = self.find_channel(message.channel_identifier)
|
||||||
for channel in channels:
|
if not isinstance(channel, discord.VoiceChannel):
|
||||||
if isinstance(channel, discord.VoiceChannel):
|
raise NoneFoundError("Channel is not a voice channel")
|
||||||
if channel.name == message.channel_name:
|
loop.create_task(self.bot.vc_connect_or_move(channel))
|
||||||
matching_channels.append(channel)
|
|
||||||
if len(matching_channels) == 0:
|
|
||||||
return RequestError("No channels with a matching name found")
|
|
||||||
elif len(matching_channels) > 1:
|
|
||||||
return RequestError("Multiple channels with a matching name found")
|
|
||||||
matching_channel = matching_channels[0]
|
|
||||||
await self.bot.vc_connect_or_move(matching_channel)
|
|
||||||
return RequestSuccessful()
|
return RequestSuccessful()
|
||||||
|
|
||||||
async def nh_play(self, message: PlayMessage):
|
async def nh_play(self, message: PlayMessage):
|
||||||
# TODO: actually do what's intended to do
|
"""Handle a play Royalnet request. That is, add audio to a PlayMode."""
|
||||||
# Download the audio
|
raise
|
||||||
file = await asyncify(RoyalAudioFile.create_from_url, message.url)
|
|
||||||
# Get the audio source
|
|
||||||
audio_source = file[0].as_audio_source()
|
|
||||||
# Play the audio source
|
|
||||||
for voice_client in self.bot.voice_clients:
|
|
||||||
voice_client: discord.VoiceClient
|
|
||||||
voice_client.play(audio_source)
|
|
||||||
return RequestError()
|
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
await self.bot.login(self.token)
|
await self.bot.login(self.token)
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import typing
|
import typing
|
||||||
from ..utils import Command, Call
|
from ..utils import Command, Call
|
||||||
from ..network import Message, RequestSuccessful, RequestError
|
from ..network import Message, RequestSuccessful, RequestError
|
||||||
|
from ..bots.discord import PlayMessage
|
||||||
|
|
||||||
class PlayMessage(Message):
|
|
||||||
def __init__(self, url: str):
|
|
||||||
self.url: str = url
|
|
||||||
|
|
||||||
|
|
||||||
class PlayCommand(Command):
|
class PlayCommand(Command):
|
||||||
|
@ -17,10 +13,5 @@ class PlayCommand(Command):
|
||||||
async def common(cls, call: Call):
|
async def common(cls, call: Call):
|
||||||
url: str = call.args[0]
|
url: str = call.args[0]
|
||||||
response: typing.Union[RequestSuccessful, RequestError] = await call.net_request(PlayMessage(url), "discord")
|
response: typing.Union[RequestSuccessful, RequestError] = await call.net_request(PlayMessage(url), "discord")
|
||||||
if isinstance(response, RequestSuccessful):
|
response.raise_on_error()
|
||||||
await call.reply(f"✅ Richiesta la riproduzione di [c]{url}[/c].")
|
await call.reply(f"✅ Richiesta la riproduzione di [c]{url}[/c].")
|
||||||
return
|
|
||||||
elif isinstance(response, RequestError):
|
|
||||||
await call.reply(f"⚠️ Si è verificato un'errore nella richiesta di riproduzione:\n[c]{response.reason}[/c]")
|
|
||||||
return
|
|
||||||
raise TypeError(f"Received unexpected response in the PlayCommand: {response.__class__.__name__}")
|
|
||||||
|
|
|
@ -2,11 +2,7 @@ import typing
|
||||||
import discord
|
import discord
|
||||||
from ..utils import Command, Call
|
from ..utils import Command, Call
|
||||||
from ..network import Message, RequestSuccessful, RequestError
|
from ..network import Message, RequestSuccessful, RequestError
|
||||||
|
from ..bots.discord import SummonMessage
|
||||||
|
|
||||||
class SummonMessage(Message):
|
|
||||||
def __init__(self, channel_name: str):
|
|
||||||
self.channel_name: str = channel_name
|
|
||||||
|
|
||||||
|
|
||||||
class SummonCommand(Command):
|
class SummonCommand(Command):
|
||||||
|
@ -19,13 +15,8 @@ class SummonCommand(Command):
|
||||||
async def common(cls, call: Call):
|
async def common(cls, call: Call):
|
||||||
channel_name: str = call.args[0].lstrip("#")
|
channel_name: str = call.args[0].lstrip("#")
|
||||||
response: typing.Union[RequestSuccessful, RequestError] = await call.net_request(SummonMessage(channel_name), "discord")
|
response: typing.Union[RequestSuccessful, RequestError] = await call.net_request(SummonMessage(channel_name), "discord")
|
||||||
if isinstance(response, RequestError):
|
response.raise_on_error()
|
||||||
await call.reply(f"⚠️ Si è verificato un'errore nella richiesta di connessione:\n[c]{response.exc}[/c]")
|
await call.reply(f"✅ Mi sono connesso in [c]#{channel_name}[/c].")
|
||||||
return
|
|
||||||
elif isinstance(response, RequestSuccessful):
|
|
||||||
await call.reply(f"✅ Mi sono connesso in [c]#{channel_name}[/c].")
|
|
||||||
return
|
|
||||||
raise TypeError(f"Received unexpected response type while summoning the bot: {response.__class__.__name__}")
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def discord(cls, call: Call):
|
async def discord(cls, call: Call):
|
||||||
|
|
|
@ -2,6 +2,9 @@ class Message:
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__}>"
|
return f"<{self.__class__.__name__}>"
|
||||||
|
|
||||||
|
def raise_on_error(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class IdentifySuccessfulMessage(Message):
|
class IdentifySuccessfulMessage(Message):
|
||||||
pass
|
pass
|
||||||
|
@ -32,3 +35,6 @@ class RequestSuccessful(Message):
|
||||||
class RequestError(Message):
|
class RequestError(Message):
|
||||||
def __init__(self, exc: Exception):
|
def __init__(self, exc: Exception):
|
||||||
self.exc = exc
|
self.exc = exc
|
||||||
|
|
||||||
|
def raise_on_error(self):
|
||||||
|
raise self.exc
|
||||||
|
|
Loading…
Reference in a new issue