├── .flake8 ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── config.yml │ └── feature.yml ├── red_data │ ├── cogs │ │ └── CogManager │ │ │ └── settings.json │ └── core │ │ └── settings.json └── workflows │ ├── checks.yml │ ├── loadcheck.yml │ ├── release.yml │ ├── scripts │ ├── loadcheck.py │ ├── release.py │ └── syncutils.py │ └── syncutils.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yaml ├── .stubs ├── asyncache │ └── __init__.pyi ├── dislash │ ├── __init__.pyi │ ├── application_commands │ │ ├── __init__.pyi │ │ ├── _decohub.pyi │ │ ├── _modifications │ │ │ ├── __init__.pyi │ │ │ ├── new.pyi │ │ │ └── old.pyi │ │ ├── context_menus_core.pyi │ │ ├── core.pyi │ │ ├── errors.pyi │ │ ├── slash_client.pyi │ │ ├── slash_core.pyi │ │ └── utils.pyi │ ├── interactions │ │ ├── __init__.pyi │ │ ├── app_command_interaction.pyi │ │ ├── application_command.pyi │ │ ├── interaction.pyi │ │ ├── message_components.pyi │ │ ├── message_interaction.pyi │ │ └── slash_interaction.pyi │ └── slash_commands │ │ ├── __init__.pyi │ │ ├── _decohub.pyi │ │ ├── _modifications │ │ ├── new.pyi │ │ └── old.pyi │ │ ├── errors.pyi │ │ ├── slash_client.pyi │ │ ├── slash_command.pyi │ │ ├── slash_core.pyi │ │ └── utils.pyi ├── markdownify.pyi ├── psutil │ ├── __init__.pyi │ └── _common.pyi ├── pyjson5.pyi ├── pytrends │ ├── exceptions.pyi │ └── request.pyi ├── rapidfuzz │ ├── __init__.pyi │ └── process.pyi └── wakeonlan.pyi ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── aliases ├── __init__.py ├── aliases.py ├── info.json └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── anotherpingcog ├── __init__.py ├── anotherpingcog.py ├── info.json ├── objects.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── autoping ├── __init__.py ├── autoping.py ├── info.json └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── beautify ├── __init__.py ├── beautify.py ├── errors.py ├── info.json ├── utils.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── betteruptime ├── __init__.py ├── abc.py ├── betteruptime.py ├── commands.py ├── consts.py ├── info.json ├── loop.py ├── plot.py ├── slash.py ├── utils.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── birthday ├── __init__.py ├── abc.py ├── birthday.py ├── commands.py ├── components │ └── setup.py ├── consts.py ├── converters.py ├── info.json ├── loop.py ├── utils.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── bump.py ├── buttonpoll ├── __init__.py ├── buttonpoll.py ├── components │ ├── poll.py │ └── setup.py ├── info.json ├── poll.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── calc ├── __init__.py ├── calc.py ├── info.json ├── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py └── view.py ├── caseinsensitive ├── __init__.py ├── caseinsensitive.py ├── fakealias.py ├── info.json └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── cmdlog ├── __init__.py ├── channellogger.py ├── cmdlog.py ├── info.json ├── objects.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── covidgraph ├── __init__.py └── info.json ├── dev-requirements.txt ├── docs ├── Makefile ├── _templates │ └── footer.html ├── changelog.rst ├── cogs │ ├── aliases.rst │ ├── anotherpingcog.rst │ ├── autoping.rst │ ├── beautify.rst │ ├── betteruptime.rst │ ├── birthday.rst │ ├── buttonpoll.rst │ ├── calc.rst │ ├── caseinsensitive.rst │ ├── cmdlog.rst │ ├── covidgraph.rst │ ├── fivemstatus.rst │ ├── ghissues.rst │ ├── github.rst │ ├── googletrends.rst │ ├── madtranslate.rst │ ├── resources │ │ ├── all.png │ │ ├── latest.png │ │ └── webhook.png │ ├── roleplay.rst │ ├── stattrack.rst │ ├── status.rst │ ├── statusref.rst │ ├── system.rst │ ├── timechannel.rst │ ├── uptimeresponder.rst │ └── wol.rst ├── conf.py ├── getting_started.rst ├── index.rst ├── make.bat ├── requirements.txt ├── statusdev.rst └── trends_geos.rst ├── fivemstatus ├── __init__.py ├── abc.py ├── fivemstatus.py ├── info.json ├── loop.py ├── objects.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── ghissues ├── __init__.py ├── api.py ├── consts.py ├── errors.py ├── format.py ├── ghissues.py ├── info.json ├── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py └── views │ ├── label.py │ ├── master.py │ ├── merge.py │ ├── merge_confirm.py │ └── utils.py ├── github ├── __init__.py └── info.json ├── googletrends ├── __init__.py ├── abc.py ├── consts.py ├── converters.py ├── errors.py ├── googletrends.py ├── info.json ├── plot.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── info.json ├── madtranslate ├── __init__.py ├── info.json ├── langs.py ├── madtranslate.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── pyproject.toml ├── roleplay ├── __init__.py ├── info.json ├── roleplay.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── stattrack ├── __init__.py ├── abc.py ├── commands.py ├── components │ └── view.py ├── consts.py ├── converters.py ├── driver.py ├── info.json ├── plot.py ├── stattrack.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── status ├── __init__.py ├── commands │ ├── command.py │ ├── components.py │ ├── converters.py │ ├── status_com.py │ ├── statusdev_com.py │ └── statusset_com.py ├── core │ ├── __init__.py │ ├── abc.py │ ├── consts.py │ ├── core.py │ └── statusapi.py ├── info.json ├── objects │ ├── __init__.py │ ├── caches.py │ ├── channel.py │ ├── configwrapper.py │ ├── incidentdata.py │ ├── sendcache.py │ └── typeddict.py ├── updateloop │ ├── __init__.py │ ├── processfeed.py │ ├── sendupdate.py │ ├── updatechecker.py │ └── utils.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── system ├── __init__.py ├── backend.py ├── command.py ├── components │ └── view.py ├── info.json ├── system.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── tests ├── __init__.py ├── consts.py ├── info.json └── test_status.py ├── timechannel ├── __init__.py ├── abc.py ├── converters.py ├── data.py ├── info.json ├── loop.py ├── timechannel.py ├── utils.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py ├── tox.ini ├── uptimeresponder ├── __init__.py ├── info.json ├── uptimeresponder.py └── vexutils │ ├── README.md │ ├── __init__.py │ ├── button_pred.py │ ├── chat.py │ ├── commit.json │ ├── consts.py │ ├── loop.py │ ├── meta.py │ ├── py.typed │ ├── sqldriver.py │ ├── url_buttons.py │ └── version.py └── wol ├── __init__.py ├── info.json ├── vexutils ├── README.md ├── __init__.py ├── button_pred.py ├── chat.py ├── commit.json ├── consts.py ├── loop.py ├── meta.py ├── py.typed ├── sqldriver.py ├── url_buttons.py └── version.py └── wol.py /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = W503,E203,E402 3 | per-file-ignores = __init__.py:F401,consts.py:E501 4 | max-line-length = 99 5 | exclude = .git,.venv,.tox,__pycache__,docs,vexutils 6 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @Vexed01 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | description: "File a bug report" 2 | labels: ["type: bug"] 3 | name: "Bug Report" 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | ### Thanks for taking the time to make an issue! 9 | If you want general support please ask in the Red Cog Support server at https://discord.gg/GET4DVk 10 | - type: input 11 | id: cog-name 12 | attributes: 13 | label: "What cog is this bug report for?" 14 | placeholder: "Enter the name of the cog" 15 | validations: 16 | required: true 17 | - type: textarea 18 | id: vers 19 | attributes: 20 | description: "Please enter the first code block of the command `[p]info` where `[p]` is your prefix and `` is the name of the cog in lower case.\nFor example, if the cog is called `Status` run `[p]statusinfo`.\nYou can skip this if the cog doesn't load." 21 | label: "What versions are you running?" 22 | placeholder: "Copy and paste the first codeblock here" 23 | render: "yes please" 24 | validations: 25 | required: false 26 | - type: textarea 27 | id: desc 28 | attributes: 29 | description: "Please go into as much detail as possible and, if you can, show steps to reproduce it. If there's an error, paste it in the next box below." 30 | label: "Describe the bug" 31 | validations: 32 | required: true 33 | - type: textarea 34 | id: logs 35 | attributes: 36 | description: "Please copy and paste any relevant log output either from the console or using the `[p]traceback` command. This will be automatically formatted into code, so no need for backticks." 37 | label: "If there's an error, paste it here" 38 | render: python 39 | validations: 40 | required: false 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - name: General Support 3 | url: https://discord.gg/GD43Nb9H86 4 | about: For support questions please ask in the Red - Cog Support (#support_vex-cogs) 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.yml: -------------------------------------------------------------------------------- 1 | description: "File a feature request" 2 | labels: ["type: enhancement"] 3 | name: "Feature request" 4 | body: 5 | - type: input 6 | id: cog-name 7 | attributes: 8 | label: "What cog is this feature request for?" 9 | placeholder: "Enter the name of the cog" 10 | validations: 11 | required: true 12 | - type: textarea 13 | id: desc 14 | attributes: 15 | label: "Describe the feature request in as much detail as possible" 16 | placeholder: "The more information the better!" 17 | validations: 18 | required: true 19 | -------------------------------------------------------------------------------- /.github/red_data/cogs/CogManager/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "2938473984732": { 3 | "GLOBAL": { 4 | "paths": [ 5 | "C:\\Data\\Git\\Vex-Cogs", 6 | "/home/runner/work/Vex-Cogs/Vex-Cogs" 7 | ] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/red_data/core/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "0": { 3 | "CUSTOM_GROUPS": {}, 4 | "GLOBAL": { 5 | "prefix": [ 6 | "!" 7 | ], 8 | "schema_version": 2 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.github/workflows/checks.yml: -------------------------------------------------------------------------------- 1 | name: Checks 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | # thanks red or wherever you got it from 10 | jobs: 11 | tox: 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | python_version: 16 | - "3.8" 17 | - "3.11" 18 | tox_env: 19 | - style-black 20 | - style-isort 21 | - lint-flake8 22 | # - type-pyright 23 | - docs 24 | - pytest 25 | include: 26 | - tox_env: style-black 27 | friendly_name: Style (black) 28 | - tox_env: style-isort 29 | friendly_name: Style (isort) 30 | - tox_env: lint-flake8 31 | friendly_name: Lint (flake8) 32 | # - tox_env: type-pyright 33 | # friendly_name: Type check (pyright) 34 | - tox_env: docs 35 | friendly_name: Docs 36 | - tox_env: pytest 37 | friendly_name: Tests 38 | 39 | fail-fast: false 40 | 41 | name: Tox - ${{ matrix.python_version }} - ${{ matrix.friendly_name }} 42 | steps: 43 | - uses: actions/checkout@v3 44 | with: 45 | ref: ${{ env.ref }} 46 | - name: Set up Python ${{ matrix.python_version }} 47 | uses: actions/setup-python@v4 48 | with: 49 | python-version: ${{ matrix.python_version }} 50 | 51 | # caching cuts down time for tox (for example black) from ~40 secs to 4 52 | - name: Cache tox 53 | uses: actions/cache@v3 54 | with: 55 | path: .tox 56 | key: tox-${{ matrix.python_version }}-${{ matrix.tox_env }}-${{ hashFiles('tox.ini') }} 57 | 58 | - name: Install tox 59 | run: | 60 | python -m pip install --upgrade pip 61 | pip install tox 62 | 63 | - name: "Run tox: ${{ matrix.friendly_name }}" 64 | env: 65 | TOXENV: ${{ matrix.tox_env }} 66 | run: | 67 | tox 68 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Cog release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | python-version: ["3.11"] 14 | 15 | name: Release 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - name: Set up Python ${{ matrix.python-version }} 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: 3.11 23 | 24 | - name: Install dependencies 25 | run: | 26 | pip install gitpython requests 27 | 28 | - name: Set up git 29 | run: | 30 | git config user.name "actions-user" 31 | git config user.email "" 32 | 33 | - name: Run script release.py 34 | run: | 35 | python .github/workflows/scripts/release.py 36 | env: 37 | CF_KV: ${{ secrets.CF_KV }} 38 | -------------------------------------------------------------------------------- /.github/workflows/scripts/release.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import re 4 | 5 | import requests 6 | from git import Repo 7 | 8 | # hello person looking at my code 9 | # i chose not to do releases as they are "repo-wide"... but then so are tags. tags just feel less 10 | # sorta... invasive. idk. 11 | 12 | TAG_MESSAGE = """ 13 | Created with GitHub Actions. 14 | 15 | The changelog can be found at 16 | https://cogdocs.vexcodes.com/en/latest/changelog.html#{cogname} 17 | 18 | This is an automatically created tag based of the following commit: 19 | {commit} 20 | """ 21 | 22 | repo = Repo() # repo in working dir 23 | 24 | regex = re.compile(r"\[(\w+) (\d+\.\d+\.\d+)\]") 25 | 26 | latest_commit = repo.head.commit.message 27 | print("Most recent commit detected as: " + latest_commit) 28 | 29 | match = regex.match(latest_commit) 30 | if match is None or len(list(match.groups())) != 2: 31 | print("Most recent commit does not match regex, nothing to do.") 32 | else: 33 | print("Commit matches regex.") 34 | cog = match.group(1).lower() 35 | if cog == "apc": 36 | cog = "anotherpingcog" 37 | ver = match.group(2) 38 | 39 | print("Creating and pushing new tag...") 40 | tag_name = f"{cog}-{ver}" 41 | repo.create_tag(tag_name, message=TAG_MESSAGE.format(cogname=cog, commit=latest_commit)) 42 | repo.remote().push(f"refs/tags/{tag_name}") 43 | print(f"Pushed a new tag {tag_name} to GitHub.") 44 | 45 | token = os.environ["CF_KV"] 46 | headers = { 47 | "Authorization": f"Bearer {token}", 48 | "Content-Type": "text/plain", 49 | } 50 | 51 | url = ( 52 | "https://api.cloudflare.com/client/v4/accounts/5d6844358ea26524bf29b35cb98628f5/" 53 | "storage/kv/namespaces/10cca0f984d143768bf7f23ee276f5e0/values/cogs" 54 | ) 55 | data = requests.get(url, headers=headers).json() 56 | data[cog] = ver 57 | requests.put(url, headers=headers, data=json.dumps(data)) 58 | print("Updated Cloudflare KV.") 59 | 60 | print("Script finished.") 61 | -------------------------------------------------------------------------------- /.github/workflows/syncutils.yml: -------------------------------------------------------------------------------- 1 | name: Sync utils 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | syncutils: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | python-version: ["3.11"] 11 | 12 | name: Sync utils 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Set up Python ${{ matrix.python-version }} 17 | uses: actions/setup-python@v4 18 | with: 19 | python-version: ${{ matrix.python-version }} 20 | 21 | - name: Install dependencies 22 | run: | 23 | pip install gitpython requests 24 | 25 | - name: Run script syncutils.py 26 | run: | 27 | python .github/workflows/scripts/syncutils.py 28 | env: 29 | CF_KV: ${{ secrets.CF_KV}} 30 | 31 | - name: "Commit and push changes" 32 | uses: stefanzweifel/git-auto-commit-action@v4 33 | with: 34 | commit_message: Automated utils sync 35 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v2.3.0 4 | hooks: 5 | - id: check-ast 6 | - id: check-json 7 | - id: pretty-format-json 8 | args: ["--autofix", "--indent", "4"] 9 | - id: end-of-file-fixer 10 | - id: mixed-line-ending 11 | - repo: https://github.com/psf/black 12 | rev: "22.3.0" 13 | hooks: 14 | - id: black 15 | - repo: https://github.com/PyCQA/isort 16 | rev: "5.8.0" 17 | hooks: 18 | - id: isort 19 | - repo: https://github.com/myint/autoflake 20 | rev: "v1.4" 21 | hooks: 22 | - id: autoflake 23 | args: 24 | [ 25 | "--in-place", 26 | "--remove-unused-variables", 27 | "--remove-all-unused-imports", 28 | "--ignore-init-module-imports", 29 | ] 30 | - repo: https://github.com/pycqa/flake8 31 | rev: "3.9.2" 32 | hooks: 33 | - id: flake8 34 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: "3.11" 7 | 8 | sphinx: 9 | configuration: docs/conf.py 10 | 11 | python: 12 | install: 13 | - requirements: docs/requirements.txt 14 | -------------------------------------------------------------------------------- /.stubs/asyncache/__init__.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | import functools 6 | import inspect 7 | 8 | from cachetools import Cache, keys 9 | 10 | """ 11 | Helpers to use [cachetools](https://github.com/tkem/cachetools) with 12 | asyncio. 13 | """ 14 | __all__ = ["cached"] 15 | 16 | class nullcontext: 17 | """A class for noop context managers.""" 18 | 19 | def __enter__(self): # -> Self@nullcontext: 20 | """Return ``self`` upon entering the runtime context.""" 21 | ... 22 | def __exit__(self, exc_type, exc_value, traceback): # -> None: 23 | """Raise any exception triggered within the runtime context.""" 24 | ... 25 | async def __aenter__(self): # -> Self@nullcontext: 26 | """Return ``self`` upon entering the runtime context.""" 27 | ... 28 | async def __aexit__(self, exc_type, exc_value, traceback): # -> None: 29 | """Raise any exception triggered within the runtime context.""" 30 | ... 31 | 32 | def cached(cache: Cache, key=..., lock=...): 33 | """ 34 | Decorator to wrap a function or a coroutine with a memoizing callable 35 | that saves results in a cache. 36 | 37 | When ``lock`` is provided for a standard function, it's expected to 38 | implement ``__enter__`` and ``__exit__`` that will be used to lock 39 | the cache when gets updated. If it wraps a coroutine, ``lock`` 40 | must implement ``__aenter__`` and ``__aexit__``. 41 | """ 42 | ... 43 | -------------------------------------------------------------------------------- /.stubs/dislash/__init__.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | from .application_commands import * 6 | from .interactions import * 7 | 8 | __version__ = ... 9 | slash_commands = application_commands 10 | -------------------------------------------------------------------------------- /.stubs/dislash/application_commands/__init__.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | from .context_menus_core import * 6 | from .core import * 7 | from .errors import * 8 | from .slash_client import * 9 | from .slash_core import * 10 | from .utils import * 11 | -------------------------------------------------------------------------------- /.stubs/dislash/application_commands/_decohub.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | class _HANDLER: 6 | client = ... 7 | slash_commands = ... 8 | user_commands = ... 9 | message_commands = ... 10 | -------------------------------------------------------------------------------- /.stubs/dislash/application_commands/_modifications/__init__.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | -------------------------------------------------------------------------------- /.stubs/dislash/application_commands/_modifications/old.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | from discord import Message 6 | 7 | __all__ = ( 8 | "create_message_with_components", 9 | "send_with_components", 10 | "edit_with_components", 11 | "MessageWithComponents", 12 | ) 13 | 14 | def create_message_with_components(self, *, channel, data): ... 15 | def send_message( 16 | self, 17 | channel_id, 18 | content, 19 | *, 20 | tts=..., 21 | embed=..., 22 | nonce=..., 23 | allowed_mentions=..., 24 | message_reference=..., 25 | components=..., 26 | ): ... 27 | def send_files( 28 | self, 29 | channel_id, 30 | *, 31 | files, 32 | content=..., 33 | tts=..., 34 | embed=..., 35 | nonce=..., 36 | allowed_mentions=..., 37 | message_reference=..., 38 | components=..., 39 | ): ... 40 | async def send_with_components( 41 | messageable, 42 | content=..., 43 | *, 44 | tts=..., 45 | embed=..., 46 | components=..., 47 | file=..., 48 | files=..., 49 | delete_after=..., 50 | nonce=..., 51 | allowed_mentions=..., 52 | reference=..., 53 | mention_author=..., 54 | ): ... 55 | async def edit_with_components(message, **fields): ... 56 | 57 | class MessageWithComponents(Message): 58 | def __init__(self, *, state, channel, data) -> None: ... 59 | def __repr__(self): ... 60 | -------------------------------------------------------------------------------- /.stubs/dislash/application_commands/context_menus_core.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | from .core import InvokableApplicationCommand 6 | 7 | __all__ = ( 8 | "InvokableContextMenuCommand", 9 | "InvokableUserCommand", 10 | "InvokableMessageCommand", 11 | "user_command", 12 | "message_command", 13 | ) 14 | 15 | class InvokableContextMenuCommand(InvokableApplicationCommand): 16 | def __init__(self, func, *, name=..., guild_ids=..., **kwargs) -> None: ... 17 | async def invoke(self, interaction): ... 18 | 19 | class InvokableUserCommand(InvokableContextMenuCommand): 20 | def __init__(self, func, *, name=..., guild_ids=..., **kwargs) -> None: ... 21 | 22 | class InvokableMessageCommand(InvokableContextMenuCommand): 23 | def __init__(self, func, *, name=..., guild_ids=..., **kwargs) -> None: ... 24 | 25 | def user_command(*args, **kwargs): # -> (func: Unknown) -> InvokableUserCommand: 26 | """ 27 | A decorator that allows to build a user command, visible in a context menu. 28 | 29 | Parameters 30 | ---------- 31 | name : :class:`str` 32 | name of the user command you want to respond to (equals to function name by default). 33 | guild_ids : :class:`List[int]` 34 | if specified, the client will register the command in these guilds. 35 | Otherwise this command will be registered globally. 36 | """ 37 | ... 38 | 39 | def message_command(*args, **kwargs): # -> (func: Unknown) -> InvokableMessageCommand: 40 | """ 41 | A decorator that allows to build a message command, visible in a context menu. 42 | 43 | Parameters 44 | ---------- 45 | name : :class:`str` 46 | name of the user command you want to respond to (equals to function name by default). 47 | guild_ids : :class:`List[int]` 48 | if specified, the client will register the command in these guilds. 49 | Otherwise this command will be registered globally. 50 | """ 51 | ... 52 | -------------------------------------------------------------------------------- /.stubs/dislash/interactions/__init__.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | from .app_command_interaction import * 6 | from .application_command import * 7 | from .interaction import * 8 | from .message_components import * 9 | from .message_interaction import * 10 | -------------------------------------------------------------------------------- /.stubs/dislash/interactions/message_interaction.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | from .interaction import * 6 | from .message_components import * 7 | 8 | __all__ = ("MessageInteraction", "ButtonInteraction") 9 | 10 | class PartialTextChannel: 11 | def __init__(self, channel_id) -> None: ... 12 | 13 | class MessageInteraction(BaseInteraction): 14 | """ 15 | Represents a button interaction. 16 | Obtainable via :class:`discord.Context.wait_for_button_click` 17 | and in ``on_button_click`` event. 18 | 19 | Attributes 20 | ---------- 21 | author : :class:`discord.Member` | :class:`discord.User` 22 | The user that clicked the button 23 | channel : :class:`discord.Messageable` 24 | The channel where the click happened 25 | guild : :class:`discord.Guild` | ``None`` 26 | The guild where the click happened 27 | message : :class:`discord.Message` 28 | The message where the button was clicked 29 | components : :class:`list` 30 | A list of :class:`ActionRow` instances containing other components 31 | component : :class:`Component` 32 | The component that author interacted with 33 | """ 34 | 35 | def __init__(self, client, data) -> None: ... 36 | @property 37 | def clicked_button(self) -> Button: ... 38 | @property 39 | def button(self) -> Button: ... 40 | @property 41 | def select_menu(self) -> SelectMenu: ... 42 | 43 | ButtonInteraction = MessageInteraction 44 | -------------------------------------------------------------------------------- /.stubs/dislash/slash_commands/__init__.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | from .errors import * 6 | from .slash_client import * 7 | from .slash_command import * 8 | from .slash_core import * 9 | from .utils import * 10 | -------------------------------------------------------------------------------- /.stubs/dislash/slash_commands/_decohub.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | class _HANDLER: 6 | client = ... 7 | commands = ... 8 | -------------------------------------------------------------------------------- /.stubs/dislash/slash_commands/_modifications/old.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | __all__ = ("send_with_components", "edit_with_components") 6 | 7 | def send_message( 8 | self, 9 | channel_id, 10 | content, 11 | *, 12 | tts=..., 13 | embed=..., 14 | nonce=..., 15 | allowed_mentions=..., 16 | message_reference=..., 17 | components=..., 18 | ): ... 19 | def send_files( 20 | self, 21 | channel_id, 22 | *, 23 | files, 24 | content=..., 25 | tts=..., 26 | embed=..., 27 | nonce=..., 28 | allowed_mentions=..., 29 | message_reference=..., 30 | components=..., 31 | ): ... 32 | async def send_with_components( 33 | messageable, 34 | content=..., 35 | *, 36 | tts=..., 37 | embed=..., 38 | components=..., 39 | file=..., 40 | files=..., 41 | delete_after=..., 42 | nonce=..., 43 | allowed_mentions=..., 44 | reference=..., 45 | mention_author=..., 46 | ): ... 47 | async def edit_with_components(message, **fields): ... 48 | -------------------------------------------------------------------------------- /.stubs/dislash/slash_commands/errors.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | from discord import DiscordException 6 | 7 | class SlashCommandError(DiscordException): 8 | """ 9 | The base exception type for all slash-command related errors. 10 | 11 | This inherits from :exc:`discord.DiscordException`. 12 | 13 | This exception and exceptions inherited from it are handled 14 | in a special way as they are caught and passed into a special event 15 | from :class:`.SlashClient`, :func:`on_slash_command_error`. 16 | """ 17 | 18 | def __init__(self, message=..., *args) -> None: ... 19 | 20 | class BadArgument(SlashCommandError): ... 21 | class SlashCheckFailure(SlashCommandError): ... 22 | 23 | class CheckAnyFailure(SlashCheckFailure): 24 | def __init__(self, checks, errors) -> None: ... 25 | 26 | class PrivateMessageOnly(SlashCheckFailure): 27 | def __init__(self, message=...) -> None: ... 28 | 29 | class NoPrivateMessage(SlashCheckFailure): 30 | def __init__(self, message=...) -> None: ... 31 | 32 | class NotOwner(SlashCheckFailure): ... 33 | 34 | class CommandOnCooldown(SlashCommandError): 35 | """Exception raised when the slash-command being invoked is on cooldown. 36 | 37 | This inherits from `SlashCommandError` 38 | 39 | ## Attributes 40 | 41 | `cooldown`: `Cooldown` (a class with attributes `rate`, `per`, and `type`) 42 | 43 | `retry_after`: `float` (the amount of seconds to wait before you can retry again) 44 | """ 45 | 46 | def __init__(self, cooldown, retry_after) -> None: ... 47 | 48 | class NotGuildOwner(SlashCommandError): ... 49 | 50 | class MissingRole(SlashCheckFailure): 51 | def __init__(self, missing_role) -> None: ... 52 | 53 | class BotMissingRole(SlashCheckFailure): 54 | def __init__(self, missing_role) -> None: ... 55 | 56 | class MissingAnyRole(SlashCheckFailure): 57 | def __init__(self, missing_roles) -> None: ... 58 | 59 | class BotMissingAnyRole(SlashCheckFailure): 60 | def __init__(self, missing_roles) -> None: ... 61 | 62 | class NSFWChannelRequired(SlashCheckFailure): 63 | def __init__(self, channel) -> None: ... 64 | 65 | class MissingPermissions(SlashCheckFailure): 66 | def __init__(self, missing_perms, *args) -> None: ... 67 | 68 | class BotMissingPermissions(SlashCheckFailure): 69 | def __init__(self, missing_perms, *args) -> None: ... 70 | -------------------------------------------------------------------------------- /.stubs/markdownify.pyi: -------------------------------------------------------------------------------- 1 | def markdownify(html: str, **options) -> str: ... 2 | -------------------------------------------------------------------------------- /.stubs/psutil/_common.pyi: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | 3 | sdiskpart = namedtuple( 4 | "sdiskpart", ["device", "mountpoint", "fstype", "opts", "maxfile", "maxpath"] 5 | ) 6 | sdiskusage = namedtuple("sdiskusage", ["total", "used", "free", "percent"]) 7 | suser = namedtuple("suser", ["name", "terminal", "host", "started", "pid"]) 8 | snetio = namedtuple( 9 | "snetio", 10 | [ 11 | "bytes_sent", 12 | "bytes_recv", 13 | "packets_sent", 14 | "packets_recv", 15 | "errin", 16 | "errout", 17 | "dropin", 18 | "dropout", 19 | ], 20 | ) 21 | -------------------------------------------------------------------------------- /.stubs/pyjson5.pyi: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | def decode(data: str, maxdepth: Optional[int] = ..., some: bool = ...) -> object: ... 4 | -------------------------------------------------------------------------------- /.stubs/pytrends/exceptions.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This type stub file was generated by pyright. 3 | """ 4 | 5 | import requests 6 | 7 | class ResponseError(Exception): 8 | """Something was wrong with the response from Google""" 9 | 10 | response: requests.Response 11 | def __init__(self, message, response) -> None: ... 12 | -------------------------------------------------------------------------------- /.stubs/rapidfuzz/__init__.pyi: -------------------------------------------------------------------------------- 1 | from rapidfuzz import process as process 2 | -------------------------------------------------------------------------------- /.stubs/rapidfuzz/process.pyi: -------------------------------------------------------------------------------- 1 | from typing import Callable, Iterable, Optional, Tuple 2 | 3 | # type hints from docs, assume score_cutoff is meant to be float from source and also assuming 4 | # the last 2 return values in the tuple 5 | 6 | def extractOne( 7 | query: str, 8 | choices: Iterable, 9 | scorer: Callable = ..., 10 | processor: Callable = ..., 11 | score_cutoff: float = ..., 12 | **kwargs, 13 | ) -> Optional[Tuple[str, float, int]]: ... 14 | -------------------------------------------------------------------------------- /.stubs/wakeonlan.pyi: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | BROADCAST_IP: str 4 | DEFAULT_PORT: int 5 | 6 | def create_magic_packet(macaddress: str) -> bytes: ... 7 | def send_magic_packet(*macs: str, ip_address: str = ..., port: int = ...) -> None: ... 8 | def main(argv: List[str] = ...) -> None: ... 9 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Vex-Cogs 2 | 3 | Thanks for taking the time to look into contributing! Whether you'll open an issue or PR, or do something else, _everything_ is appreciated. 4 | 5 | To avoid wasting time, it's sometimes best to speak to me in Discord (`@vexingvexed`) or create an Issue before making non-trivial Pull Requests. 6 | 7 | Not much else to say really, just this: 8 | 9 | ## Checks 10 | 11 | When you open a PR, they'll be some basic checks to make sure the style is consistent so other checks that nothing's broken. 12 | 13 | **You do not need to set up pre-commit or similar locally for smaller PRs**, as GitHub Actions will let you know if there's an issue with details in the logs. However, you may need to use black or isort. 14 | 15 | Pyright (or Pylance if you're using VS Code) is used for type checking. 16 | 17 | The config files in the repo will let you run any style checks and type checking without arguments. 18 | 19 | ## pre-commit 20 | 21 | I've set up pre-commit. This will ensure your code conforms to the correct style when you commit changes. 22 | 23 | To use it, simply run this: 24 | 25 | pip install pre-commit 26 | 27 | pre-commit install 28 | 29 | It will now automatically run on every commit. 30 | 31 | ## tox 32 | 33 | If you would like, you can run (almost) the full test suite using `tox` 34 | 35 | 1. If you haven't already, install tox: 36 | 37 | pip install tox 38 | 39 | 2. Now run tox: 40 | 41 | tox 42 | -------------------------------------------------------------------------------- /aliases/__init__.py: -------------------------------------------------------------------------------- 1 | import json 2 | from pathlib import Path 3 | 4 | from redbot.core.bot import Red 5 | 6 | from .aliases import Aliases 7 | from .vexutils.meta import out_of_date_check 8 | 9 | with open(Path(__file__).parent / "info.json", encoding="utf8") as fp: 10 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 11 | 12 | 13 | async def setup(bot: Red) -> None: 14 | cog = Aliases(bot) 15 | await out_of_date_check("aliases", cog.__version__) 16 | 17 | await bot.add_cog(cog) 18 | -------------------------------------------------------------------------------- /aliases/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Get all the information you could ever need about a command's aliases. IF YOU ARE TRYING TO *MAKE* ALIASES, JUST USE THE CORE 'alias` COG.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "\\N{WARNING SIGN}\\N{VARIATION SELECTOR-16}\nThis cog reads the config of the alias cog. This means it might break without much notice.\n\nIf you are just trying to **make aliases**: this cog isn't for that. Use the core `alias` cog to make and manage aliases with the `[p]load alias` command, then `[p]help alias`.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "Aliases", 16 | "requirements": [], 17 | "short": "Get all the information you could ever need about a command's aliases. IF YOU ARE TRYING TO *MAKE* ALIASES, JUST USE THE CORE 'alias` COG.", 18 | "tags": [ 19 | "utility", 20 | "alias" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /aliases/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /aliases/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /aliases/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /aliases/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /aliases/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/aliases/vexutils/py.typed -------------------------------------------------------------------------------- /aliases/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /aliases/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /anotherpingcog/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | 8 | from . import vexutils 9 | from .anotherpingcog import setup 10 | 11 | with open(Path(__file__).parent / "info.json") as fp: 12 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 13 | -------------------------------------------------------------------------------- /anotherpingcog/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Replace the ping command with a rich embed that shows ping time and message time. It is colour coded: red, orange and green, and the bot owner can customise the colours and emojis for different latency levels, as well as force an embed.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing! This cog will replace the normal `ping` command. The bot owner can customise the colours and emojis for different latency levels, as well as force an embed with use `[p]pingset`.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "AnotherPingCog", 16 | "requirements": [ 17 | "tabulate" 18 | ], 19 | "short": "Just another ping cog... But this one has fancy colours in an embed the bot owner can customise!", 20 | "tags": [ 21 | "utility", 22 | "ping", 23 | "pingtime" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /anotherpingcog/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /anotherpingcog/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /anotherpingcog/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /anotherpingcog/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /anotherpingcog/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/anotherpingcog/vexutils/py.typed -------------------------------------------------------------------------------- /anotherpingcog/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /anotherpingcog/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /autoping/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .autoping import AutoPing 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red): 18 | cog = AutoPing(bot) 19 | await out_of_date_check("autoping", cog.__version__) 20 | await bot.add_cog(cog) 21 | -------------------------------------------------------------------------------- /autoping/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Do you ever forget to check for messages in a channel? This cog automatically pings a user/role when a message is sent in a channel.", 7 | "end_user_data_statement": "This cog stores the channel ID and role/user ID for each channel that has a ping set. No other data is stored.", 8 | "install_msg": "Thanks for installing! Once you've loaded the cog, get started with `[p]autoping add`\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "AutoPing", 16 | "requirements": [], 17 | "short": "Automatically ping a user/role when a message is sent in a channel.", 18 | "tags": [ 19 | "utility", 20 | "ping", 21 | "mention" 22 | ] 23 | } -------------------------------------------------------------------------------- /autoping/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /autoping/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /autoping/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /autoping/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /autoping/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/autoping/vexutils/py.typed -------------------------------------------------------------------------------- /autoping/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /autoping/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /beautify/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .beautify import Beautify 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red): 18 | cog = Beautify(bot) 19 | await out_of_date_check("beautify", cog.__version__) 20 | await bot.add_cog(cog) 21 | -------------------------------------------------------------------------------- /beautify/errors.py: -------------------------------------------------------------------------------- 1 | class NoData(Exception): 2 | """ 3 | No argument or file was passed 4 | 5 | Has child errors AttachmentPermsError and AttachmentInvalid 6 | """ 7 | 8 | # i think "child errors" might not be the right thing to say but oh well (PR a fix if you want) 9 | 10 | 11 | class AttachmentPermsError(NoData): 12 | """Can't access attachment""" 13 | 14 | 15 | class AttachmentInvalid(NoData): 16 | """Attachment has wrong file type""" 17 | 18 | 19 | class JSONDecodeError(Exception): 20 | """Custom decoding error for either pyjson5 or json modules""" 21 | -------------------------------------------------------------------------------- /beautify/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Beautify and minify JSON. Supports attachments, codeblocks and replies.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "This cog has two commands - `beautify` and `minify`.\n\n**If you would like this cog to support Python dicts as well as normal JSON, please run this command with your prefix ([p]) replaced: `[p]pipinstall pyjson5`. This should work on Linux, but it can error on Windows. It is not required for the cog so don't worry if it does error.**\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "Beautify", 16 | "requirements": [], 17 | "short": "Beautify and minify JSON. Supports attachments, codeblocks and replies.", 18 | "tags": [ 19 | "utility", 20 | "json" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /beautify/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /beautify/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /beautify/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /beautify/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /beautify/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/beautify/vexutils/py.typed -------------------------------------------------------------------------------- /beautify/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /beautify/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /betteruptime/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | 8 | from . import vexutils 9 | from .betteruptime import setup 10 | 11 | with open(Path(__file__).parent / "info.json") as fp: 12 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 13 | -------------------------------------------------------------------------------- /betteruptime/abc.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from abc import ABC, ABCMeta, abstractmethod 3 | from typing import TYPE_CHECKING 4 | 5 | import pandas 6 | from redbot.core import commands 7 | from redbot.core.bot import Red 8 | from redbot.core.config import Config 9 | 10 | from .vexutils.loop import VexLoop 11 | 12 | if TYPE_CHECKING: 13 | from betteruptime.utils import UptimeData 14 | 15 | 16 | class CompositeMetaClass(commands.CogMeta, ABCMeta): 17 | """ 18 | This allows the metaclass used for proper type detection to 19 | coexist with discord.py's metaclass 20 | """ 21 | 22 | 23 | class MixinMeta(ABC): 24 | """A wonderful class for typehinting :tada:""" 25 | 26 | bot: Red 27 | config: Config 28 | 29 | main_loop_meta: VexLoop 30 | main_loop: asyncio.Task 31 | 32 | last_known_ping: float 33 | last_ping_change: float 34 | 35 | first_load: float 36 | 37 | cog_loaded_cache: pandas.Series 38 | connected_cache: pandas.Series 39 | 40 | ready: asyncio.Event 41 | 42 | @abstractmethod 43 | async def get_data(self, num_days: int) -> "UptimeData": 44 | raise NotImplementedError 45 | 46 | @abstractmethod 47 | async def uptime_command(self, ctx: commands.Context, days: int = 30) -> None: 48 | raise NotImplementedError 49 | 50 | @abstractmethod 51 | async def downtime(self, ctx: commands.Context, days: int = 30) -> None: 52 | raise NotImplementedError 53 | 54 | @abstractmethod 55 | async def uptimegraph(self, ctx: commands.Context, days: int = 30) -> None: 56 | raise NotImplementedError 57 | -------------------------------------------------------------------------------- /betteruptime/consts.py: -------------------------------------------------------------------------------- 1 | INF = float("inf") 2 | 3 | SECONDS_IN_DAY = 86400 4 | 5 | 6 | CROSS = "\N{CROSS MARK}" 7 | 8 | WARN = "\N{WARNING SIGN}\N{VARIATION SELECTOR-16}" 9 | -------------------------------------------------------------------------------- /betteruptime/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Replace the uptime command with a rich embed that shows the bot's percentage uptime (both time of the bot being on and time connected to Discord). There is also a new `downtime` command which shows when downtime happened. This cog writes to config every 60 seconds to prevent data loss. It is also very storage efficient, using under 150 bytes each day the cog runs.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing! This cog will replace the default `uptime` command once you load it.\n\nWhilst the cog will start showing data from first load, it will ignore today's data from tomorrow onwards. Once the cog's been running for a while, data over 30 days old will no longer be counted in the `uptime` command.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "BetterUptime", 16 | "requirements": [ 17 | "pandas", 18 | "plotly", 19 | "kaleido" 20 | ], 21 | "short": "A better uptime command that tracks the bot's uptime as a percentage over the last 30 days, and has a new `downtime` command that shows when downtime happened.", 22 | "tags": [ 23 | "utility", 24 | "uptime", 25 | "meta" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /betteruptime/slash.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from redbot.core import app_commands, commands 3 | 4 | from .abc import MixinMeta 5 | 6 | 7 | class BUSlash(MixinMeta): 8 | uptime = app_commands.Group(name="uptime", description="Get my uptime data") 9 | 10 | @uptime.command(name="data", description="Get my uptime data in an embed") 11 | @app_commands.describe(days="Days of data to show, use 0 for all-time data. Default: 30") 12 | async def uptime_slash(self, interaction: discord.Interaction, days: int = 30): 13 | context: commands.Context = await self.bot.get_context(interaction) 14 | await self.uptime_command(context) 15 | 16 | @uptime.command(name="graph", description="Get my uptime graph in an embed") 17 | @app_commands.describe(days="Days of data to show, use 0 for all-time data. Default: 30") 18 | async def uptimegraph_slash(self, interaction: discord.Interaction, days: int = 30): 19 | context: commands.Context = await self.bot.get_context(interaction) 20 | await self.uptimegraph(context) 21 | 22 | @uptime.command(name="downtime", description="Get my downtime data in an embed") 23 | @app_commands.describe(days="Days of data to show, use 0 for all-time data. Default: 30") 24 | async def downtime_slash(self, interaction: discord.Interaction, days: int = 30): 25 | context: commands.Context = await self.bot.get_context(interaction) 26 | await self.downtime(context) 27 | -------------------------------------------------------------------------------- /betteruptime/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /betteruptime/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /betteruptime/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /betteruptime/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /betteruptime/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/betteruptime/vexutils/py.typed -------------------------------------------------------------------------------- /betteruptime/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /betteruptime/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /birthday/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .birthday import Birthday 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json", encoding="utf8") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red) -> None: 18 | cog = Birthday(bot) 19 | await out_of_date_check("birthday", cog.__version__) 20 | await bot.add_cog(cog) 21 | -------------------------------------------------------------------------------- /birthday/abc.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import asyncio 4 | from abc import ABC, ABCMeta, abstractmethod 5 | from typing import Coroutine 6 | 7 | import discord 8 | from redbot.core.bot import Red 9 | from redbot.core.commands import CogMeta 10 | from redbot.core.config import Config 11 | 12 | from .vexutils.loop import VexLoop 13 | 14 | 15 | class CompositeMetaClass(CogMeta, ABCMeta): 16 | """ 17 | This allows the metaclass used for proper type detection to 18 | coexist with discord.py's metaclass 19 | """ 20 | 21 | 22 | class MixinMeta(ABC): 23 | """A wonderful class for typehinting :tada:""" 24 | 25 | bot: Red 26 | config: Config 27 | 28 | loop_meta: VexLoop 29 | loop: asyncio.Task 30 | role_manager: asyncio.Task 31 | 32 | ready: asyncio.Event 33 | 34 | coro_queue: asyncio.Queue[Coroutine] 35 | 36 | @abstractmethod 37 | async def check_if_setup(self, guild: discord.Guild) -> bool: 38 | raise NotImplementedError 39 | 40 | @abstractmethod 41 | async def birthday_loop(self) -> None: 42 | raise NotImplementedError 43 | 44 | @abstractmethod 45 | async def birthday_role_manager(self) -> None: 46 | raise NotImplementedError 47 | -------------------------------------------------------------------------------- /birthday/consts.py: -------------------------------------------------------------------------------- 1 | MIN_BDAY_YEAR = 1900 2 | 3 | MAX_BDAY_MSG_LEN = 750 4 | -------------------------------------------------------------------------------- /birthday/converters.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import TYPE_CHECKING 3 | 4 | from dateutil.parser import ParserError, parse 5 | from redbot.core.commands import BadArgument, Context, Converter 6 | 7 | from .vexutils import get_vex_logger 8 | 9 | log = get_vex_logger(__name__) 10 | 11 | 12 | if TYPE_CHECKING: 13 | BirthdayConverter = datetime.datetime 14 | TimeConverter = datetime.datetime 15 | else: 16 | 17 | class BirthdayConverter(Converter): 18 | async def convert(self, ctx: Context, argument: str) -> datetime.datetime: 19 | log.trace("attempting to parse date %s", argument) 20 | try: 21 | default = datetime.datetime(year=1, month=1, day=1) 22 | log.trace("parsed date: %s", argument) 23 | out = parse(argument, default=default, ignoretz=True).replace( 24 | hour=0, minute=0, second=0, microsecond=0 25 | ) 26 | 27 | return out 28 | except ParserError: 29 | if ctx.interaction: 30 | raise BadArgument("That's not a valid date. Example: `1 Jan` or `1 Jan 2000`.") 31 | raise BadArgument( 32 | f"That's not a valid date. See {ctx.clean_prefix}help" 33 | f" {ctx.command.qualified_name} for more information." 34 | ) 35 | 36 | class TimeConverter(Converter): 37 | async def convert(self, ctx: Context, argument: str) -> datetime.datetime: 38 | log.trace("attempting to parse time %s", argument) 39 | try: 40 | out = parse(argument, ignoretz=True).replace( 41 | year=1, month=1, day=1, minute=0, second=0, microsecond=0 42 | ) 43 | log.trace("parsed time: %s", argument) 44 | return out 45 | except ParserError: 46 | if ctx.interaction: 47 | raise BadArgument("That's not a valid time.") 48 | raise BadArgument( 49 | f"That's not a valid time. See {ctx.clean_prefix}help" 50 | f" {ctx.command.qualified_name} for more information." 51 | ) 52 | -------------------------------------------------------------------------------- /birthday/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Get users to add their birthday, then on their birthday they will get a special role. Server owners can set the time of day, announcement message and role.", 7 | "end_user_data_statement": "This cog will associate a User ID with a birthday if the user explicitly sets it. This data is also associated with a specific guild ID. No other data or metadata about users is stored.", 8 | "install_msg": "Thanks for installing! You can set the cog up with `[p]bdset interactive`, then your members can use `[p]bday set `.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "Birthday", 16 | "requirements": [], 17 | "short": "Birthday cog with customisable roles, messages and times.", 18 | "tags": [ 19 | "birthday", 20 | "birthdays", 21 | "bday", 22 | "fun", 23 | "role" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /birthday/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from discord import Member, Role 4 | from discord.abc import GuildChannel 5 | 6 | 7 | def format_bday_message(message: str, author: Member, new_age: int | None = None) -> str: 8 | """Format the birthday message. 9 | 10 | Parameters 11 | ---------- 12 | message : str 13 | Unformatted message from Config 14 | 15 | role : discord.Role 16 | Birthday role 17 | 18 | Returns 19 | ------- 20 | str 21 | Formatted message 22 | """ 23 | if new_age: 24 | return message.format(mention=author.mention, name=author.display_name, new_age=new_age) 25 | else: 26 | return message.format(mention=author.mention, name=author.display_name) 27 | 28 | 29 | def role_perm_check(me: Member, role: Role) -> str: 30 | """Check if I have the correct permissions for this to be the Birthday role. 31 | 32 | Parameters 33 | ---------- 34 | me : discord.Member 35 | My user object 36 | 37 | role : discord.Role 38 | Role to check 39 | 40 | Returns 41 | ------- 42 | str 43 | Error message or empty string 44 | """ 45 | if me.top_role.position <= role.position: 46 | return ( 47 | "I don't have the required role position. Make sure my role is above the birthday" 48 | " role." 49 | ) 50 | if me.guild_permissions.manage_roles is False: 51 | return "I don't have the Manage Roles permission." 52 | return "" 53 | 54 | 55 | def channel_perm_check(me: Member, channel: GuildChannel) -> str: 56 | """Check if I have the correct permissions for this to be the Birthday channel. 57 | 58 | Parameters 59 | ---------- 60 | me : discord.Member 61 | My user object 62 | 63 | channel : discord.TextChannel 64 | Channel to check 65 | 66 | Returns 67 | ------- 68 | str 69 | Error message or empty string 70 | """ 71 | if channel.permissions_for(me).send_messages is False: 72 | return "I don't have the Send Messages permission." 73 | return "" 74 | -------------------------------------------------------------------------------- /birthday/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /birthday/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /birthday/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /birthday/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /birthday/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/birthday/vexutils/py.typed -------------------------------------------------------------------------------- /birthday/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /birthday/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /buttonpoll/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | import discord 7 | from redbot.core import VersionInfo 8 | from redbot.core.bot import Red 9 | from redbot.core.errors import CogLoadError 10 | 11 | from . import vexutils 12 | from .buttonpoll import ButtonPoll 13 | from .vexutils.meta import out_of_date_check 14 | 15 | with open(Path(__file__).parent / "info.json") as fp: 16 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 17 | 18 | 19 | async def setup(bot: Red): 20 | cog = ButtonPoll(bot) 21 | await out_of_date_check("buttonpoll", cog.__version__) 22 | await bot.add_cog(cog) 23 | -------------------------------------------------------------------------------- /buttonpoll/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "end_user_data_statement": "This cog stores user IDs paired with guild IDs and how they voted if a user participated in a poll. This is to ensure no double voting can happen. This data is removed once a poll finishes. No other data or metadata about users is persistently stored. This cog respects data deletion requests.", 7 | "install_msg": "Thanks for installing! Load the cog and get started with the `buttonpoll` command.\n\nThis cog has docs! Check them out at ", 8 | "min_bot_version": "3.5.1", 9 | "min_python_version": [ 10 | 3, 11 | 8, 12 | 1 13 | ], 14 | "name": "ButtonPoll", 15 | "requirements": [ 16 | "plotly", 17 | "kaleido", 18 | "pandas" 19 | ], 20 | "short": "A poll in Discord, but with powered by buttons and with a pie chart at the end!", 21 | "tags": [ 22 | "utility", 23 | "poll", 24 | "button" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /buttonpoll/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /buttonpoll/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /buttonpoll/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /buttonpoll/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /buttonpoll/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/buttonpoll/vexutils/py.typed -------------------------------------------------------------------------------- /buttonpoll/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /buttonpoll/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /calc/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | import discord 7 | from redbot.core import VersionInfo 8 | from redbot.core.bot import Red 9 | from redbot.core.errors import CogLoadError 10 | 11 | from . import vexutils 12 | from .calc import Calc 13 | from .vexutils.meta import out_of_date_check 14 | 15 | with open(Path(__file__).parent / "info.json", encoding="utf8") as fp: 16 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 17 | 18 | 19 | async def setup(bot: Red) -> None: 20 | cog = Calc(bot) 21 | await out_of_date_check("calculator", cog.__version__) 22 | await bot.add_cog(cog) 23 | -------------------------------------------------------------------------------- /calc/calc.py: -------------------------------------------------------------------------------- 1 | from redbot.core import commands 2 | from redbot.core.bot import Red 3 | 4 | from .vexutils import format_help, format_info 5 | from .view import CalcView 6 | 7 | 8 | class Calc(commands.Cog): 9 | """Calculate simple mathematical expressions.""" 10 | 11 | __version__ = "0.0.2" 12 | __author__ = "@vexingvexed" 13 | 14 | def __init__(self, bot: Red) -> None: 15 | self.bot = bot 16 | 17 | def format_help_for_context(self, ctx: commands.Context) -> str: 18 | """Thanks Sinbad.""" 19 | return format_help(self, ctx) 20 | 21 | async def red_delete_data_for_user(self, **kwargs) -> None: 22 | """Nothing to delete""" 23 | return 24 | 25 | @commands.command(hidden=True) 26 | async def calcinfo(self, ctx: commands.Context): 27 | await ctx.send(await format_info(ctx, self.qualified_name, self.__version__)) 28 | 29 | @commands.command() 30 | async def calc(self, ctx: commands.Context): 31 | """ 32 | Start an interactive calculator using buttons. 33 | """ 34 | view = CalcView(self.bot, ctx.author.id) 35 | embed = await view.build_embed(await ctx.embed_colour()) 36 | message = await ctx.send(embed=embed, view=view) 37 | view.message = message 38 | view.ready.set() 39 | -------------------------------------------------------------------------------- /calc/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Calculate simple mathematical expressions, right in Discord with buttons.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing! Load the cog and get started with the `calculator` command.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "Calc", 16 | "requirements": [ 17 | "expr.py", 18 | "asyncache" 19 | ], 20 | "short": "Calculate simple mathematical expressions, right in Discord with buttons.", 21 | "tags": [ 22 | "utility", 23 | "calc", 24 | "math", 25 | "maths" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /calc/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /calc/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /calc/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /calc/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /calc/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/calc/vexutils/py.typed -------------------------------------------------------------------------------- /calc/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /calc/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /caseinsensitive/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import contextlib 4 | import importlib 5 | import json 6 | from pathlib import Path 7 | 8 | from redbot.core import VersionInfo 9 | from redbot.core.bot import Red 10 | from redbot.core.errors import CogLoadError 11 | 12 | from . import vexutils 13 | from .caseinsensitive import CaseInsensitive 14 | from .vexutils.meta import out_of_date_check 15 | 16 | with open(Path(__file__).parent / "info.json") as fp: 17 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 18 | 19 | INCOMPATIBLE_COGS: list[str] = [""] 20 | 21 | 22 | async def setup(bot: Red): 23 | for cog in INCOMPATIBLE_COGS: 24 | if cog in bot.cogs: 25 | raise CogLoadError(f"Cog {cog} is incompatible with this cog.") 26 | 27 | cog = CaseInsensitive(bot) 28 | await out_of_date_check("caseinsensitive", cog.__version__) 29 | await bot.add_cog(cog) 30 | -------------------------------------------------------------------------------- /caseinsensitive/fakealias.py: -------------------------------------------------------------------------------- 1 | from redbot.cogs.alias.alias_entry import AliasCache 2 | 3 | 4 | class FakeAlias: 5 | _aliases: AliasCache 6 | -------------------------------------------------------------------------------- /caseinsensitive/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Make all prefixes and commands case insensitive (so that something like !Ping works). This will have a negative performance impact.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing! This cog is **active whenever it is loaded** and has no commands. Try out `[p]piNG`! (once you load the cog)\n\nPlease be aware that this cog:\n1) may affect other cogs that call or change bot.get_context\n2) has a negative performance impact\n3) may break at any time\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "CaseInsensitive", 16 | "requirements": [], 17 | "short": "Make all commands case insensitive.", 18 | "tags": [ 19 | "utility", 20 | "case", 21 | "commands", 22 | "case-insensitive", 23 | "caseinsensitive" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /caseinsensitive/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /caseinsensitive/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /caseinsensitive/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /caseinsensitive/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /caseinsensitive/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/caseinsensitive/vexutils/py.typed -------------------------------------------------------------------------------- /caseinsensitive/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /caseinsensitive/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /cmdlog/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .cmdlog import CmdLog 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red): 18 | cog = CmdLog(bot) 19 | await out_of_date_check("cmdlog", cog.__version__) 20 | await bot.add_cog(cog) 21 | -------------------------------------------------------------------------------- /cmdlog/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Track who used what commands. All command usage is logged to the bot's console/log and also internally cached. You can view the activity of an individual user, server or command. Supports slash and text commands.", 7 | "end_user_data_statement": "This cog may persistently store data or metadata about users. Operational data is temporarily collected and cached whenever a command is used and may be stored.\n\nWhen a command is used, the following data is collected: the message invoking the command, the user that invoked it, the server it was invoked in, and the channel it was invoked in. This includes application commands, as well as old-style text commands.\n\nThis cog does not support data deletion requests, as it handles operational data.", 8 | "install_msg": "This cog will immediately start tracking commands once you have loaded it. They are logged with the `logging` module, so they'll appear in the bot's console or main logs (search for `red.vex.cmdlog`). An internal cache is kept, which you can see in Discord with the `[p]cmdlog` command.\n\nIf you want to store the whole message content, including arguments, instead of just the command invoked, run `[p]cmdlog content true` once you've loaded the cog.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "CmdLog", 16 | "requirements": [], 17 | "short": "Track who uses what commands, with the ability to search for a specific user, server command.", 18 | "tags": [ 19 | "utility", 20 | "log", 21 | "logging" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /cmdlog/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /cmdlog/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /cmdlog/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /cmdlog/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /cmdlog/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/cmdlog/vexutils/py.typed -------------------------------------------------------------------------------- /cmdlog/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /cmdlog/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /covidgraph/__init__.py: -------------------------------------------------------------------------------- 1 | from redbot.core.errors import CogLoadError 2 | 3 | 4 | async def setup(_): 5 | raise CogLoadError( 6 | "This cog will not be updated to be compatible with Red 3.5 due to irrelevance and data " 7 | "issues, and has therefore been removed." 8 | ) 9 | -------------------------------------------------------------------------------- /covidgraph/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "This cog has been removed, please uninstall.", 7 | "disabled": true, 8 | "hidden": true, 9 | "name": "CovidGraph", 10 | "short": "This cog has been removed, please uninstall." 11 | } 12 | -------------------------------------------------------------------------------- /dev-requirements.txt: -------------------------------------------------------------------------------- 1 | # Red itself is also a requriement, however it is not listed here because 2 | # some people may have special setups (eg dev version installed) 3 | 4 | # Required for utils 5 | tabulate 6 | cachetools 7 | asyncache 8 | 9 | # Required for optional PandasSQLDriver in utils 10 | pandas 11 | 12 | # Cogs 13 | plotly # betteruptime, stattrack, googletrends 14 | kaleido # betteruptime, stattrack, googletrends 15 | gidgethub # ghissues, gitub 16 | pytrends # googletrends 17 | psutil # stattrack, system 18 | markdownify # status 19 | rapidfuzz # timechannel 20 | wakeonlan # wol 21 | expr.py # calc 22 | aiosqlite # stattrack 23 | 24 | # checking tools 25 | pyright 26 | black 27 | isort 28 | flake8 29 | pytest 30 | tox 31 | pre-commit 32 | 33 | # docs 34 | sphinx 35 | sphinx-rtd-theme 36 | furo 37 | 38 | # checks 39 | python-dotenv 40 | 41 | # docs 42 | sphinx_rtd_theme 43 | furo 44 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_templates/footer.html: -------------------------------------------------------------------------------- 1 | {% extends "!footer.html" %} 2 | {% block extrafooter %} 3 |

