From ef98a4941fb7b8269463271835cbcc54612a82a5 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Thu, 27 Jun 2024 11:23:22 +0930 Subject: [PATCH 01/22] feat: Add skullboard that updates based on skull count --- .example.env | 1 + poetry.lock | 1108 +----------------------------------- pyproject.toml | 4 +- src/commands/skullboard.py | 110 ++++ src/main.py | 24 +- 5 files changed, 142 insertions(+), 1105 deletions(-) create mode 100644 src/commands/skullboard.py diff --git a/.example.env b/.example.env index 1bb16e8..36e13e5 100644 --- a/.example.env +++ b/.example.env @@ -1,2 +1,3 @@ GUILD_ID=GUILD_ID BOT_TOKEN="BOT_TOKEN" +SKULLBOARD_CHANNEL_ID=SKULLBOARD_CHANNEL_ID diff --git a/poetry.lock b/poetry.lock index bba6e0a..7eaf8c8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohttp" version = "3.9.5" description = "Async http client/server framework (asyncio)" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -100,7 +99,6 @@ speedups = ["Brotli", "aiodns", "brotlicffi"] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -115,7 +113,6 @@ frozenlist = ">=1.1.0" name = "attrs" version = "23.2.0" description = "Classes Without Boilerplate" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -135,7 +132,6 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p name = "black" version = "24.4.2" description = "The uncompromising code formatter." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -176,250 +172,10 @@ d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] -[[package]] -name = "build" -version = "1.2.1" -description = "A simple, correct Python build frontend" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "build-1.2.1-py3-none-any.whl", hash = "sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4"}, - {file = "build-1.2.1.tar.gz", hash = "sha256:526263f4870c26f26c433545579475377b2b7588b6f1eac76a001e873ae3e19d"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "os_name == \"nt\""} -packaging = ">=19.1" -pyproject_hooks = "*" - -[package.extras] -docs = ["furo (>=2023.08.17)", "sphinx (>=7.0,<8.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)", "sphinx-issues (>=3.0.0)"] -test = ["build[uv,virtualenv]", "filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "setuptools (>=56.0.0)", "setuptools (>=67.8.0)", "wheel (>=0.36.0)"] -typing = ["build[uv]", "importlib-metadata (>=5.1)", "mypy (>=1.9.0,<1.10.0)", "tomli", "typing-extensions (>=3.7.4.3)"] -uv = ["uv (>=0.1.18)"] -virtualenv = ["virtualenv (>=20.0.35)"] - -[[package]] -name = "cachecontrol" -version = "0.14.0" -description = "httplib2 caching for requests" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cachecontrol-0.14.0-py3-none-any.whl", hash = "sha256:f5bf3f0620c38db2e5122c0726bdebb0d16869de966ea6a2befe92470b740ea0"}, - {file = "cachecontrol-0.14.0.tar.gz", hash = "sha256:7db1195b41c81f8274a7bbd97c956f44e8348265a1bc7641c37dfebc39f0c938"}, -] - -[package.dependencies] -filelock = {version = ">=3.8.0", optional = true, markers = "extra == \"filecache\""} -msgpack = ">=0.5.2,<2.0.0" -requests = ">=2.16.0" - -[package.extras] -dev = ["CacheControl[filecache,redis]", "black", "build", "cherrypy", "furo", "mypy", "pytest", "pytest-cov", "sphinx", "sphinx-copybutton", "tox", "types-redis", "types-requests"] -filecache = ["filelock (>=3.8.0)"] -redis = ["redis (>=2.10.5)"] - -[[package]] -name = "certifi" -version = "2024.6.2" -description = "Python package for providing Mozilla's CA Bundle." -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, - {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, -] - -[[package]] -name = "cffi" -version = "1.16.0" -description = "Foreign Function Interface for Python calling C code." -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, -] - -[package.dependencies] -pycparser = "*" - -[[package]] -name = "charset-normalizer" -version = "3.3.2" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, -] - -[[package]] -name = "cleo" -version = "2.1.0" -description = "Cleo allows you to create beautiful and testable command-line interfaces." -category = "main" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "cleo-2.1.0-py3-none-any.whl", hash = "sha256:4a31bd4dd45695a64ee3c4758f583f134267c2bc518d8ae9a29cf237d009b07e"}, - {file = "cleo-2.1.0.tar.gz", hash = "sha256:0b2c880b5d13660a7ea651001fb4acb527696c01f15c9ee650f377aa543fd523"}, -] - -[package.dependencies] -crashtest = ">=0.4.1,<0.5.0" -rapidfuzz = ">=3.0.0,<4.0.0" - [[package]] name = "click" version = "8.1.7" description = "Composable command line interface toolkit" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -434,7 +190,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -442,78 +197,10 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[[package]] -name = "crashtest" -version = "0.4.1" -description = "Manage Python errors with ease" -category = "main" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "crashtest-0.4.1-py3-none-any.whl", hash = "sha256:8d23eac5fa660409f57472e3851dab7ac18aba459a8d19cbbba86d3d5aecd2a5"}, - {file = "crashtest-0.4.1.tar.gz", hash = "sha256:80d7b1f316ebfbd429f648076d6275c877ba30ba48979de4191714a75266f0ce"}, -] - -[[package]] -name = "cryptography" -version = "42.0.8" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, - {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, - {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, - {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, - {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, - {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, - {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, - {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, -] - -[package.dependencies] -cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} - -[package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] -nox = ["nox"] -pep8test = ["check-sdist", "click", "mypy", "ruff"] -sdist = ["build"] -ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] -test-randomorder = ["pytest-randomly"] - [[package]] name = "discord-py" version = "2.3.2" description = "A Python wrapper for the Discord API" -category = "main" optional = false python-versions = ">=3.8.0" files = [ @@ -530,143 +217,10 @@ speed = ["Brotli", "aiodns (>=1.1)", "cchardet (==2.1.7)", "orjson (>=3.5.4)"] test = ["coverage[toml]", "pytest", "pytest-asyncio", "pytest-cov", "pytest-mock", "typing-extensions (>=4.3,<5)"] voice = ["PyNaCl (>=1.3.0,<1.6)"] -[[package]] -name = "distlib" -version = "0.3.8" -description = "Distribution utilities" -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, -] - -[[package]] -name = "dulwich" -version = "0.21.7" -description = "Python Git Library" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "dulwich-0.21.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d4c0110798099bb7d36a110090f2688050703065448895c4f53ade808d889dd3"}, - {file = "dulwich-0.21.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2bc12697f0918bee324c18836053644035362bb3983dc1b210318f2fed1d7132"}, - {file = "dulwich-0.21.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:471305af74790827fcbafe330fc2e8bdcee4fb56ca1177c8c481b1c8f806c4a4"}, - {file = "dulwich-0.21.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d54c9d0e845be26f65f954dff13a1cd3f2b9739820c19064257b8fd7435ab263"}, - {file = "dulwich-0.21.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12d61334a575474e707614f2e93d6ed4cdae9eb47214f9277076d9e5615171d3"}, - {file = "dulwich-0.21.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e274cebaf345f0b1e3b70197f2651de92b652386b68020cfd3bf61bc30f6eaaa"}, - {file = "dulwich-0.21.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:817822f970e196e757ae01281ecbf21369383285b9f4a83496312204cf889b8c"}, - {file = "dulwich-0.21.7-cp310-cp310-win32.whl", hash = "sha256:7836da3f4110ce684dcd53489015fb7fa94ed33c5276e3318b8b1cbcb5b71e08"}, - {file = "dulwich-0.21.7-cp310-cp310-win_amd64.whl", hash = "sha256:4a043b90958cec866b4edc6aef5fe3c2c96a664d0b357e1682a46f6c477273c4"}, - {file = "dulwich-0.21.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ce8db196e79c1f381469410d26fb1d8b89c6b87a4e7f00ff418c22a35121405c"}, - {file = "dulwich-0.21.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:62bfb26bdce869cd40be443dfd93143caea7089b165d2dcc33de40f6ac9d812a"}, - {file = "dulwich-0.21.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c01a735b9a171dcb634a97a3cec1b174cfbfa8e840156870384b633da0460f18"}, - {file = "dulwich-0.21.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa4d14767cf7a49c9231c2e52cb2a3e90d0c83f843eb6a2ca2b5d81d254cf6b9"}, - {file = "dulwich-0.21.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bca4b86e96d6ef18c5bc39828ea349efb5be2f9b1f6ac9863f90589bac1084d"}, - {file = "dulwich-0.21.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a7b5624b02ef808cdc62dabd47eb10cd4ac15e8ac6df9e2e88b6ac6b40133673"}, - {file = "dulwich-0.21.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c3a539b4696a42fbdb7412cb7b66a4d4d332761299d3613d90a642923c7560e1"}, - {file = "dulwich-0.21.7-cp311-cp311-win32.whl", hash = "sha256:675a612ce913081beb0f37b286891e795d905691dfccfb9bf73721dca6757cde"}, - {file = "dulwich-0.21.7-cp311-cp311-win_amd64.whl", hash = "sha256:460ba74bdb19f8d498786ae7776745875059b1178066208c0fd509792d7f7bfc"}, - {file = "dulwich-0.21.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4c51058ec4c0b45dc5189225b9e0c671b96ca9713c1daf71d622c13b0ab07681"}, - {file = "dulwich-0.21.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4bc4c5366eaf26dda3fdffe160a3b515666ed27c2419f1d483da285ac1411de0"}, - {file = "dulwich-0.21.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a0650ec77d89cb947e3e4bbd4841c96f74e52b4650830112c3057a8ca891dc2f"}, - {file = "dulwich-0.21.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f18f0a311fb7734b033a3101292b932158cade54b74d1c44db519e42825e5a2"}, - {file = "dulwich-0.21.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c589468e5c0cd84e97eb7ec209ab005a2cb69399e8c5861c3edfe38989ac3a8"}, - {file = "dulwich-0.21.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d62446797163317a397a10080c6397ffaaca51a7804c0120b334f8165736c56a"}, - {file = "dulwich-0.21.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e84cc606b1f581733df4350ca4070e6a8b30be3662bbb81a590b177d0c996c91"}, - {file = "dulwich-0.21.7-cp312-cp312-win32.whl", hash = "sha256:c3d1685f320907a52c40fd5890627945c51f3a5fa4bcfe10edb24fec79caadec"}, - {file = "dulwich-0.21.7-cp312-cp312-win_amd64.whl", hash = "sha256:6bd69921fdd813b7469a3c77bc75c1783cc1d8d72ab15a406598e5a3ba1a1503"}, - {file = "dulwich-0.21.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d8ab29c660125db52106775caa1f8f7f77a69ed1fe8bc4b42bdf115731a25bf"}, - {file = "dulwich-0.21.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0d2e4485b98695bf95350ce9d38b1bb0aaac2c34ad00a0df789aa33c934469b"}, - {file = "dulwich-0.21.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e138d516baa6b5bafbe8f030eccc544d0d486d6819b82387fc0e285e62ef5261"}, - {file = "dulwich-0.21.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f34bf9b9fa9308376263fd9ac43143c7c09da9bc75037bb75c6c2423a151b92c"}, - {file = "dulwich-0.21.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2e2c66888207b71cd1daa2acb06d3984a6bc13787b837397a64117aa9fc5936a"}, - {file = "dulwich-0.21.7-cp37-cp37m-win32.whl", hash = "sha256:10893105c6566fc95bc2a67b61df7cc1e8f9126d02a1df6a8b2b82eb59db8ab9"}, - {file = "dulwich-0.21.7-cp37-cp37m-win_amd64.whl", hash = "sha256:460b3849d5c3d3818a80743b4f7a0094c893c559f678e56a02fff570b49a644a"}, - {file = "dulwich-0.21.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:74700e4c7d532877355743336c36f51b414d01e92ba7d304c4f8d9a5946dbc81"}, - {file = "dulwich-0.21.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c92e72c43c9e9e936b01a57167e0ea77d3fd2d82416edf9489faa87278a1cdf7"}, - {file = "dulwich-0.21.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d097e963eb6b9fa53266146471531ad9c6765bf390849230311514546ed64db2"}, - {file = "dulwich-0.21.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:808e8b9cc0aa9ac74870b49db4f9f39a52fb61694573f84b9c0613c928d4caf8"}, - {file = "dulwich-0.21.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1957b65f96e36c301e419d7adaadcff47647c30eb072468901bb683b1000bc5"}, - {file = "dulwich-0.21.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4b09bc3a64fb70132ec14326ecbe6e0555381108caff3496898962c4136a48c6"}, - {file = "dulwich-0.21.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5882e70b74ac3c736a42d3fdd4f5f2e6570637f59ad5d3e684760290b58f041"}, - {file = "dulwich-0.21.7-cp38-cp38-win32.whl", hash = "sha256:29bb5c1d70eba155ded41ed8a62be2f72edbb3c77b08f65b89c03976292f6d1b"}, - {file = "dulwich-0.21.7-cp38-cp38-win_amd64.whl", hash = "sha256:25c3ab8fb2e201ad2031ddd32e4c68b7c03cb34b24a5ff477b7a7dcef86372f5"}, - {file = "dulwich-0.21.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8929c37986c83deb4eb500c766ee28b6670285b512402647ee02a857320e377c"}, - {file = "dulwich-0.21.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc1e11be527ac06316539b57a7688bcb1b6a3e53933bc2f844397bc50734e9ae"}, - {file = "dulwich-0.21.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0fc3078a1ba04c588fabb0969d3530efd5cd1ce2cf248eefb6baf7cbc15fc285"}, - {file = "dulwich-0.21.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dcbd29ba30ba2c5bfbab07a61a5f20095541d5ac66d813056c122244df4ac0"}, - {file = "dulwich-0.21.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8869fc8ec3dda743e03d06d698ad489b3705775fe62825e00fa95aa158097fc0"}, - {file = "dulwich-0.21.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d96ca5e0dde49376fbcb44f10eddb6c30284a87bd03bb577c59bb0a1f63903fa"}, - {file = "dulwich-0.21.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0064363bd5e814359657ae32517fa8001e8573d9d040bd997908d488ab886ed"}, - {file = "dulwich-0.21.7-cp39-cp39-win32.whl", hash = "sha256:869eb7be48243e695673b07905d18b73d1054a85e1f6e298fe63ba2843bb2ca1"}, - {file = "dulwich-0.21.7-cp39-cp39-win_amd64.whl", hash = "sha256:404b8edeb3c3a86c47c0a498699fc064c93fa1f8bab2ffe919e8ab03eafaaad3"}, - {file = "dulwich-0.21.7-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e598d743c6c0548ebcd2baf94aa9c8bfacb787ea671eeeb5828cfbd7d56b552f"}, - {file = "dulwich-0.21.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a2d76c96426e791556836ef43542b639def81be4f1d6d4322cd886c115eae1"}, - {file = "dulwich-0.21.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6c88acb60a1f4d31bd6d13bfba465853b3df940ee4a0f2a3d6c7a0778c705b7"}, - {file = "dulwich-0.21.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ecd315847dea406a4decfa39d388a2521e4e31acde3bd9c2609c989e817c6d62"}, - {file = "dulwich-0.21.7-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d05d3c781bc74e2c2a2a8f4e4e2ed693540fbe88e6ac36df81deac574a6dad99"}, - {file = "dulwich-0.21.7-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6de6f8de4a453fdbae8062a6faa652255d22a3d8bce0cd6d2d6701305c75f2b3"}, - {file = "dulwich-0.21.7-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e25953c7acbbe4e19650d0225af1c0c0e6882f8bddd2056f75c1cc2b109b88ad"}, - {file = "dulwich-0.21.7-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:4637cbd8ed1012f67e1068aaed19fcc8b649bcf3e9e26649826a303298c89b9d"}, - {file = "dulwich-0.21.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:858842b30ad6486aacaa607d60bab9c9a29e7c59dc2d9cb77ae5a94053878c08"}, - {file = "dulwich-0.21.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:739b191f61e1c4ce18ac7d520e7a7cbda00e182c3489552408237200ce8411ad"}, - {file = "dulwich-0.21.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:274c18ec3599a92a9b67abaf110e4f181a4f779ee1aaab9e23a72e89d71b2bd9"}, - {file = "dulwich-0.21.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2590e9b431efa94fc356ae33b38f5e64f1834ec3a94a6ac3a64283b206d07aa3"}, - {file = "dulwich-0.21.7-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed60d1f610ef6437586f7768254c2a93820ccbd4cfdac7d182cf2d6e615969bb"}, - {file = "dulwich-0.21.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8278835e168dd097089f9e53088c7a69c6ca0841aef580d9603eafe9aea8c358"}, - {file = "dulwich-0.21.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffc27fb063f740712e02b4d2f826aee8bbed737ed799962fef625e2ce56e2d29"}, - {file = "dulwich-0.21.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:61e3451bd3d3844f2dca53f131982553be4d1b1e1ebd9db701843dd76c4dba31"}, - {file = "dulwich-0.21.7.tar.gz", hash = "sha256:a9e9c66833cea580c3ac12927e4b9711985d76afca98da971405d414de60e968"}, -] - -[package.dependencies] -urllib3 = ">=1.25" - -[package.extras] -fastimport = ["fastimport"] -https = ["urllib3 (>=1.24.1)"] -paramiko = ["paramiko"] -pgp = ["gpg"] - -[[package]] -name = "fastjsonschema" -version = "2.19.1" -description = "Fastest Python implementation of JSON schema" -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, - {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, -] - -[package.extras] -devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] - -[[package]] -name = "filelock" -version = "3.14.0" -description = "A platform independent file lock." -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, - {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, -] - -[package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] -typing = ["typing-extensions (>=4.8)"] - [[package]] name = "frozenlist" version = "1.4.1" description = "A list-like structure which implements collections.abc.MutableSequence" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -753,7 +307,6 @@ files = [ name = "idna" version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -761,180 +314,10 @@ files = [ {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] -[[package]] -name = "importlib-metadata" -version = "7.1.0" -description = "Read metadata from Python packages" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, - {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, -] - -[package.dependencies] -zipp = ">=0.5" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] - -[[package]] -name = "installer" -version = "0.7.0" -description = "A library for installing Python wheels." -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "installer-0.7.0-py3-none-any.whl", hash = "sha256:05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53"}, - {file = "installer-0.7.0.tar.gz", hash = "sha256:a26d3e3116289bb08216e0d0f7d925fcef0b0194eedfa0c944bcaaa106c4b631"}, -] - -[[package]] -name = "jaraco-classes" -version = "3.4.0" -description = "Utility functions for Python class constructs" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, - {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, -] - -[package.dependencies] -more-itertools = "*" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] - -[[package]] -name = "jeepney" -version = "0.8.0" -description = "Low-level, pure Python DBus protocol wrapper." -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"}, - {file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"}, -] - -[package.extras] -test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] -trio = ["async_generator", "trio"] - -[[package]] -name = "keyring" -version = "24.3.1" -description = "Store and access your passwords safely." -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "keyring-24.3.1-py3-none-any.whl", hash = "sha256:df38a4d7419a6a60fea5cef1e45a948a3e8430dd12ad88b0f423c5c143906218"}, - {file = "keyring-24.3.1.tar.gz", hash = "sha256:c3327b6ffafc0e8befbdb597cacdb4928ffe5c1212f7645f186e6d9957a898db"}, -] - -[package.dependencies] -importlib-metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} -"jaraco.classes" = "*" -jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} -pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} -SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} - -[package.extras] -completion = ["shtab (>=1.1.0)"] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] - -[[package]] -name = "more-itertools" -version = "10.2.0" -description = "More routines for operating on iterables, beyond itertools" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "more-itertools-10.2.0.tar.gz", hash = "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1"}, - {file = "more_itertools-10.2.0-py3-none-any.whl", hash = "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684"}, -] - -[[package]] -name = "msgpack" -version = "1.0.8" -description = "MessagePack serializer" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868"}, - {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c"}, - {file = "msgpack-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659"}, - {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2"}, - {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982"}, - {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa"}, - {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128"}, - {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d"}, - {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653"}, - {file = "msgpack-1.0.8-cp310-cp310-win32.whl", hash = "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693"}, - {file = "msgpack-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a"}, - {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836"}, - {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad"}, - {file = "msgpack-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b"}, - {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba"}, - {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85"}, - {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950"}, - {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a"}, - {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b"}, - {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce"}, - {file = "msgpack-1.0.8-cp311-cp311-win32.whl", hash = "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305"}, - {file = "msgpack-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e"}, - {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee"}, - {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b"}, - {file = "msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8"}, - {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3"}, - {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc"}, - {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58"}, - {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f"}, - {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04"}, - {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543"}, - {file = "msgpack-1.0.8-cp312-cp312-win32.whl", hash = "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c"}, - {file = "msgpack-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd"}, - {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40"}, - {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151"}, - {file = "msgpack-1.0.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24"}, - {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d"}, - {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db"}, - {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77"}, - {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13"}, - {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2"}, - {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a"}, - {file = "msgpack-1.0.8-cp38-cp38-win32.whl", hash = "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c"}, - {file = "msgpack-1.0.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480"}, - {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a"}, - {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596"}, - {file = "msgpack-1.0.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d"}, - {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f"}, - {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228"}, - {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18"}, - {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8"}, - {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746"}, - {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, - {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, - {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, - {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, -] - [[package]] name = "multidict" version = "6.0.5" description = "multidict implementation" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1034,7 +417,6 @@ files = [ name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1046,7 +428,6 @@ files = [ name = "packaging" version = "24.0" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1058,7 +439,6 @@ files = [ name = "pathspec" version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1066,41 +446,10 @@ files = [ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] -[[package]] -name = "pexpect" -version = "4.9.0" -description = "Pexpect allows easy control of interactive console applications." -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, - {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, -] - -[package.dependencies] -ptyprocess = ">=0.5" - -[[package]] -name = "pkginfo" -version = "1.11.0" -description = "Query metadata from sdists / bdists / installed packages." -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pkginfo-1.11.0-py3-none-any.whl", hash = "sha256:6d4998d1cd42c297af72cc0eab5f5bab1d356fb8a55b828fa914173f8bc1ba05"}, - {file = "pkginfo-1.11.0.tar.gz", hash = "sha256:dba885aa82e31e80d615119874384923f4e011c2a39b0c4b7104359e36cb7087"}, -] - -[package.extras] -testing = ["pytest", "pytest-cov", "wheel"] - [[package]] name = "platformdirs" version = "4.2.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1113,127 +462,10 @@ docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx- test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] type = ["mypy (>=1.8)"] -[[package]] -name = "poetry" -version = "1.8.3" -description = "Python dependency management and packaging made easy." -category = "main" -optional = false -python-versions = "<4.0,>=3.8" -files = [ - {file = "poetry-1.8.3-py3-none-any.whl", hash = "sha256:88191c69b08d06f9db671b793d68f40048e8904c0718404b63dcc2b5aec62d13"}, - {file = "poetry-1.8.3.tar.gz", hash = "sha256:67f4eb68288eab41e841cc71a00d26cf6bdda9533022d0189a145a34d0a35f48"}, -] - -[package.dependencies] -build = ">=1.0.3,<2.0.0" -cachecontrol = {version = ">=0.14.0,<0.15.0", extras = ["filecache"]} -cleo = ">=2.1.0,<3.0.0" -crashtest = ">=0.4.1,<0.5.0" -dulwich = ">=0.21.2,<0.22.0" -fastjsonschema = ">=2.18.0,<3.0.0" -installer = ">=0.7.0,<0.8.0" -keyring = ">=24.0.0,<25.0.0" -packaging = ">=23.1" -pexpect = ">=4.7.0,<5.0.0" -pkginfo = ">=1.10,<2.0" -platformdirs = ">=3.0.0,<5" -poetry-core = "1.9.0" -poetry-plugin-export = ">=1.6.0,<2.0.0" -pyproject-hooks = ">=1.0.0,<2.0.0" -requests = ">=2.26,<3.0" -requests-toolbelt = ">=1.0.0,<2.0.0" -shellingham = ">=1.5,<2.0" -tomlkit = ">=0.11.4,<1.0.0" -trove-classifiers = ">=2022.5.19" -virtualenv = ">=20.23.0,<21.0.0" -xattr = {version = ">=1.0.0,<2.0.0", markers = "sys_platform == \"darwin\""} - -[[package]] -name = "poetry-core" -version = "1.9.0" -description = "Poetry PEP 517 Build Backend" -category = "main" -optional = false -python-versions = ">=3.8,<4.0" -files = [ - {file = "poetry_core-1.9.0-py3-none-any.whl", hash = "sha256:4e0c9c6ad8cf89956f03b308736d84ea6ddb44089d16f2adc94050108ec1f5a1"}, - {file = "poetry_core-1.9.0.tar.gz", hash = "sha256:fa7a4001eae8aa572ee84f35feb510b321bd652e5cf9293249d62853e1f935a2"}, -] - -[[package]] -name = "poetry-dotenv-plugin" -version = "0.2.0" -description = "A Poetry plugin to automatically load environment variables from .env files" -category = "main" -optional = false -python-versions = ">=3.7,<4" -files = [ - {file = "poetry_dotenv_plugin-0.2.0-py3-none-any.whl", hash = "sha256:dc2fd816a96e32586afb6507f01de6070a8a50877207ae20efa7c6a75648143a"}, - {file = "poetry_dotenv_plugin-0.2.0.tar.gz", hash = "sha256:9bdd0a96d81ba5f2e75bda7c8944e2c5132b0c615c44452770dd1e7f1aca62f6"}, -] - -[package.dependencies] -poetry = ">=1.2.0a1" -python-dotenv = ">=0.10.0" - -[[package]] -name = "poetry-plugin-export" -version = "1.8.0" -description = "Poetry plugin to export the dependencies to various formats" -category = "main" -optional = false -python-versions = "<4.0,>=3.8" -files = [ - {file = "poetry_plugin_export-1.8.0-py3-none-any.whl", hash = "sha256:adbe232cfa0cc04991ea3680c865cf748bff27593b9abcb1f35fb50ed7ba2c22"}, - {file = "poetry_plugin_export-1.8.0.tar.gz", hash = "sha256:1fa6168a85d59395d835ca564bc19862a7c76061e60c3e7dfaec70d50937fc61"}, -] - -[package.dependencies] -poetry = ">=1.8.0,<3.0.0" -poetry-core = ">=1.7.0,<3.0.0" - -[[package]] -name = "ptyprocess" -version = "0.7.0" -description = "Run a subprocess in a pseudo terminal" -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] - -[[package]] -name = "pycparser" -version = "2.22" -description = "C parser in Python" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, - {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, -] - -[[package]] -name = "pyproject-hooks" -version = "1.1.0" -description = "Wrappers to call pyproject.toml-based build backend hooks." -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pyproject_hooks-1.1.0-py3-none-any.whl", hash = "sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2"}, - {file = "pyproject_hooks-1.1.0.tar.gz", hash = "sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965"}, -] - [[package]] name = "python-dotenv" version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1245,330 +477,20 @@ files = [ cli = ["click (>=5.0)"] [[package]] -name = "pywin32-ctypes" -version = "0.2.2" -description = "A (partial) reimplementation of pywin32 using ctypes/cffi" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"}, - {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"}, -] - -[[package]] -name = "rapidfuzz" -version = "3.9.3" -description = "rapid fuzzy string matching" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "rapidfuzz-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bdb8c5b8e29238ec80727c2ba3b301efd45aa30c6a7001123a6647b8e6f77ea4"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3bd0d9632088c63a241f217742b1cf86e2e8ae573e01354775bd5016d12138c"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:153f23c03d4917f6a1fc2fb56d279cc6537d1929237ff08ee7429d0e40464a18"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a96c5225e840f1587f1bac8fa6f67562b38e095341576e82b728a82021f26d62"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b777cd910ceecd738adc58593d6ed42e73f60ad04ecdb4a841ae410b51c92e0e"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53e06e4b81f552da04940aa41fc556ba39dee5513d1861144300c36c33265b76"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c7ca5b6050f18fdcacdada2dc5fb7619ff998cd9aba82aed2414eee74ebe6cd"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:87bb8d84cb41446a808c4b5f746e29d8a53499381ed72f6c4e456fe0f81c80a8"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:959a15186d18425d19811bea86a8ffbe19fd48644004d29008e636631420a9b7"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a24603dd05fb4e3c09d636b881ce347e5f55f925a6b1b4115527308a323b9f8e"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d055da0e801c71dd74ba81d72d41b2fa32afa182b9fea6b4b199d2ce937450d"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:875b581afb29a7213cf9d98cb0f98df862f1020bce9d9b2e6199b60e78a41d14"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-win32.whl", hash = "sha256:6073a46f61479a89802e3f04655267caa6c14eb8ac9d81a635a13805f735ebc1"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:119c010e20e561249b99ca2627f769fdc8305b07193f63dbc07bca0a6c27e892"}, - {file = "rapidfuzz-3.9.3-cp310-cp310-win_arm64.whl", hash = "sha256:790b0b244f3213581d42baa2fed8875f9ee2b2f9b91f94f100ec80d15b140ba9"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f57e8305c281e8c8bc720515540e0580355100c0a7a541105c6cafc5de71daae"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a4fc7b784cf987dbddc300cef70e09a92ed1bce136f7bb723ea79d7e297fe76d"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b422c0a6fe139d5447a0766268e68e6a2a8c2611519f894b1f31f0a392b9167"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f50fed4a9b0c9825ff37cf0bccafd51ff5792090618f7846a7650f21f85579c9"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b80eb7cbe62348c61d3e67e17057cddfd6defab168863028146e07d5a8b24a89"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f45be77ec82da32ce5709a362e236ccf801615cc7163b136d1778cf9e31b14"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd84b7f652a5610733400307dc732f57c4a907080bef9520412e6d9b55bc9adc"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3e6d27dad8c990218b8cd4a5c99cbc8834f82bb46ab965a7265d5aa69fc7ced7"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:05ee0696ebf0dfe8f7c17f364d70617616afc7dafe366532730ca34056065b8a"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2bc8391749e5022cd9e514ede5316f86e332ffd3cfceeabdc0b17b7e45198a8c"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:93981895602cf5944d89d317ae3b1b4cc684d175a8ae2a80ce5b65615e72ddd0"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:754b719a4990735f66653c9e9261dcf52fd4d925597e43d6b9069afcae700d21"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-win32.whl", hash = "sha256:14c9f268ade4c88cf77ab007ad0fdf63699af071ee69378de89fff7aa3cae134"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc1991b4cde6c9d3c0bbcb83d5581dc7621bec8c666c095c65b4277233265a82"}, - {file = "rapidfuzz-3.9.3-cp311-cp311-win_arm64.whl", hash = "sha256:0c34139df09a61b1b557ab65782ada971b4a3bce7081d1b2bee45b0a52231adb"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d6a210347d6e71234af5c76d55eeb0348b026c9bb98fe7c1cca89bac50fb734"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b300708c917ce52f6075bdc6e05b07c51a085733650f14b732c087dc26e0aaad"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83ea7ca577d76778250421de61fb55a719e45b841deb769351fc2b1740763050"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8319838fb5b7b5f088d12187d91d152b9386ce3979ed7660daa0ed1bff953791"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:505d99131afd21529293a9a7b91dfc661b7e889680b95534756134dc1cc2cd86"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c52970f7784518d7c82b07a62a26e345d2de8c2bd8ed4774e13342e4b3ff4200"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:143caf7247449055ecc3c1e874b69e42f403dfc049fc2f3d5f70e1daf21c1318"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b8ab0fa653d9225195a8ff924f992f4249c1e6fa0aea563f685e71b81b9fcccf"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57e7c5bf7b61c7320cfa5dde1e60e678d954ede9bb7da8e763959b2138391401"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:51fa1ba84653ab480a2e2044e2277bd7f0123d6693051729755addc0d015c44f"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:17ff7f7eecdb169f9236e3b872c96dbbaf116f7787f4d490abd34b0116e3e9c8"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:afe7c72d3f917b066257f7ff48562e5d462d865a25fbcabf40fca303a9fa8d35"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-win32.whl", hash = "sha256:e53ed2e9b32674ce96eed80b3b572db9fd87aae6742941fb8e4705e541d861ce"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:35b7286f177e4d8ba1e48b03612f928a3c4bdac78e5651379cec59f95d8651e6"}, - {file = "rapidfuzz-3.9.3-cp312-cp312-win_arm64.whl", hash = "sha256:e6e4b9380ed4758d0cb578b0d1970c3f32dd9e87119378729a5340cb3169f879"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a39890013f6d5b056cc4bfdedc093e322462ece1027a57ef0c636537bdde7531"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b5bc0fdbf419493163c5c9cb147c5fbe95b8e25844a74a8807dcb1a125e630cf"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efe6e200a75a792d37b960457904c4fce7c928a96ae9e5d21d2bd382fe39066e"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de077c468c225d4c18f7188c47d955a16d65f21aab121cbdd98e3e2011002c37"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f917eaadf5388466a95f6a236f678a1588d231e52eda85374077101842e794e"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:858ba57c05afd720db8088a8707079e8d024afe4644001fe0dbd26ef7ca74a65"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d36447d21b05f90282a6f98c5a33771805f9222e5d0441d03eb8824e33e5bbb4"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:acbe4b6f1ccd5b90c29d428e849aa4242e51bb6cab0448d5f3c022eb9a25f7b1"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:53c7f27cdf899e94712972237bda48cfd427646aa6f5d939bf45d084780e4c16"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:6175682a829c6dea4d35ed707f1dadc16513270ef64436568d03b81ccb6bdb74"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:5276df395bd8497397197fca2b5c85f052d2e6a66ffc3eb0544dd9664d661f95"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:77b5c4f3e72924d7845f0e189c304270066d0f49635cf8a3938e122c437e58de"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-win32.whl", hash = "sha256:8add34061e5cd561c72ed4febb5c15969e7b25bda2bb5102d02afc3abc1f52d0"}, - {file = "rapidfuzz-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:604e0502a39cf8e67fa9ad239394dddad4cdef6d7008fdb037553817d420e108"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21047f55d674614eb4b0ab34e35c3dc66f36403b9fbfae645199c4a19d4ed447"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a56da3aff97cb56fe85d9ca957d1f55dbac7c27da927a86a2a86d8a7e17f80aa"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:964c08481aec2fe574f0062e342924db2c6b321391aeb73d68853ed42420fd6d"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e2b827258beefbe5d3f958243caa5a44cf46187eff0c20e0b2ab62d1550327a"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6e65a301fcd19fbfbee3a514cc0014ff3f3b254b9fd65886e8a9d6957fb7bca"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe93ba1725a8d47d2b9dca6c1f435174859427fbc054d83de52aea5adc65729"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aca21c0a34adee582775da997a600283e012a608a107398d80a42f9a57ad323d"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:256e07d3465173b2a91c35715a2277b1ee3ae0b9bbab4e519df6af78570741d0"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:802ca2cc8aa6b8b34c6fdafb9e32540c1ba05fca7ad60b3bbd7ec89ed1797a87"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:dd789100fc852cffac1449f82af0da139d36d84fd9faa4f79fc4140a88778343"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:5d0abbacdb06e27ff803d7ae0bd0624020096802758068ebdcab9bd49cf53115"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:378d1744828e27490a823fc6fe6ebfb98c15228d54826bf4e49e4b76eb5f5579"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-win32.whl", hash = "sha256:5d0cb272d43e6d3c0dedefdcd9d00007471f77b52d2787a4695e9dd319bb39d2"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:15e4158ac4b3fb58108072ec35b8a69165f651ba1c8f43559a36d518dbf9fb3f"}, - {file = "rapidfuzz-3.9.3-cp39-cp39-win_arm64.whl", hash = "sha256:58c6a4936190c558d5626b79fc9e16497e5df7098589a7e80d8bff68148ff096"}, - {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5410dc848c947a603792f4f51b904a3331cf1dc60621586bfbe7a6de72da1091"}, - {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:282d55700a1a3d3a7980746eb2fcd48c9bbc1572ebe0840d0340d548a54d01fe"}, - {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc1037507810833646481f5729901a154523f98cbebb1157ba3a821012e16402"}, - {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e33f779391caedcba2ba3089fb6e8e557feab540e9149a5c3f7fea7a3a7df37"}, - {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41a81a9f311dc83d22661f9b1a1de983b201322df0c4554042ffffd0f2040c37"}, - {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a93250bd8fae996350c251e1752f2c03335bb8a0a5b0c7e910a593849121a435"}, - {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3617d1aa7716c57d120b6adc8f7c989f2d65bc2b0cbd5f9288f1fc7bf469da11"}, - {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:ad04a3f5384b82933213bba2459f6424decc2823df40098920856bdee5fd6e88"}, - {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8709918da8a88ad73c9d4dd0ecf24179a4f0ceba0bee21efc6ea21a8b5290349"}, - {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b770f85eab24034e6ef7df04b2bfd9a45048e24f8a808e903441aa5abde8ecdd"}, - {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930b4e6fdb4d914390141a2b99a6f77a52beacf1d06aa4e170cba3a98e24c1bc"}, - {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c8444e921bfc3757c475c4f4d7416a7aa69b2d992d5114fe55af21411187ab0d"}, - {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c1d3ef3878f871abe6826e386c3d61b5292ef5f7946fe646f4206b85836b5da"}, - {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d861bf326ee7dabc35c532a40384541578cd1ec1e1b7db9f9ecbba56eb76ca22"}, - {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cde6b9d9ba5007077ee321ec722fa714ebc0cbd9a32ccf0f4dd3cc3f20952d71"}, - {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bb6546e7b6bed1aefbe24f68a5fb9b891cc5aef61bca6c1a7b1054b7f0359bb"}, - {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d8a57261ef7996d5ced7c8cba9189ada3fbeffd1815f70f635e4558d93766cb"}, - {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:67201c02efc596923ad950519e0b75ceb78d524177ea557134d6567b9ac2c283"}, - {file = "rapidfuzz-3.9.3.tar.gz", hash = "sha256:b398ea66e8ed50451bce5997c430197d5e4b06ac4aa74602717f792d8d8d06e2"}, -] - -[package.extras] -full = ["numpy"] - -[[package]] -name = "requests" -version = "2.32.3" -description = "Python HTTP for Humans." -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, - {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "requests-toolbelt" -version = "1.0.0" -description = "A utility belt for advanced users of python-requests" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, - {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, -] - -[package.dependencies] -requests = ">=2.0.1,<3.0.0" - -[[package]] -name = "secretstorage" -version = "3.3.3" -description = "Python bindings to FreeDesktop.org Secret Service API" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, - {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, -] - -[package.dependencies] -cryptography = ">=2.0" -jeepney = ">=0.6" - -[[package]] -name = "shellingham" -version = "1.5.4" -description = "Tool to Detect Surrounding Shell" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, - {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, -] - -[[package]] -name = "tomlkit" -version = "0.12.5" -description = "Style preserving TOML library" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomlkit-0.12.5-py3-none-any.whl", hash = "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f"}, - {file = "tomlkit-0.12.5.tar.gz", hash = "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c"}, -] - -[[package]] -name = "trove-classifiers" -version = "2024.5.22" -description = "Canonical source for classifiers on PyPI (pypi.org)." -category = "main" +name = "pytz" +version = "2024.1" +description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "trove_classifiers-2024.5.22-py3-none-any.whl", hash = "sha256:c43ade18704823e4afa3d9db7083294bc4708a5e02afbcefacd0e9d03a7a24ef"}, - {file = "trove_classifiers-2024.5.22.tar.gz", hash = "sha256:8a6242bbb5c9ae88d34cf665e816b287d2212973c8777dfaef5ec18d72ac1d03"}, + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] -[[package]] -name = "urllib3" -version = "2.2.1" -description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, - {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, -] - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "virtualenv" -version = "20.26.2" -description = "Virtual Python Environment builder" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, - {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, -] - -[package.dependencies] -distlib = ">=0.3.7,<1" -filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<5" - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] - -[[package]] -name = "xattr" -version = "1.1.0" -description = "Python wrapper for extended filesystem attributes" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "xattr-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef2fa0f85458736178fd3dcfeb09c3cf423f0843313e25391db2cfd1acec8888"}, - {file = "xattr-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ccab735d0632fe71f7d72e72adf886f45c18b7787430467ce0070207882cfe25"}, - {file = "xattr-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9013f290387f1ac90bccbb1926555ca9aef75651271098d99217284d9e010f7c"}, - {file = "xattr-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcd5dfbcee73c7be057676ecb900cabb46c691aff4397bf48c579ffb30bb963"}, - {file = "xattr-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6480589c1dac7785d1f851347a32c4a97305937bf7b488b857fe8b28a25de9e9"}, - {file = "xattr-1.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08f61cbed52dc6f7c181455826a9ff1e375ad86f67dd9d5eb7663574abb32451"}, - {file = "xattr-1.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:918e1f83f2e8a072da2671eac710871ee5af337e9bf8554b5ce7f20cdb113186"}, - {file = "xattr-1.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0f06e0c1e4d06b4e0e49aaa1184b6f0e81c3758c2e8365597918054890763b53"}, - {file = "xattr-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a641ac038a9f53d2f696716147ca4dbd6a01998dc9cd4bc628801bc0df7f4d"}, - {file = "xattr-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7e4ca0956fd11679bb2e0c0d6b9cdc0f25470cc00d8da173bb7656cc9a9cf104"}, - {file = "xattr-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6881b120f9a4b36ccd8a28d933bc0f6e1de67218b6ce6e66874e0280fc006844"}, - {file = "xattr-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dab29d9288aa28e68a6f355ddfc3f0a7342b40c9012798829f3e7bd765e85c2c"}, - {file = "xattr-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0c80bbf55339c93770fc294b4b6586b5bf8e85ec00a4c2d585c33dbd84b5006"}, - {file = "xattr-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1418705f253b6b6a7224b69773842cac83fcbcd12870354b6e11dd1cd54630f"}, - {file = "xattr-1.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:687e7d18611ef8d84a6ecd8f4d1ab6757500c1302f4c2046ce0aa3585e13da3f"}, - {file = "xattr-1.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6ceb9efe0657a982ccb8b8a2efe96b690891779584c901d2f920784e5d20ae3"}, - {file = "xattr-1.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b489b7916f239100956ea0b39c504f3c3a00258ba65677e4c8ba1bd0b5513446"}, - {file = "xattr-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0a9c431b0e66516a078125e9a273251d4b8e5ba84fe644b619f2725050d688a0"}, - {file = "xattr-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1a5921ea3313cc1c57f2f53b63ea8ca9a91e48f4cc7ebec057d2447ec82c7efe"}, - {file = "xattr-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f6ad2a7bd5e6cf71d4a862413234a067cf158ca0ae94a40d4b87b98b62808498"}, - {file = "xattr-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0683dae7609f7280b0c89774d00b5957e6ffcb181c6019c46632b389706b77e6"}, - {file = "xattr-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54cb15cd94e5ef8a0ef02309f1bf973ba0e13c11e87686e983f371948cfee6af"}, - {file = "xattr-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff6223a854229055e803c2ad0c0ea9a6da50c6be30d92c198cf5f9f28819a921"}, - {file = "xattr-1.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d44e8f955218638c9ab222eed21e9bd9ab430d296caf2176fb37abe69a714e5c"}, - {file = "xattr-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:caab2c2986c30f92301f12e9c50415d324412e8e6a739a52a603c3e6a54b3610"}, - {file = "xattr-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d6eb7d5f281014cd44e2d847a9107491af1bf3087f5afeded75ed3e37ec87239"}, - {file = "xattr-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:47a3bdfe034b4fdb70e5941d97037405e3904accc28e10dbef6d1c9061fb6fd7"}, - {file = "xattr-1.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:00d2b415cf9d6a24112d019e721aa2a85652f7bbc9f3b9574b2d1cd8668eb491"}, - {file = "xattr-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:78b377832dd0ee408f9f121a354082c6346960f7b6b1480483ed0618b1912120"}, - {file = "xattr-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6461a43b585e5f2e049b39bcbfcb6391bfef3c5118231f1b15d10bdb89ef17fe"}, - {file = "xattr-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24d97f0d28f63695e3344ffdabca9fcc30c33e5c8ccc198c7524361a98d526f2"}, - {file = "xattr-1.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ad47d89968c9097900607457a0c89160b4771601d813e769f68263755516065"}, - {file = "xattr-1.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc53cab265f6e8449bd683d5ee3bc5a191e6dd940736f3de1a188e6da66b0653"}, - {file = "xattr-1.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cd11e917f5b89f2a0ad639d9875943806c6c9309a3dd02da5a3e8ef92db7bed9"}, - {file = "xattr-1.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9c5a78c7558989492c4cb7242e490ffb03482437bf782967dfff114e44242343"}, - {file = "xattr-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cebcf8a303a44fbc439b68321408af7267507c0d8643229dbb107f6c132d389c"}, - {file = "xattr-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b0d73150f2f9655b4da01c2369eb33a294b7f9d56eccb089819eafdbeb99f896"}, - {file = "xattr-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:793c01deaadac50926c0e1481702133260c7cb5e62116762f6fe1543d07b826f"}, - {file = "xattr-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e189e440bcd04ccaad0474720abee6ee64890823ec0db361fb0a4fb5e843a1bf"}, - {file = "xattr-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afacebbc1fa519f41728f8746a92da891c7755e6745164bd0d5739face318e86"}, - {file = "xattr-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b1664edf003153ac8d1911e83a0fc60db1b1b374ee8ac943f215f93754a1102"}, - {file = "xattr-1.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda2684228798e937a7c29b0e1c7ef3d70e2b85390a69b42a1c61b2039ba81de"}, - {file = "xattr-1.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b735ac2625a4fc2c9343b19f806793db6494336338537d2911c8ee4c390dda46"}, - {file = "xattr-1.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fa6a7af7a4ada43f15ccc58b6f9adcdbff4c36ba040013d2681e589e07ae280a"}, - {file = "xattr-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1059b2f726e2702c8bbf9bbf369acfc042202a4cc576c2dec6791234ad5e948"}, - {file = "xattr-1.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e2255f36ebf2cb2dbf772a7437ad870836b7396e60517211834cf66ce678b595"}, - {file = "xattr-1.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dba4f80b9855cc98513ddf22b7ad8551bc448c70d3147799ea4f6c0b758fb466"}, - {file = "xattr-1.1.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cb70c16e7c3ae6ba0ab6c6835c8448c61d8caf43ea63b813af1f4dbe83dd156"}, - {file = "xattr-1.1.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83652910ef6a368b77b00825ad67815e5c92bfab551a848ca66e9981d14a7519"}, - {file = "xattr-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7a92aff66c43fa3e44cbeab7cbeee66266c91178a0f595e044bf3ce51485743b"}, - {file = "xattr-1.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d4f71b673339aeaae1f6ea9ef8ea6c9643c8cd0df5003b9a0eaa75403e2e06c"}, - {file = "xattr-1.1.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a20de1c47b5cd7b47da61799a3b34e11e5815d716299351f82a88627a43f9a96"}, - {file = "xattr-1.1.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23705c7079b05761ff2fa778ad17396e7599c8759401abc05b312dfb3bc99f69"}, - {file = "xattr-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:27272afeba8422f2a9d27e1080a9a7b807394e88cce73db9ed8d2dde3afcfb87"}, - {file = "xattr-1.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd43978966de3baf4aea367c99ffa102b289d6c2ea5f3d9ce34a203dc2f2ab73"}, - {file = "xattr-1.1.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ded771eaf27bb4eb3c64c0d09866460ee8801d81dc21097269cf495b3cac8657"}, - {file = "xattr-1.1.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca300c0acca4f0cddd2332bb860ef58e1465d376364f0e72a1823fdd58e90d"}, - {file = "xattr-1.1.0.tar.gz", hash = "sha256:fecbf3b05043ed3487a28190dec3e4c4d879b2fcec0e30bafd8ec5d4b6043630"}, -] - -[package.dependencies] -cffi = ">=1.16.0" - -[package.extras] -test = ["pytest"] - [[package]] name = "yarl" version = "1.9.4" description = "Yet another URL library" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1668,23 +590,7 @@ files = [ idna = ">=2.0" multidict = ">=4.0" -[[package]] -name = "zipp" -version = "3.19.2" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, - {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, -] - -[package.extras] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] - [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "4f9565156f980d97739575e85c822d8b32674b504f57e7c8135bd4d52abd73d2" +content-hash = "d3236891695e0c80dc622603c0069aa140c7cac4f9e3ffd9bfb2256fb217906c" diff --git a/pyproject.toml b/pyproject.toml index 6806981..9f68a2c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,12 +5,14 @@ description = "DuckBot is the CS Club's Discord Bot, created by the CS Club Open authors = ["CS Club Open Source Team "] license = "MIT" readme = "README.md" +package-mode = false [tool.poetry.dependencies] python = "^3.11" "discord.py" = "2.3.2" black = "^24.4.2" -poetry-dotenv-plugin = "^0.2.0" +python-dotenv = "^1.0.1" +pytz = "^2024.1" [build-system] requires = ["poetry-core"] diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py new file mode 100644 index 0000000..1cc9ca6 --- /dev/null +++ b/src/commands/skullboard.py @@ -0,0 +1,110 @@ +import os +import datetime +import pytz +from discord import Embed + +# Dictionary to map original message IDs to Skullboard message IDs and current skull counts +message_map = {} + +async def handle_skullboard(client, reaction, SKULLBOARD_CHANNEL_ID, type): + skullboard_channel = client.get_channel(SKULLBOARD_CHANNEL_ID) + if skullboard_channel: + message = reaction.message + emoji = "💀" + + # Check if the reaction is a skull emoji + if str(reaction.emoji) == emoji: + # Skip reposting messages sent by the bot + if message.author == client.user: + return + + # Check if the message ID is in the map + if message.id in message_map: + skullboard_message_id, current_count = message_map[message.id] + else: + skullboard_message_id = None + current_count = 0 + + # Update the current count based on the reaction event + if type == "ADD": + current_count += 1 + elif type == "REMOVE": + current_count -= 1 + + # Store the updated count in the message map + message_map[message.id] = (skullboard_message_id, current_count) + + # Determine action based on current count + if current_count > 0: + await update_or_send_skullboard_message(skullboard_channel, message, current_count, emoji) + else: + await delete_skullboard_message(skullboard_channel, message) + else: + print("Reaction is not a skull emoji. Skipping Skullboard handling.") + else: + print(f"Skullboard channel not found with ID {SKULLBOARD_CHANNEL_ID}. Message could not be sent.") + +async def update_or_send_skullboard_message(channel, message, current_count, emoji): + if message.id in message_map: + skullboard_message_id, _ = message_map[message.id] + if skullboard_message_id: + await update_skullboard_message(channel, message, current_count, emoji, skullboard_message_id) + else: + await send_skullboard_message(channel, message, current_count, emoji) + else: + await send_skullboard_message(channel, message, current_count, emoji) + +async def send_skullboard_message(channel, message, current_count, emoji): + # Format the reposted message with the number of skulls, channel name, timestamp, and mention + channel_name = message.channel.name + adelaide_time = get_adelaide_time() + mention = message.author.mention + message_content = message.content + message_link = message.jump_url + + # Constructing the embed + embed = Embed( + title=f"{current_count} {emoji} | #{channel_name}", + description=f"{mention}\n\n{message_content}\n\n[Click to go to message!]({message_link})", + timestamp=adelaide_time + ) + + # Send the reposted message as an embed in the selected channel + skullboard_message = await channel.send(embed=embed) + message_map[message.id] = (skullboard_message.id, current_count) + +async def update_skullboard_message(channel, message, current_count, emoji, skullboard_message_id): + # Format the updated embed with the current count + channel_name = message.channel.name + adelaide_time = get_adelaide_time() + mention = message.author.mention + message_content = message.content + message_link = message.jump_url # URL to jump to the message + + # Constructing the updated embed + embed = Embed( + title=f"{current_count} {emoji} | #{channel_name}", + description=f"{mention}\n\n{message_content}\n\n[Click to go to message!]({message_link})", + timestamp=adelaide_time + ) + + # Fetch the existing Skullboard message and update it + skullboard_message = await channel.fetch_message(skullboard_message_id) + await skullboard_message.edit(embed=embed) + message_map[message.id] = (skullboard_message.id, current_count) + +async def delete_skullboard_message(channel, message): + # Delete the Skullboard message + if message.id in message_map: + skullboard_message_id, _ = message_map[message.id] + if skullboard_message_id: + skullboard_message = await channel.fetch_message(skullboard_message_id) + await skullboard_message.delete() + del message_map[message.id] + +def get_adelaide_time(): + # Convert UTC timestamp to Adelaide time + adelaide_tz = pytz.timezone('Australia/Adelaide') + utc_now = datetime.datetime.utcnow() + adelaide_time = utc_now.replace(tzinfo=pytz.utc).astimezone(adelaide_tz) + return adelaide_time diff --git a/src/main.py b/src/main.py index 190f613..95582d0 100644 --- a/src/main.py +++ b/src/main.py @@ -1,17 +1,24 @@ import os +from dotenv import load_dotenv import importlib import pkgutil -from discord import Intents, app_commands, Object, Interaction, Embed, Message, Color +from discord import Intents, app_commands, Object, Interaction, Embed, Color, Message, Reaction, User from discord.ext import commands +import commands.skullboard as skullboard -# Retrieve guild ID and bot token from environment variables +# Load environment variables from .env file +load_dotenv() + +# Retrieve environment variables GUILD_ID = int(os.environ["GUILD_ID"]) BOT_TOKEN = os.environ["BOT_TOKEN"] +SKULLBOARD_CHANNEL_ID = int(os.environ["SKULLBOARD_CHANNEL_ID"]) # Load the permissions the bot has been granted in the previous configuration intents = Intents.default() intents.message_content = True - +intents.reactions = True +intents.members = True class DuckBot(commands.Bot): def __init__(self): @@ -79,6 +86,17 @@ async def help(interaction: Interaction): async def on_message(message: Message): pass +# Register the reaction handling +@client.event +async def on_reaction_add(reaction: Reaction, user: User): + type = "ADD" + await skullboard.handle_skullboard(client, reaction, SKULLBOARD_CHANNEL_ID, type) + +@client.event +async def on_reaction_remove(reaction: Reaction, user: User): + type = "REMOVE" + await skullboard.handle_skullboard(client, reaction, SKULLBOARD_CHANNEL_ID, type) + # Add the token of bot client.run(BOT_TOKEN) From fdb890dc0db348cad9f5187926df19d73977371e Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Thu, 27 Jun 2024 11:54:57 +0930 Subject: [PATCH 02/22] refactor Move Adelaide time function to seperate file and combine shared lines --- src/commands/skullboard.py | 121 ++++++++++++++----------------------- src/commands/utils/time.py | 9 +++ 2 files changed, 56 insertions(+), 74 deletions(-) create mode 100644 src/commands/utils/time.py diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 1cc9ca6..15639b9 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -1,97 +1,77 @@ -import os -import datetime -import pytz from discord import Embed +from .utils.time import get_adelaide_time # Dictionary to map original message IDs to Skullboard message IDs and current skull counts message_map = {} async def handle_skullboard(client, reaction, SKULLBOARD_CHANNEL_ID, type): skullboard_channel = client.get_channel(SKULLBOARD_CHANNEL_ID) - if skullboard_channel: - message = reaction.message - emoji = "💀" - - # Check if the reaction is a skull emoji - if str(reaction.emoji) == emoji: - # Skip reposting messages sent by the bot - if message.author == client.user: - return - - # Check if the message ID is in the map - if message.id in message_map: - skullboard_message_id, current_count = message_map[message.id] - else: - skullboard_message_id = None - current_count = 0 - - # Update the current count based on the reaction event - if type == "ADD": - current_count += 1 - elif type == "REMOVE": - current_count -= 1 - - # Store the updated count in the message map - message_map[message.id] = (skullboard_message_id, current_count) - - # Determine action based on current count - if current_count > 0: - await update_or_send_skullboard_message(skullboard_channel, message, current_count, emoji) - else: - await delete_skullboard_message(skullboard_channel, message) - else: - print("Reaction is not a skull emoji. Skipping Skullboard handling.") - else: + if not skullboard_channel: print(f"Skullboard channel not found with ID {SKULLBOARD_CHANNEL_ID}. Message could not be sent.") + return -async def update_or_send_skullboard_message(channel, message, current_count, emoji): + message = reaction.message + emoji = "💀" + + # Check if the reaction is a skull emoji + if str(reaction.emoji) != emoji or message.author == client.user: + return + + # Update or delete Skullboard message based on reaction type if message.id in message_map: - skullboard_message_id, _ = message_map[message.id] - if skullboard_message_id: - await update_skullboard_message(channel, message, current_count, emoji, skullboard_message_id) - else: - await send_skullboard_message(channel, message, current_count, emoji) + skullboard_message_id, current_count = message_map[message.id] else: - await send_skullboard_message(channel, message, current_count, emoji) + skullboard_message_id = None + current_count = 0 -async def send_skullboard_message(channel, message, current_count, emoji): - # Format the reposted message with the number of skulls, channel name, timestamp, and mention - channel_name = message.channel.name - adelaide_time = get_adelaide_time() - mention = message.author.mention - message_content = message.content - message_link = message.jump_url + if type == "ADD": + current_count += 1 + elif type == "REMOVE": + current_count = max(0, current_count - 1) - # Constructing the embed - embed = Embed( - title=f"{current_count} {emoji} | #{channel_name}", - description=f"{mention}\n\n{message_content}\n\n[Click to go to message!]({message_link})", - timestamp=adelaide_time - ) + message_map[message.id] = (skullboard_message_id, current_count) + + if current_count > 0: + await update_or_send_skullboard_message(skullboard_channel, message, current_count, emoji) + else: + await delete_skullboard_message(skullboard_channel, message) + +async def update_or_send_skullboard_message(channel, message, current_count, emoji): + skullboard_message_id, _ = message_map.get(message.id, (None, 0)) + + if skullboard_message_id: + await update_skullboard_message(channel, message, current_count, emoji, skullboard_message_id) + else: + await send_skullboard_message(channel, message, current_count, emoji) - # Send the reposted message as an embed in the selected channel - skullboard_message = await channel.send(embed=embed) - message_map[message.id] = (skullboard_message.id, current_count) +async def send_skullboard_message(channel, message, current_count, emoji): + await edit_or_send_skullboard_message(channel, message, current_count, emoji, send=True) async def update_skullboard_message(channel, message, current_count, emoji, skullboard_message_id): - # Format the updated embed with the current count + await edit_or_send_skullboard_message(channel, message, current_count, emoji, send=False, skullboard_message_id=skullboard_message_id) + +async def edit_or_send_skullboard_message(channel, message, current_count, emoji, send=False, skullboard_message_id=None): + # Format the message details channel_name = message.channel.name adelaide_time = get_adelaide_time() mention = message.author.mention message_content = message.content - message_link = message.jump_url # URL to jump to the message + message_link = message.jump_url - # Constructing the updated embed + # Constructing the embed embed = Embed( title=f"{current_count} {emoji} | #{channel_name}", description=f"{mention}\n\n{message_content}\n\n[Click to go to message!]({message_link})", timestamp=adelaide_time ) - # Fetch the existing Skullboard message and update it - skullboard_message = await channel.fetch_message(skullboard_message_id) - await skullboard_message.edit(embed=embed) - message_map[message.id] = (skullboard_message.id, current_count) + # Determine if sending or editing the message + if send: + skullboard_message = await channel.send(embed=embed) + message_map[message.id] = (skullboard_message.id, current_count) + else: + skullboard_message = await channel.fetch_message(skullboard_message_id) + await skullboard_message.edit(embed=embed) async def delete_skullboard_message(channel, message): # Delete the Skullboard message @@ -101,10 +81,3 @@ async def delete_skullboard_message(channel, message): skullboard_message = await channel.fetch_message(skullboard_message_id) await skullboard_message.delete() del message_map[message.id] - -def get_adelaide_time(): - # Convert UTC timestamp to Adelaide time - adelaide_tz = pytz.timezone('Australia/Adelaide') - utc_now = datetime.datetime.utcnow() - adelaide_time = utc_now.replace(tzinfo=pytz.utc).astimezone(adelaide_tz) - return adelaide_time diff --git a/src/commands/utils/time.py b/src/commands/utils/time.py new file mode 100644 index 0000000..9e72a60 --- /dev/null +++ b/src/commands/utils/time.py @@ -0,0 +1,9 @@ +import datetime +import pytz + +def get_adelaide_time(): + # Convert UTC timestamp to Adelaide time + adelaide_tz = pytz.timezone('Australia/Adelaide') + utc_now = datetime.datetime.utcnow() + adelaide_time = utc_now.replace(tzinfo=pytz.utc).astimezone(adelaide_tz) + return adelaide_time From 451a433e1f1d1f985b40757af220fcf33090c3c8 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Thu, 27 Jun 2024 15:45:30 +0930 Subject: [PATCH 03/22] feat: Handles reacts to messages before server started --- .gitignore | 2 ++ src/commands/skullboard.py | 65 ++++++++++++++++++++++++++++---------- src/main.py | 24 ++++++++++---- 3 files changed, 68 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 51387d0..ea13935 100644 --- a/.gitignore +++ b/.gitignore @@ -163,3 +163,5 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +skullboard_data.json diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 15639b9..43a27d6 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -1,25 +1,44 @@ +import os +import json from discord import Embed from .utils.time import get_adelaide_time -# Dictionary to map original message IDs to Skullboard message IDs and current skull counts +# Global variable to store the path to the JSON file +DATA_FILE = 'skullboard_data.json' + +# Initialise message_map message_map = {} -async def handle_skullboard(client, reaction, SKULLBOARD_CHANNEL_ID, type): +# Load existing data from JSON file if available +def load_data(): + global message_map + if os.path.exists(DATA_FILE): + with open(DATA_FILE, 'r') as f: + message_map = json.load(f) + +# Save data to JSON file +def save_data(): + with open(DATA_FILE, 'w') as f: + json.dump(message_map, f) + +# Function to handle reactions and update/delete skullboard messages +async def handle_skullboard(client, message, SKULLBOARD_CHANNEL_ID, type): + # Load data at the start + load_data() + skullboard_channel = client.get_channel(SKULLBOARD_CHANNEL_ID) if not skullboard_channel: print(f"Skullboard channel not found with ID {SKULLBOARD_CHANNEL_ID}. Message could not be sent.") return - - message = reaction.message + emoji = "💀" - # Check if the reaction is a skull emoji - if str(reaction.emoji) != emoji or message.author == client.user: - return + # Convert message id to string to ensure consistency + message_id_str = str(message.id) # Update or delete Skullboard message based on reaction type - if message.id in message_map: - skullboard_message_id, current_count = message_map[message.id] + if message_id_str in message_map: + skullboard_message_id, current_count = message_map[message_id_str] else: skullboard_message_id = None current_count = 0 @@ -29,27 +48,33 @@ async def handle_skullboard(client, reaction, SKULLBOARD_CHANNEL_ID, type): elif type == "REMOVE": current_count = max(0, current_count - 1) - message_map[message.id] = (skullboard_message_id, current_count) - + message_map[message_id_str] = (skullboard_message_id, current_count) if current_count > 0: await update_or_send_skullboard_message(skullboard_channel, message, current_count, emoji) else: await delete_skullboard_message(skullboard_channel, message) + # Save the updated message_map to the JSON file after each modification + save_data() + +# Function to update or send skullboard message async def update_or_send_skullboard_message(channel, message, current_count, emoji): - skullboard_message_id, _ = message_map.get(message.id, (None, 0)) + skullboard_message_id, _ = message_map.get(str(message.id), (None, 0)) if skullboard_message_id: await update_skullboard_message(channel, message, current_count, emoji, skullboard_message_id) else: await send_skullboard_message(channel, message, current_count, emoji) +# Function to send skullboard message async def send_skullboard_message(channel, message, current_count, emoji): await edit_or_send_skullboard_message(channel, message, current_count, emoji, send=True) +# Function to update skullboard message async def update_skullboard_message(channel, message, current_count, emoji, skullboard_message_id): await edit_or_send_skullboard_message(channel, message, current_count, emoji, send=False, skullboard_message_id=skullboard_message_id) +# Function to edit or send skullboard message async def edit_or_send_skullboard_message(channel, message, current_count, emoji, send=False, skullboard_message_id=None): # Format the message details channel_name = message.channel.name @@ -68,16 +93,24 @@ async def edit_or_send_skullboard_message(channel, message, current_count, emoji # Determine if sending or editing the message if send: skullboard_message = await channel.send(embed=embed) - message_map[message.id] = (skullboard_message.id, current_count) + message_map[str(message.id)] = (skullboard_message.id, current_count) else: skullboard_message = await channel.fetch_message(skullboard_message_id) await skullboard_message.edit(embed=embed) + # Save the updated message_map to the JSON file after each modification + save_data() + +# Function to delete skullboard message async def delete_skullboard_message(channel, message): # Delete the Skullboard message - if message.id in message_map: - skullboard_message_id, _ = message_map[message.id] + message_id_str = str(message.id) + if message_id_str in message_map: + skullboard_message_id, _ = message_map[message_id_str] if skullboard_message_id: skullboard_message = await channel.fetch_message(skullboard_message_id) await skullboard_message.delete() - del message_map[message.id] + del message_map[message_id_str] + + # Save the updated message_map to the JSON file after each modification + save_data() diff --git a/src/main.py b/src/main.py index 95582d0..fb56dba 100644 --- a/src/main.py +++ b/src/main.py @@ -2,7 +2,7 @@ from dotenv import load_dotenv import importlib import pkgutil -from discord import Intents, app_commands, Object, Interaction, Embed, Color, Message, Reaction, User +from discord import Intents, app_commands, Object, Interaction, Embed, Color, Message, RawReactionActionEvent from discord.ext import commands import commands.skullboard as skullboard @@ -16,6 +16,8 @@ # Load the permissions the bot has been granted in the previous configuration intents = Intents.default() +intents.guilds = True +intents.messages = True intents.message_content = True intents.reactions = True intents.members = True @@ -88,14 +90,22 @@ async def on_message(message: Message): # Register the reaction handling @client.event -async def on_reaction_add(reaction: Reaction, user: User): - type = "ADD" - await skullboard.handle_skullboard(client, reaction, SKULLBOARD_CHANNEL_ID, type) +async def on_raw_reaction_add(payload: RawReactionActionEvent): + print("Reaction added") + if payload.emoji.name == "💀": + channel = client.get_channel(payload.channel_id) + message = await channel.fetch_message(payload.message_id) + type = "ADD" + await skullboard.handle_skullboard(client, message, SKULLBOARD_CHANNEL_ID, type) @client.event -async def on_reaction_remove(reaction: Reaction, user: User): - type = "REMOVE" - await skullboard.handle_skullboard(client, reaction, SKULLBOARD_CHANNEL_ID, type) +async def on_raw_reaction_remove(payload: RawReactionActionEvent): + print("Reaction removed") + if payload.emoji.name == "💀": + channel = client.get_channel(payload.channel_id) + message = await channel.fetch_message(payload.message_id) + type = "REMOVE" + await skullboard.handle_skullboard(client, message, SKULLBOARD_CHANNEL_ID, type) # Add the token of bot From 764aa128ac1a2bf7883e14722124fc11d3a78569 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Thu, 27 Jun 2024 17:39:16 +0930 Subject: [PATCH 04/22] chore: Replace utcnow with now --- src/commands/utils/time.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/utils/time.py b/src/commands/utils/time.py index 9e72a60..7db3385 100644 --- a/src/commands/utils/time.py +++ b/src/commands/utils/time.py @@ -4,6 +4,6 @@ def get_adelaide_time(): # Convert UTC timestamp to Adelaide time adelaide_tz = pytz.timezone('Australia/Adelaide') - utc_now = datetime.datetime.utcnow() - adelaide_time = utc_now.replace(tzinfo=pytz.utc).astimezone(adelaide_tz) + utc_now = datetime.datetime.now(pytz.utc) + adelaide_time = utc_now.astimezone(adelaide_tz) return adelaide_time From 548a16d53aef0be254336d761d92463e64ed5bed Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Thu, 27 Jun 2024 17:51:27 +0930 Subject: [PATCH 05/22] refactor: Move required reactions count and data file name to .env --- .example.env | 2 ++ src/commands/skullboard.py | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.example.env b/.example.env index 36e13e5..24118c0 100644 --- a/.example.env +++ b/.example.env @@ -1,3 +1,5 @@ GUILD_ID=GUILD_ID BOT_TOKEN="BOT_TOKEN" SKULLBOARD_CHANNEL_ID=SKULLBOARD_CHANNEL_ID +REQUIRED_REACTIONS=3 +DATA_FILE=skullboard_data.json \ No newline at end of file diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 43a27d6..effff03 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -1,10 +1,15 @@ import os import json from discord import Embed +from dotenv import load_dotenv from .utils.time import get_adelaide_time +# Load environment variables from .env file +load_dotenv() + # Global variable to store the path to the JSON file -DATA_FILE = 'skullboard_data.json' +DATA_FILE = os.getenv('DATA_FILE') +REQUIRED_REACTIONS = int(os.getenv('REQUIRED_REACTIONS')) # Initialise message_map message_map = {} @@ -49,7 +54,7 @@ async def handle_skullboard(client, message, SKULLBOARD_CHANNEL_ID, type): current_count = max(0, current_count - 1) message_map[message_id_str] = (skullboard_message_id, current_count) - if current_count > 0: + if current_count >= REQUIRED_REACTIONS: await update_or_send_skullboard_message(skullboard_channel, message, current_count, emoji) else: await delete_skullboard_message(skullboard_channel, message) From 4ea61a4dea88dae2fe80b39fd8804baa70e0f9b4 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Thu, 27 Jun 2024 18:34:21 +0930 Subject: [PATCH 06/22] refactor: Update skullboard message handling logic --- src/commands/skullboard.py | 32 +++----------------------------- src/main.py | 2 -- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index effff03..e829b3a 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -33,7 +33,6 @@ async def handle_skullboard(client, message, SKULLBOARD_CHANNEL_ID, type): skullboard_channel = client.get_channel(SKULLBOARD_CHANNEL_ID) if not skullboard_channel: - print(f"Skullboard channel not found with ID {SKULLBOARD_CHANNEL_ID}. Message could not be sent.") return emoji = "💀" @@ -54,10 +53,7 @@ async def handle_skullboard(client, message, SKULLBOARD_CHANNEL_ID, type): current_count = max(0, current_count - 1) message_map[message_id_str] = (skullboard_message_id, current_count) - if current_count >= REQUIRED_REACTIONS: - await update_or_send_skullboard_message(skullboard_channel, message, current_count, emoji) - else: - await delete_skullboard_message(skullboard_channel, message) + await update_or_send_skullboard_message(skullboard_channel, message, current_count, emoji) # Save the updated message_map to the JSON file after each modification save_data() @@ -67,17 +63,9 @@ async def update_or_send_skullboard_message(channel, message, current_count, emo skullboard_message_id, _ = message_map.get(str(message.id), (None, 0)) if skullboard_message_id: - await update_skullboard_message(channel, message, current_count, emoji, skullboard_message_id) + await edit_or_send_skullboard_message(channel, message, current_count, emoji, send=False, skullboard_message_id=skullboard_message_id) else: - await send_skullboard_message(channel, message, current_count, emoji) - -# Function to send skullboard message -async def send_skullboard_message(channel, message, current_count, emoji): - await edit_or_send_skullboard_message(channel, message, current_count, emoji, send=True) - -# Function to update skullboard message -async def update_skullboard_message(channel, message, current_count, emoji, skullboard_message_id): - await edit_or_send_skullboard_message(channel, message, current_count, emoji, send=False, skullboard_message_id=skullboard_message_id) + await edit_or_send_skullboard_message(channel, message, current_count, emoji, send=True) # Function to edit or send skullboard message async def edit_or_send_skullboard_message(channel, message, current_count, emoji, send=False, skullboard_message_id=None): @@ -105,17 +93,3 @@ async def edit_or_send_skullboard_message(channel, message, current_count, emoji # Save the updated message_map to the JSON file after each modification save_data() - -# Function to delete skullboard message -async def delete_skullboard_message(channel, message): - # Delete the Skullboard message - message_id_str = str(message.id) - if message_id_str in message_map: - skullboard_message_id, _ = message_map[message_id_str] - if skullboard_message_id: - skullboard_message = await channel.fetch_message(skullboard_message_id) - await skullboard_message.delete() - del message_map[message_id_str] - - # Save the updated message_map to the JSON file after each modification - save_data() diff --git a/src/main.py b/src/main.py index fb56dba..06d2e32 100644 --- a/src/main.py +++ b/src/main.py @@ -91,7 +91,6 @@ async def on_message(message: Message): # Register the reaction handling @client.event async def on_raw_reaction_add(payload: RawReactionActionEvent): - print("Reaction added") if payload.emoji.name == "💀": channel = client.get_channel(payload.channel_id) message = await channel.fetch_message(payload.message_id) @@ -100,7 +99,6 @@ async def on_raw_reaction_add(payload: RawReactionActionEvent): @client.event async def on_raw_reaction_remove(payload: RawReactionActionEvent): - print("Reaction removed") if payload.emoji.name == "💀": channel = client.get_channel(payload.channel_id) message = await channel.fetch_message(payload.message_id) From 1666f504ca17354152ac26cb9cd8f188ad1639a1 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Thu, 27 Jun 2024 19:25:58 +0930 Subject: [PATCH 07/22] fix: Use message time instead of current time --- poetry.lock | 13 +------------ pyproject.toml | 1 - src/commands/skullboard.py | 5 ++--- src/commands/utils/time.py | 9 --------- 4 files changed, 3 insertions(+), 25 deletions(-) delete mode 100644 src/commands/utils/time.py diff --git a/poetry.lock b/poetry.lock index 7eaf8c8..49d6cb7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -476,17 +476,6 @@ files = [ [package.extras] cli = ["click (>=5.0)"] -[[package]] -name = "pytz" -version = "2024.1" -description = "World timezone definitions, modern and historical" -optional = false -python-versions = "*" -files = [ - {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, - {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, -] - [[package]] name = "yarl" version = "1.9.4" @@ -593,4 +582,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "d3236891695e0c80dc622603c0069aa140c7cac4f9e3ffd9bfb2256fb217906c" +content-hash = "82ea93c36b144a94cab17365b523f0234f31d07261c00f959c49866748bdc901" diff --git a/pyproject.toml b/pyproject.toml index 9f68a2c..a664ddf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,6 @@ python = "^3.11" "discord.py" = "2.3.2" black = "^24.4.2" python-dotenv = "^1.0.1" -pytz = "^2024.1" [build-system] requires = ["poetry-core"] diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index e829b3a..4d01962 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -2,7 +2,6 @@ import json from discord import Embed from dotenv import load_dotenv -from .utils.time import get_adelaide_time # Load environment variables from .env file load_dotenv() @@ -71,7 +70,7 @@ async def update_or_send_skullboard_message(channel, message, current_count, emo async def edit_or_send_skullboard_message(channel, message, current_count, emoji, send=False, skullboard_message_id=None): # Format the message details channel_name = message.channel.name - adelaide_time = get_adelaide_time() + message_time = message.created_at mention = message.author.mention message_content = message.content message_link = message.jump_url @@ -80,7 +79,7 @@ async def edit_or_send_skullboard_message(channel, message, current_count, emoji embed = Embed( title=f"{current_count} {emoji} | #{channel_name}", description=f"{mention}\n\n{message_content}\n\n[Click to go to message!]({message_link})", - timestamp=adelaide_time + timestamp=message_time ) # Determine if sending or editing the message diff --git a/src/commands/utils/time.py b/src/commands/utils/time.py deleted file mode 100644 index 7db3385..0000000 --- a/src/commands/utils/time.py +++ /dev/null @@ -1,9 +0,0 @@ -import datetime -import pytz - -def get_adelaide_time(): - # Convert UTC timestamp to Adelaide time - adelaide_tz = pytz.timezone('Australia/Adelaide') - utc_now = datetime.datetime.now(pytz.utc) - adelaide_time = utc_now.astimezone(adelaide_tz) - return adelaide_time From 70d77ccb4b35eada749c84f1ec8a3208a202994c Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Sun, 7 Jul 2024 18:33:51 +0930 Subject: [PATCH 08/22] refactor: Move skullboard functions into a class --- src/commands/skullboard.py | 192 ++++++++++++++++++++----------------- src/main.py | 64 +++++++------ 2 files changed, 142 insertions(+), 114 deletions(-) diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 4d01962..92a4c75 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -1,94 +1,112 @@ import os import json -from discord import Embed +from discord import Embed, Client from dotenv import load_dotenv # Load environment variables from .env file load_dotenv() -# Global variable to store the path to the JSON file -DATA_FILE = os.getenv('DATA_FILE') -REQUIRED_REACTIONS = int(os.getenv('REQUIRED_REACTIONS')) - -# Initialise message_map -message_map = {} - -# Load existing data from JSON file if available -def load_data(): - global message_map - if os.path.exists(DATA_FILE): - with open(DATA_FILE, 'r') as f: - message_map = json.load(f) - -# Save data to JSON file -def save_data(): - with open(DATA_FILE, 'w') as f: - json.dump(message_map, f) - -# Function to handle reactions and update/delete skullboard messages -async def handle_skullboard(client, message, SKULLBOARD_CHANNEL_ID, type): - # Load data at the start - load_data() - - skullboard_channel = client.get_channel(SKULLBOARD_CHANNEL_ID) - if not skullboard_channel: - return - - emoji = "💀" - - # Convert message id to string to ensure consistency - message_id_str = str(message.id) - - # Update or delete Skullboard message based on reaction type - if message_id_str in message_map: - skullboard_message_id, current_count = message_map[message_id_str] - else: - skullboard_message_id = None - current_count = 0 - - if type == "ADD": - current_count += 1 - elif type == "REMOVE": - current_count = max(0, current_count - 1) - - message_map[message_id_str] = (skullboard_message_id, current_count) - await update_or_send_skullboard_message(skullboard_channel, message, current_count, emoji) - - # Save the updated message_map to the JSON file after each modification - save_data() - -# Function to update or send skullboard message -async def update_or_send_skullboard_message(channel, message, current_count, emoji): - skullboard_message_id, _ = message_map.get(str(message.id), (None, 0)) - - if skullboard_message_id: - await edit_or_send_skullboard_message(channel, message, current_count, emoji, send=False, skullboard_message_id=skullboard_message_id) - else: - await edit_or_send_skullboard_message(channel, message, current_count, emoji, send=True) - -# Function to edit or send skullboard message -async def edit_or_send_skullboard_message(channel, message, current_count, emoji, send=False, skullboard_message_id=None): - # Format the message details - channel_name = message.channel.name - message_time = message.created_at - mention = message.author.mention - message_content = message.content - message_link = message.jump_url - - # Constructing the embed - embed = Embed( - title=f"{current_count} {emoji} | #{channel_name}", - description=f"{mention}\n\n{message_content}\n\n[Click to go to message!]({message_link})", - timestamp=message_time - ) - - # Determine if sending or editing the message - if send: - skullboard_message = await channel.send(embed=embed) - message_map[str(message.id)] = (skullboard_message.id, current_count) - else: - skullboard_message = await channel.fetch_message(skullboard_message_id) - await skullboard_message.edit(embed=embed) - - # Save the updated message_map to the JSON file after each modification - save_data() +DATA_FILE = os.getenv("DATA_FILE") +REQUIRED_REACTIONS = int(os.getenv("REQUIRED_REACTIONS")) + + +class SkullboardManager: + def __init__(self, client: Client): + self.client = client + self.data_file = DATA_FILE + self.required_reactions = REQUIRED_REACTIONS + self.message_map = {} + self.load_data() + + # Load existing data from JSON file if available + def load_data(self): + if os.path.exists(self.data_file): + with open(self.data_file, "r", encoding="utf-8") as f: + self.message_map = json.load(f) + + # Save data to JSON file + def save_data(self): + with open(self.data_file, "w", encoding="utf-8") as f: + json.dump(self.message_map, f) + + # Function to handle reactions and update/delete skullboard messages + async def handle_skullboard(self, message, skullboard_channel_id, value): + skullboard_channel = self.client.get_channel(skullboard_channel_id) + if not skullboard_channel: + return + + emoji = "💀" + message_id_str = str(message.id) + + if message_id_str in self.message_map: + skullboard_message_id, current_count = self.message_map[message_id_str] + else: + skullboard_message_id = None + current_count = 0 + + if value == "ADD": + current_count += 1 + elif value == "REMOVE": + current_count = max(0, current_count - 1) + + self.message_map[message_id_str] = (skullboard_message_id, current_count) + await self.update_or_send_skullboard_message( + skullboard_channel, message, current_count, emoji + ) + self.save_data() + + # Function to update or send skullboard message + async def update_or_send_skullboard_message( + self, channel, message, current_count, emoji + ): + skullboard_message_id, _ = self.message_map.get(str(message.id), (None, 0)) + + if skullboard_message_id: + await self.edit_or_send_skullboard_message( + channel, + message, + current_count, + emoji, + send=False, + skullboard_message_id=skullboard_message_id, + ) + else: + await self.edit_or_send_skullboard_message( + channel, message, current_count, emoji, send=True + ) + + # Function to edit or send skullboard message + async def edit_or_send_skullboard_message( + self, + channel, + message, + current_count, + emoji, + send=False, + skullboard_message_id=None, + ): + # Format the message details + channel_name = message.channel.name + message_time = message.created_at + mention = message.author.mention + message_content = message.content + message_link = message.jump_url + + # Constructing the embed + embed = Embed( + title=f"{current_count} {emoji} | #{channel_name}", + description=f"{mention}\n\n{message_content}\n\n[Click to go to message!]({ + message_link})", + timestamp=message_time, + ) + + # Determine if sending or editing the message + if send: + skullboard_message = await channel.send(embed=embed) + self.message_map[str(message.id)] = (skullboard_message.id, current_count) + else: + skullboard_message = await channel.fetch_message(skullboard_message_id) + await skullboard_message.edit(embed=embed) + + # Save the updated message_map to the JSON file after each modification + self.save_data() diff --git a/src/main.py b/src/main.py index 06d2e32..6a17d28 100644 --- a/src/main.py +++ b/src/main.py @@ -2,9 +2,17 @@ from dotenv import load_dotenv import importlib import pkgutil -from discord import Intents, app_commands, Object, Interaction, Embed, Color, Message, RawReactionActionEvent +from discord import ( + Intents, + app_commands, + Object, + Interaction, + Embed, + Color, + RawReactionActionEvent, +) from discord.ext import commands -import commands.skullboard as skullboard +from commands import skullboard # Load environment variables from .env file load_dotenv() @@ -22,10 +30,14 @@ intents.reactions = True intents.members = True + class DuckBot(commands.Bot): def __init__(self): super().__init__(command_prefix="", intents=intents) self.synced = False # Make sure that the command tree will be synced only once + self.skullboard_manager = skullboard.SkullboardManager( + self + ) # Initialise SkullboardManager async def setup_hook(self): # Dynamically load all command groups from the commands directory @@ -43,6 +55,27 @@ async def setup_hook(self): async def on_ready(self): print(f"Say hi to {self.user}!") + # Override on_message method with correct parameters + async def on_message(self, message): + pass + + # Register the reaction handling + async def on_raw_reaction_add(self, payload: RawReactionActionEvent): + if payload.emoji.name == "💀": + channel = self.get_channel(payload.channel_id) + message = await channel.fetch_message(payload.message_id) + await self.skullboard_manager.handle_skullboard( + message, SKULLBOARD_CHANNEL_ID, "ADD" + ) + + async def on_raw_reaction_remove(self, payload: RawReactionActionEvent): + if payload.emoji.name == "💀": + channel = self.get_channel(payload.channel_id) + message = await channel.fetch_message(payload.message_id) + await self.skullboard_manager.handle_skullboard( + message, SKULLBOARD_CHANNEL_ID, "REMOVE" + ) + client = DuckBot() @@ -57,13 +90,13 @@ async def ping(interaction: Interaction): guild=Object(GUILD_ID), ) async def help(interaction: Interaction): - commands = list(client.tree.get_commands(guild=Object(GUILD_ID))) + commands_list = list(client.tree.get_commands(guild=Object(GUILD_ID))) embed = Embed( title="DuckBot", description="DuckBot is the CS Club's Discord bot, created by the CS Club Open Source Team.", color=Color.yellow(), ) - for command in commands: + for command in commands_list: if isinstance(command, app_commands.Group): # Add the group name embed.add_field( @@ -83,28 +116,5 @@ async def help(interaction: Interaction): await interaction.response.send_message(embed=embed) -# Ignore non-slash commands -@client.event -async def on_message(message: Message): - pass - -# Register the reaction handling -@client.event -async def on_raw_reaction_add(payload: RawReactionActionEvent): - if payload.emoji.name == "💀": - channel = client.get_channel(payload.channel_id) - message = await channel.fetch_message(payload.message_id) - type = "ADD" - await skullboard.handle_skullboard(client, message, SKULLBOARD_CHANNEL_ID, type) - -@client.event -async def on_raw_reaction_remove(payload: RawReactionActionEvent): - if payload.emoji.name == "💀": - channel = client.get_channel(payload.channel_id) - message = await channel.fetch_message(payload.message_id) - type = "REMOVE" - await skullboard.handle_skullboard(client, message, SKULLBOARD_CHANNEL_ID, type) - - # Add the token of bot client.run(BOT_TOKEN) From 5e29710ca3bf68c298dcdc5a30dc6cc30aae450b Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Sun, 7 Jul 2024 22:02:56 +0930 Subject: [PATCH 09/22] feat: Add user nickname and avatar to skullboard messages --- src/commands/skullboard.py | 39 +++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 92a4c75..6d55e36 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -49,7 +49,8 @@ async def handle_skullboard(self, message, skullboard_channel_id, value): elif value == "REMOVE": current_count = max(0, current_count - 1) - self.message_map[message_id_str] = (skullboard_message_id, current_count) + self.message_map[message_id_str] = ( + skullboard_message_id, current_count) await self.update_or_send_skullboard_message( skullboard_channel, message, current_count, emoji ) @@ -59,7 +60,8 @@ async def handle_skullboard(self, message, skullboard_channel_id, value): async def update_or_send_skullboard_message( self, channel, message, current_count, emoji ): - skullboard_message_id, _ = self.message_map.get(str(message.id), (None, 0)) + skullboard_message_id, _ = self.message_map.get( + str(message.id), (None, 0)) if skullboard_message_id: await self.edit_or_send_skullboard_message( @@ -85,28 +87,35 @@ async def edit_or_send_skullboard_message( send=False, skullboard_message_id=None, ): - # Format the message details - channel_name = message.channel.name - message_time = message.created_at - mention = message.author.mention - message_content = message.content - message_link = message.jump_url + # Fetch user's nickname and avatar url + guild = self.client.get_guild(message.guild.id) + member = guild.get_member(message.author.id) + user_nickname = member.nick if member.nick else message.author.name + user_avatar_url = message.author.avatar + + # Constructing the message content + message_jump_url = message.jump_url + message_content = f"{emoji} { + current_count} | {message_jump_url}" # Constructing the embed embed = Embed( - title=f"{current_count} {emoji} | #{channel_name}", - description=f"{mention}\n\n{message_content}\n\n[Click to go to message!]({ - message_link})", - timestamp=message_time, + description=( + f"{message.content}\n\n" + ), + timestamp=message.created_at, ) + # Set user nickname and thumbnail + embed.set_author(name=user_nickname, icon_url=user_avatar_url) # Determine if sending or editing the message if send: - skullboard_message = await channel.send(embed=embed) - self.message_map[str(message.id)] = (skullboard_message.id, current_count) + skullboard_message = await channel.send(message_content, embed=embed) + self.message_map[str(message.id)] = ( + skullboard_message.id, current_count) else: skullboard_message = await channel.fetch_message(skullboard_message_id) - await skullboard_message.edit(embed=embed) + await skullboard_message.edit(content=message_content, embed=embed) # Save the updated message_map to the JSON file after each modification self.save_data() From ae9ab6cf8ea0fe18af344176d820d21a7d750cb2 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Sun, 7 Jul 2024 22:06:04 +0930 Subject: [PATCH 10/22] fix: Ignore reactions to own messages --- src/main.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main.py b/src/main.py index 6a17d28..59a9a3b 100644 --- a/src/main.py +++ b/src/main.py @@ -64,17 +64,21 @@ async def on_raw_reaction_add(self, payload: RawReactionActionEvent): if payload.emoji.name == "💀": channel = self.get_channel(payload.channel_id) message = await channel.fetch_message(payload.message_id) - await self.skullboard_manager.handle_skullboard( - message, SKULLBOARD_CHANNEL_ID, "ADD" - ) + # Ignore reactions to own messages + if message.author.id != self.user.id: + await self.skullboard_manager.handle_skullboard( + message, SKULLBOARD_CHANNEL_ID, "ADD" + ) async def on_raw_reaction_remove(self, payload: RawReactionActionEvent): if payload.emoji.name == "💀": channel = self.get_channel(payload.channel_id) message = await channel.fetch_message(payload.message_id) - await self.skullboard_manager.handle_skullboard( - message, SKULLBOARD_CHANNEL_ID, "REMOVE" - ) + # Ignore reactions to own messages + if message.author.id != self.user.id: + await self.skullboard_manager.handle_skullboard( + message, SKULLBOARD_CHANNEL_ID, "REMOVE" + ) client = DuckBot() From e3a7b9ad7196f7779725d71f6f73befdf8277d8b Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Sun, 7 Jul 2024 22:06:36 +0930 Subject: [PATCH 11/22] style: Run Black --- src/commands/skullboard.py | 13 ++++--------- src/main.py | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 6d55e36..4366dcf 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -49,8 +49,7 @@ async def handle_skullboard(self, message, skullboard_channel_id, value): elif value == "REMOVE": current_count = max(0, current_count - 1) - self.message_map[message_id_str] = ( - skullboard_message_id, current_count) + self.message_map[message_id_str] = (skullboard_message_id, current_count) await self.update_or_send_skullboard_message( skullboard_channel, message, current_count, emoji ) @@ -60,8 +59,7 @@ async def handle_skullboard(self, message, skullboard_channel_id, value): async def update_or_send_skullboard_message( self, channel, message, current_count, emoji ): - skullboard_message_id, _ = self.message_map.get( - str(message.id), (None, 0)) + skullboard_message_id, _ = self.message_map.get(str(message.id), (None, 0)) if skullboard_message_id: await self.edit_or_send_skullboard_message( @@ -100,9 +98,7 @@ async def edit_or_send_skullboard_message( # Constructing the embed embed = Embed( - description=( - f"{message.content}\n\n" - ), + description=(f"{message.content}\n\n"), timestamp=message.created_at, ) # Set user nickname and thumbnail @@ -111,8 +107,7 @@ async def edit_or_send_skullboard_message( # Determine if sending or editing the message if send: skullboard_message = await channel.send(message_content, embed=embed) - self.message_map[str(message.id)] = ( - skullboard_message.id, current_count) + self.message_map[str(message.id)] = (skullboard_message.id, current_count) else: skullboard_message = await channel.fetch_message(skullboard_message_id) await skullboard_message.edit(content=message_content, embed=embed) diff --git a/src/main.py b/src/main.py index 59a9a3b..4e40b5e 100644 --- a/src/main.py +++ b/src/main.py @@ -65,7 +65,7 @@ async def on_raw_reaction_add(self, payload: RawReactionActionEvent): channel = self.get_channel(payload.channel_id) message = await channel.fetch_message(payload.message_id) # Ignore reactions to own messages - if message.author.id != self.user.id: + if message.author.id != self.user.id: await self.skullboard_manager.handle_skullboard( message, SKULLBOARD_CHANNEL_ID, "ADD" ) From 8e7ff02cd3d30874e3421a3b439c6c0c1a7ce0fc Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Mon, 8 Jul 2024 11:10:59 +0930 Subject: [PATCH 12/22] refactor: Make skullboard function without data file --- .example.env | 3 +- src/commands/skullboard.py | 86 ++++++++++++++++---------------------- src/main.py | 5 +-- 3 files changed, 38 insertions(+), 56 deletions(-) diff --git a/.example.env b/.example.env index 24118c0..a39bee7 100644 --- a/.example.env +++ b/.example.env @@ -1,5 +1,4 @@ GUILD_ID=GUILD_ID BOT_TOKEN="BOT_TOKEN" SKULLBOARD_CHANNEL_ID=SKULLBOARD_CHANNEL_ID -REQUIRED_REACTIONS=3 -DATA_FILE=skullboard_data.json \ No newline at end of file +REQUIRED_REACTIONS=5 \ No newline at end of file diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 4366dcf..726580e 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -1,79 +1,67 @@ import os -import json from discord import Embed, Client from dotenv import load_dotenv # Load environment variables from .env file load_dotenv() -DATA_FILE = os.getenv("DATA_FILE") REQUIRED_REACTIONS = int(os.getenv("REQUIRED_REACTIONS")) class SkullboardManager: def __init__(self, client: Client): self.client = client - self.data_file = DATA_FILE self.required_reactions = REQUIRED_REACTIONS - self.message_map = {} - self.load_data() - - # Load existing data from JSON file if available - def load_data(self): - if os.path.exists(self.data_file): - with open(self.data_file, "r", encoding="utf-8") as f: - self.message_map = json.load(f) - - # Save data to JSON file - def save_data(self): - with open(self.data_file, "w", encoding="utf-8") as f: - json.dump(self.message_map, f) # Function to handle reactions and update/delete skullboard messages - async def handle_skullboard(self, message, skullboard_channel_id, value): + async def handle_skullboard(self, message, skullboard_channel_id): skullboard_channel = self.client.get_channel(skullboard_channel_id) if not skullboard_channel: return emoji = "💀" - message_id_str = str(message.id) - - if message_id_str in self.message_map: - skullboard_message_id, current_count = self.message_map[message_id_str] - else: - skullboard_message_id = None - current_count = 0 - - if value == "ADD": - current_count += 1 - elif value == "REMOVE": - current_count = max(0, current_count - 1) + current_count = next( + ( + reaction.count + for reaction in message.reactions + if reaction.emoji == emoji + ), + 0, + ) - self.message_map[message_id_str] = (skullboard_message_id, current_count) await self.update_or_send_skullboard_message( skullboard_channel, message, current_count, emoji ) - self.save_data() # Function to update or send skullboard message async def update_or_send_skullboard_message( self, channel, message, current_count, emoji ): - skullboard_message_id, _ = self.message_map.get(str(message.id), (None, 0)) + skullboard_message_id = None + message_jump_url = message.jump_url - if skullboard_message_id: - await self.edit_or_send_skullboard_message( - channel, - message, - current_count, - emoji, - send=False, - skullboard_message_id=skullboard_message_id, - ) - else: - await self.edit_or_send_skullboard_message( - channel, message, current_count, emoji, send=True - ) + async for skullboard_message in channel.history(limit=100): + if message_jump_url in skullboard_message.content: + skullboard_message_id = skullboard_message.id + break + + if current_count >= self.required_reactions: + if skullboard_message_id: + await self.edit_or_send_skullboard_message( + channel, + message, + current_count, + emoji, + send=False, + skullboard_message_id=skullboard_message_id, + ) + else: + await self.edit_or_send_skullboard_message( + channel, message, current_count, emoji, send=True + ) + elif skullboard_message_id: + skullboard_message = await channel.fetch_message(skullboard_message_id) + await skullboard_message.delete() # Function to edit or send skullboard message async def edit_or_send_skullboard_message( @@ -98,7 +86,7 @@ async def edit_or_send_skullboard_message( # Constructing the embed embed = Embed( - description=(f"{message.content}\n\n"), + description=f"{message.content}\n\n", timestamp=message.created_at, ) # Set user nickname and thumbnail @@ -106,11 +94,7 @@ async def edit_or_send_skullboard_message( # Determine if sending or editing the message if send: - skullboard_message = await channel.send(message_content, embed=embed) - self.message_map[str(message.id)] = (skullboard_message.id, current_count) + await channel.send(message_content, embed=embed) else: skullboard_message = await channel.fetch_message(skullboard_message_id) await skullboard_message.edit(content=message_content, embed=embed) - - # Save the updated message_map to the JSON file after each modification - self.save_data() diff --git a/src/main.py b/src/main.py index 4e40b5e..c9b8738 100644 --- a/src/main.py +++ b/src/main.py @@ -17,7 +17,6 @@ # Load environment variables from .env file load_dotenv() -# Retrieve environment variables GUILD_ID = int(os.environ["GUILD_ID"]) BOT_TOKEN = os.environ["BOT_TOKEN"] SKULLBOARD_CHANNEL_ID = int(os.environ["SKULLBOARD_CHANNEL_ID"]) @@ -67,7 +66,7 @@ async def on_raw_reaction_add(self, payload: RawReactionActionEvent): # Ignore reactions to own messages if message.author.id != self.user.id: await self.skullboard_manager.handle_skullboard( - message, SKULLBOARD_CHANNEL_ID, "ADD" + message, SKULLBOARD_CHANNEL_ID ) async def on_raw_reaction_remove(self, payload: RawReactionActionEvent): @@ -77,7 +76,7 @@ async def on_raw_reaction_remove(self, payload: RawReactionActionEvent): # Ignore reactions to own messages if message.author.id != self.user.id: await self.skullboard_manager.handle_skullboard( - message, SKULLBOARD_CHANNEL_ID, "REMOVE" + message, SKULLBOARD_CHANNEL_ID ) From ca74746eee1999d24a5a16b0d0da17825f603b1b Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Mon, 8 Jul 2024 11:16:26 +0930 Subject: [PATCH 13/22] chore: Add colour to skullboard embed --- src/commands/skullboard.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 726580e..74f39fd 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -1,5 +1,5 @@ import os -from discord import Embed, Client +from discord import Embed, Client, Color from dotenv import load_dotenv # Load environment variables from .env file @@ -88,6 +88,7 @@ async def edit_or_send_skullboard_message( embed = Embed( description=f"{message.content}\n\n", timestamp=message.created_at, + colour=Color.from_rgb(204, 214, 221), ) # Set user nickname and thumbnail embed.set_author(name=user_nickname, icon_url=user_avatar_url) From bd1ea678910124560e965047506e9094a41e37bf Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Mon, 8 Jul 2024 11:26:07 +0930 Subject: [PATCH 14/22] chore: Update production workflow to use environment variables for skullboard --- .github/workflows/production.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 749bb71..156396c 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -54,6 +54,8 @@ jobs: USER: ${{ secrets.SSH_EC2_USER }} GUILD_ID: ${{ secrets.GUILD_ID }} BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + SKULLBOARD_CHANNEL_ID: ${{ secrets.SKULLBOARD_CHANNEL_ID }} + REQUIRED_REACTIONS: ${{ secrets.REQUIRED_REACTIONS }} run: | echo "$KEY" > private_key && chmod 600 private_key ssh -v -o StrictHostKeyChecking=no -i private_key ${USER}@${HOSTNAME} ' @@ -62,6 +64,8 @@ jobs: aws s3 cp s3://${{ secrets.AWS_S3_BUCKET }}/duckbot/docker-compose.yml . echo GUILD_ID=${{ secrets.GUILD_ID }} > .env echo BOT_TOKEN=${{ secrets.BOT_TOKEN }} >> .env + echo SKULLBOARD_CHANNEL_ID=${{ secrets.SKULLBOARD_CHANNEL_ID }} >> .env + echo REQUIRED_REACTIONS=${{ secrets.REQUIRED_REACTIONS }} >> .env docker load -i duckbot.tar.gz docker compose up -d ' From a3c5766f1e2e649fd533ca9ed959d978ebb9ff66 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Wed, 10 Jul 2024 13:34:44 +0930 Subject: [PATCH 15/22] feature: Support images, stickers, and gifs --- src/commands/skullboard.py | 51 +++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 74f39fd..d542b3c 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -1,4 +1,6 @@ import os +import requests +import re from discord import Embed, Client, Color from dotenv import load_dotenv @@ -63,6 +65,19 @@ async def update_or_send_skullboard_message( skullboard_message = await channel.fetch_message(skullboard_message_id) await skullboard_message.delete() + @staticmethod + async def get_gif_url(view_url): + # Get the page content + page_content = requests.get(view_url).text + + # Regex to find the URL on the media.tenor.com domain that ends with .gif + regex = r"(?i)\b((https?://media1[.]tenor[.]com/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))[.]gif)" + + # Find and return the first match + match = re.findall(regex, page_content) + + return match[0][0] if match else None + # Function to edit or send skullboard message async def edit_or_send_skullboard_message( self, @@ -77,12 +92,11 @@ async def edit_or_send_skullboard_message( guild = self.client.get_guild(message.guild.id) member = guild.get_member(message.author.id) user_nickname = member.nick if member.nick else message.author.name - user_avatar_url = message.author.avatar + user_avatar_url = message.author.avatar.url # Constructing the message content message_jump_url = message.jump_url - message_content = f"{emoji} { - current_count} | {message_jump_url}" + message_content = f"{emoji} {current_count} | {message_jump_url}" # Constructing the embed embed = Embed( @@ -90,9 +104,40 @@ async def edit_or_send_skullboard_message( timestamp=message.created_at, colour=Color.from_rgb(204, 214, 221), ) + + if message.content.startswith("https://tenor.com/view/"): + # Constructing the embed + embed = Embed( + timestamp=message.created_at, + colour=Color.from_rgb(204, 214, 221), + ) + + # Find the URL of the gif + gif_url = await self.get_gif_url(message.content) + + if gif_url: + embed.set_image(url=gif_url) + # Set user nickname and thumbnail embed.set_author(name=user_nickname, icon_url=user_avatar_url) + # Add images, stickers, and attachments + if message.stickers: + print(message.stickers[0].id) + print(message.stickers[0].format) + + # Replace the pattern with just the format type + format_type = str(message.stickers[0].format).split('.', maxsplit=1)[-1] + + sticker_id = message.stickers[0].id + sticker_url = f"https://media.discordapp.net/stickers/{ + sticker_id}.{format_type}" + print(sticker_url) + embed.set_image(url=sticker_url) + + if message.attachments: + embed.set_image(url=message.attachments[0].url) + # Determine if sending or editing the message if send: await channel.send(message_content, embed=embed) From 46a5a6d98d12c02d8a2bd8ad4c5294c78f37c68a Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Mon, 22 Jul 2024 15:46:27 +0930 Subject: [PATCH 16/22] fix: Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a664ddf..c1e9716 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ package-mode = false python = "^3.11" "discord.py" = "2.3.2" black = "^24.4.2" -python-dotenv = "^1.0.1" +poetry-dotenv-plugin = "^0.2.0" [build-system] requires = ["poetry-core"] From faca79ef1d55077afa32899d8280f56856b80e69 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Mon, 22 Jul 2024 15:46:43 +0930 Subject: [PATCH 17/22] style: Run Black --- src/commands/skullboard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index d542b3c..8c0c227 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -117,7 +117,7 @@ async def edit_or_send_skullboard_message( if gif_url: embed.set_image(url=gif_url) - + # Set user nickname and thumbnail embed.set_author(name=user_nickname, icon_url=user_avatar_url) @@ -127,7 +127,7 @@ async def edit_or_send_skullboard_message( print(message.stickers[0].format) # Replace the pattern with just the format type - format_type = str(message.stickers[0].format).split('.', maxsplit=1)[-1] + format_type = str(message.stickers[0].format).split(".", maxsplit=1)[-1] sticker_id = message.stickers[0].id sticker_url = f"https://media.discordapp.net/stickers/{ From ac631ccf43122c1dc6cab5667a22cdf86ad6d46c Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Mon, 22 Jul 2024 15:56:29 +0930 Subject: [PATCH 18/22] chore: Clean up code --- .gitignore | 2 -- src/commands/skullboard.py | 4 ---- src/main.py | 12 ++++++++++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index ea13935..51387d0 100644 --- a/.gitignore +++ b/.gitignore @@ -163,5 +163,3 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ - -skullboard_data.json diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 8c0c227..02f8d9f 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -123,16 +123,12 @@ async def edit_or_send_skullboard_message( # Add images, stickers, and attachments if message.stickers: - print(message.stickers[0].id) - print(message.stickers[0].format) - # Replace the pattern with just the format type format_type = str(message.stickers[0].format).split(".", maxsplit=1)[-1] sticker_id = message.stickers[0].id sticker_url = f"https://media.discordapp.net/stickers/{ sticker_id}.{format_type}" - print(sticker_url) embed.set_image(url=sticker_url) if message.attachments: diff --git a/src/main.py b/src/main.py index a3eb5a7..7135837 100644 --- a/src/main.py +++ b/src/main.py @@ -8,6 +8,7 @@ Interaction, Embed, Color, + Message, RawReactionActionEvent, ) from discord.ext import commands @@ -17,6 +18,7 @@ # Load environment variables from .env file load_dotenv() +# Retrieve guild ID and bot token from environment variables GUILD_ID = int(os.environ["GUILD_ID"]) BOT_TOKEN = os.environ["BOT_TOKEN"] SKULLBOARD_CHANNEL_ID = int(os.environ["SKULLBOARD_CHANNEL_ID"]) @@ -93,13 +95,13 @@ async def ping(interaction: Interaction): guild=Object(GUILD_ID), ) async def help(interaction: Interaction): - commands_list = list(client.tree.get_commands(guild=Object(GUILD_ID))) + commands = list(client.tree.get_commands(guild=Object(GUILD_ID))) embed = Embed( title="DuckBot", description="DuckBot is the CS Club's Discord bot, created by the CS Club Open Source Team.", color=Color.yellow(), ) - for command in commands_list: + for command in commands: if isinstance(command, app_commands.Group): # Add the group name embed.add_field( @@ -119,5 +121,11 @@ async def help(interaction: Interaction): await interaction.response.send_message(embed=embed) +# Ignore non-slash commands +@client.event +async def on_message(message: Message): + pass + + # Add the token of bot client.run(BOT_TOKEN) From 647bdbb4582d2e4aff82ac89533d7476683788b5 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Mon, 22 Jul 2024 16:14:41 +0930 Subject: [PATCH 19/22] feat: Handle video attachments --- src/commands/skullboard.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 02f8d9f..48ede28 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -132,7 +132,11 @@ async def edit_or_send_skullboard_message( embed.set_image(url=sticker_url) if message.attachments: - embed.set_image(url=message.attachments[0].url) + attachment = message.attachments[0] + if attachment.content_type.startswith("video"): + embed.add_field(name="", value=attachment.url) + else: + embed.set_image(url=attachment.url) # Determine if sending or editing the message if send: From 755dae365e9b1871449e7b75e5d0bd9f812ac280 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Tue, 23 Jul 2024 11:03:33 +0930 Subject: [PATCH 20/22] chore: Remove unneeded environment variables in production workflow --- .example.env | 2 +- .github/workflows/production.yml | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/.example.env b/.example.env index a39bee7..ad786a9 100644 --- a/.example.env +++ b/.example.env @@ -1,4 +1,4 @@ GUILD_ID=GUILD_ID BOT_TOKEN="BOT_TOKEN" SKULLBOARD_CHANNEL_ID=SKULLBOARD_CHANNEL_ID -REQUIRED_REACTIONS=5 \ No newline at end of file +REQUIRED_REACTIONS=5 diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 156396c..391132a 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -52,20 +52,12 @@ jobs: KEY: ${{ secrets.SSH_EC2_KEY }} HOSTNAME: ${{ secrets.SSH_EC2_HOSTNAME }} USER: ${{ secrets.SSH_EC2_USER }} - GUILD_ID: ${{ secrets.GUILD_ID }} - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - SKULLBOARD_CHANNEL_ID: ${{ secrets.SKULLBOARD_CHANNEL_ID }} - REQUIRED_REACTIONS: ${{ secrets.REQUIRED_REACTIONS }} run: | echo "$KEY" > private_key && chmod 600 private_key ssh -v -o StrictHostKeyChecking=no -i private_key ${USER}@${HOSTNAME} ' cd ~/duckbot aws s3 cp s3://${{ secrets.AWS_S3_BUCKET }}/duckbot/duckbot.tar.gz . aws s3 cp s3://${{ secrets.AWS_S3_BUCKET }}/duckbot/docker-compose.yml . - echo GUILD_ID=${{ secrets.GUILD_ID }} > .env - echo BOT_TOKEN=${{ secrets.BOT_TOKEN }} >> .env - echo SKULLBOARD_CHANNEL_ID=${{ secrets.SKULLBOARD_CHANNEL_ID }} >> .env - echo REQUIRED_REACTIONS=${{ secrets.REQUIRED_REACTIONS }} >> .env docker load -i duckbot.tar.gz docker compose up -d ' From bb267aaab943fadd251bc7fa7cf1cd854a22e8f6 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Tue, 23 Jul 2024 12:29:12 +0930 Subject: [PATCH 21/22] refactor: Improve code organisation and readability based on feedback --- src/commands/skullboard.py | 41 ++++++++++++++++++++------------------ src/constants/colours.py | 3 +++ 2 files changed, 25 insertions(+), 19 deletions(-) create mode 100644 src/constants/colours.py diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 48ede28..2de4d9a 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -1,28 +1,21 @@ import os import requests import re -from discord import Embed, Client, Color +from discord import Embed, Client from dotenv import load_dotenv - -# Load environment variables from .env file -load_dotenv() - -REQUIRED_REACTIONS = int(os.getenv("REQUIRED_REACTIONS")) +from constants.colours import LIGHT_GREY class SkullboardManager: def __init__(self, client: Client): + """Initialise SkullboardManager""" + load_dotenv() # Load environment variables from .env file self.client = client - self.required_reactions = REQUIRED_REACTIONS - - # Function to handle reactions and update/delete skullboard messages - async def handle_skullboard(self, message, skullboard_channel_id): - skullboard_channel = self.client.get_channel(skullboard_channel_id) - if not skullboard_channel: - return + self.required_reactions = int(os.getenv("REQUIRED_REACTIONS")) - emoji = "💀" - current_count = next( + async def get_reaction_count(self, message, emoji): + """Get count of a specific emoji reaction on a message""" + return next( ( reaction.count for reaction in message.reactions @@ -31,14 +24,23 @@ async def handle_skullboard(self, message, skullboard_channel_id): 0, ) + async def handle_skullboard(self, message, skullboard_channel_id): + """Handle reactions and update/delete skullboard messages""" + skullboard_channel = self.client.get_channel(skullboard_channel_id) + if not skullboard_channel: + return + + emoji = "💀" + current_count = await self.get_reaction_count(message, emoji) + await self.update_or_send_skullboard_message( skullboard_channel, message, current_count, emoji ) - # Function to update or send skullboard message async def update_or_send_skullboard_message( self, channel, message, current_count, emoji ): + """Update or send skullboard message""" skullboard_message_id = None message_jump_url = message.jump_url @@ -67,6 +69,7 @@ async def update_or_send_skullboard_message( @staticmethod async def get_gif_url(view_url): + """Get URL of GIF from a Tenor view URL""" # Get the page content page_content = requests.get(view_url).text @@ -78,7 +81,6 @@ async def get_gif_url(view_url): return match[0][0] if match else None - # Function to edit or send skullboard message async def edit_or_send_skullboard_message( self, channel, @@ -88,6 +90,7 @@ async def edit_or_send_skullboard_message( send=False, skullboard_message_id=None, ): + """Edit or send a skullboard message""" # Fetch user's nickname and avatar url guild = self.client.get_guild(message.guild.id) member = guild.get_member(message.author.id) @@ -102,14 +105,14 @@ async def edit_or_send_skullboard_message( embed = Embed( description=f"{message.content}\n\n", timestamp=message.created_at, - colour=Color.from_rgb(204, 214, 221), + colour=LIGHT_GREY, ) if message.content.startswith("https://tenor.com/view/"): # Constructing the embed embed = Embed( timestamp=message.created_at, - colour=Color.from_rgb(204, 214, 221), + colour=LIGHT_GREY, ) # Find the URL of the gif diff --git a/src/constants/colours.py b/src/constants/colours.py new file mode 100644 index 0000000..0073a8e --- /dev/null +++ b/src/constants/colours.py @@ -0,0 +1,3 @@ +from discord import Color + +LIGHT_GREY = Color.from_rgb(204, 214, 221) From 4329460cda8dd77f29a966241028635f5aeaf1d1 Mon Sep 17 00:00:00 2001 From: Phoenix Isaac Pereira Date: Tue, 23 Jul 2024 15:03:05 +0930 Subject: [PATCH 22/22] style: Seperate imports by type --- src/commands/skullboard.py | 2 ++ src/main.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/commands/skullboard.py b/src/commands/skullboard.py index 2de4d9a..132e9c6 100644 --- a/src/commands/skullboard.py +++ b/src/commands/skullboard.py @@ -1,8 +1,10 @@ import os import requests import re + from discord import Embed, Client from dotenv import load_dotenv + from constants.colours import LIGHT_GREY diff --git a/src/main.py b/src/main.py index 7135837..490c914 100644 --- a/src/main.py +++ b/src/main.py @@ -1,6 +1,7 @@ import os import importlib import pkgutil + from discord import ( Intents, app_commands, @@ -12,9 +13,10 @@ RawReactionActionEvent, ) from discord.ext import commands -from commands import skullboard from dotenv import load_dotenv +from commands import skullboard + # Load environment variables from .env file load_dotenv()