Update dependencies and copyright year (#2436)

- aiohttp 3.5
- websockets 7
- Rapptz/discord.py@700dbb5
- A few others

Signed-off-by: Toby Harradine <tobyharradine@gmail.com>
This commit is contained in:
Toby Harradine 2019-02-13 10:49:11 +11:00 committed by GitHub
parent c87286d3c6
commit 9869f95bd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 439 additions and 294 deletions

View File

@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found. the "copyright" line and a pointer to where the full notice is found.
Red - A fully customizable Discord bot Red - A fully customizable Discord bot
Copyright (C) 2015-2018 Twentysix Copyright (C) 2015-2019 Twentysix
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode: notice like this when it starts in an interactive mode:
Red-DiscordBot Copyright (C) 2015-2018 Twentysix Red-DiscordBot Copyright (C) 2015-2019 Twentysix
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details. under certain conditions; type `show c' for details.

View File

@ -9,5 +9,5 @@ gettext:
REF?=rewrite REF?=rewrite
update_vendor: update_vendor:
pip install --upgrade --no-deps -t . https://github.com/Rapptz/discord.py/archive/$(REF).tar.gz#egg=discord.py pip install --upgrade --no-deps -t . https://github.com/Rapptz/discord.py/archive/$(REF).tar.gz#egg=discord.py
rm -r discord.py*.egg-info rm -r discord.py*-info
$(MAKE) reformat $(MAKE) reformat

267
Pipfile.lock generated
View File

@ -16,37 +16,37 @@
"default": { "default": {
"aiohttp": { "aiohttp": {
"hashes": [ "hashes": [
"sha256:0419705a36b43c0ac6f15469f9c2a08cad5c939d78bd12a5c23ea167c8253b2b", "sha256:00d198585474299c9c3b4f1d5de1a576cc230d562abc5e4a0e81d71a20a6ca55",
"sha256:1812fc4bc6ac1bde007daa05d2d0f61199324e0cc893b11523e646595047ca08", "sha256:0155af66de8c21b8dba4992aaeeabf55503caefae00067a3b1139f86d0ec50ed",
"sha256:2214b5c0153f45256d5d52d1e0cafe53f9905ed035a142191727a5fb620c03dd", "sha256:09654a9eca62d1bd6d64aa44db2498f60a5c1e0ac4750953fdd79d5c88955e10",
"sha256:275909137f0c92c61ba6bb1af856a522d5546f1de8ea01e4e726321c697754ac", "sha256:199f1d106e2b44b6dacdf6f9245493c7d716b01d0b7fbe1959318ba4dc64d1f5",
"sha256:3983611922b561868428ea1e7269e757803713f55b53502423decc509fef1650", "sha256:296f30dedc9f4b9e7a301e5cc963012264112d78a1d3094cd83ef148fdf33ca1",
"sha256:51afec6ffa50a9da4cdef188971a802beb1ca8e8edb40fa429e5e529db3475fa", "sha256:368ed312550bd663ce84dc4b032a962fcb3c7cae099dbbd48663afc305e3b939",
"sha256:589f2ec8a101a0f340453ee6945bdfea8e1cd84c8d88e5be08716c34c0799d95", "sha256:40d7ea570b88db017c51392349cf99b7aefaaddd19d2c78368aeb0bddde9d390",
"sha256:789820ddc65e1f5e71516adaca2e9022498fa5a837c79ba9c692a9f8f916c330", "sha256:629102a193162e37102c50713e2e31dc9a2fe7ac5e481da83e5bb3c0cee700aa",
"sha256:7a968a0bdaaf9abacc260911775611c9a602214a23aeb846f2eb2eeaa350c4dc", "sha256:6d5ec9b8948c3d957e75ea14d41e9330e1ac3fed24ec53766c780f82805140dc",
"sha256:7aeefbed253f59ea39e70c5848de42ed85cb941165357fc7e87ab5d8f1f9592b", "sha256:87331d1d6810214085a50749160196391a712a13336cd02ce1c3ea3d05bcf8d5",
"sha256:7b2eb55c66512405103485bd7d285a839d53e7fdc261ab20e5bcc51d7aaff5de", "sha256:9a02a04bbe581c8605ac423ba3a74999ec9d8bce7ae37977a3d38680f5780b6d",
"sha256:87bc95d3d333bb689c8d755b4a9d7095a2356108002149523dfc8e607d5d32a4", "sha256:9c4c83f4fa1938377da32bc2d59379025ceeee8e24b89f72fcbccd8ca22dc9bf",
"sha256:9d80e40db208e29168d3723d1440ecbb06054d349c5ece6a2c5a611490830dd7", "sha256:9cddaff94c0135ee627213ac6ca6d05724bfe6e7a356e5e09ec57bd3249510f6",
"sha256:a1b442195c2a77d33e4dbee67c9877ccbdd3a1f686f91eb479a9577ed8cc326b", "sha256:a25237abf327530d9561ef751eef9511ab56fd9431023ca6f4803f1994104d72",
"sha256:ab3d769413b322d6092f169f316f7b21cd261a7589f7e31db779d5731b0480d8", "sha256:a5cbd7157b0e383738b8e29d6e556fde8726823dae0e348952a61742b21aeb12",
"sha256:b066d3dec5d0f5aee6e34e5765095dc3d6d78ef9839640141a2b20816a0642bd", "sha256:a97a516e02b726e089cffcde2eea0d3258450389bbac48cbe89e0f0b6e7b0366",
"sha256:b24e7845ae8de3e388ef4bcfcf7f96b05f52c8e633b33cf8003a6b1d726fc7c2", "sha256:acc89b29b5f4e2332d65cd1b7d10c609a75b88ef8925d487a611ca788432dfa4",
"sha256:c59a953c3f8524a7c86eaeaef5bf702555be12f5668f6384149fe4bb75c52698", "sha256:b05bd85cc99b06740aad3629c2585bda7b83bd86e080b44ba47faf905fdf1300",
"sha256:cf2cc6c2c10d242790412bea7ccf73726a9a44b4c4b073d2699ef3b48971fd95", "sha256:c2bec436a2b5dafe5eaeb297c03711074d46b6eb236d002c13c42f25c4a8ce9d",
"sha256:e0c9c8d4150ae904f308ff27b35446990d2b1dfc944702a21925937e937394c6", "sha256:cc619d974c8c11fe84527e4b5e1c07238799a8c29ea1c1285149170524ba9303",
"sha256:f1839db4c2b08a9c8f9788112644f8a8557e8e0ecc77b07091afabb941dc55d0", "sha256:d4392defd4648badaa42b3e101080ae3313e8f4787cb517efd3f5b8157eaefd6",
"sha256:f3df52362be39908f9c028a65490fae0475e4898b43a03d8aa29d1e765b45e07" "sha256:e1c3c582ee11af7f63a34a46f0448fca58e59889396ffdae1f482085061a2889"
], ],
"version": "==3.4.4" "version": "==3.5.4"
}, },
"aiohttp-json-rpc": { "aiohttp-json-rpc": {
"hashes": [ "hashes": [
"sha256:00d72f40edfc7271578d545a8c47874c0e23cc5d3201ed8128481f6a4af47e32", "sha256:1d040b7b10ff414f9174398ff6e9c647eb0434a00939450b33aa539177c51dcf",
"sha256:02d83b6998f8a0b7e59b46f0cb8a96b475bbf82600b1f9527df47135353f1ca8" "sha256:5f5fb141c6263d2ea52a4173babe9449eef4029620dc49936dca45cdc17ac9dd"
], ],
"version": "==0.11.2" "version": "==0.12"
}, },
"appdirs": { "appdirs": {
"hashes": [ "hashes": [
@ -83,13 +83,6 @@
], ],
"version": "==0.4.1" "version": "==0.4.1"
}, },
"distro": {
"hashes": [
"sha256:224041cef9600e72d19ae41ba006e71c05c4dc802516da715d7fda55ba3d8742",
"sha256:6ec8e539cf412830e5ccf521aecf879f2c7fcf60ce446e33cd16eef1ed8a0158"
],
"version": "==1.3.0"
},
"dnspython": { "dnspython": {
"hashes": [ "hashes": [
"sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01", "sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01",
@ -261,10 +254,10 @@
}, },
"red-lavalink": { "red-lavalink": {
"hashes": [ "hashes": [
"sha256:6348cc168572b1984e9831a29b4023f02372bb683fec8e863df5abeb605b630a", "sha256:10a07b2b5736f52a0f5c3eeab3fbc3bf6a242ca6ee284a29ad79d6d1673ddfc3",
"sha256:a5ab9d66d1a4728abe48ccb38a2a130a8a2d70fb23c9d9df2b747c82fbeb67a6" "sha256:9df0ddaa92d0d7294a4e236c4069765a0b8e5f258c18075dedf28f4b64a1aab5"
], ],
"version": "==0.2.0" "version": "==0.2.1"
}, },
"schema": { "schema": {
"hashes": [ "hashes": [
@ -275,29 +268,29 @@
}, },
"websockets": { "websockets": {
"hashes": [ "hashes": [
"sha256:0e2f7d6567838369af074f0ef4d0b802d19fa1fee135d864acc656ceefa33136", "sha256:04b42a1b57096ffa5627d6a78ea1ff7fad3bc2c0331ffc17bc32a4024da7fea0",
"sha256:2a16dac282b2fdae75178d0ed3d5b9bc3258dabfae50196cbb30578d84b6f6a6", "sha256:08e3c3e0535befa4f0c4443824496c03ecc25062debbcf895874f8a0b4c97c9f",
"sha256:5a1fa6072405648cb5b3688e9ed3b94be683ce4a4e5723e6f5d34859dee495c1", "sha256:10d89d4326045bf5e15e83e9867c85d686b612822e4d8f149cf4840aab5f46e0",
"sha256:5c1f55a1274df9d6a37553fef8cff2958515438c58920897675c9bc70f5a0538", "sha256:232fac8a1978fc1dead4b1c2fa27c7756750fb393eb4ac52f6bc87ba7242b2fa",
"sha256:669d1e46f165e0ad152ed8197f7edead22854a6c90419f544e0f234cc9dac6c4", "sha256:4bf4c8097440eff22bc78ec76fe2a865a6e658b6977a504679aaf08f02c121da",
"sha256:695e34c4dbea18d09ab2c258994a8bf6a09564e762655408241f6a14592d2908", "sha256:51642ea3a00772d1e48fb0c492f0d3ae3b6474f34d20eca005a83f8c9c06c561",
"sha256:6b2e03d69afa8d20253455e67b64de1a82ff8612db105113cccec35d3f8429f0", "sha256:55d86102282a636e195dad68aaaf85b81d0bef449d7e2ef2ff79ac450bb25d53",
"sha256:79ca7cdda7ad4e3663ea3c43bfa8637fc5d5604c7737f19a8964781abbd1148d", "sha256:564d2675682bd497b59907d2205031acbf7d3fadf8c763b689b9ede20300b215",
"sha256:7fd2dd9a856f72e6ed06f82facfce01d119b88457cd4b47b7ae501e8e11eba9c", "sha256:5d13bf5197a92149dc0badcc2b699267ff65a867029f465accfca8abab95f412",
"sha256:82c0354ac39379d836719a77ee360ef865377aa6fdead87909d50248d0f05f4d", "sha256:5eda665f6789edb9b57b57a159b9c55482cbe5b046d7db458948370554b16439",
"sha256:8f3b956d11c5b301206382726210dc1d3bee1a9ccf7aadf895aaf31f71c3716c", "sha256:5edb2524d4032be4564c65dc4f9d01e79fe8fad5f966e5b552f4e5164fef0885",
"sha256:91ec98640220ae05b34b79ee88abf27f97ef7c61cf525eec57ea8fcea9f7dddb", "sha256:79691794288bc51e2a3b8de2bc0272ca8355d0b8503077ea57c0716e840ebaef",
"sha256:952be9540d83dba815569d5cb5f31708801e0bbfc3a8c5aef1890b57ed7e58bf", "sha256:7fcc8681e9981b9b511cdee7c580d5b005f3bb86b65bde2188e04a29f1d63317",
"sha256:99ac266af38ba1b1fe13975aea01ac0e14bb5f3a3200d2c69f05385768b8568e", "sha256:8e447e05ec88b1b408a4c9cde85aa6f4b04f06aa874b9f0b8e8319faf51b1fee",
"sha256:9fa122e7adb24232247f8a89f2d9070bf64b7869daf93ac5e19546b409e47e96", "sha256:90ea6b3e7787620bb295a4ae050d2811c807d65b1486749414f78cfd6fb61489",
"sha256:a0873eadc4b8ca93e2e848d490809e0123eea154aa44ecd0109c4d0171869584", "sha256:9e13239952694b8b831088431d15f771beace10edfcf9ef230cefea14f18508f",
"sha256:cb998bd4d93af46b8b49ecf5a72c0a98e5cc6d57fdca6527ba78ad89d6606484", "sha256:d40f081187f7b54d7a99d8a5c782eaa4edc335a057aa54c85059272ed826dc09",
"sha256:e02e57346f6a68523e3c43bbdf35dde5c440318d1f827208ae455f6a2ace446d", "sha256:e1df1a58ed2468c7b7ce9a2f9752a32ad08eac2bcd56318625c3647c2cd2da6f",
"sha256:e79a5a896bcee7fff24a788d72e5c69f13e61369d055f28113e71945a7eb1559", "sha256:e98d0cec437097f09c7834a11c69d79fe6241729b23f656cfc227e93294fc242",
"sha256:ee55eb6bcf23ecc975e6b47c127c201b913598f38b6a300075f84eeef2d3baff", "sha256:f8d59627702d2ff27cb495ca1abdea8bd8d581de425c56e93bff6517134e0a9b",
"sha256:f1414e6cbcea8d22843e7eafdfdfae3dd1aba41d1945f6ca66e4806c07c4f454" "sha256:fc30cdf2e949a2225b012a7911d1d031df3d23e99b7eda7dfc982dc4a860dae9"
], ],
"version": "==6.0" "version": "==7.0"
}, },
"yarl": { "yarl": {
"hashes": [ "hashes": [
@ -319,37 +312,37 @@
"develop": { "develop": {
"aiohttp": { "aiohttp": {
"hashes": [ "hashes": [
"sha256:0419705a36b43c0ac6f15469f9c2a08cad5c939d78bd12a5c23ea167c8253b2b", "sha256:00d198585474299c9c3b4f1d5de1a576cc230d562abc5e4a0e81d71a20a6ca55",
"sha256:1812fc4bc6ac1bde007daa05d2d0f61199324e0cc893b11523e646595047ca08", "sha256:0155af66de8c21b8dba4992aaeeabf55503caefae00067a3b1139f86d0ec50ed",
"sha256:2214b5c0153f45256d5d52d1e0cafe53f9905ed035a142191727a5fb620c03dd", "sha256:09654a9eca62d1bd6d64aa44db2498f60a5c1e0ac4750953fdd79d5c88955e10",
"sha256:275909137f0c92c61ba6bb1af856a522d5546f1de8ea01e4e726321c697754ac", "sha256:199f1d106e2b44b6dacdf6f9245493c7d716b01d0b7fbe1959318ba4dc64d1f5",
"sha256:3983611922b561868428ea1e7269e757803713f55b53502423decc509fef1650", "sha256:296f30dedc9f4b9e7a301e5cc963012264112d78a1d3094cd83ef148fdf33ca1",
"sha256:51afec6ffa50a9da4cdef188971a802beb1ca8e8edb40fa429e5e529db3475fa", "sha256:368ed312550bd663ce84dc4b032a962fcb3c7cae099dbbd48663afc305e3b939",
"sha256:589f2ec8a101a0f340453ee6945bdfea8e1cd84c8d88e5be08716c34c0799d95", "sha256:40d7ea570b88db017c51392349cf99b7aefaaddd19d2c78368aeb0bddde9d390",
"sha256:789820ddc65e1f5e71516adaca2e9022498fa5a837c79ba9c692a9f8f916c330", "sha256:629102a193162e37102c50713e2e31dc9a2fe7ac5e481da83e5bb3c0cee700aa",
"sha256:7a968a0bdaaf9abacc260911775611c9a602214a23aeb846f2eb2eeaa350c4dc", "sha256:6d5ec9b8948c3d957e75ea14d41e9330e1ac3fed24ec53766c780f82805140dc",
"sha256:7aeefbed253f59ea39e70c5848de42ed85cb941165357fc7e87ab5d8f1f9592b", "sha256:87331d1d6810214085a50749160196391a712a13336cd02ce1c3ea3d05bcf8d5",
"sha256:7b2eb55c66512405103485bd7d285a839d53e7fdc261ab20e5bcc51d7aaff5de", "sha256:9a02a04bbe581c8605ac423ba3a74999ec9d8bce7ae37977a3d38680f5780b6d",
"sha256:87bc95d3d333bb689c8d755b4a9d7095a2356108002149523dfc8e607d5d32a4", "sha256:9c4c83f4fa1938377da32bc2d59379025ceeee8e24b89f72fcbccd8ca22dc9bf",
"sha256:9d80e40db208e29168d3723d1440ecbb06054d349c5ece6a2c5a611490830dd7", "sha256:9cddaff94c0135ee627213ac6ca6d05724bfe6e7a356e5e09ec57bd3249510f6",
"sha256:a1b442195c2a77d33e4dbee67c9877ccbdd3a1f686f91eb479a9577ed8cc326b", "sha256:a25237abf327530d9561ef751eef9511ab56fd9431023ca6f4803f1994104d72",
"sha256:ab3d769413b322d6092f169f316f7b21cd261a7589f7e31db779d5731b0480d8", "sha256:a5cbd7157b0e383738b8e29d6e556fde8726823dae0e348952a61742b21aeb12",
"sha256:b066d3dec5d0f5aee6e34e5765095dc3d6d78ef9839640141a2b20816a0642bd", "sha256:a97a516e02b726e089cffcde2eea0d3258450389bbac48cbe89e0f0b6e7b0366",
"sha256:b24e7845ae8de3e388ef4bcfcf7f96b05f52c8e633b33cf8003a6b1d726fc7c2", "sha256:acc89b29b5f4e2332d65cd1b7d10c609a75b88ef8925d487a611ca788432dfa4",
"sha256:c59a953c3f8524a7c86eaeaef5bf702555be12f5668f6384149fe4bb75c52698", "sha256:b05bd85cc99b06740aad3629c2585bda7b83bd86e080b44ba47faf905fdf1300",
"sha256:cf2cc6c2c10d242790412bea7ccf73726a9a44b4c4b073d2699ef3b48971fd95", "sha256:c2bec436a2b5dafe5eaeb297c03711074d46b6eb236d002c13c42f25c4a8ce9d",
"sha256:e0c9c8d4150ae904f308ff27b35446990d2b1dfc944702a21925937e937394c6", "sha256:cc619d974c8c11fe84527e4b5e1c07238799a8c29ea1c1285149170524ba9303",
"sha256:f1839db4c2b08a9c8f9788112644f8a8557e8e0ecc77b07091afabb941dc55d0", "sha256:d4392defd4648badaa42b3e101080ae3313e8f4787cb517efd3f5b8157eaefd6",
"sha256:f3df52362be39908f9c028a65490fae0475e4898b43a03d8aa29d1e765b45e07" "sha256:e1c3c582ee11af7f63a34a46f0448fca58e59889396ffdae1f482085061a2889"
], ],
"version": "==3.4.4" "version": "==3.5.4"
}, },
"aiohttp-json-rpc": { "aiohttp-json-rpc": {
"hashes": [ "hashes": [
"sha256:00d72f40edfc7271578d545a8c47874c0e23cc5d3201ed8128481f6a4af47e32", "sha256:1d040b7b10ff414f9174398ff6e9c647eb0434a00939450b33aa539177c51dcf",
"sha256:02d83b6998f8a0b7e59b46f0cb8a96b475bbf82600b1f9527df47135353f1ca8" "sha256:5f5fb141c6263d2ea52a4173babe9449eef4029620dc49936dca45cdc17ac9dd"
], ],
"version": "==0.11.2" "version": "==0.12"
}, },
"alabaster": { "alabaster": {
"hashes": [ "hashes": [
@ -374,10 +367,10 @@
}, },
"atomicwrites": { "atomicwrites": {
"hashes": [ "hashes": [
"sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0", "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4",
"sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee" "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"
], ],
"version": "==1.2.1" "version": "==1.3.0"
}, },
"attrs": { "attrs": {
"hashes": [ "hashes": [
@ -428,13 +421,6 @@
], ],
"version": "==0.4.1" "version": "==0.4.1"
}, },
"distro": {
"hashes": [
"sha256:224041cef9600e72d19ae41ba006e71c05c4dc802516da715d7fda55ba3d8742",
"sha256:6ec8e539cf412830e5ccf521aecf879f2c7fcf60ce446e33cd16eef1ed8a0158"
],
"version": "==1.3.0"
},
"docutils": { "docutils": {
"hashes": [ "hashes": [
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
@ -519,11 +505,10 @@
}, },
"more-itertools": { "more-itertools": {
"hashes": [ "hashes": [
"sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4", "sha256:0125e8f60e9e031347105eb1682cef932f5e97d7b9a1a28d9bf00c22a5daef40",
"sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc", "sha256:590044e3942351a1bdb1de960b739ff4ce277960f2425ad4509446dbace8d9d1"
"sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"
], ],
"version": "==5.0.0" "version": "==6.0.0"
}, },
"multidict": { "multidict": {
"hashes": [ "hashes": [
@ -561,10 +546,10 @@
}, },
"packaging": { "packaging": {
"hashes": [ "hashes": [
"sha256:0886227f54515e592aaa2e5a553332c73962917f2831f1b0f9b9f4380a4b9807", "sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af",
"sha256:f95a1e147590f204328170981833854229bb2912ac3d5f89e2a8ccd2834800c9" "sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3"
], ],
"version": "==18.0" "version": "==19.0"
}, },
"pluggy": { "pluggy": {
"hashes": [ "hashes": [
@ -589,17 +574,17 @@
}, },
"pyparsing": { "pyparsing": {
"hashes": [ "hashes": [
"sha256:40856e74d4987de5d01761a22d1621ae1c7f8774585acae358aa5c5936c6c90b", "sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a",
"sha256:f353aab21fd474459d97b709e527b5571314ee5f067441dc9f88e33eecd96592" "sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3"
], ],
"version": "==2.3.0" "version": "==2.3.1"
}, },
"pytest": { "pytest": {
"hashes": [ "hashes": [
"sha256:3e65a22eb0d4f1bdbc1eacccf4a3198bf8d4049dea5112d70a0c61b00e748d02", "sha256:65aeaa77ae87c7fc95de56285282546cfa9c886dc8e5dc78313db1c25e21bc07",
"sha256:5924060b374f62608a078494b909d341720a050b5224ff87e17e12377486a71d" "sha256:6ac6d467d9f053e95aaacd79f831dbecfe730f419c6c7022cb316b365cd9199d"
], ],
"version": "==4.1.0" "version": "==4.2.0"
}, },
"pytest-asyncio": { "pytest-asyncio": {
"hashes": [ "hashes": [
@ -679,10 +664,10 @@
}, },
"red-lavalink": { "red-lavalink": {
"hashes": [ "hashes": [
"sha256:6348cc168572b1984e9831a29b4023f02372bb683fec8e863df5abeb605b630a", "sha256:10a07b2b5736f52a0f5c3eeab3fbc3bf6a242ca6ee284a29ad79d6d1673ddfc3",
"sha256:a5ab9d66d1a4728abe48ccb38a2a130a8a2d70fb23c9d9df2b747c82fbeb67a6" "sha256:9df0ddaa92d0d7294a4e236c4069765a0b8e5f258c18075dedf28f4b64a1aab5"
], ],
"version": "==0.2.0" "version": "==0.2.1"
}, },
"requests": { "requests": {
"hashes": [ "hashes": [
@ -714,17 +699,17 @@
}, },
"sphinx": { "sphinx": {
"hashes": [ "hashes": [
"sha256:429e3172466df289f0f742471d7e30ba3ee11f3b5aecd9a840480d03f14bcfe5", "sha256:b53904fa7cb4b06a39409a492b949193a1b68cc7241a1a8ce9974f86f0d24287",
"sha256:c4cb17ba44acffae3d3209646b6baec1e215cad3065e852c68cc569d4df1b9f8" "sha256:c1c00fc4f6e8b101a0d037065043460dffc2d507257f2f11acaed71fd2b0c83c"
], ],
"version": "==1.8.3" "version": "==1.8.4"
}, },
"sphinx-rtd-theme": { "sphinx-rtd-theme": {
"hashes": [ "hashes": [
"sha256:02f02a676d6baabb758a20c7a479d58648e0f64f13e07d1b388e9bb2afe86a09", "sha256:00cf895504a7895ee433807c62094cf1e95f065843bf3acd17037c3e9a2becd4",
"sha256:d0f6bc70f98961145c5b0e26a992829363a197321ba571b31b24ea91879e0c96" "sha256:728607e34d60456d736cc7991fd236afb828b21b82f956c5ea75f94c8414040a"
], ],
"version": "==0.4.2" "version": "==0.4.3"
}, },
"sphinxcontrib-asyncio": { "sphinxcontrib-asyncio": {
"hashes": [ "hashes": [
@ -763,36 +748,36 @@
}, },
"virtualenv": { "virtualenv": {
"hashes": [ "hashes": [
"sha256:58c359370401e0af817fb0070911e599c5fdc836166306b04fd0f278151ed125", "sha256:8b9abfc51c38b70f61634bf265e5beacf6fae11fc25d355d1871f49b8e45f0db",
"sha256:729f0bcab430e4ef137646805b5b1d8efbb43fe53d4a0f33328624a84a5121f7" "sha256:cceab52aa7d4df1e1871a70236eb2b89fcfe29b6b43510d9738689787c513261"
], ],
"version": "==16.3.0" "version": "==16.4.0"
}, },
"websockets": { "websockets": {
"hashes": [ "hashes": [
"sha256:0e2f7d6567838369af074f0ef4d0b802d19fa1fee135d864acc656ceefa33136", "sha256:04b42a1b57096ffa5627d6a78ea1ff7fad3bc2c0331ffc17bc32a4024da7fea0",
"sha256:2a16dac282b2fdae75178d0ed3d5b9bc3258dabfae50196cbb30578d84b6f6a6", "sha256:08e3c3e0535befa4f0c4443824496c03ecc25062debbcf895874f8a0b4c97c9f",
"sha256:5a1fa6072405648cb5b3688e9ed3b94be683ce4a4e5723e6f5d34859dee495c1", "sha256:10d89d4326045bf5e15e83e9867c85d686b612822e4d8f149cf4840aab5f46e0",
"sha256:5c1f55a1274df9d6a37553fef8cff2958515438c58920897675c9bc70f5a0538", "sha256:232fac8a1978fc1dead4b1c2fa27c7756750fb393eb4ac52f6bc87ba7242b2fa",
"sha256:669d1e46f165e0ad152ed8197f7edead22854a6c90419f544e0f234cc9dac6c4", "sha256:4bf4c8097440eff22bc78ec76fe2a865a6e658b6977a504679aaf08f02c121da",
"sha256:695e34c4dbea18d09ab2c258994a8bf6a09564e762655408241f6a14592d2908", "sha256:51642ea3a00772d1e48fb0c492f0d3ae3b6474f34d20eca005a83f8c9c06c561",
"sha256:6b2e03d69afa8d20253455e67b64de1a82ff8612db105113cccec35d3f8429f0", "sha256:55d86102282a636e195dad68aaaf85b81d0bef449d7e2ef2ff79ac450bb25d53",
"sha256:79ca7cdda7ad4e3663ea3c43bfa8637fc5d5604c7737f19a8964781abbd1148d", "sha256:564d2675682bd497b59907d2205031acbf7d3fadf8c763b689b9ede20300b215",
"sha256:7fd2dd9a856f72e6ed06f82facfce01d119b88457cd4b47b7ae501e8e11eba9c", "sha256:5d13bf5197a92149dc0badcc2b699267ff65a867029f465accfca8abab95f412",
"sha256:82c0354ac39379d836719a77ee360ef865377aa6fdead87909d50248d0f05f4d", "sha256:5eda665f6789edb9b57b57a159b9c55482cbe5b046d7db458948370554b16439",
"sha256:8f3b956d11c5b301206382726210dc1d3bee1a9ccf7aadf895aaf31f71c3716c", "sha256:5edb2524d4032be4564c65dc4f9d01e79fe8fad5f966e5b552f4e5164fef0885",
"sha256:91ec98640220ae05b34b79ee88abf27f97ef7c61cf525eec57ea8fcea9f7dddb", "sha256:79691794288bc51e2a3b8de2bc0272ca8355d0b8503077ea57c0716e840ebaef",
"sha256:952be9540d83dba815569d5cb5f31708801e0bbfc3a8c5aef1890b57ed7e58bf", "sha256:7fcc8681e9981b9b511cdee7c580d5b005f3bb86b65bde2188e04a29f1d63317",
"sha256:99ac266af38ba1b1fe13975aea01ac0e14bb5f3a3200d2c69f05385768b8568e", "sha256:8e447e05ec88b1b408a4c9cde85aa6f4b04f06aa874b9f0b8e8319faf51b1fee",
"sha256:9fa122e7adb24232247f8a89f2d9070bf64b7869daf93ac5e19546b409e47e96", "sha256:90ea6b3e7787620bb295a4ae050d2811c807d65b1486749414f78cfd6fb61489",
"sha256:a0873eadc4b8ca93e2e848d490809e0123eea154aa44ecd0109c4d0171869584", "sha256:9e13239952694b8b831088431d15f771beace10edfcf9ef230cefea14f18508f",
"sha256:cb998bd4d93af46b8b49ecf5a72c0a98e5cc6d57fdca6527ba78ad89d6606484", "sha256:d40f081187f7b54d7a99d8a5c782eaa4edc335a057aa54c85059272ed826dc09",
"sha256:e02e57346f6a68523e3c43bbdf35dde5c440318d1f827208ae455f6a2ace446d", "sha256:e1df1a58ed2468c7b7ce9a2f9752a32ad08eac2bcd56318625c3647c2cd2da6f",
"sha256:e79a5a896bcee7fff24a788d72e5c69f13e61369d055f28113e71945a7eb1559", "sha256:e98d0cec437097f09c7834a11c69d79fe6241729b23f656cfc227e93294fc242",
"sha256:ee55eb6bcf23ecc975e6b47c127c201b913598f38b6a300075f84eeef2d3baff", "sha256:f8d59627702d2ff27cb495ca1abdea8bd8d581de425c56e93bff6517134e0a9b",
"sha256:f1414e6cbcea8d22843e7eafdfdfae3dd1aba41d1945f6ca66e4806c07c4f454" "sha256:fc30cdf2e949a2225b012a7911d1d031df3d23e99b7eda7dfc982dc4a860dae9"
], ],
"version": "==6.0" "version": "==7.0"
}, },
"yarl": { "yarl": {
"hashes": [ "hashes": [

View File

@ -6,7 +6,7 @@ Discord API Wrapper
A basic wrapper for the Discord API. A basic wrapper for the Discord API.
:copyright: (c) 2015-2017 Rapptz :copyright: (c) 2015-2019 Rapptz
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
@ -14,7 +14,7 @@ A basic wrapper for the Discord API.
__title__ = "discord" __title__ = "discord"
__author__ = "Rapptz" __author__ = "Rapptz"
__license__ = "MIT" __license__ = "MIT"
__copyright__ = "Copyright 2015-2017 Rapptz" __copyright__ = "Copyright 2015-2019 Rapptz"
__version__ = "1.0.0a" __version__ = "1.0.0a"
from collections import namedtuple from collections import namedtuple

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -667,6 +667,28 @@ class CategoryChannel(discord.abc.GuildChannel, Hashable):
ret.sort(key=comparator) ret.sort(key=comparator)
return ret return ret
@property
def text_channels(self):
"""List[:class:`TextChannel`]: Returns the text channels that are under this category."""
ret = [
c
for c in self.guild.channels
if c.category_id == self.id and isinstance(c, TextChannel)
]
ret.sort(key=lambda c: (c.position, c.id))
return ret
@property
def voice_channels(self):
"""List[:class:`VoiceChannel`]: Returns the text channels that are under this category."""
ret = [
c
for c in self.guild.channels
if c.category_id == self.id and isinstance(c, VoiceChannel)
]
ret.sort(key=lambda c: (c.position, c.id))
return ret
class DMChannel(discord.abc.Messageable, Hashable): class DMChannel(discord.abc.Messageable, Hashable):
"""Represents a Discord direct message channel. """Represents a Discord direct message channel.

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -76,6 +76,13 @@ class PartialEmoji(namedtuple("PartialEmoji", "animated name id")):
return "<a:%s:%s>" % (self.name, self.id) return "<a:%s:%s>" % (self.name, self.id)
return "<:%s:%s>" % (self.name, self.id) return "<:%s:%s>" % (self.name, self.id)
def __eq__(self, other):
if self.is_unicode_emoji():
return isinstance(other, PartialEmoji) and self.name == other.name
if isinstance(other, (PartialEmoji, Emoji)):
return self.id == other.id
def is_custom_emoji(self): def is_custom_emoji(self):
"""Checks if this is a custom non-Unicode emoji.""" """Checks if this is a custom non-Unicode emoji."""
return self.id is not None return self.id is not None
@ -186,6 +193,9 @@ class Emoji(Hashable):
def __repr__(self): def __repr__(self):
return "<Emoji id={0.id} name={0.name!r}>".format(self) return "<Emoji id={0.id} name={0.name!r}>".format(self)
def __eq__(self, other):
return isinstance(other, (PartialEmoji, Emoji)) and self.id == other.id
@property @property
def created_at(self): def created_at(self):
"""Returns the emoji's creation time in UTC.""" """Returns the emoji's creation time in UTC."""

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -30,6 +30,7 @@ __all__ = [
"ChannelType", "ChannelType",
"MessageType", "MessageType",
"VoiceRegion", "VoiceRegion",
"SpeakingState",
"VerificationLevel", "VerificationLevel",
"ContentFilter", "ContentFilter",
"Status", "Status",
@ -91,6 +92,16 @@ class VoiceRegion(Enum):
return self.value return self.value
class SpeakingState(IntEnum):
none = 0
voice = 1
soundshare = 2
priority = 4
def __str__(self):
return self.name
class VerificationLevel(IntEnum): class VerificationLevel(IntEnum):
none = 0 none = 0
low = 1 low = 1

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -6,7 +6,7 @@ discord.ext.commands
An extension module to facilitate creation of bot commands. An extension module to facilitate creation of bot commands.
:copyright: (c) 2017 Rapptz :copyright: (c) 2019 Rapptz
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -443,9 +443,9 @@ class BotBase(GroupMixin):
Parameters Parameters
----------- -----------
func : :ref:`coroutine <coroutine>` func : :ref:`coroutine <coroutine>`
The extra event to listen to. The function to call.
name : Optional[str] name : Optional[str]
The name of the command to use. Defaults to ``func.__name__``. The name of the event to listen for. Defaults to ``func.__name__``.
Example Example
-------- --------

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -523,7 +523,7 @@ class clean_content(Converter):
result = pattern.sub(repl, argument) result = pattern.sub(repl, argument)
if self.escape_markdown: if self.escape_markdown:
transformations = {re.escape(c): "\\" + c for c in ("*", "`", "_", "~", "\\")} transformations = {re.escape(c): "\\" + c for c in ("*", "`", "_", "~", "\\", "||")}
def replace(obj): def replace(obj):
return transformations.get(re.escape(obj.group(0)), "") return transformations.get(re.escape(obj.group(0)), "")

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -385,22 +385,18 @@ class Command:
# for use with a manual undo # for use with a manual undo
previous = view.index previous = view.index
# parsing errors get propagated
view.skip_ws() view.skip_ws()
argument = quoted_word(view) argument = quoted_word(view)
try: try:
value = await self.do_conversion(ctx, converter, argument, param) value = await self.do_conversion(ctx, converter, argument, param)
except CommandError: except CommandError:
if not result:
if required:
raise
else:
view.index = previous
return param.default
view.index = previous view.index = previous
break break
else: else:
result.append(value) result.append(value)
if not result and not required:
return param.default
return result return result
async def _transform_greedy_var_pos(self, ctx, param, converter): async def _transform_greedy_var_pos(self, ctx, param, converter):
@ -750,9 +746,9 @@ class Command:
If that lookup leads to an empty string then the first line of the If that lookup leads to an empty string then the first line of the
:attr:`help` attribute is used instead. :attr:`help` attribute is used instead.
""" """
if self.brief: if self.brief is not None:
return self.brief return self.brief
if self.help: if self.help is not None:
return self.help.split("\n", 1)[0] return self.help.split("\n", 1)[0]
return "" return ""
@ -771,7 +767,7 @@ class Command:
name = self.name if not parent else parent + " " + self.name name = self.name if not parent else parent + " " + self.name
result.append(name) result.append(name)
if self.usage: if self.usage is not None:
result.append(self.usage) result.append(self.usage)
return " ".join(result) return " ".join(result)

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,7 @@ DEALINGS IN THE SOFTWARE.
import itertools import itertools
import inspect import inspect
import discord.utils
from .core import GroupMixin, Command from .core import GroupMixin, Command
from .errors import CommandError from .errors import CommandError
@ -183,7 +184,9 @@ class HelpFormatter:
if commands: if commands:
return max( return max(
map( map(
lambda c: len(c.name) if self.show_hidden or not c.hidden else 0, lambda c: discord.utils._string_width(c.name)
if self.show_hidden or not c.hidden
else 0,
commands.values(), commands.values(),
) )
) )
@ -272,8 +275,10 @@ class HelpFormatter:
if name in command.aliases: if name in command.aliases:
# skip aliases # skip aliases
continue continue
width_gap = discord.utils._string_width(name) - len(name)
entry = " {0:<{width}} {1}".format(name, command.short_doc, width=max_width) entry = " {0:<{width}} {1}".format(
name, command.short_doc, width=max_width - width_gap
)
shortened = self.shorten(entry) shortened = self.shorten(entry)
self._paginator.add_line(shortened) self._paginator.add_line(shortened)

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,7 @@ DEALINGS IN THE SOFTWARE.
import asyncio import asyncio
from collections import namedtuple from collections import namedtuple
import concurrent.futures
import json import json
import logging import logging
import struct import struct
@ -38,6 +39,7 @@ import websockets
from . import utils from . import utils
from .activity import _ActivityTag from .activity import _ActivityTag
from .enums import SpeakingState
from .errors import ConnectionClosed, InvalidArgument from .errors import ConnectionClosed, InvalidArgument
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -72,6 +74,8 @@ class KeepAliveHandler(threading.Thread):
self.daemon = True self.daemon = True
self.shard_id = shard_id self.shard_id = shard_id
self.msg = "Keeping websocket alive with sequence %s." self.msg = "Keeping websocket alive with sequence %s."
self.block_msg = "Heartbeat blocked for more than %s seconds."
self.behind_msg = "Can't keep up, websocket is %.1fs behind."
self._stop_ev = threading.Event() self._stop_ev = threading.Event()
self._last_ack = time.perf_counter() self._last_ack = time.perf_counter()
self._last_send = time.perf_counter() self._last_send = time.perf_counter()
@ -102,7 +106,15 @@ class KeepAliveHandler(threading.Thread):
f = asyncio.run_coroutine_threadsafe(coro, loop=self.ws.loop) f = asyncio.run_coroutine_threadsafe(coro, loop=self.ws.loop)
try: try:
# block until sending is complete # block until sending is complete
f.result() total = 0
while True:
try:
f.result(5)
break
except concurrent.futures.TimeoutError:
total += 5
log.warning(self.block_msg, total)
except Exception: except Exception:
self.stop() self.stop()
else: else:
@ -118,12 +130,16 @@ class KeepAliveHandler(threading.Thread):
ack_time = time.perf_counter() ack_time = time.perf_counter()
self._last_ack = ack_time self._last_ack = ack_time
self.latency = ack_time - self._last_send self.latency = ack_time - self._last_send
if self.latency > 10:
log.warning(self.behind_msg, self.latency)
class VoiceKeepAliveHandler(KeepAliveHandler): class VoiceKeepAliveHandler(KeepAliveHandler):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.msg = "Keeping voice websocket alive with timestamp %s." self.msg = "Keeping voice websocket alive with timestamp %s."
self.block_msg = "Voice heartbeat blocked for more than %s seconds"
self.behind_msg = "Can't keep up, voice websocket is %.1fs behind"
def get_payload(self): def get_payload(self):
return {"op": self.ws.HEARTBEAT, "d": int(time.time() * 1000)} return {"op": self.ws.HEARTBEAT, "d": int(time.time() * 1000)}
@ -482,7 +498,7 @@ class DiscordWebSocket(websockets.client.WebSocketClientProtocol):
async def send_as_json(self, data): async def send_as_json(self, data):
try: try:
await super().send(utils.to_json(data)) await self.send(utils.to_json(data))
except websockets.exceptions.ConnectionClosed as exc: except websockets.exceptions.ConnectionClosed as exc:
if not self._can_handle_close(exc.code): if not self._can_handle_close(exc.code):
raise ConnectionClosed(exc, shard_id=self.shard_id) from exc raise ConnectionClosed(exc, shard_id=self.shard_id) from exc
@ -561,6 +577,10 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
Receive only. Tells you that your websocket connection was acknowledged. Receive only. Tells you that your websocket connection was acknowledged.
INVALIDATE_SESSION INVALIDATE_SESSION
Sent only. Tells you that your RESUME request has failed and to re-IDENTIFY. Sent only. Tells you that your RESUME request has failed and to re-IDENTIFY.
CLIENT_CONNECT
Indicates a user has connected to voice.
CLIENT_DISCONNECT
Receive only. Indicates a user has disconnected from voice.
""" """
IDENTIFY = 0 IDENTIFY = 0
@ -573,6 +593,8 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
RESUME = 7 RESUME = 7
HELLO = 8 HELLO = 8
INVALIDATE_SESSION = 9 INVALIDATE_SESSION = 9
CLIENT_CONNECT = 12
CLIENT_DISCONNECT = 13
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -611,7 +633,7 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
@classmethod @classmethod
async def from_client(cls, client, *, resume=False): async def from_client(cls, client, *, resume=False):
"""Creates a voice websocket for the :class:`VoiceClient`.""" """Creates a voice websocket for the :class:`VoiceClient`."""
gateway = "wss://" + client.endpoint + "/?v=3" gateway = "wss://" + client.endpoint + "/?v=4"
ws = await websockets.connect(gateway, loop=client.loop, klass=cls, compression=None) ws = await websockets.connect(gateway, loop=client.loop, klass=cls, compression=None)
ws.gateway = gateway ws.gateway = gateway
ws._connection = client ws._connection = client
@ -624,19 +646,21 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
return ws return ws
async def select_protocol(self, ip, port): async def select_protocol(self, ip, port, mode):
payload = { payload = {
"op": self.SELECT_PROTOCOL, "op": self.SELECT_PROTOCOL,
"d": { "d": {"protocol": "udp", "data": {"address": ip, "port": port, "mode": mode}},
"protocol": "udp",
"data": {"address": ip, "port": port, "mode": "xsalsa20_poly1305"},
},
} }
await self.send_as_json(payload) await self.send_as_json(payload)
async def speak(self, is_speaking=True): async def client_connect(self):
payload = {"op": self.SPEAKING, "d": {"speaking": is_speaking, "delay": 0}} payload = {"op": self.CLIENT_CONNECT, "d": {"audio_ssrc": self._connection.ssrc}}
await self.send_as_json(payload)
async def speak(self, state=SpeakingState.voice):
payload = {"op": self.SPEAKING, "d": {"speaking": int(state), "delay": 0}}
await self.send_as_json(payload) await self.send_as_json(payload)
@ -646,9 +670,6 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
data = msg.get("d") data = msg.get("d")
if op == self.READY: if op == self.READY:
interval = data["heartbeat_interval"] / 1000.0
self._keep_alive = VoiceKeepAliveHandler(ws=self, interval=interval)
self._keep_alive.start()
await self.initial_connection(data) await self.initial_connection(data)
elif op == self.HEARTBEAT_ACK: elif op == self.HEARTBEAT_ACK:
self._keep_alive.ack() self._keep_alive.ack()
@ -656,7 +677,12 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
log.info("Voice RESUME failed.") log.info("Voice RESUME failed.")
await self.identify() await self.identify()
elif op == self.SESSION_DESCRIPTION: elif op == self.SESSION_DESCRIPTION:
self._connection.mode = data["mode"]
await self.load_secret_key(data) await self.load_secret_key(data)
elif op == self.HELLO:
interval = data["heartbeat_interval"] / 1000.0
self._keep_alive = VoiceKeepAliveHandler(ws=self, interval=interval)
self._keep_alive.start()
async def initial_connection(self, data): async def initial_connection(self, data):
state = self._connection state = self._connection
@ -677,15 +703,23 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
# the port is a little endian unsigned short in the last two bytes # the port is a little endian unsigned short in the last two bytes
# yes, this is different endianness from everything else # yes, this is different endianness from everything else
state.port = struct.unpack_from("<H", recv, len(recv) - 2)[0] state.port = struct.unpack_from("<H", recv, len(recv) - 2)[0]
log.debug("detected ip: %s port: %s", state.ip, state.port) log.debug("detected ip: %s port: %s", state.ip, state.port)
await self.select_protocol(state.ip, state.port)
log.info("selected the voice protocol for use") # there *should* always be at least one supported mode (xsalsa20_poly1305)
modes = [mode for mode in data["modes"] if mode in self._connection.supported_modes]
log.debug("received supported encryption modes: %s", ", ".join(modes))
mode = modes[0]
await self.select_protocol(state.ip, state.port, mode)
log.info("selected the voice protocol for use (%s)", mode)
await self.client_connect()
async def load_secret_key(self, data): async def load_secret_key(self, data):
log.info("received secret key for voice connection") log.info("received secret key for voice connection")
self._connection.secret_key = data.get("secret_key") self._connection.secret_key = data.get("secret_key")
await self.speak() await self.speak()
await self.speak(False)
async def poll_event(self): async def poll_event(self):
try: try:

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -592,7 +592,7 @@ class Guild(Hashable):
return utils.find(pred, members) return utils.find(pred, members)
def _create_channel(self, name, overwrites, channel_type, category=None, reason=None): def _create_channel(self, name, overwrites, channel_type, category=None, **options):
if overwrites is None: if overwrites is None:
overwrites = {} overwrites = {}
elif not isinstance(overwrites, dict): elif not isinstance(overwrites, dict):
@ -615,17 +615,24 @@ class Guild(Hashable):
perms.append(payload) perms.append(payload)
try:
options["rate_limit_per_user"] = options.pop("slowmode_delay")
except KeyError:
pass
parent_id = category.id if category else None parent_id = category.id if category else None
return self._state.http.create_channel( return self._state.http.create_channel(
self.id, self.id,
name,
channel_type.value, channel_type.value,
name=name,
parent_id=parent_id, parent_id=parent_id,
permission_overwrites=perms, permission_overwrites=perms,
reason=reason, **options
) )
async def create_text_channel(self, name, *, overwrites=None, category=None, reason=None): async def create_text_channel(
self, name, *, overwrites=None, category=None, reason=None, **options
):
"""|coro| """|coro|
Creates a :class:`TextChannel` for the guild. Creates a :class:`TextChannel` for the guild.
@ -637,6 +644,12 @@ class Guild(Hashable):
channel upon creation. This parameter expects a :class:`dict` of channel upon creation. This parameter expects a :class:`dict` of
overwrites with the target (either a :class:`Member` or a :class:`Role`) overwrites with the target (either a :class:`Member` or a :class:`Role`)
as the key and a :class:`PermissionOverwrite` as the value. as the key and a :class:`PermissionOverwrite` as the value.
Note
--------
Creating a channel of a specified position will not update the position of
other channels to follow suit. A follow-up call to :meth:`~TextChannel.edit`
will be required to update the position of the channel in the channel list.
Examples Examples
---------- ----------
@ -660,7 +673,7 @@ class Guild(Hashable):
Parameters Parameters
----------- -----------
name: str name: :class:`str`
The channel's name. The channel's name.
overwrites overwrites
A :class:`dict` of target (either a role or a member) to A :class:`dict` of target (either a role or a member) to
@ -670,7 +683,17 @@ class Guild(Hashable):
The category to place the newly created channel under. The category to place the newly created channel under.
The permissions will be automatically synced to category if no The permissions will be automatically synced to category if no
overwrites are provided. overwrites are provided.
reason: Optional[str] position: :class:`int`
The position in the channel list. This is a number that starts
at 0. e.g. the top channel is position 0.
topic: Optional[:class:`str`]
The new channel's topic.
slowmode_delay: :class:`int`
Specifies the slowmode rate limit for user in this channel.
The maximum value possible is `120`.
nsfw: :class:`bool`
To mark the channel as NSFW or not.
reason: Optional[:class:`str`]
The reason for creating this channel. Shows up on the audit log. The reason for creating this channel. Shows up on the audit log.
Raises Raises
@ -688,7 +711,7 @@ class Guild(Hashable):
The channel that was just created. The channel that was just created.
""" """
data = await self._create_channel( data = await self._create_channel(
name, overwrites, ChannelType.text, category, reason=reason name, overwrites, ChannelType.text, category, reason=reason, **options
) )
channel = TextChannel(state=self._state, guild=self, data=data) channel = TextChannel(state=self._state, guild=self, data=data)
@ -696,13 +719,23 @@ class Guild(Hashable):
self._channels[channel.id] = channel self._channels[channel.id] = channel
return channel return channel
async def create_voice_channel(self, name, *, overwrites=None, category=None, reason=None): async def create_voice_channel(
self, name, *, overwrites=None, category=None, reason=None, **options
):
"""|coro| """|coro|
Same as :meth:`create_text_channel` except makes a :class:`VoiceChannel` instead. This is similar to :meth:`create_text_channel` except makes a :class:`VoiceChannel` instead, in addition
to having the following new parameters.
Parameters
-----------
bitrate: :class:`int`
The channel's preferred audio bitrate in bits per second.
user_limit: :class:`int`
The channel's limit for number of members that can be in a voice channel.
""" """
data = await self._create_channel( data = await self._create_channel(
name, overwrites, ChannelType.voice, category, reason=reason name, overwrites, ChannelType.voice, category, reason=reason, **options
) )
channel = VoiceChannel(state=self._state, guild=self, data=data) channel = VoiceChannel(state=self._state, guild=self, data=data)

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -152,7 +152,7 @@ class HTTPClient:
# wait until the global lock is complete # wait until the global lock is complete
await self._global_over.wait() await self._global_over.wait()
await lock await lock.acquire()
with MaybeUnlock(lock) as maybe_lock: with MaybeUnlock(lock) as maybe_lock:
for tries in range(5): for tries in range(5):
async with self._session.request(method, url, **kwargs) as r: async with self._session.request(method, url, **kwargs) as r:
@ -596,23 +596,21 @@ class HTTPClient:
r = Route("PATCH", "/guilds/{guild_id}/channels", guild_id=guild_id) r = Route("PATCH", "/guilds/{guild_id}/channels", guild_id=guild_id)
return self.request(r, json=data, reason=reason) return self.request(r, json=data, reason=reason)
def create_channel( def create_channel(self, guild_id, channel_type, *, reason=None, **options):
self, payload = {"type": channel_type}
guild_id,
name,
channel_type,
parent_id=None,
permission_overwrites=None,
*,
reason=None
):
payload = {"name": name, "type": channel_type}
if permission_overwrites is not None: valid_keys = (
payload["permission_overwrites"] = permission_overwrites "name",
"parent_id",
if parent_id is not None: "topic",
payload["parent_id"] = parent_id "bitrate",
"nsfw",
"user_limit",
"position",
"permission_overwrites",
"rate_limit_per_user",
)
payload.update({k: v for k, v in options.items() if k in valid_keys and v is not None})
return self.request( return self.request(
Route("POST", "/guilds/{guild_id}/channels", guild_id=guild_id), Route("POST", "/guilds/{guild_id}/channels", guild_id=guild_id),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -160,7 +160,7 @@ class ReactionIterator(_AsyncIterator):
if data: if data:
self.limit -= retrieve self.limit -= retrieve
self.after = Object(id=int(data[0]["id"])) self.after = Object(id=int(data[-1]["id"]))
if self.guild is None: if self.guild is None:
for element in reversed(data): for element in reversed(data):

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -157,7 +157,7 @@ class Permissions:
- kick_members - kick_members
- ban_members - ban_members
- administrator - administrator
- change_nicknames - change_nickname
- manage_nicknames - manage_nicknames
""" """
return cls(0b00110011111101111111110001010001) return cls(0b00110011111101111111110001010001)
@ -543,6 +543,10 @@ class PermissionOverwrite:
+-----------+------------------------------------------+ +-----------+------------------------------------------+
| Operation | Description | | Operation | Description |
+===========+==========================================+ +===========+==========================================+
| x == y | Checks if two overwrites are equal. |
+-----------+------------------------------------------+
| x != y | Checks if two overwrites are not equal. |
+-----------+------------------------------------------+
| iter(x) | Returns an iterator of (perm, value) | | iter(x) | Returns an iterator of (perm, value) |
| | pairs. This allows this class to be used | | | pairs. This allows this class to be used |
| | as an iterable in e.g. set/list/dict | | | as an iterable in e.g. set/list/dict |
@ -566,6 +570,9 @@ class PermissionOverwrite:
setattr(self, key, value) setattr(self, key, value)
def __eq__(self, other):
return self._values == other._values
def _set(self, key, value): def _set(self, key, value):
if value not in (True, None, False): if value not in (True, None, False):
raise TypeError( raise TypeError(

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -27,6 +27,7 @@ DEALINGS IN THE SOFTWARE.
import threading import threading
import subprocess import subprocess
import audioop import audioop
import asyncio
import logging import logging
import shlex import shlex
import time import time
@ -286,6 +287,7 @@ class AudioPlayer(threading.Thread):
# getattr lookup speed ups # getattr lookup speed ups
play_audio = self.client.send_audio_packet play_audio = self.client.send_audio_packet
self._speak(True)
while not self._end.is_set(): while not self._end.is_set():
# are we paused? # are we paused?
@ -334,14 +336,19 @@ class AudioPlayer(threading.Thread):
def stop(self): def stop(self):
self._end.set() self._end.set()
self._resumed.set() self._resumed.set()
self._speak(False)
def pause(self): def pause(self, *, update_speaking=True):
self._resumed.clear() self._resumed.clear()
if update_speaking:
self._speak(False)
def resume(self): def resume(self, *, update_speaking=True):
self.loops = 0 self.loops = 0
self._start = time.time() self._start = time.time()
self._resumed.set() self._resumed.set()
if update_speaking:
self._speak(True)
def is_playing(self): def is_playing(self):
return self._resumed.is_set() and not self._end.is_set() return self._resumed.is_set() and not self._end.is_set()
@ -351,6 +358,12 @@ class AudioPlayer(threading.Thread):
def _set_source(self, source): def _set_source(self, source):
with self._lock: with self._lock:
self.pause() self.pause(update_speaking=False)
self.source = source self.source = source
self.resume() self.resume(update_speaking=False)
def _speak(self, speaking):
try:
asyncio.run_coroutine_threadsafe(self.client.ws.speak(speaking), self.client.loop)
except Exception as e:
log.info("Speaking call in player failed: %s", e)

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2018 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -103,7 +103,7 @@ class RawReactionActionEvent:
message_id: :class:`int` message_id: :class:`int`
The message ID that got or lost a reaction. The message ID that got or lost a reaction.
user_id: :class:`int` user_id: :class:`int`
The user ID who added or removed the reaction. The user ID who added the reaction or whose reaction was removed.
channel_id: :class:`int` channel_id: :class:`int`
The channel ID where the reaction got added or removed. The channel ID where the reaction got added or removed.
guild_id: Optional[:class:`int`] guild_id: Optional[:class:`int`]

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,7 @@ DEALINGS IN THE SOFTWARE.
import array import array
import asyncio import asyncio
import unicodedata
from base64 import b64encode from base64 import b64encode
from bisect import bisect_left from bisect import bisect_left
import datetime import datetime
@ -33,7 +34,7 @@ from email.utils import parsedate_to_datetime
import functools import functools
from inspect import isawaitable as _isawaitable from inspect import isawaitable as _isawaitable
import json import json
from re import split as re_split import re
import warnings import warnings
from .errors import InvalidArgument from .errors import InvalidArgument
@ -83,7 +84,7 @@ def cached_slot_property(name):
def parse_time(timestamp): def parse_time(timestamp):
if timestamp: if timestamp:
return datetime.datetime(*map(int, re_split(r"[^\d]", timestamp.replace("+00:00", "")))) return datetime.datetime(*map(int, re.split(r"[^\d]", timestamp.replace("+00:00", ""))))
return None return None
@ -265,9 +266,7 @@ def _get_mime_type_for_image(data):
return "image/png" return "image/png"
elif data.startswith(b"\xFF\xD8") and data.rstrip(b"\0").endswith(b"\xFF\xD9"): elif data.startswith(b"\xFF\xD8") and data.rstrip(b"\0").endswith(b"\xFF\xD9"):
return "image/jpeg" return "image/jpeg"
elif data.startswith(b"\x47\x49\x46\x38\x37\x61") or data.startswith( elif data.startswith((b"\x47\x49\x46\x38\x37\x61", b"\x47\x49\x46\x38\x39\x61")):
b"\x47\x49\x46\x38\x39\x61"
):
return "image/gif" return "image/gif"
elif data.startswith(b"RIFF") and data[8:12] == b"WEBP": elif data.startswith(b"RIFF") and data[8:12] == b"WEBP":
return "image/webp" return "image/webp"
@ -351,3 +350,20 @@ class SnowflakeList(array.array):
def has(self, element): def has(self, element):
i = bisect_left(self, element) i = bisect_left(self, element)
return i != len(self) and self[i] == element return i != len(self) and self[i] == element
_IS_ASCII = re.compile(r"^[\x00-\x7f]+$")
def _string_width(string, *, _IS_ASCII=_IS_ASCII):
"""Returns string's width."""
match = _IS_ASCII.match(string)
if match:
return match.endpos
UNICODE_WIDE_CHAR_TYPE = "WFA"
width = 0
func = unicodedata.east_asian_width
for char in string:
width += 2 if func(char) in UNICODE_WIDE_CHAR_TYPE else 1
return width

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -105,6 +105,7 @@ class VoiceClient:
self._connected = threading.Event() self._connected = threading.Event()
self._handshake_complete = asyncio.Event(loop=self.loop) self._handshake_complete = asyncio.Event(loop=self.loop)
self.mode = None
self._connections = 0 self._connections = 0
self.sequence = 0 self.sequence = 0
self.timestamp = 0 self.timestamp = 0
@ -113,6 +114,7 @@ class VoiceClient:
self.encoder = opus.Encoder() self.encoder = opus.Encoder()
warn_nacl = not has_nacl warn_nacl = not has_nacl
supported_modes = ("xsalsa20_poly1305_suffix", "xsalsa20_poly1305")
@property @property
def guild(self): def guild(self):
@ -305,22 +307,30 @@ class VoiceClient:
def _get_voice_packet(self, data): def _get_voice_packet(self, data):
header = bytearray(12) header = bytearray(12)
nonce = bytearray(24)
box = nacl.secret.SecretBox(bytes(self.secret_key))
# Formulate header # Formulate rtp header
header[0] = 0x80 header[0] = 0x80
header[1] = 0x78 header[1] = 0x78
struct.pack_into(">H", header, 2, self.sequence) struct.pack_into(">H", header, 2, self.sequence)
struct.pack_into(">I", header, 4, self.timestamp) struct.pack_into(">I", header, 4, self.timestamp)
struct.pack_into(">I", header, 8, self.ssrc) struct.pack_into(">I", header, 8, self.ssrc)
# Copy header to nonce's first 12 bytes encrypt_packet = getattr(self, "_encrypt_" + self.mode)
return encrypt_packet(header, data)
def _encrypt_xsalsa20_poly1305(self, header, data):
box = nacl.secret.SecretBox(bytes(self.secret_key))
nonce = bytearray(24)
nonce[:12] = header nonce[:12] = header
# Encrypt and return the data
return header + box.encrypt(bytes(data), bytes(nonce)).ciphertext return header + box.encrypt(bytes(data), bytes(nonce)).ciphertext
def _encrypt_xsalsa20_poly1305_suffix(self, header, data):
box = nacl.secret.SecretBox(bytes(self.secret_key))
nonce = nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE)
return header + box.encrypt(bytes(data), nonce).ciphertext + nonce
def play(self, source, *, after=None): def play(self, source, *, after=None):
"""Plays an :class:`AudioSource`. """Plays an :class:`AudioSource`.

View File

@ -3,7 +3,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -103,7 +103,7 @@ class WebhookAdapter:
def store_user(self, data): def store_user(self, data):
# mocks a ConnectionState for appropriate use for Message # mocks a ConnectionState for appropriate use for Message
return BaseUser(state=self, data=data) return BaseUser(state=self.webhook._state, data=data)
def execute_webhook(self, *, payload, wait=False, file=None, files=None): def execute_webhook(self, *, payload, wait=False, file=None, files=None):
if file is not None: if file is not None:
@ -195,7 +195,7 @@ class AsyncWebhookAdapter(WebhookAdapter):
# transform into Message object # transform into Message object
from .message import Message from .message import Message
return Message(data=data, state=self, channel=self.webhook.channel) return Message(data=data, state=self.webhook._state, channel=self.webhook.channel)
class RequestsWebhookAdapter(WebhookAdapter): class RequestsWebhookAdapter(WebhookAdapter):
@ -279,7 +279,7 @@ class RequestsWebhookAdapter(WebhookAdapter):
# transform into Message object # transform into Message object
from .message import Message from .message import Message
return Message(data=response, state=self, channel=self.webhook.channel) return Message(data=response, state=self.webhook._state, channel=self.webhook.channel)
class Webhook: class Webhook:

View File

@ -28,7 +28,7 @@ if [%REF%] == [] (
set REF2=%REF% set REF2=%REF%
) )
pip install --upgrade --no-deps -t . https://github.com/Rapptz/discord.py/archive/!REF2!.tar.gz#egg=discord.py pip install --upgrade --no-deps -t . https://github.com/Rapptz/discord.py/archive/!REF2!.tar.gz#egg=discord.py
del /S /Q "discord.py*.egg-info" del /S /Q "discord.py*-info"
for /F %%i in ('dir /S /B discord.py*.egg-info') do rmdir /S /Q %%i for /F %%i in ('dir /S /B discord.py*.egg-info') do rmdir /S /Q %%i
goto reformat goto reformat

View File

@ -1,5 +1,6 @@
import re as _re import re as _re
import sys as _sys import sys as _sys
import warnings as _warnings
from math import inf as _inf from math import inf as _inf
from typing import ( from typing import (
Any as _Any, Any as _Any,
@ -157,3 +158,6 @@ class VersionInfo:
__version__ = "3.0.0" __version__ = "3.0.0"
version_info = VersionInfo.from_str(__version__) version_info = VersionInfo.from_str(__version__)
# Filter fuzzywuzzy slow sequence matcher warning
_warnings.filterwarnings("ignore", module=r"fuzzywuzzy.*")

View File

@ -183,7 +183,7 @@ def main():
gathered = asyncio.gather(*pending, loop=red.loop, return_exceptions=True) gathered = asyncio.gather(*pending, loop=red.loop, return_exceptions=True)
gathered.cancel() gathered.cancel()
try: try:
red.rpc.server.close() loop.run_until_complete(red.rpc.close())
except AttributeError: except AttributeError:
pass pass

View File

@ -1,4 +1,5 @@
import asyncio import asyncio
from typing import Optional
from aiohttp import web from aiohttp import web
from aiohttp_json_rpc import JsonRpc from aiohttp_json_rpc import JsonRpc
@ -63,25 +64,26 @@ class RPC:
def __init__(self): def __init__(self):
self.app = web.Application() self.app = web.Application()
self._rpc = RedRpc() self._rpc = RedRpc()
self.app.router.add_route("*", "/", self._rpc) self.app.router.add_route("*", "/", self._rpc.handle_request)
self.app_handler = self.app.make_handler() self._runner = web.AppRunner(self.app)
self._site: Optional[web.TCPSite] = None
self.server = None
async def initialize(self): async def initialize(self):
""" """
Finalizes the initialization of the RPC server and allows it to begin Finalizes the initialization of the RPC server and allows it to begin
accepting queries. accepting queries.
""" """
self.server = await self.app.loop.create_server(self.app_handler, "127.0.0.1", 6133) await self._runner.setup()
self._site = web.TCPSite(self._runner, host="127.0.0.1", port=6133)
await self._site.start()
log.debug("Created RPC server listener.") log.debug("Created RPC server listener.")
def close(self): async def close(self):
""" """
Closes the RPC server. Closes the RPC server.
""" """
self.server.close() await self._runner.cleanup()
def add_method(self, method, prefix: str = None): def add_method(self, method, prefix: str = None):
if prefix is None: if prefix is None:
@ -117,7 +119,8 @@ class RPCMixin:
""" """
Registers a method to act as an RPC handler if the internal RPC server is active. Registers a method to act as an RPC handler if the internal RPC server is active.
When calling this method through the RPC server, use the naming scheme "cogname__methodname". When calling this method through the RPC server, use the naming scheme
"cogname__methodname".
.. important:: .. important::

View File

@ -26,25 +26,23 @@ classifiers =
packages = find_namespace: packages = find_namespace:
python_requires = >=3.7 python_requires = >=3.7
install_requires = install_requires =
aiohttp-json-rpc==0.11.2 aiohttp-json-rpc==0.12
aiohttp==3.4.4 aiohttp==3.5.4
appdirs==1.4.3 appdirs==1.4.3
async-timeout==3.0.1 async-timeout==3.0.1
attrs==18.2.0 attrs==18.2.0
chardet==3.0.4 chardet==3.0.4
colorama==0.4.1 colorama==0.4.1
distro==1.3.0; sys_platform == "linux" distro==1.4.0; sys_platform == "linux"
fuzzywuzzy==0.17.0 fuzzywuzzy==0.17.0
idna-ssl==1.1.0 idna-ssl==1.1.0
idna==2.8 idna==2.8
multidict==4.5.2 multidict==4.5.2
python-levenshtein-wheels==0.13.1 python-levenshtein-wheels==0.13.1
pyyaml==3.13 pyyaml==3.13
raven==6.10.0 red-lavalink==0.2.1
raven-aiohttp==0.7.0
red-lavalink==0.2.0
schema==0.6.8 schema==0.6.8
websockets==6.0 websockets==7.0
yarl==1.3.0 yarl==1.3.0
[options.extras_require] [options.extras_require]
@ -56,15 +54,15 @@ docs =
imagesize==1.1.0 imagesize==1.1.0
Jinja2==2.10 Jinja2==2.10
MarkupSafe==1.1.0 MarkupSafe==1.1.0
packaging==18.0 packaging==19.0
pyparsing==2.3.0 pyparsing==2.3.1
Pygments==2.3.1 Pygments==2.3.1
pytz==2018.9 pytz==2018.9
requests==2.21.0 requests==2.21.0
six==1.12.0 six==1.12.0
snowballstemmer==1.2.1 snowballstemmer==1.2.1
sphinx==1.8.3 sphinx==1.8.4
sphinx_rtd_theme==0.4.2 sphinx_rtd_theme==0.4.3
sphinxcontrib-asyncio==0.2.0 sphinxcontrib-asyncio==0.2.0
sphinxcontrib-websupport==1.1.0 sphinxcontrib-websupport==1.1.0
urllib3==1.24.1 urllib3==1.24.1
@ -77,11 +75,11 @@ style =
click==7.0 click==7.0
toml==0.10.0 toml==0.10.0
test = test =
atomicwrites==1.2.1 atomicwrites==1.3.0
more-itertools==5.0.0 more-itertools==6.0.0
pluggy==0.8.1 pluggy==0.8.1
py==1.7.0 py==1.7.0
pytest==4.1.0 pytest==4.2.0
pytest-asyncio==0.10.0 pytest-asyncio==0.10.0
six==1.12.0 six==1.12.0