-
-
group
= <RelationshipProperty at 0x7a5f978; no key>
+group
= <RelationshipProperty at 0x7f81333173c8; no key>
@@ -446,7 +446,7 @@
-
-
royal
= <RelationshipProperty at 0x7a5fae0; no key>
+royal
= <RelationshipProperty at 0x7f8133317948; no key>
diff --git a/docs/html/genindex.html b/docs/html/genindex.html
index ed14650c..7fe725cd 100644
--- a/docs/html/genindex.html
+++ b/docs/html/genindex.html
@@ -267,7 +267,7 @@
Alchemy (class in royalnet.database)
- alchemy (royalnet.utils.Call attribute)
+ alchemy (royalnet.utils.Call attribute), [1]
|
- - interface_obj (royalnet.utils.Call attribute)
+
- interface_obj (royalnet.utils.Call attribute), [1]
- - interface_prefix (royalnet.utils.Call attribute)
+
- interface_prefix (royalnet.utils.Call attribute), [1]
- InvalidConfigError
@@ -559,7 +559,7 @@
- network_handler_dict() (royalnet.utils.Command class method)
- - network_handlers (royalnet.utils.Command attribute)
+
- network_handlers (royalnet.utils.Command attribute), [1]
- NetworkError
@@ -659,7 +659,7 @@
- request() (royalnet.network.RoyalnetLink method)
- - require_alchemy_tables (royalnet.utils.Command attribute)
+
- require_alchemy_tables (royalnet.utils.Command attribute), [1]
- Response (class in royalnet.network)
@@ -801,6 +801,8 @@
- (royalnet.network.Response method)
+ to_discord_embed() (royalnet.audio.YtdlInfo method)
+
to_json_bytes() (royalnet.network.Package method)
to_json_string() (royalnet.network.Package method)
@@ -865,9 +867,11 @@
(royalnet.audio.YtdlFile attribute)
+ ytdl_filename (royalnet.audio.RoyalPCMFile attribute)
+
|
- - ytdl_filename (royalnet.audio.RoyalPCMFile attribute)
+
- ytdldateformat() (in module royalnet.utils)
- YtdlFile (class in royalnet.audio)
diff --git a/docs/html/network.html b/docs/html/network.html
index d043df08..ef989940 100644
--- a/docs/html/network.html
+++ b/docs/html/network.html
@@ -158,10 +158,10 @@
royalnet.network
-Royalnet realated classes.
+Royalnet (websocket) related classes.
-
-class
royalnet.network. RoyalnetLink (master_uri: str, secret: str, link_type: str, request_handler, *, loop: asyncio.events.AbstractEventLoop = <_WindowsSelectorEventLoop running=False closed=False debug=False>)
+class royalnet.network. RoyalnetLink (master_uri: str, secret: str, link_type: str, request_handler, *, loop: asyncio.events.AbstractEventLoop = <_UnixSelectorEventLoop running=False closed=False debug=False>)
-
connect ()
@@ -295,7 +295,7 @@ Contains info about the source and the destination.
-
-class
royalnet.network. RoyalnetServer (address: str, port: int, required_secret: str, *, loop: asyncio.events.AbstractEventLoop = <_WindowsSelectorEventLoop running=False closed=False debug=False>)
+class royalnet.network. RoyalnetServer (address: str, port: int, required_secret: str, *, loop: asyncio.events.AbstractEventLoop = <_UnixSelectorEventLoop running=False closed=False debug=False>)
-
find_client (*, nid: str = None, link_type: str = None) → List[royalnet.network.royalnetserver.ConnectedClient]
diff --git a/docs/html/objects.inv b/docs/html/objects.inv
index 47f0b6ae..a85d3b11 100644
Binary files a/docs/html/objects.inv and b/docs/html/objects.inv differ
diff --git a/docs/html/searchindex.js b/docs/html/searchindex.js
index c86e25eb..25ed4af2 100644
--- a/docs/html/searchindex.js
+++ b/docs/html/searchindex.js
@@ -1 +1 @@
-Search.setIndex({docnames:["audio","bots","commands","database","error","index","network","utils"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":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"],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,""],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,""],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,""],videos_left:[0,2,1,""]},"royalnet.audio.RoyalPCMAudio":{"delete":[0,2,1,""],__init__:[0,2,1,""],create_from_url:[0,3,1,""],create_from_ytsearch:[0,3,1,""],is_opus:[0,2,1,""],read:[0,2,1,""]},"royalnet.audio.RoyalPCMFile":{audio_filename:[0,4,1,""],create_from_url:[0,3,1,""],create_from_ytsearch:[0,3,1,""],delete_audio_file:[0,2,1,""],ytdl_args:[0,4,1,""],ytdl_filename:[0,4,1,""]},"royalnet.audio.YtdlFile":{_stop_download:[0,2,1,""],create_from_url:[0,3,1,""],delete_video_file:[0,2,1,""],ytdl_args:[0,4,1,""]},"royalnet.audio.YtdlInfo":{__init__:[0,2,1,""],create_from_url:[0,3,1,""],download:[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,4,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,4,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,4,1,""],interface_name:[1,4,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,""],PingCommand:[2,1,1,""],PlayCommand:[2,1,1,""],PlaymodeCommand:[2,1,1,""],RageCommand:[2,1,1,""],ReminderCommand:[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,5,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,""]},"royalnet.database.tables.ActiveKvGroup":{group:[3,4,1,""],group_name:[3,4,1,""],royal:[3,4,1,""],royal_id:[3,4,1,""]},"royalnet.database.tables.Alias":{alias:[3,4,1,""],royal:[3,4,1,""],royal_id:[3,4,1,""]},"royalnet.database.tables.Diario":{context:[3,4,1,""],creator:[3,4,1,""],creator_id:[3,4,1,""],diario_id:[3,4,1,""],media_url:[3,4,1,""],quoted:[3,4,1,""],quoted_account:[3,4,1,""],quoted_account_id:[3,4,1,""],spoiler:[3,4,1,""],text:[3,4,1,""],timestamp:[3,4,1,""]},"royalnet.database.tables.Discord":{avatar_hash:[3,4,1,""],discord_id:[3,4,1,""],discriminator:[3,4,1,""],full_username:[3,2,1,""],royal:[3,4,1,""],royal_id:[3,4,1,""],username:[3,4,1,""]},"royalnet.database.tables.Keygroup":{group_name:[3,4,1,""]},"royalnet.database.tables.Keyvalue":{group:[3,4,1,""],group_name:[3,4,1,""],key:[3,4,1,""],value:[3,4,1,""]},"royalnet.database.tables.Royal":{avatar:[3,4,1,""],password:[3,4,1,""],role:[3,4,1,""],uid:[3,4,1,""],username:[3,4,1,""]},"royalnet.database.tables.Telegram":{first_name:[3,4,1,""],last_name:[3,4,1,""],mention:[3,2,1,""],royal:[3,4,1,""],royal_id:[3,4,1,""],tg_id:[3,4,1,""],username:[3,4,1,""]},"royalnet.error":{ExternalError:[4,6,1,""],InvalidConfigError:[4,6,1,""],InvalidInputError:[4,6,1,""],NoneFoundError:[4,6,1,""],RoyalnetRequestError:[4,6,1,""],RoyalnetResponseError:[4,6,1,""],TooManyFoundError:[4,6,1,""],UnregisteredError:[4,6,1,""],UnsupportedError:[4,6,1,""]},"royalnet.network":{ConnectionClosedError:[6,6,1,""],NetworkError:[6,6,1,""],NotConnectedError:[6,6,1,""],NotIdentifiedError:[6,6,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,3,1,""],from_json_bytes:[6,3,1,""],from_json_string:[6,3,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,3,1,""],to_dict:[6,2,1,""]},"royalnet.network.Response":{from_dict:[6,7,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,5,1,""],asyncify:[7,5,1,""],cdj:[7,5,1,""],fileformat:[7,5,1,""],plusformat:[7,5,1,""],safeformat:[7,5,1,""],sleep_until:[7,5,1,""]},"royalnet.utils.Call":{__init__:[7,2,1,""],_session_init:[7,2,1,""],alchemy:[7,4,1,""],get_author:[7,2,1,""],interface_name:[7,4,1,""],interface_obj:[7,4,1,""],interface_prefix:[7,4,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,4,1,""],command_name:[7,4,1,""],command_syntax:[7,4,1,""],common:[7,7,1,""],network_handler_dict:[7,7,1,""],network_handlers:[7,4,1,""],require_alchemy_tables:[7,4,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,4,1,""]},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,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","staticmethod","Python static method"],"4":["py","attribute","Python attribute"],"5":["py","function","Python function"],"6":["py","exception","Python exception"],"7":["py","classmethod","Python class method"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:staticmethod","4":"py:attribute","5":"py:function","6":"py:exception","7":"py:classmethod"},terms:{"0x7a5f150":3,"0x7a5f588":3,"0x7a5f738":3,"0x7a5f978":3,"0x7a5fa98":3,"0x7a5fae0":3,"0x7a5fc48":3,"20m":0,"48khz":0,"abstract":7,"boolean":3,"byte":[0,6],"class":[0,1,2,3,6,7],"default":[0,3,7],"final":7,"float":0,"function":[0,4,7],"int":[0,6,7],"new":[0,1,3,7],"null":[1,6],"return":[0,1,4,6,7],"static":[0,6],"true":[0,3,7],"try":[1,7],"while":[0,1,3,4,7],Not:0,That:7,The:[0,1,3,4,6,7],Then:1,These:2,Use:3,__dict__:7,__doc__:7,__getitem__:7,__init__:[0,3,6,7],__module__: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,_windowsselectoreventloop:6,abl:7,about:[0,6],abstracteventloop:6,access:7,accur:7,activekvgroup:3,add:[0,1],add_to_music_data:1,added:7,adding:7,addit:[6,7],address:6,advanc:0,advance_music_data:1,akin:6,alchemi:[1,3,7],alia:3,all:[0,6,7],allow:3,alreadi:0,also:[0,6],altern:6,alwai:1,amount:[0,7],andformat:7,ani:[0,7],anoth:[1,6],anymor:6,anystr:7,arg:[6,7],argument:[0,7],around:[0,3],arrai:7,async:[0,3],asyncifi:7,asyncio:[1,6],asyncron:3,attempt:7,attribut:7,audio:[1,5],audio_filenam:0,audio_sourc:1,audiosourc:0,author:7,authorcommand:2,avatar:3,avatar_hash:3,base:[0,1,6,7],been:[0,4],being:4,bestaudio:0,between:7,biginteg:3,bit:0,block:[1,7],blockingli:6,bot:[0,2,3,4,5,7],botfather_command_str:1,both:3,call:[1,7],callabl:7,can:[2,4,6,7],cancel:7,cannot:[4,7],cdj:7,chain:1,chang:[0,1],change_pres:1,channel:[1,7],charact:7,chat:1,check:[0,2,3],ciaoruozicommand:2,class_:7,classmethod:[6,7],client:1,close:[6,7],colorcommand:2,column:3,columndefault:3,command:[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],compat:0,complet:[0,4],compon:[3,4],configur:[1,3,4],connect:[1,6],connectedcli:6,connectionclosederror:6,contain:[0,4,6],context:3,convers:6,convert:[0,6,7],core:3,coroutin:[1,7],correctli:4,correspond:[0,1],creat:[0,1,3,6,7],create_from_url:0,create_from_ytsearch:0,creator:3,creator_id:3,ct_co:3,current:1,custom:[0,1],cvcommand:2,data:[0,6,7],databas:[1,5,7],database_config:1,database_uri:3,databaseconfig:[1,3],dateparsercommand:2,datetim:[3,7],debug:6,declar:[3,7],delet:0,delete_audio_fil:0,delete_video_fil:0,describ:3,descript:6,destin:[6,7],destination_conv_id:6,detail:3,diario:3,diario_id:3,diariocommand:2,dict:[0,1,6,7],dictionari:[1,6],discord:[0,1,3],discord_config:1,discord_id:3,discordbot:1,discordcli:1,discordconfig:1,discrimin:3,doc:3,doe:0,doesn:1,don:7,download:0,dure:1,dynam:7,each:0,either:[0,7],element:[4,7],empti:[0,1],encod:[0,6],end:3,ending_class:3,engin:3,ensur:7,error:[5,6,7],error_command:1,error_data:6,error_if_non:7,event:6,everi:[0,6],except:[1,4,6],execut:[1,4,6,7],exist:1,expect:4,ext:0,externalerror:4,extra:0,extra_info:6,extract:0,extract_info:0,factori:0,fals:[0,3,6,7],file:[0,1],fileformat:7,filenam:7,find:[1,3,6,7],find_client:6,find_destin:6,first:0,first_nam:3,follow:3,foreignkei:3,format:[0,1,7],found:[4,7],frame:0,from:[0,1,3,6,7],from_dict:6,from_json_byt:6,from_json_str:6,full_usernam:3,fullfil:7,game:2,gener:[0,1,7],genericbot:[1,3],get:[0,3,7],get_author:7,going:0,greater:7,group:[3,7],group_nam:3,guild:1,handl:[1,4],handler:6,has:[0,4,6,7],have:1,html:3,http:3,identifi:[6,7],identity_column_nam:3,identity_t:[1,3],ignor:7,implement:0,incom:1,index:[5,7],inf:[0,6],infinit:0,info:[0,6],inherit:[0,1,6],initi:[0,1],input:[4,7],insid:0,instanc:1,instead:[0,7],integ:3,interfac:[1,4],interface_nam:[1,7],interface_obj:7,interface_prefix:7,invalid:[4,6],invalidconfigerror:4,invalidinputerror:[4,7],is_opu:0,item:[0,7],join:7,json:6,jsonabl:6,just:1,keep:0,kei:[3,7],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,like:0,link:[1,4,6],link_typ:6,list:[0,1,6,7],listen:[1,6],logger:0,login:1,look:4,loop:6,made:7,mai:[0,7],mainli:0,maintain:3,make:1,manag: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:[0,3],middl:7,minimum:7,miscellan:7,miss:7,missing_command:1,missingcommand:2,modul:5,more:[1,3],multipl:[1,3,4],music_data:1,must:[0,6,7],name:[0,1,6],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,non:[4,7],none:[0,1,3,6,7],nonefounderror:4,noplaylist:0,notat:7,notconnectederror:6,noth:[6,7],notidentifiederror:6,notimpl:[1,7],now_plai:0,nullabl:3,nullcommand:[1,2],number:[0,6],object:[0,1,3,7],offset:1,onc:[0,3],one:4,ones:1,onli:[4,7],option:[0,1,3,6,7],opu:0,order:0,org:3,other:[1,4,6,7],otherwis:[0,1,6,7],output:7,outtmpl:0,packag:6,packet:6,page:5,paramet:[0,1,3,6,7],pass:[0,7],password:3,path:[3,6],pattern:7,pcm:0,per: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:7,prepar:6,presenc:1,previous:7,primary_kei:3,probabl:[0,2,7],properti:0,quiet:0,quot:3,quoted_account:3,quoted_account_id:3,ragecommand:2,rais:[1,4,6,7],raise_on_error:6,random:0,read:0,real:6,realat:6,receiv:[1,4,6,7],reciev:6,recommend:0,recreat:6,refer:2,regex:7,regist:4,relat:[0,3],relationshiplinkchain:3,relationshipproperti:3,remindercommand:2,remov:0,repeat:0,replac:7,repli:[6,7],repres:[0,1],request:[1,4,6],request_dict:1,request_handl:6,requir:[1,4,7],require_alchemy_t:7,require_at_least:7,required_secret:6,respons:[1,4,6],responseerror:[4,6],responsesuccess:6,result:7,retriev:7,role:3,rout:6,route_packag:6,row:7,royal:[2,3],royal_id:3,royalnet_config:1,royalnetconfig:[1,6],royalnetlink:[1,6,7],royalnetrequesterror:4,royalnetresponseerror:4,royalnetserv:6,royalpcmaudio:[0,1],royalpcmfil:0,rpf:0,run:[1,6,7],safeformat:7,search:[0,5],second:7,secret:6,select:[0,3],self:[1,6],send:[6,7],sent:[6,7],sequenc:[6,7],serv:6,server:6,session:7,session_acm:3,session_cm:3,session_end:7,set:[1,3],shipcommand:2,should:[1,6,7],signal:0,singl:[1,3],skipcommand:2,sleep_until:7,smecdscommand:2,someth:[4,7],somewher:6,song:[0,1],soon:0,sourc:[0,6,7],source_conv_id:6,space:7,specif:[1,7],specifi:[1,4,7],spoiler:3,sqlalchemi:[3,7],start:[1,3,6],starting_class:3,starting_list:0,starting_pool:0,statement:3,statu:1,stereo:0,str:[0,1,3,6,7],string:[0,3,6,7],sub:7,subclass:0,submodul:3,success:6,suit:2,summoncommand:2,support:4,synccommand:2,tabl:[1,7],tailor:2,task:1,telegram:[1,3],telegram_config:1,telegrambot:1,telegramcal:1,telegramconfig:1,text:[3,7],tg_id:3,than:7,thei:[2,7],them:[2,3],therefor:4,thi:[0,4,6,7],those:0,through:7,time:6,timestamp:3,titl:0,to_dict:6,to_json_byt:6,to_json_str:6,token:1,toomanyfounderror:4,tupl:3,two:7,type:[0,1,3,6,7],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,use:[0,3],used:[0,1,2,3,6,7],useful:[0,7],user:[4,7],usernam:3,using:[1,7],usual:[0,6],utf8:6,util:[1,5],valu:[0,3,6,7],variabl:1,variou:1,veri:0,video:0,videochannelcommand:2,videoinfocommand:2,videos_left:0,voic:[0,1],wai:0,wait:7,want:[0,7],warn:0,websocket:6,websocketserverprotocol:6,weird:7,went:4,were:4,when:7,where:7,which:[0,6],without:7,won:2,word:7,worth:0,wrapper:[0,3],wrong:4,yet:6,yield:0,you:[0,2,7],your:2,youtub:0,youtube_dl:0,youtubedl:0,ytdl_arg:0,ytdl_filenam:0,ytdlfile:0,ytdlinfo:0},titles:["royalnet.audio","royalnet.bots","royalnet.commands","royalnet.database","royalnet.error","royalnet","royalnet.network","royalnet.utils"],titleterms:{audio:0,bot:1,command:2,databas:3,error:4,indic:5,network:6,royalnet:[0,1,2,3,4,5,6,7],tabl:[3,5],util:7}})
\ No newline at end of file
+Search.setIndex({docnames:["audio","bots","commands","database","error","index","network","utils"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":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"],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,""],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,""],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,""],videos_left:[0,2,1,""]},"royalnet.audio.RoyalPCMAudio":{"delete":[0,2,1,""],__init__:[0,2,1,""],create_from_url:[0,3,1,""],create_from_ytsearch:[0,3,1,""],is_opus:[0,2,1,""],read:[0,2,1,""]},"royalnet.audio.RoyalPCMFile":{audio_filename:[0,4,1,""],create_from_url:[0,3,1,""],create_from_ytsearch:[0,3,1,""],delete_audio_file:[0,2,1,""],ytdl_args:[0,4,1,""],ytdl_filename:[0,4,1,""]},"royalnet.audio.YtdlFile":{_stop_download:[0,2,1,""],create_from_url:[0,3,1,""],delete_video_file:[0,2,1,""],ytdl_args:[0,4,1,""]},"royalnet.audio.YtdlInfo":{__init__:[0,2,1,""],create_from_url:[0,3,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,4,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,4,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,4,1,""],interface_name:[1,4,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,""],PingCommand:[2,1,1,""],PlayCommand:[2,1,1,""],PlaymodeCommand:[2,1,1,""],RageCommand:[2,1,1,""],ReminderCommand:[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,5,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,""]},"royalnet.database.tables.ActiveKvGroup":{group:[3,4,1,""],group_name:[3,4,1,""],royal:[3,4,1,""],royal_id:[3,4,1,""]},"royalnet.database.tables.Alias":{alias:[3,4,1,""],royal:[3,4,1,""],royal_id:[3,4,1,""]},"royalnet.database.tables.Diario":{context:[3,4,1,""],creator:[3,4,1,""],creator_id:[3,4,1,""],diario_id:[3,4,1,""],media_url:[3,4,1,""],quoted:[3,4,1,""],quoted_account:[3,4,1,""],quoted_account_id:[3,4,1,""],spoiler:[3,4,1,""],text:[3,4,1,""],timestamp:[3,4,1,""]},"royalnet.database.tables.Discord":{avatar_hash:[3,4,1,""],discord_id:[3,4,1,""],discriminator:[3,4,1,""],full_username:[3,2,1,""],royal:[3,4,1,""],royal_id:[3,4,1,""],username:[3,4,1,""]},"royalnet.database.tables.Keygroup":{group_name:[3,4,1,""]},"royalnet.database.tables.Keyvalue":{group:[3,4,1,""],group_name:[3,4,1,""],key:[3,4,1,""],value:[3,4,1,""]},"royalnet.database.tables.Royal":{avatar:[3,4,1,""],password:[3,4,1,""],role:[3,4,1,""],uid:[3,4,1,""],username:[3,4,1,""]},"royalnet.database.tables.Telegram":{first_name:[3,4,1,""],last_name:[3,4,1,""],mention:[3,2,1,""],royal:[3,4,1,""],royal_id:[3,4,1,""],tg_id:[3,4,1,""],username:[3,4,1,""]},"royalnet.error":{ExternalError:[4,6,1,""],InvalidConfigError:[4,6,1,""],InvalidInputError:[4,6,1,""],NoneFoundError:[4,6,1,""],RoyalnetRequestError:[4,6,1,""],RoyalnetResponseError:[4,6,1,""],TooManyFoundError:[4,6,1,""],UnregisteredError:[4,6,1,""],UnsupportedError:[4,6,1,""]},"royalnet.network":{ConnectionClosedError:[6,6,1,""],NetworkError:[6,6,1,""],NotConnectedError:[6,6,1,""],NotIdentifiedError:[6,6,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,3,1,""],from_json_bytes:[6,3,1,""],from_json_string:[6,3,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,3,1,""],to_dict:[6,2,1,""]},"royalnet.network.Response":{from_dict:[6,7,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,5,1,""],asyncify:[7,5,1,""],cdj:[7,5,1,""],fileformat:[7,5,1,""],plusformat:[7,5,1,""],safeformat:[7,5,1,""],sleep_until:[7,5,1,""],ytdldateformat:[7,5,1,""]},"royalnet.utils.Call":{__init__:[7,2,1,""],_session_init:[7,2,1,""],alchemy:[7,4,1,""],get_author:[7,2,1,""],interface_name:[7,4,1,""],interface_obj:[7,4,1,""],interface_prefix:[7,4,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,4,1,""],command_name:[7,4,1,""],command_syntax:[7,4,1,""],common:[7,7,1,""],network_handler_dict:[7,7,1,""],network_handlers:[7,4,1,""],require_alchemy_tables:[7,4,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,4,1,""]},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,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","staticmethod","Python static method"],"4":["py","attribute","Python attribute"],"5":["py","function","Python function"],"6":["py","exception","Python exception"],"7":["py","classmethod","Python class method"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:staticmethod","4":"py:attribute","5":"py:function","6":"py:exception","7":"py:classmethod"},terms:{"0x7f81332fcbc8":3,"0x7f81333171c8":3,"0x7f81333173c8":3,"0x7f81333176c8":3,"0x7f8133317948":3,"0x7f8133317a48":3,"0x7f8133317ec8":3,"20m":0,"abstract":7,"boolean":3,"byte":[0,6],"class":[0,1,2,3,6,7],"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],"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],Then:1,These:2,Use:3,__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,_unixselectoreventloop:6,abl:7,about:6,abstracteventloop:6,access:7,accord:0,accur:7,activekvgroup:3,add:[0,1,7],add_to_music_data:1,added:7,adding:7,addit:[6,7],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],altern:6,alwai:[0,1],amount:[0,7],andformat:7,ani:[0,7],anoth:[1,6],anymor:6,anystr:7,arg:[6,7],argument:[0,7],around:[0,3],arrai:7,associ:7,async:[0,3],asyncifi:7,asyncio:[1,6],asyncron:3,attempt:7,attribut:7,audio:[1,5],audio_filenam:0,audio_sourc:1,audiosourc:0,author:7,authorcommand:2,autocomplet:7,avatar:3,avatar_hash:3,base:[0,1,6,7],been:[0,4],being:[4,7],bestaudio:0,between:7,biginteg:3,block:[1,7],blockingli:6,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],cancel:7,cannot:[4,7],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],classyalnet:7,client:1,close:[6,7],clue:0,colorcommand:2,column:3,columndefault:3,command:[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],configur:[1,3,4],connect:[1,6,7],connectedcli:6,connectionclosederror:6,contain:[0,4,6],context:3,convers:6,convert:[0,6,7],core:3,coroutin:[1,7],correctli:4,correspond:[0,1],creat:[0,1,3,6,7],create_from_url:0,create_from_ytsearch:0,creator:3,creator_id:3,ct_co:3,current:1,custom:[0,1],cvcommand:2,dai:7,data:[0,6,7],databas:[1,5,7],database_config:1,database_uri:3,databaseconfig:[1,3],date:7,dateparsercommand:2,datetim:[3,7],debug:6,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],discord:[0,1,3,7],discord_config:1,discord_id:3,discordbot:1,discordcli:1,discordconfig:1,discrimin:3,displai:7,doc:3,document:0,doe:[0,7],doesn:[1,7],don:7,done:0,download:0,dure:1,dynam:7,each:0,eas:7,edit:1,either:[0,7],element:[4,7],emb:0,empti:[0,1],encod:[0,6],end:3,ending_class:3,engin:3,ensur:7,error:[5,6,7],error_command:1,error_data:6,error_if_non:7,event:6,everi:[0,6],exampl: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,6,7],file:[0,1],fileformat:7,filenam:[0,7],find:[1,3,6,7],find_client:6,find_destin:6,first:0,first_nam:3,follow:3,foreignkei:3,format:[0,1,7],found:[4,7],from:[0,1,3,6,7],from_dict:6,from_json_byt:6,from_json_str:6,full_usernam:3,fullfil:7,game:2,gener:[0,1,7],genericbot:[1,3],get:[0,3,7],get_author:7,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],here:0,html:3,http:3,identifi:[6,7],identity_column_nam:3,identity_t:[1,3],ifi:7,ignor:7,incom:1,index:[5,7],inf:[0,6],infinit:0,info:[0,6],inherit:[0,1,6,7],initi:[0,1],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],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],listen:[1,6],locat:0,logger:0,login:1,look:4,loop:6,made:7,mai:[0,2,7],main:7,mainli:0,maintain:3,make:1,manag: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,modul:5,month:7,more:[1,3],multipl:[1,3,4],music_data:1,must:[6,7],name:[0,1,6,7],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],nonefounderror:4,noplaylist:0,notat:7,notconnectederror:6,noth:[6,7],notidentifiederror:6,notimpl:[1,7],now_plai:0,nullabl:3,nullcommand:[1,2],number:[0,6],object:[0,1,3,7],offset:1,onc:[0,3],one:4,ones:[1,2],onli:[4,7],option:[0,1,3,6,7],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:5,paramet:[0,1,3,6,7],pass:[0,7],password:3,past:1,path:[3,6],pattern:7,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],prefix:7,prepar:6,prepend:7,presenc:1,previous:7,primary_kei:3,probabl:[0,2,7],prompt:1,properti:0,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,receiv:[1,4,6,7],reciev:6,recommend:0,recreat:6,regex:7,regist:4,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,4,7],require_alchemy_t:7,require_at_least:7,required_arg:7,required_secret:6,respons:[1,4,6],responseerror:[4,6],responsesuccess:6,result:7,retriev:7,role:3,rout:6,route_packag:6,row:7,royal:[2,3],royal_id:3,royalnet_config:1,royalnetconfig:[1,6],royalnetlink:[1,6,7],royalnetrequesterror:4,royalnetresponseerror:4,royalnetserv:6,royalpcmaudio:[0,1],royalpcmfil:0,rpf:0,run:[1,6,7],safeformat:7,search:[0,5],second:7,secret:6,select:[0,3],self:[0,1,6],send:[6,7],sent:[6,7],separ:7,sequenc:[6,7],serv:6,server:6,session:7,session_acm:3,session_cm:3,session_end:7,set:[1,3,7],shipcommand:2,should:[1,6,7],signal:0,singl:[1,3],skipcommand:2,sleep_until:7,small:7,smecdscommand:2,some:0,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,statu:1,str:[0,1,3,6,7],string:[0,1,3,6,7],stuff:0,sub:7,submodul:3,success:6,suit:2,summoncommand:2,support:4,synccommand:2,syntax:7,tabl:[1,7],tailor:2,task:1,telegram:[1,3,7],telegram_config:1,telegrambot:[1,7],telegramcal:1,telegramconfig:1,text:[3,7],tg_id:3,than:7,thei:2,them:3,therefor:4,thi:[0,4,6,7],those:0,through:7,time:6,timestamp:3,titl:0,to_dict:6,to_discord_emb:0,to_json_byt:6,to_json_str:6,token:1,toomanyfounderror:4,tupl:3,two:7,type:[1,3,6,7],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,use:[0,3],used:[0,1,2,3,6,7],useful:[0,2,7],user:[4,7],usernam:3,using:[1,7],usual:[0,6],utf8:6,util:[1,5],uuid: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,websocket:6,websocketserverprotocol:6,weird:[0,7],went:4,were:4,what:0,when:[0,7],where:7,which:[0,6,7],why:0,without:7,won:2,word:7,work:7,worth:0,wrapper:[0,3],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"],titleterms:{audio:0,bot:1,command:2,databas:3,error:4,indic:5,network:6,royalnet:[0,1,2,3,4,5,6,7],tabl:[3,5],util:7}})
\ No newline at end of file
diff --git a/docs/html/utils.html b/docs/html/utils.html
index e15f0ff6..914ce373 100644
--- a/docs/html/utils.html
+++ b/docs/html/utils.html
@@ -173,6 +173,30 @@
-
class
royalnet.utils. Call (channel, command: Type[royalnet.utils.command.Command], command_args: List[str] = 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, **kwargs)
@@ -196,8 +220,8 @@
--
-
alchemy = NotImplemented
+-
+
alchemy = NotImplemented
@@ -216,18 +240,18 @@ That probably means, the database row identifying the user.
--
-
interface_name = NotImplemented
+-
+
interface_name = NotImplemented
--
-
interface_obj = NotImplemented
+-
+
interface_obj = NotImplemented
--
-
interface_prefix = NotImplemented
+-
+
interface_prefix = NotImplemented
@@ -238,7 +262,7 @@ That probably means, the database row identifying the user.
- Parameters
message – The data to be sent. Must be pickle -able.
-destination –
+destination – The destination of the request, either in UUID format or node name.
@@ -272,20 +296,50 @@ That probably means, the database row identifying the user.
-
class
royalnet.utils. Command
-A generic command, called from any source.
-
--
-
command_description = NotImplemented
-
-
+The base class from which all commands should inherit.
-
-
command_name = NotImplemented
-
+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 = NotImplemented
+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:`classyalnet.utils.NetworkHandler`s that must exist for this command to work.
+
+
+
+-
+
command_description = NotImplemented
+
+
+
+-
+
command_name = NotImplemented
+
+
+
+-
+
command_syntax = NotImplemented
@@ -299,13 +353,13 @@ That probably means, the database row identifying the user.
--
-
network_handlers = {}
+-
+
network_handlers = {}
--
-
require_alchemy_tables = {}
+-
+
require_alchemy_tables = {}
@@ -329,8 +383,20 @@ That probably means, the database row identifying the user.
-
-
royalnet.utils. cdj (class_) → dict
+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__ !
+
@@ -346,7 +412,7 @@ That probably means, the database row identifying the user.
-
royalnet.utils. plusformat (i: int) → str
-Convert an int to a str , adding a + if they are greater than 0.
+Convert an int to a str , prepending a + if it’s greater than 0.
- Parameters
i – the int to convert.
@@ -360,14 +426,14 @@ That probably means, the database row identifying the user.
-
class
royalnet.utils. CommandArgs
-The arguments of a command.
+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
-InvalidInputError –
+royalnet.error.InvalidInputError – if the requested argument does not exist.
@@ -381,7 +447,7 @@ That probably means, the database row identifying the user.
require_at_least – the minimum amount of arguments required, will raise royalnet.error.InvalidInputError if the requirement is not fullfilled.
- Raises
-royalnet.error.InvalidInputError –
+royalnet.error.InvalidInputError – if there are less than require_at_least arguments.
- Returns
The space-joined string.
@@ -397,8 +463,11 @@ That probably means, the database row identifying the user.
- Parameters
pattern – The regex pattern to be passed to re.match() .
-- Returns
-The matched groups, as returned by re.Match.groups() .
+- Raises
+royalnet.error.InvalidInputError – if the pattern doesn’t match.
+
+- Returns
+The matched groups, as returned by re.Match.groups() .
@@ -454,7 +523,7 @@ That probably means, the database row identifying the user.
-
royalnet.utils. plusformat (i: int) → str
-Convert an int to a str , adding a + if they are greater than 0.
+Convert an int to a str , prepending a + if it’s greater than 0.
- Parameters
i – the int to convert.
@@ -469,6 +538,31 @@ That probably means, the database row identifying the user.
-
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.
+
+
diff --git a/royalnet/__init__.py b/royalnet/__init__.py
index cdd20349..32461c59 100644
--- a/royalnet/__init__.py
+++ b/royalnet/__init__.py
@@ -1,5 +1,5 @@
from . import audio, bots, commands, database, network, utils, error
-version = "5.0a11"
+version = "5.0a12"
__all__ = ["audio", "bots", "commands", "database", "network", "utils", "error"]
diff --git a/royalnet/audio/playmodes.py b/royalnet/audio/playmodes.py
index 7b8d59c3..d93ad243 100644
--- a/royalnet/audio/playmodes.py
+++ b/royalnet/audio/playmodes.py
@@ -47,6 +47,18 @@ class PlayMode:
"""Delete all :py:class:`royalnet.audio.RoyalPCMAudio` contained inside this PlayMode."""
raise NotImplementedError()
+ def queue_preview(self) -> typing.List[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."""
+ raise NotImplementedError()
+
class Playlist(PlayMode):
"""A video list. :py:class:`royalnet.audio.RoyalPCMAudio` played are removed from the list."""
@@ -80,9 +92,13 @@ class Playlist(PlayMode):
self.list.append(item)
def delete(self) -> None:
+ if self.now_playing is not None:
+ self.now_playing.delete()
while self.list:
self.list.pop(0).delete()
- self.now_playing.delete()
+
+ def queue_preview(self) -> typing.List[RoyalPCMAudio]:
+ return self.list
class Pool(PlayMode):
@@ -125,3 +141,8 @@ class Pool(PlayMode):
item.delete()
self.pool = None
self._pool_copy = None
+
+ def queue_preview(self) -> typing.List[RoyalPCMAudio]:
+ preview_pool = self.pool.copy()
+ random.shuffle(preview_pool)
+ return preview_pool
\ No newline at end of file
diff --git a/royalnet/audio/royalpcmaudio.py b/royalnet/audio/royalpcmaudio.py
index 3a4ed425..76ddc7e9 100644
--- a/royalnet/audio/royalpcmaudio.py
+++ b/royalnet/audio/royalpcmaudio.py
@@ -5,7 +5,7 @@ from .royalpcmfile import RoyalPCMFile
class RoyalPCMAudio(AudioSource):
- """A discord-compatible :py:class:`discord.AudioSource` that keeps data in a file instead of in memory."""
+ """A :py:class:`discord.AudioSource` that keeps data in a file instead of in memory."""
def __init__(self, rpf: "RoyalPCMFile"):
"""Create a :py:class:`discord.audio.RoyalPCMAudio` from a :py:class:`royalnet.audio.RoyalPCMFile`.
@@ -41,9 +41,16 @@ class RoyalPCMAudio(AudioSource):
return [RoyalPCMAudio(rpf) for rpf in rpf_list]
def is_opus(self):
+ """This audio file isn't Opus-encoded, but PCM-encoded.
+
+ Returns:
+ ``False``."""
return False
def read(self):
+ """Reads 20ms worth of audio.
+
+ If the audio is complete, then returning an empty :py:class:`bytes`-like object to signal this is the way to do so."""
data: bytes = self._file.read(OpusEncoder.FRAME_SIZE)
# If the file was externally closed, it means it was deleted
if self._file.closed:
diff --git a/royalnet/audio/youtubedl.py b/royalnet/audio/youtubedl.py
index cc9a3289..bfce5976 100644
--- a/royalnet/audio/youtubedl.py
+++ b/royalnet/audio/youtubedl.py
@@ -48,14 +48,30 @@ class YtdlFile:
@staticmethod
def create_from_url(url, outtmpl="%(title)s-%(id)s.%(ext)s", **ytdl_args) -> typing.List["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 :py:class:`list` of YtdlFiles."""
info_list = YtdlInfo.create_from_url(url)
return [info.download(outtmpl, **ytdl_args) for info in info_list]
def _stop_download(self):
+ """I have no clue of what this does, or why is it here. Possibly remove it?
+
+ Raises:
+ InterruptDownload: ...uhhh, always?"""
raise InterruptDownload()
def delete_video_file(self):
- # TODO: _might_ be unsafe, test this
+ """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."""
os.remove(self.video_filename)
@@ -150,9 +166,9 @@ class YtdlInfo:
embed.set_thumbnail(
url=self.thumbnail)
embed.set_author(name=self.uploader, url=self.uploader_url)
- embed.set_footer(text="Fonte: youtube-dl", icon_url="https://i.imgur.com/TSvSRYn.png")
+ embed.set_footer(text="Source: youtube-dl", icon_url="https://i.imgur.com/TSvSRYn.png")
embed.add_field(name="Duration", value=str(self.duration), inline=True)
- embed.add_field(name="Published on", value=str(self.upload_date), inline=True)
+ embed.add_field(name="Published on", value=self.upload_date.strftime("%d %b %Y"), inline=True)
return embed
def __repr__(self):
diff --git a/royalnet/bots/telegram.py b/royalnet/bots/telegram.py
index 874576c0..430f979d 100644
--- a/royalnet/bots/telegram.py
+++ b/royalnet/bots/telegram.py
@@ -130,6 +130,7 @@ class TelegramBot(GenericBot):
@property
def botfather_command_string(self) -> str:
+ """Generate a string to be pasted in the "Edit Commands" BotFather prompt."""
string = ""
for command_key in self.commands:
command = self.commands[command_key]
diff --git a/royalnet/commands/__init__.py b/royalnet/commands/__init__.py
index e034cfdd..4dcb2dd3 100644
--- a/royalnet/commands/__init__.py
+++ b/royalnet/commands/__init__.py
@@ -1,4 +1,6 @@
-"""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 you can check them for reference."""
+"""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."""
from .null import NullCommand
from .ping import PingCommand
@@ -23,9 +25,12 @@ from .playmode import PlaymodeCommand
from .videochannel import VideochannelCommand
from .missing import MissingCommand
from .cv import CvCommand
+from .pause import PauseCommand
+from .queue import QueueCommand
__all__ = ["NullCommand", "PingCommand", "ShipCommand", "SmecdsCommand", "CiaoruoziCommand", "ColorCommand",
"SyncCommand", "DiarioCommand", "RageCommand", "DateparserCommand", "AuthorCommand", "ReminderCommand",
"KvactiveCommand", "KvCommand", "KvrollCommand", "VideoinfoCommand", "SummonCommand", "PlayCommand",
- "SkipCommand", "PlaymodeCommand", "VideochannelCommand", "MissingCommand", "CvCommand"]
+ "SkipCommand", "PlaymodeCommand", "VideochannelCommand", "MissingCommand", "CvCommand", "PauseCommand",
+ "QueueCommand"]
diff --git a/royalnet/commands/pause.py b/royalnet/commands/pause.py
new file mode 100644
index 00000000..95437ff4
--- /dev/null
+++ b/royalnet/commands/pause.py
@@ -0,0 +1,53 @@
+import typing
+import discord
+from ..network import Request, ResponseSuccess
+from ..utils import Command, Call, NetworkHandler
+from ..error import TooManyFoundError, NoneFoundError
+if typing.TYPE_CHECKING:
+ from ..bots import DiscordBot
+
+
+class PauseNH(NetworkHandler):
+ message_type = "music_pause"
+
+ # noinspection PyProtectedMember
+ @classmethod
+ async def discord(cls, bot: "DiscordBot", data: dict):
+ # Find the matching guild
+ if data["guild_name"]:
+ guild = bot.client.find_guild_by_name(data["guild_name"])
+ else:
+ if len(bot.music_data) == 0:
+ raise NoneFoundError("No voice clients active")
+ 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() or voice_client.is_paused()):
+ raise NoneFoundError("Nothing to pause")
+ # Toggle pause
+ resume = voice_client._player.is_paused()
+ if resume:
+ voice_client._player.resume()
+ else:
+ voice_client._player.pause()
+ return ResponseSuccess({"resume": resume})
+
+
+class PauseCommand(Command):
+
+ command_name = "pause"
+ command_description = "Mette in pausa o riprende la riproduzione della canzone attuale."
+ command_syntax = "[ [guild] ]"
+
+ network_handlers = [PauseNH]
+
+ @classmethod
+ async def common(cls, call: Call):
+ guild, = call.args.match(r"(?:\[(.+)])?")
+ response = await call.net_request(Request("music_pause", {"guild_name": guild}), "discord")
+ if response["resume"]:
+ await call.reply(f"▶️ Riproduzione ripresa.")
+ else:
+ await call.reply(f"⏸ Riproduzione messa in pausa.")
diff --git a/royalnet/commands/queue.py b/royalnet/commands/queue.py
new file mode 100644
index 00000000..b6acf99d
--- /dev/null
+++ b/royalnet/commands/queue.py
@@ -0,0 +1,76 @@
+import typing
+import pickle
+from ..network import Request, ResponseSuccess
+from ..utils import Command, Call, NetworkHandler, numberemojiformat
+from ..error import TooManyFoundError, NoneFoundError
+if typing.TYPE_CHECKING:
+ from ..bots import DiscordBot
+
+
+class QueueNH(NetworkHandler):
+ message_type = "music_queue"
+
+ @classmethod
+ async def discord(cls, bot: "DiscordBot", data: dict):
+ # Find the matching guild
+ if data["guild_name"]:
+ guild = bot.client.find_guild_by_name(data["guild_name"])
+ else:
+ if len(bot.music_data) == 0:
+ raise NoneFoundError("No voice clients active")
+ if len(bot.music_data) > 1:
+ raise TooManyFoundError("Multiple guilds found")
+ guild = list(bot.music_data)[0]
+ # Check if the guild has a PlayMode
+ playmode = bot.music_data.get(guild)
+ if not playmode:
+ return ResponseSuccess({
+ "type": None
+ })
+ try:
+ queue = playmode.queue_preview()
+ except NotImplementedError:
+ return ResponseSuccess({
+ "type": playmode.__class__.__name__
+ })
+ return ResponseSuccess({
+ "type": playmode.__class__.__name__,
+ "queue":
+ {
+ "strings": [str(element.rpf.info) for element in queue],
+ "pickled_embeds": str(pickle.dumps([element.rpf.info.to_discord_embed() for element in queue]))
+ }
+ })
+
+
+class QueueCommand(Command):
+
+ command_name = "queue"
+ command_description = "Visualizza un'anteprima della coda di riproduzione attuale."
+ command_syntax = "[ [guild] ]"
+
+ network_handlers = [QueueNH]
+
+ @classmethod
+ async def common(cls, call: Call):
+ guild, = call.args.match(r"(?:\[(.+)])?")
+ data = await call.net_request(Request("music_queue", {"guild_name": guild}), "discord")
+ if data["type"] is None:
+ await call.reply("ℹ️ Non c'è nessuna coda di riproduzione attiva al momento.")
+ return
+ elif "queue" not in data:
+ await call.reply(f"ℹ️ La coda di riproduzione attuale ([c]{data['type']}[/c]) non permette l'anteprima.")
+ return
+ if data["type"] == "Playlist":
+ message = f"ℹ️ Questa [c]Playlist[/c] contiene {len(data['queue'])} elementi, e i prossimi saranno:\n"
+ elif data["type"] == "Pool":
+ message = f"ℹ️ Questo [c]Pool[/c] contiene {len(data['queue'])} elementi, tra cui:\n"
+ else:
+ message = f"ℹ️ Il PlayMode attuale, [c]{data['type']}[/c], contiene {len(data['queue'])} elementi:\n"
+ if call.interface_name == "discord":
+ await call.reply(message)
+ for embed in pickle.loads(eval(data["queue"]["pickled_embeds"]))[:5]:
+ await call.channel.send(embed=embed)
+ else:
+ message += numberemojiformat(data["queue"]["strings"][:10])
+ await call.reply(message)
diff --git a/royalnet/commands/skip.py b/royalnet/commands/skip.py
index 238cf885..a91a02b4 100644
--- a/royalnet/commands/skip.py
+++ b/royalnet/commands/skip.py
@@ -23,7 +23,7 @@ class SkipNH(NetworkHandler):
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():
+ if not (voice_client.is_playing() or voice_client.is_paused()):
raise NoneFoundError("Nothing to skip")
# noinspection PyProtectedMember
voice_client._player.stop()
diff --git a/royalnet/network/__init__.py b/royalnet/network/__init__.py
index 1737f835..eee8ebc4 100644
--- a/royalnet/network/__init__.py
+++ b/royalnet/network/__init__.py
@@ -1,4 +1,4 @@
-"""Royalnet realated classes."""
+"""Royalnet (websocket) related classes."""
from .request import Request
from .response import Response, ResponseSuccess, ResponseError
from .package import Package
diff --git a/royalnet/royalgames.py b/royalnet/royalgames.py
index 867a66e7..ba387c1c 100644
--- a/royalnet/royalgames.py
+++ b/royalnet/royalgames.py
@@ -20,7 +20,7 @@ log.setLevel(logging.WARNING)
commands = [PingCommand, ShipCommand, SmecdsCommand, ColorCommand, CiaoruoziCommand, DebugCreateCommand, SyncCommand,
AuthorCommand, DiarioCommand, RageCommand, DateparserCommand, ReminderCommand, KvactiveCommand, KvCommand,
KvrollCommand, VideoinfoCommand, SummonCommand, PlayCommand, SkipCommand, PlaymodeCommand,
- VideochannelCommand, CvCommand]
+ VideochannelCommand, CvCommand, PauseCommand, QueueCommand]
address, port = "127.0.0.1", 1234
diff --git a/royalnet/utils/__init__.py b/royalnet/utils/__init__.py
index cd1860b0..770b7196 100644
--- a/royalnet/utils/__init__.py
+++ b/royalnet/utils/__init__.py
@@ -9,7 +9,7 @@ from .safeformat import safeformat
from .classdictjanitor import cdj
from .sleepuntil import sleep_until
from .networkhandler import NetworkHandler
-from .formatters import andformat, plusformat, fileformat, ytdldateformat
+from .formatters import andformat, plusformat, fileformat, ytdldateformat, numberemojiformat
__all__ = ["asyncify", "Call", "Command", "safeformat", "cdj", "sleep_until", "plusformat", "CommandArgs",
- "NetworkHandler", "andformat", "plusformat", "fileformat", "ytdldateformat"]
+ "NetworkHandler", "andformat", "plusformat", "fileformat", "ytdldateformat", "numberemojiformat"]
diff --git a/royalnet/utils/call.py b/royalnet/utils/call.py
index ea8799d2..f45c8c82 100644
--- a/royalnet/utils/call.py
+++ b/royalnet/utils/call.py
@@ -10,7 +10,13 @@ loop = asyncio.get_event_loop()
class Call:
- """A command call. An abstract class, sub-bots should create a new call class from this."""
+ """A command call. An abstract class, sub-bots should create a new call class from this.
+
+ Attributes:
+ 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 :py:class:`royalnet.bots.TelegramBot` object.
+ interface_prefix: The command prefix used by the interface. For example, ``/``, or ``!``.
+ alchemy: The :py:class:`royalnet.database.Alchemy` object associated to this interface. May be None if the interface is not connected to any database."""
# These parameters / methods should be overridden
interface_name = NotImplemented
@@ -30,7 +36,7 @@ class Call:
Parameters:
message: The data to be sent. Must be :py:mod:`pickle`-able.
- destination: """
+ destination: The destination of the request, either in UUID format or node name."""
raise NotImplementedError()
async def get_author(self, error_if_none=False):
diff --git a/royalnet/utils/classdictjanitor.py b/royalnet/utils/classdictjanitor.py
index d4b97065..3897f8dd 100644
--- a/royalnet/utils/classdictjanitor.py
+++ b/royalnet/utils/classdictjanitor.py
@@ -1,5 +1,16 @@
-def cdj(class_) -> 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."""
+import typing
+
+def cdj(class_: typing.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__``!"""
d = dict(class_.__dict__)
del d["__module__"]
del d["__dict__"]
diff --git a/royalnet/utils/command.py b/royalnet/utils/command.py
index 5c88f33c..f9e515f8 100644
--- a/royalnet/utils/command.py
+++ b/royalnet/utils/command.py
@@ -6,7 +6,14 @@ if typing.TYPE_CHECKING:
class Command:
- """A generic command, called from any source."""
+ """The base class from which all commands should inherit.
+
+ Attributes:
+ 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 :py:exc:`royalnet.error.InvalidInputError` is raised, in the format ``(required_arg) [optional_arg]``.
+ require_alchemy_tables: A set of :py:class:`royalnet.database` tables, that must exist for this command to work.
+ network_handlers: A list of :py:class:`classyalnet.utils.NetworkHandler`s that must exist for this command to work."""
command_name: str = NotImplemented
command_description: str = NotImplemented
diff --git a/royalnet/utils/commandargs.py b/royalnet/utils/commandargs.py
index e87f4924..575f2682 100644
--- a/royalnet/utils/commandargs.py
+++ b/royalnet/utils/commandargs.py
@@ -4,13 +4,13 @@ from royalnet.error import InvalidInputError
class CommandArgs(list):
- """The arguments of a command."""
+ """An interface to access the arguments of a command with ease."""
def __getitem__(self, item):
"""Arguments can be accessed with an array notation, such as ``args[0]``.
Raises:
- :py:exc:`InvalidInputError` if the requested argument does not exist."""
+ royalnet.error.InvalidInputError: if the requested argument does not exist."""
if isinstance(item, int):
try:
return super().__getitem__(item)
@@ -30,7 +30,7 @@ class CommandArgs(list):
require_at_least: the minimum amount of arguments required, will raise :py:exc:`royalnet.error.InvalidInputError` if the requirement is not fullfilled.
Raises:
- :py:exc:`royalnet.error.InvalidInputError` if the ``require_at_least`` requirement is not fullfilled.
+ royalnet.error.InvalidInputError: if there are less than ``require_at_least`` arguments.
Returns:
The space-joined string."""
@@ -44,6 +44,9 @@ class CommandArgs(list):
Parameters:
pattern: The regex pattern to be passed to :py:func:`re.match`.
+ Raises:
+ royalnet.error.InvalidInputError: if the pattern doesn't match.
+
Returns:
The matched groups, as returned by :py:func:`re.Match.groups`."""
text = self.joined()
diff --git a/royalnet/utils/escaping.py b/royalnet/utils/escaping.py
index dc59bfde..31a99ec7 100644
--- a/royalnet/utils/escaping.py
+++ b/royalnet/utils/escaping.py
@@ -1,4 +1,8 @@
def 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."""
return string.replace("*", "\\*") \
.replace("_", "\\_") \
.replace("`", "\\`") \
@@ -15,6 +19,10 @@ def discord_escape(string: str) -> str:
def 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."""
return string.replace("<", "<") \
.replace(">", ">") \
.replace("[b]", "") \
diff --git a/royalnet/utils/formatters.py b/royalnet/utils/formatters.py
index 9e519fb4..1e4f92ee 100644
--- a/royalnet/utils/formatters.py
+++ b/royalnet/utils/formatters.py
@@ -23,7 +23,7 @@ def andformat(l: typing.List[str], middle=", ", final=" and ") -> str:
def plusformat(i: int) -> str:
- """Convert an :py:class:`int` to a :py:class:`str`, adding a ``+`` if they are greater than 0.
+ """Convert an :py:class:`int` to a :py:class:`str`, prepending a ``+`` if it's greater than 0.
Parameters:
i: the :py:class:`int` to convert.
@@ -36,11 +36,37 @@ def plusformat(i: int) -> str:
def fileformat(string: str) -> str:
- """Ensure a string can be used as a filename by replacing all non-word characters with underscores."""
+ """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."""
return re.sub(r"\W", "_", string)
def ytdldateformat(string: typing.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."""
if string is None:
return ""
- return f"{string[0:4]}-{string[4:6]}-{string[6:8]}"
+ return f"{string[0:4]}{separator}{string[4:6]}{separator}{string[6:8]}"
+
+
+def numberemojiformat(l: typing.List[str]) -> str:
+ number_emojis = ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟"]
+ extra_emoji = "*️⃣"
+ result = ""
+ for index, element in enumerate(l):
+ try:
+ result += f"{number_emojis[index]} {element}\n"
+ except IndexError:
+ result += f"{extra_emoji} {element}\n"
+ return result
diff --git a/royalnet/web/blueprints/helloworld.py b/royalnet/web/blueprints/helloworld.py
new file mode 100644
index 00000000..cd8e77aa
--- /dev/null
+++ b/royalnet/web/blueprints/helloworld.py
@@ -0,0 +1,11 @@
+import flask as f
+from .. import Royalprint
+
+
+bp = Royalprint("helloworld", __name__, url_prefix="/helloworld")
+
+
+@bp.route("/")
+def helloworld():
+ return "Hello world!"
+
diff --git a/royalnet/web/blueprints/testing.py b/royalnet/web/blueprints/testing.py
new file mode 100644
index 00000000..989b95af
--- /dev/null
+++ b/royalnet/web/blueprints/testing.py
@@ -0,0 +1,13 @@
+import flask as f
+from .. import Royalprint
+from ...database.tables import Royal
+
+
+bp = Royalprint("testing", __name__, url_prefix="/testing", required_tables={Royal})
+
+
+@bp.route("/listroyals")
+def listroyals():
+ from ..alchemyhandler import alchemy, alchemy_session
+ royals = alchemy_session.query(alchemy.Royal).all()
+ return f''
|