1
0
Fork 0
mirror of https://github.com/myned/modufur.git synced 2024-12-24 14:27:27 +00:00

Merge remote-tracking branch 'origin/master' into dev

This commit is contained in:
Myned 2018-03-31 16:37:58 -04:00
commit f5f8687adf
7 changed files with 1186 additions and 904 deletions

226
.gitignore vendored
View file

@ -1,113 +1,113 @@
# Custom # Custom
*.json *.json
*.pyo *.pyo
*.pyc *.pyc
*.DS_Store *.DS_Store
*.pkl *.pkl
*.png *.png
*.bat *.bat
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
*$py.class *$py.class
# C extensions # C extensions
*.so *.so
# Distribution / packaging # Distribution / packaging
.Python .Python
build/ build/
develop-eggs/ develop-eggs/
dist/ dist/
downloads/ downloads/
eggs/ eggs/
.eggs/ .eggs/
lib/ lib/
lib64/ lib64/
parts/ parts/
sdist/ sdist/
var/ var/
wheels/ wheels/
*.egg-info/ *.egg-info/
.installed.cfg .installed.cfg
*.egg *.egg
MANIFEST MANIFEST
# PyInstaller # PyInstaller
# Usually these files are written by a python script from a template # Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it. # before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest *.manifest
*.spec *.spec
# Installer logs # Installer logs
pip-log.txt pip-log.txt
pip-delete-this-directory.txt pip-delete-this-directory.txt
# Unit test / coverage reports # Unit test / coverage reports
htmlcov/ htmlcov/
.tox/ .tox/
.coverage .coverage
.coverage.* .coverage.*
.cache .cache
nosetests.xml nosetests.xml
coverage.xml coverage.xml
*.cover *.cover
.hypothesis/ .hypothesis/
# Translations # Translations
*.mo *.mo
*.pot *.pot
# Django stuff: # Django stuff:
*.log *.log
.static_storage/ .static_storage/
.media/ .media/
local_settings.py local_settings.py
# Flask stuff: # Flask stuff:
instance/ instance/
.webassets-cache .webassets-cache
# Scrapy stuff: # Scrapy stuff:
.scrapy .scrapy
# Sphinx documentation # Sphinx documentation
docs/_build/ docs/_build/
# PyBuilder # PyBuilder
target/ target/
# Jupyter Notebook # Jupyter Notebook
.ipynb_checkpoints .ipynb_checkpoints
# pyenv # pyenv
.python-version .python-version
# celery beat schedule file # celery beat schedule file
celerybeat-schedule celerybeat-schedule
# SageMath parsed files # SageMath parsed files
*.sage.py *.sage.py
# Environments # Environments
.env .env
.venv .venv
env/ env/
venv/ venv/
ENV/ ENV/
env.bak/ env.bak/
venv.bak/ venv.bak/
# Spyder project settings # Spyder project settings
.spyderproject .spyderproject
.spyproject .spyproject
# Rope project settings # Rope project settings
.ropeproject .ropeproject
# mkdocs documentation # mkdocs documentation
/site /site
# mypy # mypy
.mypy_cache/ .mypy_cache/

12
Pipfile
View file

@ -4,6 +4,8 @@ url = "https://pypi.python.org/simple"
verify_ssl = true verify_ssl = true
name = "pypi" name = "pypi"
[requires]
python_version = "3.6"
[packages] [packages]
@ -13,7 +15,15 @@ google-api-python-client = "*"
pyrasite = "*" pyrasite = "*"
"discord.py" = {extras = ["voice"], git = "https://github.com/Rapptz/discord.py", ref = "rewrite"} "discord.py" = {extras = ["voice"], git = "https://github.com/Rapptz/discord.py", ref = "rewrite"}
aiohttp = "*" aiohttp = "*"
"hurry.filesize" = "*"
gitpython = "*"
gmusicapi = "*"
python-telegram-bot = "*"
requests = "*"
requests-oauthlib = "*"
yarl = "*"
hurry = "*"
pynacl = "*"
[dev-packages] [dev-packages]

