diff options
| author | 2021-04-17 17:58:36 +0200 | |
|---|---|---|
| committer | 2021-04-17 17:58:36 +0200 | |
| commit | 91507175c268492f8b809569897489e7efdc8721 (patch) | |
| tree | 07ed83b4e9fcdc4be15ef70ae76720c0afd4e435 | |
| parent | Remove check for `exit` to reset context (diff) | |
| parent | Merge pull request #686 from python-discord/remove-ffmpg (diff) | |
Merge branch 'main' into int-eval
31 files changed, 730 insertions, 472 deletions
@@ -1,7 +1,7 @@  # bot (project-specific)  log/*  data/* - +_latex_cache/* @@ -6,12 +6,6 @@ ENV PIP_NO_CACHE_DIR=false \      PIPENV_IGNORE_VIRTUALENVS=1 \      PIPENV_NOSPIN=1 -# Install git to be able to dowload git dependencies in the Pipfile -RUN apt-get -y update \ -    && apt-get install -y \ -        ffmpeg \ -    && rm -rf /var/lib/apt/lists/* -  # Install pipenv  RUN pip install -U pipenv @@ -12,9 +12,10 @@ pillow = "~=8.1"  pytz = "~=2019.2"  sentry-sdk = "~=0.19"  PyYAML = "~=5.4" -"discord.py" = {extras = ["voice"], version = "~=1.5.1"} +"discord.py" = "~=1.5.1"  async-rediscache = {extras = ["fakeredis"], version = "~=0.1.4"}  emojis = "~=0.6.0" +matplotlib = "~=3.4.1"  [dev-packages]  flake8 = "~=3.8" diff --git a/Pipfile.lock b/Pipfile.lock index 64cae8cc..915c3784 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@  {      "_meta": {          "hash": { -            "sha256": "427595155192c24bd1b3de5e8ffc242dc55f4390b9b90257179b5fa76457b611" +            "sha256": "96cd9674aea76763df9582acd392eece6546876698fffaf9024e5a2daccb8f6f"          },          "pipfile-spec": 6,          "requires": { @@ -40,6 +40,7 @@                  "sha256:c506853ba52e516b264b106321c424d03f3ddef2813246432fa9d1cefd361c81",                  "sha256:fb83326d8295e8840e4ba774edf346e87eca78ba8a89c55d2690352842c15ba5"              ], +            "markers": "python_full_version >= '3.5.3'",              "version": "==3.6.3"          },          "aioredis": { @@ -73,6 +74,7 @@                  "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",                  "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"              ], +            "markers": "python_full_version >= '3.5.3'",              "version": "==3.0.1"          },          "attrs": { @@ -80,6 +82,7 @@                  "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6",                  "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"              ], +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",              "version": "==20.3.0"          },          "beautifulsoup4": { @@ -147,10 +150,15 @@              ],              "version": "==3.0.4"          }, -        "discord.py": { -            "extras": [ -                "voice" +        "cycler": { +            "hashes": [ +                "sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d", +                "sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"              ], +            "version": "==0.10.0" +        }, +        "discord.py": { +            "extras": [],              "hashes": [                  "sha256:2367359e31f6527f8a936751fc20b09d7495dd6a76b28c8fb13d4ca6c55b7563",                  "sha256:def00dc50cf36d21346d71bc89f0cad8f18f9a3522978dc18c7796287d47de8b" @@ -225,6 +233,7 @@                  "sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0",                  "sha256:f8196f739092a78e4f6b1b2172679ed3343c39c61a3e9d722ce6fcf1dac2824a"              ], +            "markers": "python_version >= '3.6'",              "version": "==2.0.0"          },          "idna": { @@ -232,8 +241,72 @@                  "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16",                  "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1"              ], +            "markers": "python_version >= '3.4'",              "version": "==3.1"          }, +        "kiwisolver": { +            "hashes": [ +                "sha256:0cd53f403202159b44528498de18f9285b04482bab2a6fc3f5dd8dbb9352e30d", +                "sha256:1e1bc12fb773a7b2ffdeb8380609f4f8064777877b2225dec3da711b421fda31", +                "sha256:225e2e18f271e0ed8157d7f4518ffbf99b9450fca398d561eb5c4a87d0986dd9", +                "sha256:232c9e11fd7ac3a470d65cd67e4359eee155ec57e822e5220322d7b2ac84fbf0", +                "sha256:31dfd2ac56edc0ff9ac295193eeaea1c0c923c0355bf948fbd99ed6018010b72", +                "sha256:33449715e0101e4d34f64990352bce4095c8bf13bed1b390773fc0a7295967b3", +                "sha256:401a2e9afa8588589775fe34fc22d918ae839aaaf0c0e96441c0fdbce6d8ebe6", +                "sha256:44a62e24d9b01ba94ae7a4a6c3fb215dc4af1dde817e7498d901e229aaf50e4e", +                "sha256:50af681a36b2a1dee1d3c169ade9fdc59207d3c31e522519181e12f1b3ba7000", +                "sha256:563c649cfdef27d081c84e72a03b48ea9408c16657500c312575ae9d9f7bc1c3", +                "sha256:5989db3b3b34b76c09253deeaf7fbc2707616f130e166996606c284395da3f18", +                "sha256:5a7a7dbff17e66fac9142ae2ecafb719393aaee6a3768c9de2fd425c63b53e21", +                "sha256:5c3e6455341008a054cccee8c5d24481bcfe1acdbc9add30aa95798e95c65621", +                "sha256:5f6ccd3dd0b9739edcf407514016108e2280769c73a85b9e59aa390046dbf08b", +                "sha256:72c99e39d005b793fb7d3d4e660aed6b6281b502e8c1eaf8ee8346023c8e03bc", +                "sha256:78751b33595f7f9511952e7e60ce858c6d64db2e062afb325985ddbd34b5c131", +                "sha256:834ee27348c4aefc20b479335fd422a2c69db55f7d9ab61721ac8cd83eb78882", +                "sha256:8be8d84b7d4f2ba4ffff3665bcd0211318aa632395a1a41553250484a871d454", +                "sha256:950a199911a8d94683a6b10321f9345d5a3a8433ec58b217ace979e18f16e248", +                "sha256:a357fd4f15ee49b4a98b44ec23a34a95f1e00292a139d6015c11f55774ef10de", +                "sha256:a53d27d0c2a0ebd07e395e56a1fbdf75ffedc4a05943daf472af163413ce9598", +                "sha256:acef3d59d47dd85ecf909c359d0fd2c81ed33bdff70216d3956b463e12c38a54", +                "sha256:b38694dcdac990a743aa654037ff1188c7a9801ac3ccc548d3341014bc5ca278", +                "sha256:b9edd0110a77fc321ab090aaa1cfcaba1d8499850a12848b81be2222eab648f6", +                "sha256:c08e95114951dc2090c4a630c2385bef681cacf12636fb0241accdc6b303fd81", +                "sha256:c5518d51a0735b1e6cee1fdce66359f8d2b59c3ca85dc2b0813a8aa86818a030", +                "sha256:c8fd0f1ae9d92b42854b2979024d7597685ce4ada367172ed7c09edf2cef9cb8", +                "sha256:ca3820eb7f7faf7f0aa88de0e54681bddcb46e485beb844fcecbcd1c8bd01689", +                "sha256:cf8b574c7b9aa060c62116d4181f3a1a4e821b2ec5cbfe3775809474113748d4", +                "sha256:d3155d828dec1d43283bd24d3d3e0d9c7c350cdfcc0bd06c0ad1209c1bbc36d0", +                "sha256:f8d6f8db88049a699817fd9178782867bf22283e3813064302ac59f61d95be05", +                "sha256:fd34fbbfbc40628200730bc1febe30631347103fc8d3d4fa012c21ab9c11eca9" +            ], +            "markers": "python_version >= '3.6'", +            "version": "==1.3.1" +        }, +        "matplotlib": { +            "hashes": [ +                "sha256:1f83a32e4b6045191f9d34e4dc68c0a17c870b57ef9cca518e516da591246e79", +                "sha256:2eee37340ca1b353e0a43a33da79d0cd4bcb087064a0c3c3d1329cdea8fbc6f3", +                "sha256:53ceb12ef44f8982b45adc7a0889a7e2df1d758e8b360f460e435abe8a8cd658", +                "sha256:574306171b84cd6854c83dc87bc353cacc0f60184149fb00c9ea871eca8c1ecb", +                "sha256:7561fd541477d41f3aa09457c434dd1f7604f3bd26d7858d52018f5dfe1c06d1", +                "sha256:7a54efd6fcad9cb3cd5ef2064b5a3eeb0b63c99f26c346bdcf66e7c98294d7cc", +                "sha256:7f16660edf9a8bcc0f766f51c9e1b9d2dc6ceff6bf636d2dbd8eb925d5832dfd", +                "sha256:81e6fe8b18ef5be67f40a1d4f07d5a4ed21d3878530193898449ddef7793952f", +                "sha256:84a10e462120aa7d9eb6186b50917ed5a6286ee61157bfc17c5b47987d1a9068", +                "sha256:84d4c4f650f356678a5d658a43ca21a41fca13f9b8b00169c0b76e6a6a948908", +                "sha256:86dc94e44403fa0f2b1dd76c9794d66a34e821361962fe7c4e078746362e3b14", +                "sha256:90dbc007f6389bcfd9ef4fe5d4c78c8d2efe4e0ebefd48b4f221cdfed5672be2", +                "sha256:9f374961a3996c2d1b41ba3145462c3708a89759e604112073ed6c8bdf9f622f", +                "sha256:a18cc1ab4a35b845cf33b7880c979f5c609fd26c2d6e74ddfacb73dcc60dd956", +                "sha256:a97781453ac79409ddf455fccf344860719d95142f9c334f2a8f3fff049ffec3", +                "sha256:a989022f89cda417f82dbf65e0a830832afd8af743d05d1414fb49549287ff04", +                "sha256:ac2a30a09984c2719f112a574b6543ccb82d020fd1b23b4d55bf4759ba8dd8f5", +                "sha256:be4430b33b25e127fc4ea239cc386389de420be4d63e71d5359c20b562951ce1", +                "sha256:c45e7bf89ea33a2adaef34774df4e692c7436a18a48bcb0e47a53e698a39fa39" +            ], +            "index": "pypi", +            "version": "==3.4.1" +        },          "multidict": {              "hashes": [                  "sha256:1ece5a3369835c20ed57adadc663400b5525904e53bae59ec854a5d36b39b21a", @@ -254,46 +327,77 @@                  "sha256:fcfbb44c59af3f8ea984de67ec7c306f618a3ec771c2843804069917a8f2e255",                  "sha256:feed85993dbdb1dbc29102f50bca65bdc68f2c0c8d352468c25b54874f23c39d"              ], +            "markers": "python_version >= '3.5'",              "version": "==4.7.6"          }, +        "numpy": { +            "hashes": [ +                "sha256:2428b109306075d89d21135bdd6b785f132a1f5a3260c371cee1fae427e12727", +                "sha256:377751954da04d4a6950191b20539066b4e19e3b559d4695399c5e8e3e683bf6", +                "sha256:4703b9e937df83f5b6b7447ca5912b5f5f297aba45f91dbbbc63ff9278c7aa98", +                "sha256:471c0571d0895c68da309dacee4e95a0811d0a9f9f532a48dc1bea5f3b7ad2b7", +                "sha256:61d5b4cf73622e4d0c6b83408a16631b670fc045afd6540679aa35591a17fe6d", +                "sha256:6c915ee7dba1071554e70a3664a839fbc033e1d6528199d4621eeaaa5487ccd2", +                "sha256:6e51e417d9ae2e7848314994e6fc3832c9d426abce9328cf7571eefceb43e6c9", +                "sha256:719656636c48be22c23641859ff2419b27b6bdf844b36a2447cb39caceb00935", +                "sha256:780ae5284cb770ade51d4b4a7dce4faa554eb1d88a56d0e8b9f35fca9b0270ff", +                "sha256:878922bf5ad7550aa044aa9301d417e2d3ae50f0f577de92051d739ac6096cee", +                "sha256:924dc3f83de20437de95a73516f36e09918e9c9c18d5eac520062c49191025fb", +                "sha256:97ce8b8ace7d3b9288d88177e66ee75480fb79b9cf745e91ecfe65d91a856042", +                "sha256:9c0fab855ae790ca74b27e55240fe4f2a36a364a3f1ebcfd1fb5ac4088f1cec3", +                "sha256:9cab23439eb1ebfed1aaec9cd42b7dc50fc96d5cd3147da348d9161f0501ada5", +                "sha256:a8e6859913ec8eeef3dbe9aed3bf475347642d1cdd6217c30f28dee8903528e6", +                "sha256:aa046527c04688af680217fffac61eec2350ef3f3d7320c07fd33f5c6e7b4d5f", +                "sha256:abc81829c4039e7e4c30f7897938fa5d4916a09c2c7eb9b244b7a35ddc9656f4", +                "sha256:bad70051de2c50b1a6259a6df1daaafe8c480ca98132da98976d8591c412e737", +                "sha256:c73a7975d77f15f7f68dacfb2bca3d3f479f158313642e8ea9058eea06637931", +                "sha256:d15007f857d6995db15195217afdbddfcd203dfaa0ba6878a2f580eaf810ecd6", +                "sha256:d76061ae5cab49b83a8cf3feacefc2053fac672728802ac137dd8c4123397677", +                "sha256:e8e4fbbb7e7634f263c5b0150a629342cc19b47c5eba8d1cd4363ab3455ab576", +                "sha256:e9459f40244bb02b2f14f6af0cd0732791d72232bbb0dc4bab57ef88e75f6935", +                "sha256:edb1f041a9146dcf02cd7df7187db46ab524b9af2515f392f337c7cbbf5b52cd" +            ], +            "markers": "python_version >= '3.7'", +            "version": "==1.20.2" +        },          "pillow": {              "hashes": [ -                "sha256:01bb0a34f1a6689b138c0089d670ae2e8f886d2666a9b2f2019031abdea673c4", -                "sha256:07872f1d8421db5a3fe770f7480835e5e90fddb58f36c216d4a2ac0d594de474", -                "sha256:1022f8f6dc3c5b0dcf928f1c49ba2ac73051f576af100d57776e2b65c1f76a8d", -                "sha256:14415e9e28410232370615dbde0cf0a00e526f522f665460344a5b96973a3086", -                "sha256:172acfaf00434a28dddfe592d83f2980e22e63c769ff4a448ddf7b7a38ffd165", -                "sha256:1c5e3c36f02c815766ae9dd91899b1c5b4652f2a37b7a51609f3bd467c0f11fb", -                "sha256:292f2aa1ae5c5c1451cb4b558addb88c257411d3fd71c6cf45562911baffc979", -                "sha256:2a40d7d4b17db87f5b9a1efc0aff56000e1d0d5ece415090c102aafa0ccbe858", -                "sha256:2f0d7034d5faae9a8d1019d152ede924f653df2ce77d3bba4ce62cd21b5f94ae", -                "sha256:33fdbd4f5608c852d97264f9d2e3b54e9e9959083d008145175b86100b275e5b", -                "sha256:3b13d89d97b551e02549d1f0edf22bed6acfd6fd2e888cd1e9a953bf215f0e81", -                "sha256:3e759bcc03d6f39bc751e56d86bc87252b9a21c689a27c5ed753717a87d53a5b", -                "sha256:3ec87bd1248b23a2e4e19e774367fbe30fddc73913edc5f9b37470624f55dc1f", -                "sha256:436b0a2dd9fe3f7aa6a444af6bdf53c1eb8f5ced9ea3ef104daa83f0ea18e7bc", -                "sha256:43b3c859912e8bf754b3c5142df624794b18eb7ae07cfeddc917e1a9406a3ef2", -                "sha256:4fe74636ee71c57a7f65d7b21a9f127d842b4fb75511e5d256ace258826eb352", -                "sha256:59445af66b59cc39530b4f810776928d75e95f41e945f0c32a3de4aceb93c15d", -                "sha256:69da5b1d7102a61ce9b45deb2920a2012d52fd8f4201495ea9411d0071b0ec22", -                "sha256:7094bbdecb95ebe53166e4c12cf5e28310c2b550b08c07c5dc15433898e2238e", -                "sha256:8211cac9bf10461f9e33fe9a3af6c5131f3fdd0d10672afc2abb2c70cf95c5ca", -                "sha256:8cf77e458bd996dc85455f10fe443c0c946f5b13253773439bcbec08aa1aebc2", -                "sha256:924fc33cb4acaf6267b8ca3b8f1922620d57a28470d5e4f49672cea9a841eb08", -                "sha256:99ce3333b40b7a4435e0a18baad468d44ab118a4b1da0af0a888893d03253f1d", -                "sha256:a7d690b2c5f7e4a932374615fedceb1e305d2dd5363c1de15961725fe10e7d16", -                "sha256:b9af590adc1e46898a1276527f3cfe2da8048ae43fbbf9b1bf9395f6c99d9b47", -                "sha256:bb18422ad00c1fecc731d06592e99c3be2c634da19e26942ba2f13d805005cf2", -                "sha256:c10af40ee2f1a99e1ae755ab1f773916e8bca3364029a042cd9161c400416bd8", -                "sha256:c143c409e7bc1db784471fe9d0bf95f37c4458e879ad84cfae640cb74ee11a26", -                "sha256:c448d2b335e21951416a30cd48d35588d122a912d5fe9e41900afacecc7d21a1", -                "sha256:d30f30c044bdc0ab8f3924e1eeaac87e0ff8a27e87369c5cac4064b6ec78fd83", -                "sha256:df534e64d4f3e84e8f1e1a37da3f541555d947c1c1c09b32178537f0f243f69d", -                "sha256:f6fc18f9c9c7959bf58e6faf801d14fafb6d4717faaf6f79a68c8bb2a13dcf20", -                "sha256:ff83dfeb04c98bb3e7948f876c17513a34e9a19fd92e292288649164924c1b39" +                "sha256:01425106e4e8cee195a411f729cff2a7d61813b0b11737c12bd5991f5f14bcd5", +                "sha256:031a6c88c77d08aab84fecc05c3cde8414cd6f8406f4d2b16fed1e97634cc8a4", +                "sha256:083781abd261bdabf090ad07bb69f8f5599943ddb539d64497ed021b2a67e5a9", +                "sha256:0d19d70ee7c2ba97631bae1e7d4725cdb2ecf238178096e8c82ee481e189168a", +                "sha256:0e04d61f0064b545b989126197930807c86bcbd4534d39168f4aa5fda39bb8f9", +                "sha256:12e5e7471f9b637762453da74e390e56cc43e486a88289995c1f4c1dc0bfe727", +                "sha256:22fd0f42ad15dfdde6c581347eaa4adb9a6fc4b865f90b23378aa7914895e120", +                "sha256:238c197fc275b475e87c1453b05b467d2d02c2915fdfdd4af126145ff2e4610c", +                "sha256:3b570f84a6161cf8865c4e08adf629441f56e32f180f7aa4ccbd2e0a5a02cba2", +                "sha256:463822e2f0d81459e113372a168f2ff59723e78528f91f0bd25680ac185cf797", +                "sha256:4d98abdd6b1e3bf1a1cbb14c3895226816e666749ac040c4e2554231068c639b", +                "sha256:5afe6b237a0b81bd54b53f835a153770802f164c5570bab5e005aad693dab87f", +                "sha256:5b70110acb39f3aff6b74cf09bb4169b167e2660dabc304c1e25b6555fa781ef", +                "sha256:5cbf3e3b1014dddc45496e8cf38b9f099c95a326275885199f427825c6522232", +                "sha256:624b977355cde8b065f6d51b98497d6cd5fbdd4f36405f7a8790e3376125e2bb", +                "sha256:63728564c1410d99e6d1ae8e3b810fe012bc440952168af0a2877e8ff5ab96b9", +                "sha256:66cc56579fd91f517290ab02c51e3a80f581aba45fd924fcdee01fa06e635812", +                "sha256:6c32cc3145928c4305d142ebec682419a6c0a8ce9e33db900027ddca1ec39178", +                "sha256:8bb1e155a74e1bfbacd84555ea62fa21c58e0b4e7e6b20e4447b8d07990ac78b", +                "sha256:95d5ef984eff897850f3a83883363da64aae1000e79cb3c321915468e8c6add5", +                "sha256:a013cbe25d20c2e0c4e85a9daf438f85121a4d0344ddc76e33fd7e3965d9af4b", +                "sha256:a787ab10d7bb5494e5f76536ac460741788f1fbce851068d73a87ca7c35fc3e1", +                "sha256:a7d5e9fad90eff8f6f6106d3b98b553a88b6f976e51fce287192a5d2d5363713", +                "sha256:aac00e4bc94d1b7813fe882c28990c1bc2f9d0e1aa765a5f2b516e8a6a16a9e4", +                "sha256:b91c36492a4bbb1ee855b7d16fe51379e5f96b85692dc8210831fbb24c43e484", +                "sha256:c03c07ed32c5324939b19e36ae5f75c660c81461e312a41aea30acdd46f93a7c", +                "sha256:c5236606e8570542ed424849f7852a0ff0bce2c4c8d0ba05cc202a5a9c97dee9", +                "sha256:c6b39294464b03457f9064e98c124e09008b35a62e3189d3513e5148611c9388", +                "sha256:cb7a09e173903541fa888ba010c345893cd9fc1b5891aaf060f6ca77b6a3722d", +                "sha256:d68cb92c408261f806b15923834203f024110a2e2872ecb0bd2a110f89d3c602", +                "sha256:dc38f57d8f20f06dd7c3161c59ca2c86893632623f33a42d592f097b00f720a9", +                "sha256:e98eca29a05913e82177b3ba3d198b1728e164869c613d76d0de4bde6768a50e", +                "sha256:f217c3954ce5fd88303fc0c317af55d5e0204106d86dea17eb8205700d47dec2"              ],              "index": "pypi", -            "version": "==8.1.1" +            "version": "==8.2.0"          },          "pycares": {              "hashes": [ @@ -334,39 +438,23 @@                  "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",                  "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"              ], +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",              "version": "==2.20"          }, -        "pynacl": { -            "hashes": [ -                "sha256:05c26f93964373fc0abe332676cb6735f0ecad27711035b9472751faa8521255", -                "sha256:0c6100edd16fefd1557da078c7a31e7b7d7a52ce39fdca2bec29d4f7b6e7600c", -                "sha256:0d0a8171a68edf51add1e73d2159c4bc19fc0718e79dec51166e940856c2f28e", -                "sha256:1c780712b206317a746ace34c209b8c29dbfd841dfbc02aa27f2084dd3db77ae", -                "sha256:2424c8b9f41aa65bbdbd7a64e73a7450ebb4aa9ddedc6a081e7afcc4c97f7621", -                "sha256:2d23c04e8d709444220557ae48ed01f3f1086439f12dbf11976e849a4926db56", -                "sha256:30f36a9c70450c7878053fa1344aca0145fd47d845270b43a7ee9192a051bf39", -                "sha256:37aa336a317209f1bb099ad177fef0da45be36a2aa664507c5d72015f956c310", -                "sha256:4943decfc5b905748f0756fdd99d4f9498d7064815c4cf3643820c9028b711d1", -                "sha256:53126cd91356342dcae7e209f840212a58dcf1177ad52c1d938d428eebc9fee5", -                "sha256:57ef38a65056e7800859e5ba9e6091053cd06e1038983016effaffe0efcd594a", -                "sha256:5bd61e9b44c543016ce1f6aef48606280e45f892a928ca7068fba30021e9b786", -                "sha256:6482d3017a0c0327a49dddc8bd1074cc730d45db2ccb09c3bac1f8f32d1eb61b", -                "sha256:7d3ce02c0784b7cbcc771a2da6ea51f87e8716004512493a2b69016326301c3b", -                "sha256:a14e499c0f5955dcc3991f785f3f8e2130ed504fa3a7f44009ff458ad6bdd17f", -                "sha256:a39f54ccbcd2757d1d63b0ec00a00980c0b382c62865b61a505163943624ab20", -                "sha256:aabb0c5232910a20eec8563503c153a8e78bbf5459490c49ab31f6adf3f3a415", -                "sha256:bd4ecb473a96ad0f90c20acba4f0bf0df91a4e03a1f4dd6a4bdc9ca75aa3a715", -                "sha256:bf459128feb543cfca16a95f8da31e2e65e4c5257d2f3dfa8c0c1031139c9c92", -                "sha256:e2da3c13307eac601f3de04887624939aca8ee3c9488a0bb0eca4fb9401fc6b1", -                "sha256:f67814c38162f4deb31f68d590771a29d5ae3b1bd64b75cf232308e5c74777e0" -            ], -            "version": "==1.3.0" +        "pyparsing": { +            "hashes": [ +                "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", +                "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" +            ], +            "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", +            "version": "==2.4.7"          },          "python-dateutil": {              "hashes": [                  "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",                  "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"              ], +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",              "version": "==2.8.1"          },          "pytz": { @@ -379,36 +467,45 @@          },          "pyyaml": {              "hashes": [ -                "sha256:02c78d77281d8f8d07a255e57abdbf43b02257f59f50cc6b636937d68efa5dd0", -                "sha256:0dc9f2eb2e3c97640928dec63fd8dc1dd91e6b6ed236bd5ac00332b99b5c2ff9", -                "sha256:124fd7c7bc1e95b1eafc60825f2daf67c73ce7b33f1194731240d24b0d1bf628", -                "sha256:26fcb33776857f4072601502d93e1a619f166c9c00befb52826e7b774efaa9db", -                "sha256:31ba07c54ef4a897758563e3a0fcc60077698df10180abe4b8165d9895c00ebf", -                "sha256:3c49e39ac034fd64fd576d63bb4db53cda89b362768a67f07749d55f128ac18a", -                "sha256:52bf0930903818e600ae6c2901f748bc4869c0c406056f679ab9614e5d21a166", -                "sha256:5a3f345acff76cad4aa9cb171ee76c590f37394186325d53d1aa25318b0d4a09", -                "sha256:5e7ac4e0e79a53451dc2814f6876c2fa6f71452de1498bbe29c0b54b69a986f4", -                "sha256:7242790ab6c20316b8e7bb545be48d7ed36e26bbe279fd56f2c4a12510e60b4b", -                "sha256:737bd70e454a284d456aa1fa71a0b429dd527bcbf52c5c33f7c8eee81ac16b89", -                "sha256:8635d53223b1f561b081ff4adecb828fd484b8efffe542edcfdff471997f7c39", -                "sha256:8b818b6c5a920cbe4203b5a6b14256f0e5244338244560da89b7b0f1313ea4b6", -                "sha256:8bf38641b4713d77da19e91f8b5296b832e4db87338d6aeffe422d42f1ca896d", -                "sha256:a36a48a51e5471513a5aea920cdad84cbd56d70a5057cca3499a637496ea379c", -                "sha256:b2243dd033fd02c01212ad5c601dafb44fbb293065f430b0d3dbf03f3254d615", -                "sha256:cc547d3ead3754712223abb7b403f0a184e4c3eae18c9bb7fd15adef1597cc4b", -                "sha256:cc552b6434b90d9dbed6a4f13339625dc466fd82597119897e9489c953acbc22", -                "sha256:f3790156c606299ff499ec44db422f66f05a7363b39eb9d5b064f17bd7d7c47b", -                "sha256:f7a21e3d99aa3095ef0553e7ceba36fb693998fbb1226f1392ce33681047465f", -                "sha256:fdc6b2cb4b19e431994f25a9160695cc59a4e861710cc6fc97161c5e845fc579" +                "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf", +                "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696", +                "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393", +                "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77", +                "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922", +                "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5", +                "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8", +                "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10", +                "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc", +                "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018", +                "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e", +                "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253", +                "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347", +                "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183", +                "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541", +                "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb", +                "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185", +                "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc", +                "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db", +                "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa", +                "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46", +                "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122", +                "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b", +                "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63", +                "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df", +                "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc", +                "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247", +                "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6", +                "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"              ],              "index": "pypi", -            "version": "==5.4" +            "version": "==5.4.1"          },          "redis": {              "hashes": [                  "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2",                  "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"              ], +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",              "version": "==3.5.3"          },          "sentry-sdk": { @@ -424,6 +521,7 @@                  "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",                  "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"              ], +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",              "version": "==1.15.0"          },          "sortedcontainers": { @@ -446,6 +544,7 @@                  "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df",                  "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"              ], +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",              "version": "==1.26.4"          },          "yarl": { @@ -468,6 +567,7 @@                  "sha256:f18d68f2be6bf0e89f1521af2b1bb46e66ab0018faafa81d70f358153170a317",                  "sha256:f379b7f83f23fe12823085cd6b906edc49df969eb99757f58ff382349a3303c6"              ], +            "markers": "python_version >= '3.5'",              "version": "==1.5.1"          }      }, @@ -484,6 +584,7 @@                  "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6",                  "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"              ], +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",              "version": "==20.3.0"          },          "cfgv": { @@ -491,6 +592,7 @@                  "sha256:32e43d604bbe7896fe7c248a9c2276447dbef840feb28fe20494f62af110211d",                  "sha256:cf22deb93d4bcf92f345a5c3cd39d3d41d6340adc60c78bbbd6588c384fda6a1"              ], +            "markers": "python_full_version >= '3.6.1'",              "version": "==3.2.0"          },          "distlib": { @@ -509,19 +611,19 @@          },          "flake8": {              "hashes": [ -                "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839", -                "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b" +                "sha256:1aa8990be1e689d96c745c5682b687ea49f2e05a443aff1f8251092b0014e378", +                "sha256:3b9f848952dddccf635be78098ca75010f073bfe14d2c6bda867154bea728d2a"              ],              "index": "pypi", -            "version": "==3.8.4" +            "version": "==3.9.1"          },          "flake8-annotations": {              "hashes": [ -                "sha256:3a377140556aecf11fa9f3bb18c10db01f5ea56dc79a730e2ec9b4f1f49e2055", -                "sha256:e17947a48a5b9f632fe0c72682fc797c385e451048e7dfb20139f448a074cb3e" +                "sha256:0d6cd2e770b5095f09689c9d84cc054c51b929c41a68969ea1beb4b825cac515", +                "sha256:d10c4638231f8a50c0a597c4efce42bd7b7d85df4f620a0ddaca526138936a4f"              ],              "index": "pypi", -            "version": "==2.5.0" +            "version": "==2.6.2"          },          "flake8-bugbear": {              "hashes": [ @@ -533,11 +635,11 @@          },          "flake8-docstrings": {              "hashes": [ -                "sha256:3d5a31c7ec6b7367ea6506a87ec293b94a0a46c0bce2bb4975b7f1d09b6f3717", -                "sha256:a256ba91bc52307bef1de59e2a009c3cf61c3d0952dbe035d6ff7208940c2edc" +                "sha256:99cac583d6c7e32dd28bbfbef120a7c0d1b6dde4adb5a9fd441c4227a6534bde", +                "sha256:9fe7c6a306064af8e62a055c2f61e9eb1da55f84bb39caef2b84ce53708ac34b"              ],              "index": "pypi", -            "version": "==1.5.0" +            "version": "==1.6.0"          },          "flake8-import-order": {              "hashes": [ @@ -579,10 +681,11 @@          },          "identify": {              "hashes": [ -                "sha256:43cb1965e84cdd247e875dec6d13332ef5be355ddc16776396d98089b9053d87", -                "sha256:c7c0f590526008911ccc5ceee6ed7b085cbc92f7b6591d0ee5913a130ad64034" +                "sha256:398cb92a7599da0b433c65301a1b62b9b1f4bb8248719b84736af6c0b22289d6", +                "sha256:4537474817e0bbb8cea3e5b7504b7de6d44e3f169a90846cbc6adb0fc8294502"              ], -            "version": "==2.2.2" +            "markers": "python_full_version >= '3.6.1'", +            "version": "==2.2.3"          },          "mccabe": {              "hashes": [ @@ -593,10 +696,10 @@          },          "nodeenv": {              "hashes": [ -                "sha256:5304d424c529c997bc888453aeaa6362d242b6b4631e90f3d4bf1b290f1c84a9", -                "sha256:ab45090ae383b716c4ef89e690c41ff8c2b257b85b309f01f3654df3d084bd7c" +                "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b", +                "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"              ], -            "version": "==1.5.0" +            "version": "==1.6.0"          },          "pep8-naming": {              "hashes": [ @@ -608,65 +711,77 @@          },          "pre-commit": {              "hashes": [ -                "sha256:16212d1fde2bed88159287da88ff03796863854b04dc9f838a55979325a3d20e", -                "sha256:399baf78f13f4de82a29b649afd74bef2c4e28eb4f021661fc7f29246e8c7a3a" +                "sha256:029d53cb83c241fe7d66eeee1e24db426f42c858f15a38d20bcefd8d8e05c9da", +                "sha256:46b6ffbab37986c47d0a35e40906ae029376deed89a0eb2e446fb6e67b220427"              ],              "index": "pypi", -            "version": "==2.10.1" +            "version": "==2.12.0"          },          "pycodestyle": {              "hashes": [ -                "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367", -                "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e" +                "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068", +                "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"              ], -            "version": "==2.6.0" +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", +            "version": "==2.7.0"          },          "pydocstyle": {              "hashes": [                  "sha256:164befb520d851dbcf0e029681b91f4f599c62c5cd8933fd54b1bfbd50e89e1f",                  "sha256:d4449cf16d7e6709f63192146706933c7a334af7c0f083904799ccb851c50f6d"              ], +            "markers": "python_version >= '3.6'",              "version": "==6.0.0"          },          "pyflakes": {              "hashes": [ -                "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92", -                "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8" +                "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3", +                "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"              ], -            "version": "==2.2.0" +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", +            "version": "==2.3.1"          },          "pyyaml": {              "hashes": [ -                "sha256:02c78d77281d8f8d07a255e57abdbf43b02257f59f50cc6b636937d68efa5dd0", -                "sha256:0dc9f2eb2e3c97640928dec63fd8dc1dd91e6b6ed236bd5ac00332b99b5c2ff9", -                "sha256:124fd7c7bc1e95b1eafc60825f2daf67c73ce7b33f1194731240d24b0d1bf628", -                "sha256:26fcb33776857f4072601502d93e1a619f166c9c00befb52826e7b774efaa9db", -                "sha256:31ba07c54ef4a897758563e3a0fcc60077698df10180abe4b8165d9895c00ebf", -                "sha256:3c49e39ac034fd64fd576d63bb4db53cda89b362768a67f07749d55f128ac18a", -                "sha256:52bf0930903818e600ae6c2901f748bc4869c0c406056f679ab9614e5d21a166", -                "sha256:5a3f345acff76cad4aa9cb171ee76c590f37394186325d53d1aa25318b0d4a09", -                "sha256:5e7ac4e0e79a53451dc2814f6876c2fa6f71452de1498bbe29c0b54b69a986f4", -                "sha256:7242790ab6c20316b8e7bb545be48d7ed36e26bbe279fd56f2c4a12510e60b4b", -                "sha256:737bd70e454a284d456aa1fa71a0b429dd527bcbf52c5c33f7c8eee81ac16b89", -                "sha256:8635d53223b1f561b081ff4adecb828fd484b8efffe542edcfdff471997f7c39", -                "sha256:8b818b6c5a920cbe4203b5a6b14256f0e5244338244560da89b7b0f1313ea4b6", -                "sha256:8bf38641b4713d77da19e91f8b5296b832e4db87338d6aeffe422d42f1ca896d", -                "sha256:a36a48a51e5471513a5aea920cdad84cbd56d70a5057cca3499a637496ea379c", -                "sha256:b2243dd033fd02c01212ad5c601dafb44fbb293065f430b0d3dbf03f3254d615", -                "sha256:cc547d3ead3754712223abb7b403f0a184e4c3eae18c9bb7fd15adef1597cc4b", -                "sha256:cc552b6434b90d9dbed6a4f13339625dc466fd82597119897e9489c953acbc22", -                "sha256:f3790156c606299ff499ec44db422f66f05a7363b39eb9d5b064f17bd7d7c47b", -                "sha256:f7a21e3d99aa3095ef0553e7ceba36fb693998fbb1226f1392ce33681047465f", -                "sha256:fdc6b2cb4b19e431994f25a9160695cc59a4e861710cc6fc97161c5e845fc579" +                "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf", +                "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696", +                "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393", +                "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77", +                "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922", +                "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5", +                "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8", +                "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10", +                "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc", +                "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018", +                "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e", +                "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253", +                "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347", +                "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183", +                "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541", +                "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb", +                "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185", +                "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc", +                "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db", +                "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa", +                "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46", +                "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122", +                "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b", +                "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63", +                "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df", +                "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc", +                "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247", +                "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6", +                "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"              ],              "index": "pypi", -            "version": "==5.4" +            "version": "==5.4.1"          },          "six": {              "hashes": [                  "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",                  "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"              ], +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",              "version": "==1.15.0"          },          "snowballstemmer": { @@ -681,6 +796,7 @@                  "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",                  "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"              ], +            "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",              "version": "==0.10.2"          },          "virtualenv": { @@ -688,6 +804,7 @@                  "sha256:49ec4eb4c224c6f7dd81bb6d0a28a09ecae5894f4e593c89b0db0885f565a107",                  "sha256:83f95875d382c7abafe06bd2a4cdd1b363e1bb77e02f155ebe8ac082a916b37c"              ], +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",              "version": "==20.4.3"          }      } diff --git a/bot/constants.py b/bot/constants.py index 416dd0e7..a64882db 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -153,7 +153,7 @@ class Emojis:      christmas_tree = "\U0001F384"      check = "\u2611"      envelope = "\U0001F4E8" -    trashcan = "<:trashcan:637136429717389331>" +    trashcan = environ.get("TRASHCAN_EMOJI", "<:trashcan:637136429717389331>")      ok_hand = ":ok_hand:"      hand_raised = "\U0001f64b" @@ -168,6 +168,7 @@ class Emojis:      issue_closed = "<:IssueClosed:629695470570307614>"      pull_request = "<:PROpen:629695470175780875>"      pull_request_closed = "<:PRClosed:629695470519713818>" +    pull_request_draft = "<:PRDraft:829755345425399848>"      merge = "<:PRMerged:629695470570176522>"      number_emojis = { diff --git a/bot/exts/easter/april_fools_vids.py b/bot/exts/easter/april_fools_vids.py index efe7e677..c7a3c014 100644 --- a/bot/exts/easter/april_fools_vids.py +++ b/bot/exts/easter/april_fools_vids.py @@ -1,36 +1,26 @@  import logging  import random  from json import load -from pathlib import Path  from discord.ext import commands  log = logging.getLogger(__name__) +with open("bot/resources/easter/april_fools_vids.json", encoding="utf-8") as f: +    ALL_VIDS = load(f) +  class AprilFoolVideos(commands.Cog):      """A cog for April Fools' that gets a random April Fools' video from Youtube.""" -    def __init__(self, bot: commands.Bot): -        self.bot = bot -        self.yt_vids = self.load_json() -        self.youtubers = ['google']  # will add more in future - -    @staticmethod -    def load_json() -> dict: -        """A function to load JSON data.""" -        p = Path('bot/resources/easter/april_fools_vids.json') -        with p.open(encoding="utf-8") as json_file: -            all_vids = load(json_file) -        return all_vids -      @commands.command(name='fool')      async def april_fools(self, ctx: commands.Context) -> None:          """Get a random April Fools' video from Youtube.""" -        random_youtuber = random.choice(self.youtubers) -        category = self.yt_vids[random_youtuber] -        random_vid = random.choice(category) -        await ctx.send(f"Check out this April Fools' video by {random_youtuber}.\n\n{random_vid['link']}") +        video = random.choice(ALL_VIDS) + +        channel, url = video["channel"], video["url"] + +        await ctx.send(f"Check out this April Fools' video by {channel}.\n\n{url}")  def setup(bot: commands.Bot) -> None: diff --git a/bot/exts/evergreen/battleship.py b/bot/exts/evergreen/battleship.py index fa3fb35c..1681434f 100644 --- a/bot/exts/evergreen/battleship.py +++ b/bot/exts/evergreen/battleship.py @@ -227,7 +227,7 @@ class Game:              if message.content.lower() == "surrender":                  self.surrender = True                  return True -            self.match = re.match("([A-J]|[a-j]) ?((10)|[1-9])", message.content.strip()) +            self.match = re.fullmatch("([A-J]|[a-j]) ?((10)|[1-9])", message.content.strip())              if not self.match:                  self.bot.loop.create_task(message.add_reaction(CROSS_EMOJI))              return bool(self.match) diff --git a/bot/exts/evergreen/error_handler.py b/bot/exts/evergreen/error_handler.py index 28902503..8db49748 100644 --- a/bot/exts/evergreen/error_handler.py +++ b/bot/exts/evergreen/error_handler.py @@ -46,6 +46,11 @@ class CommandErrorHandler(commands.Cog):              logging.debug(f"Command {ctx.command} had its error already handled locally; ignoring.")              return +        parent_command = "" +        if subctx := getattr(ctx, "subcontext", None): +            parent_command = f"{ctx.command} " +            ctx = subctx +          error = getattr(error, 'original', error)          logging.debug(              f"Error Encountered: {type(error).__name__} - {str(error)}, " @@ -63,8 +68,9 @@ class CommandErrorHandler(commands.Cog):          if isinstance(error, commands.UserInputError):              self.revert_cooldown_counter(ctx.command, ctx.message) +            usage = f"```{ctx.prefix}{parent_command}{ctx.command} {ctx.command.signature}```"              embed = self.error_embed( -                f"Your input was invalid: {error}\n\nUsage:\n```{ctx.prefix}{ctx.command} {ctx.command.signature}```" +                f"Your input was invalid: {error}\n\nUsage:{usage}"              )              await ctx.send(embed=embed)              return @@ -95,7 +101,7 @@ class CommandErrorHandler(commands.Cog):              self.revert_cooldown_counter(ctx.command, ctx.message)              embed = self.error_embed(                  "The argument you provided was invalid: " -                f"{error}\n\nUsage:\n```{ctx.prefix}{ctx.command} {ctx.command.signature}```" +                f"{error}\n\nUsage:\n```{ctx.prefix}{parent_command}{ctx.command} {ctx.command.signature}```"              )              await ctx.send(embed=embed)              return diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 4a73d20b..a0316080 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -2,10 +2,10 @@ import logging  import random  import re  import typing as t -from enum import Enum +from dataclasses import dataclass  import discord -from discord.ext import commands, tasks +from discord.ext import commands  from bot.constants import (      Categories, @@ -17,6 +17,8 @@ from bot.constants import (      Tokens,      WHITELISTED_CHANNELS  ) +from bot.utils.decorators import whitelist_override +from bot.utils.extensions import invoke_help_command  log = logging.getLogger(__name__) @@ -24,20 +26,20 @@ BAD_RESPONSE = {      404: "Issue/pull request not located! Please enter a valid number!",      403: "Rate limit has been hit! Please try again later!"  } +REQUEST_HEADERS = { +    "Accept": "application/vnd.github.v3+json" +} -MAX_REQUESTS = 10 -REQUEST_HEADERS = dict() +REPOSITORY_ENDPOINT = "https://api.github.com/orgs/{org}/repos?per_page=100&type=public" +ISSUE_ENDPOINT = "https://api.github.com/repos/{user}/{repository}/issues/{number}" +PR_ENDPOINT = "https://api.github.com/repos/{user}/{repository}/pulls/{number}" -REPOS_API = "https://api.github.com/orgs/{org}/repos"  if GITHUB_TOKEN := Tokens.github:      REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}"  WHITELISTED_CATEGORIES = (      Categories.development, Categories.devprojects, Categories.media, Categories.staff  ) -WHITELISTED_CHANNELS_ON_MESSAGE = ( -    Channels.organisation, Channels.mod_meta, Channels.mod_tools, Channels.staff_voice -)  CODE_BLOCK_RE = re.compile(      r"^`([^`\n]+)`"  # Inline codeblock @@ -45,12 +47,45 @@ CODE_BLOCK_RE = re.compile(      re.DOTALL | re.MULTILINE  ) +# Maximum number of issues in one message +MAXIMUM_ISSUES = 5 + +# Regex used when looking for automatic linking in messages +# regex101 of current regex https://regex101.com/r/V2ji8M/6 +AUTOMATIC_REGEX = re.compile( +    r"((?P<org>[a-zA-Z0-9][a-zA-Z0-9\-]{1,39})\/)?(?P<repo>[\w\-\.]{1,100})#(?P<number>[0-9]+)" +) + + +@dataclass +class FoundIssue: +    """Dataclass representing an issue found by the regex.""" + +    organisation: t.Optional[str] +    repository: str +    number: str + +    def __hash__(self) -> int: +        return hash((self.organisation, self.repository, self.number)) -class FetchIssueErrors(Enum): -    """Errors returned in fetch issues.""" -    value_error = "Numbers not found." -    max_requests = "Max requests hit." +@dataclass +class FetchError: +    """Dataclass representing an error while fetching an issue.""" + +    return_code: int +    message: str + + +@dataclass +class IssueState: +    """Dataclass representing the state of an issue.""" + +    repository: str +    number: int +    url: str +    title: str +    emoji: str  class Issues(commands.Cog): @@ -59,97 +94,96 @@ class Issues(commands.Cog):      def __init__(self, bot: commands.Bot):          self.bot = bot          self.repos = [] -        self.get_pydis_repos.start() - -    @tasks.loop(minutes=30) -    async def get_pydis_repos(self) -> None: -        """Get all python-discord repositories on github.""" -        async with self.bot.http_session.get(REPOS_API.format(org="python-discord")) as resp: -            if resp.status == 200: -                data = await resp.json() -                for repo in data: -                    self.repos.append(repo["full_name"].split("/")[1]) -                self.repo_regex = "|".join(self.repos) -            else: -                log.debug(f"Failed to get latest Pydis repositories. Status code {resp.status}")      @staticmethod -    def check_in_block(message: discord.Message, repo_issue: str) -> bool: -        """Check whether the <repo>#<issue> is in codeblocks.""" -        block = re.findall(CODE_BLOCK_RE, message.content) - -        if not block: -            return False -        elif "#".join(repo_issue.split(" ")) in "".join([*block[0]]): -            return True -        return False +    def remove_codeblocks(message: str) -> str: +        """Remove any codeblock in a message.""" +        return re.sub(CODE_BLOCK_RE, "", message)      async def fetch_issues(              self, -            numbers: set, +            number: int,              repository: str,              user: str -    ) -> t.Union[FetchIssueErrors, str, list]: -        """Retrieve issue(s) from a GitHub repository.""" -        links = [] -        if not numbers: -            return FetchIssueErrors.value_error - -        if len(numbers) > MAX_REQUESTS: -            return FetchIssueErrors.max_requests - -        for number in numbers: -            url = f"https://api.github.com/repos/{user}/{repository}/issues/{number}" -            merge_url = f"https://api.github.com/repos/{user}/{repository}/pulls/{number}/merge" -            log.trace(f"Querying GH issues API: {url}") -            async with self.bot.http_session.get(url, headers=REQUEST_HEADERS) as r: -                json_data = await r.json() - -            if r.status in BAD_RESPONSE: -                log.warning(f"Received response {r.status} from: {url}") -                return f"[{str(r.status)}] #{number} {BAD_RESPONSE.get(r.status)}" - -            # The initial API request is made to the issues API endpoint, which will return information -            # if the issue or PR is present. However, the scope of information returned for PRs differs -            # from issues: if the 'issues' key is present in the response then we can pull the data we -            # need from the initial API call. -            if "issues" in json_data.get("html_url"): -                if json_data.get("state") == "open": -                    icon_url = Emojis.issue -                else: -                    icon_url = Emojis.issue_closed - -            # If the 'issues' key is not contained in the API response and there is no error code, then -            # we know that a PR has been requested and a call to the pulls API endpoint is necessary -            # to get the desired information for the PR. +    ) -> t.Union[IssueState, FetchError]: +        """ +        Retrieve an issue from a GitHub repository. + +        Returns IssueState on success, FetchError on failure. +        """ +        url = ISSUE_ENDPOINT.format(user=user, repository=repository, number=number) +        pulls_url = PR_ENDPOINT.format(user=user, repository=repository, number=number) +        log.trace(f"Querying GH issues API: {url}") + +        async with self.bot.http_session.get(url, headers=REQUEST_HEADERS) as r: +            json_data = await r.json() + +        if r.status == 403: +            if r.headers.get("X-RateLimit-Remaining") == "0": +                log.info(f"Ratelimit reached while fetching {url}") +                return FetchError(403, "Ratelimit reached, please retry in a few minutes.") +            return FetchError(403, "Cannot access issue.") +        elif r.status in (404, 410): +            return FetchError(r.status, "Issue not found.") +        elif r.status != 200: +            return FetchError(r.status, "Error while fetching issue.") + +        # The initial API request is made to the issues API endpoint, which will return information +        # if the issue or PR is present. However, the scope of information returned for PRs differs +        # from issues: if the 'issues' key is present in the response then we can pull the data we +        # need from the initial API call. +        if "issues" in json_data["html_url"]: +            if json_data.get("state") == "open": +                emoji = Emojis.issue              else: -                log.trace(f"PR provided, querying GH pulls API for additional information: {merge_url}") -                async with self.bot.http_session.get(merge_url) as m: -                    if json_data.get("state") == "open": -                        icon_url = Emojis.pull_request -                    # When the status is 204 this means that the state of the PR is merged -                    elif m.status == 204: -                        icon_url = Emojis.merge -                    else: -                        icon_url = Emojis.pull_request_closed +                emoji = Emojis.issue_closed + +        # If the 'issues' key is not contained in the API response and there is no error code, then +        # we know that a PR has been requested and a call to the pulls API endpoint is necessary +        # to get the desired information for the PR. +        else: +            log.trace(f"PR provided, querying GH pulls API for additional information: {pulls_url}") +            async with self.bot.http_session.get(pulls_url) as p: +                pull_data = await p.json() +                if pull_data["draft"]: +                    emoji = Emojis.pull_request_draft +                elif pull_data["state"] == "open": +                    emoji = Emojis.pull_request +                # When 'merged_at' is not None, this means that the state of the PR is merged +                elif pull_data["merged_at"] is not None: +                    emoji = Emojis.merge +                else: +                    emoji = Emojis.pull_request_closed -            issue_url = json_data.get("html_url") -            links.append([icon_url, f"[{repository}] #{number} {json_data.get('title')}", issue_url]) +        issue_url = json_data.get("html_url") -        return links +        return IssueState(repository, number, issue_url, json_data.get('title', ''), emoji)      @staticmethod -    def get_embed(result: list, user: str = "python-discord", repository: str = "") -> discord.Embed: -        """Get Response Embed.""" -        description_list = ["{0} [{1}]({2})".format(*link) for link in result] +    def format_embed( +            results: t.List[t.Union[IssueState, FetchError]], +            user: str, +            repository: t.Optional[str] = None +    ) -> discord.Embed: +        """Take a list of IssueState or FetchError and format a Discord embed for them.""" +        description_list = [] + +        for result in results: +            if isinstance(result, IssueState): +                description_list.append(f"{result.emoji} [{result.title}]({result.url})") +            elif isinstance(result, FetchError): +                description_list.append(f":x: [{result.return_code}] {result.message}") +          resp = discord.Embed(              colour=Colours.bright_green,              description='\n'.join(description_list)          ) -        resp.set_author(name="GitHub", url=f"https://github.com/{user}/{repository}") +        embed_url = f"https://github.com/{user}/{repository}" if repository else f"https://github.com/{user}" +        resp.set_author(name="GitHub", url=embed_url)          return resp +    @whitelist_override(channels=WHITELISTED_CHANNELS, categories=WHITELISTED_CATEGORIES)      @commands.command(aliases=("pr",))      async def issue(              self, @@ -159,79 +193,79 @@ class Issues(commands.Cog):              user: str = "python-discord"      ) -> None:          """Command to retrieve issue(s) from a GitHub repository.""" -        if not ctx.guild or not( -            ctx.channel.category.id in WHITELISTED_CATEGORIES -            or ctx.channel.id in WHITELISTED_CHANNELS -        ): -            await ctx.send( -                embed=discord.Embed( -                    title=random.choice(NEGATIVE_REPLIES), -                    description=( -                        "You can't run this command in this channel. " -                        f"Try again in <#{Channels.community_bot_commands}>" -                    ), -                    colour=discord.Colour.red() -                ) -            ) -            return - -        result = await self.fetch_issues(set(numbers), repository, user) - -        if result == FetchIssueErrors.value_error: -            await ctx.invoke(self.bot.get_command('help'), 'issue') +        # Remove duplicates +        numbers = set(numbers) -        elif result == FetchIssueErrors.max_requests: +        if len(numbers) > MAXIMUM_ISSUES:              embed = discord.Embed(                  title=random.choice(ERROR_REPLIES),                  color=Colours.soft_red, -                description=f"Too many issues/PRs! (maximum of {MAX_REQUESTS})" +                description=f"Too many issues/PRs! (maximum of {MAXIMUM_ISSUES})"              )              await ctx.send(embed=embed) +            await invoke_help_command(ctx) -        elif isinstance(result, list): -            # Issue/PR format: emoji to show if open/closed/merged, number and the title as a singular link. -            resp = self.get_embed(result, user, repository) -            await ctx.send(embed=resp) - -        elif isinstance(result, str): -            await ctx.send(result) +        results = [await self.fetch_issues(number, repository, user) for number in numbers] +        await ctx.send(embed=self.format_embed(results, user, repository))      @commands.Cog.listener()      async def on_message(self, message: discord.Message) -> None: -        """Command to retrieve issue(s) from a GitHub repository using automatic linking if matching <repo>#<issue>.""" -        # Ignore messages not in whitelisted categories / channels, only when in guild. -        if message.guild and not ( -            message.channel.category.id in WHITELISTED_CATEGORIES -            or message.channel.id in WHITELISTED_CHANNELS_ON_MESSAGE -        ): +        """ +        Automatic issue linking. + +        Listener to retrieve issue(s) from a GitHub repository using automatic linking if matching <org>/<repo>#<issue>. +        """ +        # Ignore bots +        if message.author.bot:              return -        message_repo_issue_map = re.findall(fr"({self.repo_regex})#(\d+)", message.content) +        issues = [ +            FoundIssue(*match.group("org", "repo", "number")) +            for match in AUTOMATIC_REGEX.finditer(self.remove_codeblocks(message.content)) +        ]          links = [] -        if message_repo_issue_map: +        if issues: +            # Block this from working in DMs              if not message.guild:                  await message.channel.send(                      embed=discord.Embed(                          title=random.choice(NEGATIVE_REPLIES),                          description=( -                            "You can't retreive issues from DMs. " +                            "You can't retrieve issues from DMs. "                              f"Try again in <#{Channels.community_bot_commands}>"                          ), -                        colour=discord.Colour.red() +                        colour=Colours.soft_red                      )                  )                  return -            for repo_issue in message_repo_issue_map: -                if not self.check_in_block(message, " ".join(repo_issue)): -                    result = await self.fetch_issues({repo_issue[1]}, repo_issue[0], "python-discord") -                    if isinstance(result, list): -                        links.extend(result) + +            log.trace(f"Found {issues = }") +            # Remove duplicates +            issues = set(issues) + +            if len(issues) > MAXIMUM_ISSUES: +                embed = discord.Embed( +                    title=random.choice(ERROR_REPLIES), +                    color=Colours.soft_red, +                    description=f"Too many issues/PRs! (maximum of {MAXIMUM_ISSUES})" +                ) +                await message.channel.send(embed=embed, delete_after=5) +                return + +            for repo_issue in issues: +                result = await self.fetch_issues( +                    int(repo_issue.number), +                    repo_issue.repository, +                    repo_issue.organisation or "python-discord" +                ) +                if isinstance(result, IssueState): +                    links.append(result)          if not links:              return -        resp = self.get_embed(links, "python-discord") +        resp = self.format_embed(links, "python-discord")          await message.channel.send(embed=resp) diff --git a/bot/exts/evergreen/latex.py b/bot/exts/evergreen/latex.py new file mode 100644 index 00000000..c4a8597c --- /dev/null +++ b/bot/exts/evergreen/latex.py @@ -0,0 +1,94 @@ +import asyncio +import hashlib +import pathlib +import re +from concurrent.futures import ThreadPoolExecutor +from io import BytesIO + +import discord +import matplotlib.pyplot as plt +from discord.ext import commands + +# configure fonts and colors for matplotlib +plt.rcParams.update( +    { +        "font.size": 16, +        "mathtext.fontset": "cm",  # Computer Modern font set +        "mathtext.rm": "serif", +        "figure.facecolor": "36393F",  # matches Discord's dark mode background color +        "text.color": "white", +    } +) + +FORMATTED_CODE_REGEX = re.compile( +    r"(?P<delim>(?P<block>```)|``?)"        # code delimiter: 1-3 backticks; (?P=block) only matches if it's a block +    r"(?(block)(?:(?P<lang>[a-z]+)\n)?)"    # if we're in a block, match optional language (only letters plus newline) +    r"(?:[ \t]*\n)*"                        # any blank (empty or tabs/spaces only) lines before the code +    r"(?P<code>.*?)"                        # extract all code inside the markup +    r"\s*"                                  # any more whitespace before the end of the code markup +    r"(?P=delim)",                          # match the exact same delimiter from the start again +    re.DOTALL | re.IGNORECASE,              # "." also matches newlines, case insensitive +) + +CACHE_DIRECTORY = pathlib.Path("_latex_cache") +CACHE_DIRECTORY.mkdir(exist_ok=True) + + +class Latex(commands.Cog): +    """Renders latex.""" + +    @staticmethod +    def _render(text: str, filepath: pathlib.Path) -> BytesIO: +        """ +        Return the rendered image if latex compiles without errors, otherwise raise a BadArgument Exception. + +        Saves rendered image to cache. +        """ +        fig = plt.figure() +        rendered_image = BytesIO() +        fig.text(0, 1, text, horizontalalignment="left", verticalalignment="top") + +        try: +            plt.savefig(rendered_image, bbox_inches="tight", dpi=600) +        except ValueError as e: +            raise commands.BadArgument(str(e)) + +        rendered_image.seek(0) + +        with open(filepath, "wb") as f: +            f.write(rendered_image.getbuffer()) + +        return rendered_image + +    @staticmethod +    def _prepare_input(text: str) -> str: +        text = text.replace(r"\\", "$\n$")  # matplotlib uses \n for newlines, not \\ + +        if match := FORMATTED_CODE_REGEX.match(text): +            return match.group("code") +        else: +            return text + +    @commands.command() +    @commands.max_concurrency(1, commands.BucketType.guild, wait=True) +    async def latex(self, ctx: commands.Context, *, text: str) -> None: +        """Renders the text in latex and sends the image.""" +        text = self._prepare_input(text) +        query_hash = hashlib.md5(text.encode()).hexdigest() +        image_path = CACHE_DIRECTORY.joinpath(f"{query_hash}.png") +        async with ctx.typing(): +            if image_path.exists(): +                await ctx.send(file=discord.File(image_path)) +                return + +            with ThreadPoolExecutor() as pool: +                image = await asyncio.get_running_loop().run_in_executor( +                    pool, self._render, text, image_path +                ) + +            await ctx.send(file=discord.File(image, "latex.png")) + + +def setup(bot: commands.Bot) -> None: +    """Load the Latex Cog.""" +    bot.add_cog(Latex(bot)) diff --git a/bot/exts/evergreen/ping.py b/bot/exts/evergreen/ping.py new file mode 100644 index 00000000..97f8b34d --- /dev/null +++ b/bot/exts/evergreen/ping.py @@ -0,0 +1,27 @@ +from discord import Embed +from discord.ext import commands + +from bot.constants import Colours + + +class Ping(commands.Cog): +    """Ping the bot to see its latency and state.""" + +    def __init__(self, bot: commands.Bot): +        self.bot = bot + +    @commands.command(name="ping") +    async def ping(self, ctx: commands.Context) -> None: +        """Ping the bot to see its latency and state.""" +        embed = Embed( +            title=":ping_pong: Pong!", +            colour=Colours.bright_green, +            description=f"Gateway Latency: {round(self.bot.latency * 1000)}ms", +        ) + +        await ctx.send(embed=embed) + + +def setup(bot: commands.Bot) -> None: +    """Cog load.""" +    bot.add_cog(Ping(bot)) diff --git a/bot/exts/evergreen/timed.py b/bot/exts/evergreen/timed.py new file mode 100644 index 00000000..5f177fd6 --- /dev/null +++ b/bot/exts/evergreen/timed.py @@ -0,0 +1,46 @@ +from copy import copy +from time import perf_counter + +from discord import Message +from discord.ext import commands + + +class TimedCommands(commands.Cog): +    """Time the command execution of a command.""" + +    @staticmethod +    async def create_execution_context(ctx: commands.Context, command: str) -> commands.Context: +        """Get a new execution context for a command.""" +        msg: Message = copy(ctx.message) +        msg.content = f"{ctx.prefix}{command}" + +        return await ctx.bot.get_context(msg) + +    @commands.command(name="timed", aliases=["time", "t"]) +    async def timed(self, ctx: commands.Context, *, command: str) -> None: +        """Time the command execution of a command.""" +        new_ctx = await self.create_execution_context(ctx, command) + +        ctx.subcontext = new_ctx + +        if not ctx.subcontext.command: +            help_command = f"{ctx.prefix}help" +            error = f"The command you are trying to time doesn't exist. Use `{help_command}` for a list of commands." + +            await ctx.send(error) +            return + +        if new_ctx.command.qualified_name == "timed": +            await ctx.send("You are not allowed to time the execution of the `timed` command.") +            return + +        t_start = perf_counter() +        await new_ctx.command.invoke(new_ctx) +        t_end = perf_counter() + +        await ctx.send(f"Command execution for `{new_ctx.command}` finished in {(t_end - t_start):.4f} seconds.") + + +def setup(bot: commands.Bot) -> None: +    """Cog load.""" +    bot.add_cog(TimedCommands(bot)) diff --git a/bot/resources/easter/april_fools_vids.json b/bot/resources/easter/april_fools_vids.json index b2cbd07b..e1e8c70a 100644 --- a/bot/resources/easter/april_fools_vids.json +++ b/bot/resources/easter/april_fools_vids.json @@ -1,133 +1,130 @@ -{ -  "google": [ -    { -      "title": "Introducing Bad Joke Detector", -      "link": "https://youtu.be/OYcv406J_J4" -    }, -    { -      "title": "Introducing Google Cloud Hummus API - Find your Hummus!", -      "link": "https://youtu.be/0_5X6N6DHyk" -    }, -    { -      "title": "Introducing Google Play for Pets", -      "link": "https://youtu.be/UmJ2NBHXTqo" -    }, -    { -      "title": "Haptic Helpers: bringing you to your senses", -      "link": "https://youtu.be/3MA6_21nka8" -    }, -    { -      "title": "Introducing Google Wind", -      "link": "https://youtu.be/QAwL0O5nXe0" -    }, -    { -      "title": "Experience YouTube in #SnoopaVision", -      "link": "https://youtu.be/DPEJB-FCItk" -    }, -    { -      "title": "Introducing the self-driving bicycle in the Netherlands", -      "link": "https://youtu.be/LSZPNwZex9s" -    }, -    { -      "title": "Android Developer Story: The Guardian goes galactic with Android and Google Play", -      "link": "https://youtu.be/dFrgNiweQDk" -    }, -    { -      "title": "Introducing new delivery technology from Google Express", -      "link": "https://youtu.be/F0F6SnbqUcE" -    }, -    { -      "title": "Google Cardboard Plastic", -      "link": "https://youtu.be/VkOuShXpoKc" -    }, -    { -      "title": "Google Photos: Search your photos by emoji", -      "link": "https://youtu.be/HQtGFBbwKEk" -    }, -    { -      "title": "Introducing Google Actual Cloud Platform", -      "link": "https://youtu.be/Cp10_PygJ4o" -    }, -    { -      "title": "Introducing Dial-Up mode", -      "link": "https://youtu.be/XTTtkisylQw" -    }, -    { -      "title": "Smartbox by Inbox: the mailbox of tomorrow, today", -      "link": "https://youtu.be/hydLZJXG3Tk" -    }, -    { -      "title": "Introducing Coffee to the Home", -      "link": "https://youtu.be/U2JBFlW--UU" -    }, -    { -      "title": "Chrome for Android and iOS: Emojify the Web", -      "link": "https://youtu.be/G3NXNnoGr3Y" -    }, -    { -      "title": "Google Maps: Pokémon Challenge", -      "link": "https://youtu.be/4YMD6xELI_k" -    }, -    { -      "title": "Introducing Google Fiber to the Pole", -      "link": "https://youtu.be/qcgWRpQP6ds" -    }, -    { -      "title": "Introducing Gmail Blue", -      "link": "https://youtu.be/Zr4JwPb99qU" -    }, -    { -      "title": "Introducing Google Nose", -      "link": "https://youtu.be/VFbYadm_mrw" -    }, -    { -      "title": "Explore Treasure Mode with Google Maps", -      "link": "https://youtu.be/_qFFHC0eIUc" -    }, -    { -      "title": "YouTube's ready to select a winner", -      "link": "https://youtu.be/H542nLTTbu0" -    }, -    { -      "title": "A word about Gmail Tap", -      "link": "https://youtu.be/Je7Xq9tdCJc" -    }, -    { -      "title": "Introducing the Google Fiber Bar", -      "link": "https://youtu.be/re0VRK6ouwI" -    }, -    { -      "title": "Introducing Gmail Tap", -      "link": "https://youtu.be/1KhZKNZO8mQ" -    }, -    { -      "title": "Chrome Multitask Mode", -      "link": "https://youtu.be/UiLSiqyDf4Y" -    }, -    { -      "title": "Google Maps 8-bit for NES", -      "link": "https://youtu.be/rznYifPHxDg" -    }, -    { -      "title": "Being a Google Autocompleter", -      "link": "https://youtu.be/blB_X38YSxQ" -    }, -    { -      "title": "Introducing Gmail Motion", -      "link": "https://youtu.be/Bu927_ul_X0" -    }, -    { -      "title": "Introducing GeForce GTX G-Assist", -      "link": "https://youtu.be/smM-Wdk2RLQ" -    }, -    { -      "title": "The Hovering Mouse - Project McFly | Razer", -      "link": "https://youtu.be/IlCx5gjAmqI" -    }, -    { -      "title": "Be the Machine | Project Venom v2", -      "link": "https://youtu.be/j8UJE7DoyJ8" -    } -  ] - -} +[ +  { +    "url": "https://youtu.be/OYcv406J_J4", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/0_5X6N6DHyk", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/UmJ2NBHXTqo", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/3MA6_21nka8", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/QAwL0O5nXe0", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/DPEJB-FCItk", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/LSZPNwZex9s", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/dFrgNiweQDk", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/F0F6SnbqUcE", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/VkOuShXpoKc", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/HQtGFBbwKEk", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/Cp10_PygJ4o", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/XTTtkisylQw", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/hydLZJXG3Tk", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/U2JBFlW--UU", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/G3NXNnoGr3Y", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/4YMD6xELI_k", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/qcgWRpQP6ds", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/Zr4JwPb99qU", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/VFbYadm_mrw", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/_qFFHC0eIUc", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/H542nLTTbu0", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/Je7Xq9tdCJc", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/re0VRK6ouwI", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/1KhZKNZO8mQ", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/UiLSiqyDf4Y", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/rznYifPHxDg", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/blB_X38YSxQ", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/Bu927_ul_X0", +    "channel": "google" +  }, +  { +    "url": "https://youtu.be/smM-Wdk2RLQ", +    "channel": "nvidia" +  }, +  { +    "url": "https://youtu.be/IlCx5gjAmqI", +    "channel": "razer" +  }, +  { +    "url": "https://youtu.be/j8UJE7DoyJ8", +    "channel": "razer" +  } +] diff --git a/bot/resources/easter/easter_riddle.json b/bot/resources/easter/easter_riddle.json index e93f6dad..f7eb63d8 100644 --- a/bot/resources/easter/easter_riddle.json +++ b/bot/resources/easter/easter_riddle.json @@ -64,14 +64,6 @@        "correct_answer": "A chocolate one"    },    { -      "question": "Where does the Easter Bunny get his eggs?", -      "riddles": [ -            "Not a bush or tree", -            "Emoji for a body part" -        ], -      "correct_answer": "Eggplants" -  }, -  {        "question": "Why did the Easter Bunny have to fire the duck?",        "riddles": [              "Quack", diff --git a/bot/resources/halloween/spookysounds/109710__tomlija__horror-gate.mp3 b/bot/resources/halloween/spookysounds/109710__tomlija__horror-gate.mp3 Binary files differdeleted file mode 100644 index 495f2bd1..00000000 --- a/bot/resources/halloween/spookysounds/109710__tomlija__horror-gate.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/126113__klankbeeld__laugh.mp3 b/bot/resources/halloween/spookysounds/126113__klankbeeld__laugh.mp3 Binary files differdeleted file mode 100644 index 538feabc..00000000 --- a/bot/resources/halloween/spookysounds/126113__klankbeeld__laugh.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/133674__klankbeeld__horror-laugh-original-132802-nanakisan-evil-laugh-08.mp3 b/bot/resources/halloween/spookysounds/133674__klankbeeld__horror-laugh-original-132802-nanakisan-evil-laugh-08.mp3 Binary files differdeleted file mode 100644 index 17f66698..00000000 --- a/bot/resources/halloween/spookysounds/133674__klankbeeld__horror-laugh-original-132802-nanakisan-evil-laugh-08.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/14570__oscillator__ghost-fx.mp3 b/bot/resources/halloween/spookysounds/14570__oscillator__ghost-fx.mp3 Binary files differdeleted file mode 100644 index 5670657c..00000000 --- a/bot/resources/halloween/spookysounds/14570__oscillator__ghost-fx.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/168650__0xmusex0__doorcreak.mp3 b/bot/resources/halloween/spookysounds/168650__0xmusex0__doorcreak.mp3 Binary files differdeleted file mode 100644 index 42f9e9fd..00000000 --- a/bot/resources/halloween/spookysounds/168650__0xmusex0__doorcreak.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/171078__klankbeeld__horror-scream-woman-long.mp3 b/bot/resources/halloween/spookysounds/171078__klankbeeld__horror-scream-woman-long.mp3 Binary files differdeleted file mode 100644 index 1cdb0f4d..00000000 --- a/bot/resources/halloween/spookysounds/171078__klankbeeld__horror-scream-woman-long.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/193812__geoneo0__four-voices-whispering-6.mp3 b/bot/resources/halloween/spookysounds/193812__geoneo0__four-voices-whispering-6.mp3 Binary files differdeleted file mode 100644 index 89150d57..00000000 --- a/bot/resources/halloween/spookysounds/193812__geoneo0__four-voices-whispering-6.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/237282__devilfish101__frantic-violin-screech.mp3 b/bot/resources/halloween/spookysounds/237282__devilfish101__frantic-violin-screech.mp3 Binary files differdeleted file mode 100644 index b5f85f8d..00000000 --- a/bot/resources/halloween/spookysounds/237282__devilfish101__frantic-violin-screech.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/249686__cylon8472__cthulhu-growl.mp3 b/bot/resources/halloween/spookysounds/249686__cylon8472__cthulhu-growl.mp3 Binary files differdeleted file mode 100644 index d141f68e..00000000 --- a/bot/resources/halloween/spookysounds/249686__cylon8472__cthulhu-growl.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/35716__analogchill__scream.mp3 b/bot/resources/halloween/spookysounds/35716__analogchill__scream.mp3 Binary files differdeleted file mode 100644 index a0614b53..00000000 --- a/bot/resources/halloween/spookysounds/35716__analogchill__scream.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/413315__inspectorj__something-evil-approaches-a.mp3 b/bot/resources/halloween/spookysounds/413315__inspectorj__something-evil-approaches-a.mp3 Binary files differdeleted file mode 100644 index 38374316..00000000 --- a/bot/resources/halloween/spookysounds/413315__inspectorj__something-evil-approaches-a.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/60571__gabemiller74__breathofdeath.mp3 b/bot/resources/halloween/spookysounds/60571__gabemiller74__breathofdeath.mp3 Binary files differdeleted file mode 100644 index f769d9d8..00000000 --- a/bot/resources/halloween/spookysounds/60571__gabemiller74__breathofdeath.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/Female_Monster_Growls_.mp3 b/bot/resources/halloween/spookysounds/Female_Monster_Growls_.mp3 Binary files differdeleted file mode 100644 index 8b04f0f5..00000000 --- a/bot/resources/halloween/spookysounds/Female_Monster_Growls_.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/Male_Zombie_Roar_.mp3 b/bot/resources/halloween/spookysounds/Male_Zombie_Roar_.mp3 Binary files differdeleted file mode 100644 index 964d685e..00000000 --- a/bot/resources/halloween/spookysounds/Male_Zombie_Roar_.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/Monster_Alien_Growl_Calm_.mp3 b/bot/resources/halloween/spookysounds/Monster_Alien_Growl_Calm_.mp3 Binary files differdeleted file mode 100644 index 9e643773..00000000 --- a/bot/resources/halloween/spookysounds/Monster_Alien_Growl_Calm_.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/Monster_Alien_Grunt_Hiss_.mp3 b/bot/resources/halloween/spookysounds/Monster_Alien_Grunt_Hiss_.mp3 Binary files differdeleted file mode 100644 index ad99cf76..00000000 --- a/bot/resources/halloween/spookysounds/Monster_Alien_Grunt_Hiss_.mp3 +++ /dev/null diff --git a/bot/resources/halloween/spookysounds/sources.txt b/bot/resources/halloween/spookysounds/sources.txt deleted file mode 100644 index 7df03c2e..00000000 --- a/bot/resources/halloween/spookysounds/sources.txt +++ /dev/null @@ -1,41 +0,0 @@ -Female_Monster_Growls_ -Male_Zombie_Roar_ -Monster_Alien_Growl_Calm_ -Monster_Alien_Grunt_Hiss_ -https://www.youtube.com/audiolibrary/soundeffects - -413315__inspectorj__something-evil-approaches-a -https://freesound.org/people/InspectorJ/sounds/413315/ - -133674__klankbeeld__horror-laugh-original-132802-nanakisan-evil-laugh-08 -https://freesound.org/people/klankbeeld/sounds/133674/ - -35716__analogchill__scream -https://freesound.org/people/analogchill/sounds/35716/ - -249686__cylon8472__cthulhu-growl -https://freesound.org/people/cylon8472/sounds/249686/ - -126113__klankbeeld__laugh -https://freesound.org/people/klankbeeld/sounds/126113/ - -14570__oscillator__ghost-fx -https://freesound.org/people/oscillator/sounds/14570/ - -60571__gabemiller74__breathofdeath -https://freesound.org/people/gabemiller74/sounds/60571/ - -168650__0xmusex0__doorcreak -https://freesound.org/people/0XMUSEX0/sounds/168650/ - -193812__geoneo0__four-voices-whispering-6 -https://freesound.org/people/geoneo0/sounds/193812/ - -109710__tomlija__horror-gate -https://freesound.org/people/Tomlija/sounds/109710/ - -171078__klankbeeld__horror-scream-woman-long -https://freesound.org/people/klankbeeld/sounds/171078/ - -237282__devilfish101__frantic-violin-screech -https://freesound.org/people/devilfish101/sounds/237282/  |