1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-27 13:34:28 +00:00

publish: 5.8.0

This commit is contained in:
Steffo 2020-05-11 00:46:12 +02:00
parent 59bb841678
commit fe815aaa2f
Signed by: steffo
GPG key ID: 896A80F55F7C97F0
56 changed files with 391 additions and 722 deletions

222
README.md
View file

@ -1,204 +1,22 @@
<!--This documentation was autogenerated with `python -m royalnet.generate -f markdown`.-->
# `royalpack` # `royalpack`
## Commands ## Required configuration options
### `ciaoruozi` ```toml
Imgur.token =
Saluta Ruozi, un leggendario essere che una volta era in User Games. Telegram.main_group_id =
Discord.main_channel_id =
### `color` Dota.updater =
Peertube.instance_url =
Invia un colore in chat...? Peertube.feed_update_timeout =
Funkwhale.instance_url =
### `cv` Cv.displayed_role_id =
Lol.token =
Elenca le persone attualmente connesse alla chat vocale. Lol.region =
Lol.updater =
### `diario` Play.max_song_duration =
Steam.web_api_key =
Aggiungi una citazione al Diario. Brawlhalla.api_key =
Brawlhalla.updater =
### `rage` Matchmaking.mm_chat_id =
```
Arrabbiati per qualcosa, come una software house californiana.
> Aliases: `balurage` `madden`
### `reminder`
Ti ricorda di fare qualcosa dopo un po' di tempo.
> Aliases: `calendar`
### `ship`
Crea una ship tra due nomi.
### `smecds`
Secondo me, è colpa dello stagista...
> Aliases: `secondomeecolpadellostagista`
### `videochannel`
Converti il canale vocale in un canale video.
> Aliases: `golive` `live` `video`
### `pause`
Metti in pausa o riprendi la riproduzione di un file.
> Aliases: `resume`
### `play`
Aggiunge un url alla coda della chat vocale.
> Aliases: `p`
### `queue`
Visualizza la coda di riproduzione attuale..
> Aliases: `q`
### `skip`
Salta il file attualmente in riproduzione.
> Aliases: `s`
### `summon`
Evoca il bot in un canale vocale.
> Aliases: `cv`
### `youtube`
Cerca un video su YouTube e lo aggiunge alla coda della chat vocale.
> Aliases: `yt`
### `soundcloud`
Cerca un video su SoundCloud e lo aggiunge alla coda della chat vocale.
> Aliases: `sc`
### `emojify`
Converti un messaggio in emoji.
### `leagueoflegends`
Connetti un account di League of Legends a un account Royalnet, e visualizzane le statistiche.
> Aliases: `lol` `league`
### `diarioquote`
Cita una riga del diario.
> Aliases: `dq` `quote` `dquote`
### `peertube`
Guarda quando è uscito l'ultimo video su RoyalTube.
### `googlevideo`
Cerca un video su Google Video e lo aggiunge alla coda della chat vocale.
> Aliases: `gv`
### `yahoovideo`
Cerca un video su Yahoo Video e lo aggiunge alla coda della chat vocale.
> Aliases: `yv`
### `userinfo`
Visualizza informazioni su un utente.
> Aliases: `uinfo` `ui` `useri`
### `spell`
Genera casualmente una spell!
### `ahnonlosoio`
Ah, non lo so io!
### `eat`
Mangia qualcosa!
### `pmots`
Confondi Proto!
## Events
### `discord_cv`
### `discord_summon`
### `discord_play`
### `discord_skip`
### `discord_queue`
### `discord_pause`
## Page Stars
### `/api/user/list`
### `/api/user/get/{uid_str}`
### `/api/diario/list`
### `/api/diario/get/{diario_id}`
## Exception Stars
## Tables
### `diario`
### `aliases`
### `wikipages`
Wiki page properties.
Warning:
Requires PostgreSQL!
### `wikirevisions`
A wiki page revision.
Warning:
Requires PostgreSQL!
### `bios`
### `reminder`
### `triviascores`
### `mmevents`
### `mmresponse`
### `leagueoflegends`

308
poetry.lock generated
View file

@ -233,7 +233,7 @@ description = "Coroutine-based network library"
name = "gevent" name = "gevent"
optional = false optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
version = "20.4.0" version = "20.5.0"
[package.dependencies] [package.dependencies]
cffi = ">=1.12.2" cffi = ">=1.12.2"
@ -275,26 +275,6 @@ optional = false
python-versions = "*" python-versions = "*"
version = "0.9.0" version = "0.9.0"
[[package]]
category = "main"
description = "HTTP/2 State-Machine based protocol implementation"
name = "h2"
optional = false
python-versions = "*"
version = "3.2.0"
[package.dependencies]
hpack = ">=3.0,<4"
hyperframe = ">=5.2.0,<6"
[[package]]
category = "main"
description = "Pure-Python HPACK header compression"
name = "hpack"
optional = false
python-versions = "*"
version = "3.0.0"
[[package]] [[package]]
category = "main" category = "main"
description = "A collection of framework independent HTTP protocol utils." description = "A collection of framework independent HTTP protocol utils."
@ -315,14 +295,6 @@ version = "8.2"
[package.dependencies] [package.dependencies]
pyreadline = "*" pyreadline = "*"
[[package]]
category = "main"
description = "HTTP/2 framing layer for Python"
name = "hyperframe"
optional = false
python-versions = "*"
version = "5.2.0"
[[package]] [[package]]
category = "main" category = "main"
description = "Internationalized Domain Names in Applications (IDNA)" description = "Internationalized Domain Names in Applications (IDNA)"
@ -331,68 +303,6 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.9" version = "2.9"
[[package]]
category = "main"
description = "An implementation of JSON Schema validation for Python"
name = "jsonschema"
optional = false
python-versions = "*"
version = "3.2.0"
[package.dependencies]
attrs = ">=17.4.0"
pyrsistent = ">=0.14.0"
setuptools = "*"
six = ">=1.11.0"
[package.extras]
format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"]
format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"]
[[package]]
category = "main"
description = "A logging replacement for Python"
name = "logbook"
optional = false
python-versions = "*"
version = "1.5.3"
[package.extras]
all = ["redis", "brotli", "pytest (>4.0)", "execnet (>=1.0.9)", "cython", "pyzmq", "pytest-cov (>=2.6)", "sqlalchemy", "jinja2"]
compression = ["brotli"]
dev = ["pytest-cov (>=2.6)", "pytest (>4.0)", "cython"]
execnet = ["execnet (>=1.0.9)"]
jinja = ["jinja2"]
redis = ["redis"]
sqlalchemy = ["sqlalchemy"]
test = ["pytest-cov (>=2.6)", "pytest (>4.0)"]
zmq = ["pyzmq"]
[[package]]
category = "main"
description = "A Python Matrix client library, designed according to sans I/O principles."
name = "matrix-nio"
optional = false
python-versions = "*"
version = "0.6"
[package.dependencies]
attrs = "*"
future = "*"
h11 = "*"
h2 = "*"
jsonschema = "*"
logbook = "*"
pycryptodome = "*"
unpaddedbase64 = "*"
[package.dependencies.aiohttp]
python = ">=3.6"
version = "*"
[package.extras]
e2e = ["python-olm (>=3.1.0)", "peewee (>=3.9.5)", "cachetools", "atomicwrites"]
[[package]] [[package]]
category = "main" category = "main"
description = "multidict implementation" description = "multidict implementation"
@ -441,14 +351,6 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.20" version = "2.20"
[[package]]
category = "main"
description = "Cryptographic library for Python"
name = "pycryptodome"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "3.9.7"
[[package]] [[package]]
category = "main" category = "main"
description = "Python binding to the Networking and Cryptography (NaCl) library" description = "Python binding to the Networking and Cryptography (NaCl) library"
@ -482,17 +384,6 @@ optional = false
python-versions = "*" python-versions = "*"
version = "2.1" version = "2.1"
[[package]]
category = "main"
description = "Persistent/Functional/Immutable data structures"
name = "pyrsistent"
optional = false
python-versions = "*"
version = "0.16.0"
[package.dependencies]
six = "*"
[[package]] [[package]]
category = "main" category = "main"
description = "Extensions to the standard Python datetime module" description = "Extensions to the standard Python datetime module"
@ -521,7 +412,7 @@ description = "We have made you a wrapper you can't refuse"
name = "python-telegram-bot" name = "python-telegram-bot"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "12.6.1" version = "12.7"
[package.dependencies] [package.dependencies]
certifi = "*" certifi = "*"
@ -548,7 +439,7 @@ description = "Alternative regular expression module, to replace re."
name = "regex" name = "regex"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "2020.4.4" version = "2020.5.7"
[[package]] [[package]]
category = "main" category = "main"
@ -588,7 +479,7 @@ description = "A multipurpose bot and web framework"
name = "royalnet" name = "royalnet"
optional = false optional = false
python-versions = ">=3.8,<4.0" python-versions = ">=3.8,<4.0"
version = "5.7.7" version = "5.8.7"
[package.dependencies] [package.dependencies]
dateparser = ">=0.7.2,<0.8.0" dateparser = ">=0.7.2,<0.8.0"
@ -614,10 +505,6 @@ version = ">=0.9,<0.10"
optional = true optional = true
version = ">=0.2.0,<0.3.0" version = ">=0.2.0,<0.3.0"
[package.dependencies.matrix-nio]
optional = true
version = ">=0.6,<0.7"
[package.dependencies.psycopg2_binary] [package.dependencies.psycopg2_binary]
optional = true optional = true
version = ">=2.8.4,<3.0.0" version = ">=2.8.4,<3.0.0"
@ -782,19 +669,11 @@ description = "tzinfo object for the local timezone"
name = "tzlocal" name = "tzlocal"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "2.0.0" version = "2.1"
[package.dependencies] [package.dependencies]
pytz = "*" pytz = "*"
[[package]]
category = "main"
description = "Unpadded Base64"
name = "unpaddedbase64"
optional = false
python-versions = "*"
version = "1.1.0"
[[package]] [[package]]
category = "main" category = "main"
description = "HTTP library with thread-safe connection pooling, file post, and more." description = "HTTP library with thread-safe connection pooling, file post, and more."
@ -866,10 +745,10 @@ description = "YouTube video downloader"
name = "youtube-dl" name = "youtube-dl"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "2020.3.24" version = "2020.5.8"
[metadata] [metadata]
content-hash = "c05aace99f49203f824c7f6cdc5ed816fd139935673d8b01c4275eb14f45e590" content-hash = "d8d544d6f79b7389ef160d65a596fd18e07ab31bd035d1ebfc2cf3dbb9c36a0f"
python-versions = "^3.8" python-versions = "^3.8"
[metadata.files] [metadata.files]
@ -1019,30 +898,28 @@ future = [
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
] ]
gevent = [ gevent = [
{file = "gevent-20.4.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1ef086264e846371beb5742ebaeb148dc96adf72da2ff350ae5603421cdc2ad9"}, {file = "gevent-20.5.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:efd9546468502a30ddd4699c3124ccb9d3099130f9b5ae1e2a54ad5b46e86120"},
{file = "gevent-20.4.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:2070c65896f89a85b39f49427d6132f7abd047129fc4da88b3670f0ba13b0cf7"}, {file = "gevent-20.5.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ff477b6d275396123faf8ce2d5b82f96d85ba264e0b9d4b56a2bac49d1b9adc"},
{file = "gevent-20.4.0-cp27-cp27m-win32.whl", hash = "sha256:de6c0cbcb890d0a79323961d3b593a0f2f54dcb9fe38ee5167f2d514e69e3c8c"}, {file = "gevent-20.5.0-cp27-cp27m-win32.whl", hash = "sha256:92edc18a357473e01a4e4a82c073ed3c99ceca6e3ce93c23668dd4a2401f07dc"},
{file = "gevent-20.4.0-cp27-cp27m-win_amd64.whl", hash = "sha256:3b4c4d99f87c0d04b825879c5a91fbfa2b66da7c25b8689e9bdd9f4741d5f80d"}, {file = "gevent-20.5.0-cp27-cp27m-win_amd64.whl", hash = "sha256:1dd95433be45e1115053878366e3f5332ae99c39cb345be23851327c062b9f4a"},
{file = "gevent-20.4.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:8cca7ffd58559f8d51e5605ad73afcc6f348f9747d2fa539b336e70851b69b79"}, {file = "gevent-20.5.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:fcb64f3a28420d1b872b7ef41b12e8a1a4dcadfc8eff3c09993ab0cdf52584a1"},
{file = "gevent-20.4.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:b46399f6c9eccc2e6de1dc1057d362be840443e5439b06cce8b01d114ba1a7ec"}, {file = "gevent-20.5.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:4d2729dd4bf9c4d0f29482f53cdf9fc90a498aebb5cd7ae8b45d35657437d2ac"},
{file = "gevent-20.4.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:ee39caf14d66e619709cdfe3962bc68a234518e43ea8c811c0d67a864bc7c196"}, {file = "gevent-20.5.0-cp35-cp35m-win32.whl", hash = "sha256:00b03601b8dd1ee2aa07811cb60a4befe36173b15d91c6e207e37f8d77dd6fac"},
{file = "gevent-20.4.0-cp35-cp35m-win32.whl", hash = "sha256:8a9aba59a3268f20c7b584119215bdc589cb81500d93dad4dab428eb02f72944"}, {file = "gevent-20.5.0-cp35-cp35m-win_amd64.whl", hash = "sha256:937d36730f2b0dee3387712074b1f15b802e2e074a3d7c6dcaf70521236d607c"},
{file = "gevent-20.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:6088bedd8b6bcdb815be322304a5d1c028ffa837d84e93b349928dadac62f354"}, {file = "gevent-20.5.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:929c33df8e9bcbe31906024fcd21580bd018196dbd3249eb5b2f19d63e11092d"},
{file = "gevent-20.4.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c0b38a654c8fde5b9d9bd27ea3261aeefe36bc9244b170b6d3b11d72a2163bdb"}, {file = "gevent-20.5.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:52e5cd607749ed3b8aa0272cacf2c11deec61fca4c3bec57a9fea8c49316627d"},
{file = "gevent-20.4.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e7d23d5f32c9db6ae49c4b58585618dcafd6ad0babae251c9c8297afebc4744b"}, {file = "gevent-20.5.0-cp36-cp36m-win32.whl", hash = "sha256:15eae3cd450dac7dae7f4ac59e01db1378965c9ef565c39c5ae78c5a888f9ac9"},
{file = "gevent-20.4.0-cp36-cp36m-win32.whl", hash = "sha256:0b84a8d6f088b29a74402728681c9f11864b95e49f5587a666e6fbf5c683e597"}, {file = "gevent-20.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:9b4e940fc6071afebb86ba5f48dbb5f1fc3cb96ebeb8cf145eb5b499e9c6ee33"},
{file = "gevent-20.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:b0aea12de542f8fcd6882087bdd5b4d7dc8bb316d28181f6b012dd0b91583285"}, {file = "gevent-20.5.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:e01d5373528e4ebdde66dc47a608d225fa3c4408ccd828d26c49b7ff75d82bd9"},
{file = "gevent-20.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e0990009e7c1624f9a0f3335df1ab8d45678241c852659ac645b70ed8229097c"}, {file = "gevent-20.5.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:31dc5d4ab8172cc00c4ff17cb18edee633babd961f64bf54214244d769bc3a74"},
{file = "gevent-20.4.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:c7a62d51c6dca84f91a91b940037523c926a516f0568f47dc1386bd1682cf4e9"}, {file = "gevent-20.5.0-cp37-cp37m-win32.whl", hash = "sha256:0acc15ba2ac2a555529ad82d5a28fc85dbb6b2ff947657d67bebfd352e2b5c14"},
{file = "gevent-20.4.0-cp37-cp37m-win32.whl", hash = "sha256:d56f36eb98532d2bccc51cb0964c31e9fbd9b2282074c297dc9b006b047e2966"}, {file = "gevent-20.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a7805934e8ce81610b61f806572c3d504cedd698cc8c9460d78d2893ba598c4a"},
{file = "gevent-20.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2fbe0bc43d8c5540153f06eece6235dda14e5f99bdd9183838396313100815d7"}, {file = "gevent-20.5.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:5c604179cebcc57f10505d8db177b92a715907815a464b066e7eba322d1c33ac"},
{file = "gevent-20.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4572dc7907a0ac3c39b9f0898dbdf390ae3250baaae5f7395661fb844e2e23be"}, {file = "gevent-20.5.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:88c76df4967c5229f853aa67ad1b394d9e4f985b0359c9bc9879416bba3e7c68"},
{file = "gevent-20.4.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:956e82a5d0e90f8d71efe4cecccde602cfb657cd866c58bb953c9c30ca1b3d77"}, {file = "gevent-20.5.0-cp38-cp38-win32.whl", hash = "sha256:d07a2afe4215731eb57d5b257a2e7e7e170d8a7ae1f02f6d0682cd3403debea9"},
{file = "gevent-20.4.0-cp38-cp38-win32.whl", hash = "sha256:38c45d8a3b647f56f8a68769a8ac4953be84a84735c7c7a4d7ca62022bd54036"}, {file = "gevent-20.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:28b7d83b4327ceb79668eca2049bf4b9ce66d5ace18a88335e3035b573f889fd"},
{file = "gevent-20.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:32813de352918fb652a3db805fd6e08e0a1666a1a9304eef95938c9c426f9573"}, {file = "gevent-20.5.0-pp27-pypy_73-win32.whl", hash = "sha256:38db524ea88d81d596b2cbb6948fced26654a15fec40ea4529224e239a6f45e8"},
{file = "gevent-20.4.0-pp27-pypy_73-macosx_10_7_x86_64.whl", hash = "sha256:42cae3be36b7458f411bd589c66aaba27e4e611ec3d3621e37fd732fe383f9b6"}, {file = "gevent-20.5.0.tar.gz", hash = "sha256:1dc7f1f6bc1f67d625e4272b01e717eba0b4fa024d2ff7934c8d320674d6f7fa"},
{file = "gevent-20.4.0-pp27-pypy_73-win32.whl", hash = "sha256:cea28f958bc4206ae092043e0775cd7a2bb2536bcbece292732c6484c1076c01"},
{file = "gevent-20.4.0.tar.gz", hash = "sha256:c516cc5d70c3faf07f271d50930d144339c69fb80f3cac9b687aa964e518535e"},
] ]
gevent-eventemitter = [ gevent-eventemitter = [
{file = "gevent-eventemitter-2.1.tar.gz", hash = "sha256:00e6e688c6a255f7bdcef1d8c999e0d02d9ab87d3c6ff626e6dc1a09762107f4"}, {file = "gevent-eventemitter-2.1.tar.gz", hash = "sha256:00e6e688c6a255f7bdcef1d8c999e0d02d9ab87d3c6ff626e6dc1a09762107f4"},
@ -1076,14 +953,6 @@ h11 = [
{file = "h11-0.9.0-py2.py3-none-any.whl", hash = "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1"}, {file = "h11-0.9.0-py2.py3-none-any.whl", hash = "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1"},
{file = "h11-0.9.0.tar.gz", hash = "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1"}, {file = "h11-0.9.0.tar.gz", hash = "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1"},
] ]
h2 = [
{file = "h2-3.2.0-py2.py3-none-any.whl", hash = "sha256:61e0f6601fa709f35cdb730863b4e5ec7ad449792add80d1410d4174ed139af5"},
{file = "h2-3.2.0.tar.gz", hash = "sha256:875f41ebd6f2c44781259005b157faed1a5031df3ae5aa7bcb4628a6c0782f14"},
]
hpack = [
{file = "hpack-3.0.0-py2.py3-none-any.whl", hash = "sha256:0edd79eda27a53ba5be2dfabf3b15780928a0dff6eb0c60a3d6767720e970c89"},
{file = "hpack-3.0.0.tar.gz", hash = "sha256:8eec9c1f4bfae3408a3f30500261f7e6a65912dc138526ea054f9ad98892e9d2"},
]
httptools = [ httptools = [
{file = "httptools-0.0.13.tar.gz", hash = "sha256:e00cbd7ba01ff748e494248183abc6e153f49181169d8a3d41bb49132ca01dfc"}, {file = "httptools-0.0.13.tar.gz", hash = "sha256:e00cbd7ba01ff748e494248183abc6e153f49181169d8a3d41bb49132ca01dfc"},
] ]
@ -1091,32 +960,10 @@ humanfriendly = [
{file = "humanfriendly-8.2-py2.py3-none-any.whl", hash = "sha256:e78960b31198511f45fd455534ae7645a6207d33e512d2e842c766d15d9c8080"}, {file = "humanfriendly-8.2-py2.py3-none-any.whl", hash = "sha256:e78960b31198511f45fd455534ae7645a6207d33e512d2e842c766d15d9c8080"},
{file = "humanfriendly-8.2.tar.gz", hash = "sha256:bf52ec91244819c780341a3438d5d7b09f431d3f113a475147ac9b7b167a3d12"}, {file = "humanfriendly-8.2.tar.gz", hash = "sha256:bf52ec91244819c780341a3438d5d7b09f431d3f113a475147ac9b7b167a3d12"},
] ]
hyperframe = [
{file = "hyperframe-5.2.0-py2.py3-none-any.whl", hash = "sha256:5187962cb16dcc078f23cb5a4b110098d546c3f41ff2d4038a9896893bbd0b40"},
{file = "hyperframe-5.2.0.tar.gz", hash = "sha256:a9f5c17f2cc3c719b917c4f33ed1c61bd1f8dfac4b1bd23b7c80b3400971b41f"},
]
idna = [ idna = [
{file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"}, {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"},
{file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"}, {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"},
] ]
jsonschema = [
{file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"},
{file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"},
]
logbook = [
{file = "Logbook-1.5.3-cp27-cp27m-win32.whl", hash = "sha256:56ee54c11df3377314cedcd6507638f015b4b88c0238c2e01b5eb44fd3a6ad1b"},
{file = "Logbook-1.5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:2dc85f1510533fddb481e97677bb7bca913560862734c0b3b289bfed04f78c92"},
{file = "Logbook-1.5.3-cp35-cp35m-win32.whl", hash = "sha256:94e2e11ff3c2304b0d09a36c6208e5ae756eb948b210e5cbd63cd8d27f911542"},
{file = "Logbook-1.5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:97fee1bd9605f76335b169430ed65e15e457a844b2121bd1d90a08cf7e30aba0"},
{file = "Logbook-1.5.3-cp36-cp36m-win32.whl", hash = "sha256:7c533eb728b3d220b1b5414ba4635292d149d79f74f6973b4aa744c850ca944a"},
{file = "Logbook-1.5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:e18f7422214b1cf0240c56f884fd9c9b4ff9d0da2eabca9abccba56df7222f66"},
{file = "Logbook-1.5.3-cp37-cp37m-win32.whl", hash = "sha256:8f76a2e7b1f72595f753228732f81ce342caf03babc3fed6bbdcf366f2f20f18"},
{file = "Logbook-1.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0cf2cdbfb65a03b5987d19109dacad13417809dcf697f66e1a7084fb21744ea9"},
{file = "Logbook-1.5.3.tar.gz", hash = "sha256:66f454ada0f56eae43066f604a222b09893f98c1adc18df169710761b8f32fe8"},
]
matrix-nio = [
{file = "matrix-nio-0.6.tar.gz", hash = "sha256:25a4ac9d5e1435035f5c5b6e9a6b453ac66ade25cb455ba6bbe9cc3ae1e0ef50"},
]
multidict = [ multidict = [
{file = "multidict-4.7.5-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:fc3b4adc2ee8474cb3cd2a155305d5f8eda0a9c91320f83e55748e1fcb68f8e3"}, {file = "multidict-4.7.5-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:fc3b4adc2ee8474cb3cd2a155305d5f8eda0a9c91320f83e55748e1fcb68f8e3"},
{file = "multidict-4.7.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:42f56542166040b4474c0c608ed051732033cd821126493cf25b6c276df7dd35"}, {file = "multidict-4.7.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:42f56542166040b4474c0c608ed051732033cd821126493cf25b6c276df7dd35"},
@ -1197,38 +1044,6 @@ pycparser = [
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
] ]
pycryptodome = [
{file = "pycryptodome-3.9.7-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:0e10f352ccbbcb5bb2dc4ecaf106564e65702a717d72ab260f9ac4c19753cfc2"},
{file = "pycryptodome-3.9.7-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:9c739b7795ccf2ef1fdad8d44e539a39ad300ee6786e804ea7f0c6a786eb5343"},
{file = "pycryptodome-3.9.7-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9977086e0f93adb326379897437373871b80501e1d176fec63c7f46fb300c862"},
{file = "pycryptodome-3.9.7-cp27-cp27m-win32.whl", hash = "sha256:83295a3fb5cf50c48631eb5b440cb5e9832d8c14d81d1d45f4497b67a9987de8"},
{file = "pycryptodome-3.9.7-cp27-cp27m-win_amd64.whl", hash = "sha256:b1e332587b3b195542e77681389c296e1837ca01240399d88803a075447d3557"},
{file = "pycryptodome-3.9.7-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9378c309aec1f8cd8bad361ed0816a440151b97a2a3f6ffdaba1d1a1fb76873a"},
{file = "pycryptodome-3.9.7-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4f94368ce2d65873a87ad867eb3bf63f4ba81eb97a9ee66d38c2b71ce5a7439"},
{file = "pycryptodome-3.9.7-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:f655addaaaa9974108d4808f4150652589cada96074c87115c52e575bfcd87d5"},
{file = "pycryptodome-3.9.7-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:9a94fca11fdc161460bd8659c15b6adef45c1b20da86402256eaf3addfaab324"},
{file = "pycryptodome-3.9.7-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:ea83bcd9d6c03248ebd46e71ac313858e0afd5aa2fa81478c0e653242f3eb476"},
{file = "pycryptodome-3.9.7-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:07024fc364869eae8d6ac0d316e089956e6aeffe42dbdcf44fe1320d96becf7f"},
{file = "pycryptodome-3.9.7-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:426c188c83c10df71f053e04b4003b1437bae5cb37606440e498b00f160d71d0"},
{file = "pycryptodome-3.9.7-cp35-cp35m-win32.whl", hash = "sha256:d61b012baa8c2b659e9890011358455c0019a4108536b811602d2f638c40802a"},
{file = "pycryptodome-3.9.7-cp35-cp35m-win_amd64.whl", hash = "sha256:1f4752186298caf2e9ff5354f2e694d607ca7342aa313a62005235d46e28cf04"},
{file = "pycryptodome-3.9.7-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:767ad0fb5d23efc36a4d5c2fc608ac603f3de028909bcf59abc943e0d0bc5a36"},
{file = "pycryptodome-3.9.7-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:2fbc472e0b567318fe2052281d5a8c0ae70099b446679815f655e9fbc18c3a65"},
{file = "pycryptodome-3.9.7-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:9230fcb5d948c3fb40049bace4d33c5d254f8232c2c0bba05d2570aea3ba4520"},
{file = "pycryptodome-3.9.7-cp36-cp36m-win32.whl", hash = "sha256:8f06556a8f7ea7b1e42eff39726bb0dca1c251205debae64e6eebea3cd7b438a"},
{file = "pycryptodome-3.9.7-cp36-cp36m-win_amd64.whl", hash = "sha256:d6e1bc5c94873bec742afe2dfadce0d20445b18e75c47afc0c115b19e5dd38dd"},
{file = "pycryptodome-3.9.7-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:3ec3dc2f80f71fd0c955ce48b81bfaf8914c6f63a41a738f28885a1c4892968a"},
{file = "pycryptodome-3.9.7-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cff31f5a8977534f255f729d5d2467526f2b10563a30bbdade92223e0bf264bd"},
{file = "pycryptodome-3.9.7-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ed5761b37615a1f222c5345bbf45272ae2cf8c7dff88a4f53a1e9f977cbb6d95"},
{file = "pycryptodome-3.9.7-cp37-cp37m-win32.whl", hash = "sha256:f011cd0062e54658b7086a76f8cf0f4222812acc66e219e196ea2d0a8849d0ed"},
{file = "pycryptodome-3.9.7-cp37-cp37m-win_amd64.whl", hash = "sha256:626c0a1d4d83ec6303f970a17158114f75c3ba1736f7f2983f7b40a265861bd8"},
{file = "pycryptodome-3.9.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be56bde3312e022d9d1d6afa124556460ad5c844c2fc63642f6af723c098d35"},
{file = "pycryptodome-3.9.7-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c818dc1f3eace93ee50c2b6b5c2becf7c418fa5dd1ba6fc0ef7db279ea21d5e4"},
{file = "pycryptodome-3.9.7-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:09b6d6bcc01a4eb1a2b4deeff5aa602a108ec5aed8ac75ae554f97d1d7f0a5ad"},
{file = "pycryptodome-3.9.7-cp38-cp38-win32.whl", hash = "sha256:7ac729d9091ed5478af2b4a4f44f5335a98febbc008af619e4569a59fe503e40"},
{file = "pycryptodome-3.9.7-cp38-cp38-win_amd64.whl", hash = "sha256:c109a26a21f21f695d369ff9b87f5d43e0d6c768d8384e10bc74142bed2e092e"},
{file = "pycryptodome-3.9.7.tar.gz", hash = "sha256:f1add21b6d179179b3c177c33d18a2186a09cc0d3af41ff5ed3f377360b869f2"},
]
pynacl = [ pynacl = [
{file = "PyNaCl-1.3.0-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:2424c8b9f41aa65bbdbd7a64e73a7450ebb4aa9ddedc6a081e7afcc4c97f7621"}, {file = "PyNaCl-1.3.0-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:2424c8b9f41aa65bbdbd7a64e73a7450ebb4aa9ddedc6a081e7afcc4c97f7621"},
{file = "PyNaCl-1.3.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:30f36a9c70450c7878053fa1344aca0145fd47d845270b43a7ee9192a051bf39"}, {file = "PyNaCl-1.3.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:30f36a9c70450c7878053fa1344aca0145fd47d845270b43a7ee9192a051bf39"},
@ -1261,9 +1076,6 @@ pyreadline = [
{file = "pyreadline-2.1.win32.exe", hash = "sha256:65540c21bfe14405a3a77e4c085ecfce88724743a4ead47c66b84defcf82c32e"}, {file = "pyreadline-2.1.win32.exe", hash = "sha256:65540c21bfe14405a3a77e4c085ecfce88724743a4ead47c66b84defcf82c32e"},
{file = "pyreadline-2.1.zip", hash = "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1"}, {file = "pyreadline-2.1.zip", hash = "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1"},
] ]
pyrsistent = [
{file = "pyrsistent-0.16.0.tar.gz", hash = "sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3"},
]
python-dateutil = [ python-dateutil = [
{file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
{file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"},
@ -1272,35 +1084,35 @@ python-multipart = [
{file = "python-multipart-0.0.5.tar.gz", hash = "sha256:f7bb5f611fc600d15fa47b3974c8aa16e93724513b49b5f95c81e6624c83fa43"}, {file = "python-multipart-0.0.5.tar.gz", hash = "sha256:f7bb5f611fc600d15fa47b3974c8aa16e93724513b49b5f95c81e6624c83fa43"},
] ]
python-telegram-bot = [ python-telegram-bot = [
{file = "python-telegram-bot-12.6.1.tar.gz", hash = "sha256:935397390910291c8e41d7f2a06a3bb13d1d74d78b59562be9f8a330d4527049"}, {file = "python-telegram-bot-12.7.tar.gz", hash = "sha256:218b0583afb8baeefe6f2f1ddd8f1bb1ae30f0af3ce9160a372abd2cdf258eef"},
{file = "python_telegram_bot-12.6.1-py2.py3-none-any.whl", hash = "sha256:c7bdb5788ad2edea5c5c1bc8e50967fad68aa35245c209baadf74fc8ad00ff06"}, {file = "python_telegram_bot-12.7-py2.py3-none-any.whl", hash = "sha256:6878cc642114c8c116ceada41639a9df487f42d5478d9f34cae513cc5c260dee"},
] ]
pytz = [ pytz = [
{file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"},
{file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"},
] ]
regex = [ regex = [
{file = "regex-2020.4.4-cp27-cp27m-win32.whl", hash = "sha256:90742c6ff121a9c5b261b9b215cb476eea97df98ea82037ec8ac95d1be7a034f"}, {file = "regex-2020.5.7-cp27-cp27m-win32.whl", hash = "sha256:5493a02c1882d2acaaf17be81a3b65408ff541c922bfd002535c5f148aa29f74"},
{file = "regex-2020.4.4-cp27-cp27m-win_amd64.whl", hash = "sha256:24f4f4062eb16c5bbfff6a22312e8eab92c2c99c51a02e39b4eae54ce8255cd1"}, {file = "regex-2020.5.7-cp27-cp27m-win_amd64.whl", hash = "sha256:021a0ae4d2baeeb60a3014805a2096cb329bd6d9f30669b7ad0da51a9cb73349"},
{file = "regex-2020.4.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:08119f707f0ebf2da60d2f24c2f39ca616277bb67ef6c92b72cbf90cbe3a556b"}, {file = "regex-2020.5.7-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4df91094ced6f53e71f695c909d9bad1cca8761d96fd9f23db12245b5521136e"},
{file = "regex-2020.4.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c9423a150d3a4fc0f3f2aae897a59919acd293f4cb397429b120a5fcd96ea3db"}, {file = "regex-2020.5.7-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:7ce4a213a96d6c25eeae2f7d60d4dad89ac2b8134ec3e69db9bc522e2c0f9388"},
{file = "regex-2020.4.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:c087bff162158536387c53647411db09b6ee3f9603c334c90943e97b1052a156"}, {file = "regex-2020.5.7-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b059e2476b327b9794c792c855aa05531a3f3044737e455d283c7539bd7534d"},
{file = "regex-2020.4.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:1cbe0fa0b7f673400eb29e9ef41d4f53638f65f9a2143854de6b1ce2899185c3"}, {file = "regex-2020.5.7-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:652ab4836cd5531d64a34403c00ada4077bb91112e8bcdae933e2eae232cf4a8"},
{file = "regex-2020.4.4-cp36-cp36m-win32.whl", hash = "sha256:0ce9537396d8f556bcfc317c65b6a0705320701e5ce511f05fc04421ba05b8a8"}, {file = "regex-2020.5.7-cp36-cp36m-win32.whl", hash = "sha256:1e2255ae938a36e9bd7db3b93618796d90c07e5f64dd6a6750c55f51f8b76918"},
{file = "regex-2020.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:7e1037073b1b7053ee74c3c6c0ada80f3501ec29d5f46e42669378eae6d4405a"}, {file = "regex-2020.5.7-cp36-cp36m-win_amd64.whl", hash = "sha256:8127ca2bf9539d6a64d03686fd9e789e8c194fc19af49b69b081f8c7e6ecb1bc"},
{file = "regex-2020.4.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4385f12aa289d79419fede43f979e372f527892ac44a541b5446617e4406c468"}, {file = "regex-2020.5.7-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f7f2f4226db6acd1da228adf433c5c3792858474e49d80668ea82ac87cf74a03"},
{file = "regex-2020.4.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a58dd45cb865be0ce1d5ecc4cfc85cd8c6867bea66733623e54bd95131f473b6"}, {file = "regex-2020.5.7-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2bc6a17a7fa8afd33c02d51b6f417fc271538990297167f68a98cae1c9e5c945"},
{file = "regex-2020.4.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ccccdd84912875e34c5ad2d06e1989d890d43af6c2242c6fcfa51556997af6cd"}, {file = "regex-2020.5.7-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:b7c9f65524ff06bf70c945cd8d8d1fd90853e27ccf86026af2afb4d9a63d06b1"},
{file = "regex-2020.4.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:ea4adf02d23b437684cd388d557bf76e3afa72f7fed5bbc013482cc00c816948"}, {file = "regex-2020.5.7-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:fa09da4af4e5b15c0e8b4986a083f3fd159302ea115a6cc0649cd163435538b8"},
{file = "regex-2020.4.4-cp37-cp37m-win32.whl", hash = "sha256:2294f8b70e058a2553cd009df003a20802ef75b3c629506be20687df0908177e"}, {file = "regex-2020.5.7-cp37-cp37m-win32.whl", hash = "sha256:669a8d46764a09f198f2e91fc0d5acdac8e6b620376757a04682846ae28879c4"},
{file = "regex-2020.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:e91ba11da11cf770f389e47c3f5c30473e6d85e06d7fd9dcba0017d2867aab4a"}, {file = "regex-2020.5.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b5b5b2e95f761a88d4c93691716ce01dc55f288a153face1654f868a8034f494"},
{file = "regex-2020.4.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5635cd1ed0a12b4c42cce18a8d2fb53ff13ff537f09de5fd791e97de27b6400e"}, {file = "regex-2020.5.7-cp38-cp38-manylinux1_i686.whl", hash = "sha256:0ff50843535593ee93acab662663cb2f52af8e31c3f525f630f1dc6156247938"},
{file = "regex-2020.4.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:23069d9c07e115537f37270d1d5faea3e0bdded8279081c4d4d607a2ad393683"}, {file = "regex-2020.5.7-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1b17bf37c2aefc4cac8436971fe6ee52542ae4225cfc7762017f7e97a63ca998"},
{file = "regex-2020.4.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c162a21e0da33eb3d31a3ac17a51db5e634fc347f650d271f0305d96601dc15b"}, {file = "regex-2020.5.7-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:04d6e948ef34d3eac133bedc0098364a9e635a7914f050edb61272d2ddae3608"},
{file = "regex-2020.4.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:fb95debbd1a824b2c4376932f2216cc186912e389bdb0e27147778cf6acb3f89"}, {file = "regex-2020.5.7-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:5b741ecc3ad3e463d2ba32dce512b412c319993c1bb3d999be49e6092a769fb2"},
{file = "regex-2020.4.4-cp38-cp38-win32.whl", hash = "sha256:2a3bf8b48f8e37c3a40bb3f854bf0121c194e69a650b209628d951190b862de3"}, {file = "regex-2020.5.7-cp38-cp38-win32.whl", hash = "sha256:099568b372bda492be09c4f291b398475587d49937c659824f891182df728cdf"},
{file = "regex-2020.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bfed051dbff32fd8945eccca70f5e22b55e4148d2a8a45141a3b053d6455ae3"}, {file = "regex-2020.5.7-cp38-cp38-win_amd64.whl", hash = "sha256:3ab5e41c4ed7cd4fa426c50add2892eb0f04ae4e73162155cd668257d02259dd"},
{file = "regex-2020.4.4.tar.gz", hash = "sha256:295badf61a51add2d428a46b8580309c520d8b26e769868b922750cf3ce67142"}, {file = "regex-2020.5.7.tar.gz", hash = "sha256:73a10404867b835f1b8a64253e4621908f0d71150eb4e97ab2e7e441b53e9451"},
] ]
requests = [ requests = [
{file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"}, {file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"},
@ -1311,8 +1123,8 @@ riotwatcher = [
{file = "riotwatcher-2.7.1.tar.gz", hash = "sha256:5349271c7e00637b7619491a6070e66603705db60558ea2a690e7016f6e6d9a4"}, {file = "riotwatcher-2.7.1.tar.gz", hash = "sha256:5349271c7e00637b7619491a6070e66603705db60558ea2a690e7016f6e6d9a4"},
] ]
royalnet = [ royalnet = [
{file = "royalnet-5.7.7-py3-none-any.whl", hash = "sha256:e426c5fa21ee81deccd5ba35a17bd110d9de8382713b09851647fa71f3f9e3fa"}, {file = "royalnet-5.8.7-py3-none-any.whl", hash = "sha256:5fee088e02ec375b580af48e03894db2ca2edd10c19f7fcbfdacf0a6e07622e7"},
{file = "royalnet-5.7.7.tar.gz", hash = "sha256:6c7724296df890ea61f9f9f46efa4270e857dbe84a76521675fec7a163321bf5"}, {file = "royalnet-5.8.7.tar.gz", hash = "sha256:a72fd52e2ed9fa2a8163859ac93b517ec684348d44f5c0b09146c9880430f67b"},
] ]
royalspells = [ royalspells = [
{file = "royalspells-3.2.tar.gz", hash = "sha256:2bd4a9a66514532e35c02c3907425af48c7cb292364c4843c795719a82b25dfe"}, {file = "royalspells-3.2.tar.gz", hash = "sha256:2bd4a9a66514532e35c02c3907425af48c7cb292364c4843c795719a82b25dfe"},
@ -1369,12 +1181,8 @@ tornado = [
{file = "tornado-6.0.4.tar.gz", hash = "sha256:0fe2d45ba43b00a41cd73f8be321a44936dc1aba233dee979f17a042b83eb6dc"}, {file = "tornado-6.0.4.tar.gz", hash = "sha256:0fe2d45ba43b00a41cd73f8be321a44936dc1aba233dee979f17a042b83eb6dc"},
] ]
tzlocal = [ tzlocal = [
{file = "tzlocal-2.0.0-py2.py3-none-any.whl", hash = "sha256:11c9f16e0a633b4b60e1eede97d8a46340d042e67b670b290ca526576e039048"}, {file = "tzlocal-2.1-py2.py3-none-any.whl", hash = "sha256:e2cb6c6b5b604af38597403e9852872d7f534962ae2954c7f35efcb1ccacf4a4"},
{file = "tzlocal-2.0.0.tar.gz", hash = "sha256:949b9dd5ba4be17190a80c0268167d7e6c92c62b30026cf9764caf3e308e5590"}, {file = "tzlocal-2.1.tar.gz", hash = "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44"},
]
unpaddedbase64 = [
{file = "unpaddedbase64-1.1.0-py2-none-any.whl", hash = "sha256:8917367e4e915b7dce1a72a99db8798c9f3d0d9a74cdd9aafac6d7c65ca495c5"},
{file = "unpaddedbase64-1.1.0-py2.py3-none-any.whl", hash = "sha256:81cb4eaaa28cc6a282dd3f2c3855eaa1fbaafa736b5ee64df69889e20540a339"},
] ]
urllib3 = [ urllib3 = [
{file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"},
@ -1443,6 +1251,6 @@ yarl = [
{file = "yarl-1.4.2.tar.gz", hash = "sha256:58cd9c469eced558cd81aa3f484b2924e8897049e06889e8ff2510435b7ef74b"}, {file = "yarl-1.4.2.tar.gz", hash = "sha256:58cd9c469eced558cd81aa3f484b2924e8897049e06889e8ff2510435b7ef74b"},
] ]
youtube-dl = [ youtube-dl = [
{file = "youtube_dl-2020.3.24-py2.py3-none-any.whl", hash = "sha256:c0be39ea9bca72fa02a0d2d043c5e9bd8ea8e0fe79705e891161d6fcd29da59e"}, {file = "youtube_dl-2020.5.8-py2.py3-none-any.whl", hash = "sha256:0b5d3280522469968eb62eecb1f966f422b2be22f000a801bf87cb2172d8ea39"},
{file = "youtube_dl-2020.3.24.tar.gz", hash = "sha256:4b03efe439f7cae26eba909821d1df00a9a4eb82741cb2e8b78fe29702bd4633"}, {file = "youtube_dl-2020.5.8.tar.gz", hash = "sha256:22da6788b55b7b267c6d59bcdfaf10e67a9ac980976d50d29a670473ad2a05bb"},
] ]

View file

@ -2,7 +2,7 @@
[tool.poetry] [tool.poetry]
name = "royalpack" name = "royalpack"
version = "5.7.15" version = "5.8.0"
description = "A Royalnet command pack for the Royal Games community" description = "A Royalnet command pack for the Royal Games community"
authors = ["Stefano Pigozzi <ste.pigozzi@gmail.com>"] authors = ["Stefano Pigozzi <ste.pigozzi@gmail.com>"]
license = "AGPL-3.0+" license = "AGPL-3.0+"
@ -25,7 +25,7 @@
steam = "^0.9.1" steam = "^0.9.1"
[tool.poetry.dependencies.royalnet] [tool.poetry.dependencies.royalnet]
version = "~5.7.7" version = "~5.8.7"
# Maybe... there is a way to make these selectable? # Maybe... there is a way to make these selectable?
extras = [ extras = [
"telegram", "telegram",
@ -36,7 +36,6 @@
"sentry", "sentry",
"herald", "herald",
"coloredlogs", "coloredlogs",
"matrix"
] ]
# Development dependencies # Development dependencies

View file

@ -1,14 +1,15 @@
from typing import *
import asyncio import asyncio
import logging import logging
import sentry_sdk
import aiohttp import aiohttp
from typing import *
from royalnet.commands import * from royalnet.commands import *
from royalnet.utils import * from royalnet.utils import *
from royalnet.serf.telegram.escape import escape as tg_escape from royalnet.serf.telegram.escape import escape as tg_escape
from sqlalchemy import or_, and_
from ..tables import Steam, Brawlhalla, BrawlhallaDuo from ..tables import Steam, Brawlhalla, BrawlhallaDuo
from ..types import BrawlhallaRank, BrawlhallaMetal, BrawlhallaTier from ..types import BrawlhallaRank, BrawlhallaMetal, BrawlhallaTier
from sqlalchemy import or_, and_
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View file

@ -1,3 +1,4 @@
from typing import *
import telegram import telegram
from royalnet.commands import * from royalnet.commands import *

View file

@ -1,3 +1,4 @@
from typing import *
from royalnet.commands import * from royalnet.commands import *

View file

@ -3,7 +3,8 @@ import logging
import asyncio import asyncio
import datetime import datetime
import royalnet.commands as rc import royalnet.commands as rc
from royalnet.utils import asyncify import royalnet.utils as ru
from ..tables import Cvstats from ..tables import Cvstats
@ -101,7 +102,7 @@ class CvstatsCommand(rc.Command):
log.debug("Saving to database...") log.debug("Saving to database...")
db_session.add(cvstats) db_session.add(cvstats)
await asyncify(db_session.commit) await ru.asyncify(db_session.commit)
log.debug("Done!") log.debug("Done!")
async def _updater(self, period: int): async def _updater(self, period: int):

View file

@ -1,11 +1,12 @@
from typing import *
import re import re
import datetime import datetime
import telegram import telegram
import aiohttp import aiohttp
from typing import * import royalnet.commands as rc
from royalnet.commands import * import royalnet.utils as ru
from royalnet.utils import asyncify import royalnet.backpack.tables as rbt
from royalnet.backpack.tables import *
from ..tables import * from ..tables import *
@ -13,7 +14,7 @@ async def to_imgur(imgur_api_key, photosizes: List[telegram.PhotoSize], caption=
# Select the largest photo # Select the largest photo
largest_photo = sorted(photosizes, key=lambda p: p.width * p.height)[-1] largest_photo = sorted(photosizes, key=lambda p: p.width * p.height)[-1]
# Get the photo url # Get the photo url
photo_file: telegram.File = await asyncify(largest_photo.get_file) photo_file: telegram.File = await ru.asyncify(largest_photo.get_file)
# Forward the url to imgur, as an upload # Forward the url to imgur, as an upload
async with aiohttp.request("post", "https://api.imgur.com/3/upload", data={ async with aiohttp.request("post", "https://api.imgur.com/3/upload", data={
"image": photo_file.file_path, "image": photo_file.file_path,
@ -25,18 +26,18 @@ async def to_imgur(imgur_api_key, photosizes: List[telegram.PhotoSize], caption=
}) as request: }) as request:
response = await request.json() response = await request.json()
if not response["success"]: if not response["success"]:
raise CommandError("Imgur returned an error in the image upload.") raise rc.CommandError("Imgur returned an error in the image upload.")
return response["data"]["link"] return response["data"]["link"]
class DiarioCommand(Command): class DiarioCommand(rc.Command):
name: str = "diario" name: str = "diario"
description: str = "Aggiungi una citazione al Diario." description: str = "Aggiungi una citazione al Diario."
syntax = "[!] \"{testo}\" --[autore], [contesto]" syntax = "[!] \"{testo}\" --[autore], [contesto]"
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if self.interface.name == "telegram": if self.interface.name == "telegram":
message: telegram.Message = data.message message: telegram.Message = data.message
reply: telegram.Message = message.reply_to_message reply: telegram.Message = message.reply_to_message
@ -70,9 +71,9 @@ class DiarioCommand(Command):
media_url = None media_url = None
# Ensure there is a text or an image # Ensure there is a text or an image
if not (text or media_url): if not (text or media_url):
raise InvalidInputError("Il messaggio a cui hai risposto non contiene testo o immagini.") raise rc.InvalidInputError("Il messaggio a cui hai risposto non contiene testo o immagini.")
# Find the Royalnet account associated with the sender # Find the Royalnet account associated with the sender
quoted_tg = await asyncify(data.session.query(self.alchemy.get(Telegram)) quoted_tg = await ru.asyncify(data.session.query(self.alchemy.get(rbt.Telegram))
.filter_by(tg_id=reply.from_user.id) .filter_by(tg_id=reply.from_user.id)
.one_or_none) .one_or_none)
quoted_account = quoted_tg.user if quoted_tg is not None else None quoted_account = quoted_tg.user if quoted_tg is not None else None
@ -121,8 +122,8 @@ class DiarioCommand(Command):
context = None context = None
# Find if there's a Royalnet account associated with the quoted name # Find if there's a Royalnet account associated with the quoted name
if quoted is not None: if quoted is not None:
quoted_alias = await asyncify( quoted_alias = await ru.asyncify(
data.session.query(self.alchemy.get(Alias)) data.session.query(self.alchemy.get(rbt.Alias))
.filter_by(alias=quoted.lower()).one_or_none .filter_by(alias=quoted.lower()).one_or_none
) )
else: else:
@ -136,7 +137,7 @@ class DiarioCommand(Command):
context = None context = None
# Ensure there is a text or an image # Ensure there is a text or an image
if not (text or media_url): if not (text or media_url):
raise InvalidInputError("Manca il testo o l'immagine da inserire nel diario.") raise rc.InvalidInputError("Manca il testo o l'immagine da inserire nel diario.")
# Create the diario quote # Create the diario quote
diario = self.alchemy.get(Diario)(creator=creator, diario = self.alchemy.get(Diario)(creator=creator,
quoted_account=quoted_account, quoted_account=quoted_account,
@ -147,7 +148,7 @@ class DiarioCommand(Command):
media_url=media_url, media_url=media_url,
spoiler=spoiler) spoiler=spoiler)
data.session.add(diario) data.session.add(diario)
await asyncify(data.session.commit) await ru.asyncify(data.session.commit)
await data.reply(f"{str(diario)}") await data.reply(f"{str(diario)}")
else: else:
# Find the creator of the quotes # Find the creator of the quotes
@ -172,7 +173,7 @@ class DiarioCommand(Command):
timestamp = datetime.datetime.now() timestamp = datetime.datetime.now()
# Ensure there is some text # Ensure there is some text
if not text: if not text:
raise InvalidInputError("Manca il testo o l'immagine da inserire nel diario.") raise rc.InvalidInputError("Manca il testo o l'immagine da inserire nel diario.")
# Or a quoted # Or a quoted
if not quoted: if not quoted:
quoted = None quoted = None
@ -180,8 +181,8 @@ class DiarioCommand(Command):
context = None context = None
# Find if there's a Royalnet account associated with the quoted name # Find if there's a Royalnet account associated with the quoted name
if quoted is not None: if quoted is not None:
quoted_alias = await asyncify( quoted_alias = await ru.asyncify(
data.session.query(self.alchemy.get(Alias)) data.session.query(self.alchemy.get(rbt.Alias))
.filter_by(alias=quoted.lower()) .filter_by(alias=quoted.lower())
.one_or_none .one_or_none
) )
@ -189,7 +190,7 @@ class DiarioCommand(Command):
quoted_alias = None quoted_alias = None
quoted_account = quoted_alias.user if quoted_alias is not None else None quoted_account = quoted_alias.user if quoted_alias is not None else None
if quoted_alias is not None and quoted_account is None: if quoted_alias is not None and quoted_account is None:
raise UserError("Il nome dell'autore è ambiguo, quindi la riga non è stata aggiunta.\n" raise rc.UserError("Il nome dell'autore è ambiguo, quindi la riga non è stata aggiunta.\n"
"Per piacere, ripeti il comando con un nome più specifico!") "Per piacere, ripeti il comando con un nome più specifico!")
# Create the diario quote # Create the diario quote
diario = self.alchemy.Diario(creator=creator, diario = self.alchemy.Diario(creator=creator,
@ -201,5 +202,5 @@ class DiarioCommand(Command):
media_url=None, media_url=None,
spoiler=spoiler) spoiler=spoiler)
data.session.add(diario) data.session.add(diario)
await asyncify(data.session.commit) await ru.asyncify(data.session.commit)
await data.reply(f"{str(diario)}") await data.reply(f"{str(diario)}")

View file

@ -1,9 +1,11 @@
from royalnet.commands import * from typing import *
from royalnet.utils import * import royalnet.commands as rc
import royalnet.utils as ru
from ..tables import Diario from ..tables import Diario
class DiarioquoteCommand(Command): class DiarioquoteCommand(rc.Command):
name: str = "diarioquote" name: str = "diarioquote"
description: str = "Cita una riga del diario." description: str = "Cita una riga del diario."
@ -12,12 +14,12 @@ class DiarioquoteCommand(Command):
syntax = "{id}" syntax = "{id}"
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
try: try:
entry_id = int(args[0].lstrip("#")) entry_id = int(args[0].lstrip("#"))
except ValueError: except ValueError:
raise CommandError("L'id che hai specificato non è valido.") raise rc.CommandError("L'id che hai specificato non è valido.")
entry: Diario = await asyncify(data.session.query(self.alchemy.get(Diario)).get, entry_id) entry: Diario = await ru.asyncify(data.session.query(self.alchemy.get(Diario)).get, entry_id)
if entry is None: if entry is None:
raise CommandError("Nessuna riga con quell'id trovata.") raise rc.CommandError("Nessuna riga con quell'id trovata.")
await data.reply(f" {entry}") await data.reply(f" {entry}")

View file

@ -1,11 +1,12 @@
from typing import * from typing import *
from royalnet.commands import * import royalnet.commands as rc
from royalnet.utils import * import royalnet.utils as ru
from ..tables import Diario
from sqlalchemy import func from sqlalchemy import func
from ..tables import Diario
class DiarioshuffleCommand(Command):
class DiarioshuffleCommand(rc.Command):
name: str = "diarioshuffle" name: str = "diarioshuffle"
description: str = "Cita una riga casuale del diario." description: str = "Cita una riga casuale del diario."
@ -14,9 +15,9 @@ class DiarioshuffleCommand(Command):
syntax = "" syntax = ""
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
DiarioT = self.alchemy.get(Diario) DiarioT = self.alchemy.get(Diario)
entry: List[Diario] = await asyncify( entry: List[Diario] = await ru.asyncify(
data.session data.session
.query(DiarioT) .query(DiarioT)
.order_by(func.random()) .order_by(func.random())
@ -24,5 +25,5 @@ class DiarioshuffleCommand(Command):
.one_or_none .one_or_none
) )
if entry is None: if entry is None:
raise CommandError("Nessuna riga del diario trovata.") raise rc.CommandError("Nessuna riga del diario trovata.")
await data.reply(f" {entry}") await data.reply(f" {entry}")

View file

@ -1,18 +1,19 @@
from typing import *
import asyncio import asyncio
import logging import logging
import sentry_sdk import sentry_sdk
import aiohttp import aiohttp
from typing import * import royalnet.commands as rc
from royalnet.commands import * import royalnet.utils as ru
from royalnet.utils import * import royalnet.serf.telegram as rst
from royalnet.serf.telegram.escape import escape as tg_escape
from ..tables import Steam, Dota from ..tables import Steam, Dota
from ..types import DotaRank from ..types import DotaRank
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class DotaCommand(Command): class DotaCommand(rc.Command):
name: str = "dota" name: str = "dota"
aliases = ["dota2", "doto", "doto2", "dotka", "dotka2"] aliases = ["dota2", "doto", "doto2", "dotka", "dotka2"]
@ -21,7 +22,7 @@ class DotaCommand(Command):
syntax: str = "" syntax: str = ""
def __init__(self, interface: CommandInterface): def __init__(self, interface: rc.CommandInterface):
super().__init__(interface) super().__init__(interface)
if self.interface.name == "telegram" and self.config["Dota"]["updater"]: if self.interface.name == "telegram" and self.config["Dota"]["updater"]:
self.loop.create_task(self._updater(7200)) self.loop.create_task(self._updater(7200))
@ -30,7 +31,7 @@ class DotaCommand(Command):
client = self.serf.client client = self.serf.client
await self.serf.api_call(client.send_message, await self.serf.api_call(client.send_message,
chat_id=self.config["Telegram"]["main_group_id"], chat_id=self.config["Telegram"]["main_group_id"],
text=tg_escape(message), text=rst.escape(message),
parse_mode="HTML", parse_mode="HTML",
disable_webpage_preview=True) disable_webpage_preview=True)
@ -85,7 +86,7 @@ class DotaCommand(Command):
# Get profile data # Get profile data
async with session.get(f"https://api.opendota.com/api/players/{steam.steamid.as_32}/") as response: async with session.get(f"https://api.opendota.com/api/players/{steam.steamid.as_32}/") as response:
if response.status != 200: if response.status != 200:
raise ExternalError(f"OpenDota / returned {response.status}!") raise rc.ExternalError(f"OpenDota / returned {response.status}!")
p = await response.json() p = await response.json()
# No such user # No such user
if "profile" not in p: if "profile" not in p:
@ -94,7 +95,7 @@ class DotaCommand(Command):
# Get win/loss data # Get win/loss data
async with session.get(f"https://api.opendota.com/api/players/{steam.steamid.as_32}/wl") as response: async with session.get(f"https://api.opendota.com/api/players/{steam.steamid.as_32}/wl") as response:
if response.status != 200: if response.status != 200:
raise ExternalError(f"OpenDota /wl returned {response.status}!") raise rc.ExternalError(f"OpenDota /wl returned {response.status}!")
wl = await response.json() wl = await response.json()
# No such user # No such user
if wl["win"] == 0 and wl["lose"] == 0: if wl["win"] == 0 and wl["lose"] == 0:
@ -127,12 +128,12 @@ class DotaCommand(Command):
sentry_sdk.capture_exception(e) sentry_sdk.capture_exception(e)
log.error(f"Error while updating {steam.user.username}: {e}") log.error(f"Error while updating {steam.user.username}: {e}")
await asyncio.sleep(1) await asyncio.sleep(1)
await asyncify(session.commit) await ru.asyncify(session.commit)
session.close() session.close()
log.info(f"Sleeping for {period}s") log.info(f"Sleeping for {period}s")
await asyncio.sleep(period) await asyncio.sleep(period)
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
author = await data.get_author(error_if_none=True) author = await data.get_author(error_if_none=True)
found_something = False found_something = False
@ -146,5 +147,5 @@ class DotaCommand(Command):
message += self._display(steam.dota) message += self._display(steam.dota)
message += "\n" message += "\n"
if not found_something: if not found_something:
raise UserError("Nessun account di Dota 2 trovato.") raise rc.UserError("Nessun account di Dota 2 trovato.")
await data.reply(message) await data.reply(message)

View file

@ -165,7 +165,10 @@ class EatCommand(Command):
"mia sul fiume": "💧 Hai mangiato il miglior piatto al mondo, la {food}, esclusivo ai membri Royal Games.\n" "mia sul fiume": "💧 Hai mangiato il miglior piatto al mondo, la {food}, esclusivo ai membri Royal Games.\n"
"[i]Nessuno, tranne il bot, sa di cosa è fatta esattamente, ma una cosa è certa: è " "[i]Nessuno, tranne il bot, sa di cosa è fatta esattamente, ma una cosa è certa: è "
"buonissima![/i]", "buonissima![/i]",
"angelo": "👼 Oh mio dio! E' un {food}!\n[i]Ora hai un digramma ad onda blu.[/i]" "angelo": "👼 Oh mio dio! E' un {food}!\n[i]Ora hai un digramma ad onda blu.[/i]",
"terraria": "🌳 Hai provato a mangiare {food}, ma non ne sei stato all'Altezza (Coniglio).\n[i]Prova a mangiare qualcos'altro...[/i]",
"cooked fish": "🐟 Hai mangiato {food}.\n[i]Ora sei Well Fed per 20 minuti.[/i]"
} }
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: CommandArgs, data: CommandData) -> None:

View file

@ -1,5 +1,7 @@
from typing import *
import random import random
import royalnet.commands as rc import royalnet.commands as rc
from .play import PlayCommand from .play import PlayCommand

View file

@ -1,8 +1,9 @@
from typing import *
import random import random
from royalnet.commands import * import royalnet.commands as rc
class EmojifyCommand(Command): class EmojifyCommand(rc.Command):
name: str = "emojify" name: str = "emojify"
description: str = "Converti un messaggio in emoji." description: str = "Converti un messaggio in emoji."
@ -94,6 +95,6 @@ class EmojifyCommand(Command):
new_string = new_string.replace(key, selected_emoji) new_string = new_string.replace(key, selected_emoji)
return new_string return new_string
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
string = args.joined(require_at_least=1) string = args.joined(require_at_least=1)
await data.reply(self._emojify(string)) await data.reply(self._emojify(string))

View file

@ -1,9 +1,9 @@
import royalnet from typing import *
from royalnet.commands import * import royalnet.commands as rc
from royalnet.backpack.tables import * import royalnet.backpack.tables as rbt
class EvalCommand(Command): class EvalCommand(rc.Command):
# oh god if there is a security vulnerability # oh god if there is a security vulnerability
name: str = "eval" name: str = "eval"
@ -11,13 +11,13 @@ class EvalCommand(Command):
syntax: str = "{espressione}" syntax: str = "{espressione}"
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
user: User = await data.get_author(error_if_none=True) user: rbt.User = await data.get_author(error_if_none=True)
if user.role != "Admin": if "admin" not in user.roles:
raise CommandError("Non sei autorizzato a eseguire codice arbitrario!\n" raise rc.CommandError("Non sei autorizzato a eseguire codice arbitrario!\n"
"(Sarebbe un po' pericoloso se te lo lasciassi eseguire, non trovi?)") "(Sarebbe un po' pericoloso se te lo lasciassi eseguire, non trovi?)")
try: try:
result = eval(args.joined(require_at_least=1)) result = eval(args.joined(require_at_least=1))
except Exception as e: except Exception as e:
raise CommandError(f"Eval fallito: {e}") raise rc.CommandError(f"Eval fallito: {e}")
await data.reply(repr(result)) await data.reply(repr(result))

View file

@ -1,9 +1,9 @@
import royalnet from typing import *
from royalnet.commands import * import royalnet.commands as rc
from royalnet.backpack.tables import * import royalnet.backpack.tables as rbt
class ExecCommand(Command): class ExecCommand(rc.Command):
# oh god if there is a security vulnerability # oh god if there is a security vulnerability
name: str = "exec" name: str = "exec"
@ -11,13 +11,13 @@ class ExecCommand(Command):
syntax: str = "{script}" syntax: str = "{script}"
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
user: User = await data.get_author(error_if_none=True) user: rbt.User = await data.get_author(error_if_none=True)
if user.role != "Admin": if "admin" not in user.roles:
raise CommandError("Non sei autorizzato a eseguire codice arbitrario!\n" raise rc.CommandError("Non sei autorizzato a eseguire codice arbitrario!\n"
"(Sarebbe un po' pericoloso se te lo lasciassi eseguire, non trovi?)") "(Sarebbe un po' pericoloso se te lo lasciassi eseguire, non trovi?)")
try: try:
exec(args.joined(require_at_least=1)) exec(args.joined(require_at_least=1))
except Exception as e: except Exception as e:
raise CommandError(f"Esecuzione fallita: {e}") raise rc.CommandError(f"Esecuzione fallita: {e}")
await data.reply(f"✅ Fatto!") await data.reply(f"✅ Fatto!")

View file

@ -1,7 +1,9 @@
from .play import PlayCommand from typing import *
from royalnet.commands import *
import aiohttp import aiohttp
import urllib.parse import urllib.parse
import royalnet.commands as rc
from .play import PlayCommand
class FunkwhaleCommand(PlayCommand): class FunkwhaleCommand(PlayCommand):
@ -23,5 +25,5 @@ class FunkwhaleCommand(PlayCommand):
f"/api/v1/search?query={search}") as response: f"/api/v1/search?query={search}") as response:
j = await response.json() j = await response.json()
if len(j["tracks"]) < 1: if len(j["tracks"]) < 1:
raise UserError("Nessun file audio trovato con il nome richiesto.") raise rc.UserError("Nessun file audio trovato con il nome richiesto.")
return [f'{self.config["Funkwhale"]["instance_url"]}{j["tracks"][0]["listen_url"]}'] return [f'{self.config["Funkwhale"]["instance_url"]}{j["tracks"][0]["listen_url"]}']

View file

@ -1,7 +1,9 @@
from .play import PlayCommand from typing import *
from royalnet.commands import *
import aiohttp import aiohttp
import urllib.parse import urllib.parse
import royalnet.commands as rc
from .play import PlayCommand
class FunkwhalealbumCommand(PlayCommand): class FunkwhalealbumCommand(PlayCommand):
@ -23,6 +25,6 @@ class FunkwhalealbumCommand(PlayCommand):
f"/api/v1/search?query={search}") as response: f"/api/v1/search?query={search}") as response:
j = await response.json() j = await response.json()
if len(j["albums"]) < 1: if len(j["albums"]) < 1:
raise UserError("Nessun file audio trovato con il nome richiesto.") raise rc.UserError("Nessun file audio trovato con il nome richiesto.")
album = j["albums"][0] album = j["albums"][0]
return [f'{self.config["Funkwhale"]["instance_url"]}{track["listen_url"]}' for track in album["tracks"]] return [f'{self.config["Funkwhale"]["instance_url"]}{track["listen_url"]}' for track in album["tracks"]]

View file

@ -1,7 +1,9 @@
from .play import PlayCommand from typing import *
from royalnet.commands import *
import aiohttp import aiohttp
import urllib.parse import urllib.parse
import royalnet.commands as rc
from .play import PlayCommand
class FunkwhaleplaylistCommand(PlayCommand): class FunkwhaleplaylistCommand(PlayCommand):
@ -23,7 +25,7 @@ class FunkwhaleplaylistCommand(PlayCommand):
f"/api/v1/playlists/?q={search}&ordering=-creation_date&playable=true") as response: f"/api/v1/playlists/?q={search}&ordering=-creation_date&playable=true") as response:
j = await response.json() j = await response.json()
if len(j["results"]) < 1: if len(j["results"]) < 1:
raise UserError("Nessuna playlist trovata con il nome richiesto.") raise rc.UserError("Nessuna playlist trovata con il nome richiesto.")
playlist = j["results"][0] playlist = j["results"][0]
playlist_id = playlist["id"] playlist_id = playlist["id"]
async with session.get(self.config["Funkwhale"]["instance_url"] + async with session.get(self.config["Funkwhale"]["instance_url"] +

View file

@ -1,3 +1,4 @@
from typing import *
from .play import PlayCommand from .play import PlayCommand

View file

@ -1,8 +1,10 @@
from .lazyplay import LazyplayCommand from typing import *
from royalnet.commands import * import royalnet.commands as rc
import aiohttp import aiohttp
import urllib.parse import urllib.parse
from .lazyplay import LazyplayCommand
class LazyfunkwhaleCommand(LazyplayCommand): class LazyfunkwhaleCommand(LazyplayCommand):
name: str = "lazyfunkwhale" name: str = "lazyfunkwhale"
@ -23,5 +25,5 @@ class LazyfunkwhaleCommand(LazyplayCommand):
f"/api/v1/search?query={search}") as response: f"/api/v1/search?query={search}") as response:
j = await response.json() j = await response.json()
if len(j["tracks"]) < 1: if len(j["tracks"]) < 1:
raise UserError("Nessun file audio trovato con il nome richiesto.") raise rc.UserError("Nessun file audio trovato con il nome richiesto.")
return [f'{self.config["Funkwhale"]["instance_url"]}{j["tracks"][0]["listen_url"]}'] return [f'{self.config["Funkwhale"]["instance_url"]}{j["tracks"][0]["listen_url"]}']

View file

@ -1,8 +1,10 @@
from .lazyplay import LazyplayCommand from typing import *
from royalnet.commands import * import royalnet.commands as rc
import aiohttp import aiohttp
import urllib.parse import urllib.parse
from .lazyplay import LazyplayCommand
class LazyfunkwhalealbumCommand(LazyplayCommand): class LazyfunkwhalealbumCommand(LazyplayCommand):
name: str = "lazyfunkwhalealbum" name: str = "lazyfunkwhalealbum"
@ -23,6 +25,6 @@ class LazyfunkwhalealbumCommand(LazyplayCommand):
f"/api/v1/search?query={search}") as response: f"/api/v1/search?query={search}") as response:
j = await response.json() j = await response.json()
if len(j["albums"]) < 1: if len(j["albums"]) < 1:
raise UserError("Nessun file audio trovato con il nome richiesto.") raise rc.UserError("Nessun file audio trovato con il nome richiesto.")
album = j["albums"][0] album = j["albums"][0]
return [f'{self.config["Funkwhale"]["instance_url"]}{track["listen_url"]}' for track in album["tracks"]] return [f'{self.config["Funkwhale"]["instance_url"]}{track["listen_url"]}' for track in album["tracks"]]

View file

@ -1,7 +1,7 @@
from .lazyplay import LazyplayCommand
from royalnet.commands import *
import aiohttp import aiohttp
import urllib.parse import urllib.parse
import royalnet.commands as rc
from .lazyplay import LazyplayCommand
class LazyfunkwhaleplaylistCommand(LazyplayCommand): class LazyfunkwhaleplaylistCommand(LazyplayCommand):
@ -23,7 +23,7 @@ class LazyfunkwhaleplaylistCommand(LazyplayCommand):
f"/api/v1/playlists/?q={search}&ordering=-creation_date&playable=true") as response: f"/api/v1/playlists/?q={search}&ordering=-creation_date&playable=true") as response:
j = await response.json() j = await response.json()
if len(j["results"]) < 1: if len(j["results"]) < 1:
raise UserError("Nessuna playlist trovata con il nome richiesto.") raise rc.UserError("Nessuna playlist trovata con il nome richiesto.")
playlist = j["results"][0] playlist = j["results"][0]
playlist_id = playlist["id"] playlist_id = playlist["id"]
async with session.get(self.config["Funkwhale"]["instance_url"] + async with session.get(self.config["Funkwhale"]["instance_url"] +

View file

@ -1,3 +1,4 @@
from typing import *
from .lazyplay import LazyplayCommand from .lazyplay import LazyplayCommand

View file

@ -1,8 +1,10 @@
from .lazyplay import LazyplayCommand from typing import *
from royalnet.commands import * import royalnet.commands as rc
import aiohttp import aiohttp
import urllib.parse import urllib.parse
from .lazyplay import LazyplayCommand
class LazypeertubeCommand(LazyplayCommand): class LazypeertubeCommand(LazyplayCommand):
name: str = "lazypeertube" name: str = "lazypeertube"
@ -20,5 +22,5 @@ class LazypeertubeCommand(LazyplayCommand):
f"/api/v1/search/videos?search={search}") as response: f"/api/v1/search/videos?search={search}") as response:
j = await response.json() j = await response.json()
if j["total"] < 1: if j["total"] < 1:
raise InvalidInputError("Nessun video trovato.") raise rc.InvalidInputError("Nessun video trovato.")
return [f'{self.config["Peertube"]["instance_url"]}/videos/watch/{j["data"][0]["uuid"]}'] return [f'{self.config["Peertube"]["instance_url"]}/videos/watch/{j["data"][0]["uuid"]}']

View file

@ -1,11 +1,11 @@
from typing import *
import discord import discord
import asyncio as aio import asyncio as aio
from typing import * import royalnet.commands as rc
from royalnet.commands import * import royalnet.backpack.tables as rbt
from royalnet.backpack.tables import User, Discord
class LazyplayCommand(Command): class LazyplayCommand(rc.Command):
name: str = "lazyplay" name: str = "lazyplay"
aliases = ["lp"] aliases = ["lp"]
@ -15,17 +15,17 @@ class LazyplayCommand(Command):
syntax = "{url}" syntax = "{url}"
async def get_urls(self, args: CommandArgs): async def get_urls(self, args: rc.CommandArgs):
url = args.joined(require_at_least=1) url = args.joined(require_at_least=1)
if not (url.startswith("http://") or url.startswith("https://")): if not (url.startswith("http://") or url.startswith("https://")):
raise InvalidInputError(f"L'URL specificato non inizia con il nome di un protocollo supportato" raise rc.InvalidInputError(f"L'URL specificato non inizia con il nome di un protocollo supportato"
f" ([c]http://[/c] o [c]https://[/c]).") f" ([c]http://[/c] o [c]https://[/c]).")
return [url] return [url]
def get_embed_color(self) -> Optional[int]: def get_embed_color(self) -> Optional[int]:
return None return None
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if self.interface.name == "discord": if self.interface.name == "discord":
message: discord.Message = data.message message: discord.Message = data.message
guild: discord.Guild = message.guild guild: discord.Guild = message.guild
@ -36,12 +36,12 @@ class LazyplayCommand(Command):
else: else:
guild_id = None guild_id = None
user: User = await data.get_author() user: rbt.User = await data.get_author()
user_str = None user_str = None
if user is not None: if user is not None:
try: try:
user_discord: Discord = user.discord[0] user_discord: rbt.Discord = user.discord[0]
except (AttributeError, IndexError): except (AttributeError, IndexError):
user_str = str(user) user_str = str(user)
else: else:

View file

@ -1,3 +1,4 @@
from typing import *
from .lazyplay import LazyplayCommand from .lazyplay import LazyplayCommand

View file

@ -1,3 +1,4 @@
from typing import *
from .lazyplay import LazyplayCommand from .lazyplay import LazyplayCommand

View file

@ -1,3 +1,4 @@
from typing import *
from .lazyplay import LazyplayCommand from .lazyplay import LazyplayCommand

View file

@ -1,18 +1,19 @@
import typing from typing import *
import riotwatcher import riotwatcher
import logging import logging
import asyncio import asyncio
import sentry_sdk import sentry_sdk
from royalnet.commands import * import royalnet.commands as rc
from royalnet.utils import * import royalnet.utils as ru
from royalnet.serf.telegram import * import royalnet.serf.telegram as rst
from ..tables import LeagueOfLegends, FiorygiTransaction from ..tables import LeagueOfLegends, FiorygiTransaction
from ..types import LeagueLeague from ..types import LeagueLeague
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class LeagueoflegendsCommand(Command): class LeagueoflegendsCommand(rc.Command):
name: str = "leagueoflegends" name: str = "leagueoflegends"
aliases = ["lol", "league"] aliases = ["lol", "league"]
@ -21,7 +22,7 @@ class LeagueoflegendsCommand(Command):
syntax = "[nomeevocatore]" syntax = "[nomeevocatore]"
def __init__(self, interface: CommandInterface): def __init__(self, interface: rc.CommandInterface):
super().__init__(interface) super().__init__(interface)
self._riotwatcher = riotwatcher.RiotWatcher(api_key=self.config["Lol"]["token"]) self._riotwatcher = riotwatcher.RiotWatcher(api_key=self.config["Lol"]["token"])
if self.interface.name == "telegram" and self.config["Lol"]["updater"]: if self.interface.name == "telegram" and self.config["Lol"]["updater"]:
@ -31,15 +32,15 @@ class LeagueoflegendsCommand(Command):
client = self.serf.client client = self.serf.client
await self.serf.api_call(client.send_message, await self.serf.api_call(client.send_message,
chat_id=self.config["Telegram"]["main_group_id"], chat_id=self.config["Telegram"]["main_group_id"],
text=escape(message), text=rst.escape(message),
parse_mode="HTML", parse_mode="HTML",
disable_webpage_preview=True) disable_webpage_preview=True)
async def _notify(self, async def _notify(self,
obj: LeagueOfLegends, obj: LeagueOfLegends,
attribute_name: str, attribute_name: str,
old_value: typing.Any, old_value: Any,
new_value: typing.Any): new_value: Any):
if isinstance(old_value, LeagueLeague): if isinstance(old_value, LeagueLeague):
# This is a rank change! # This is a rank change!
# Don't send messages for every rank change, send messages just if the TIER or RANK changes! # Don't send messages for every rank change, send messages just if the TIER or RANK changes!
@ -69,9 +70,9 @@ class LeagueoflegendsCommand(Command):
@staticmethod @staticmethod
async def _change(obj: LeagueOfLegends, async def _change(obj: LeagueOfLegends,
attribute_name: str, attribute_name: str,
new_value: typing.Any, new_value: Any,
callback: typing.Callable[ callback: Callable[
[LeagueOfLegends, str, typing.Any, typing.Any], typing.Awaitable[None]]): [LeagueOfLegends, str, Any, Any], Awaitable[None]]):
old_value = obj.__getattribute__(attribute_name) old_value = obj.__getattribute__(attribute_name)
if old_value != new_value: if old_value != new_value:
await callback(obj, attribute_name, old_value, new_value) await callback(obj, attribute_name, old_value, new_value)
@ -80,7 +81,7 @@ class LeagueoflegendsCommand(Command):
async def _update(self, lol: LeagueOfLegends): async def _update(self, lol: LeagueOfLegends):
log.info(f"Updating: {lol}") log.info(f"Updating: {lol}")
log.debug(f"Getting summoner data: {lol}") log.debug(f"Getting summoner data: {lol}")
summoner = await asyncify(self._riotwatcher.summoner.by_id, region=self.config["Lol"]["region"], summoner = await ru.asyncify(self._riotwatcher.summoner.by_id, region=self.config["Lol"]["region"],
encrypted_summoner_id=lol.summoner_id) encrypted_summoner_id=lol.summoner_id)
await self._change(lol, "profile_icon_id", summoner["profileIconId"], self._notify) await self._change(lol, "profile_icon_id", summoner["profileIconId"], self._notify)
await self._change(lol, "summoner_name", summoner["name"], self._notify) await self._change(lol, "summoner_name", summoner["name"], self._notify)
@ -89,7 +90,7 @@ class LeagueoflegendsCommand(Command):
await self._change(lol, "summoner_id", summoner["id"], self._notify) await self._change(lol, "summoner_id", summoner["id"], self._notify)
await self._change(lol, "account_id", summoner["accountId"], self._notify) await self._change(lol, "account_id", summoner["accountId"], self._notify)
log.debug(f"Getting leagues data: {lol}") log.debug(f"Getting leagues data: {lol}")
leagues = await asyncify(self._riotwatcher.league.by_summoner, region=self.config["Lol"]["region"], leagues = await ru.asyncify(self._riotwatcher.league.by_summoner, region=self.config["Lol"]["region"],
encrypted_summoner_id=lol.summoner_id) encrypted_summoner_id=lol.summoner_id)
soloq = LeagueLeague() soloq = LeagueLeague()
flexq = LeagueLeague() flexq = LeagueLeague()
@ -109,7 +110,7 @@ class LeagueoflegendsCommand(Command):
await self._change(lol, "rank_twtrq", twtrq, self._notify) await self._change(lol, "rank_twtrq", twtrq, self._notify)
await self._change(lol, "rank_tftq", tftq, self._notify) await self._change(lol, "rank_tftq", tftq, self._notify)
log.debug(f"Getting mastery data: {lol}") log.debug(f"Getting mastery data: {lol}")
mastery = await asyncify(self._riotwatcher.champion_mastery.scores_by_summoner, mastery = await ru.asyncify(self._riotwatcher.champion_mastery.scores_by_summoner,
region=self.config["Lol"]["region"], region=self.config["Lol"]["region"],
encrypted_summoner_id=lol.summoner_id) encrypted_summoner_id=lol.summoner_id)
await self._change(lol, "mastery_score", mastery, self._notify) await self._change(lol, "mastery_score", mastery, self._notify)
@ -128,7 +129,7 @@ class LeagueoflegendsCommand(Command):
sentry_sdk.capture_exception(e) sentry_sdk.capture_exception(e)
log.error(f"Error while updating {lol.user.username}: {e}") log.error(f"Error while updating {lol.user.username}: {e}")
await asyncio.sleep(1) await asyncio.sleep(1)
await asyncify(session.commit) await ru.asyncify(session.commit)
session.close() session.close()
log.info(f"Sleeping for {period}s") log.info(f"Sleeping for {period}s")
await asyncio.sleep(period) await asyncio.sleep(period)
@ -149,7 +150,7 @@ class LeagueoflegendsCommand(Command):
string += f"TFT: {lol.rank_tftq}\n" string += f"TFT: {lol.rank_tftq}\n"
return string return string
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
author = await data.get_author(error_if_none=True) author = await data.get_author(error_if_none=True)
name = args.joined() name = args.joined()
@ -159,10 +160,10 @@ class LeagueoflegendsCommand(Command):
log.debug(f"Searching for: {name}") log.debug(f"Searching for: {name}")
summoner = self._riotwatcher.summoner.by_name(region=self.config["Lol"]["region"], summoner_name=name) summoner = self._riotwatcher.summoner.by_name(region=self.config["Lol"]["region"], summoner_name=name)
# Ensure the account isn't already connected to something else # Ensure the account isn't already connected to something else
leagueoflegends = await asyncify( leagueoflegends = await ru.asyncify(
data.session.query(self.alchemy.get(LeagueOfLegends)).filter_by(summoner_id=summoner["id"]).one_or_none) data.session.query(self.alchemy.get(LeagueOfLegends)).filter_by(summoner_id=summoner["id"]).one_or_none)
if leagueoflegends: if leagueoflegends:
raise CommandError(f"L'account {leagueoflegends} è già registrato su Royalnet.") raise rc.CommandError(f"L'account {leagueoflegends} è già registrato su Royalnet.")
# Get rank information # Get rank information
log.debug(f"Getting leagues data: {name}") log.debug(f"Getting leagues data: {name}")
leagues = self._riotwatcher.league.by_summoner(region=self.config["Lol"]["region"], leagues = self._riotwatcher.league.by_summoner(region=self.config["Lol"]["region"],
@ -209,7 +210,7 @@ class LeagueoflegendsCommand(Command):
else: else:
# Update and display the League of Legends stats for the current account # Update and display the League of Legends stats for the current account
if len(author.leagueoflegends) == 0: if len(author.leagueoflegends) == 0:
raise UserError("Nessun account di League of Legends trovato.") raise rc.UserError("Nessun account di League of Legends trovato.")
message = "" message = ""
for account in author.leagueoflegends: for account in author.leagueoflegends:
try: try:

View file

@ -1,9 +1,8 @@
from typing import * from typing import *
import royalnet
import royalnet.commands as rc import royalnet.commands as rc
import royalnet.serf.telegram as rt import royalnet.backpack.tables as rbt
from royalnet.backpack.tables import Alias
from ..tables import Fiorygi, FiorygiTransaction from ..tables import FiorygiTransaction
class MagickfiorygiCommand(rc.Command): class MagickfiorygiCommand(rc.Command):
@ -24,7 +23,7 @@ class MagickfiorygiCommand(rc.Command):
if user_arg is None: if user_arg is None:
raise rc.InvalidInputError("Non hai specificato un destinatario!") raise rc.InvalidInputError("Non hai specificato un destinatario!")
user = await Alias.find_user(self.alchemy, data.session, user_arg) user = await rbt.Alias.find_user(self.alchemy, data.session, user_arg)
if user is None: if user is None:
raise rc.InvalidInputError("L'utente specificato non esiste!") raise rc.InvalidInputError("L'utente specificato non esiste!")

View file

@ -16,6 +16,7 @@ from royalnet.serf.telegram import TelegramSerf as TelegramBot
from royalnet.serf.telegram import escape as telegram_escape from royalnet.serf.telegram import escape as telegram_escape
from royalnet.utils import asyncify, sleep_until, sentry_async_wrap from royalnet.utils import asyncify, sleep_until, sentry_async_wrap
from royalnet.backpack.tables import User from royalnet.backpack.tables import User
from ..tables import MMEvent, MMResponse, FiorygiTransaction from ..tables import MMEvent, MMResponse, FiorygiTransaction
from ..types import MMChoice, MMInterfaceDataTelegram from ..types import MMChoice, MMInterfaceDataTelegram

View file

@ -1,16 +1,16 @@
import discord
from typing import * from typing import *
from royalnet.commands import * import discord
import royalnet.commands as rc
class PauseCommand(Command): class PauseCommand(rc.Command):
name: str = "pause" name: str = "pause"
aliases = ["resume"] aliases = ["resume"]
description: str = "Metti in pausa o riprendi la riproduzione di un file." description: str = "Metti in pausa o riprendi la riproduzione di un file."
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if self.interface.name == "discord": if self.interface.name == "discord":
message: discord.Message = data.message message: discord.Message = data.message
guild: discord.Guild = message.guild guild: discord.Guild = message.guild

View file

@ -1,8 +1,10 @@
from .play import PlayCommand from typing import *
from royalnet.commands import * import royalnet.commands as rc
import aiohttp import aiohttp
import urllib.parse import urllib.parse
from .play import PlayCommand
class PeertubeCommand(PlayCommand): class PeertubeCommand(PlayCommand):
name: str = "peertube" name: str = "peertube"
@ -20,5 +22,5 @@ class PeertubeCommand(PlayCommand):
f"/api/v1/search/videos?search={search}") as response: f"/api/v1/search/videos?search={search}") as response:
j = await response.json() j = await response.json()
if j["total"] < 1: if j["total"] < 1:
raise InvalidInputError("Nessun video trovato.") raise rc.InvalidInputError("Nessun video trovato.")
return [f'{self.config["Peertube"]["instance_url"]}/videos/watch/{j["data"][0]["uuid"]}'] return [f'{self.config["Peertube"]["instance_url"]}/videos/watch/{j["data"][0]["uuid"]}']

View file

@ -1,16 +1,17 @@
from typing import *
import aiohttp import aiohttp
import asyncio import asyncio
import datetime import datetime
import logging import logging
import dateparser import dateparser
from royalnet.commands import * import royalnet.commands as rc
from royalnet.serf.telegram.escape import escape import royalnet.serf.telegram as rst
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class PeertubeUpdatesCommand(Command): class PeertubeUpdatesCommand(rc.Command):
name: str = "peertubeupdates" name: str = "peertubeupdates"
description: str = "Guarda quando è uscito l'ultimo video su PeerTube." description: str = "Guarda quando è uscito l'ultimo video su PeerTube."
@ -21,7 +22,7 @@ class PeertubeUpdatesCommand(Command):
_latest_date: datetime.datetime = None _latest_date: datetime.datetime = None
def __init__(self, interface: CommandInterface): def __init__(self, interface: rc.CommandInterface):
super().__init__(interface) super().__init__(interface)
if self.interface.name == "telegram": if self.interface.name == "telegram":
self.loop.create_task(self._ready_up()) self.loop.create_task(self._ready_up())
@ -34,7 +35,7 @@ class PeertubeUpdatesCommand(Command):
"/feeds/videos.json?sort=-publishedAt&filter=local") as response: "/feeds/videos.json?sort=-publishedAt&filter=local") as response:
log.debug("Parsing jsonfeed") log.debug("Parsing jsonfeed")
if response.status != 200: if response.status != 200:
raise ExternalError("Peertube is unavailable") raise rc.ExternalError("Peertube is unavailable")
j = await response.json() j = await response.json()
log.debug("Jsonfeed parsed successfully") log.debug("Jsonfeed parsed successfully")
return j return j
@ -43,14 +44,14 @@ class PeertubeUpdatesCommand(Command):
client = self.interface.bot.client client = self.interface.bot.client
await self.interface.bot.safe_api_call(client.send_message, await self.interface.bot.safe_api_call(client.send_message,
chat_id=self.config["Telegram"]["main_group_id"], chat_id=self.config["Telegram"]["main_group_id"],
text=escape(message), text=rst.escape(message),
parse_mode="HTML", parse_mode="HTML",
disable_webpage_preview=True) disable_webpage_preview=True)
async def _ready_up(self): async def _ready_up(self):
j = await self._get_json() j = await self._get_json()
if j["version"] != "https://jsonfeed.org/version/1": if j["version"] != "https://jsonfeed.org/version/1":
raise ConfigurationError("url is not a jsonfeed") raise rc.ConfigurationError("url is not a jsonfeed")
videos = j["items"] videos = j["items"]
for video in reversed(videos): for video in reversed(videos):
date_modified = dateparser.parse(video["date_modified"]) date_modified = dateparser.parse(video["date_modified"])
@ -74,7 +75,7 @@ class PeertubeUpdatesCommand(Command):
f"{video['url']}") f"{video['url']}")
await asyncio.sleep(self.config["Peertube"]["feed_update_timeout"]) await asyncio.sleep(self.config["Peertube"]["feed_update_timeout"])
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if self.interface.name != "telegram": if self.interface.name != "telegram":
raise UnsupportedError() raise rc.UnsupportedError()
await data.reply(f" Ultimo video caricato il: [b]{self._latest_date.isoformat()}[/b]") await data.reply(f" Ultimo video caricato il: [b]{self._latest_date.isoformat()}[/b]")

View file

@ -1,11 +1,11 @@
from typing import *
import discord import discord
import asyncio as aio import asyncio as aio
from typing import * import royalnet.commands as rc
from royalnet.commands import * import royalnet.backpack.tables as rbt
from royalnet.backpack.tables import User, Discord
class PlayCommand(Command): class PlayCommand(rc.Command):
name: str = "play" name: str = "play"
aliases = ["p"] aliases = ["p"]
@ -14,17 +14,17 @@ class PlayCommand(Command):
syntax = "{url}" syntax = "{url}"
async def get_urls(self, args: CommandArgs): async def get_urls(self, args: rc.CommandArgs):
url = args.joined(require_at_least=1) url = args.joined(require_at_least=1)
if not (url.startswith("http://") or url.startswith("https://")): if not (url.startswith("http://") or url.startswith("https://")):
raise InvalidInputError(f"L'URL specificato non inizia con il nome di un protocollo supportato" raise rc.InvalidInputError(f"L'URL specificato non inizia con il nome di un protocollo supportato"
f" ([c]http://[/c] o [c]https://[/c]).") f" ([c]http://[/c] o [c]https://[/c]).")
return [url] return [url]
def get_embed_color(self) -> Optional[int]: def get_embed_color(self) -> Optional[int]:
return None return None
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if self.interface.name == "discord": if self.interface.name == "discord":
message: discord.Message = data.message message: discord.Message = data.message
guild: discord.Guild = message.guild guild: discord.Guild = message.guild
@ -35,12 +35,12 @@ class PlayCommand(Command):
else: else:
guild_id = None guild_id = None
user: User = await data.get_author() user: rbt.User = await data.get_author()
user_str = None user_str = None
if user is not None: if user is not None:
try: try:
user_discord: Discord = user.discord[0] user_discord: rbt.Discord = user.discord[0]
except (AttributeError, IndexError): except (AttributeError, IndexError):
user_str = str(user) user_str = str(user)
else: else:

View file

@ -1,8 +1,7 @@
from typing import * from typing import *
import royalnet
import royalnet.commands as rc import royalnet.commands as rc
import discord import discord
from royalnet.backpack.tables import User, Discord import royalnet.backpack.tables as rbt
class PlaymodeCommand(rc.Command): class PlaymodeCommand(rc.Command):
@ -25,12 +24,12 @@ class PlaymodeCommand(rc.Command):
else: else:
guild_id = None guild_id = None
user: User = await data.get_author() user: rbt.User = await data.get_author()
user_str = None user_str = None
if user is not None: if user is not None:
try: try:
user_discord: Discord = user.discord[0] user_discord: rbt.Discord = user.discord[0]
except (AttributeError, IndexError): except (AttributeError, IndexError):
user_str = str(user) user_str = str(user)
else: else:

View file

@ -1,11 +1,11 @@
from typing import * from typing import *
from royalnet.commands import * import royalnet.commands as rc
class PmotsCommand(Command): class PmotsCommand(rc.Command):
name: str = "pmots" name: str = "pmots"
description: str = "Confondi Proto!" description: str = "Confondi Proto!"
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
await data.reply("👣 pmots pmots") await data.reply("👣 pmots pmots")

View file

@ -1,19 +1,19 @@
from typing import *
import pickle import pickle
import base64 import base64
import discord import discord
from typing import * import royalnet.commands as rc
from royalnet.commands import * import royalnet.utils as ru
from royalnet.utils import *
class QueueCommand(Command): class QueueCommand(rc.Command):
name: str = "queue" name: str = "queue"
aliases = ["q"] aliases = ["q"]
description: str = "Visualizza la coda di riproduzione attuale." description: str = "Visualizza la coda di riproduzione attuale."
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if self.interface.name == "discord": if self.interface.name == "discord":
message: discord.Message = data.message message: discord.Message = data.message
guild: discord.Guild = message.guild guild: discord.Guild = message.guild
@ -54,9 +54,9 @@ class QueueCommand(Command):
# noinspection PyUnboundLocalVariable # noinspection PyUnboundLocalVariable
await message.channel.send(embed=embed) await message.channel.send(embed=embed)
else: else:
reply += numberemojiformat([a["title"] for a in next_up[:5]]) reply += ru.numberemojiformat([a["title"] for a in next_up[:5]])
await data.reply(reply) await data.reply(reply)
else: else:
await data.reply(" Non ci sono altri file in coda.") await data.reply(" Non ci sono altri file in coda.")
else: else:
raise CommandError(f"Non so come visualizzare il contenuto di un [c]{queue_type}[/c].") raise rc.CommandError(f"Non so come visualizzare il contenuto di un [c]{queue_type}[/c].")

View file

@ -1,9 +1,9 @@
import typing from typing import *
import random import random
from royalnet.commands import * import royalnet.commands as rc
class RageCommand(Command): class RageCommand(rc.Command):
name: str = "rage" name: str = "rage"
aliases = ["balurage", "madden"] aliases = ["balurage", "madden"]
@ -18,5 +18,5 @@ class RageCommand(Command):
"Fondiamo la RRYG!" "Fondiamo la RRYG!"
] ]
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
await data.reply(f"😠 {random.sample(self._MAD, 1)[0]}") await data.reply(f"😠 {random.sample(self._MAD, 1)[0]}")

View file

@ -1,18 +1,19 @@
import typing from typing import *
import dateparser import dateparser
import datetime import datetime
import pickle import pickle
import telegram import telegram
import discord import discord
from sqlalchemy import and_ from sqlalchemy import and_
from royalnet.commands import * import royalnet.commands as rc
from royalnet.utils import * import royalnet.utils as ru
from royalnet.serf.telegram import escape as telegram_escape from royalnet.serf.telegram import escape as telegram_escape
from royalnet.serf.discord import escape as discord_escape from royalnet.serf.discord import escape as discord_escape
from ..tables import Reminder from ..tables import Reminder
class ReminderCommand(Command): class ReminderCommand(rc.Command):
name: str = "reminder" name: str = "reminder"
aliases = ["calendar"] aliases = ["calendar"]
@ -21,7 +22,7 @@ class ReminderCommand(Command):
syntax: str = "[ {data} ] {messaggio}" syntax: str = "[ {data} ] {messaggio}"
def __init__(self, interface: CommandInterface): def __init__(self, interface: rc.CommandInterface):
super().__init__(interface) super().__init__(interface)
session = interface.alchemy.Session() session = interface.alchemy.Session()
reminders = ( reminders = (
@ -35,7 +36,7 @@ class ReminderCommand(Command):
interface.loop.create_task(self._remind(reminder)) interface.loop.create_task(self._remind(reminder))
async def _remind(self, reminder): async def _remind(self, reminder):
await sleep_until(reminder.datetime) await ru.sleep_until(reminder.datetime)
if self.interface.name == "telegram": if self.interface.name == "telegram":
chat_id: int = pickle.loads(reminder.interface_data) chat_id: int = pickle.loads(reminder.interface_data)
client: telegram.Bot = self.serf.client client: telegram.Bot = self.serf.client
@ -50,14 +51,14 @@ class ReminderCommand(Command):
channel = client.get_channel(channel_id) channel = client.get_channel(channel_id)
await channel.send(discord_escape(f"❗️ {reminder.message}")) await channel.send(discord_escape(f"❗️ {reminder.message}"))
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
try: try:
date_str, reminder_text = args.match(r"\[\s*([^]]+)\s*]\s*([^\n]+)\s*") date_str, reminder_text = args.match(r"\[\s*([^]]+)\s*]\s*([^\n]+)\s*")
except InvalidInputError: except rc.InvalidInputError:
date_str, reminder_text = args.match(r"\s*(.+?)\s*\n\s*([^\n]+)\s*") date_str, reminder_text = args.match(r"\s*(.+?)\s*\n\s*([^\n]+)\s*")
try: try:
date: typing.Optional[datetime.datetime] = dateparser.parse(date_str, settings={ date: Optional[datetime.datetime] = dateparser.parse(date_str, settings={
"PREFER_DATES_FROM": "future" "PREFER_DATES_FROM": "future"
}) })
except OverflowError: except OverflowError:
@ -74,7 +75,7 @@ class ReminderCommand(Command):
elif self.interface.name == "discord": elif self.interface.name == "discord":
interface_data = pickle.dumps(data.message.channel.id) interface_data = pickle.dumps(data.message.channel.id)
else: else:
raise UnsupportedError("This command does not support the current interface.") raise rc.UnsupportedError("This command does not support the current interface.")
creator = await data.get_author() creator = await data.get_author()
reminder = self.interface.alchemy.get(Reminder)(creator=creator, reminder = self.interface.alchemy.get(Reminder)(creator=creator,
interface_name=self.interface.name, interface_name=self.interface.name,
@ -83,4 +84,4 @@ class ReminderCommand(Command):
message=reminder_text) message=reminder_text)
self.interface.loop.create_task(self._remind(reminder)) self.interface.loop.create_task(self._remind(reminder))
data.session.add(reminder) data.session.add(reminder)
await asyncify(data.session.commit) await ru.asyncify(data.session.commit)

View file

@ -1,5 +1,6 @@
from typing import * from typing import *
import royalnet.commands as rc import royalnet.commands as rc
from ..version import semantic from ..version import semantic

View file

@ -1,15 +1,16 @@
from typing import *
import re import re
from royalnet.commands import * import royalnet.commands as rc
class ShipCommand(Command): class ShipCommand(rc.Command):
name: str = "ship" name: str = "ship"
description: str = "Crea una ship tra due nomi." description: str = "Crea una ship tra due nomi."
syntax = "{nomeuno} {nomedue}" syntax = "{nomeuno} {nomedue}"
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
name_one = args[0] name_one = args[0]
name_two = args[1] name_two = args[1]
if name_two == "+": if name_two == "+":

View file

@ -1,16 +1,16 @@
import discord
from typing import * from typing import *
from royalnet.commands import * import discord
import royalnet.commands as rc
class SkipCommand(Command): class SkipCommand(rc.Command):
name: str = "skip" name: str = "skip"
aliases = ["s"] aliases = ["s"]
description: str = "Salta il file attualmente in riproduzione." description: str = "Salta il file attualmente in riproduzione."
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if self.interface.name == "discord": if self.interface.name == "discord":
message: discord.Message = data.message message: discord.Message = data.message
guild: discord.Guild = message.guild guild: discord.Guild = message.guild

View file

@ -1,9 +1,9 @@
import typing from typing import *
import random import random
from royalnet.commands import * import royalnet.commands as rc
class SmecdsCommand(Command): class SmecdsCommand(rc.Command):
name: str = "smecds" name: str = "smecds"
aliases = ["secondomeecolpadellostagista"] aliases = ["secondomeecolpadellostagista"]
@ -61,6 +61,6 @@ class SmecdsCommand(Command):
"dello Slime God", "del salassato", "della salsa", "di Senjougahara", "di Sugar", "della Stampa", "dello Slime God", "del salassato", "della salsa", "di Senjougahara", "di Sugar", "della Stampa",
"della Stampante"] "della Stampante"]
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
ds = random.sample(self._DS_LIST, 1)[0] ds = random.sample(self._DS_LIST, 1)[0]
await data.reply(f"🤔 Secondo me, è colpa {ds}.") await data.reply(f"🤔 Secondo me, è colpa {ds}.")

View file

@ -1,3 +1,4 @@
from typing import *
from .play import PlayCommand from .play import PlayCommand

View file

@ -1,19 +1,17 @@
from typing import * from typing import *
from royalnet.commands import * import royalnet.commands as rc
from royalnet.utils import * import royalnet.utils as ru
from royalnet.backpack.tables import User
from sqlalchemy import func
import royalspells as rs import royalspells as rs
class SpellCommand(Command): class SpellCommand(rc.Command):
name: str = "spell" name: str = "spell"
description: str = "Genera casualmente una spell!" description: str = "Genera casualmente una spell!"
syntax = "{nome_spell}" syntax = "{nome_spell}"
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
spell_name = args.joined(require_at_least=1) spell_name = args.joined(require_at_least=1)
spell = rs.Spell(spell_name) spell = rs.Spell(spell_name)
@ -23,7 +21,7 @@ class SpellCommand(Command):
dmg: rs.DamageComponent = spell.damage_component dmg: rs.DamageComponent = spell.damage_component
constant_str: str = f"{dmg.constant:+d}" if dmg.constant != 0 else "" constant_str: str = f"{dmg.constant:+d}" if dmg.constant != 0 else ""
rows.append(f"Danni: [b]{dmg.dice_number}d{dmg.dice_type}{constant_str}[/b]" rows.append(f"Danni: [b]{dmg.dice_number}d{dmg.dice_type}{constant_str}[/b]"
f" {andformat(dmg.damage_types, final=' e ')}") f" {ru.andformat(dmg.damage_types, final=' e ')}")
rows.append(f"Precisione: [b]{dmg.miss_chance}%[/b]") rows.append(f"Precisione: [b]{dmg.miss_chance}%[/b]")
if dmg.repeat > 1: if dmg.repeat > 1:
rows.append(f"Multiattacco: [b]×{dmg.repeat}[/b]") rows.append(f"Multiattacco: [b]×{dmg.repeat}[/b]")

View file

@ -1,10 +1,11 @@
from typing import * from typing import *
from royalnet.commands import *
from royalnet.utils import *
from royalnet.backpack.tables import Alias
from ..tables import Steam
import steam import steam
import requests.exceptions import requests.exceptions
import royalnet.commands as rc
import royalnet.utils as ru
import royalnet.backpack.tables as rbt
from ..tables import Steam
class SteamGame: class SteamGame:
@ -45,47 +46,47 @@ class SteamGame:
return f"<{self.__class__.__qualname__} {self.appid} ({self.name})>" return f"<{self.__class__.__qualname__} {self.appid} ({self.name})>"
class SteammatchCommand(Command): class SteammatchCommand(rc.Command):
name: str = "steammatch" name: str = "steammatch"
description: str = "Vedi quali giochi hai in comune con uno o più membri!" description: str = "Vedi quali giochi hai in comune con uno o più membri!"
syntax: str = "{royalnet_username}+" syntax: str = "{royalnet_username}+"
def __init__(self, interface: CommandInterface): def __init__(self, interface: rc.CommandInterface):
super().__init__(interface) super().__init__(interface)
if "Steam" not in self.config or "web_api_key" not in self.config["Steam"]: if "Steam" not in self.config or "web_api_key" not in self.config["Steam"]:
raise ConfigurationError("[c]Steam.web_api_key[/c] config option is missing!") raise rc.ConfigurationError("[c]Steam.web_api_key[/c] config option is missing!")
self._api = steam.WebAPI(self.config["Steam"]["web_api_key"]) self._api = steam.WebAPI(self.config["Steam"]["web_api_key"])
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
users = [] users = []
author = await data.get_author(error_if_none=True) author = await data.get_author(error_if_none=True)
users.append(author) users.append(author)
for arg in args: for arg in args:
user = await Alias.find_user(self.alchemy, data.session, arg) user = await rbt.User.find(self.alchemy, data.session, arg)
users.append(user) users.append(user)
if len(users) < 2: if len(users) < 2:
raise InvalidInputError("Devi specificare almeno un altro utente!") raise rc.InvalidInputError("Devi specificare almeno un altro utente!")
shared_games: Optional[set] = None shared_games: Optional[set] = None
for user in users: for user in users:
user_games = set() user_games = set()
if len(user.steam) == 0: if len(user.steam) == 0:
raise UserError(f"{user} non ha un account Steam registrato!") raise rc.UserError(f"{user} non ha un account Steam registrato!")
for steam_account in user.steam: for steam_account in user.steam:
steam_account: Steam steam_account: Steam
try: try:
response = await asyncify(self._api.IPlayerService.GetOwnedGames, response = await ru.asyncify(self._api.IPlayerService.GetOwnedGames,
steamid=steam_account._steamid, steamid=steam_account._steamid,
include_appinfo=True, include_appinfo=True,
include_played_free_games=True, include_played_free_games=True,
appids_filter=0) appids_filter=0)
except requests.exceptions.HTTPError: except requests.exceptions.HTTPError:
raise ExternalError(f"L'account Steam di {user} è privato!") raise rc.ExternalError(f"L'account Steam di {user} è privato!")
games = response["response"]["games"] games = response["response"]["games"]
for game in games: for game in games:
user_games.add(SteamGame(**game)) user_games.add(SteamGame(**game))
@ -94,7 +95,7 @@ class SteammatchCommand(Command):
else: else:
shared_games = shared_games.intersection(user_games) shared_games = shared_games.intersection(user_games)
message_rows = [f"🎮 Giochi in comune tra {andformat([str(user) for user in users], final=' e ')}:"] message_rows = [f"🎮 Giochi in comune tra {ru.andformat([str(user) for user in users], final=' e ')}:"]
for game in sorted(list(shared_games), key=lambda g: g.name): for game in sorted(list(shared_games), key=lambda g: g.name):
message_rows.append(f"- {game}") message_rows.append(f"- {game}")

View file

@ -1,22 +1,23 @@
from typing import * from typing import *
from royalnet.commands import *
from royalnet.utils import *
from ..tables import Steam, FiorygiTransaction
import steam import steam
import datetime import datetime
import royalnet.commands as rc
import royalnet.utils as ru
from ..tables import Steam, FiorygiTransaction
class SteampoweredCommand(Command): class SteampoweredCommand(rc.Command):
name: str = "steampowered" name: str = "steampowered"
description: str = "Connetti il tuo account di Steam!" description: str = "Connetti il tuo account di Steam!"
syntax: str = "{profile_url}" syntax: str = "{profile_url}"
def __init__(self, interface: CommandInterface): def __init__(self, interface: rc.CommandInterface):
super().__init__(interface) super().__init__(interface)
if "Steam" not in self.config or "web_api_key" not in self.config["Steam"]: if "Steam" not in self.config or "web_api_key" not in self.config["Steam"]:
raise ConfigurationError("[c]Steam.web_api_key[/c] config option is missing!") raise rc.ConfigurationError("[c]Steam.web_api_key[/c] config option is missing!")
self._api = steam.WebAPI(self.config["Steam"]["web_api_key"]) self._api = steam.WebAPI(self.config["Steam"]["web_api_key"])
@staticmethod @staticmethod
@ -34,9 +35,9 @@ class SteampoweredCommand(Command):
async def _call(self, method, *args, **kwargs): async def _call(self, method, *args, **kwargs):
try: try:
await asyncify(method, *args, **kwargs) await ru.asyncify(method, *args, **kwargs)
except Exception as e: except Exception as e:
raise ExternalError("\n".join(e.args).replace(self.config["Steam"]["web_api_key"], "HIDDEN")) raise rc.ExternalError("\n".join(e.args).replace(self.config["Steam"]["web_api_key"], "HIDDEN"))
async def _update(self, account: Steam): async def _update(self, account: Steam):
# noinspection PyProtectedMember # noinspection PyProtectedMember
@ -48,13 +49,13 @@ class SteampoweredCommand(Command):
account.primary_clan_id = r["primaryclanid"] account.primary_clan_id = r["primaryclanid"]
account.account_creation_date = datetime.datetime.fromtimestamp(r["timecreated"]) account.account_creation_date = datetime.datetime.fromtimestamp(r["timecreated"])
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
author = await data.get_author() author = await data.get_author()
if len(args) > 0: if len(args) > 0:
url = args.joined() url = args.joined()
steamid64 = await self._call(steam.steamid.steam64_from_url, url) steamid64 = await self._call(steam.steamid.steam64_from_url, url)
if steamid64 is None: if steamid64 is None:
raise InvalidInputError("Quel link non è associato ad alcun account Steam.") raise rc.InvalidInputError("Quel link non è associato ad alcun account Steam.")
response = await self._call(self._api.ISteamUser.GetPlayerSummaries_v2, steamids=steamid64) response = await self._call(self._api.ISteamUser.GetPlayerSummaries_v2, steamids=steamid64)
r = response["response"]["players"][0] r = response["response"]["players"][0]
steam_account = self.alchemy.get(Steam)( steam_account = self.alchemy.get(Steam)(
@ -74,7 +75,7 @@ class SteampoweredCommand(Command):
else: else:
# Update and display the Steam info for the current account # Update and display the Steam info for the current account
if len(author.steam) == 0: if len(author.steam) == 0:
raise UserError("Nessun account di Steam trovato.") raise rc.UserError("Nessun account di Steam trovato.")
message = "" message = ""
for account in author.steam: for account in author.steam:
await self._update(account) await self._update(account)

View file

@ -1,8 +1,9 @@
from typing import *
import royalnet.commands as rc
import discord import discord
from royalnet.commands import *
class SummonCommand(Command): class SummonCommand(rc.Command):
name: str = "summon" name: str = "summon"
aliases = ["cv"] aliases = ["cv"]
@ -11,7 +12,7 @@ class SummonCommand(Command):
syntax: str = "[nomecanale]" syntax: str = "[nomecanale]"
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
channel_name = args.joined() channel_name = args.joined()
if self.interface.name == "discord": if self.interface.name == "discord":
message: discord.Message = data.message message: discord.Message = data.message

View file

@ -6,8 +6,8 @@ import uuid
import html import html
import royalnet.commands as rc import royalnet.commands as rc
import royalnet.utils as ru import royalnet.utils as ru
import royalnet.backpack.tables as rbt
from ..tables import TriviaScore from ..tables import TriviaScore
from royalnet.backpack.tables.users import User
class TriviaCommand(rc.Command): class TriviaCommand(rc.Command):
@ -126,7 +126,7 @@ class TriviaCommand(rc.Command):
results = f"❗️ Tempo scaduto!\n" \ results = f"❗️ Tempo scaduto!\n" \
f"La risposta corretta era [b]{answers[correct_index]}[/b]!\n\n" f"La risposta corretta era [b]{answers[correct_index]}[/b]!\n\n"
for answerer_id in self._answerers[question_id]: for answerer_id in self._answerers[question_id]:
answerer = data.session.query(self.alchemy.get(User)).get(answerer_id) answerer = data.session.query(self.alchemy.get(rbt.users.User)).get(answerer_id)
if answerer.trivia_score is None: if answerer.trivia_score is None:
ts = self.interface.alchemy.get(TriviaScore)(user=answerer) ts = self.interface.alchemy.get(TriviaScore)(user=answerer)
data.session.add(ts) data.session.add(ts)

View file

@ -1,11 +1,9 @@
from typing import * from typing import *
from royalnet.commands import * import royalnet.commands as rc
from royalnet.utils import * import royalnet.backpack.tables as rbt
from royalnet.backpack.tables import User, Alias
from sqlalchemy import func
class UserinfoCommand(Command): class UserinfoCommand(rc.Command):
name: str = "userinfo" name: str = "userinfo"
aliases = ["uinfo", "ui", "useri"] aliases = ["uinfo", "ui", "useri"]
@ -14,23 +12,27 @@ class UserinfoCommand(Command):
syntax = "[username]" syntax = "[username]"
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
username = args.optional(0) username = args.optional(0)
if username is None: if username is None:
user: User = await data.get_author(error_if_none=True) user: rbt.User = await data.get_author(error_if_none=True)
else: else:
found: Optional[User] = await Alias.find_user(self.alchemy, data.session, username) found: Optional[rbt.User] = await rbt.User.find(self.alchemy, data.session, username)
if not found: if not found:
raise InvalidInputError("Utente non trovato.") raise rc.InvalidInputError("Utente non trovato.")
else: else:
user = found user = found
r = [ r = [
f" [url=https://ryg.steffo.eu/#/user/{user.uid}]{user.username}[/url]", f" [url=https://ryg.steffo.eu/#/user/{user.uid}]{user.username}[/url]",
f"{user.role}", f"{', '.join(user.roles)}",
"",
] ]
if user.email:
r.append(f"{user.email}")
r.append("")
# Bios are a bit too long # Bios are a bit too long
# if user.bio: # if user.bio:
# r.append(f"{user.bio}") # r.append(f"{user.bio}")

View file

@ -1,9 +1,9 @@
import typing from typing import *
import discord import discord
from royalnet.commands import * import royalnet.commands as rc
class VideochannelCommand(Command): class VideochannelCommand(rc.Command):
name: str = "videochannel" name: str = "videochannel"
aliases = ["golive", "live", "video"] aliases = ["golive", "live", "video"]
@ -12,33 +12,33 @@ class VideochannelCommand(Command):
syntax = "[nomecanale]" syntax = "[nomecanale]"
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if self.interface.name != "discord": if self.interface.name != "discord":
raise UnsupportedError(f"{self} non è supportato su {self.interface.name}.") raise rc.UnsupportedError(f"{self} non è supportato su {self.interface.name}.")
bot: discord.Client = self.serf.client bot: discord.Client = self.serf.client
message: discord.Message = data.message message: discord.Message = data.message
channel_name: str = args.optional(0) channel_name: str = args.optional(0)
if channel_name: if channel_name:
guild: typing.Optional[discord.Guild] = message.guild guild: Optional[discord.Guild] = message.guild
if guild is not None: if guild is not None:
channels: typing.List[discord.abc.GuildChannel] = guild.channels channels: List[discord.abc.GuildChannel] = guild.channels
else: else:
channels = bot.get_all_channels() channels = bot.get_all_channels()
matching_channels: typing.List[discord.VoiceChannel] = [] matching_channels: List[discord.VoiceChannel] = []
for channel in channels: for channel in channels:
if isinstance(channel, discord.VoiceChannel): if isinstance(channel, discord.VoiceChannel):
if channel.name == channel_name: if channel.name == channel_name:
matching_channels.append(channel) matching_channels.append(channel)
if len(matching_channels) == 0: if len(matching_channels) == 0:
raise InvalidInputError("Non esiste alcun canale vocale con il nome specificato.") raise rc.InvalidInputError("Non esiste alcun canale vocale con il nome specificato.")
elif len(matching_channels) > 1: elif len(matching_channels) > 1:
raise UserError("Esiste più di un canale vocale con il nome specificato.") raise rc.UserError("Esiste più di un canale vocale con il nome specificato.")
channel = matching_channels[0] channel = matching_channels[0]
else: else:
author: discord.Member = message.author author: discord.Member = message.author
voice: typing.Optional[discord.VoiceState] = author.voice voice: Optional[discord.VoiceState] = author.voice
if voice is None: if voice is None:
raise InvalidInputError("Non sei connesso a nessun canale vocale.") raise rc.InvalidInputError("Non sei connesso a nessun canale vocale.")
channel = voice.channel channel = voice.channel
if author.is_on_mobile(): if author.is_on_mobile():
await data.reply(f"📹 Per entrare in modalità video, clicca qui:\n" await data.reply(f"📹 Per entrare in modalità video, clicca qui:\n"

View file

@ -1,3 +1,4 @@
from typing import *
from .play import PlayCommand from .play import PlayCommand

View file

@ -1,3 +1,4 @@
from typing import *
from .play import PlayCommand from .play import PlayCommand

View file

@ -1 +1 @@
semantic = "5.7.15" semantic = "5.8.0"