(mostly) Auto-generated from Bobloy's cogguide cog - thanks for making this!

4 | {{ super() }} 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /docs/cogs/aliases.rst: -------------------------------------------------------------------------------- 1 | .. _aliases: 2 | 3 | ======= 4 | Aliases 5 | ======= 6 | 7 | This is the cog guide for the aliases cog. You will 8 | find detailed docs about usage and commands. 9 | 10 | ``[p]`` is considered as your prefix. 11 | 12 | .. note:: 13 | 14 | To use this cog, you will need to install and load it. 15 | 16 | See the :ref:`getting_started` page. 17 | 18 | .. _aliases-usage: 19 | 20 | ----- 21 | Usage 22 | ----- 23 | 24 | Get all the alias information you could ever want about a command. 25 | 26 | 27 | .. _aliases-commands: 28 | 29 | -------- 30 | Commands 31 | -------- 32 | 33 | .. _aliases-command-aliases: 34 | 35 | ^^^^^^^ 36 | aliases 37 | ^^^^^^^ 38 | 39 | **Syntax** 40 | 41 | .. code-block:: none 42 | 43 | [p]aliases 44 | 45 | **Description** 46 | 47 | Get all the alias information you could ever want about a command. 48 | 49 | This will show the main command, built-in aliases, global aliases and 50 | server aliases. 51 | 52 | **Examples:** 53 | - ``[p]aliases foo`` 54 | - ``[p]aliases foo bar`` 55 | -------------------------------------------------------------------------------- /docs/cogs/beautify.rst: -------------------------------------------------------------------------------- 1 | .. _beautify: 2 | 3 | ======== 4 | Beautify 5 | ======== 6 | 7 | This is the cog guide for the beautify cog. You will 8 | find detailed docs about usage and commands. 9 | 10 | ``[p]`` is considered as your prefix. 11 | 12 | .. note:: 13 | 14 | To use this cog, you will need to install and load it. 15 | 16 | See the :ref:`getting_started` page. 17 | 18 | .. _beautify-usage: 19 | 20 | ----- 21 | Usage 22 | ----- 23 | 24 | Beautify and minify JSON. 25 | 26 | This cog has two commands, ``[p]beautify`` and ``[p]minify``. Both of which behave in similar ways. 27 | 28 | They are very flexible and accept inputs in many ways, 29 | for example replies or uploading - or just simply putting it after the command. 30 | 31 | 32 | .. _beautify-commands: 33 | 34 | -------- 35 | Commands 36 | -------- 37 | 38 | .. _beautify-command-beautify: 39 | 40 | ^^^^^^^^ 41 | beautify 42 | ^^^^^^^^ 43 | 44 | **Syntax** 45 | 46 | .. code-block:: none 47 | 48 | [p]beautify [data] 49 | 50 | **Description** 51 | 52 | Beautify some JSON. 53 | 54 | This command accepts it in a few forms. 55 | 56 | 1. Upload the JSON as a file (it can be .txt or .json) 57 | - Note that if you upload multiple files I will only scan the first one 58 | 2. Paste the JSON in the command 59 | - You can send it raw, in inline code or a codeblock 60 | 3. Reply to a message with JSON 61 | - I will search for attachments and any codeblocks in the message 62 | 63 | **Examples:** 64 | - ``[p]beautify {"1": "One", "2": "Two"}`` 65 | - ``[p]beautify`` (with file uploaded) 66 | - ``[p]beautify`` (while replying to a messsage) 67 | 68 | .. _beautify-command-minify: 69 | 70 | ^^^^^^ 71 | minify 72 | ^^^^^^ 73 | 74 | **Syntax** 75 | 76 | .. code-block:: none 77 | 78 | [p]minify [data] 79 | 80 | **Description** 81 | 82 | Minify some JSON. 83 | 84 | This command accepts it in a few forms. 85 | 86 | 1. Upload the JSON as a file (it can be .txt or .json) 87 | - Note that if you upload multiple files I will only scan the first one 88 | 2. Paste the JSON in the command 89 | - You can send it raw, in inline code or a codeblock 90 | 3. Reply to a message with JSON 91 | - I will search for attachments and any codeblocks in the message 92 | 93 | **Examples:** 94 | - ``[p]minify {"1": "One", "2": "Two"}`` 95 | - ``[p]minify`` (with file uploaded) 96 | - ``[p]minify`` (while replying to a messsage) 97 | -------------------------------------------------------------------------------- /docs/cogs/calc.rst: -------------------------------------------------------------------------------- 1 | .. _calc: 2 | 3 | ==== 4 | Calc 5 | ==== 6 | 7 | This is the cog guide for the calc cog. You will 8 | find detailed docs about usage and commands. 9 | 10 | ``[p]`` is considered as your prefix. 11 | 12 | .. note:: 13 | 14 | To use this cog, you will need to install and load it. 15 | 16 | See the :ref:`getting_started` page. 17 | 18 | .. _calc-usage: 19 | 20 | ----- 21 | Usage 22 | ----- 23 | 24 | Calculate simple mathematical expressions. 25 | 26 | 27 | .. _calc-commands: 28 | 29 | -------- 30 | Commands 31 | -------- 32 | 33 | .. _calc-command-calc: 34 | 35 | ^^^^ 36 | calc 37 | ^^^^ 38 | 39 | **Syntax** 40 | 41 | .. code-block:: none 42 | 43 | [p]calc 44 | 45 | **Description** 46 | 47 | Start an interactive calculator using buttons. 48 | -------------------------------------------------------------------------------- /docs/cogs/caseinsensitive.rst: -------------------------------------------------------------------------------- 1 | .. _caseinsensitive: 2 | 3 | =============== 4 | CaseInsensitive 5 | =============== 6 | 7 | This is the cog guide for the caseinsensitive cog. You will 8 | find detailed docs about usage and commands. 9 | 10 | ``[p]`` is considered as your prefix. 11 | 12 | .. note:: 13 | 14 | To use this cog, you will need to install and load it. 15 | 16 | See the :ref:`getting_started` page. 17 | 18 | .. _caseinsensitive-usage: 19 | 20 | ----- 21 | Usage 22 | ----- 23 | 24 | This allows prefixes and commands to be case insensitive (for example ````!Ping```` 25 | would be accepted and responded to). 26 | 27 | Whenever the cog is loaded, prefixes and commands will be case insensitive. 28 | This cog itself has no commands. 29 | 30 | If you want to disable it in a certain servers, use 31 | ``[p]command disablecog CaseInsensitive``. 32 | 33 | There are also other configurations, such as setting a default as disabled 34 | and enabling per-server, listed under ``[p]help command``. 35 | 36 | 37 | .. _caseinsensitive-commands: 38 | 39 | -------- 40 | Commands 41 | -------- 42 | 43 | This cog has no commands. It is always active when loaded. 44 | -------------------------------------------------------------------------------- /docs/cogs/covidgraph.rst: -------------------------------------------------------------------------------- 1 | .. _covidgraph: 2 | 3 | ========== 4 | CovidGraph 5 | ========== 6 | 7 | This cog will not be updated to Red 3.5 and has been removed due to irrelevance and data issues. 8 | 9 | The previous version may still be installed on Red 3.4, however it may break at any time. 10 | -------------------------------------------------------------------------------- /docs/cogs/fivemstatus.rst: -------------------------------------------------------------------------------- 1 | .. _fivemstatus: 2 | 3 | =========== 4 | FiveMStatus 5 | =========== 6 | 7 | This is the cog guide for the fivemstatus cog. You will 8 | find detailed docs about usage and commands. 9 | 10 | ``[p]`` is considered as your prefix. 11 | 12 | .. note:: 13 | 14 | To use this cog, you will need to install and load it. 15 | 16 | See the :ref:`getting_started` page. 17 | 18 | .. _fivemstatus-usage: 19 | 20 | ----- 21 | Usage 22 | ----- 23 | 24 | View the live status of a FiveM server, in a updating Discord message. 25 | 26 | The message is an embed that updates minutely. 27 | 28 | 29 | .. _fivemstatus-commands: 30 | 31 | -------- 32 | Commands 33 | -------- 34 | 35 | .. _fivemstatus-command-fivemstatus: 36 | 37 | ^^^^^^^^^^^ 38 | fivemstatus 39 | ^^^^^^^^^^^ 40 | 41 | .. note:: |admin-lock| 42 | 43 | **Syntax** 44 | 45 | .. code-block:: none 46 | 47 | [p]fivemstatus 48 | 49 | **Description** 50 | 51 | Set up a live FiveM status embed. 52 | 53 | To stop updating the message, just delete it. 54 | 55 | .. _fivemstatus-command-fivemstatus-maintenance: 56 | 57 | """"""""""""""""""""""" 58 | fivemstatus maintenance 59 | """"""""""""""""""""""" 60 | 61 | **Syntax** 62 | 63 | .. code-block:: none 64 | 65 | [p]fivemstatus maintenance 66 | 67 | **Description** 68 | 69 | Toggle maintenance mode. 70 | 71 | .. _fivemstatus-command-fivemstatus-setup: 72 | 73 | """"""""""""""""" 74 | fivemstatus setup 75 | """"""""""""""""" 76 | 77 | **Syntax** 78 | 79 | .. code-block:: none 80 | 81 | [p]fivemstatus setup 82 | 83 | **Description** 84 | 85 | Set up a FiveM status message. 86 | 87 | **Examples:** 88 | - ``[p]fivemstatus setup #status 1.0.1.0:30120`` 89 | -------------------------------------------------------------------------------- /docs/cogs/github.rst: -------------------------------------------------------------------------------- 1 | .. _github: 2 | 3 | ====== 4 | GitHub 5 | ====== 6 | 7 | This cog has been removed in favour of my :ref:`GHIssues ` cog. 8 | -------------------------------------------------------------------------------- /docs/cogs/madtranslate.rst: -------------------------------------------------------------------------------- 1 | .. _madtranslate: 2 | 3 | ============ 4 | MadTranslate 5 | ============ 6 | 7 | This is the cog guide for the madtranslate cog. You will 8 | find detailed docs about usage and commands. 9 | 10 | ``[p]`` is considered as your prefix. 11 | 12 | .. note:: 13 | 14 | To use this cog, you will need to install and load it. 15 | 16 | See the :ref:`getting_started` page. 17 | 18 | .. _madtranslate-usage: 19 | 20 | ----- 21 | Usage 22 | ----- 23 | 24 | Translate things into lots of languages then back to English! 25 | 26 | This will defiantly have some funny moments... Take everything with a pinch of salt! 27 | 28 | 29 | .. _madtranslate-commands: 30 | 31 | -------- 32 | Commands 33 | -------- 34 | 35 | .. _madtranslate-command-madtranslate: 36 | 37 | ^^^^^^^^^^^^ 38 | madtranslate 39 | ^^^^^^^^^^^^ 40 | 41 | **Syntax** 42 | 43 | .. code-block:: none 44 | 45 | [p]madtranslate [count=15] 46 | 47 | .. tip:: Aliases: ``mtranslate``, ``mtrans`` 48 | 49 | **Description** 50 | 51 | Translate something into lots of languages, then back to English! 52 | 53 | **Examples:** 54 | - ``[p]mtrans This is a sentence.`` 55 | - ``[p]mtrans 25 Here's another one.`` 56 | 57 | At the bottom of the output embed is a count-seed pair. You can use this with 58 | the ``mtransseed`` command to use the same language set. 59 | 60 | .. _madtranslate-command-mtransseed: 61 | 62 | ^^^^^^^^^^ 63 | mtransseed 64 | ^^^^^^^^^^ 65 | 66 | **Syntax** 67 | 68 | .. code-block:: none 69 | 70 | [p]mtransseed 71 | 72 | **Description** 73 | 74 | Use a count-seed pair to (hopefully) get reproducible results. 75 | 76 | They may be unreproducible if Google Translate changes its translations. 77 | 78 | The count-seed pair is obtained from the main command, ``mtrans``, in the embed footer. 79 | 80 | **Examples:** 81 | - ``[p]mtrans 15-111111 This is a sentence.`` 82 | - ``[p]mtrans 25-000000 Here's another one.`` 83 | -------------------------------------------------------------------------------- /docs/cogs/resources/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/docs/cogs/resources/all.png -------------------------------------------------------------------------------- /docs/cogs/resources/latest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/docs/cogs/resources/latest.png -------------------------------------------------------------------------------- /docs/cogs/resources/webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/docs/cogs/resources/webhook.png -------------------------------------------------------------------------------- /docs/cogs/statusref.rst: -------------------------------------------------------------------------------- 1 | .. _statusref: 2 | 3 | ================ 4 | Status Reference 5 | ================ 6 | 7 | Below you will see previews for different modes, and webhook. 8 | 9 | 10 | Modes 11 | ===== 12 | 13 | The below modes were sent *without* a webhook. 14 | 15 | ------------ 16 | All and Edit 17 | ------------ 18 | 19 | .. note:: 20 | 21 | The edit mode is the same as the all mode, however it will only send one message per 22 | per incident. This message will then be edited to reflect recent updates. 23 | 24 | 25 | .. image:: resources/all.png 26 | 27 | ------ 28 | Latest 29 | ------ 30 | 31 | .. image:: resources/latest.png 32 | 33 | 34 | Webhook 35 | ======= 36 | 37 | To stay brief only the ``latest`` mode is included, however the ``all`` and ``edit`` modes 38 | are also fully supported - just with a few more fields in the embed. 39 | 40 | .. image:: resources/webhook.png 41 | -------------------------------------------------------------------------------- /docs/cogs/uptimeresponder.rst: -------------------------------------------------------------------------------- 1 | .. _uptimeresponder: 2 | 3 | =============== 4 | UptimeResponder 5 | =============== 6 | 7 | This is the cog guide for the uptimeresponder cog. You will 8 | find detailed docs about usage and commands. 9 | 10 | ``[p]`` is considered as your prefix. 11 | 12 | .. note:: 13 | 14 | To use this cog, you will need to install and load it. 15 | 16 | See the :ref:`getting_started` page. 17 | 18 | .. _uptimeresponder-usage: 19 | 20 | ----- 21 | Usage 22 | ----- 23 | 24 | A cog for responding to pings form various uptime monitoring services, 25 | such as UptimeRobot, Pingdom, Uptime.com, or self-hosted ones like UptimeKuma or Upptime. 26 | 27 | The web server will run in the background whenever the cog is loaded on the specified port. 28 | 29 | It will respond with status code 200 when a request is made to the root URL. 30 | 31 | If you want to use this with an external service, you will need to set up port forwarding. 32 | Make sure you are aware of the security risk of exposing your machine to the internet. 33 | 34 | 35 | .. _uptimeresponder-commands: 36 | 37 | -------- 38 | Commands 39 | -------- 40 | 41 | .. _uptimeresponder-command-uptimeresponderport: 42 | 43 | ^^^^^^^^^^^^^^^^^^^ 44 | uptimeresponderport 45 | ^^^^^^^^^^^^^^^^^^^ 46 | 47 | .. note:: |owner-lock| 48 | 49 | **Syntax** 50 | 51 | .. code-block:: none 52 | 53 | [p]uptimeresponderport [port=None] 54 | 55 | **Description** 56 | 57 | Get or set the port to run the simple web server on. 58 | 59 | Run the command on it's own (``[p]uptimeresponderport``) to see what it's 60 | set to at the moment, and to set it run ``[p]uptimeresponderport 8080``, for example. 61 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Vex-Cogs documentation master file, created by 2 | sphinx-quickstart on Sun Feb 28 10:41:54 2021. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Vex-Cogs's documentation! 7 | ==================================== 8 | 9 | You can view documentation for each of my cogs below, 10 | or you can view the :ref:`Getting started` page 11 | if you want to install my cogs. 12 | 13 | You can reach out to me in the `Red - Cog Support `_ server, 14 | in #support_vex-cogs. 15 | 16 | 17 | .. toctree:: 18 | :maxdepth: 1 19 | :caption: Getting started: 20 | 21 | getting_started 22 | 23 | .. toctree:: 24 | :maxdepth: 1 25 | :caption: Cog guides: 26 | 27 | cogs/anotherpingcog 28 | cogs/aliases 29 | cogs/autoping 30 | cogs/beautify 31 | cogs/betteruptime 32 | cogs/birthday 33 | cogs/buttonpoll 34 | cogs/calc 35 | cogs/caseinsensitive 36 | cogs/cmdlog 37 | cogs/fivemstatus 38 | cogs/ghissues 39 | cogs/googletrends 40 | cogs/madtranslate 41 | cogs/roleplay 42 | cogs/stattrack 43 | cogs/status 44 | cogs/statusref 45 | cogs/system 46 | cogs/timechannel 47 | cogs/uptimeresponder 48 | cogs/wol 49 | 50 | .. toctree:: 51 | :maxdepth: 1 52 | :caption: Event docs for developers: 53 | 54 | statusdev 55 | 56 | .. toctree:: 57 | :maxdepth: 1 58 | :caption: Changelog: 59 | 60 | changelog 61 | 62 | 63 | Indices and tables 64 | ================== 65 | 66 | * :ref:`genindex` 67 | * :ref:`modindex` 68 | * :ref:`search` 69 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | furo 2 | sphinx-rtd-theme -------------------------------------------------------------------------------- /fivemstatus/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .fivemstatus import FiveMStatus 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red) -> None: 18 | cog = FiveMStatus(bot) 19 | await out_of_date_check("fivemstatus", cog.__version__) 20 | r = bot.add_cog(cog) 21 | if r is not None: 22 | await r 23 | -------------------------------------------------------------------------------- /fivemstatus/abc.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import asyncio 4 | from abc import ABC, ABCMeta, abstractmethod 5 | from typing import TYPE_CHECKING 6 | 7 | import discord 8 | from redbot.core.bot import Red 9 | from redbot.core.commands import CogMeta 10 | from redbot.core.config import Config 11 | 12 | from .vexutils.loop import VexLoop 13 | 14 | if TYPE_CHECKING: 15 | from .objects import MessageData, ServerData 16 | 17 | 18 | class CompositeMetaClass(CogMeta, ABCMeta): 19 | """ 20 | This allows the metaclass used for proper type detection to 21 | coexist with discord.py's metaclass 22 | """ 23 | 24 | 25 | class MixinMeta(ABC): 26 | """A wonderful class for typehinting :tada:""" 27 | 28 | bot: Red 29 | config: Config 30 | 31 | loop_meta: VexLoop 32 | loop: asyncio.Task 33 | 34 | @abstractmethod 35 | async def get_data(self, server: str) -> ServerData: 36 | raise NotImplementedError() 37 | 38 | @abstractmethod 39 | async def generate_embed( 40 | self, data: ServerData | None, config_data: MessageData, maintenance: bool 41 | ) -> discord.Embed: 42 | raise NotImplementedError() 43 | -------------------------------------------------------------------------------- /fivemstatus/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "View the live status of a FiveM server, in an auto updating Discord message.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing! You can get started with the `fivemstatus setup` command, to send the message and start automatic updates.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "FiveMStatus", 16 | "requirements": [], 17 | "short": "View the live status of a FiveM server, in an auto updating Discord message.", 18 | "tags": [ 19 | "status", 20 | "live", 21 | "fivem" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /fivemstatus/objects.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from dataclasses import dataclass 4 | from typing import Literal, TypedDict 5 | 6 | 7 | class MessageData(TypedDict): 8 | server: str 9 | msg_id: int 10 | maintenance: bool 11 | last_known_name: str 12 | channel_id: int 13 | 14 | 15 | @dataclass 16 | class ServerData: 17 | current_users: int | Literal["?"] 18 | max_users: int 19 | name: str 20 | ip: str 21 | 22 | 23 | class ServerUnreachable(Exception): 24 | pass 25 | -------------------------------------------------------------------------------- /fivemstatus/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /fivemstatus/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /fivemstatus/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /fivemstatus/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /fivemstatus/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/fivemstatus/vexutils/py.typed -------------------------------------------------------------------------------- /fivemstatus/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /fivemstatus/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /ghissues/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | import json 3 | from pathlib import Path 4 | 5 | import discord 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | from redbot.core.errors import CogLoadError 9 | 10 | from .ghissues import GHIssues 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red) -> None: 18 | cog = GHIssues(bot) 19 | await out_of_date_check("ghissues", cog.__version__) 20 | await bot.add_cog(cog) 21 | -------------------------------------------------------------------------------- /ghissues/consts.py: -------------------------------------------------------------------------------- 1 | from gidgethub import HTTPException 2 | 3 | from .errors import CustomError 4 | 5 | GET_ISSUE = "get_issue" 6 | GET_REPO_LABELS = "get_repo_labels" 7 | GET_ISSUE_LABELS = "get_issue_labels" 8 | 9 | ADD_LABEL = "add_label" 10 | REMOVE_LABEL = "remove_label" 11 | 12 | CREATE_ISSUE = "create_issue" 13 | COMMENT = "comment" 14 | CLOSE = "close" 15 | CHECK_REAL = "check_real" 16 | 17 | EXCEPTIONS = (HTTPException, CustomError) 18 | 19 | CROSS = "\N{CROSS MARK}" 20 | -------------------------------------------------------------------------------- /ghissues/errors.py: -------------------------------------------------------------------------------- 1 | class CustomError(Exception): 2 | pass 3 | -------------------------------------------------------------------------------- /ghissues/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Create, comment, labelify and close GitHub issues, with partial PR support.\n\n", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing! Load the cog and see how to get set up with the `ghi howtoken` command.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "GHIssues", 16 | "requirements": [ 17 | "gidgethub>=5.0.0" 18 | ], 19 | "short": "Create, comment, labelify and close GitHub issues.", 20 | "tags": [ 21 | "utility", 22 | "github", 23 | "issues" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /ghissues/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /ghissues/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /ghissues/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /ghissues/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /ghissues/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/ghissues/vexutils/py.typed -------------------------------------------------------------------------------- /ghissues/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /ghissues/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /ghissues/views/merge_confirm.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | from discord import Interaction 4 | from discord.enums import ButtonStyle 5 | from discord.ui import View 6 | from discord.ui.button import Button, button 7 | 8 | from ..vexutils import get_vex_logger 9 | 10 | if TYPE_CHECKING: 11 | from .master import GHView 12 | 13 | log = get_vex_logger(__name__) 14 | 15 | 16 | class MergeConfirm(View): 17 | def __init__( 18 | self, master: "GHView", commit_title: str, commit_message: Optional[str], merge_method: str 19 | ): 20 | super().__init__() 21 | self.master = master 22 | 23 | self.commit_message = commit_message 24 | self.commit_title = commit_title 25 | self.merge_method = merge_method 26 | 27 | async def interaction_check(self, interaction: Interaction) -> bool: 28 | if interaction.user is None: 29 | return False 30 | 31 | if interaction.user.id == self.master.author_id: 32 | return True 33 | 34 | await interaction.response.send_message( 35 | "You don't have have permission to do this.", ephemeral=True 36 | ) 37 | return False 38 | 39 | @button(label="Confirm merge", style=ButtonStyle.green) 40 | async def btn_confirm(self, interaction: Interaction, button: Button): 41 | self.stop() 42 | try: 43 | await self.master.api.merge( 44 | self.master.issue_data["number"], 45 | self.commit_title, 46 | self.commit_message, 47 | self.merge_method, 48 | ) 49 | except Exception as e: # lazy 50 | log.warning("Unable to merge PR. See the logs for more info.", exc_info=e) 51 | else: 52 | self.master.btn_merge.disabled = True 53 | self.master.btn_close.disabled = True 54 | self.master.btn_open.disabled = True 55 | await self.master.regen_viw() 56 | await interaction.response.send_message("Pull request merged.") 57 | 58 | @button(label="Cancel merge", style=ButtonStyle.red) 59 | async def btn_cancel(self, interaction: Interaction, button: Button): 60 | self.stop() 61 | await interaction.response.send_message("Merge cancelled.") 62 | -------------------------------------------------------------------------------- /ghissues/views/utils.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Generator, List, Tuple 2 | 3 | 4 | def make_label_content(page: int = 0, total_pages: int = 0): 5 | base = ( 6 | "Click a label to toggle it. Labels in GREEN are on the issue, labels in GREY " 7 | "are not on the issue." 8 | ) 9 | page_info = ( 10 | "\nAs you've got lots of labels, click the bottons at the bottom to change " 11 | f"pages.\n\nPage {page + 1} of {total_pages}" 12 | if total_pages > 1 13 | else "" 14 | ) 15 | 16 | return base + page_info 17 | 18 | 19 | def get_menu_sets(raw_labels: Dict[str, bool]) -> Generator[List[Tuple[str, bool]], None, None]: 20 | # partially from a sketchy site and SO 21 | sorted_labels = {k: v for k, v in sorted(raw_labels.items(), key=lambda item: not item[1])} 22 | labels = list(sorted_labels.items()) 23 | for i in range(0, len(labels), 20): 24 | yield labels[i : i + 20] 25 | -------------------------------------------------------------------------------- /github/__init__.py: -------------------------------------------------------------------------------- 1 | from redbot.core.bot import Red 2 | from redbot.core.errors import CogLoadError 3 | 4 | 5 | async def setup(bot: Red) -> None: 6 | raise CogLoadError( 7 | "This cog has been replaced by my `ghissues` cog. Please uninstall this cog and install " 8 | "that instead." 9 | ) 10 | -------------------------------------------------------------------------------- /github/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Create, comment, labelify and close GitHub issues, with partial PR support.", 7 | "disabled": true, 8 | "hidden": true, 9 | "install_msg": "This cog has been removed in favour of my `ghissues` cog. Please uninstall this one and install that.", 10 | "name": "GitHub", 11 | "short": "Create, comment, labelify and close GitHub issues." 12 | } 13 | -------------------------------------------------------------------------------- /googletrends/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .googletrends import GoogleTrends 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red) -> None: 18 | cog = GoogleTrends(bot) 19 | await out_of_date_check("googletrends", cog.__version__) 20 | await bot.add_cog(cog) 21 | -------------------------------------------------------------------------------- /googletrends/abc.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, ABCMeta 2 | from concurrent.futures.thread import ThreadPoolExecutor 3 | 4 | from redbot.core.bot import Red 5 | from redbot.core.commands import CogMeta 6 | 7 | 8 | class CompositeMetaClass(CogMeta, ABCMeta): 9 | """ 10 | This allows the metaclass used for proper type detection to 11 | coexist with discord.py's metaclass 12 | """ 13 | 14 | 15 | class MixinMeta(ABC): 16 | """A wonderful class for typehinting :tada:""" 17 | 18 | bot: Red 19 | executor: ThreadPoolExecutor 20 | -------------------------------------------------------------------------------- /googletrends/errors.py: -------------------------------------------------------------------------------- 1 | class NoData(Exception): 2 | """No data found.""" 3 | -------------------------------------------------------------------------------- /googletrends/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Find out what the world is searching, right from Discord. Includes charts.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing! Find out what the world is searching, right from Discord. Once you've loaded the cog, start with `[p]trends help`.\n\nPlease note there is no Google Trends API, so therefore this is a scraper and may break at any time.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "GoogleTrends", 16 | "requirements": [ 17 | "plotly", 18 | "kaleido", 19 | "pytrends" 20 | ], 21 | "short": "Find out what the world is searching, right from Discord. Includes charts.", 22 | "tags": [ 23 | "utility", 24 | "data", 25 | "google", 26 | "pytrends" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /googletrends/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /googletrends/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /googletrends/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /googletrends/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /googletrends/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/googletrends/vexutils/py.typed -------------------------------------------------------------------------------- /googletrends/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /googletrends/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog_repo.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "These cogs are stuff typically utility stuff that I wanted myself that might be useful to others.\nIt's mainly cogs for bot or server owners.\n\nIf you find anything that's wrong, feel free to make a GH issue or find me in the main Red server or the cog support server (https://discord.gg/GET4DVk). I'm @vexingvexed", 7 | "install_msg": "Thanks for installing this! These cogs are typically utility stuff that I wanted myself that might be useful to others.\nIf you find anything that's wrong, feel free to make a GH issue or find me in the main Red server or in the cog support server https://discord.gg/GET4DVk - I'm @vexingvexed.\n\nAll these cogs have detailed documentation! Check them out at ", 8 | "short": "Mainly utility cogs." 9 | } 10 | -------------------------------------------------------------------------------- /madtranslate/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .madtranslate import MadTranslate 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red) -> None: 18 | cog = MadTranslate(bot) 19 | await out_of_date_check("madtranslate", cog.__version__) 20 | await bot.add_cog(cog) 21 | -------------------------------------------------------------------------------- /madtranslate/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Translate something from English into a gazillion different languages then back to English. Uses an undocumented Google Translate API.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing! Note that this cog uses an undocumented API for Google Translate. As such, this cog may break at short notice.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "MadTranslate", 16 | "requirements": [], 17 | "short": "Translate something from English into a gazillion different languages then back to English. You'll get some funny responses! Uses an undocumented Google Translate API.", 18 | "tags": [ 19 | "madtranslate", 20 | "translate", 21 | "google", 22 | "fun" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /madtranslate/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /madtranslate/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /madtranslate/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /madtranslate/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /madtranslate/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/madtranslate/vexutils/py.typed -------------------------------------------------------------------------------- /madtranslate/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /madtranslate/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 99 3 | target-version = ["py38"] 4 | extend-exclude = "vexutils|.stubs" 5 | 6 | [tool.isort] 7 | profile = "black" 8 | line_length = 99 9 | extend_skip = "vexutils" 10 | 11 | [tool.pyright] 12 | stubPath = "./.stubs" 13 | exclude = ["*/vexutils", ".tox", "**/__pycache__", ".venv", ".github", ".stubs"] 14 | useLibraryCodeForTypes = true 15 | -------------------------------------------------------------------------------- /roleplay/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .roleplay import RolePlay 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red) -> None: 18 | cog = RolePlay(bot) 19 | await out_of_date_check("roleplay", cog.__version__) 20 | await cog.populate_cache() 21 | r = bot.add_cog(cog) 22 | if r is not None: 23 | await r 24 | -------------------------------------------------------------------------------- /roleplay/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Create a role play channel where users can contribute in secret, with some customisation options and logging for admins.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users. Messages sent in channels designated as role play channels by Administrators are not stored in memory by this cog, but they are re-sent from the bot with no association to the user. As such this cog does not directly store data, but data is posted to a Discord channel.", 8 | "install_msg": "Thanks for installing!\n\nTo set the cog up, start with `roleplay channel`. There are some other optional configuration settings available under `roleplay`\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "System", 16 | "requirements": [], 17 | "short": "Create an anonymous role play in your sever.", 18 | "tags": [ 19 | "secret", 20 | "radio", 21 | "transmission", 22 | "fun" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /roleplay/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /roleplay/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /roleplay/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /roleplay/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /roleplay/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/roleplay/vexutils/py.typed -------------------------------------------------------------------------------- /roleplay/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /roleplay/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /stattrack/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .stattrack import StatTrack 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json", encoding="utf8") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red) -> None: 18 | cog = StatTrack(bot) 19 | await out_of_date_check("stattrack", cog.__version__) 20 | await bot.add_cog(cog) 21 | -------------------------------------------------------------------------------- /stattrack/abc.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import asyncio 4 | from abc import ABC, ABCMeta, abstractmethod 5 | from concurrent.futures import ThreadPoolExecutor 6 | from typing import Any 7 | 8 | import discord 9 | import pandas 10 | from discord.ext.commands.cog import CogMeta 11 | from redbot.core.bot import Red 12 | from redbot.core.config import Config 13 | 14 | from .driver import StatTrackSQLiteDriver 15 | from .vexutils.loop import VexLoop 16 | 17 | 18 | class CompositeMetaClass(CogMeta, ABCMeta): 19 | """ 20 | This allows the metaclass used for proper type detection to 21 | coexist with discord.py's metaclass 22 | """ 23 | 24 | 25 | class MixinMeta(ABC): 26 | """A wonderful class for typehinting :tada:""" 27 | 28 | bot: Red 29 | config: Config 30 | 31 | driver: StatTrackSQLiteDriver 32 | plot_executor: ThreadPoolExecutor 33 | 34 | loop_meta: VexLoop 35 | loop: asyncio.Task 36 | last_loop_time: str 37 | 38 | last_plot_debug: dict[str, Any] | None 39 | 40 | cmd_count: int 41 | msg_count: int 42 | 43 | @abstractmethod 44 | async def plot(self, df: pandas.DataFrame, ylabel: str, status_colours: bool) -> discord.File: 45 | raise NotImplementedError 46 | -------------------------------------------------------------------------------- /stattrack/converters.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import datetime 4 | from typing import TYPE_CHECKING 5 | 6 | from redbot.core.commands import BadArgument, Context, Converter, parse_timedelta 7 | 8 | 9 | class _GraphConverter(Converter): 10 | async def convert(self, ctx: Context, argument: str, valid: list[str]) -> str: 11 | if argument.lower() not in valid: 12 | raise BadArgument( 13 | f"That's not a valid graph. See `{ctx.clean_prefix}help stattrack " 14 | f"{ctx.command.name}` for a list of valid types and some examples." 15 | ) 16 | return argument.lower() 17 | 18 | 19 | if TYPE_CHECKING: 20 | TimespanConverter = datetime.timedelta 21 | StatusGraphConverter = str 22 | UserGraphConverter = str 23 | ChannelGraphConverter = str 24 | 25 | else: 26 | 27 | class TimespanConverter(Converter): 28 | async def convert(self, ctx: Context, argument: str) -> datetime.timedelta: 29 | if argument.lower() == "all": 30 | return datetime.timedelta(days=9000) 31 | delta = parse_timedelta(argument, minimum=datetime.timedelta(hours=1)) 32 | if delta is None: 33 | raise BadArgument("That's not a valid time.") 34 | 35 | return delta 36 | 37 | class StatusGraphConverter(_GraphConverter): 38 | async def convert(self, ctx: Context, argument: str) -> str: 39 | return await super().convert(ctx, argument, ["online", "offline", "idle", "dnd"]) 40 | 41 | class UserGraphConverter(_GraphConverter): 42 | async def convert(self, ctx: Context, argument: str) -> str: 43 | return await super().convert(ctx, argument, ["total", "unique", "humans", "bots"]) 44 | 45 | class ChannelGraphConverter(_GraphConverter): 46 | async def convert(self, ctx: Context, argument: str) -> str: 47 | return await super().convert( 48 | ctx, argument, ["text", "voice", "category", "stage", "total"] 49 | ) 50 | -------------------------------------------------------------------------------- /stattrack/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Track your bot's statistics over time, including ping, members, guild and message/command counts.\n\nThis has a background process which could be intensive.\n\nThis stores data in Red's config which is not especially built for this cog's usage.", 7 | "end_user_data_statement": "This cog permanently stores anonymised and aggregated data about users' statuses and counts messages sent, not including their content. This data cannot be traced back to individual users.", 8 | "install_msg": "This cog will immediately start a background process which could use some extra resources. See for details.\n\n**Once you load the cog, please wait a few seconds then run the `stattrackinfo` command. If the 'loop time' is None then wait a bit and try again. When it appears, if it's over 30 seconds __you should not use this cog on your bot.__**\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "StatTrack", 16 | "requirements": [ 17 | "pandas>=1.1.0", 18 | "psutil", 19 | "plotly", 20 | "kaleido", 21 | "aiosqlite" 22 | ], 23 | "short": "Stat tracking cog including ping, member counts and counts of commands/messages. View the data in Discord.", 24 | "tags": [ 25 | "utility", 26 | "timeseries", 27 | "tracking", 28 | "stats" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /stattrack/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /stattrack/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /stattrack/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /stattrack/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /stattrack/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/stattrack/vexutils/py.typed -------------------------------------------------------------------------------- /stattrack/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /stattrack/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /status/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | from typing import AsyncContextManager 6 | 7 | from redbot.core import VersionInfo 8 | from redbot.core.bot import Red 9 | from redbot.core.config import Config 10 | from redbot.core.utils import AsyncIter 11 | 12 | from status.vexutils.meta import out_of_date_check 13 | 14 | from . import vexutils 15 | from .core.core import Status 16 | 17 | with open(Path(__file__).parent / "info.json") as fp: 18 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 19 | 20 | 21 | async def maybe_migrate_config_identifier() -> None: 22 | old_config: Config = Config.get_conf( 23 | None, cog_name="Status", identifier="Vexed-status" # type:ignore 24 | ) 25 | new_config: Config = Config.get_conf(None, cog_name="Status", identifier=418078199982063626) 26 | new_config.register_global(migrated_identifier=False) 27 | 28 | if await new_config.migrated_identifier() is True: 29 | return 30 | 31 | await new_config.version.set(await old_config.version()) 32 | await new_config.feed_store.set(await old_config.feed_store()) 33 | await new_config.old_ids.set(await old_config.old_ids()) 34 | 35 | old_channel_data = await old_config.all_channels() 36 | async for channel, data in AsyncIter(old_channel_data.items(), steps=25): 37 | await new_config.channel_from_id(channel).feeds.set(data.get("feeds")) 38 | 39 | old_guild_data = await old_config.all_guilds() 40 | async for guild, data in AsyncIter(old_guild_data.items(), steps=25): 41 | await new_config.guild_from_id(guild).service_restrictions.set( 42 | data.get("service_restrictions") 43 | ) 44 | 45 | await new_config.migrated_identifier.set(True) 46 | await old_config.clear_all() 47 | 48 | 49 | async def setup(bot: Red) -> None: 50 | await maybe_migrate_config_identifier() 51 | 52 | cog = Status(bot) 53 | await out_of_date_check("status", cog.__version__) 54 | await bot.add_cog(cog) 55 | -------------------------------------------------------------------------------- /status/commands/command.py: -------------------------------------------------------------------------------- 1 | from redbot.core import commands 2 | 3 | from ..core.consts import FEEDS 4 | from ..vexutils.chat import inline_hum_list 5 | 6 | SERVICE_LIST = inline_hum_list(tuple(FEEDS.keys())) 7 | 8 | 9 | class DynamicHelp(commands.Command): 10 | """Append a dynamic list of available servies to the help.""" 11 | 12 | def format_help_for_context(self, ctx: commands.Context) -> str: 13 | return super().format_help_for_context(ctx) + "\n\nAvailable services:\n" + SERVICE_LIST 14 | 15 | 16 | class DynamicHelpGroup(commands.Group): 17 | """Append a dynamic list of avalible services to the help.""" 18 | 19 | def format_help_for_context(self, ctx: commands.Context) -> str: 20 | return super().format_help_for_context(ctx) + "\n\nAvailable services:\n" + SERVICE_LIST 21 | 22 | def command(self, *args, **kwargs): 23 | return super().command(*args, **kwargs) 24 | -------------------------------------------------------------------------------- /status/commands/converters.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING 2 | 3 | from redbot.core.commands import BadArgument, Context, Converter 4 | 5 | from ..core import FEEDS, MODES_LITERAL, SERVICE_LITERAL 6 | from ..core.consts import ICON_BASE 7 | 8 | 9 | class _ServiceTypeHint: 10 | name: SERVICE_LITERAL 11 | id: str 12 | url: str 13 | friendly: str 14 | avatar: str 15 | 16 | 17 | if TYPE_CHECKING: 18 | ServiceConverter = _ServiceTypeHint 19 | ModeConverter = MODES_LITERAL 20 | else: 21 | 22 | class ServiceConverter(Converter): 23 | async def convert(self, ctx: Context, argument: str) -> _ServiceTypeHint: 24 | argument = argument.casefold() 25 | if argument not in FEEDS.keys(): 26 | # not the best but atm only used with `status` and `statusset` with both have 27 | # service lists in the docstring. 28 | raise BadArgument( 29 | "That doesn't look like a valid service. " 30 | f"Take a look at `{ctx.clean_prefix}help {ctx.command}` for a list." 31 | ) 32 | 33 | self.name = argument 34 | self.id = FEEDS[argument]["id"] 35 | self.url = FEEDS[argument]["url"] 36 | self.friendly = FEEDS[argument]["friendly"] 37 | self.avatar = ICON_BASE.format(argument) 38 | 39 | return self 40 | 41 | class ModeConverter(Converter): 42 | async def convert(self, ctx: Context, argument: str) -> MODES_LITERAL: 43 | if argument.casefold() in ["all", "edit", "latest"]: 44 | return argument.casefold() 45 | 46 | raise BadArgument( 47 | "That doesn't look like a valid mode. Valid modes are `all`, `latest` and `edit`." 48 | ) 49 | -------------------------------------------------------------------------------- /status/core/__init__.py: -------------------------------------------------------------------------------- 1 | from .consts import ( 2 | ALL, 3 | EDIT, 4 | FEEDS, 5 | LATEST, 6 | LINK_RE, 7 | MODES_LITERAL, 8 | SERVICE_LITERAL, 9 | SPECIAL_INFO, 10 | TYPES_LITERAL, 11 | UPDATE_NAME, 12 | ) 13 | from .statusapi import StatusAPI 14 | -------------------------------------------------------------------------------- /status/core/abc.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from abc import ABC, ABCMeta, abstractmethod 3 | from typing import Optional 4 | 5 | from aiohttp import ClientSession 6 | from discord.ext.commands.cog import CogMeta 7 | from redbot.core.bot import Red 8 | from redbot.core.config import Config 9 | 10 | from ..core.consts import SERVICE_LITERAL 11 | from ..core.statusapi import StatusAPI 12 | from ..objects import ( 13 | ConfigWrapper, 14 | LastChecked, 15 | ServiceCooldown, 16 | ServiceRestrictionsCache, 17 | UsedFeeds, 18 | ) 19 | from ..vexutils.loop import VexLoop 20 | 21 | 22 | class CompositeMetaClass(CogMeta, ABCMeta): 23 | """ 24 | This allows the metaclass used for proper type detection to 25 | coexist with discord.py's metaclass 26 | """ 27 | 28 | 29 | class MixinMeta(ABC): 30 | """A wonderful class for typehinting :tada:""" 31 | 32 | bot: Red 33 | config: Config 34 | config_wrapper: ConfigWrapper 35 | 36 | loop_meta: VexLoop 37 | loop: asyncio.Task 38 | actually_send: bool 39 | 40 | used_feeds: UsedFeeds 41 | last_checked: LastChecked 42 | service_cooldown: ServiceCooldown 43 | service_restrictions_cache: ServiceRestrictionsCache 44 | 45 | session: ClientSession 46 | statusapi: StatusAPI 47 | 48 | ready: asyncio.Event 49 | 50 | @abstractmethod 51 | async def get_initial_data(self, specific_service: Optional[SERVICE_LITERAL] = None) -> None: 52 | raise NotImplementedError() 53 | -------------------------------------------------------------------------------- /status/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "This cog can automatically send updates form various services including Discord, Cloudflare and GitHub. Members can also use a command to check incidents on-demand. Support all Statuspage.io which I have added.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing! The auto commands are all in `statusset`, and anyone can check statuses with the `status` command. Make sure to load the cog first.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "Status", 16 | "requirements": [ 17 | "markdownify", 18 | "asyncache", 19 | "tabulate" 20 | ], 21 | "short": "Get automatic status updates from various services, and check the latest incidents on-demand. Includes Discord, GitHub and Cloudflare.", 22 | "tags": [ 23 | "utility", 24 | "statuspage", 25 | "trust" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /status/objects/__init__.py: -------------------------------------------------------------------------------- 1 | from .caches import LastChecked, ServiceCooldown, ServiceRestrictionsCache, UsedFeeds 2 | from .channel import ChannelData, CogDisabled, InvalidChannel, NoPermission, NotFound 3 | from .configwrapper import ConfigWrapper 4 | from .incidentdata import IncidentData, Update, UpdateField 5 | from .sendcache import SendCache 6 | from .typeddict import ConfChannelSettings, ConfFeeds, IncidentDataDict 7 | -------------------------------------------------------------------------------- /status/objects/channel.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from dataclasses import dataclass 4 | 5 | import discord 6 | 7 | from ..core import MODES_LITERAL 8 | 9 | 10 | @dataclass 11 | class ChannelData: 12 | channel: discord.TextChannel | discord.Thread 13 | mode: MODES_LITERAL 14 | webhook: bool 15 | embed: bool 16 | edit_id: dict[str, int] 17 | 18 | 19 | class InvalidChannel(Exception): 20 | pass 21 | 22 | 23 | class NotFound(InvalidChannel): 24 | pass 25 | 26 | 27 | class NoPermission(InvalidChannel): 28 | pass 29 | 30 | 31 | class CogDisabled(InvalidChannel): 32 | pass 33 | -------------------------------------------------------------------------------- /status/objects/typeddict.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import datetime 4 | from typing import TypedDict 5 | 6 | from ..core import MODES_LITERAL 7 | from .incidentdata import UpdateField 8 | 9 | 10 | class ConfChannelSettings(TypedDict): 11 | mode: MODES_LITERAL 12 | webhook: bool 13 | edit_id: dict[str, int] 14 | 15 | 16 | class _ConfFeedsFields(TypedDict): 17 | name: str 18 | value: str 19 | update_id: str 20 | 21 | 22 | class ConfFeeds(TypedDict): 23 | fields: list[_ConfFeedsFields] 24 | time: int 25 | title: str 26 | link: str 27 | actual_time: int 28 | description: str 29 | incident_id: str 30 | scheduled_for: int 31 | 32 | 33 | class IncidentDataDict(TypedDict, total=False): 34 | fields: list[UpdateField] 35 | time: datetime.datetime | None 36 | title: str 37 | link: str 38 | actual_time: datetime.datetime | None 39 | description: str 40 | incident_id: str 41 | scheduled_for: datetime.datetime | None 42 | -------------------------------------------------------------------------------- /status/updateloop/__init__.py: -------------------------------------------------------------------------------- 1 | from .processfeed import process_json 2 | from .sendupdate import SendUpdate 3 | from .updatechecker import StatusLoop 4 | -------------------------------------------------------------------------------- /status/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /status/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /status/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /status/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /status/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/status/vexutils/py.typed -------------------------------------------------------------------------------- /status/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /status/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /system/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .system import System 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red) -> None: 18 | cog = System(bot) 19 | await out_of_date_check("system", cog.__version__) 20 | await bot.add_cog(cog) 21 | -------------------------------------------------------------------------------- /system/command.py: -------------------------------------------------------------------------------- 1 | from redbot.core import commands 2 | 3 | # when i did this i thought there were a few commands with limited OSes... but not, only 1 command 4 | # has limited OS support 5 | 6 | 7 | class DynamicHelp(commands.Command): 8 | def __init__(self, *args, **kwargs): 9 | self.supported_system = kwargs.pop("supported_sys", True) # unsupported sys is handled 10 | super().__init__(*args, **kwargs) 11 | 12 | @property 13 | def short_doc(self) -> str: 14 | if self.supported_system: 15 | return super().short_doc 16 | return "Not supported on this OS." 17 | 18 | def format_help_for_context(self, ctx: commands.Context) -> str: 19 | if self.supported_system: 20 | return super().format_help_for_context(ctx) 21 | return "Not supported on this OS.\n\n" + super().format_help_for_context(ctx) 22 | -------------------------------------------------------------------------------- /system/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Check system metrics on the host device, such as CPU or RAM usage", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing!\n\nThis cog supports **both embeds and non-embeds**. Embeds are enabled by default, you can disable them with `[p]embedset`. Because of how Red handles this, you will need to do this for each subcommand.\nThis DOES NOT try to be similar to standard console commands.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "System", 16 | "requirements": [ 17 | "psutil>=5.8.0", 18 | "tabulate" 19 | ], 20 | "short": "Check system metrics on the host device.", 21 | "tags": [ 22 | "utility", 23 | "system", 24 | "metrics", 25 | "top" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /system/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /system/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /system/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /system/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /system/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/system/vexutils/py.typed -------------------------------------------------------------------------------- /system/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /system/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/tests/__init__.py -------------------------------------------------------------------------------- /tests/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": true, 3 | "hidden": true, 4 | "short": "Contrary to what downloader thinks, this isn't a cog!" 5 | } 6 | -------------------------------------------------------------------------------- /timechannel/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .timechannel import TimeChannel 11 | from .vexutils.meta import out_of_date_check 12 | 13 | with open(Path(__file__).parent / "info.json") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red) -> None: 18 | cog = TimeChannel(bot) 19 | await out_of_date_check("timechannel", cog.__version__) 20 | await bot.add_cog(cog) 21 | -------------------------------------------------------------------------------- /timechannel/abc.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from abc import ABC, ABCMeta, abstractmethod 3 | 4 | from redbot.core.bot import Red 5 | from redbot.core.commands import CogMeta 6 | from redbot.core.config import Config 7 | 8 | from .vexutils.loop import VexLoop 9 | 10 | 11 | class CompositeMetaClass(CogMeta, ABCMeta): 12 | """ 13 | This allows the metaclass used for proper type detection to 14 | coexist with discord.py's metaclass 15 | """ 16 | 17 | 18 | class MixinMeta(ABC): 19 | """A wonderful class for typehinting :tada:""" 20 | 21 | bot: Red 22 | config: Config 23 | 24 | loop_meta: VexLoop 25 | loop: asyncio.Task 26 | 27 | @abstractmethod 28 | async def maybe_migrate(self) -> None: 29 | raise NotImplementedError() 30 | -------------------------------------------------------------------------------- /timechannel/converters.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Tuple 2 | 3 | import rapidfuzz.process 4 | from redbot.core.commands import BadArgument, Context, Converter 5 | 6 | from timechannel.data import ZONE_KEYS 7 | 8 | if TYPE_CHECKING: 9 | TimezoneConverter = Tuple[str, float, int] 10 | else: 11 | 12 | class TimezoneConverter(Converter): 13 | async def convert(self, ctx: Context, argument: str) -> Tuple[str, float, int]: 14 | fuzzy_results = rapidfuzz.process.extract( 15 | argument, ZONE_KEYS, limit=2, score_cutoff=90 16 | ) 17 | if len(fuzzy_results) > 1: 18 | raise BadArgument( 19 | "That search returned too many matches. Use the `Region/Location` format or " 20 | 'you can see the full list here (the "TZ database name" ' 21 | "column):\nhttps://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List" 22 | ) 23 | if len(fuzzy_results) == 0: 24 | raise BadArgument( 25 | "That search didn't find any matches. You should be able to enter any " 26 | 'major city, or you can see the full list here (the "TZ database name" ' 27 | "column):\nhttps://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List" 28 | ) 29 | 30 | return fuzzy_results[0] 31 | -------------------------------------------------------------------------------- /timechannel/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Get the time in different timezones in voice channels.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing! You can get started with the `tcset` command, and anything added as a channel can be seen by users in the server with `[p]timezones`\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "TimeChannel", 16 | "requirements": [ 17 | "rapidfuzz" 18 | ], 19 | "short": "Get the time in different timezones in voice channels.", 20 | "tags": [ 21 | "utility", 22 | "channel", 23 | "time", 24 | "timezone" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /timechannel/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import datetime 4 | 5 | import pytz 6 | 7 | from .data import ZONE_KEYS 8 | 9 | 10 | def gen_replacements() -> dict[str, str]: 11 | replacements: dict[str, str] = {} 12 | for key, zone in ZONE_KEYS.items(): 13 | foramtted_time = datetime.datetime.now(pytz.timezone(zone)).strftime("%I:%M%p").lstrip("0") 14 | replacements[key] = foramtted_time 15 | 16 | formatted_24h_time = datetime.datetime.now(pytz.timezone(zone)).strftime("%H:%M") 17 | replacements[f"{key}-24h"] = formatted_24h_time 18 | return replacements 19 | -------------------------------------------------------------------------------- /timechannel/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /timechannel/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /timechannel/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /timechannel/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /timechannel/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/timechannel/vexutils/py.typed -------------------------------------------------------------------------------- /timechannel/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /timechannel/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py38, style-black, style-isort, lint-flake8, type-pyright, docs, pytest 3 | skipsdist = true 4 | 5 | [testenv] 6 | description = Run style and static type checking. 7 | deps = 8 | # style 9 | black 10 | isort 11 | 12 | # lint 13 | flake8 14 | gidgethub 15 | wakeonlan 16 | 17 | # non-typeshed stubs 18 | pandas-stubs 19 | 20 | tabulate 21 | asyncache 22 | rapidfuzz 23 | plotly 24 | pytrends 25 | pyjson5 26 | expr.py 27 | 28 | # docs 29 | sphinx 30 | sphinx-rtd-theme==1.0.0 31 | furo 32 | 33 | # pytest 34 | pytest 35 | Red-DiscordBot 36 | markdownify 37 | 38 | # type 39 | # (some are covered under below) 40 | pyright 41 | asyncache 42 | 43 | [testenv:style-black] 44 | description = Check the style conforms with black. 45 | envdir = {toxworkdir}/py38 46 | 47 | commands = black --check . 48 | 49 | [testenv:style-isort] 50 | description = Check imports conform with isort. 51 | envdir = {toxworkdir}/py38 52 | 53 | commands = isort --check . 54 | 55 | [testenv:lint-flake8] 56 | description = Lint with flake8. 57 | envdir = {toxworkdir}/py38 58 | 59 | commands = flake8 . 60 | 61 | ; [testenv:type-pyright] 62 | ; description = Type checking with pyright. 63 | ; envdir = {toxworkdir}/py38 64 | 65 | ; commands = 66 | ; pip install --force-reinstall git+https://github.com/Rapptz/discord.py 67 | ; pyright 68 | 69 | [testenv:docs] 70 | description = Try to build the docs (HTML) 71 | envdir = {toxworkdir}/py38 72 | 73 | commands = sphinx-build -d "{toxworkdir}/docs_doctree" docs "{toxworkdir}/docs_out" --keep-going 74 | 75 | [testenv:pytest] 76 | description = Run pytest 77 | envdir = {toxworkdir}/py38 78 | 79 | commands = 80 | pytest tests 81 | -------------------------------------------------------------------------------- /uptimeresponder/__init__.py: -------------------------------------------------------------------------------- 1 | import json 2 | from pathlib import Path 3 | 4 | from redbot.core.bot import Red 5 | 6 | from .uptimeresponder import UptimeResponder 7 | from .vexutils import out_of_date_check 8 | 9 | with open(Path(__file__).parent / "info.json") as fp: 10 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 11 | 12 | 13 | async def setup(bot: Red) -> None: 14 | cog = UptimeResponder(bot) 15 | await out_of_date_check("uptimeresponder", cog.__version__) 16 | await bot.add_cog(cog) 17 | -------------------------------------------------------------------------------- /uptimeresponder/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": [ 3 | "Vexed" 4 | ], 5 | "description": "A cog which starts up a simple webserver whenever the cog is loaded, which can then be used by uptime monitoring services such as UptimeRobot, Pingdom, Uptime.com, or self-hosted ones like UptimeKuma or Upptime.. If you are using an external monitor, you will need to configure port forwarding. Make sure you are aware of the security risks of exposing your machine to the internet. The cog responds with status code 200.", 6 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 7 | "install_msg": "As soon as you start the cog, it will start a simple web server for listening to responses on port 8710. The server is shut down when the cog is unloaded. You can change the port with `[p]uptimeresponderport `.\n\nIf you are using an external uptime monitor, you will need to open up port forwarding. Make sure you are aware of the security risk of exposing your machine to the internet. This cog responds with status code 200 at the root only.\n\nThis cog has docs! ", 8 | "min_bot_version": "3.5.1", 9 | "min_python_version": [ 10 | 3, 11 | 8, 12 | 1 13 | ], 14 | "name": "UptimeResponder", 15 | "requirements": [ 16 | "asyncache" 17 | ], 18 | "short": "A cog which starts up a simple webserver whenever the cog is loaded, which can then be used by uptime monitoring services such as UptimeRobot, Pingdom, Uptime.com, or self-hosted ones like Uptime Kuma or Upptime.", 19 | "tags": [ 20 | "webserver", 21 | "server", 22 | "ping", 23 | "uptimerobot", 24 | "uptimekuma", 25 | "kuma", 26 | "upptime", 27 | "pingdom" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /uptimeresponder/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /uptimeresponder/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /uptimeresponder/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /uptimeresponder/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /uptimeresponder/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/uptimeresponder/vexutils/py.typed -------------------------------------------------------------------------------- /uptimeresponder/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /uptimeresponder/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | -------------------------------------------------------------------------------- /wol/__init__.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import importlib 3 | import json 4 | from pathlib import Path 5 | 6 | from redbot.core import VersionInfo 7 | from redbot.core.bot import Red 8 | 9 | from . import vexutils 10 | from .vexutils.meta import out_of_date_check 11 | from .wol import WOL 12 | 13 | with open(Path(__file__).parent / "info.json") as fp: 14 | __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] 15 | 16 | 17 | async def setup(bot: Red): 18 | cog = WOL(bot) 19 | await out_of_date_check("wol", cog.__version__) 20 | await bot.add_cog(cog) 21 | -------------------------------------------------------------------------------- /wol/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/Cog-Creators/Red-DiscordBot/V3/develop/schema/red_cog.schema.json", 3 | "author": [ 4 | "Vexed (@vexingvexed)" 5 | ], 6 | "description": "Use Wake on LAN from Discord! This cog sends magic packets on the local network. You'll need to have set up the computer beforehand to listen to these - just search how to set it up for your operating system.", 7 | "end_user_data_statement": "This cog does not persistently store data or metadata about users.", 8 | "install_msg": "Thanks for installing! Once you've loaded the cog, get started by adding the computer you want to wake's MAC address with `wolset add ` then you can wake it with just `wol `. `` can be whatever you want.\n\nThis cog has docs! Check them out at ", 9 | "min_bot_version": "3.5.1", 10 | "min_python_version": [ 11 | 3, 12 | 8, 13 | 1 14 | ], 15 | "name": "WOL", 16 | "requirements": [ 17 | "wakeonlan", 18 | "tabulate" 19 | ], 20 | "short": "Use Wake on LAN from Discord! This cog sends magic packets on the local network.", 21 | "tags": [ 22 | "utility", 23 | "wakeonlan", 24 | "local" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /wol/vexutils/README.md: -------------------------------------------------------------------------------- 1 | ## My utils 2 | 3 | Hello there! If you're contributing or taking a look, everything in this folder 4 | is synced from a master repo at https://github.com/Vexed01/vex-cog-utils by GitHub Actions - 5 | so it's probably best to look/edit there. 6 | 7 | --- 8 | 9 | Last sync at: 2023-02-16 14:37:06 UTC 10 | 11 | Version: `2.6.1` 12 | 13 | Commit: [`b98072829ca902ef207688334da34f8e6c1da1e8`](https://github.com/Vexed01/vex-cog-utils/commit/b98072829ca902ef207688334da34f8e6c1da1e8) 14 | -------------------------------------------------------------------------------- /wol/vexutils/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Optional 2 | 3 | import discord 4 | from redbot.core.bot import Red 5 | 6 | from .chat import humanize_bytes, inline_hum_list, no_colour_rich_markup 7 | from .meta import format_help, format_info, get_vex_logger, out_of_date_check 8 | from .version import __version__ 9 | -------------------------------------------------------------------------------- /wol/vexutils/commit.json: -------------------------------------------------------------------------------- 1 | {"latest_commit": "b98072829ca902ef207688334da34f8e6c1da1e8"} -------------------------------------------------------------------------------- /wol/vexutils/consts.py: -------------------------------------------------------------------------------- 1 | DOCS_BASE = "This cog has docs! Check them out at\nhttps://s.vexcodes.com/c/{}" 2 | 3 | CHECK = "\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}" 4 | CROSS = "\N{CROSS MARK}" 5 | 6 | RED_CIRCLE = "\N{LARGE RED CIRCLE}" 7 | GREEN_CIRCLE = "\N{LARGE GREEN CIRCLE}" 8 | 9 | SNOWFLAKE_REGEX = r"\b\d{17,20}\b" 10 | -------------------------------------------------------------------------------- /wol/vexutils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vexed01/Vex-Cogs/b7768ce113c498ba76ccbadc858459560fc20205/wol/vexutils/py.typed -------------------------------------------------------------------------------- /wol/vexutils/url_buttons.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import discord 4 | from discord.http import Route 5 | from redbot.core.bot import Red 6 | 7 | 8 | class URLButton: 9 | def __init__(self, label: str, url: str) -> None: 10 | if not isinstance(label, str): 11 | raise TypeError("Label must be a string") 12 | if not isinstance(url, str): 13 | raise TypeError("URL must be a string") 14 | 15 | self.label = label 16 | self.url = url 17 | 18 | def to_dict(self) -> dict: 19 | return { 20 | "label": self.label, 21 | "style": 5, 22 | "type": 2, 23 | "url": self.url, 24 | } 25 | 26 | 27 | async def send_message( 28 | bot: Red, 29 | channel_id: int, 30 | *, 31 | content: Optional[str] = None, 32 | embed: Optional[discord.Embed] = None, 33 | file: Optional[discord.File] = None, 34 | url_button: Optional[URLButton] = None, 35 | ): 36 | """Send a message with a URL button, with pure dpy 1.7.""" 37 | payload = {} 38 | 39 | if content: 40 | payload["content"] = content 41 | 42 | if embed: 43 | payload["embed"] = embed.to_dict() 44 | 45 | if url_button: 46 | payload["components"] = [{"type": 1, "components": [url_button.to_dict()]}] # type:ignore 47 | 48 | if file: 49 | form = [ 50 | { 51 | "name": "file", 52 | "value": file.fp, 53 | "filename": file.filename, 54 | "content_type": "application/octet-stream", 55 | }, 56 | {"name": "payload_json", "value": discord.utils.to_json(payload)}, 57 | ] 58 | 59 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 60 | await bot._connection.http.request(r, form=form, files=[file]) 61 | 62 | else: 63 | r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id) 64 | await bot._connection.http.request(r, json=payload) 65 | -------------------------------------------------------------------------------- /wol/vexutils/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.6.1" 2 | --------------------------------------------------------------------------------