diff --git a/docs/doctrees/audio.doctree b/docs/doctrees/audio.doctree
index e796186d..e2b97294 100644
Binary files a/docs/doctrees/audio.doctree and b/docs/doctrees/audio.doctree differ
diff --git a/docs/doctrees/bots.doctree b/docs/doctrees/bots.doctree
index 390d8b16..88d943c7 100644
Binary files a/docs/doctrees/bots.doctree and b/docs/doctrees/bots.doctree differ
diff --git a/docs/doctrees/commands.doctree b/docs/doctrees/commands.doctree
index 2d4c1106..d16bba80 100644
Binary files a/docs/doctrees/commands.doctree and b/docs/doctrees/commands.doctree differ
diff --git a/docs/doctrees/database.doctree b/docs/doctrees/database.doctree
index c91dab64..e1b86d2d 100644
Binary files a/docs/doctrees/database.doctree and b/docs/doctrees/database.doctree differ
diff --git a/docs/doctrees/environment.pickle b/docs/doctrees/environment.pickle
index 57177c7a..c30e0fd3 100644
Binary files a/docs/doctrees/environment.pickle and b/docs/doctrees/environment.pickle differ
diff --git a/docs/doctrees/error.doctree b/docs/doctrees/error.doctree
index b10c9edb..400a99aa 100644
Binary files a/docs/doctrees/error.doctree and b/docs/doctrees/error.doctree differ
diff --git a/docs/doctrees/network.doctree b/docs/doctrees/network.doctree
index c6b8dffe..c3212919 100644
Binary files a/docs/doctrees/network.doctree and b/docs/doctrees/network.doctree differ
diff --git a/docs/doctrees/utils.doctree b/docs/doctrees/utils.doctree
index a2bdf8ab..8688165b 100644
Binary files a/docs/doctrees/utils.doctree and b/docs/doctrees/utils.doctree differ
diff --git a/docs/doctrees/web.doctree b/docs/doctrees/web.doctree
index 3a8bc0a6..5df16542 100644
Binary files a/docs/doctrees/web.doctree and b/docs/doctrees/web.doctree differ
diff --git a/docs/html/audio.html b/docs/html/audio.html
index 099bbf78..fc119209 100644
--- a/docs/html/audio.html
+++ b/docs/html/audio.html
@@ -159,6 +159,450 @@
royalnet.audio
+Video and audio downloading related classes, mainly used for Discord voice bots.
+
+
+class royalnet.audio.
PlayMode
+The base class for a PlayMode, such as royalnet.audio.Playlist
. Inherit from this class if you want to create a custom PlayMode.
+
+
+__init__
( )
+Create a new PlayMode and initialize the generator inside.
+
+
+
+
+_generate_generator
( )
+Factory function for an async generator that changes the now_playing
property either to a discord.audio.RoyalPCMAudio
or to None
, then yields the value it changed it to.
+
+Yields
+The royalnet.audio.RoyalPCMAudio
to be played next.
+
+
+
+
+
+
+add
( item: royalnet.audio.royalpcmaudio.RoyalPCMAudio ) → None
+Add a new royalnet.audio.RoyalPCMAudio
to the PlayMode.
+
+Parameters
+item – The item to add to the PlayMode.
+
+
+
+
+
+
+delete
( ) → None
+Delete all royalnet.audio.RoyalPCMAudio
contained inside this PlayMode.
+
+
+
+
+async next
( ) → Optional[royalnet.audio.royalpcmaudio.RoyalPCMAudio]
+Get the next royalnet.audio.RoyalPCMAudio
from the list and advance it.
+
+Returns
+The next royalnet.audio.RoyalPCMAudio
.
+
+
+
+
+
+
+queue_preview
( ) → List[royalnet.audio.royalpcmaudio.RoyalPCMAudio]
+Display all the videos in the PlayMode as a list, if possible.
+To be used with queue commands, for example.
+
+Raises
+NotImplementedError – If a preview can’t be generated.
+
+Returns
+A list of videos contained in the queue.
+
+
+
+
+
+
+videos_left
( ) → Union[int, float]
+Return the number of videos left in the PlayMode.
+
+Returns
+Usually a int
, but may return also math.inf
if the PlayMode is infinite.
+
+
+
+
+
+
+
+
+class royalnet.audio.
Playlist
( starting_list: List[royalnet.audio.royalpcmaudio.RoyalPCMAudio] = None )
+A video list. royalnet.audio.RoyalPCMAudio
played are removed from the list.
+
+
+__init__
( starting_list: List[royalnet.audio.royalpcmaudio.RoyalPCMAudio] = None )
+Create a new Playlist.
+
+Parameters
+starting_list – A list of items with which the Playlist will be created.
+
+
+
+
+
+
+_generate_generator
( )
+Factory function for an async generator that changes the now_playing
property either to a discord.audio.RoyalPCMAudio
or to None
, then yields the value it changed it to.
+
+Yields
+The royalnet.audio.RoyalPCMAudio
to be played next.
+
+
+
+
+
+
+add
( item ) → None
+Add a new royalnet.audio.RoyalPCMAudio
to the PlayMode.
+
+Parameters
+item – The item to add to the PlayMode.
+
+
+
+
+
+
+delete
( ) → None
+Delete all royalnet.audio.RoyalPCMAudio
contained inside this PlayMode.
+
+
+
+
+queue_preview
( ) → List[royalnet.audio.royalpcmaudio.RoyalPCMAudio]
+Display all the videos in the PlayMode as a list, if possible.
+To be used with queue commands, for example.
+
+Raises
+NotImplementedError – If a preview can’t be generated.
+
+Returns
+A list of videos contained in the queue.
+
+
+
+
+
+
+videos_left
( ) → Union[int, float]
+Return the number of videos left in the PlayMode.
+
+Returns
+Usually a int
, but may return also math.inf
if the PlayMode is infinite.
+
+
+
+
+
+
+
+
+class royalnet.audio.
Pool
( starting_pool: List[royalnet.audio.royalpcmaudio.RoyalPCMAudio] = None )
+A royalnet.audio.RoyalPCMAudio
pool. royalnet.audio.RoyalPCMAudio
are selected in random order and are not repeated until every song has been played at least once.
+
+
+__init__
( starting_pool: List[royalnet.audio.royalpcmaudio.RoyalPCMAudio] = None )
+Create a new Pool.
+
+Parameters
+starting_pool – A list of items the Pool will be created from.
+
+
+
+
+
+
+_generate_generator
( )
+Factory function for an async generator that changes the now_playing
property either to a discord.audio.RoyalPCMAudio
or to None
, then yields the value it changed it to.
+
+Yields
+The royalnet.audio.RoyalPCMAudio
to be played next.
+
+
+
+
+
+
+add
( item ) → None
+Add a new royalnet.audio.RoyalPCMAudio
to the PlayMode.
+
+Parameters
+item – The item to add to the PlayMode.
+
+
+
+
+
+
+delete
( ) → None
+Delete all royalnet.audio.RoyalPCMAudio
contained inside this PlayMode.
+
+
+
+
+queue_preview
( ) → List[royalnet.audio.royalpcmaudio.RoyalPCMAudio]
+Display all the videos in the PlayMode as a list, if possible.
+To be used with queue commands, for example.
+
+Raises
+NotImplementedError – If a preview can’t be generated.
+
+Returns
+A list of videos contained in the queue.
+
+
+
+
+
+
+videos_left
( ) → Union[int, float]
+Return the number of videos left in the PlayMode.
+
+Returns
+Usually a int
, but may return also math.inf
if the PlayMode is infinite.
+
+
+
+
+
+
+
+
+class royalnet.audio.
YtdlFile
( info: royalnet.audio.youtubedl.YtdlInfo , outtmpl='%(title)s-%(id)s.%(ext)s' , **ytdl_args )
+A wrapper around a youtube_dl downloaded file.
+
+
+_stop_download
( )
+I have no clue of what this does, or why is it here. Possibly remove it?
+
+Raises
+InterruptDownload – …uhhh, always?
+
+
+
+
+
+
+static create_from_url
( url , outtmpl='%(title)s-%(id)s.%(ext)s' , **ytdl_args ) → List[royalnet.audio.youtubedl.YtdlFile]
+Download the videos at the specified url.
+
+Parameters
+
+url – The url to download the videos from.
+outtmpl – The filename that the downloaded videos are going to have. The name can be formatted according to the outtmpl documentation .
+ytdl_args – Other arguments to be passed to the YoutubeDL object.
+
+
+Returns
+A list
of YtdlFiles.
+
+
+
+
+
+
+delete_video_file
( )
+Delete the file located at self.video_filename
.
+
+
Note
+
No checks are done when deleting, so it may try to delete a non-existing file and raise an exception or do some other weird stuff with weird filenames.
+
+
+
+
+
+ytdl_args
= {'logger': <Logger royalnet.audio.youtubedl (WARNING)>, 'no_warnings': True, 'noplaylist': True, 'quiet': True}
+
+
+
+
+
+
+class royalnet.audio.
YtdlInfo
( info: Dict[str, Any] )
+A wrapper around youtube_dl extracted info.
+
+
+__init__
( info: Dict[str, Any] )
+Create a YtdlInfo from the dict returned by the youtube_dl.YoutubeDL.extract_info()
function.
+
+
+
+
+
+static create_from_url
( url , **ytdl_args ) → List[royalnet.audio.youtubedl.YtdlInfo]
+
+
+
+
+download
( outtmpl='%(title)s-%(id)s.%(ext)s' , **ytdl_args ) → royalnet.audio.youtubedl.YtdlFile
+
+
+
+
+to_discord_embed
( ) → discord.embeds.Embed
+
+
+
+
+
+
+class royalnet.audio.
RoyalPCMFile
( info: royalnet.audio.youtubedl.YtdlInfo , **ytdl_args )
+
+
+property audio_filename
+Returns:
+The name of the downloaded and PCM-converted audio file.
+
+
+
+
+static create_from_url
( url: str , **ytdl_args ) → List[royalnet.audio.royalpcmfile.RoyalPCMFile]
+Download a file with youtube_dl and create a list of discord.audio.RoyalPCMFile
.
+
+Parameters
+
+
+Returns
+A list
of RoyalPCMAudios, each corresponding to a downloaded video.
+
+
+
+
+
+
+static create_from_ytsearch
( search: str , amount: int = 1 , **ytdl_args ) → List[royalnet.audio.royalpcmfile.RoyalPCMFile]
+Search a string on YouTube and download the first amount
number of videos, then download those with youtube_dl and create a list of discord.audio.RoyalPCMFile
.
+
+Parameters
+
+search – The string to search on YouTube.
+amount – The number of videos to download.
+ytdl_args – Extra arguments to be passed to YoutubeDL while downloading.
+
+
+Returns
+A list
of RoyalPCMFiles, each corresponding to a downloaded video.
+
+
+
+
+
+
+delete_audio_file
( )
+Delete the PCM-converted audio file.
+
+
+
+
+ytdl_args
= {'format': 'bestaudio'}
+
+
+
+
+property ytdl_filename
+
+Returns
+The name of the downloaded video file, as a str
.
+
+
+
+
Warning
+
It’s going to be deleted as soon as the royalnet.audio.RoyalPCMFile.__init__()
function has completed, so it’s probably not going to be very useful…
+
+
+
+
+
+
+
+class royalnet.audio.
RoyalPCMAudio
( rpf: royalnet.audio.royalpcmfile.RoyalPCMFile )
+A discord.AudioSource
that keeps data in a file instead of in memory.
+
+
+__init__
( rpf: royalnet.audio.royalpcmfile.RoyalPCMFile )
+Create a discord.audio.RoyalPCMAudio
from a royalnet.audio.RoyalPCMFile
.
+
+
+
+
+
+static create_from_url
( url: str ) → List[royalnet.audio.royalpcmaudio.RoyalPCMAudio]
+Download a file with youtube_dl and create a list of RoyalPCMAudios.
+
+Parameters
+url – The url of the file to download.
+
+Returns
+A list
of RoyalPCMAudios, each corresponding to a downloaded video.
+
+
+
+
+
+
+static create_from_ytsearch
( search: str , amount: int = 1 ) → List[royalnet.audio.royalpcmaudio.RoyalPCMAudio]
+Search a string on YouTube and download the first amount
number of videos, then download those with youtube_dl and create a list of RoyalPCMAudios.
+
+Parameters
+
+
+Returns
+A list
of RoyalPCMAudios, each corresponding to a downloaded video.
+
+
+
+
+
+
+delete
( )
+Permanently delete the downloaded file.
+
+
+
+
+is_opus
( )
+This audio file isn’t Opus-encoded, but PCM-encoded.
+
+Returns
+False
.
+
+
+
+
+
+
+read
( )
+Reads 20ms worth of audio.
+If the audio is complete, then returning an empty bytes
-like object to signal this is the way to do so.
+
+
+
+
diff --git a/docs/html/bots.html b/docs/html/bots.html
index 40a14279..9c7d43b1 100644
--- a/docs/html/bots.html
+++ b/docs/html/bots.html
@@ -159,6 +159,194 @@
royalnet.bots
+Various bot interfaces, and a generic class to create new ones.
+
+
+class royalnet.bots.
TelegramBot
( * , telegram_config: royalnet.bots.telegram.TelegramConfig , royalnet_config: Optional[royalnet.network.royalnetconfig.RoyalnetConfig] = None , database_config: Optional[royalnet.database.databaseconfig.DatabaseConfig] = None , command_prefix: str = '/' , commands: List[Type[royalnet.utils.command.Command]] = None , missing_command: Type[royalnet.utils.command.Command] = <class 'royalnet.commands.null.NullCommand'> , error_command: Type[royalnet.utils.command.Command] = <class 'royalnet.commands.null.NullCommand'> )
+A bot that connects to Telegram .
+
+
+_call_factory
( ) → Type[royalnet.utils.call.Call]
+Create the TelegramCall class, representing a command call. It should inherit from royalnet.utils.Call
.
+
+Returns
+The created TelegramCall class.
+
+
+
+
+
+
+async _handle_update
( update: telegram.update.Update )
+
+
+
+
+_init_client
( )
+Create the telegram.Bot
, and set the starting offset.
+
+
+
+
+property botfather_command_string
+Generate a string to be pasted in the “Edit Commands” BotFather prompt.
+
+
+
+
+interface_name
= 'telegram'
+
+
+
+
+async run
( )
+A blocking coroutine that should make the bot start listening to commands and requests.
+
+
+
+
+
+
+class royalnet.bots.
TelegramConfig
( token: str )
+The specific configuration to be used for royalnet.database.TelegramBot
.
+
+
+
+
+class royalnet.bots.
DiscordBot
( * , discord_config: royalnet.bots.discord.DiscordConfig , royalnet_config: Optional[royalnet.network.royalnetconfig.RoyalnetConfig] = None , database_config: Optional[royalnet.database.databaseconfig.DatabaseConfig] = None , command_prefix: str = '!' , commands: List[Type[royalnet.utils.command.Command]] = None , missing_command: Type[royalnet.utils.command.Command] = <class 'royalnet.commands.null.NullCommand'> , error_command: Type[royalnet.utils.command.Command] = <class 'royalnet.commands.null.NullCommand'> )
+A bot that connects to Discord .
+
+
+_bot_factory
( ) → Type[discord.client.Client]
+Create a custom DiscordClient class inheriting from discord.Client
.
+
+
+
+
+_call_factory
( ) → Type[royalnet.utils.call.Call]
+Create the TelegramCall class, representing a command call. It should inherit from royalnet.utils.Call
.
+
+Returns
+The created TelegramCall class.
+
+
+
+
+
+
+_init_client
( )
+Create an instance of the DiscordClient class created in royalnet.bots.DiscordBot._bot_factory()
.
+
+
+
+
+_init_voice
( )
+Initialize the variables needed for the connection to voice chat.
+
+
+
+
+async add_to_music_data
( audio_sources: List[royalnet.audio.royalpcmaudio.RoyalPCMAudio], guild: discord.guild.Guild )
+Add a file to the corresponding music_data object.
+
+
+
+
+async advance_music_data
( guild: discord.guild.Guild )
+Try to play the next song, while it exists. Otherwise, just return.
+
+
+
+
+interface_name
= 'discord'
+
+
+
+
+async run
( )
+Login to Discord, then run the bot.
+
+
+
+
+async update_activity_with_source_title
( )
+Change the bot’s presence (using discord.Client.change_presence()
) to match the current listening status.
+If multiple guilds are using the bot, the bot will always have an empty presence.
+
+
+
+
+
+
+class royalnet.bots.
DiscordConfig
( token: str )
+The specific configuration to be used for royalnet.bots.DiscordBot
.
+
+
+
+
+class royalnet.bots.
GenericBot
( * , royalnet_config: Optional[royalnet.network.royalnetconfig.RoyalnetConfig] = None , database_config: Optional[royalnet.database.databaseconfig.DatabaseConfig] = None , command_prefix: str , commands: List[Type[royalnet.utils.command.Command]] = None , missing_command: Type[royalnet.utils.command.Command] = <class 'royalnet.commands.null.NullCommand'> , error_command: Type[royalnet.utils.command.Command] = <class 'royalnet.commands.null.NullCommand'> , loop: asyncio.events.AbstractEventLoop = None )
+A generic bot class, to be used as base for the other more specific classes, such as royalnet.bots.TelegramBot and royalnet.bots.DiscordBot .
+
+
+_call_factory
( ) → Type[royalnet.utils.call.Call]
+Create the TelegramCall class, representing a command call. It should inherit from royalnet.utils.Call
.
+
+Returns
+The created TelegramCall class.
+
+
+
+
+
+
+_init_commands
( command_prefix: str, commands: List[Type[royalnet.utils.command.Command]], missing_command: Type[royalnet.utils.command.Command], error_command: Type[royalnet.utils.command.Command] ) → None
+Generate the commands
dictionary required to handle incoming messages, and the network_handlers
dictionary required to handle incoming requests.
+
+
+
+
+_init_database
( commands: List[Type[royalnet.utils.command.Command]], database_config: royalnet.database.databaseconfig.DatabaseConfig )
+Create an royalnet.database.Alchemy
with the tables required by the commands. Then, find the chain that links the master_table
to the identity_table
.
+
+
+
+
+_init_royalnet
( royalnet_config: royalnet.network.royalnetconfig.RoyalnetConfig )
+Create a royalnet.network.RoyalnetLink
, and run it as a asyncio.Task
.
+
+
+
+
+async _network_handler
( request_dict: dict ) → dict
+Handle a single dict
received from the royalnet.network.RoyalnetLink
.
+
+Returns
+Another dict
, formatted as a royalnet.network.Response
.
+
+
+
+
+
+
+async call
( command_name: str , channel , parameters: List[str] = None , **kwargs )
+Call the command with the specified name.
+If it doesn’t exist, call self.missing_command
.
+If an exception is raised during the execution of the command, call self.error_command
.
+
+
+
+
+interface_name
= NotImplemented
+
+
+
+
+async run
( )
+A blocking coroutine that should make the bot start listening to commands and requests.
+
+
+
+
diff --git a/docs/html/commands.html b/docs/html/commands.html
index 82159801..e1fc928b 100644
--- a/docs/html/commands.html
+++ b/docs/html/commands.html
@@ -159,6 +159,138 @@
royalnet.commands
+Commands that can be used in bots.
+These probably won’t suit your needs, as they are tailored for the bots of the Royal Games gaming community, but they may be useful to develop new ones.
+
+
+class royalnet.commands.
NullCommand
+
+
+
+
+class royalnet.commands.
PingCommand
+
+
+
+
+class royalnet.commands.
ShipCommand
+
+
+
+
+class royalnet.commands.
SmecdsCommand
+
+
+
+
+class royalnet.commands.
CiaoruoziCommand
+
+
+
+
+class royalnet.commands.
ColorCommand
+
+
+
+
+class royalnet.commands.
SyncCommand
+
+
+
+
+class royalnet.commands.
DiarioCommand
+
+
+
+
+class royalnet.commands.
RageCommand
+
+
+
+
+class royalnet.commands.
DateparserCommand
+
+
+
+
+class royalnet.commands.
AuthorCommand
+
+
+
+
+class royalnet.commands.
ReminderCommand
+
+
+
+
+class royalnet.commands.
KvactiveCommand
+
+
+
+
+class royalnet.commands.
KvCommand
+
+
+
+
+class royalnet.commands.
KvrollCommand
+
+
+
+
+class royalnet.commands.
VideoinfoCommand
+
+
+
+
+class royalnet.commands.
SummonCommand
+
+
+
+
+class royalnet.commands.
PlayCommand
+
+
+
+
+class royalnet.commands.
SkipCommand
+
+
+
+
+class royalnet.commands.
PlaymodeCommand
+
+
+
+
+class royalnet.commands.
VideochannelCommand
+
+
+
+
+class royalnet.commands.
MissingCommand
+
+
+
+
+class royalnet.commands.
CvCommand
+
+
+
+
+class royalnet.commands.
PauseCommand
+
+
+
+
+class royalnet.commands.
QueueCommand
+
+
+
+
+class royalnet.commands.
RoyalnetprofileCommand
+
+
diff --git a/docs/html/database.html b/docs/html/database.html
index 5698031e..018f9f8c 100644
--- a/docs/html/database.html
+++ b/docs/html/database.html
@@ -85,7 +85,7 @@
royalnet.bots
royalnet.commands
royalnet.database
royalnet.network
@@ -160,8 +160,393 @@
royalnet.database
-
-
Tables
+
Relational database classes and methods.
+
+
+class royalnet.database.
Alchemy
( database_uri: str , tables: Set )
+A wrapper around SQLAlchemy declarative that allows to use multiple databases at once while maintaining a single table-class for both of them.
+
+
+__init__
( database_uri: str , tables: Set )
+Create a new Alchemy object.
+
+Parameters
+
+
+
+
+
+
+
+_create_tables
( tables: Set )
+
+
+
+
+session_acm
( )
+Use Alchemy as a asyncronous context manager (to be used in async with statements).
+
+
+
+
+session_cm
( )
+Use Alchemy as a context manager (to be used in with statements).
+
+
+
+
+
+
+royalnet.database.
relationshiplinkchain
( starting_class , ending_class ) → Optional[tuple]
+Find the path to follow to get from the starting table to the ending table.
+
+
+
+
+class royalnet.database.
DatabaseConfig
( database_uri: str , master_table: Type , identity_table: Type , identity_column_name: str )
+The configuration to be used for the royalnet.database.Alchemy component of royalnet.bots.GenericBot .
+
+
+
+
Tables
+
+
+class royalnet.database.tables.
Royal
+
+
+avatar
= Column(None, LargeBinary(), table=None)
+
+
+
+
+password
= Column(None, LargeBinary(), table=None)
+
+
+
+
+role
= Column(None, String(), table=None, nullable=False)
+
+
+
+
+uid
= Column(None, Integer(), table=None, primary_key=True, nullable=False)
+
+
+
+
+username
= Column(None, String(), table=None, nullable=False)
+
+
+
+
+
+
+class royalnet.database.tables.
Telegram
+
+
+first_name
= Column(None, String(), table=None)
+
+
+
+
+last_name
= Column(None, String(), table=None)
+
+
+
+
+mention
( ) → str
+
+
+
+
+royal
= <RelationshipProperty at 0x7fafa024a8c8; no key>
+
+
+
+
+royal_id
= Column(None, Integer(), ForeignKey('royals.uid'), table=None)
+
+
+
+
+tg_id
= Column(None, BigInteger(), table=None, primary_key=True, nullable=False)
+
+
+
+
+username
= Column(None, String(), table=None)
+
+
+
+
+
+
+class royalnet.database.tables.
Diario
+
+
+context
= Column(None, Text(), table=None)
+
+
+
+
+creator
= <RelationshipProperty at 0x7fafa01e6448; no key>
+
+
+
+
+creator_id
= Column(None, Integer(), ForeignKey('royals.uid'), table=None)
+
+
+
+
+diario_id
= Column(None, Integer(), table=None, primary_key=True, nullable=False)
+
+
+
+
+media_url
= Column(None, String(), table=None)
+
+
+
+
+quoted
= Column(None, String(), table=None)
+
+
+
+
+quoted_account
= <RelationshipProperty at 0x7fafa01e6648; no key>
+
+
+
+
+quoted_account_id
= Column(None, Integer(), ForeignKey('royals.uid'), table=None)
+
+
+
+
+spoiler
= Column(None, Boolean(), table=None, default=ColumnDefault(False))
+
+
+
+
+text
= Column(None, Text(), table=None)
+
+
+
+
+timestamp
= Column(None, DateTime(), table=None, nullable=False)
+
+
+
+
+
+
+class royalnet.database.tables.
Alias
+
+
+alias
= Column(None, String(), table=None, primary_key=True, nullable=False)
+
+
+
+
+royal
= <RelationshipProperty at 0x7fafa01e6bc8; no key>
+
+
+
+
+royal_id
= Column(None, Integer(), ForeignKey('royals.uid'), table=None)
+
+
+
+
+
+
+class royalnet.database.tables.
ActiveKvGroup
+
+
+group
= <RelationshipProperty at 0x7fafa024ad48; no key>
+
+
+
+
+group_name
= Column(None, String(), ForeignKey('keygroups.group_name'), table=None, nullable=False)
+
+
+
+
+royal
= <RelationshipProperty at 0x7fafa01e64c8; no key>
+
+
+
+
+royal_id
= Column(None, Integer(), ForeignKey('royals.uid'), table=None, primary_key=True, nullable=False)
+
+
+
+
+
+
+class royalnet.database.tables.
Keyvalue
+
+
+group
= <RelationshipProperty at 0x7fafa024acc8; no key>
+
+
+
+
+group_name
= Column(None, String(), ForeignKey('keygroups.group_name'), table=None, primary_key=True, nullable=False)
+
+
+
+
+key
= Column(None, String(), table=None, primary_key=True, nullable=False)
+
+
+
+
+value
= Column(None, String(), table=None, nullable=False)
+
+
+
+
+
+
+class royalnet.database.tables.
Keygroup
+
+
+group_name
= Column(None, String(), ForeignKey('keygroups.group_name'), table=None, primary_key=True, nullable=False)
+
+
+
+
+
+
+class royalnet.database.tables.
Discord
+
+
+avatar_hash
= Column(None, String(), table=None)
+
+
+
+
+discord_id
= Column(None, BigInteger(), table=None, primary_key=True, nullable=False)
+
+
+
+
+discriminator
= Column(None, String(), table=None)
+
+
+
+
+full_username
( )
+
+
+
+
+royal
= <RelationshipProperty at 0x7fafa024abc8; no key>
+
+
+
+
+royal_id
= Column(None, Integer(), ForeignKey('royals.uid'), table=None)
+
+
+
+
+username
= Column(None, String(), table=None)
+
+
+
+
+
+
+class royalnet.database.tables.
WikiPage
+Wiki page properties.
+
+
Warning
+
Requires PostgreSQL!
+
+
+
+content
= Column(None, Text(), table=None)
+
+
+
+
+css
= Column(None, String(), table=None)
+
+
+
+
+format
= Column(None, String(), table=None, nullable=False, default=ColumnDefault('markdown'))
+
+
+
+
+page_id
= Column(None, UUID(as_uuid=True), table=None, primary_key=True, nullable=False)
+
+
+
+
+title
= Column(None, String(), table=None, nullable=False)
+
+
+
+
+
+
+class royalnet.database.tables.
WikiRevision
+A wiki page revision.
+
+
Warning
+
Requires PostgreSQL!
+
+
+
+author
= <RelationshipProperty at 0x7fafa01e6b48; no key>
+
+
+
+
+author_id
= Column(None, Integer(), ForeignKey('royals.uid'), table=None, nullable=False)
+
+
+
+
+diff
= Column(None, Text(), table=None)
+
+
+
+
+page
= <RelationshipProperty at 0x7fafa01e6448; no key>
+
+
+
+
+page_id
= Column(None, UUID(as_uuid=True), ForeignKey('wikipages.page_id'), table=None, nullable=False)
+
+
+
+
+reason
= Column(None, Text(), table=None)
+
+
+
+
+revision_id
= Column(None, UUID(as_uuid=True), table=None, primary_key=True, nullable=False)
+
+
+
+
+timestamp
= Column(None, DateTime(), table=None, nullable=False)
+
+
+
+
diff --git a/docs/html/error.html b/docs/html/error.html
index c9513bb2..008127f7 100644
--- a/docs/html/error.html
+++ b/docs/html/error.html
@@ -159,6 +159,73 @@
royalnet.error
+
+
+exception royalnet.error.
CurrentlyDisabledError
+This feature is temporarely disabled and is not available right now.
+
+
+
+
+exception royalnet.error.
ExternalError
+Something went wrong in a non-Royalnet component and the command execution cannot be completed.
+
+
+
+
+exception royalnet.error.
FileTooBigError
+The file to be downloaded would be too big to store; therefore, it has been skipped.
+
+
+
+
+exception royalnet.error.
InvalidConfigError
+The bot has not been configured correctly, therefore the command can not function.
+
+
+
+
+exception royalnet.error.
InvalidInputError
+The command has received invalid input and cannot complete.
+
+
+
+
+exception royalnet.error.
NoneFoundError
+The element that was being looked for was not found.
+
+
+
+
+exception royalnet.error.
RoyalnetRequestError
( error: ResponseError )
+An error was raised while handling the Royalnet request.
+This exception contains the royalnet.network.ResponseError
that was returned by the other Link.
+
+
+
+
+exception royalnet.error.
RoyalnetResponseError
+The royalnet.network.Response
that was received is invalid.
+
+
+
+
+exception royalnet.error.
TooManyFoundError
+Multiple elements matching the request were found, and only one was expected.
+
+
+
+
+exception royalnet.error.
UnregisteredError
+The command required a registered user, and the user was not registered.
+
+
+
+
+exception royalnet.error.
UnsupportedError
+The command is not supported for the specified interface.
+
+
diff --git a/docs/html/genindex.html b/docs/html/genindex.html
index fcc173cc..d2a16137 100644
--- a/docs/html/genindex.html
+++ b/docs/html/genindex.html
@@ -154,8 +154,808 @@
Index
+
_
+ |
A
+ |
B
+ |
C
+ |
D
+ |
E
+ |
F
+ |
G
+ |
I
+ |
J
+ |
K
+ |
L
+ |
M
+ |
N
+ |
O
+ |
P
+ |
Q
+ |
R
+ |
S
+ |
T
+ |
U
+ |
V
+ |
W
+ |
Y
+_
+
+
+A
+
+
+B
+
+
+C
+
+
+D
+
+
+E
+
+
+F
+
+
+G
+
+
+I
+
+
+J
+
+
+K
+
+
+L
+
+
+M
+
+
+N
+
+
+O
+
+
+P
+
+
+Q
+
+
+R
+
+
+S
+
+
+T
+
+
+U
+
+
+V
+
+
+W
+
+
+Y
+
+
diff --git a/docs/html/index.html b/docs/html/index.html
index 1ddaff1e..c74c4423 100644
--- a/docs/html/index.html
+++ b/docs/html/index.html
@@ -166,7 +166,7 @@
royalnet.database
royalnet.network
royalnet.web
diff --git a/docs/html/network.html b/docs/html/network.html
index 2b4e29f0..b37e1873 100644
--- a/docs/html/network.html
+++ b/docs/html/network.html
@@ -159,6 +159,262 @@
royalnet.network
+Royalnet (websocket) related classes.
+
+
+class royalnet.network.
RoyalnetLink
( master_uri: str , secret: str , link_type: str , request_handler , * , loop: asyncio.events.AbstractEventLoop = None )
+
+
+async connect
( )
+Connect to the royalnet.network.RoyalnetServer
at self.master_uri
.
+
+
+
+
+async identify
( ) → None
+
+
+
+
+async receive
( ) → royalnet.network.package.Package
+Recieve a Package
from the royalnet.network.RoyalnetServer
.
+
+Raises
+royalnet.network.royalnetlink.ConnectionClosedError –
+
+
+
+
+
+
+async request
( message , destination )
+
+
+
+
+async run
( loops: numbers.Real = inf )
+Blockingly run the Link.
+
+
+
+
+async send
( package: royalnet.network.package.Package )
+
+
+
+
+
+
+exception royalnet.network.
NetworkError
( error_data: dict , *args )
+
+
+
+
+exception royalnet.network.
NotConnectedError
+The royalnet.network.RoyalnetLink
is not connected to a royalnet.network.RoyalnetServer
.
+
+
+
+
+exception royalnet.network.
NotIdentifiedError
+The royalnet.network.RoyalnetLink
has not identified yet to a royalnet.network.RoyalnetServer
.
+
+
+
+
+class royalnet.network.
Package
( data: dict , * , source: str , destination: str , source_conv_id: Optional[str] = None , destination_conv_id: Optional[str] = None )
+A Royalnet package, the data type with which a royalnet.network.RoyalnetLink
communicates with a royalnet.network.RoyalnetServer
or another link.
+Contains info about the source and the destination.
+
+
+__init__
( data: dict , * , source: str , destination: str , source_conv_id: Optional[str] = None , destination_conv_id: Optional[str] = None )
+Create a Package.
+
+Parameters
+
+data – The data that should be sent. Usually a royalnet.network.Message
.
+source – The nid
of the node that created this Package.
+destination – The link_type
of the destination node, or alternatively, the nid
of the node. Can also be the NULL
value to send the message to nobody.
+source_conv_id – The conversation id of the node that created this package. Akin to the sequence number on IP packets.
+destination_conv_id – The conversation id of the node that this Package is a reply to.
+
+
+
+
+
+
+
+static from_dict
( d ) → royalnet.network.package.Package
+Create a Package from a dictionary.
+
+
+
+
+static from_json_bytes
( b: bytes ) → royalnet.network.package.Package
+Create a Package from UTF8-encoded JSON bytes.
+
+
+
+
+static from_json_string
( string: str ) → royalnet.network.package.Package
+Create a Package from a JSON string.
+
+
+
+
+reply
( data ) → royalnet.network.package.Package
+Reply to this Package with another Package.
+
+Parameters
+data – The data that should be sent. Usually a royalnet.network.Message
.
+
+Returns
+The reply Package.
+
+
+
+
+
+
+to_dict
( ) → dict
+Convert the Package into a dictionary.
+
+
+
+
+to_json_bytes
( ) → bytes
+Convert the Package into UTF8-encoded JSON bytes.
+
+
+
+
+to_json_string
( ) → str
+Convert the Package into a JSON string.
+
+
+
+
+
+
+class royalnet.network.
RoyalnetServer
( address: str , port: int , required_secret: str , * , loop: asyncio.events.AbstractEventLoop = None )
+
+
+find_client
( * , nid: str = None , link_type: str = None ) → List[royalnet.network.royalnetserver.ConnectedClient]
+
+
+
+
+find_destination
( package: royalnet.network.package.Package ) → List[royalnet.network.royalnetserver.ConnectedClient]
+Find a list of destinations for the package.
+
+Parameters
+package – The package to find the destination of.
+
+Returns
+A list
of ConnectedClients
to send the package to.
+
+
+
+
+
+
+async listener
( websocket: websockets.server.WebSocketServerProtocol , path )
+
+
+
+
+async route_package
( package: royalnet.network.package.Package ) → None
+Executed every time a package is received and must be routed somewhere.
+
+
+
+
+async serve
( )
+
+
+
+
+async start
( )
+
+
+
+
+
+
+class royalnet.network.
RoyalnetConfig
( master_uri: str , master_secret: str )
+
+
+
+
+exception royalnet.network.
ConnectionClosedError
+The royalnet.network.RoyalnetLink
’s connection was closed unexpectedly. The link can’t be used anymore.
+
+
+
+
+class royalnet.network.
Request
( handler: str , data: dict )
+A request sent from a royalnet.network.RoyalnetLink
to another.
+It contains the name of the requested handler, in addition to the data.
+
+
+static from_dict
( d: dict )
+
+
+
+
+to_dict
( )
+
+
+
+
+
+
+class royalnet.network.
Response
+A base class to be inherited by all other response types.
+
+
+classmethod from_dict
( d: dict ) → royalnet.network.response.Response
+Recreate the response from a received dict
.
+
+
+
+
+raise_on_error
( )
+Raise an Exception
if the Response is an error, do nothing otherwise.
+
+
+
+
+to_dict
( ) → dict
+Prepare the Response to be sent by converting it to a JSONable dict
.
+
+
+
+
+
+
+class royalnet.network.
ResponseSuccess
( data: Optional[dict] = None )
+A response to a successful royalnet.network.Request
.
+
+
+raise_on_error
( )
+Raise an Exception
if the Response is an error, do nothing otherwise.
+
+
+
+
+
+
+class royalnet.network.
ResponseError
( name: str , description: str , extra_info: Optional[dict] = None )
+A response to a invalid royalnet.network.Request
.
+
+
+raise_on_error
( )
+Raise an Exception
if the Response is an error, do nothing otherwise.
+
+
+
+
diff --git a/docs/html/objects.inv b/docs/html/objects.inv
index e45d8c52..47189e10 100644
Binary files a/docs/html/objects.inv and b/docs/html/objects.inv differ
diff --git a/docs/html/py-modindex.html b/docs/html/py-modindex.html
new file mode 100644
index 00000000..2812267f
--- /dev/null
+++ b/docs/html/py-modindex.html
@@ -0,0 +1,262 @@
+
+
+
+
+
+
+
+
+
+
+ Python Module Index — Royalnet documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Royalnet
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Docs »
+
+ Python Module Index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Python Module Index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/html/searchindex.js b/docs/html/searchindex.js
index 72d07718..05bdf817 100644
--- a/docs/html/searchindex.js
+++ b/docs/html/searchindex.js
@@ -1 +1 @@
-Search.setIndex({docnames:["audio","bots","commands","database","error","index","network","utils","web"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,sphinx:56},filenames:["audio.rst","bots.rst","commands.rst","database.rst","error.rst","index.rst","network.rst","utils.rst","web.rst"],objects:{},objnames:{},objtypes:{},terms:{audio:5,bot:5,command:5,databas:5,error:5,github:5,index:5,network:5,royalprint:5,tabl:5,util:5,web:5},titles:["royalnet.audio","royalnet.bots","royalnet.commands","royalnet.database","royalnet.error","royalnet","royalnet.network","royalnet.utils","royalnet.web"],titleterms:{audio:0,bot:1,command:2,databas:3,error:4,link:5,network:6,royalnet:[0,1,2,3,4,5,6,7,8],royalprint:8,some:5,tabl:3,useful:5,util:7,web:8}})
\ No newline at end of file
+Search.setIndex({docnames:["audio","bots","commands","database","error","index","network","utils","web"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,sphinx:56},filenames:["audio.rst","bots.rst","commands.rst","database.rst","error.rst","index.rst","network.rst","utils.rst","web.rst"],objects:{"royalnet.audio":{PlayMode:[0,1,1,""],Playlist:[0,1,1,""],Pool:[0,1,1,""],RoyalPCMAudio:[0,1,1,""],RoyalPCMFile:[0,1,1,""],YtdlFile:[0,1,1,""],YtdlInfo:[0,1,1,""]},"royalnet.audio.PlayMode":{"delete":[0,2,1,""],__init__:[0,2,1,""],_generate_generator:[0,2,1,""],add:[0,2,1,""],next:[0,2,1,""],queue_preview:[0,2,1,""],videos_left:[0,2,1,""]},"royalnet.audio.Playlist":{"delete":[0,2,1,""],__init__:[0,2,1,""],_generate_generator:[0,2,1,""],add:[0,2,1,""],queue_preview:[0,2,1,""],videos_left:[0,2,1,""]},"royalnet.audio.Pool":{"delete":[0,2,1,""],__init__:[0,2,1,""],_generate_generator:[0,2,1,""],add:[0,2,1,""],queue_preview:[0,2,1,""],videos_left:[0,2,1,""]},"royalnet.audio.RoyalPCMAudio":{"delete":[0,2,1,""],__init__:[0,2,1,""],create_from_url:[0,2,1,""],create_from_ytsearch:[0,2,1,""],is_opus:[0,2,1,""],read:[0,2,1,""]},"royalnet.audio.RoyalPCMFile":{audio_filename:[0,2,1,""],create_from_url:[0,2,1,""],create_from_ytsearch:[0,2,1,""],delete_audio_file:[0,2,1,""],ytdl_args:[0,3,1,""],ytdl_filename:[0,2,1,""]},"royalnet.audio.YtdlFile":{_stop_download:[0,2,1,""],create_from_url:[0,2,1,""],delete_video_file:[0,2,1,""],ytdl_args:[0,3,1,""]},"royalnet.audio.YtdlInfo":{__init__:[0,2,1,""],create_from_url:[0,2,1,""],download:[0,2,1,""],to_discord_embed:[0,2,1,""]},"royalnet.bots":{DiscordBot:[1,1,1,""],DiscordConfig:[1,1,1,""],GenericBot:[1,1,1,""],TelegramBot:[1,1,1,""],TelegramConfig:[1,1,1,""]},"royalnet.bots.DiscordBot":{_bot_factory:[1,2,1,""],_call_factory:[1,2,1,""],_init_client:[1,2,1,""],_init_voice:[1,2,1,""],add_to_music_data:[1,2,1,""],advance_music_data:[1,2,1,""],interface_name:[1,3,1,""],run:[1,2,1,""],update_activity_with_source_title:[1,2,1,""]},"royalnet.bots.GenericBot":{_call_factory:[1,2,1,""],_init_commands:[1,2,1,""],_init_database:[1,2,1,""],_init_royalnet:[1,2,1,""],_network_handler:[1,2,1,""],call:[1,2,1,""],interface_name:[1,3,1,""],run:[1,2,1,""]},"royalnet.bots.TelegramBot":{_call_factory:[1,2,1,""],_handle_update:[1,2,1,""],_init_client:[1,2,1,""],botfather_command_string:[1,2,1,""],interface_name:[1,3,1,""],run:[1,2,1,""]},"royalnet.commands":{AuthorCommand:[2,1,1,""],CiaoruoziCommand:[2,1,1,""],ColorCommand:[2,1,1,""],CvCommand:[2,1,1,""],DateparserCommand:[2,1,1,""],DiarioCommand:[2,1,1,""],KvCommand:[2,1,1,""],KvactiveCommand:[2,1,1,""],KvrollCommand:[2,1,1,""],MissingCommand:[2,1,1,""],NullCommand:[2,1,1,""],PauseCommand:[2,1,1,""],PingCommand:[2,1,1,""],PlayCommand:[2,1,1,""],PlaymodeCommand:[2,1,1,""],QueueCommand:[2,1,1,""],RageCommand:[2,1,1,""],ReminderCommand:[2,1,1,""],RoyalnetprofileCommand:[2,1,1,""],ShipCommand:[2,1,1,""],SkipCommand:[2,1,1,""],SmecdsCommand:[2,1,1,""],SummonCommand:[2,1,1,""],SyncCommand:[2,1,1,""],VideochannelCommand:[2,1,1,""],VideoinfoCommand:[2,1,1,""]},"royalnet.database":{Alchemy:[3,1,1,""],DatabaseConfig:[3,1,1,""],relationshiplinkchain:[3,4,1,""],tables:[3,0,0,"-"]},"royalnet.database.Alchemy":{__init__:[3,2,1,""],_create_tables:[3,2,1,""],session_acm:[3,2,1,""],session_cm:[3,2,1,""]},"royalnet.database.tables":{ActiveKvGroup:[3,1,1,""],Alias:[3,1,1,""],Diario:[3,1,1,""],Discord:[3,1,1,""],Keygroup:[3,1,1,""],Keyvalue:[3,1,1,""],Royal:[3,1,1,""],Telegram:[3,1,1,""],WikiPage:[3,1,1,""],WikiRevision:[3,1,1,""]},"royalnet.database.tables.ActiveKvGroup":{group:[3,3,1,""],group_name:[3,3,1,""],royal:[3,3,1,""],royal_id:[3,3,1,""]},"royalnet.database.tables.Alias":{alias:[3,3,1,""],royal:[3,3,1,""],royal_id:[3,3,1,""]},"royalnet.database.tables.Diario":{context:[3,3,1,""],creator:[3,3,1,""],creator_id:[3,3,1,""],diario_id:[3,3,1,""],media_url:[3,3,1,""],quoted:[3,3,1,""],quoted_account:[3,3,1,""],quoted_account_id:[3,3,1,""],spoiler:[3,3,1,""],text:[3,3,1,""],timestamp:[3,3,1,""]},"royalnet.database.tables.Discord":{avatar_hash:[3,3,1,""],discord_id:[3,3,1,""],discriminator:[3,3,1,""],full_username:[3,2,1,""],royal:[3,3,1,""],royal_id:[3,3,1,""],username:[3,3,1,""]},"royalnet.database.tables.Keygroup":{group_name:[3,3,1,""]},"royalnet.database.tables.Keyvalue":{group:[3,3,1,""],group_name:[3,3,1,""],key:[3,3,1,""],value:[3,3,1,""]},"royalnet.database.tables.Royal":{avatar:[3,3,1,""],password:[3,3,1,""],role:[3,3,1,""],uid:[3,3,1,""],username:[3,3,1,""]},"royalnet.database.tables.Telegram":{first_name:[3,3,1,""],last_name:[3,3,1,""],mention:[3,2,1,""],royal:[3,3,1,""],royal_id:[3,3,1,""],tg_id:[3,3,1,""],username:[3,3,1,""]},"royalnet.database.tables.WikiPage":{content:[3,3,1,""],css:[3,3,1,""],format:[3,3,1,""],page_id:[3,3,1,""],title:[3,3,1,""]},"royalnet.database.tables.WikiRevision":{author:[3,3,1,""],author_id:[3,3,1,""],diff:[3,3,1,""],page:[3,3,1,""],page_id:[3,3,1,""],reason:[3,3,1,""],revision_id:[3,3,1,""],timestamp:[3,3,1,""]},"royalnet.error":{CurrentlyDisabledError:[4,5,1,""],ExternalError:[4,5,1,""],FileTooBigError:[4,5,1,""],InvalidConfigError:[4,5,1,""],InvalidInputError:[4,5,1,""],NoneFoundError:[4,5,1,""],RoyalnetRequestError:[4,5,1,""],RoyalnetResponseError:[4,5,1,""],TooManyFoundError:[4,5,1,""],UnregisteredError:[4,5,1,""],UnsupportedError:[4,5,1,""]},"royalnet.network":{ConnectionClosedError:[6,5,1,""],NetworkError:[6,5,1,""],NotConnectedError:[6,5,1,""],NotIdentifiedError:[6,5,1,""],Package:[6,1,1,""],Request:[6,1,1,""],Response:[6,1,1,""],ResponseError:[6,1,1,""],ResponseSuccess:[6,1,1,""],RoyalnetConfig:[6,1,1,""],RoyalnetLink:[6,1,1,""],RoyalnetServer:[6,1,1,""]},"royalnet.network.Package":{__init__:[6,2,1,""],from_dict:[6,2,1,""],from_json_bytes:[6,2,1,""],from_json_string:[6,2,1,""],reply:[6,2,1,""],to_dict:[6,2,1,""],to_json_bytes:[6,2,1,""],to_json_string:[6,2,1,""]},"royalnet.network.Request":{from_dict:[6,2,1,""],to_dict:[6,2,1,""]},"royalnet.network.Response":{from_dict:[6,2,1,""],raise_on_error:[6,2,1,""],to_dict:[6,2,1,""]},"royalnet.network.ResponseError":{raise_on_error:[6,2,1,""]},"royalnet.network.ResponseSuccess":{raise_on_error:[6,2,1,""]},"royalnet.network.RoyalnetLink":{connect:[6,2,1,""],identify:[6,2,1,""],receive:[6,2,1,""],request:[6,2,1,""],run:[6,2,1,""],send:[6,2,1,""]},"royalnet.network.RoyalnetServer":{find_client:[6,2,1,""],find_destination:[6,2,1,""],listener:[6,2,1,""],route_package:[6,2,1,""],serve:[6,2,1,""],start:[6,2,1,""]},"royalnet.utils":{Call:[7,1,1,""],Command:[7,1,1,""],CommandArgs:[7,1,1,""],NetworkHandler:[7,1,1,""],andformat:[7,4,1,""],asyncify:[7,4,1,""],cdj:[7,4,1,""],discord_escape:[7,4,1,""],fileformat:[7,4,1,""],numberemojiformat:[7,4,1,""],plusformat:[7,4,1,""],safeformat:[7,4,1,""],sleep_until:[7,4,1,""],telegram_escape:[7,4,1,""],ytdldateformat:[7,4,1,""]},"royalnet.utils.Call":{__init__:[7,2,1,""],_session_init:[7,2,1,""],alchemy:[7,3,1,""],get_author:[7,2,1,""],interface_name:[7,3,1,""],interface_obj:[7,3,1,""],interface_prefix:[7,3,1,""],net_request:[7,2,1,""],reply:[7,2,1,""],run:[7,2,1,""],session_end:[7,2,1,""]},"royalnet.utils.Command":{command_description:[7,3,1,""],command_name:[7,3,1,""],command_syntax:[7,3,1,""],common:[7,2,1,""],network_handler_dict:[7,2,1,""],network_handlers:[7,3,1,""],require_alchemy_tables:[7,3,1,""]},"royalnet.utils.CommandArgs":{__getitem__:[7,2,1,""],joined:[7,2,1,""],match:[7,2,1,""],optional:[7,2,1,""]},"royalnet.utils.NetworkHandler":{message_type:[7,3,1,""]},"royalnet.web":{Royalprint:[8,1,1,""],create_app:[8,4,1,""],royalprints:[8,0,0,"-"]},royalnet:{audio:[0,0,0,"-"],bots:[1,0,0,"-"],commands:[2,0,0,"-"],database:[3,0,0,"-"],error:[4,0,0,"-"],network:[6,0,0,"-"],utils:[7,0,0,"-"],web:[8,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"],"4":["py","function","Python function"],"5":["py","exception","Python exception"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute","4":"py:function","5":"py:exception"},terms:{"0x7fafa01e6448":3,"0x7fafa01e64c8":3,"0x7fafa01e6648":3,"0x7fafa01e6b48":3,"0x7fafa01e6bc8":3,"0x7fafa024a8c8":3,"0x7fafa024abc8":3,"0x7fafa024acc8":3,"0x7fafa024ad48":3,"20m":0,"abstract":7,"boolean":3,"byte":[0,6],"class":[0,1,2,3,6,7,8],"default":[3,7],"final":7,"float":0,"function":[0,4,7],"int":[0,6,7],"new":[0,1,2,3,7],"null":[1,6],"return":[0,1,4,6,7,8],"static":[0,6],"true":[0,3,7],"try":[0,1,7],"while":[0,1,3,4,7],For:7,Not:0,That:7,The:[0,1,3,4,6,7,8],Then:1,These:2,Use:[3,8],__dict__:7,__doc__:7,__getitem__:7,__init__:[0,3,6,7],__module__:7,__slots__:7,__weakref__:7,_bot_factori:1,_call_factori:1,_create_t:3,_generate_gener:0,_handle_upd:1,_init_cli:1,_init_command:1,_init_databas:1,_init_royalnet:1,_init_voic:1,_network_handl:1,_session_init:7,_stop_download:0,abl:7,about:6,abstracteventloop:[1,6,7],access:7,accord:0,accur:7,activekvgroup:3,add:[0,1,7],add_to_music_data:1,added:7,adding:7,addit:[6,7,8],address:6,advanc:0,advance_music_data:1,akin:6,alchemi:[1,3,7],alia:3,all:[0,6,7],allow:3,also:[0,6,8],altern:6,alwai:[0,1],amount:[0,7],andformat:7,ani:[0,7],anoth:[1,6],anymor:6,anystr:7,app:8,applic:8,arg:[6,7],argument:[0,7],around:[0,3],arrai:7,as_uuid:3,associ:7,async:[0,1,3,6,7],asyncifi:7,asyncio:[1,6,7],asyncron:3,attempt:7,attribut:7,audio:[1,5],audio_filenam:0,audio_sourc:1,audiosourc:0,author:[3,7],author_id:3,authorcommand:2,autocomplet:7,avail:4,avatar:3,avatar_hash:3,base:[0,1,6,7],been:[0,4],being:[4,7],bestaudio:0,between:7,big:4,biginteg:3,block:[1,7],blockingli:6,blueprint:8,bot:[0,2,3,4,5,7],botfath:1,botfather_command_str:1,both:3,call:[1,7],callabl:7,can:[0,2,4,6,7,8],cancel:7,cannot:[4,7],caution:8,cdj:7,chain:1,chang:[0,1],change_pres:1,channel:[1,7],charact:7,chat:1,check:[0,3],ciaoruozicommand:2,class_:7,classmethod:[6,7],client:1,close:[6,7],clue:[0,8],code:[7,8],colorcommand:2,column:3,columndefault:3,command:[0,1,4,5,7],command_arg:7,command_descript:7,command_nam:[1,7],command_prefix:1,command_syntax:7,commandarg:7,common:7,commun:[2,6],complet:[0,4],compon:[3,4],config:8,config_obj:8,configur:[1,3,4],connect:[1,6,7,8],connectedcli:6,connectionclosederror:6,contain:[0,4,6,8],content:3,context:3,convers:6,convert:[0,6,7],core:3,coroutin:[1,7],correctli:4,correspond:[0,1],creat:[0,1,3,6,7,8],create_app:8,create_from_url:0,create_from_ytsearch:0,creator:3,creator_id:3,css:3,current:[1,7],currentlydisablederror:4,custom:[0,1],cvcommand:2,dai:7,data:[0,6,7],databas:[1,5,7,8],database_config:1,database_uri:3,databaseconfig:[1,3],date:7,dateparsercommand:2,datetim:[3,7],db_path:8,declar:[3,7],delet:0,delete_audio_fil:0,delete_video_fil:0,describ:3,descript:[6,7],destin:[6,7],destination_conv_id:6,detail:3,develop:2,diario:3,diario_id:3,diariocommand:2,dict:[0,1,6,7],dictionari:[1,6],diff:3,disabl:4,discord:[0,1,3,7],discord_config:1,discord_escap:7,discord_id:3,discordbot:1,discordcli:1,discordconfig:1,discrimin:3,displai:[0,7],doc:3,document:0,doe:[0,7,8],doesn:[1,7],don:7,done:0,download:[0,4],dure:1,dynam:7,each:0,eas:7,edit:[1,8],either:[0,7],element:[4,7],emb:0,empti:[0,1],encod:[0,6],end:3,ending_class:3,engin:3,ensur:7,envvar:8,error:[5,6,7],error_command:1,error_data:6,error_if_non:7,escap:7,even:[7,8],event:[1,6,7],everi:[0,6],everyth:7,exampl:[0,7],except:[0,1,4,6],execut:[1,4,6,7],exist:[0,1,7],expect:4,ext:0,externalerror:4,extra:0,extra_info:6,extract:0,extract_info:0,factori:0,fals:[0,3,7],featur:4,file:[0,1,4],fileformat:7,filenam:[0,7],filetoobigerror:4,find:[1,3,6,7],find_client:6,find_destin:6,first:0,first_nam:3,flask:8,follow:3,foreignkei:3,format:[0,1,3,7],found:[4,7],from:[0,1,3,6,7,8],from_dict:6,from_json_byt:6,from_json_str:6,from_object:8,full_usernam:3,fullfil:7,game:2,gener:[0,1,7],genericbot:[1,3],get:[0,3,7,8],get_author:7,github:5,going:0,greater:7,group:[3,7],group_nam:3,guild:1,handl:[1,4],handler:6,has:[0,4,6,7],have:[0,1,7,8],here:0,how:8,html:3,http:3,identifi:[6,7],identity_column_nam:3,identity_t:[1,3],ifi:7,ignor:7,import_nam:8,incom:1,index:[5,7],inf:[0,6],infinit:0,info:[0,6],inherit:[0,1,6,7],initi:[0,1,8],input:[4,7],insid:0,instanc:1,instead:[0,7],integ:3,interfac:[1,4,7],interface_nam:[1,7],interface_obj:7,interface_prefix:7,interruptdownload:0,invalid:[4,6],invalidconfigerror:4,invalidinputerror:[4,7],is_opu:0,isn:0,item:[0,7],join:7,json:6,jsonabl:6,just:1,keep:0,kei:[3,7,8],keygroup:3,keyvalu:3,keyword:7,kvactivecommand:2,kvcommand:2,kvrollcommand:2,kwarg:[1,7],largebinari:3,last:7,last_nam:3,least:0,left:0,less:7,like:0,link:[1,4,6],link_typ:6,list:[0,1,6,7,8],listen:[1,6],locat:0,logger:0,login:1,look:4,loop:[1,6,7],made:7,mai:[0,2,7],main:7,mainli:0,maintain:3,make:1,manag:3,markdown:3,markup:7,master_secret:6,master_t:[1,3],master_uri:6,match:[1,4,7],math:0,mean:7,media_url:3,memori:0,mention:3,messag:[1,6,7],message_typ:7,method:3,middl:7,minimum:7,miscellan:7,miss:7,missing_command:1,missingcommand:2,month:7,more:[1,3],multipl:[1,3,4],music_data:1,must:[6,7],name:[0,1,6,7,8],need:[1,2],net_request:7,network:[1,4,5,7],network_handl:[1,7],network_handler_dict:7,networkerror:6,networkhandl:7,next:[0,1],nid:6,no_warn:0,nobodi:6,node:[6,7],non:[0,4,7],none:[0,1,3,6,7,8],nonefounderror:4,noplaylist:0,notat:7,notconnectederror:6,noth:[6,7],notidentifiederror:6,notimpl:[1,7],notimplementederror:0,now:4,now_plai:0,nullabl:3,nullcommand:[1,2],number:[0,6],numberemojiformat:7,object:[0,1,3,7,8],offset:1,onc:[0,3],one:4,ones:[1,2],onli:[4,7],option:[0,1,3,6,7,8],optional_arg:7,opu:0,order:0,org:3,other:[0,1,4,6,7],otherwis:[1,6,7],output:7,outtmpl:0,packag:6,packet:6,page:3,page_id:3,paramet:[0,1,3,6,7,8],pass:[0,7,8],password:3,past:1,path:[3,6],pattern:7,pausecommand:2,pcm:0,perman:0,pickl:7,pingcommand:2,plai:[0,1],playcommand:2,playlist:0,playmod:0,playmodecommand:2,plusformat:7,pool:0,port:6,possibl:[0,7],postgresql:3,prefix:7,prepar:6,prepend:7,presenc:1,preview:0,previous:7,primary_kei:3,probabl:[0,2,7],prompt:1,properti:[0,1,3],queue:0,queue_preview:0,queuecommand:2,quiet:0,quot:3,quoted_account:3,quoted_account_id:3,ragecommand:2,rais:[0,1,4,6,7],raise_on_error:6,random:0,read:0,real:6,realli:8,reason:3,receiv:[1,4,6,7],reciev:6,recommend:0,recreat:6,regex:7,regist:[4,8],relat:[0,3,6],relationshiplinkchain:3,relationshipproperti:3,remindercommand:2,remov:0,repeat:0,replac:7,repli:[6,7],repres:1,request:[1,4,6,7],request_dict:1,request_handl:6,requir:[1,3,4,7,8],require_alchemy_t:7,require_at_least:7,required_arg:7,required_secret:6,required_t:8,respons:[1,4,6],responseerror:[4,6],responsesuccess:6,result:7,retriev:7,revis:3,revision_id:3,right:4,role:3,root_path:8,rout:6,route_packag:6,row:7,royal:[2,3],royal_id:3,royalcod:7,royalnet_config:1,royalnetconfig:[1,6],royalnetlink:[1,6,7],royalnetprofilecommand:2,royalnetrequesterror:4,royalnetresponseerror:4,royalnetserv:6,royalpcmaudio:[0,1],royalpcmfil:0,royalprint:5,rpf:0,run:[1,6,7],safeformat:7,search:0,second:7,secret:6,secret_kei:8,select:[0,3],self:[0,1,6],send:[6,7],sent:[6,7],separ:7,sequenc:[6,7],serv:6,server:[6,8],session:7,session_acm:3,session_cm:3,session_end:7,set:[1,3,7,8],shipcommand:2,should:[1,6,7],signal:0,singl:[1,3],skip:4,skipcommand:2,sleep_until:7,small:7,smecdscommand:2,some:[0,8],someth:[4,7],somewher:6,song:[0,1],soon:0,sourc:6,source_conv_id:6,space:7,specif:[1,7],specifi:[0,1,4,7],spoiler:3,sqlalchemi:[3,7],start:[1,3,6],starting_class:3,starting_list:0,starting_pool:0,statement:3,static_fold:8,static_url_path:8,statu:1,store:4,str:[0,1,3,6,7],string:[0,1,3,6,7],stuff:0,sub:7,subdomain:8,submodul:3,success:6,suit:2,summoncommand:2,support:4,synccommand:2,syntax:7,tabl:[1,5,7],tailor:2,task:1,telegram:[1,3,7],telegram_config:1,telegram_escap:7,telegrambot:[1,7],telegramcal:1,telegramconfig:1,template_fold:8,temporar:4,text:[3,7],tg_id:3,than:7,thei:2,them:3,therefor:4,thi:[0,4,6,7,8],those:0,through:7,time:6,timestamp:3,titl:[0,3],to_dict:6,to_discord_emb:0,to_json_byt:6,to_json_str:6,token:1,too:4,toomanyfounderror:4,tupl:3,two:7,type:[1,3,6,7,8],uhhh:0,uid:3,underscor:7,undescrib:7,unexpect:7,unexpectedli:6,union:0,univers:7,unregisterederror:[4,7],unsupportederror:4,until:[0,7],updat:1,update_activity_with_source_titl:1,uri:3,url:0,url_default:8,url_prefix:8,use:[0,3],used:[0,1,2,3,6,7,8],useful:[0,2,7],user:[4,7],usernam:3,using:[1,7],usual:[0,6],utf8:6,util:[1,5],uuid:[3,7],valid:7,valu:[0,3,6,7],variabl:1,variou:1,veri:0,video:0,video_filenam:0,videochannelcommand:2,videoinfocommand:2,videos_left:0,voic:[0,1],wai:0,wait:7,want:[0,7],warn:0,web:5,websocket:6,websocketserverprotocol:6,weird:[0,7],went:4,were:4,what:0,when:[0,7],where:7,which:[0,6,7],why:[0,8],wiki:3,wikipag:3,wikirevis:3,without:7,won:2,word:7,work:[7,8],worth:0,would:4,wrapper:[0,3],written:8,wrong:4,year:7,yet:6,yield:0,you:[0,7],your:2,youtub:[0,7],youtube_dl:0,youtubedl:0,ytdl_arg:0,ytdl_filenam:0,ytdldateformat:7,ytdlfile:0,ytdlinfo:0,yyyi:7,yyyymmdd:7},titles:["royalnet.audio","royalnet.bots","royalnet.commands","royalnet.database","royalnet.error","royalnet","royalnet.network","royalnet.utils","royalnet.web"],titleterms:{audio:0,bot:1,command:2,databas:3,error:4,link:5,network:6,royalnet:[0,1,2,3,4,5,6,7,8],royalprint:8,some:5,tabl:3,useful:5,util:7,web:8}})
\ No newline at end of file
diff --git a/docs/html/utils.html b/docs/html/utils.html
index bafe00f8..baf7a7c7 100644
--- a/docs/html/utils.html
+++ b/docs/html/utils.html
@@ -159,6 +159,438 @@
royalnet.utils
+Miscellaneous useful functions and classes.
+
+
+async royalnet.utils.
asyncify
( function: Callable , *args , **kwargs )
+Convert a function into a coroutine.
+
+
Warning
+
The coroutine cannot be cancelled, and any attempts to do so will result in unexpected outputs.
+
+
+
+
+
+class royalnet.utils.
Call
( channel, command: Type[royalnet.utils.command.Command], command_args: List[str] = None, loop: asyncio.events.AbstractEventLoop = None, **kwargs )
+A command call. An abstract class, sub-bots should create a new call class from this.
+
+
+interface_name
+The name of the interface that is calling the command. For example, telegram
, or discord
.
+
+
+
+
+interface_obj
+The main object of the interface that is calling the command. For example, the royalnet.bots.TelegramBot
object.
+
+
+
+
+interface_prefix
+The command prefix used by the interface. For example, /
, or !
.
+
+
+
+
+alchemy
+The royalnet.database.Alchemy
object associated to this interface. May be None if the interface is not connected to any database.
+
+
+
+
+__init__
( channel, command: Type[royalnet.utils.command.Command], command_args: List[str] = None, loop: asyncio.events.AbstractEventLoop = None, **kwargs )
+Create the call.
+
+Parameters
+
+channel – The channel object this call was sent in.
+command – The command to be called.
+command_args – The arguments to be passed to the command
+kwargs – Additional optional keyword arguments that may be passed to the command, possibly specific to the bot.
+
+
+
+
+
+
+
+async _session_init
( )
+If the command requires database access, create a royalnet.database.Alchemy
session for this call, otherwise, do nothing.
+
+
+
+
+alchemy
= NotImplemented
+
+
+
+
+async get_author
( error_if_none=False )
+Try to find the universal identifier of the user that sent the message.
+That probably means, the database row identifying the user.
+
+Parameters
+error_if_none – Raise a royalnet.error.UnregisteredError
if this is True and the call has no author.
+
+Raises
+royalnet.error.UnregisteredError –
+
+
+
+
+
+
+interface_name
= NotImplemented
+
+
+
+
+interface_obj
= NotImplemented
+
+
+
+
+interface_prefix
= NotImplemented
+
+
+
+
+async net_request
( message , destination: str ) → dict
+Send data through a royalnet.network.RoyalnetLink
and wait for a royalnet.network.Reply
.
+
+Parameters
+
+message – The data to be sent. Must be pickle
-able.
+destination – The destination of the request, either in UUID format or node name.
+
+
+
+
+
+
+
+async reply
( text: str ) → None
+Send a text message to the channel where the call was made.
+
+Parameters
+text – The text to be sent, possibly formatted in the weird undescribed markup that I’m using.
+
+
+
+
+
+
+async run
( )
+Execute the called command, and return the command result.
+
+
+
+
+async session_end
( )
+Close the previously created royalnet.database.Alchemy
session for this call (if it was created).
+
+
+
+
+
+
+class royalnet.utils.
Command
+The base class from which all commands should inherit.
+
+
+command_name
+The name of the command. To have /example
on Telegram, the name should be example
.
+
+
+
+
+command_description
+A small description of the command, to be displayed when the command is being autocompleted.
+
+
+
+
+command_syntax
+The syntax of the command, to be displayed when a royalnet.error.InvalidInputError
is raised, in the format (required_arg) [optional_arg]
.
+
+
+
+
+require_alchemy_tables
+A set of royalnet.database
tables, that must exist for this command to work.
+
+
+
+
+network_handlers
+A list of :py:class:` royalnet.utils.NetworkHandler`s that must exist for this command to work.
+
+
+
+
+command_description
= NotImplemented
+
+
+
+
+command_name
= NotImplemented
+
+
+
+
+command_syntax
= NotImplemented
+
+
+
+
+classmethod common
( call: Call )
+
+
+
+
+classmethod network_handler_dict
( )
+
+
+
+
+network_handlers
= {}
+
+
+
+
+require_alchemy_tables
= {}
+
+
+
+
+
+
+royalnet.utils.
safeformat
( string: str , **words ) → str
+str.format()
something, but ignore missing keys instead of raising an error.
+
+Parameters
+
+
+Returns
+The formatted string.
+
+
+
+
+
+
+royalnet.utils.
cdj
( class_: Any ) → dict
+Return a dict of the class attributes without the __module__
, __dict__
, __weakref__
and __doc__
keys, to be used while generating dynamically SQLAlchemy declarative table classes.
+
+Parameters
+class_ – The object that you want to dict-ify.
+
+Returns
+The class dict.
+
+
+
+
Warning
+
You can’t dict-ify classes with __slots__
!
+
+
+
+
+
+async royalnet.utils.
sleep_until
( dt: datetime.datetime ) → None
+Block the call until the specified datetime.
+
+
Warning
+
Accurate only to seconds.
+
+
+
+
+
+royalnet.utils.
plusformat
( i: int ) → str
+Convert an int
to a str
, prepending a +
if it’s greater than 0.
+
+Parameters
+i – the int
to convert.
+
+Returns
+The resulting str
.
+
+
+
+
+
+
+class royalnet.utils.
CommandArgs
+An interface to access the arguments of a command with ease.
+
+
+__getitem__
( item )
+Arguments can be accessed with an array notation, such as args[0]
.
+
+Raises
+royalnet.error.InvalidInputError – if the requested argument does not exist.
+
+
+
+
+
+
+joined
( * , require_at_least=0 ) → str
+Get the arguments as a space-joined string.
+
+Parameters
+require_at_least – the minimum amount of arguments required, will raise royalnet.error.InvalidInputError
if the requirement is not fullfilled.
+
+Raises
+royalnet.error.InvalidInputError – if there are less than require_at_least
arguments.
+
+Returns
+The space-joined string.
+
+
+
+
+
+
+match
( pattern: Pattern ) → Sequence[AnyStr]
+Match the royalnet.utils.commandargs.joined()
to a regex pattern.
+
+Parameters
+pattern – The regex pattern to be passed to re.match()
.
+
+Raises
+royalnet.error.InvalidInputError – if the pattern doesn’t match.
+
+Returns
+The matched groups, as returned by re.Match.groups()
.
+
+
+
+
+
+
+optional
( index: int , default=None )
+Get the argument at a specific index, but don’t raise an error if nothing is found, instead returning the default
value.
+
+Parameters
+
+
+Returns
+Either the argument or the default
value, defaulting to None
.
+
+
+
+
+
+
+
+
+class royalnet.utils.
NetworkHandler
+The NetworkHandler functions are called when a specific Message type is received.
+
+
+message_type
= NotImplemented
+
+
+
+
+
+
+royalnet.utils.
andformat
( l: List[str], middle=', ', final=' and ' ) → str
+Convert a list
to a str
by adding final
between the last two elements and middle
between the others.
+
+Parameters
+
+
+Returns
+The resulting str
.
+
+
+
+
+
+
+royalnet.utils.
plusformat
( i: int ) → str
+Convert an int
to a str
, prepending a +
if it’s greater than 0.
+
+Parameters
+i – the int
to convert.
+
+Returns
+The resulting str
.
+
+
+
+
+
+
+royalnet.utils.
fileformat
( string: str ) → str
+Ensure a string can be used as a filename by replacing all non-word characters with underscores.
+
+Parameters
+string – the input string.
+
+Returns
+A valid filename string.
+
+
+
+
+
+
+royalnet.utils.
ytdldateformat
( string: Optional[str], separator: str = '-' ) → str
+Convert the weird date string returned by youtube-dl
into the YYYY-MM-DD
format.
+
+Parameters
+
+string – the input string, in the YYYYMMDD
format.
+separator – the string to add between the years, the months and the days. Defaults to -
.
+
+
+Returns
+The resulting string, in the format YYYY-MM-DD
format.
+
+
+
+
+
+
+royalnet.utils.
numberemojiformat
( l: List[str] ) → str
+
+
+
+
+royalnet.utils.
telegram_escape
( string: str ) → str
+Escape a string to be sent through Telegram, and format it using RoyalCode.
+
+
Warning
+
Currently escapes everything, even items in code blocks.
+
+
+
+
+
+royalnet.utils.
discord_escape
( string: str ) → str
+Escape a string to be sent through Discord, and format it using RoyalCode.
+
+
Warning
+
Currently escapes everything, even items in code blocks.
+
+
+
diff --git a/docs/html/web.html b/docs/html/web.html
index c40a72ac..bc2fa1d2 100644
--- a/docs/html/web.html
+++ b/docs/html/web.html
@@ -88,7 +88,7 @@
royalnet.utils
royalnet.error
royalnet.web
@@ -159,8 +159,39 @@
royalnet.web
-
-
Royalprints
+
+
+royalnet.web.
create_app
( config_obj: Type, blueprints: List[royalnet.web.royalprint.Royalprint] )
+Create a flask.Flask
application object.
+Gets the app.secret_key
from the SECRET_KEY
envvar.
+Also requires a DB_PATH
key in config_obj
to initialize the database connection.
+
+
Warning
+
The code for this class was written at 1 AM, and I have no clue of how and why it works or even of if it really does work.
+Use with caution?
+
+
+Parameters
+
+
+Returns
+The created flask.Flask
.
+
+
+
+
+
+
+class royalnet.web.
Royalprint
( name , import_name , static_folder=None , static_url_path=None , template_folder=None , url_prefix=None , subdomain=None , url_defaults=None , root_path=None , required_tables: Optional[set] = None )
+An edited flask.Blueprint
containing an additional required_tables
parameter.
+
+
+
+
Royalprints
+
Some Royalprints that can be used with the Royalnet Flask server.