452
Pipfile.lock generated
View file

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "968a2d3c16bf72fd0a52baaa3bbdac69c5dc46dd953874af00479bbe854b678c" "sha256": "c8426f63f07b00a7dcc5220e1210acfc6279bb1eccb40d9a884d34e203bf8f85"
}, },
"host-environment-markers": { "host-environment-markers": {
"implementation_name": "cpython", "implementation_name": "cpython",
@ -9,15 +9,17 @@
"os_name": "posix", "os_name": "posix",
"platform_machine": "x86_64", "platform_machine": "x86_64",
"platform_python_implementation": "CPython", "platform_python_implementation": "CPython",
"platform_release": "17.2.0", "platform_release": "17.4.0",
"platform_system": "Darwin", "platform_system": "Darwin",
"platform_version": "Darwin Kernel Version 17.2.0: Fri Sep 29 18:27:05 PDT 2017; root:xnu-4570.20.62~3/RELEASE_X86_64", "platform_version": "Darwin Kernel Version 17.4.0: Sun Dec 17 09:19:54 PST 2017; root:xnu-4570.41.2~1/RELEASE_X86_64",
"python_full_version": "3.6.2", "python_full_version": "3.6.2",
"python_version": "3.6", "python_version": "3.6",
"sys_platform": "darwin" "sys_platform": "darwin"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": {}, "requires": {
"python_version": "3.6"
},
"sources": [ "sources": [
{ {
"name": "pypi", "name": "pypi",
@ -29,30 +31,30 @@
"default": { "default": {
"aiohttp": { "aiohttp": {
"hashes": [ "hashes": [
"sha256:cb281a30655efe939550b7dfbe8c5d6e84951caf52510528a88ae7fe483109ae", "sha256:2e8be4c46083ced9d9bc9ff4d77f31bfcd3e7486613f6138c5aa302d33ea54ed",
"sha256:7ff6173cc691a44845e10f452d52932f12b45c6d5db85f5702b17d15addda808", "sha256:4634dd3bbb68d0c7e5e4bca7571369d53c497b3300d9d678f939038e1b1231ee",
"sha256:e5c2c16ae815d883d4072f2d4542effdeae1d9a464b56bd06186d9eeca1981fe", "sha256:25825c61688fc95e09d6be19e513e925cb4f08aae4d7a7c38a1fa75e0e4c22bd",
"sha256:bd920a8b5da1e0ed89c1a688d1ed252ba71189ff747747d38803728a9fba17d4", "sha256:9e6d6f0bca955923b515f8b5631c4c4f43aa152763852284cbefc89bd544069e",
"sha256:34dc28c31786f43dcd5a25e19da1dd8a5289d338f4ed1a1a9e5d1431ad4b79e2", "sha256:6eef1d7eff9e6fa1029f7a62504f88b2b0afce89ced5c95d3a4cf1c2faef1231",
"sha256:8b5087310db23b1976776beedab05c8aa8e490755e9f3473fc1f07aa0cbe3bb9", "sha256:040eecbc37aa5bd007108388fab6c42b2a01b964c4feac26bdffc8fe8af6c110",
"sha256:3654f4913a6c02e742051881f94b7b8a9dfe527318e8d7a7dd2f2d8474b0c082", "sha256:53988a8cf76c3fb74a759e77b1c2f55ab36880d57c6e7d0d59ad28743a2535fe",
"sha256:9af1260050bb29db245d284c659e710161c45575f8fb365202551c5fd43ed1c1", "sha256:d51673140330c660e68c182e14164ddba47810dca873bbd28662f31d7d8c0185",
"sha256:0589a94051aa0573b28eb5d330a0d12cee891d2ed9fd9323c9ddbe322e88fc15", "sha256:2fe26e836a1803c7414613c376fe29fc4ae0e5145e3813e1db1854cb05c91a3c",
"sha256:b3b047ecd8b899f99d669f5e22aeabcc77e78f3eb4ee985755ec49c53fcccfc2", "sha256:15ad4d76bddfd98bf9e48263c70f6603e96d823c5a5c0c842646e9871be72c64",
"sha256:b73d90381c915c8f873da65520af3e8ac8d26e054b9bc849faa802b25623172a", "sha256:7910089093296b5c8f683965044f553b0c5c9c2dbf310a219db76c6e793fea55",
"sha256:e698a369200b6d4e50a493cf1da4a25f5457f61afd5e7fe91b40f9859f632d1f", "sha256:a19b96f77763ddf0249420438ebfc4d9a470daeb26f6614366d913ff520fa29b",
"sha256:c58ddcb3ef4dde692e98738f6b3d06650d2b2722910e4d18184530ff8d092d95", "sha256:b53bc7b44b1115af50bd18d9671972603e5a4934e98dd3f4d671104c070e331d",
"sha256:0965fa5e798b7faacd6417eeb5c476aa6a7d730ba2793106e5bae610fdb043cb", "sha256:4b6fa00885ec778154244b010acecb862d277e6652b87fcd85c0f4735d26451c",
"sha256:3979ef9071bd3c909d33cc333bde356f7063555ad8a0383e53f18dc31131b7d8", "sha256:7aee5c0750584946fde40da70f0b28fe769f85182f1171acef18a35fd8ecd221"
"sha256:85caf471c5216d615b01443293cc5ead7502053dedd804da32dd35de816a7436",
"sha256:63de1a47530b7bf770f1ad26f342ea94babb451ae04cd3119e87cbfea1c970e5",
"sha256:04a8c24a376bb547c0c9b6e721d6ced23062d262d24d5e63a3e383c8b49e14ef",
"sha256:9e70efab3bfea1493f3099031e3731a6519adad62e6d3f464b429a80a6e2ff6f",
"sha256:c7cb8d2be2f3351a28bee9deca1194e1402171c47b52f16708321ef4ce682333",
"sha256:ab9e7ecf375387ae3d17ac25492801860f2726f541d73cf1108fa157e1da75a3",
"sha256:42373fbdbe8f09233c17e74f53cee877bc7d5b495b4fc14c32a119255e85e736"
], ],
"version": "==2.3.2" "version": "==3.0.1"
},
"appdirs": {
"hashes": [
"sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e",
"sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"
],
"version": "==1.4.3"
}, },
"async-timeout": { "async-timeout": {
"hashes": [ "hashes": [
@ -61,6 +63,13 @@
], ],
"version": "==2.0.0" "version": "==2.0.0"
}, },
"attrs": {
"hashes": [
"sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450",
"sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9"
],
"version": "==17.4.0"
},
"beautifulsoup4": { "beautifulsoup4": {
"hashes": [ "hashes": [
"sha256:7015e76bf32f1f574636c4288399a6de66ce08fb7b2457f628a8d70c0fbabb11", "sha256:7015e76bf32f1f574636c4288399a6de66ce08fb7b2457f628a8d70c0fbabb11",
@ -69,6 +78,45 @@
], ],
"version": "==4.6.0" "version": "==4.6.0"
}, },
"certifi": {
"hashes": [
"sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296",
"sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d"
],
"version": "==2018.1.18"
},
"cffi": {
"hashes": [
"sha256:5d0d7023b72794ea847725680e2156d1d01bc698a9007fccce46d03c904fe093",
"sha256:86903c0afab4a3390170aca61f753f5adad8ffff947030719ee44dedc5b68403",
"sha256:7d35678a54da0d3f1bc30e3a58a232043753d57c691875b5a75e4e062793bc9a",
"sha256:824cac33906be5c8e976f0d950924d88ec058989ef9cd2f77f5cd53cec417635",
"sha256:6ca52651f6bd4b8647cb7dee15c82619de3e13490f8e0bc0620830a2245b51d1",
"sha256:a183959a4b1e01d6172aeed356e2523ec8682596075aa6cf0003fe08da959a49",
"sha256:9532c5bc0108bd0fe43c0eb3faa2ef98a2db60fc0d4019f106b88d46803dd663",
"sha256:96652215ef328262b5f1d5647632bd342ac6b31dfbc495b21f1ab27cb06d621d",
"sha256:6c99d19225e3135f6190a3bfce2a614cae8eaa5dcaf9e0705d4ccb79a3959a3f",
"sha256:12cbf4c04c1ad07124bfc9e928c01e282feac9ec7dd72a18042d4fc56456289a",
"sha256:69c37089ccf10692361c8d14dbf4138b00b46741ffe9628755054499f06ed548",
"sha256:b8d1454ef627098dc76ccfd6211a08065e6f84efe3754d8d112049fec3768e71",
"sha256:cd13f347235410c592f6e36395ee1c136a64b66534f10173bfa4df1dc88f47d0",
"sha256:0640f12f04f257c4467075a804a4920a5d07ef91e11c525fc65d715c08231c81",
"sha256:89a8d05b96bdeca8fdc89c5fa9469a357d30f6c066262e92c0c8d2e4d3c53cae",
"sha256:a67c430a9bde73ae85b0c885fcf41b556760e42ea74c16dc70431a349989b448",
"sha256:7a831170b621e98f45ed1d5758325be19619a593924127a0a47af9a72a117319",
"sha256:796d0379102e6da5215acfcd20e8e69cca9d97309215b4ce088fe175b1c2f586",
"sha256:0fe3b3d571543a4065059d1d3d6d39f4ca6da0f2207ad13547094522e32ead46",
"sha256:678135090c311780382b1dd3f828f715583ea8a69687ed053c047d3cec6625d6",
"sha256:f4992cd7b4c867f453d44c213ee29e8fd484cf81cfece4b6e836d0982b6fa1cf",
"sha256:6d191fb20138fe1948727b20e7b96582b7b7e676135eabf72d910e10bf7bfa65",
"sha256:ec208ca16e57904dd7f4c7568665f80b1f7eb7e3214be014560c28def219060d",
"sha256:b3653644d6411bf4bd64c1f2ca3cb1b093f98c68439ade5cef328609bbfabf8c",
"sha256:f4719d0bafc5f0a67b2ec432086d40f653840698d41fa6e9afa679403dea9d78",
"sha256:87f837459c3c78d75cb4f5aadf08a7104db15e8c7618a5c732e60f252279c7a6",
"sha256:df9083a992b17a28cd4251a3f5c879e0198bb26c9e808c4647e0a18739f1d11d"
],
"version": "==1.11.4"
},
"chardet": { "chardet": {
"hashes": [ "hashes": [
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691", "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691",
@ -76,6 +124,13 @@
], ],
"version": "==3.0.4" "version": "==3.0.4"
}, },
"decorator": {
"hashes": [
"sha256:94d1d8905f5010d74bbbd86c30471255661a14187c45f8d7f3e5aa8540fdb2e5",
"sha256:7d46dd9f3ea1cf5f06ee0e4e1277ae618cf48dfb10ada7c8427cd46c42702a0e"
],
"version": "==4.2.1"
},
"discord.py": { "discord.py": {
"extras": [ "extras": [
"voice" "voice"
@ -83,12 +138,36 @@
"git": "https://github.com/Rapptz/discord.py", "git": "https://github.com/Rapptz/discord.py",
"ref": "rewrite" "ref": "rewrite"
}, },
"docopt": {
"hashes": [
"sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
],
"version": "==0.6.2"
},
"future": {
"hashes": [
"sha256:e39ced1ab767b5936646cedba8bcce582398233d6a627067d4c6a454c90cfedb"
],
"version": "==0.16.0"
},
"gmusicapi": {
"hashes": [
"sha256:fcee09c2f3cf274f514589eabf82f2281fb184526106432079e641a6bcb697f2"
],
"version": "==11.0.0"
},
"google-api-python-client": { "google-api-python-client": {
"hashes": [ "hashes": [
"sha256:441d638e5fff7d9f97587aa99387efd0ee13f577c9d4d50820dfda4bb80d0e64", "sha256:2cf9ab83fa62e06717363e8855fb027864caeb35a3197cadb7f0de38356881c4",
"sha256:bb1f27740f6596f8272a2e1033d93d68e27e8ed5d22d6ab957e3f1d3f8ce05f6" "sha256:95ce394028754ec537e5791e811511fdd5fabe6f1f8879407a8daed71ecb0b4c"
], ],
"version": "==1.6.4" "version": "==1.6.5"
},
"gpsoauth": {
"hashes": [
"sha256:1c3f45824d45ac3d06b9d9a0c0eccafe1052505d31ac9a698aef8b00fb0dfc37"
],
"version": "==0.4.1"
}, },
"httplib2": { "httplib2": {
"hashes": [ "hashes": [
@ -96,6 +175,31 @@
], ],
"version": "==0.10.3" "version": "==0.10.3"
}, },
"hurry": {
"hashes": [
"sha256:d94d3bb94573c17b215257f3f77a9279f2dbb2e794c1862bdb180529edeb8d3f"
],
"version": "==1.0"
},
"hurry.filesize": {
"hashes": [
"sha256:f5368329adbef86accd3bc9490522340bb79260455ae89b1a42c10f63801b9a6"
],
"version": "==0.9"
},
"idna": {
"hashes": [
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4",
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f"
],
"version": "==2.6"
},
"idna-ssl": {
"hashes": [
"sha256:1227e44039bd31e02adaeafdbba61281596d623d222643fb021f87f2144ea147"
],
"version": "==1.0.0"
},
"lxml": { "lxml": {
"hashes": [ "hashes": [
"sha256:41f59cbdab232f11680d5d4dec9f2e6782fd24d78e37ee833447702e34e675f4", "sha256:41f59cbdab232f11680d5d4dec9f2e6782fd24d78e37ee833447702e34e675f4",
@ -129,32 +233,51 @@
], ],
"version": "==4.1.1" "version": "==4.1.1"
}, },
"mechanicalsoup": {
"hashes": [
"sha256:22423efd025c3eedb06f41d3ff1127174a59f40dc560e82dce143956976195bf"
],
"version": "==0.10.0"
},
"mock": {
"hashes": [
"sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1",
"sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba"
],
"version": "==2.0.0"
},
"multidict": { "multidict": {
"hashes": [ "hashes": [
"sha256:d12dfcff45b5c0eb3d586289cbf928012e75f93f10f4b9d7af903acb07b3c226", "sha256:0fd4d255adcbab3341d64a2fff5acce23409e57bb94e626485dea3db70ddc35e",
"sha256:f7deb65a184cbe757faaf4c6d2b8f203cb1a11dd44603a34d7befc343253d5bf", "sha256:93f1af99bbe75c854370460a60823d6726f9af2196818a64346000d02e074ed7",
"sha256:80ad69b8330135b52a6da7a1f0ab6a278025bb72ea08768966785c829f515a6f", "sha256:65546242d0c481c0daf0ef20c1be81c075fb763c5f4346f18f748b422fc40f32",
"sha256:3261b631cd6d079e6a20def3306b433794f800ea896dce4f1d5e833ad9bf6f26", "sha256:0462372fc74e4c061335118a4a5992b9a618d6c584b028ef03cf3e9b88a960e2",
"sha256:80e2bd17ea98fe77867771e1ee03433a54fa492a8413966a6caa766bdd6d6e62", "sha256:63663541d395ffe4d51a3c021467d0a7b46c965b63fa1646cb46e2e2f1f36415",
"sha256:8eb59892040198741944eafca0c34be4da6b58be7fddf6e491a2d9e7e1767548", "sha256:84a1cb5320f1494cd444ca3bd09ddba2e0af0cb210f9263bcf17357ab22671a1",
"sha256:24ec0d645ca70981e1c84e97e48c874b47f4970a173c8c751be9c213a8658e40", "sha256:241c11614f64535e213ea143efa8b7e598793256601fc795e77075bdfa54f5d6",
"sha256:167558cfb7c43077b3d8602142109f2b52fae0841a7ff97eb0a7443db199f303", "sha256:ea8a18ea02bf84981ec93faded773a866554666f13955c92139127892c4bb45c",
"sha256:80abc93d197e24fb7c5aa5a8be3eacbcbc7115a2ff64e46162a4c2b46cd2f75a", "sha256:b46ec31bb7729eaa678a3bb1c999460902df1e295fcc093b9aa5f2c7e68d5803",
"sha256:ff2b92a41df2e4c5cafaefb782469f3e6053ed00026d75a398521096192d0408", "sha256:608f7eef60e6558418d7da6551dd3d07ccc1290ecc85755d781bd8100322ea5b",
"sha256:5cfb63f0ddfa86ce6e80eee64e4fe886f9dfdb6dbbd724997bccb66513b0e29f", "sha256:068e91060e3e211441b1a31f5e65de88fc346490e1fae583c35a75a5295c8ef7",
"sha256:50dac1151e34974b04419073ee9726f4180c6daf3454fd4af258824a19ad8c1d", "sha256:288e8f94fb6f586e7386c1f22c979ce3ec866ab23371fa8fef1dd526cd4dfde1",
"sha256:ebf1ba2af62dbaa37cf3db346830bb43d40d05a5f1f1966888a620f9b795e7c7", "sha256:503ae54582601b0ff647731fee5efcdff5db1f4da0350febb31b628236a5f0b5",
"sha256:3f513f3bf933d7cb6f5741f6676d4fac1e96aa634161c071974f9bb86a7bbac9", "sha256:6d5f6f26f9025756035c473167b39c5a72e4e519a2286c9399d21f6682e4e5bc",
"sha256:ef6dc6e2d51b6058aa62cdd44dbf02c250c19eee6ff0065babc0ac126b068d43", "sha256:e13265feabb1fa26f9cd49cbafd9b5de70ad768093ddb092af477c9823f44f0e",
"sha256:90dc3b8fefc58a865d64957f8f901d724250ba2a40e02f49d0df0103e96f5afa", "sha256:50de6f3786ba868ffb7d78d4bcacf0928321f9892366b2f4a0426bba644e3f25",
"sha256:70630854b820d73ae102440123df38c983d77cd4ae444f3930a6bb6bbda87b76", "sha256:16c78b10e897a512aa34ab1969982e42246e53077ae903c1b334926e1ea832d1",
"sha256:faf2b6447521d2075d03fb5e7c5467bac68f67df1c69e034ebca3afb6b3c619d", "sha256:e04b5bf8581718cf84c1c60bda40221d926ceb06f942ebabfc3baf467a1e34be",
"sha256:eb7d5d39463137726138fc14c8458131136b8f4b06ba65f1cecd7aa6abe91df1", "sha256:d99819e9e15e1295a31a757360cab65bc96162870f90c29432564bd8e8999aca",
"sha256:fa04df1503fae7045883c57db47ba0c07de2ebe4a91c3e64d56f20d3d99e5dc8", "sha256:cd172509bfc9144395204dd2c0eb305ae5e89f8ad1714ffd7d793607c53c3244",
"sha256:bce16633f3ee88863e4c9bcd7e037a6133c56fd9e7e7c0776bbaeeddcf154ac4", "sha256:3508bea4974ee30fabcf7c8852fca7d9d54d496eaa068bee8311e0ac4df4ade3",
"sha256:f82e61c7408ed0dce1862100db55595481911f159d6ddec0b375d35b6449509b" "sha256:fb4412490324705dcd2172baa8a3ea58ae23c5f982476805cad58ae929fe2a52"
], ],
"version": "==3.3.2" "version": "==4.1.0"
},
"mutagen": {
"hashes": [
"sha256:b2a2c2ce87863af12ed7896f341419cd051a3c72c3c6733db9e83060dcadee5e"
],
"version": "==1.40.0"
}, },
"oauth2client": { "oauth2client": {
"hashes": [ "hashes": [
@ -163,39 +286,140 @@
], ],
"version": "==4.1.2" "version": "==4.1.2"
}, },
"oauthlib": {
"hashes": [
"sha256:ce57b501e906ff4f614e71c36a3ab9eacbb96d35c24d1970d2539bbc3ec70ce1"
],
"version": "==2.0.6"
},
"pbr": {
"hashes": [
"sha256:60c25b7dfd054ef9bb0ae327af949dd4676aa09ac3a9471cdc871d8a9213f9ac",
"sha256:05f61c71aaefc02d8e37c0a3eeb9815ff526ea28b3b76324769e6158d7f95be1"
],
"version": "==3.1.1"
},
"proboscis": {
"hashes": [
"sha256:b822b243a7c82030fce0de97bdc432345941306d2c24ef227ca561dd019cd238"
],
"version": "==1.2.6.0"
},
"protobuf": {
"hashes": [
"sha256:11788df3e176f44e0375fe6361342d7258a457b346504ea259a21b77ffc18a90",
"sha256:50c24f0d00b7efb3a72ae638ddc118e713cfe8cef40527afe24f7ebcb878e46d",
"sha256:41661f9a442eba2f1967f15333ebe9ecc7e7c51bcbaa2972303ad33a4ca0168e",
"sha256:06ec363b74bceb7d018f2171e0892f03ab6816530e2b0f77d725a58264551e48",
"sha256:b20f861b55efd8206428c13e017cc8e2c34b40b2a714446eb202bbf0ff7597a6",
"sha256:c1f9c36004a7ae6f1ce4a23f06070f6b07f57495f251851aa15cc4da16d08378",
"sha256:4d2e665410b0a278d2eb2c0a529ca2366bb325eb2ae34e189a826b71fb1b28cd",
"sha256:95b78959572de7d7fafa3acb718ed71f482932ddddddbd29ba8319c10639d863"
],
"version": "==3.5.1"
},
"py": {
"hashes": [
"sha256:2ccb79b01769d99115aa600d7eed99f524bf752bba8f041dc1c184853514655a",
"sha256:0f2d585d22050e90c7d293b6451c83db097df77871974d90efd5a30dc12fcde3"
],
"version": "==1.4.34"
},
"pyasn1": { "pyasn1": {
"hashes": [ "hashes": [
"sha256:5eac8d0c1c1282842c9145ae134990a1baf7616eb4cee9129213fad76eba4f54", "sha256:f81c96761fca60d64b1c9b79ec2e40cf9495a745cf570613079ef324aeb9672b",
"sha256:960a603e677897ea29b9a1327b789b7b8a9e187a89e05fed9c3152b3b7c22954", "sha256:7d626683e3d792cccc608da02498aff37ab4f3dafd8905d6bf755d11f9b26b43",
"sha256:4bb562b9f1fc4526028b2aa4dc027dce08f3ade0780abc593a02ce6dbade6e6c", "sha256:e85895087905c65b5b594eb91f7522664c85545b147d5f4d4e7b1b07da8dcbdc",
"sha256:8fa8884056bd5b2c92ca1685e6344121b6b43718b44f0c6eb223958003c9d14a", "sha256:5a0db897b311d265cde49615cf783f1c78613138605cdd0f907ecfa5b2aba3ee",
"sha256:16e896433f84575f0636cd9aa8b24659689268a62e00f17235e1fc23c6b00b25", "sha256:d5cd6ed995dba16fad0c521cfe31cd2d68400b53fcc2bce93326829be73ab6d1",
"sha256:bb6f5d5507621e0298794bc3e75b8f963e886cee388a378ab58e5c35ac024276", "sha256:a7efe807c4b83a859e2735c692b92ed7b567cfddc4163763412920041d876c2b",
"sha256:60bf78784b117979f5517c38308f6965fff6c803660fbb16368d94433953b62a", "sha256:b5a9ca48055b9a20f6d1b3d68e38692e5431c86a0f99ea602e61294e891fee5b",
"sha256:4a677c6c9e484977ed6c6a93714ff06ac374220408afeaeef4ef2af652af0f3d", "sha256:c07d6e587b2f928366b1f67c09bda026a3e6fcc99e80a744dc67f8fca3895626",
"sha256:b16fb6097d00bbafc114861b16ea41cfe63e32fed1bdc7cd5905a3e02a992fa3", "sha256:d84c2aea3cf43780e9e6a19f4e4dddee9f6976519020e64e47c57e5c7a8c3dd2",
"sha256:8212bde51ec192e30654efe10e636082738ed728e316049f3685d66b8c92941c", "sha256:758cb50abddc03e4563fd9e7f03db56e3e87b58c0bd01247360326e5c0c7ffa5",
"sha256:8d4f0971682203bdfc93740ee7d3fcba0a7f55629451dbe2d32af2335c55b2be", "sha256:0d7f6e959fe53f3960a23d73f35e1fce61348b30915b6664309ca756de7c1f89",
"sha256:187f2a66d617683f8e82d5c00033b7c8a0287e1da88a9d577aebec321cad4965" "sha256:d258b0a71994f7770599835249cece1caef3c70def868c4915e6e5ca49b67d15"
], ],
"version": "==0.3.7" "version": "==0.4.2"
}, },
"pyasn1-modules": { "pyasn1-modules": {
"hashes": [ "hashes": [
"sha256:ea8b89f79724c3cf4ca88bc7327964f0750e5219618805dcc85ca0fdae9e5b34", "sha256:b1f395cae2d669e0830cb023aa86f9f283b7a9aa32317d7f80d8e78aa2745812",
"sha256:16b086729c7af47a67c9e64cea2f763975b602155319b6c63f1f20e5f0179be7", "sha256:854700bbdd01394e2ada9c1bfbd0ed9f5d0c551350dbbd023e88b11d2771ae06",
"sha256:7fc70766b8ef5a62eb43767cd7a1c1b3a6aa5095b263a6f2a734987fd90a35d6", "sha256:598a6004ec26a8ab40a39ea955068cf2a3949ad9c0030da970f2e1ca4c9f1cc9",
"sha256:92caf877c06c033786f0149dd37ea1abfd2c398a007bb40ae6b1f2c96804c1b2", "sha256:f53fe5bcebdf318f51399b250fe8325ef3a26d927f012cc0c8e0f9e9af7f9deb",
"sha256:018225e6718cfff7e515bd23efe8c0956e5226e3a416ba829e695c607e8ac58f", "sha256:47fb6757ab78fe966e7c58b2030b546854f78416d653163f0ce9290cf2278e8b",
"sha256:773641c73f6eaac19b5ed7c3e6c3e733dc43b494282ef067325ea6583763f531", "sha256:041e9fbafac548d095f5b6c3b328b80792f006196e15a232b731a83c93d59493",
"sha256:3350c74c22eb821acfd22ecf4bbb9abfc1de2bd5befb5befd5b1b7ede2d92ace", "sha256:0cea139045c38f84abaa803bcb4b5e8775ea12a42af10019d942f227acc426c3",
"sha256:6c457b5037e6a145a43bf3b5b1db622d20a08d4d1ad9a9bdc22dbef7229b250c", "sha256:0cdca76a68dcb701fff58c397de0ef9922b472b1cb3ea9695ca19d03f1869787",
"sha256:d37774d5de3887b1cdce7415209e92da49fcd13b99db1c44c179a93a5f87c8b2", "sha256:72fd8b0c11191da088147c6e4678ec53e573923ecf60b57eeac9e97433e09fc2",
"sha256:6d8ad92e399b3140259b2c5249c49e67806a3eee332ed3734da807733925f04e", "sha256:c6747146e95d2b14cc2a8399b2b0bde3f93778f8f9ec704690d2b589c376c137",
"sha256:b437be576bdf440fc0e9307a4334303d117a577f2d809ecb9abd715539cb0109", "sha256:0f2e50d20bc670be170966638fa0ae603f0bc9ed6ebe8e97a6d1d4cef30cc889",
"sha256:1d303eed5aa54cafeca209d16b8c7ea2c6064735fb61f1bee2e0ed63a0816988" "sha256:af00ea8f2022b6287dc375b2c70f31ab5af83989fc6fe9eacd4976ce26cd7ccc"
], ],
"version": "==0.1.5" "version": "==0.2.1"
},
"pycparser": {
"hashes": [
"sha256:99a8ca03e29851d96616ad0404b4aad7d9ee16f25c9f9708a11faf2810f7b226"
],
"version": "==2.18"
},
"pycryptodomex": {
"hashes": [
"sha256:a2ac2eaafd7dc52920c902dae225badfbd9323f0d1166db0a1614fa55e2dc5b6",
"sha256:7464c5e2751e9fa9e3b66f3d7054edf4d837498a151d9a3ba156cb6532344455",
"sha256:3588078356c6d6f1a5765fe1b254882e1ed7ce5cd8a8a00fdc4cef507e46868d",
"sha256:88f6dfb6b3efd084df29d4ed312dde085f4a7cc9efada59998f75a8826e255a2",
"sha256:565fa996de2ab58cae9a7b7241c7fd84e6bd705a05ff89e2ea5c4d3e6c755c58",
"sha256:b95adb32f32bc85f1c6c1d4d344a73a5fddf7c69b3a6551e499963022200fc5e",
"sha256:14bdfc08d38a17fa54027b51c122ce175b84f979781a2e11e86015dd0dfa4157",
"sha256:0307cfa4c8aff4dd943933704fc4eae2119f42439d1fe456a594bee44a7d860b",
"sha256:2b64915a430fbf992c75751c13cabecf27ba8dd43fdcc8bc0551302d87ef4c91",
"sha256:acc287965dd1f08bb5b2e662289111e24fc5e7754c79571a20803fd5ce307c47",
"sha256:25d038c3d18b59e07acb0be516396d0c8ed3b098761b0f597c7f03c7516e7699",
"sha256:3ebc14df23b8bcc2734aff6255b7047b8c2f28779923f0f36f17c2d2d9fc32dc",
"sha256:da75c00a761e456fb99be7e28b60568163c6d3d631f305ffc9f1365c8991c669",
"sha256:1a1a4b604dd9dab1a55d43972e853be0c2fd0c50f3589f8c0e18febdb361235c",
"sha256:90c9a70005d5c02886ab98ef4e2d577347e3c41399aa0c35a4eac4ee27b1d718",
"sha256:51b789c2ccdc30ebf0b1dfcb2095a5e10ebaf68e2cd89bc051b1887a8e8e14d6",
"sha256:e27f557e8aab1dbfdd1a51f0053437baf5e13fc6f04c07fbe3a0da7a5c8c51f2",
"sha256:626463deb7f760507f98504413fb6035dcff7c8f0b36c6e216605680caa337f0",
"sha256:1088099e88ba7238cebd3c44b38edbe7130b229a3d7d7b4c9b0ed06533dd13e6",
"sha256:bf2a5b6eee8ca198eea13bcbd2df62721ed9b5f5c8660ac56be7249ff349f582",
"sha256:46a3c64f377f14fe9ccaa7b3307de76e312edd0cf7543edb6f159e519081254c",
"sha256:bc30c42399b268788407a1ac692ad4011e774809034e7a0bc9559b8feb727ea1",
"sha256:02dda17f54cbb37dcad6bd52c21f1208be1e435c7c8b48922366dad989a0c597"
],
"version": "==3.4.12"
},
"pynacl": {
"hashes": [
"sha256:0bfa0d94d2be6874e40f896e0a67e290749151e7de767c5aefbad1121cad7512",
"sha256:1d33e775fab3f383167afb20b9927aaf4961b953d76eeb271a5703a6d756b65b",
"sha256:eb2acabbd487a46b38540a819ef67e477a674481f84a82a7ba2234b9ba46f752",
"sha256:14339dc233e7a9dda80a3800e64e7ff89d0878ba23360eea24f1af1b13772cac",
"sha256:cf6877124ae6a0698404e169b3ba534542cfbc43f939d46b927d956daf0a373a",
"sha256:eeee629828d0eb4f6d98ac41e9a3a6461d114d1d0aa111a8931c049359298da0",
"sha256:d0eb5b2795b7ee2cbcfcadacbe95a13afbda048a262bd369da9904fecb568975",
"sha256:11aa4e141b2456ce5cecc19c130e970793fa3a2c2e6fbb8ad65b28f35aa9e6b6",
"sha256:8ac1167195b32a8755de06efd5b2d2fe76fc864517dab66aaf65662cc59e1988",
"sha256:d795f506bcc9463efb5ebb0f65ed77921dcc9e0a50499dedd89f208445de9ecb",
"sha256:be71cd5fce04061e1f3d39597f93619c80cdd3558a6c9ba99a546f144a8d8101",
"sha256:2a42b2399d0428619e58dac7734838102d35f6dcdee149e0088823629bf99fbb",
"sha256:73a5a96fb5fbf2215beee2353a128d382dbca83f5341f0d3c750877a236569ef",
"sha256:d8aaf7e5d6b0e0ef7d6dbf7abeb75085713d0100b4eb1a4e4e857de76d77ac45",
"sha256:2dce05ac8b3c37b9e2f65eab56c544885607394753e9613fd159d5e2045c2d98",
"sha256:f5ce9e26d25eb0b2d96f3ef0ad70e1d3ae89b5d60255c462252a3e456a48c053",
"sha256:6453b0dae593163ffc6db6f9c9c1597d35c650598e2c39c0590d1757207a1ac2",
"sha256:fabf73d5d0286f9e078774f3435601d2735c94ce9e514ac4fb945701edead7e4",
"sha256:13bdc1fe084ff9ac7653ae5a924cae03bf4bb07c6667c9eb5b6eb3c570220776",
"sha256:8f505f42f659012794414fa57c498404e64db78f1d98dfd40e318c569f3c783b",
"sha256:04e30e5bdeeb2d5b34107f28cd2f5bbfdc6c616f3be88fc6f53582ff1669eeca",
"sha256:8abb4ef79161a5f58848b30ab6fb98d8c466da21fdd65558ce1d7afc02c70b5f",
"sha256:e0d38fa0a75f65f556fb912f2c6790d1fa29b7dd27a1d9cc5591b281321eaaa9"
],
"version": "==1.2.1"
}, },
"pyrasite": { "pyrasite": {
"hashes": [ "hashes": [
@ -203,6 +427,34 @@
], ],
"version": "==2.0" "version": "==2.0"
}, },
"python-dateutil": {
"hashes": [
"sha256:95511bae634d69bc7329ba55e646499a842bc4ec342ad54a8cdb65645a0aad3c",
"sha256:891c38b2a02f5bb1be3e4793866c8df49c7d19baabf9c1bad62547e0b4866aca"
],
"version": "==2.6.1"
},
"python-telegram-bot": {
"hashes": [
"sha256:ca5e1d257702d194ad5a5a0e6ccffb31203f1f783bf1c5da60c128f083032c44",
"sha256:f5c3233bea7c7adf165e31225bbe9f28717e9f1f5070ebe99a4757c31c27ab28"
],
"version": "==9.0.0"
},
"requests": {
"hashes": [
"sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b",
"sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"
],
"version": "==2.18.4"
},
"requests-oauthlib": {
"hashes": [
"sha256:50a8ae2ce8273e384895972b56193c7409601a66d4975774c60c2aed869639ca",
"sha256:883ac416757eada6d3d07054ec7092ac21c7f35cb1d2cf82faf205637081f468"
],
"version": "==0.8.0"
},
"rsa": { "rsa": {
"hashes": [ "hashes": [
"sha256:43f682fea81c452c98d09fc316aae12de6d30c4b5c84226642cf8f8fd1c93abd", "sha256:43f682fea81c452c98d09fc316aae12de6d30c4b5c84226642cf8f8fd1c93abd",
@ -225,23 +477,37 @@
], ],
"version": "==3.0.0" "version": "==3.0.0"
}, },
"urllib3": {
"hashes": [
"sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
"sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
],
"version": "==1.22"
},
"validictory": {
"hashes": [
"sha256:eb7ec9d811f3cf062fb943ce369a9b34a9f291037217ecf5a40a5f2421d29c0a",
"sha256:3a87b84658592f75f37d6bab77ac223774c9989dc7349c8aad19a424770835ba"
],
"version": "==1.1.2"
},
"yarl": { "yarl": {
"hashes": [ "hashes": [
"sha256:8b6a495e754269ba3817957dfe713532b7d5485cbcf3fce3e8624832f1156e3c", "sha256:e938046ce94bcb21e4641712eee3f3c211fc1e5a4601fd89c031e638022097a3",
"sha256:14ff708e9813b961d5c0b9a30ae8323591deffca0ef4fa93fbaba94ec44f3560", "sha256:42a7fc3d31c4c5b7fb7102380e1518e5af88e3bec7e89acf1213973e880bff6f",
"sha256:8756000c3ccf91acf9557401892864d2c869c0ae7c62e5d4fc3dd20ed5e8a3a7", "sha256:d861e697e4f1dbd614c29c7594f0dd3dbc48144f1e1f9ed8380604c7dde6cb19",
"sha256:728b9b26d5927fd35b102c62c476bace5c5e0fb1275e7d4bb169d50720b1d687", "sha256:e2dbf932bc9519281393973187075f1c2261a9e58032265ae47b2e79ece30ad8",
"sha256:3a68281e8031b9eae9a1c186eff725ed31a66d4dbfd4dc7c0ceb1a15d4a0b09f", "sha256:f00d067a08836c03646ace00baaf59697e978d2f1958b090c3a098c59221e175",
"sha256:dfacdfd8b350a10d66d2af0ef59fa56564cc03bcdcdd93a1aa6e65e9306f5882", "sha256:0a5d90f6d6ed6204e58b9d10882ef1a1193010e76e744ba39e848e8ddf96ab7a",
"sha256:42d329be7cafa9210c17349fd2db90b967b76fc6fd411f9abaf450a9e7f7e2e4", "sha256:1f96aa307067766c3edfc075739e5da8c790178d98f95e033fc8e22b8f2bc920",
"sha256:8d4a3ad001747e1225af47d46da935e507e7fe5e315bb4dbd235d5460b722488", "sha256:c9adaa61e1d9487c69f40561a89fc68640dba05e014ed29315b586e106a95671",
"sha256:4dcf2e89e65745c4ae597a724a612dbdb2f38e92c0a5f145c9ec1701d4ddf384", "sha256:9d25d6d6865979a5216b5bc2b9bd913dbaff636f74411baaa3e79c708ebeafbb",
"sha256:44e4ce0f59abbf7745ee450c3c4aa261a4deef83c7e1a3624dcc9db094d630e5", "sha256:c4c7682551c0b10b5c6fe0e359745759bd6298ab5839d9433ad0ed820def0d40",
"sha256:626113e8649ff2e205ea49432c4c94f730326852905ba411fb82006e443f3231", "sha256:2aec0ae0c50997e1a7af3ada4983e11caf212eee73eff6876ce26cf3a5072644",
"sha256:bfb4256496da1b1475a72e669464db539eca7b0fc3bddd231a64cf8afadb7efb", "sha256:f96d8bd39ee85cb9e842e3c7ad8c7cfb875bebfe07d63e87ca3e3984cb2f1546",
"sha256:25fe681a982f2cec567df8abac7cbd2ac27016e4aec89193945cab0643bfdb42" "sha256:6af895b45bd49254cc309ac0fe6e1595636a024953d710e01114257736184698"
], ],
"version": "==0.13.0" "version": "==1.1.0"
} }
}, },
"develop": {} "develop": {}

View file

@ -1,5 +1,5 @@
# Modufur # Modufur
Discord booru bot with a side of management and tasking. Discord booru bot with a side of management and tasking.
Credits: Credits:
Rapptz/discord.py Rapptz/discord.py

View file

@ -1,235 +1,235 @@
import asyncio import asyncio
import traceback as tb import traceback as tb
from contextlib import suppress from contextlib import suppress
from datetime import datetime as dt from datetime import datetime as dt
import discord as d import discord as d
from discord import errors as err from discord import errors as err
from discord.ext import commands as cmds from discord.ext import commands as cmds
from discord.ext.commands import errors as errext from discord.ext.commands import errors as errext
from misc import exceptions as exc from misc import exceptions as exc
from misc import checks from misc import checks
from utils import utils as u from utils import utils as u
class Administration: class Administration:
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.RATE_LIMIT = u.RATE_LIMIT self.RATE_LIMIT = u.RATE_LIMIT
self.queue = asyncio.Queue() self.queue = asyncio.Queue()
self.deleting = False self.deleting = False
if u.tasks['auto_del']: if u.tasks['auto_del']:
for channel in u.tasks['auto_del']: for channel in u.tasks['auto_del']:
temp = self.bot.get_channel(channel) temp = self.bot.get_channel(channel)
self.bot.loop.create_task(self.queue_for_deletion(temp)) self.bot.loop.create_task(self.queue_for_deletion(temp))
print('STARTED : auto-deleting in #{}'.format(temp.name)) print('STARTED : auto-deleting in #{}'.format(temp.name))
self.deleting = True self.deleting = True
self.bot.loop.create_task(self.delete()) self.bot.loop.create_task(self.delete())
@cmds.group(aliases=['pru', 'purge', 'pur', 'clear', 'cl'], hidden=True) @cmds.group(aliases=['pru', 'purge', 'pur', 'clear', 'cl'], hidden=True)
@cmds.is_owner() @cmds.is_owner()
async def prune(self, ctx): async def prune(self, ctx):
pass pass
@prune.group(name='user', aliases=['u', 'member', 'm']) @prune.group(name='user', aliases=['u', 'member', 'm'])
async def _prune_user(self, ctx): async def _prune_user(self, ctx):
pass pass
@_prune_user.command(name='channel', aliases=['channels', 'chans', 'chan', 'ch', 'c']) @_prune_user.command(name='channel', aliases=['channels', 'chans', 'chan', 'ch', 'c'])
async def _prune_user_channel(self, ctx, user: d.User, *channels: d.TextChannel): async def _prune_user_channel(self, ctx, user: d.User, *channels: d.TextChannel):
def confirm(r, u): def confirm(r, u):
if u is ctx.author: if u is ctx.author:
if r.emoji == '\N{OCTAGONAL SIGN}': if r.emoji == '\N{OCTAGONAL SIGN}':
raise exc.Abort raise exc.Abort
if r.emoji == '\N{THUMBS UP SIGN}': if r.emoji == '\N{THUMBS UP SIGN}':
return True return True
return False return False
if not channels: if not channels:
channels = [ctx.channel] channels = [ctx.channel]
try: try:
pruning = await ctx.send(f'\N{HOURGLASS} **Pruning** {user.mention}**\'s messages from** {"**,** ".join([channel.mention for channel in channels])} **might take some time.** Proceed, {ctx.author.mention}?') pruning = await ctx.send(f'\N{HOURGLASS} **Pruning** {user.mention}**\'s messages from** {"**,** ".join([channel.mention for channel in channels])} **might take some time.** Proceed, {ctx.author.mention}?')
await pruning.add_reaction('\N{THUMBS UP SIGN}') await pruning.add_reaction('\N{THUMBS UP SIGN}')
await pruning.add_reaction('\N{OCTAGONAL SIGN}') await pruning.add_reaction('\N{OCTAGONAL SIGN}')
await asyncio.sleep(1) await asyncio.sleep(1)
await self.bot.wait_for('reaction_add', check=confirm, timeout=10 * 60) await self.bot.wait_for('reaction_add', check=confirm, timeout=10 * 60)
deleting = await ctx.send(f'\N{WASTEBASKET} **Deleting** {user.mention}**\'s messages...**') deleting = await ctx.send(f'\N{WASTEBASKET} **Deleting** {user.mention}**\'s messages...**')
await asyncio.sleep(1) await asyncio.sleep(1)
c = 0 c = 0
for channel in channels: for channel in channels:
await deleting.edit(content=f'\N{WASTEBASKET} **Deleting** {user.mention}**\'s messages from** {channel.mention}') await deleting.edit(content=f'\N{WASTEBASKET} **Deleting** {user.mention}**\'s messages from** {channel.mention}')
deleted = await channel.purge(check=lambda m: m.author.id == user.id, before=pruning, limit=None) deleted = await channel.purge(check=lambda m: m.author.id == user.id, before=pruning, limit=None)
c += len(deleted) c += len(deleted)
await asyncio.sleep(1) await asyncio.sleep(1)
for channel in channels: for channel in channels:
missed = 0 missed = 0
async for message in channel.history(before=pruning, limit=None): async for message in channel.history(before=pruning, limit=None):
if message.author.id == user.id: if message.author.id == user.id:
missed += 1 missed += 1
if missed > 0: if missed > 0:
await ctx.send(f'\N{DOUBLE EXCLAMATION MARK} `{missed}` **messages were not deleted in** {channel.mention}') await ctx.send(f'\N{DOUBLE EXCLAMATION MARK} `{missed}` **messages were not deleted in** {channel.mention}')
await ctx.send(f'\N{WHITE HEAVY CHECK MARK} **Finished deleting** `{c}` **of** {user.mention}**\'s messages**') await ctx.send(f'\N{WHITE HEAVY CHECK MARK} **Finished deleting** `{c}` **of** {user.mention}**\'s messages**')
except exc.Abort: except exc.Abort:
await ctx.send('**Deletion aborted**', delete_after=7) await ctx.send('**Deletion aborted**', delete_after=7)
await ctx.message.add_reaction('\N{CROSS MARK}') await ctx.message.add_reaction('\N{CROSS MARK}')
except TimeoutError: except TimeoutError:
await ctx.send('**Deletion timed out**', delete_after=7) await ctx.send('**Deletion timed out**', delete_after=7)
await ctx.message.add_reaction('\N{CROSS MARK}') await ctx.message.add_reaction('\N{CROSS MARK}')
@_prune_user.command(name='all', aliases=['a'], brief='Prune a user\'s messages from the guild', description='about flag centers on message 50 of 101 messages\n\npfg \{user id\} [before|after|about] [\{message id\}]\n\nExample:\npfg \{user id\} before \{message id\}', hidden=True) @_prune_user.command(name='all', aliases=['a'], brief='Prune a user\'s messages from the guild', description='about flag centers on message 50 of 101 messages\n\npfg \{user id\} [before|after|about] [\{message id\}]\n\nExample:\npfg \{user id\} before \{message id\}', hidden=True)
@cmds.is_owner() @cmds.is_owner()
async def _prune_user_all(self, ctx, user: d.User): async def _prune_user_all(self, ctx, user: d.User):
def confirm(r, u): def confirm(r, u):
if u is ctx.author: if u is ctx.author:
if r.emoji == '\N{OCTAGONAL SIGN}': if r.emoji == '\N{OCTAGONAL SIGN}':
raise exc.Abort raise exc.Abort
if r.emoji == '\N{THUMBS UP SIGN}': if r.emoji == '\N{THUMBS UP SIGN}':
return True return True
return False return False
try: try:
pruning = await ctx.send(f'\N{HOURGLASS} **Pruning** {user.mention}**\'s messages might take some time.** Proceed, {ctx.author.mention}?') pruning = await ctx.send(f'\N{HOURGLASS} **Pruning** {user.mention}**\'s messages might take some time.** Proceed, {ctx.author.mention}?')
await pruning.add_reaction('\N{THUMBS UP SIGN}') await pruning.add_reaction('\N{THUMBS UP SIGN}')
await pruning.add_reaction('\N{OCTAGONAL SIGN}') await pruning.add_reaction('\N{OCTAGONAL SIGN}')
await asyncio.sleep(1) await asyncio.sleep(1)
await self.bot.wait_for('reaction_add', check=confirm, timeout=10 * 60) await self.bot.wait_for('reaction_add', check=confirm, timeout=10 * 60)
deleting = await ctx.send(f'\N{WASTEBASKET} **Deleting** {user.mention}**\'s messages...**') deleting = await ctx.send(f'\N{WASTEBASKET} **Deleting** {user.mention}**\'s messages...**')
await asyncio.sleep(1) await asyncio.sleep(1)
c = 0 c = 0
for channel in ctx.guild.text_channels: for channel in ctx.guild.text_channels:
await deleting.edit(content=f'\N{WASTEBASKET} **Deleting** {user.mention}**\'s messages from** {channel.mention}') await deleting.edit(content=f'\N{WASTEBASKET} **Deleting** {user.mention}**\'s messages from** {channel.mention}')
deleted = await channel.purge(check=lambda m: m.author.id == user.id, before=pruning, limit=None) deleted = await channel.purge(check=lambda m: m.author.id == user.id, before=pruning, limit=None)
c += len(deleted) c += len(deleted)
await asyncio.sleep(1) await asyncio.sleep(1)
for channel in ctx.guild.text_channels: for channel in ctx.guild.text_channels:
missed = 0 missed = 0
async for message in channel.history(before=pruning, limit=None): async for message in channel.history(before=pruning, limit=None):
if message.author.id == user.id: if message.author.id == user.id:
missed += 1 missed += 1
if missed > 0: if missed > 0:
await ctx.send(f'\N{DOUBLE EXCLAMATION MARK} `{missed}` **messages were not deleted in** {channel.mention}') await ctx.send(f'\N{DOUBLE EXCLAMATION MARK} `{missed}` **messages were not deleted in** {channel.mention}')
await ctx.send(f'\N{WHITE HEAVY CHECK MARK} **Finished deleting** `{c}` **of** {user.mention}**\'s messages**') await ctx.send(f'\N{WHITE HEAVY CHECK MARK} **Finished deleting** `{c}` **of** {user.mention}**\'s messages**')
except exc.Abort: except exc.Abort:
await ctx.send('**Deletion aborted**', delete_after=7) await ctx.send('**Deletion aborted**', delete_after=7)
await ctx.message.add_reaction('\N{CROSS MARK}') await ctx.message.add_reaction('\N{CROSS MARK}')
except TimeoutError: except TimeoutError:
await ctx.send('**Deletion timed out**', delete_after=7) await ctx.send('**Deletion timed out**', delete_after=7)
await ctx.message.add_reaction('\N{CROSS MARK}') await ctx.message.add_reaction('\N{CROSS MARK}')
@cmds.group(aliases=['task', 'tsk']) @cmds.group(aliases=['task', 'tsk'])
async def tasks(self): async def tasks(self):
pass pass
async def delete(self): async def delete(self):
while self.deleting: while self.deleting:
message = await self.queue.get() message = await self.queue.get()
await asyncio.sleep(self.RATE_LIMIT) await asyncio.sleep(self.RATE_LIMIT)
with suppress(err.NotFound): with suppress(err.NotFound):
if not message.pinned: if not message.pinned:
await message.delete() await message.delete()
print('STOPPED : deleting') print('STOPPED : deleting')
async def queue_for_deletion(self, channel): async def queue_for_deletion(self, channel):
def check(msg): def check(msg):
if 'stop d' in msg.content.lower() and msg.channel is channel and msg.author.guild_permissions.administrator: if 'stop d' in msg.content.lower() and msg.channel is channel and msg.author.guild_permissions.administrator:
raise exc.Abort raise exc.Abort
elif msg.channel is channel and not msg.pinned: elif msg.channel is channel and not msg.pinned:
return True return True
return False return False
try: try:
async for message in channel.history(limit=None): async for message in channel.history(limit=None):
if 'stop d' in message.content.lower() and message.author.guild_permissions.administrator: if 'stop d' in message.content.lower() and message.author.guild_permissions.administrator:
raise exc.Abort raise exc.Abort
if not message.pinned: if not message.pinned:
await self.queue.put(message) await self.queue.put(message)
while not self.bot.is_closed(): while not self.bot.is_closed():
message = await self.bot.wait_for('message', check=check) message = await self.bot.wait_for('message', check=check)
await self.queue.put(message) await self.queue.put(message)
except exc.Abort: except exc.Abort:
u.tasks['auto_del'].remove(channel.id) u.tasks['auto_del'].remove(channel.id)
u.dump(u.tasks, 'cogs/tasks.pkl') u.dump(u.tasks, 'cogs/tasks.pkl')
if not u.tasks['auto_del']: if not u.tasks['auto_del']:
self.deleting = False self.deleting = False
print('STOPPED : deleting #{}'.format(channel.name)) print('STOPPED : deleting #{}'.format(channel.name))
await channel.send('**Stopped queueing messages for deletion in** {}'.format(channel.mention), delete_after=5) await channel.send('**Stopped queueing messages for deletion in** {}'.format(channel.mention), delete_after=5)
@cmds.command(name='autodelete', aliases=['autodel']) @cmds.command(name='autodelete', aliases=['autodel'])
@cmds.has_permissions(administrator=True) @cmds.has_permissions(administrator=True)
async def auto_delete(self, ctx): async def auto_delete(self, ctx):
try: try:
if ctx.channel.id not in u.tasks['auto_del']: if ctx.channel.id not in u.tasks['auto_del']:
u.tasks['auto_del'].append(ctx.channel.id) u.tasks['auto_del'].append(ctx.channel.id)
u.dump(u.tasks, 'cogs/tasks.pkl') u.dump(u.tasks, 'cogs/tasks.pkl')
self.bot.loop.create_task(self.queue_for_deletion(ctx.channel)) self.bot.loop.create_task(self.queue_for_deletion(ctx.channel))
if not self.deleting: if not self.deleting:
self.bot.loop.create_task(self.delete()) self.bot.loop.create_task(self.delete())
self.deleting = True self.deleting = True
print('STARTED : auto-deleting in #{}'.format(ctx.channel.name)) print('STARTED : auto-deleting in #{}'.format(ctx.channel.name))
await ctx.send('**Auto-deleting all messages in {}**'.format(ctx.channel.mention), delete_after=5) await ctx.send('**Auto-deleting all messages in {}**'.format(ctx.channel.mention), delete_after=5)
else: else:
raise exc.Exists raise exc.Exists
except exc.Exists: except exc.Exists:
await ctx.send('**Already auto-deleting in {}.** Type `stop d(eleting)` to stop.'.format(ctx.channel.mention), delete_after=7) await ctx.send('**Already auto-deleting in {}.** Type `stop d(eleting)` to stop.'.format(ctx.channel.mention), delete_after=7)
await ctx.message.add_reaction('\N{CROSS MARK}') await ctx.message.add_reaction('\N{CROSS MARK}')
@cmds.group(aliases=['setting', 'set', 's']) @cmds.group(aliases=['setting', 'set', 's'])
@cmds.has_permissions(administrator=True) @cmds.has_permissions(administrator=True)
async def settings(self, ctx): async def settings(self, ctx):
pass pass
@settings.command(name='deletecommands', aliases=['delcmds', 'delcmd']) @settings.command(name='deletecommands', aliases=['delcmds', 'delcmd'])
async def _settings_deletecommands(self, ctx): async def _settings_deletecommands(self, ctx):
if ctx.guild.id not in u.settings['del_ctx']: if ctx.guild.id not in u.settings['del_ctx']:
u.settings['del_ctx'].append(ctx.guild.id) u.settings['del_ctx'].append(ctx.guild.id)
else: else:
u.settings['del_ctx'].remove(ctx.guild.id) u.settings['del_ctx'].remove(ctx.guild.id)
u.dump(u.settings, 'settings.pkl') u.dump(u.settings, 'settings.pkl')
await ctx.send('**Delete command invocations:** `{}`'.format(ctx.guild.id in u.settings['del_ctx'])) await ctx.send('**Delete command invocations:** `{}`'.format(ctx.guild.id in u.settings['del_ctx']))
@settings.command(name='prefix', aliases=['pre', 'p']) @settings.command(name='prefix', aliases=['pre', 'p'])
async def _settings_prefix(self, ctx, *prefixes): async def _settings_prefix(self, ctx, *prefixes):
if prefixes: if prefixes:
u.settings['prefixes'][ctx.guild.id] = prefixes u.settings['prefixes'][ctx.guild.id] = prefixes
else: else:
with suppress(KeyError): with suppress(KeyError):
del u.settings['prefixes'][ctx.guild.id] del u.settings['prefixes'][ctx.guild.id]
await ctx.send(f'**Prefix set to:** `{"` or `".join(prefixes if ctx.guild.id in u.settings["prefixes"] else u.config["prefix"])}`') await ctx.send(f'**Prefix set to:** `{"` or `".join(prefixes if ctx.guild.id in u.settings["prefixes"] else u.config["prefix"])}`')
@settings.command(name='deleteresponses', aliases=['delresps', 'delresp']) @settings.command(name='deleteresponses', aliases=['delresps', 'delresp'])
async def _settings_deleteresponses(self, ctx): async def _settings_deleteresponses(self, ctx):
if ctx.guild.id not in u.settings['del_resp']: if ctx.guild.id not in u.settings['del_resp']:
u.settings['del_resp'].append(ctx.guild.id) u.settings['del_resp'].append(ctx.guild.id)
else: else:
u.settings['del_resp'].remove(ctx.guild.id) u.settings['del_resp'].remove(ctx.guild.id)
u.dump(u.settings, 'settings.pkl') u.dump(u.settings, 'settings.pkl')
await ctx.send(f'**Delete command responses:** `{ctx.guild.id in u.settings["del_resp"]}`') await ctx.send(f'**Delete command responses:** `{ctx.guild.id in u.settings["del_resp"]}`')

View file

@ -1,266 +1,272 @@
import asyncio import asyncio
from datetime import datetime as dt from datetime import datetime as dt
import json import json
import logging as log import logging as log
import subprocess import subprocess
import sys import sys
import traceback as tb import traceback as tb
from contextlib import suppress from contextlib import suppress
from pprint import pprint from pprint import pprint
from hurry.filesize import size, alternative from hurry.filesize import size, alternative
from urllib.parse import urlparse from urllib.parse import urlparse
import discord as d import discord as d
from discord import errors as err from discord import errors as err
from discord import utils from discord import utils
from discord.ext import commands as cmds from discord.ext import commands as cmds
from discord.ext.commands import errors as errext from discord.ext.commands import errors as errext
from misc import exceptions as exc from misc import exceptions as exc
from misc import checks from misc import checks
from utils import utils as u from utils import utils as u
log.basicConfig(level=log.WARNING) log.basicConfig(level=log.WARNING)
# class HelpFormatter(cmds.HelpFormatter): # class HelpFormatter(cmds.HelpFormatter):
# #
# async def format(self): # async def format(self):
# self._paginator = cmds.Paginator() # self._paginator = cmds.Paginator()
# #
# # we need a padding of ~80 or so # # we need a padding of ~80 or so
# #
# description = self.command.description if not self.is_cog() else inspect.getdoc(self.command) # description = self.command.description if not self.is_cog() else inspect.getdoc(self.command)
# #
# if description: # if description:
# # <description> portion # # <description> portion
# self._paginator.add_line(description, empty=True) # self._paginator.add_line(description, empty=True)
# #
# if isinstance(self.command, cmds.Command): # if isinstance(self.command, cmds.Command):
# # <signature portion> # # <signature portion>
# signature = self.get_command_signature() # signature = self.get_command_signature()
# self._paginator.add_line(signature, empty=True) # self._paginator.add_line(signature, empty=True)
# #
# # <long doc> section # # <long doc> section
# if self.command.help: # if self.command.help:
# self._paginator.add_line(self.command.help, empty=True) # self._paginator.add_line(self.command.help, empty=True)
# #
# # end it here if it's just a regular command # # end it here if it's just a regular command
# if not self.has_subcommands(): # if not self.has_subcommands():
# self._paginator.close_page() # self._paginator.close_page()
# return self._paginator.pages # return self._paginator.pages
# #
# max_width = self.max_name_size # max_width = self.max_name_size
def get_prefix(bot, message): def get_prefix(bot, message):
with suppress(AttributeError): with suppress(AttributeError):
return u.settings['prefixes'].get(message.guild.id, u.config['prefix']) return u.settings['prefixes'].get(message.guild.id, u.config['prefix'])
return u.config['prefix'] return u.config['prefix']
bot = cmds.Bot(command_prefix=get_prefix, self_bot=u.config['selfbot'], formatter=cmds.HelpFormatter(show_check_failure=True), description='Modufur - A booru bot with a side of management and automated tasking\nMade by @Myned#3985\n\nNSFW for Not Safe For Wumpus commands\n(G) for group commands\n@permission@ for required permissions\n!notice! for important information\np for prefix\n\n\{\} for mandatory argument\n[] for optional argument\n... for one or more arguments', help_attrs={'aliases': ['h']}, pm_help=None) bot = cmds.Bot(command_prefix=get_prefix, self_bot=u.config['selfbot'], formatter=cmds.HelpFormatter(show_check_failure=True), description='Modufur - A booru bot with a side of management and automated tasking\nMade by @Myned#3985\n\nNSFW for Not Safe For Wumpus commands\n(G) for group commands\n@permission@ for required permissions\n!notice! for important information\np for prefix\n\n\{\} for mandatory argument\n[] for optional argument\n... for one or more arguments', help_attrs={'aliases': ['h']}, pm_help=None)
@bot.command(help='help', brief='brief', description='description', usage='usage', hidden=True) @bot.command(help='help', brief='brief', description='description', usage='usage', hidden=True)
async def test(ctx): async def test(ctx):
await ctx.send('test') await ctx.send('test')
# Send and print ready message to #testing and console after logon # Send and print ready message to #testing and console after logon
@bot.event @bot.event
async def on_ready(): async def on_ready():
if not checks.ready: if not checks.ready:
# d.opus.load_opus('opuslib') # d.opus.load_opus('opuslib')
from cogs import booru, info, management, owner, tools from cogs import booru, info, management, owner, tools
for cog in (tools.Utils(bot), owner.Bot(bot), owner.Tools(bot), management.Administration(bot), info.Info(bot), booru.MsG(bot)): for cog in (tools.Utils(bot), owner.Bot(bot), owner.Tools(bot), management.Administration(bot), info.Info(bot), booru.MsG(bot)):
bot.add_cog(cog) bot.add_cog(cog)
print(f'COG : {type(cog).__name__}') print(f'COG : {type(cog).__name__}')
# bot.loop.create_task(u.clear(booru.temp_urls, 30*60)) # bot.loop.create_task(u.clear(booru.temp_urls, 30*60))
if u.config['playing'] is not '': if u.config['playing'] is not '':
await bot.change_presence(game=d.Game(name=u.config['playing'])) await bot.change_presence(game=d.Game(name=u.config['playing']))
print('\n> > > > > > > > >\nC O N N E C T E D : {}\n> > > > > > > > >\n'.format(bot.user.name)) print('\n> > > > > > > > >\nC O N N E C T E D : {}\n> > > > > > > > >\n'.format(bot.user.name))
await bot.get_channel(u.config['info_channel']).send(f'**Started** \N{BLACK SUN WITH RAYS} `{"` or `".join(u.config["prefix"])}`') await bot.get_channel(u.config['info_channel']).send(f'**Started** \N{BLACK SUN WITH RAYS} `{"` or `".join(u.config["prefix"])}`')
# u.notify('C O N N E C T E D') # u.notify('C O N N E C T E D')
if u.temp['startup']: if u.temp['startup']:
with suppress(err.NotFound): with suppress(err.NotFound):
if u.temp['startup'][0] == 'guild': if u.temp['startup'][0] == 'guild':
dest = bot.get_channel(u.temp['startup'][1]) dest = bot.get_channel(u.temp['startup'][1])
else: else:
dest = bot.get_user(u.temp['startup'][1]) dest = bot.get_user(u.temp['startup'][1])
message = await dest.get_message(u.temp['startup'][2]) message = await dest.get_message(u.temp['startup'][2])
await message.add_reaction('\N{WHITE HEAVY CHECK MARK}') await message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
u.temp['startup'] = () u.temp['startup'] = ()
u.dump(u.temp, 'temp/temp.pkl') u.dump(u.temp, 'temp/temp.pkl')
checks.ready = True checks.ready = True
else: else:
print('\n- - - -\nI N F O : reconnected, skipping initialization\n- - - -') print('\n- - - -\nI N F O : reconnected, reinitializing\n- - - -')
for cog in (tools.Utils(bot), owner.Bot(bot), owner.Tools(bot), management.Administration(bot), info.Info(bot), booru.MsG(bot)):
@bot.event bot.add_cog(cog)
async def on_message(message): print(f'COG : {type(cog).__name__}')
if not u.config['selfbot']:
if message.author is not bot.user and not message.author.bot: if u.config['playing'] is not '':
await bot.process_commands(message) await bot.change_presence(game=d.Game(name=u.config['playing']))
else:
if not message.author.bot:
await bot.process_commands(message) @bot.event
async def on_message(message):
if not u.config['selfbot']:
@bot.event if message.author is not bot.user and not message.author.bot:
async def on_error(error, *args, **kwargs): await bot.process_commands(message)
print('\n! ! ! ! !\nE R R O R : {}\n! ! ! ! !\n'.format(error), file=sys.stderr) else:
tb.print_exc() if not message.author.bot:
await bot.get_user(u.config['owner_id']).send('**ERROR** \N{WARNING SIGN}\n```\n{}```'.format(error)) await bot.process_commands(message)
await bot.get_channel(u.config['info_channel']).send('**ERROR** \N{WARNING SIGN}\n```\n{}```'.format(error))
if u.temp['startup']: @bot.event
with suppress(err.NotFound): async def on_error(error, *args, **kwargs):
if u.temp['startup'][0] == 'guild': print('\n! ! ! ! !\nE R R O R : {}\n! ! ! ! !\n'.format(error), file=sys.stderr)
dest = bot.get_channel(u.temp['startup'][1]) tb.print_exc()
else: await bot.get_user(u.config['owner_id']).send('**ERROR** \N{WARNING SIGN}\n```\n{}```'.format(error))
dest = bot.get_user(u.temp['startup'][1]) await bot.get_channel(u.config['info_channel']).send('**ERROR** \N{WARNING SIGN}\n```\n{}```'.format(error))
message = await dest.get_message(u.temp['startup'][2])
if u.temp['startup']:
await message.add_reaction('\N{WARNING SIGN}') with suppress(err.NotFound):
if u.temp['startup'][0] == 'guild':
u.temp.clear() dest = bot.get_channel(u.temp['startup'][1])
u.dump(u.temp, 'temp/temp.pkl') else:
# u.notify('E R R O R') dest = bot.get_user(u.temp['startup'][1])
await bot.logout() message = await dest.get_message(u.temp['startup'][2])
u.close(bot.loop)
await message.add_reaction('\N{WARNING SIGN}')
@bot.event u.temp.clear()
async def on_command_error(ctx, error): u.dump(u.temp, 'temp/temp.pkl')
if isinstance(error, err.NotFound): # u.notify('E R R O R')
print('NOT FOUND') await bot.logout()
elif isinstance(error, errext.MissingRequiredArgument):
await ctx.send('**Missing required argument**', delete_after=7)
await ctx.message.add_reaction('\N{CROSS MARK}') @bot.event
elif isinstance(error, errext.BadArgument): async def on_command_error(ctx, error):
await ctx.send(f'**Invalid argument.** {error}', delete_after=7) if isinstance(error, err.NotFound):
await ctx.message.add_reaction('\N{CROSS MARK}') print('NOT FOUND')
elif isinstance(error, errext.CheckFailure): elif isinstance(error, errext.MissingRequiredArgument):
await ctx.send('**Insufficient permissions**', delete_after=7) await ctx.send('**Missing required argument**', delete_after=7)
await ctx.message.add_reaction('\N{NO ENTRY}') await ctx.message.add_reaction('\N{CROSS MARK}')
elif isinstance(error, errext.CommandNotFound): elif isinstance(error, errext.BadArgument):
print('INVALID COMMAND : {}'.format(error), file=sys.stderr) await ctx.send(f'**Invalid argument.** {error}', delete_after=7)
await ctx.message.add_reaction('\N{BLACK QUESTION MARK ORNAMENT}') await ctx.message.add_reaction('\N{CROSS MARK}')
else: elif isinstance(error, errext.CheckFailure):
print('\n! ! ! ! ! ! ! ! ! ! ! !\nC O M M A N D E R R O R : {}\n! ! ! ! ! ! ! ! ! ! ! !\n'.format( await ctx.send('**Insufficient permissions**', delete_after=7)
error), file=sys.stderr) await ctx.message.add_reaction('\N{NO ENTRY}')
tb.print_exception(type(error), error, error.__traceback__, file=sys.stderr) elif isinstance(error, errext.CommandNotFound):
await bot.get_user(u.config['owner_id']).send('**COMMAND ERROR** \N{WARNING SIGN} `{}` from {} in {}\n```\n{}```'.format(ctx.message.content, ctx.author.mention, ctx.channel.mention, ''.join(tb.format_exception(type(error), error, error.__traceback__ if len(str(error.__traceback__)) < 1500 else str(error.__traceback__)[:1500])))) print('INVALID COMMAND : {}'.format(error), file=sys.stderr)
await bot.get_channel(u.config['info_channel']).send('**COMMAND ERROR** \N{WARNING SIGN} `{}` from {} in {}\n```\n{}```'.format(ctx.message.content, ctx.author.mention, ctx.channel.mention, error)) await ctx.message.add_reaction('\N{BLACK QUESTION MARK ORNAMENT}')
await exc.send_error(ctx, error) else:
await ctx.message.add_reaction('\N{WARNING SIGN}') print('\n! ! ! ! ! ! ! ! ! ! ! !\nC O M M A N D E R R O R : {}\n! ! ! ! ! ! ! ! ! ! ! !\n'.format(
# u.notify('C O M M A N D E R R O R') error), file=sys.stderr)
tb.print_exception(type(error), error, error.__traceback__, file=sys.stderr)
# @bot.event await bot.get_user(u.config['owner_id']).send('**COMMAND ERROR** \N{WARNING SIGN} `{}` from {} in {}\n```\n{}```'.format(ctx.message.content, ctx.author.mention, ctx.channel.mention, ''.join(tb.format_exception(type(error), error, error.__traceback__ if len(str(error.__traceback__)) < 1500 else str(error.__traceback__)[:1500]))))
# async def on_command(ctx): await bot.get_channel(u.config['info_channel']).send('**COMMAND ERROR** \N{WARNING SIGN} `{}` from {} in {}\n```\n{}```'.format(ctx.message.content, ctx.author.mention, ctx.channel.mention, error))
# if ctx.guild.id in u.settings['del_resp']: await exc.send_error(ctx, error)
# pass await ctx.message.add_reaction('\N{WARNING SIGN}')
# u.notify('C O M M A N D E R R O R')
@bot.event
async def on_command_completion(ctx): # @bot.event
with suppress(err.NotFound): # async def on_command(ctx):
with suppress(AttributeError): # if ctx.guild.id in u.settings['del_resp']:
if ctx.guild.id in u.settings['del_ctx'] and ctx.me.permissions_in(ctx.channel).manage_messages and isinstance(ctx.message.channel, d.TextChannel): # pass
await ctx.message.delete()
@bot.event
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}') async def on_command_completion(ctx):
with suppress(err.NotFound):
for command in ('lastcommand', ',restart', ',die'): with suppress(AttributeError):
if ctx.command.name == command: if ctx.guild.id in u.settings['del_ctx'] and ctx.me.permissions_in(ctx.channel).manage_messages and isinstance(ctx.message.channel, d.TextChannel):
return await ctx.message.delete()
u.last_commands[ctx.author.id] = ctx await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
@bot.event for command in ('lastcommand', ',restart', ',die'):
async def on_guild_remove(guild): if ctx.command.name == command:
print(f'LEFT : {guild.name}') return
for task, idents in u.tasks.items(): u.last_commands[ctx.author.id] = ctx
for channel in guild.channels:
if channel.id in idents: @bot.event
idents.remove(channel.id) async def on_guild_remove(guild):
print(f'STOPPED : {task} in #{channel.id}') print(f'LEFT : {guild.name}')
u.dump(u.tasks, 'cogs/tasks.pkl')
for task, idents in u.tasks.items():
for channel in guild.channels:
async def wait(voice): if channel.id in idents:
asyncio.sleep(5) idents.remove(channel.id)
await voice.disconnect() print(f'STOPPED : {task} in #{channel.id}')
u.dump(u.tasks, 'cogs/tasks.pkl')
def after(voice, error):
coro = voice.disconnect() async def wait(voice):
future = asyncio.run_coroutine_threadsafe(coro, voice.loop) asyncio.sleep(5)
future.result() await voice.disconnect()
# suggested = u.setdefault('cogs/suggested.pkl', {'last_update': 'None', 'tags': {}, 'total': 0})
@bot.command(name=',test', hidden=True) def after(voice, error):
@cmds.is_owner() coro = voice.disconnect()
async def test(ctx): future = asyncio.run_coroutine_threadsafe(coro, voice.loop)
post = await u.fetch('https://e621.net/post/show.json?id=1145042', json=True) future.result()
tags = [] # suggested = u.setdefault('cogs/suggested.pkl', {'last_update': 'None', 'tags': {}, 'total': 0})
if post['tags']: @bot.command(name=',test', hidden=True)
temptags = post['tags'].split(' ') @cmds.is_owner()
cis = [] async def test(ctx):
for tag in suggested: post = await u.fetch('https://e621.net/post/show.json?id=1145042', json=True)
pass
for tag in temptags: tags = []
tags.append(f'[{tag}](https://e621.net/post?tags={tag})') if post['tags']:
# tags = ' '.join(tags) temptags = post['tags'].split(' ')
else: cis = []
tags = 'None' for tag in suggested:
pass
if post['description']: for tag in temptags:
post_description = post['description'] if len(post['description']) < 200 else f'{post["description"][:200]}...' tags.append(f'[{tag}](https://e621.net/post?tags={tag})')
else: # tags = ' '.join(tags)
post_description = 'None' else:
tags = 'None'
title = ', '.join(post['artist'])
description = f'posted by: *[{post["author"]}](https://e621.net/post?tags=user:{post["author"]})*' if post['description']:
url = f'https://e621.net/post?tags={",".join(post["artist"])}' post_description = post['description'] if len(post['description']) < 200 else f'{post["description"][:200]}...'
# timestamp = dt.utcnow() else:
color = ctx.me.color post_description = 'None'
footer = {'text': post['score'], 'icon_url': 'https://images-ext-1.discordapp.net/external/W2k0ZzhU7ngvN_-CdqAa3H3FmkfCNYQTxPG_DsvacB4/https/emojipedia-us.s3.amazonaws.com/thumbs/320/twitter/103/sparkles_2728.png'}
# image = 'https://e621.net/post/show/54360' title = ', '.join(post['artist'])
thumbnail = post['file_url'] description = f'posted by: *[{post["author"]}](https://e621.net/post?tags=user:{post["author"]})*'
author = {'name': post['id'], 'url': f'https://e621.net/post/show/{post["id"]}', 'icon_url': ctx.author.avatar_url} url = f'https://e621.net/post?tags={",".join(post["artist"])}'
# timestamp = dt.utcnow()
fields = [] color = ctx.me.color
names = ('File', 'Sources', 'Description', 'tags', 'tags (ext.)') footer = {'text': post['score'], 'icon_url': 'https://images-ext-1.discordapp.net/external/W2k0ZzhU7ngvN_-CdqAa3H3FmkfCNYQTxPG_DsvacB4/https/emojipedia-us.s3.amazonaws.com/thumbs/320/twitter/103/sparkles_2728.png'}
values = (f'[{post["md5"]}]({post["file_url"]}) | [{post["file_ext"]}](https://e621.net/post?tags=type:{post["file_ext"]})\n\n**Size** [{size(post["file_size"], system=alternative)}](https://e621.net/post?tags=filesize:{post["file_size"]})\n**Resolution** [{post["width"]} x {post["height"]}](https://e621.net/post?tags=width:{post["width"]},height:{post["height"]}) | [{u.get_aspectratio(post["width"], post["height"])}](https://e621.net/post?tags=ratio:{post["width"]/post["height"]:.2f})', '\n'.join([f'[{urlparse(source).netloc}]({source})' for source in post['sources']]), post_description, ' '.join(tags[:20]), ' '.join(tags[20:])) # image = 'https://e621.net/post/show/54360'
inlines = (False, False, False, True, True) thumbnail = post['file_url']
for name, value, inline in zip(names, values, inlines): author = {'name': post['id'], 'url': f'https://e621.net/post/show/{post["id"]}', 'icon_url': ctx.author.avatar_url}
fields.append({'name': name, 'value': value, 'inline': inline})
fields = []
embed = u.generate_embed(ctx, title=title, description=description, url=url, colour=color, footer=footer, thumbnail=thumbnail, author=author, fields=fields) names = ('File', 'Sources', 'Description', 'tags', 'tags (ext.)')
values = (f'[{post["md5"]}]({post["file_url"]}) | [{post["file_ext"]}](https://e621.net/post?tags=type:{post["file_ext"]})\n\n**Size** [{size(post["file_size"], system=alternative)}](https://e621.net/post?tags=filesize:{post["file_size"]})\n**Resolution** [{post["width"]} x {post["height"]}](https://e621.net/post?tags=width:{post["width"]},height:{post["height"]}) | [{u.get_aspectratio(post["width"], post["height"])}](https://e621.net/post?tags=ratio:{post["width"]/post["height"]:.2f})', '\n'.join([f'[{urlparse(source).netloc}]({source})' for source in post['sources']]), post_description, ' '.join(tags[:20]), ' '.join(tags[20:]))
await ctx.send(embed=embed) inlines = (False, False, False, True, True)
# print(ctx.args) for name, value, inline in zip(names, values, inlines):
# print(ctx.kwargs) fields.append({'name': name, 'value': value, 'inline': inline})
# if '<:N_:368917475531816962>' in message:
# await ctx.send('<:N_:368917475531816962>') embed = u.generate_embed(ctx, title=title, description=description, url=url, colour=color, footer=footer, thumbnail=thumbnail, author=author, fields=fields)
# logs = []
# async for entry in ctx.guild.audit_logs(limit=None, action=d.AuditLogAction.message_delete): await ctx.send(embed=embed)
# logs.append( # print(ctx.args)
# f'@{entry.user.name} deleted {entry.extra.count} messages from @{entry.target.name} in #{entry.extra.channel.name}') # print(ctx.kwargs)
# pprint(logs) # if '<:N_:368917475531816962>' in message:
# channel = bot.get_channel(int(cid)) # await ctx.send('<:N_:368917475531816962>')
# voice = await channel.connect() # logs = []
# voice.play(d.AudioSource, after=lambda: after(voice)) # async for entry in ctx.guild.audit_logs(limit=None, action=d.AuditLogAction.message_delete):
# logs.append(
bot.run(u.config['token'], bot=not u.config['selfbot']) # f'@{entry.user.name} deleted {entry.extra.count} messages from @{entry.target.name} in #{entry.extra.channel.name}')
# pprint(logs)
# channel = bot.get_channel(int(cid))
# voice = await channel.connect()
# voice.play(d.AudioSource, after=lambda: after(voice))
bot.run(u.config['token'], bot=not u.config['selfbot'])

View file

@ -1,191 +1,191 @@
import asyncio import asyncio
import json as jsn import json as jsn
import os import os
import pickle as pkl import pickle as pkl
import subprocess import subprocess
from contextlib import suppress from contextlib import suppress
from fractions import gcd from fractions import gcd
import math import math
import gmusicapi as gpm import gmusicapi as gpm
import aiohttp import aiohttp
import discord as d import discord as d
from misc import exceptions as exc from misc import exceptions as exc
# from pync import Notifier # from pync import Notifier
print('\nPID : {}\n'.format(os.getpid())) print('\nPID : {}\n'.format(os.getpid()))
# def notify(message): # def notify(message):
# subprocess.run(['terminal-notifier', '-message', message, '-title', # subprocess.run(['terminal-notifier', '-message', message, '-title',
# 'Modumind', '-activate', 'com.apple.Terminal', '-appIcon', 'icon.png', '-sound', 'Ping'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) # 'Modumind', '-activate', 'com.apple.Terminal', '-appIcon', 'icon.png', '-sound', 'Ping'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
try: try:
with open('config.json') as infile: with open('config.json') as infile:
config = jsn.load(infile) config = jsn.load(infile)
print('LOADED : config.json') print('LOADED : config.json')
except FileNotFoundError: except FileNotFoundError:
with open('config.json', 'w') as outfile: with open('config.json', 'w') as outfile:
jsn.dump({'client_id': 0, 'info_channel': 0, 'owner_id': 0, 'permissions': 126016, jsn.dump({'client_id': 0, 'info_channel': 0, 'owner_id': 0, 'permissions': 126016,
'playing': 'a game', 'prefix': [',', 'm,'], 'selfbot': False, 'token': 'str'}, outfile, indent=4, sort_keys=True) 'playing': 'a game', 'prefix': [',', 'm,'], 'selfbot': False, 'token': 'str'}, outfile, indent=4, sort_keys=True)
print('FILE NOT FOUND : config.json created with abstract values. Restart run.py with correct values') print('FILE NOT FOUND : config.json created with abstract values. Restart run.py with correct values')
def setdefault(filename, default=None, json=False): def setdefault(filename, default=None, json=False):
if json: if json:
try: try:
with open(filename, 'r') as infile: with open(filename, 'r') as infile:
print(f'LOADED : {filename}') print(f'LOADED : {filename}')
return jsn.load(infile) return jsn.load(infile)
except FileNotFoundError: except FileNotFoundError:
with open(filename, 'w+') as iofile: with open(filename, 'w+') as iofile:
print(f'FILE NOT FOUND : {filename} created and loaded with default values') print(f'FILE NOT FOUND : {filename} created and loaded with default values')
jsn.dump(default, iofile) jsn.dump(default, iofile)
iofile.seek(0) iofile.seek(0)
return jsn.load(iofile) return jsn.load(iofile)
else: else:
try: try:
with open(filename, 'rb') as infile: with open(filename, 'rb') as infile:
print(f'LOADED : {filename}') print(f'LOADED : {filename}')
return pkl.load(infile) return pkl.load(infile)
except FileNotFoundError: except FileNotFoundError:
with open(filename, 'wb+') as iofile: with open(filename, 'wb+') as iofile:
print(f'FILE NOT FOUND : {filename} created and loaded with default values') print(f'FILE NOT FOUND : {filename} created and loaded with default values')
pkl.dump(default, iofile) pkl.dump(default, iofile)
iofile.seek(0) iofile.seek(0)
return pkl.load(iofile) return pkl.load(iofile)
def load(filename, *, json=False): def load(filename, *, json=False):
if not json: if not json:
with open(filename, 'rb') as infile: with open(filename, 'rb') as infile:
return pkl.load(infile) return pkl.load(infile)
else: else:
with open(filename) as infile: with open(filename) as infile:
return jsn.load(infile) return jsn.load(infile)
def dump(obj, filename, *, json=False): def dump(obj, filename, *, json=False):
if not json: if not json:
with open(filename, 'wb') as outfile: with open(filename, 'wb') as outfile:
pkl.dump(obj, outfile) pkl.dump(obj, outfile)
else: else:
with open(filename, 'w') as outfile: with open(filename, 'w') as outfile:
jsn.dump(obj, outfile, indent=4, sort_keys=True) jsn.dump(obj, outfile, indent=4, sort_keys=True)
settings = setdefault('misc/settings.pkl', default={'del_ctx': [], 'del_resp': [], 'prefixes': {}}) settings = setdefault('misc/settings.pkl', default={'del_ctx': [], 'del_resp': [], 'prefixes': {}})
tasks = setdefault('cogs/tasks.pkl', default={'auto_del': [], 'auto_hrt': [], 'auto_rev': [], 'periodic_gpm': []}) tasks = setdefault('cogs/tasks.pkl', default={'auto_del': [], 'auto_hrt': [], 'auto_rev': [], 'periodic_gpm': []})
temp = setdefault('temp/temp.pkl', default={'startup': ()}) temp = setdefault('temp/temp.pkl', default={'startup': ()})
secrets = setdefault('secrets.json', default={'client_secrets': {'client_id': '', 'client_secret': ''}}, json=True) secrets = setdefault('secrets.json', default={'client_secrets': {'client_id': '', 'client_secret': ''}}, json=True)
RATE_LIMIT = 2.2 RATE_LIMIT = 2.2
color = d.Color(0x1A1A1A) color = d.Color(0x1A1A1A)
session = aiohttp.ClientSession() session = aiohttp.ClientSession()
last_commands = {} last_commands = {}
async def fetch(url, *, params={}, json=False, response=False): async def fetch(url, *, params={}, json=False, response=False):
async with session.get(url, params=params, headers={'User-Agent': 'Myned/Modufur'}) as r: async with session.get(url, params=params, headers={'User-Agent': 'Myned/Modufur'}) as r:
if response: if response:
return r return r
elif json: elif json:
return await r.json() return await r.json()
return await r.read() return await r.read()
# async def clear(obj, interval=10 * 60, replace=None): # async def clear(obj, interval=10 * 60, replace=None):
# if replace is None: # if replace is None:
# if type(obj) is list: # if type(obj) is list:
# replace = [] # replace = []
# elif type(obj) is dict: # elif type(obj) is dict:
# replace = {} # replace = {}
# elif type(obj) is int: # elif type(obj) is int:
# replace = 0 # replace = 0
# elif type(obj) is str: # elif type(obj) is str:
# replace = '' # replace = ''
# #
# while True: # while True:
# obj = replace # obj = replace
# asyncio.sleep(interval) # asyncio.sleep(interval)
def close(loop): def close(loop):
if session: if session:
session.close() session.close()
loop.stop() loop.stop()
pending = asyncio.Task.all_tasks() pending = asyncio.Task.all_tasks()
for task in pending: for task in pending:
task.cancel() task.cancel()
# with suppress(asyncio.CancelledError): # with suppress(asyncio.CancelledError):
# loop.run_until_complete(task) # loop.run_until_complete(task)
# loop.close() # loop.close()
print('Finished cancelling tasks.') print('Finished cancelling tasks.')
def generate_embed(ctx, *, title=d.Embed.Empty, kind='rich', description=d.Embed.Empty, url=d.Embed.Empty, timestamp=d.Embed.Empty, colour=color, footer={}, image=d.Embed.Empty, thumbnail=d.Embed.Empty, author={}, fields=[]): def generate_embed(ctx, *, title=d.Embed.Empty, kind='rich', description=d.Embed.Empty, url=d.Embed.Empty, timestamp=d.Embed.Empty, colour=color, footer={}, image=d.Embed.Empty, thumbnail=d.Embed.Empty, author={}, fields=[]):
embed = d.Embed(title=title, type=kind, description=description, url=url, timestamp=timestamp, colour=colour if isinstance(ctx.channel, d.TextChannel) else color) embed = d.Embed(title=title, type=kind, description=description, url=url, timestamp=timestamp, colour=colour if isinstance(ctx.channel, d.TextChannel) else color)
if footer: if footer:
embed.set_footer(text=footer.get('text', d.Embed.Empty), icon_url=footer.get('icon_url', d.Embed.Empty)) embed.set_footer(text=footer.get('text', d.Embed.Empty), icon_url=footer.get('icon_url', d.Embed.Empty))
if image: if image:
embed.set_image(url=image) embed.set_image(url=image)
if thumbnail: if thumbnail:
embed.set_thumbnail(url=thumbnail) embed.set_thumbnail(url=thumbnail)
if author: if author:
embed.set_author(name=author.get('name', d.Embed.Empty), url=author.get('url', d.Embed.Empty), icon_url=author.get('icon_url', d.Embed.Empty)) embed.set_author(name=author.get('name', d.Embed.Empty), url=author.get('url', d.Embed.Empty), icon_url=author.get('icon_url', d.Embed.Empty))
for field in fields: for field in fields:
embed.add_field(name=field.get('name', d.Embed.Empty), value=field.get('value', d.Embed.Empty), inline=field.get('inline', True)) embed.add_field(name=field.get('name', d.Embed.Empty), value=field.get('value', d.Embed.Empty), inline=field.get('inline', True))
return embed return embed
def get_kwargs(ctx, args, *, limit=False): def get_kwargs(ctx, args, *, limit=False):
destination = ctx destination = ctx
remaining = list(args[:]) remaining = list(args[:])
rm = False rm = False
lim = 1 lim = 1
for flag in ('-d', '-dm'): for flag in ('-d', '-dm'):
if flag in remaining: if flag in remaining:
destination = ctx.author destination = ctx.author
remaining.remove(flag) remaining.remove(flag)
for flag in ('-r', '-rm', '-remove', '-re', '-repl', '-replace'): for flag in ('-r', '-rm', '-remove', '-re', '-repl', '-replace'):
if flag in remaining and ctx.author.permissions_in(ctx.channel).manage_messages: if flag in remaining and ctx.author.permissions_in(ctx.channel).manage_messages:
rm = True rm = True
remaining.remove(flag) remaining.remove(flag)
if limit: if limit:
for arg in remaining: for arg in remaining:
if arg.isdigit(): if arg.isdigit():
if 1 <= int(arg) <= limit: if 1 <= int(arg) <= limit:
lim = int(arg) lim = int(arg)
remaining.remove(arg) remaining.remove(arg)
break break
else: else:
raise exc.BoundsError(arg) raise exc.BoundsError(arg)
return {'destination': destination, 'remaining': remaining, 'remove': rm, 'limit': lim} return {'destination': destination, 'remaining': remaining, 'remove': rm, 'limit': lim}
def get_aspectratio(a, b): def get_aspectratio(a, b):
divisor = gcd(a, b) divisor = gcd(a, b)
return f'{int(a / divisor)}:{int(b / divisor)}' return f'{int(a / divisor)}:{int(b / divisor)}'
def ci(pos, n): def ci(pos, n):
z = 1.96 z = 1.96
phat = float(pos) / n phat = float(pos) / n
return (phat + z*z/(2*n) - z * math.sqrt((phat*(1-phat)+z*z/(4*n))/n))/(1+z*z/n) return (phat + z*z/(2*n) - z * math.sqrt((phat*(1-phat)+z*z/(4*n))/n))/(1+z*z/n)