Compare commits
24 commits
main
...
sugoncredi
Author | SHA1 | Date | |
---|---|---|---|
56e4e8fe7c | |||
34a9759a67 | |||
09bdf4768e | |||
78ce22aa72 | |||
3af564f9cd | |||
074569465b | |||
53d1d20942 | |||
b0c32a130b | |||
8759ee1820 | |||
d51f42289b | |||
2173998ced | |||
|
6c150045f5 | ||
|
b241606796 | ||
|
2169436a70 | ||
|
691cacbbc6 | ||
|
22d9802aa0 | ||
|
680759c5dd | ||
|
5aebdc5eed | ||
|
019f68a1e8 | ||
|
8f9c774f68 | ||
|
6c3a7d1e78 | ||
|
6d41ea67e2 | ||
|
87ea3b273e | ||
e5656d2aa2 |
68 changed files with 491 additions and 4675 deletions
|
@ -1,23 +0,0 @@
|
||||||
---
|
|
||||||
name: Bot Bug Report
|
|
||||||
about: Got an issue with the Galaxy bot? Use this.
|
|
||||||
title: "[BOT BUG]"
|
|
||||||
labels: bot, bug
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
What caused the bug?
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
|
@ -1,23 +0,0 @@
|
||||||
---
|
|
||||||
name: Bot Suggestion
|
|
||||||
about: Trying to suggest something for the Galaxy bot? Use this.
|
|
||||||
title: "[BOT SUGGESTION]"
|
|
||||||
labels: bot, enhancement
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you want to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
|
@ -1,23 +0,0 @@
|
||||||
---
|
|
||||||
name: Cog Bug Report
|
|
||||||
about: Got an issue with a cog from Galaxy Cogs? Use this.
|
|
||||||
title: "[COG BUG]"
|
|
||||||
labels: bug, cog
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
What caused the error?
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
|
@ -1,26 +0,0 @@
|
||||||
---
|
|
||||||
name: Cog Suggestion
|
|
||||||
about: Trying to suggest something for Galaxy Cogs? Use this.
|
|
||||||
title: "[COG SUGGESTION]"
|
|
||||||
labels: cog, enhancement
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**What cog is your feature request for?**
|
|
||||||
A cog in this repository.
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you want to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
|
@ -1,16 +0,0 @@
|
||||||
[MESSAGES CONTROL]
|
|
||||||
disable=
|
|
||||||
too-many-lines,
|
|
||||||
missing-module-docstring,
|
|
||||||
missing-function-docstring,
|
|
||||||
missing-class-docstring,
|
|
||||||
line-too-long,
|
|
||||||
too-many-arguments,
|
|
||||||
too-many-branches,
|
|
||||||
superfluous-parens,
|
|
||||||
invalid-name,
|
|
||||||
too-many-locals,
|
|
||||||
too-many-public-methods,
|
|
||||||
too-many-statements,
|
|
||||||
arguments-differ,
|
|
||||||
too-many-return-statements
|
|
|
@ -1,20 +0,0 @@
|
||||||
name: Actions
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'main'
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
Lint Code (Pylint):
|
|
||||||
runs-on: docker
|
|
||||||
container: www.coastalcommits.com/cswimr/actions:galaxycogs
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: poetry install --with dev --no-root
|
|
||||||
|
|
||||||
- name: Analysing code with Pylint
|
|
||||||
run: pylint --rcfile .forgejo/workflows/config/.pylintrc $(git ls-files '*.py')
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,2 +1,7 @@
|
||||||
galaxy/slashtag arguments.txt
|
galaxy/slashtag arguments.txt
|
||||||
|
galaxy_server.yaml
|
||||||
|
global.yaml
|
||||||
|
galaxy_staff_server.yaml
|
||||||
|
combat_welder.yaml
|
||||||
.venv
|
.venv
|
||||||
|
/OOUCogs
|
||||||
|
|
67
README.md
67
README.md
|
@ -1,72 +1,51 @@
|
||||||
# GalaxyCogs
|
# GalaxyCogs
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://discord.com/invite/robloxgalaxy">
|
||||||
|
<img src="https://discordapp.com/api/guilds/204965774618656769/widget.png?style=shield" alt="Galaxy Discord Server">
|
||||||
|
</a>
|
||||||
|
<a href="https://www.python.org/downloads/">
|
||||||
|
<img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/Red-Discordbot">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/Rapptz/discord.py/">
|
||||||
|
<img src="https://img.shields.io/badge/discord-py-blue.svg" alt="discord.py">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
Repository for Redbot cogs developed by the Galaxy Discord Management team.
|
Repository for Redbot cogs developed by the Galaxy Discord Management team.
|
||||||
|
|
||||||
**This readme is heavily outdated.**
|
|
||||||
|
|
||||||
## ExportChannels **(WIP)**[^incomplete]
|
|
||||||
|
|
||||||
This cog allows you to easily export channels using Discord Chat Exporter.
|
|
||||||
|
|
||||||
**THIS COG IS NOT INTENDED FOR EXTERNAL USE. YOU WILL LIKELY HAVE TO RUN THIS COG LOCALLY AND MODIFY CODE SHOULD YOU WISH TO USE IT.**
|
|
||||||
|
|
||||||
### **Credit to Tyrrrz for the bundled version of Discord Chat Exporter within this cog. The original repository can be found [here](https://github.com/Tyrrrz/DiscordChatExporter).**
|
|
||||||
|
|
||||||
## Galaxy
|
## Galaxy
|
||||||
|
|
||||||
Utility cog designed specifically for use on the Galaxy Discord server.
|
Utility cog designed specifically for use on the Galaxy Discord server.
|
||||||
|
|
||||||
Includes:
|
Includes:
|
||||||
|
|
||||||
* Warehouse command
|
* Warehouse command
|
||||||
* FAQ command
|
* FAQ command
|
||||||
* Unix command
|
* Unix command
|
||||||
|
|
||||||
## Info
|
## Info
|
||||||
|
|
||||||
Combination of a few built-in Red cogs + some custom code to provide commands that show information of specific Discord objects.
|
Combination of a few built-in Red cogs + some custom code to provide commands that show information of specific Discord objects.
|
||||||
|
|
||||||
Currently supports:
|
Currently supports:
|
||||||
|
|
||||||
* Users
|
* Users
|
||||||
* Servers/Guilds
|
* Servers/Guilds
|
||||||
* Roles
|
* Roles[^dpy_notice]
|
||||||
|
[^dpy_notice]:
|
||||||
|
Due to Red's use of Discord.py 1.7.3, the ``[p]roleinfo`` command in the Info cog does not show all permissions. This is due to the outdated Discord.py version not supporting checking for all permissions.
|
||||||
|
|
||||||
## Podcast **(WIP)**[^incomplete]
|
## Podcast **(WIP)**
|
||||||
|
Allows users to submit questions to a specified channel, intended for use with podcasts.
|
||||||
|
|
||||||
Allows users to submit questions to a specified channel, intended for use with podcasts.
|
Also features user blacklists, both configurable per-server and globally.
|
||||||
|
|
||||||
Also features user blacklists, both configurable per-server and globally.
|
## Suggestions
|
||||||
[^incomplete]:
|
Allows users to submit suggestions to a specified channel. Highly cut-down modification of [SauriCog's Suggestions Cog](https://github.com/elijabesu/SauriCogs).
|
||||||
This cog currently is non-functional. This notice will be removed once the Cog is completed.
|
|
||||||
|
|
||||||
## Shortmute
|
Features:
|
||||||
|
* Separate approved and denied channels
|
||||||
Allows staff members to shortmute individuals for up to 30 minutes, using Discord's Timeouts feature.
|
* Custom emoji support
|
||||||
|
|
||||||
## Suggestions
|
|
||||||
|
|
||||||
Allows users to submit suggestions to a specified channel. Highly cut-down modification of [SauriCog's Suggestions Cog](https://github.com/elijabesu/SauriCogs).
|
|
||||||
|
|
||||||
Features:
|
|
||||||
|
|
||||||
* Separate approved and denied channels
|
|
||||||
* Custom emoji support
|
|
||||||
|
|
||||||
## SugonCredit[^incomplete]
|
|
||||||
|
|
||||||
|
## SugonCredit
|
||||||
Implements a way for moderators to give out social-credit like points, dubbed 'sugoncredits' by the community.
|
Implements a way for moderators to give out social-credit like points, dubbed 'sugoncredits' by the community.
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
* Add Credit to people.
|
* Add Credit to people.
|
||||||
* Remove Credit from people.
|
* Remove Credit from people.
|
||||||
* Supports custom currency names and bank names.
|
* Supports custom currency names and bank names.
|
||||||
|
|
||||||
## YouTubeDownloader
|
|
||||||
|
|
||||||
Allows users to download any YouTube video.
|
|
||||||
|
|
||||||
`[p]download https://youtu.be/dQw4w9WgXcQ` - Downloads the audio from [this video](https://youtu.be/dQw4w9WgXcQ) in `.m4a` format.
|
|
||||||
|
|
||||||
`[p]download https://youtu.be/dQw4w9WgXcQ false` - Downloads [this video](https://youtu.be/dQw4w9WgXcQ) in `.mp4` format.
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
from .exportchannels import ExportChannels
|
|
||||||
|
|
||||||
async def setup(bot):
|
|
||||||
await bot.add_cog(ExportChannels(bot))
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,275 +0,0 @@
|
||||||
{
|
|
||||||
"runtimeTarget": {
|
|
||||||
"name": ".NETCoreApp,Version=v7.0",
|
|
||||||
"signature": ""
|
|
||||||
},
|
|
||||||
"compilationOptions": {},
|
|
||||||
"targets": {
|
|
||||||
".NETCoreApp,Version=v7.0": {
|
|
||||||
"DiscordChatExporter.Cli/2.40.4": {
|
|
||||||
"dependencies": {
|
|
||||||
"CliFx": "2.3.4",
|
|
||||||
"Deorcify": "1.0.2",
|
|
||||||
"DiscordChatExporter.Core": "2.40.4",
|
|
||||||
"DotnetRuntimeBootstrapper": "2.5.1",
|
|
||||||
"Gress": "2.1.1",
|
|
||||||
"Spectre.Console": "0.47.0"
|
|
||||||
},
|
|
||||||
"runtime": {
|
|
||||||
"DiscordChatExporter.Cli.dll": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AdvancedStringBuilder/0.1.0": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/netstandard2.0/AdvancedStringBuilder.dll": {
|
|
||||||
"assemblyVersion": "0.1.0.0",
|
|
||||||
"fileVersion": "0.1.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AngleSharp/1.0.4": {
|
|
||||||
"dependencies": {
|
|
||||||
"System.Text.Encoding.CodePages": "7.0.0"
|
|
||||||
},
|
|
||||||
"runtime": {
|
|
||||||
"lib/net7.0/AngleSharp.dll": {
|
|
||||||
"assemblyVersion": "1.0.4.0",
|
|
||||||
"fileVersion": "1.0.4.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AsyncKeyedLock/6.2.1": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/net5.0/AsyncKeyedLock.dll": {
|
|
||||||
"assemblyVersion": "6.2.1.0",
|
|
||||||
"fileVersion": "6.2.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"CliFx/2.3.4": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/netstandard2.1/CliFx.dll": {
|
|
||||||
"assemblyVersion": "2.3.4.0",
|
|
||||||
"fileVersion": "2.3.4.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Deorcify/1.0.2": {},
|
|
||||||
"DotnetRuntimeBootstrapper/2.5.1": {},
|
|
||||||
"Gress/2.1.1": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/netstandard2.0/Gress.dll": {
|
|
||||||
"assemblyVersion": "2.1.1.0",
|
|
||||||
"fileVersion": "2.1.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"JsonExtensions/1.2.0": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/net5.0/JsonExtensions.dll": {
|
|
||||||
"assemblyVersion": "1.2.0.0",
|
|
||||||
"fileVersion": "1.2.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Polly/7.2.4": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/netstandard2.0/Polly.dll": {
|
|
||||||
"assemblyVersion": "7.0.0.0",
|
|
||||||
"fileVersion": "7.2.4.982"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RazorBlade/0.4.3": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/net6.0/RazorBlade.dll": {
|
|
||||||
"assemblyVersion": "0.4.3.0",
|
|
||||||
"fileVersion": "0.4.3.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Spectre.Console/0.47.0": {
|
|
||||||
"dependencies": {
|
|
||||||
"System.Memory": "4.5.5"
|
|
||||||
},
|
|
||||||
"runtime": {
|
|
||||||
"lib/net7.0/Spectre.Console.dll": {
|
|
||||||
"assemblyVersion": "0.0.0.0",
|
|
||||||
"fileVersion": "0.47.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Superpower/3.0.0": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/net5.0/Superpower.dll": {
|
|
||||||
"assemblyVersion": "1.0.0.0",
|
|
||||||
"fileVersion": "3.0.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.Memory/4.5.5": {},
|
|
||||||
"System.Text.Encoding.CodePages/7.0.0": {},
|
|
||||||
"WebMarkupMin.Core/2.14.0": {
|
|
||||||
"dependencies": {
|
|
||||||
"AdvancedStringBuilder": "0.1.0"
|
|
||||||
},
|
|
||||||
"runtime": {
|
|
||||||
"lib/netstandard2.1/WebMarkupMin.Core.dll": {
|
|
||||||
"assemblyVersion": "2.14.0.0",
|
|
||||||
"fileVersion": "2.14.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"YoutubeExplode/6.3.1": {
|
|
||||||
"dependencies": {
|
|
||||||
"AngleSharp": "1.0.4"
|
|
||||||
},
|
|
||||||
"runtime": {
|
|
||||||
"lib/net5.0/YoutubeExplode.dll": {
|
|
||||||
"assemblyVersion": "6.3.1.0",
|
|
||||||
"fileVersion": "6.3.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DiscordChatExporter.Core/2.40.4": {
|
|
||||||
"dependencies": {
|
|
||||||
"AsyncKeyedLock": "6.2.1",
|
|
||||||
"Gress": "2.1.1",
|
|
||||||
"JsonExtensions": "1.2.0",
|
|
||||||
"Polly": "7.2.4",
|
|
||||||
"RazorBlade": "0.4.3",
|
|
||||||
"Superpower": "3.0.0",
|
|
||||||
"WebMarkupMin.Core": "2.14.0",
|
|
||||||
"YoutubeExplode": "6.3.1"
|
|
||||||
},
|
|
||||||
"runtime": {
|
|
||||||
"DiscordChatExporter.Core.dll": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"libraries": {
|
|
||||||
"DiscordChatExporter.Cli/2.40.4": {
|
|
||||||
"type": "project",
|
|
||||||
"serviceable": false,
|
|
||||||
"sha512": ""
|
|
||||||
},
|
|
||||||
"AdvancedStringBuilder/0.1.0": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-IbN3r5whlJvi8MhCDPVpIb+NVScyUcKSdcJZrnoXFDyzPDISl3AbWouNBYIHRdZdfGuzqCQEhM1vkxbIKqQVaQ==",
|
|
||||||
"path": "advancedstringbuilder/0.1.0",
|
|
||||||
"hashPath": "advancedstringbuilder.0.1.0.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"AngleSharp/1.0.4": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-G8R4C2MEDFQvjUbYz1QIcGfibjsTJnzP0aWy8iQgWWk7eKacYydCNGD3JMhVL0Q5pZQ9RYlqpKNESEU5NpqsRw==",
|
|
||||||
"path": "anglesharp/1.0.4",
|
|
||||||
"hashPath": "anglesharp.1.0.4.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"AsyncKeyedLock/6.2.1": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-WUvN3Q7aL3wARMcVi/KYTHjOC+0Ld+/ikKU6UGr4aOl7TuK1I2MNKeUkmfr7y4S3UNjQbpzNQCV2OcJq1S/yXg==",
|
|
||||||
"path": "asynckeyedlock/6.2.1",
|
|
||||||
"hashPath": "asynckeyedlock.6.2.1.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"CliFx/2.3.4": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-CFD8yL9McQrKa2dnGdXx/e1ob3QXcVICHpE9XbPXnFw1yPdqAgij3pdS4Xfii3U0+D1HJRW1rOPtNnuR7lI1cQ==",
|
|
||||||
"path": "clifx/2.3.4",
|
|
||||||
"hashPath": "clifx.2.3.4.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"Deorcify/1.0.2": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-khu8MahgfbXc8eQxfZgRX38Jgu1ZLg+6aK906XtIkUpzMovhaPs4ZOWcUiDLtPz0a9m7TcQwtGtoeRgghO8mVw==",
|
|
||||||
"path": "deorcify/1.0.2",
|
|
||||||
"hashPath": "deorcify.1.0.2.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"DotnetRuntimeBootstrapper/2.5.1": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-Ufbf8Qe9hwY/KojfimWX4Kqka3QFH4IoGiQj8LPRlyk68/ApHxsG+p6GeTwukY0sIgxA1VXUAFkbvnn9rbZyaw==",
|
|
||||||
"path": "dotnetruntimebootstrapper/2.5.1",
|
|
||||||
"hashPath": "dotnetruntimebootstrapper.2.5.1.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"Gress/2.1.1": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-n/YK1XYM2xUhoPFRRJpoTk5qtWBwTkSZlWtxqb4JNX3pDfwoMiu6G+zs65y8Z8SfIUxhOhU5yO/v58WkZynECg==",
|
|
||||||
"path": "gress/2.1.1",
|
|
||||||
"hashPath": "gress.2.1.1.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"JsonExtensions/1.2.0": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-ujtrK6m5BQVQLEteLfl54upN7Z59c1ZqEKmU3OlYriqnV74dIgIlNM2vkcgn2AuZEItQDNORD/2H1biI/asOdg==",
|
|
||||||
"path": "jsonextensions/1.2.0",
|
|
||||||
"hashPath": "jsonextensions.1.2.0.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"Polly/7.2.4": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-bw00Ck5sh6ekduDE3mnCo1ohzuad946uslCDEENu3091+6UKnBuKLo4e+yaNcCzXxOZCXWY2gV4a35+K1d4LDA==",
|
|
||||||
"path": "polly/7.2.4",
|
|
||||||
"hashPath": "polly.7.2.4.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"RazorBlade/0.4.3": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-EwoDxG2aw5UuKsxKbg9W8PPlmkvPvp9y7yLjRhfIQvnDRZEfr3n+RCs46VHlIvALbCGDCX3S0B/zKMEmkFLHLQ==",
|
|
||||||
"path": "razorblade/0.4.3",
|
|
||||||
"hashPath": "razorblade.0.4.3.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"Spectre.Console/0.47.0": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-wz8mszcZr0cSOo8GyoG9e2DFW0SkMT8/n78Q/lIXX7EbCtHNXOoOKWpJ9Str+rCYtmQOGGyDutZzubrUHK/XkA==",
|
|
||||||
"path": "spectre.console/0.47.0",
|
|
||||||
"hashPath": "spectre.console.0.47.0.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"Superpower/3.0.0": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-bjKbAYWePooCAvPxQq+3KnmcLfRggMyRoXmtBMlmCG71bdwBHrO6rmRJ2DRIodg5aztNcxeZXBUVWT+H+MZUhw==",
|
|
||||||
"path": "superpower/3.0.0",
|
|
||||||
"hashPath": "superpower.3.0.0.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"System.Memory/4.5.5": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
|
|
||||||
"path": "system.memory/4.5.5",
|
|
||||||
"hashPath": "system.memory.4.5.5.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"System.Text.Encoding.CodePages/7.0.0": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-LSyCblMpvOe0N3E+8e0skHcrIhgV2huaNcjUUEa8hRtgEAm36aGkRoC8Jxlb6Ra6GSfF29ftduPNywin8XolzQ==",
|
|
||||||
"path": "system.text.encoding.codepages/7.0.0",
|
|
||||||
"hashPath": "system.text.encoding.codepages.7.0.0.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"WebMarkupMin.Core/2.14.0": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-fRydp8dkCWkC3RDL+7ABWLLTgAnFEb5k7flhWrTlyGatg0rpT4HArKnGmfgfQ27FVMa1lCOAzFE1ORF5y5Pzbw==",
|
|
||||||
"path": "webmarkupmin.core/2.14.0",
|
|
||||||
"hashPath": "webmarkupmin.core.2.14.0.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"YoutubeExplode/6.3.1": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-+k/RYu3UCI2TwSo/QuIHnhSQ74GRy1gNSuthb/o2ZRNSLidzmbyWaNtBABOxqQJj6ohG/fVScin8cuFVg3Q5vA==",
|
|
||||||
"path": "youtubeexplode/6.3.1",
|
|
||||||
"hashPath": "youtubeexplode.6.3.1.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"DiscordChatExporter.Core/2.40.4": {
|
|
||||||
"type": "project",
|
|
||||||
"serviceable": false,
|
|
||||||
"sha512": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- This configuration file is required by the apphost which runs on legacy .NET Framework for compatibility reasons -->
|
|
||||||
<configuration>
|
|
||||||
<!-- Prefer .NET 3.5 (preinstalled on Windows 7), rollover to .NET 4.x (preinstalled on Windows 8+) -->
|
|
||||||
<startup useLegacyV2RuntimeActivationPolicy="true">
|
|
||||||
<supportedRuntime version="v2.0.50727" />
|
|
||||||
<supportedRuntime version="v4.0" />
|
|
||||||
</startup>
|
|
||||||
</configuration>
|
|
Binary file not shown.
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"runtimeOptions": {
|
|
||||||
"tfm": "net7.0",
|
|
||||||
"framework": {
|
|
||||||
"name": "Microsoft.NETCore.App",
|
|
||||||
"version": "7.0.0"
|
|
||||||
},
|
|
||||||
"configProperties": {
|
|
||||||
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,2 +0,0 @@
|
||||||
This bundled version of Discord Chat Exporter can be found here: https://github.com/Tyrrrz/DiscordChatExporter/releases/tag/2.40.4
|
|
||||||
I DID NOT MAKE THIS PROGRAM. This program is developed by Tyrrrz, NOT me.
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,104 +0,0 @@
|
||||||
import asyncio
|
|
||||||
import os
|
|
||||||
|
|
||||||
import discord
|
|
||||||
from redbot.core import Config, checks, commands, data_manager
|
|
||||||
|
|
||||||
|
|
||||||
class ExportChannels(commands.Cog):
|
|
||||||
"""Custom cog to export channels to JSON and HTML formats using Discord Chat Exporter.
|
|
||||||
Developed by cswimr and yname."""
|
|
||||||
|
|
||||||
def __init__(self, bot):
|
|
||||||
self.bot = bot
|
|
||||||
self.config = Config.get_conf(self, identifier=48258471944753312)
|
|
||||||
self.config.register_global(
|
|
||||||
bot_token = None
|
|
||||||
)
|
|
||||||
self.data_path = data_manager.cog_data_path(self)
|
|
||||||
|
|
||||||
class ConfigException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def export(self, channels: list):
|
|
||||||
token = await self.config.bot_token()
|
|
||||||
if token is None:
|
|
||||||
raise(self.ConfigException("Bot token not set!"))
|
|
||||||
data_path = data_manager.cog_data_path(self)
|
|
||||||
bundled_data_path = data_manager.bundled_data_path(self)
|
|
||||||
out = f'{data_path}{os.sep}Exported Channels'
|
|
||||||
channel = channels[0]
|
|
||||||
file_location_html = f'{os.sep}{out}{os.sep}%g{os.sep}%c{os.sep}Export.html'
|
|
||||||
file_location_json = f'{os.sep}{out}{os.sep}%g{os.sep}%c{os.sep}DCE-f.json'
|
|
||||||
try:
|
|
||||||
os.mkdir(out)
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
args = [
|
|
||||||
'dotnet',
|
|
||||||
'DiscordChatExporter.Cli.dll',
|
|
||||||
'export',
|
|
||||||
'--format', 'HtmlDark',
|
|
||||||
'--output', file_location_html,
|
|
||||||
'--token', token,
|
|
||||||
'--channel', channel,
|
|
||||||
'--reuse-media',
|
|
||||||
'--media',
|
|
||||||
'--fuck_russia', 'true',
|
|
||||||
]
|
|
||||||
os.chdir(bundled_data_path)
|
|
||||||
process_1 = await asyncio.create_subprocess_exec(*args)
|
|
||||||
while True:
|
|
||||||
return_code_1 = process_1.poll()
|
|
||||||
if return_code_1 is not None:
|
|
||||||
break
|
|
||||||
args = [
|
|
||||||
'dotnet',
|
|
||||||
'DiscordChatExporter.Cli.dll',
|
|
||||||
'export',
|
|
||||||
'--format', 'Json',
|
|
||||||
'--output', file_location_json,
|
|
||||||
'--token', token,
|
|
||||||
'--channel', channels,
|
|
||||||
'--reuse_media',
|
|
||||||
'--media',
|
|
||||||
'--markdown', 'false',
|
|
||||||
'--fuck_russia', 'true',
|
|
||||||
]
|
|
||||||
os.chdir(bundled_data_path)
|
|
||||||
process_2 = await asyncio.create_subprocess_exec(*args)
|
|
||||||
while True:
|
|
||||||
return_code_2 = process_2.poll()
|
|
||||||
if return_code_2 is not None:
|
|
||||||
break
|
|
||||||
|
|
||||||
@commands.group()
|
|
||||||
@checks.is_owner()
|
|
||||||
async def exportset(self, ctx: commands.Context):
|
|
||||||
"""Configuration options for the ExportChannels cog."""
|
|
||||||
|
|
||||||
@exportset.command()
|
|
||||||
@checks.is_owner()
|
|
||||||
async def token(self, ctx: commands.Context, token: str):
|
|
||||||
"""Sets the bot token used for Discord Chat Exporter."""
|
|
||||||
await self.config.bot_token.set({token})
|
|
||||||
await ctx.send(content="Token set!")
|
|
||||||
await ctx.delete()
|
|
||||||
|
|
||||||
@exportset.command()
|
|
||||||
@checks.is_owner()
|
|
||||||
async def checkoutputpath(self, ctx: commands.Context):
|
|
||||||
"""Checks what file path DCE is outputting to."""
|
|
||||||
await ctx.send(content=f"{self.data_path}")
|
|
||||||
|
|
||||||
@commands.command()
|
|
||||||
@commands.admin()
|
|
||||||
async def exportchannel(self, ctx: commands.Context, channel: discord.TextChannel):
|
|
||||||
"""Exports a channel using Discord Chat Exporter."""
|
|
||||||
token = await self.config.bot_token()
|
|
||||||
if token is None:
|
|
||||||
await ctx.send(content=f"Please set your token with the ``{ctx.prefix}exportset token`` command!")
|
|
||||||
return
|
|
||||||
id_list = [thread.id for thread in channel.threads]
|
|
||||||
id_list.insert(0, channel.id)
|
|
||||||
await self.export(id_list)
|
|
|
@ -1,5 +0,0 @@
|
||||||
from .forums import Forums
|
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
|
||||||
await bot.add_cog(Forums(bot))
|
|
208
forums/forums.py
208
forums/forums.py
|
@ -1,208 +0,0 @@
|
||||||
import discord
|
|
||||||
from discord import ui
|
|
||||||
from redbot.core import Config, commands
|
|
||||||
|
|
||||||
|
|
||||||
class Forums(commands.Cog):
|
|
||||||
"""Custom cog intended for use on the Galaxy discord server.
|
|
||||||
Developed by cswimr."""
|
|
||||||
|
|
||||||
def __init__(self, bot):
|
|
||||||
self.bot = bot
|
|
||||||
self.config = Config.get_conf(self, identifier=2352711325)
|
|
||||||
self.config.register_guild(
|
|
||||||
request_roles=[],
|
|
||||||
forum_channel=None,
|
|
||||||
forum_tag=None
|
|
||||||
)
|
|
||||||
|
|
||||||
@commands.command()
|
|
||||||
@commands.guild_only()
|
|
||||||
async def resolved(self, ctx: commands.Context, *, reason: str = None):
|
|
||||||
"""Marks a thread as resolved."""
|
|
||||||
channel_id = await self.config.guild(ctx.guild).forum_channel()
|
|
||||||
tag = await self.config.guild(ctx.guild).forum_tag()
|
|
||||||
request_role_ids = await self.config.guild(ctx.guild).request_roles()
|
|
||||||
if channel_id is None or tag is None or request_role_ids is None:
|
|
||||||
await ctx.reply(f"Configuration not set properly! Please set configuration options with `{ctx.prefix}resolvedset`.")
|
|
||||||
return
|
|
||||||
if isinstance(ctx.channel, discord.Thread) and ctx.channel.parent_id == channel_id:
|
|
||||||
request_roles = [ctx.guild.get_role(role_id) for role_id in request_role_ids]
|
|
||||||
match = any(role in ctx.author.roles for role in request_roles)
|
|
||||||
passed_info = {
|
|
||||||
"ctx": ctx
|
|
||||||
}
|
|
||||||
if match and reason:
|
|
||||||
passed_info.update({"reason": reason})
|
|
||||||
if match or ctx.author.id == ctx.channel.owner.id:
|
|
||||||
msg = await ctx.send("Are you sure you'd like to mark this thread as resolved?")
|
|
||||||
passed_info.update({"msg": msg})
|
|
||||||
await msg.edit(view=self.ResolvedButtons(timeout=180, passed_info=passed_info))
|
|
||||||
else:
|
|
||||||
await ctx.message.add_reaction("❌")
|
|
||||||
await ctx.message.delete(delay=5)
|
|
||||||
|
|
||||||
class ResolvedButtons(ui.View):
|
|
||||||
def __init__(self, timeout, passed_info: dict):
|
|
||||||
super().__init__()
|
|
||||||
self.timeout = timeout
|
|
||||||
self.ctx: commands.Context = passed_info['ctx']
|
|
||||||
self.msg: discord.Message = passed_info['msg']
|
|
||||||
if 'reason' in passed_info:
|
|
||||||
self.reason: str = passed_info['reason']
|
|
||||||
else:
|
|
||||||
self.reason = False
|
|
||||||
self.config = Config.get_conf(None, cog_name='Forums', identifier=2352711325)
|
|
||||||
|
|
||||||
@ui.button(label="Yes", style=discord.ButtonStyle.success, emoji="✅")
|
|
||||||
async def resolved_button_yes(self, interaction: discord.Interaction, button: ui.Button): # pylint: disable=unused-argument
|
|
||||||
request_role_ids = await self.config.guild(interaction.guild).request_roles()
|
|
||||||
request_roles = [interaction.guild.get_role(role_id) for role_id in request_role_ids]
|
|
||||||
match = any(role in interaction.user.roles for role in request_roles)
|
|
||||||
if match or interaction.user.id == interaction.channel.owner.id:
|
|
||||||
await interaction.response.defer()
|
|
||||||
if self.reason:
|
|
||||||
response_reason = f"Thread closed by {interaction.user.mention} with reason: {self.reason}"
|
|
||||||
reason = f"Thread closed by {interaction.user.name} ({interaction.user.id}) with reason: {self.reason}"
|
|
||||||
else:
|
|
||||||
response_reason = f"Thread closed by {interaction.user.mention}"
|
|
||||||
reason = f"Thread closed by {interaction.user.name} ({interaction.user.id})"
|
|
||||||
await self.msg.edit(content=response_reason, view=None)
|
|
||||||
await self.ctx.message.delete()
|
|
||||||
tag = interaction.channel.parent.get_tag(await self.config.guild(interaction.guild).forum_tag())
|
|
||||||
if tag in interaction.channel.applied_tags:
|
|
||||||
await interaction.channel.edit(locked=True, archived=True, reason=reason)
|
|
||||||
else:
|
|
||||||
await interaction.channel.edit(locked=True, archived=True, applied_tags=interaction.channel.applied_tags + [tag], reason=reason)
|
|
||||||
else:
|
|
||||||
await interaction.response.send_message(content="You cannot close this thread!", ephemeral=True)
|
|
||||||
|
|
||||||
@ui.button(label="No", style=discord.ButtonStyle.danger, emoji="✖️")
|
|
||||||
async def resolved_button_no(self, interaction: discord.Interaction, button: ui.Button): # pylint: disable=unused-argument
|
|
||||||
request_role_ids = await self.config.guild(interaction.guild).request_roles()
|
|
||||||
request_roles = [interaction.guild.get_role(role_id) for role_id in request_role_ids]
|
|
||||||
match = any(role in interaction.user.roles for role in request_roles)
|
|
||||||
if match or interaction.user.id == interaction.channel.owner.id:
|
|
||||||
await interaction.response.defer()
|
|
||||||
await self.msg.delete()
|
|
||||||
await self.ctx.message.delete()
|
|
||||||
else:
|
|
||||||
await interaction.response.send_message(content="You cannot close this thread!", ephemeral=True)
|
|
||||||
|
|
||||||
@commands.group(name='resolvedset', autohelp=True, aliases=['resolvedconfig'])
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def resolvedset(self, ctx: commands.Context):
|
|
||||||
"""Manages the configuration for the [p]resolved command."""
|
|
||||||
|
|
||||||
@resolvedset.command(name='show', aliases=['settings'])
|
|
||||||
async def resolvedset_show(self, ctx: commands.Context):
|
|
||||||
"""Shows the current cog configuration."""
|
|
||||||
channel_id = await self.config.guild(ctx.guild).forum_channel()
|
|
||||||
tag = await self.config.guild(ctx.guild).forum_tag()
|
|
||||||
request_role_ids = await self.config.guild(ctx.guild).request_roles()
|
|
||||||
split_content = ctx.message.content.split()
|
|
||||||
command = ' '.join(split_content[:1])
|
|
||||||
already_in_list = []
|
|
||||||
for role_id in request_role_ids:
|
|
||||||
role_obj = ctx.guild.get_role(role_id)
|
|
||||||
if role_obj:
|
|
||||||
already_in_list.append(role_obj.mention)
|
|
||||||
if already_in_list:
|
|
||||||
roles_list = "**Allowed Roles**:\n" + "\n".join(already_in_list)
|
|
||||||
else:
|
|
||||||
roles_list = f"No roles are currently in the allowed roles list.\n- Use `{command} add` to add some."
|
|
||||||
tag_str = None
|
|
||||||
if channel_id is not None:
|
|
||||||
channel_obj = ctx.guild.get_channel(channel_id)
|
|
||||||
if channel_obj is None:
|
|
||||||
channel = f"**Channel**: {channel_id}\n- ⚠️ This channel cannot be found in this guild. Is this the correct ID?\n\n"
|
|
||||||
else:
|
|
||||||
channel = f"**Channel**: {channel_obj.mention}\n\n"
|
|
||||||
if tag is not None:
|
|
||||||
tag_obj = channel_obj.get_tag(tag)
|
|
||||||
if tag_obj is None:
|
|
||||||
tag_str = f"**Tag**: {tag}\n- ⚠️ This tag cannot be found in the set forums channel. Is this the correct ID?\n\n"
|
|
||||||
else:
|
|
||||||
tag_str = f"**Tag**: {tag_obj.emoji} {tag_obj.name}\n\n"
|
|
||||||
else:
|
|
||||||
channel = f"**Channel**: Not set!\n- Use `{command} channel` to set the forums channel.\n\n"
|
|
||||||
if tag_str is None:
|
|
||||||
tag_str = f"**Tag**: Not set!\n- Use `{command} tag` to set the tag.\n\n"
|
|
||||||
embed = discord.Embed(title="Cog Settings", color=await self.bot.get_embed_color(None), description=channel + tag_str + roles_list)
|
|
||||||
await ctx.reply(embed=embed)
|
|
||||||
|
|
||||||
@resolvedset.group(name='role', autohelp=True, aliases=['roles'])
|
|
||||||
async def resolvedset_role(self, ctx: commands.Context):
|
|
||||||
"""Manages the allowed roles list."""
|
|
||||||
|
|
||||||
@resolvedset_role.command(name='add')
|
|
||||||
async def resolvedset_role_add(self, ctx: commands.Context, role: discord.Role = None):
|
|
||||||
"""Adds roles to the allowed roles list."""
|
|
||||||
current_list = await self.config.guild(ctx.guild).request_roles()
|
|
||||||
if role:
|
|
||||||
if role.id in current_list:
|
|
||||||
await ctx.send("This role is already in the allowed roles list!")
|
|
||||||
else:
|
|
||||||
current_list.append(role.id)
|
|
||||||
await self.config.guild(ctx.guild).request_roles.set(current_list)
|
|
||||||
await ctx.send(f"{role.mention} has been added to the allowed roles list.", allowed_mentions = discord.AllowedMentions(roles=False))
|
|
||||||
else:
|
|
||||||
await ctx.send("Please provide a valid role.")
|
|
||||||
|
|
||||||
@resolvedset_role.command(name='remove')
|
|
||||||
async def resolvedset_role_remove(self, ctx: commands.Context, role: discord.Role = None):
|
|
||||||
"""Removes roles from the allowed roles list."""
|
|
||||||
current_list = await self.config.guild(ctx.guild).request_roles()
|
|
||||||
if role.id in current_list:
|
|
||||||
current_list.remove(role.id)
|
|
||||||
await self.config.guild(ctx.guild).request_roles.set(current_list)
|
|
||||||
await ctx.send(f"{role.mention} has been removed from the allowed roles list.", allowed_mentions = discord.AllowedMentions(roles=False))
|
|
||||||
else:
|
|
||||||
await ctx.send("Please provide a valid role that exists in the allowed roles list.")
|
|
||||||
|
|
||||||
def create_select_options(self, ctx: commands.Context, data):
|
|
||||||
options = []
|
|
||||||
for tag in data:
|
|
||||||
emoji = ctx.guild.get_emoji(tag.emoji.id) if tag.emoji.id else str(tag.emoji.name)
|
|
||||||
options.append(discord.SelectOption(label=tag.name, emoji=emoji, description="", value=tag.id))
|
|
||||||
return options
|
|
||||||
|
|
||||||
@resolvedset.command(name="channel")
|
|
||||||
async def resolvedset_channel(self, ctx: commands.Context, channel: discord.abc.GuildChannel):
|
|
||||||
"""Sets the channel used by the [p]resolved command."""
|
|
||||||
if isinstance(channel, discord.ForumChannel):
|
|
||||||
await self.config.guild(ctx.guild).forum_channel.set(channel.id)
|
|
||||||
await ctx.reply(f"Forum channel has been set to {channel.mention}.")
|
|
||||||
else:
|
|
||||||
await ctx.reply(f"{channel.mention} is not a forums channel!")
|
|
||||||
|
|
||||||
@resolvedset.command(name="tag")
|
|
||||||
async def resolvedset_tag(self, ctx: commands.Context):
|
|
||||||
"""Sets the tag used by the [p]resolved command."""
|
|
||||||
channel: discord.ForumChannel = ctx.guild.get_channel(await self.config.guild(ctx.guild).forum_channel())
|
|
||||||
if channel is not None:
|
|
||||||
options = self.create_select_options(ctx, channel.available_tags)
|
|
||||||
msg = await ctx.reply("Select a forum tag below.")
|
|
||||||
await msg.edit(view=SelectView(msg, options))
|
|
||||||
else:
|
|
||||||
await ctx.reply("Configuration error! Channel does not exist.")
|
|
||||||
|
|
||||||
class Select(ui.Select):
|
|
||||||
def __init__(self, message, options):
|
|
||||||
self.message = message
|
|
||||||
super().__init__(placeholder="Select an option", max_values=1, min_values=1, options=options)
|
|
||||||
|
|
||||||
async def callback(self, interaction: discord.Interaction):
|
|
||||||
msg: discord.Message = self.message
|
|
||||||
config = Config.get_conf(None, cog_name='Forums', identifier=2352711325)
|
|
||||||
await config.guild(msg.guild).forum_tag.set(int(self.values[0]))
|
|
||||||
channel: discord.ForumChannel = msg.guild.get_channel(await config.guild(msg.guild).forum_channel())
|
|
||||||
tag = channel.get_tag(int(self.values[0]))
|
|
||||||
await msg.edit(content=f"Set resolved tag to {tag.emoji} {tag.name}", view=None)
|
|
||||||
await interaction.response.defer()
|
|
||||||
|
|
||||||
class SelectView(ui.View):
|
|
||||||
def __init__(self, message, options, *, timeout=180):
|
|
||||||
super().__init__(timeout=timeout)
|
|
||||||
self.add_item(Select(message, options))
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"author" : ["cswimr"],
|
|
||||||
"install_msg" : "Thank you for installing Forums!\nYou can find the source code of this cog here: https://coastalcommits.com/cswimr/GalaxyCogs",
|
|
||||||
"name" : "Forums",
|
|
||||||
"short" : "Custom cog intended for use on the Galaxy discord server.",
|
|
||||||
"description" : "Custom cog intended for use on the Galaxy discord server.",
|
|
||||||
"end_user_data_statement" : "This cog does not store any End User Data.",
|
|
||||||
"hidden": false,
|
|
||||||
"disabled": false
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
from .galaxy import Galaxy
|
from .galaxy import Galaxy
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
def setup(bot):
|
||||||
await bot.add_cog(Galaxy(bot))
|
bot.add_cog(Galaxy(bot))
|
472
galaxy/galaxy.py
472
galaxy/galaxy.py
|
@ -1,253 +1,124 @@
|
||||||
import re
|
from redbot.core import commands, checks, Config, bot
|
||||||
from datetime import datetime
|
|
||||||
from random import randint
|
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from redbot.core import Config, app_commands, commands
|
from datetime import datetime
|
||||||
from redbot.core.app_commands import Choice
|
import re
|
||||||
|
|
||||||
|
|
||||||
class Galaxy(commands.Cog):
|
class Galaxy(commands.Cog):
|
||||||
"""Custom cog intended for use on the Galaxy discord server.
|
"""Custom cog intended for use on the Galaxy discord server.
|
||||||
Developed by cswimr."""
|
Developed by SeaswimmerTheFsh."""
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.config = Config.get_conf(self, identifier=6621962)
|
self.config = Config.get_conf(self, identifier=6621962)
|
||||||
self.config.register_guild(
|
self.config.register_guild(
|
||||||
autoreact_target = 0,
|
cocotarget = 0,
|
||||||
autoreact_emoji = '💀'
|
cocoemoji = 1028535684757209118
|
||||||
)
|
)
|
||||||
|
|
||||||
@commands.command()
|
@commands.command(aliases=["pxc", "pc", "polarisconvert", "tatsutopolaris", "ttp"])
|
||||||
async def carnagerefund(self, ctx: commands.Context, message_id: str):
|
@commands.guild_only()
|
||||||
"""This command generates a link to refund carnage of killed ships."""
|
async def polarisxpconvert(self, ctx, *, tatsu_studs: str):
|
||||||
output = f"https://info.galaxy.casa/kills/{message_id}"
|
"""Converts Tatsu Studs to Polaris XP."""
|
||||||
await ctx.send(f"Output link: {output}")
|
try:
|
||||||
|
tatsu_studs_int = int(f"{tatsu_studs}".replace(",", ""))
|
||||||
@commands.Cog.listener('on_message')
|
except ValueError:
|
||||||
async def gank_won_let_us_flee(self, message: discord.Message):
|
await ctx.send(content="Please input a number!")
|
||||||
if message.author.id == 745790085789909033 and message.guild.id == 204965774618656769 and message.channel.id == 753714180900519937:
|
|
||||||
gank_media_list = [
|
|
||||||
"https://cdn.discordapp.com/attachments/1070838419212738621/1155174309711577138/gank_won_let_us_flee.gif",
|
|
||||||
"https://cdn.discordapp.com/attachments/1070838419212738621/1155174310093262951/spin_back_I_dare_you.jpg",
|
|
||||||
"https://cdn.discordapp.com/attachments/1070838419212738621/1155174310466572328/spin_back_mutt.gif",
|
|
||||||
"https://cdn.discordapp.com/attachments/1070838419212738621/1155174310806290533/We_dont_run_1s_around_here.gif"
|
|
||||||
]
|
|
||||||
if len(message.embeds) == 1 and str(message.embeds[0].color) == '#57f287':
|
|
||||||
await message.reply(gank_media_list[randint(0,3)])
|
|
||||||
|
|
||||||
@commands.Cog.listener('on_message')
|
|
||||||
async def autoreact(self, message: discord.Message):
|
|
||||||
if message.guild is not None:
|
|
||||||
emoji_id = await self.config.guild(message.guild).autoreact_emoji()
|
|
||||||
if self.check_if_discord_unicode_emoji(emoji_id) is False:
|
|
||||||
emoji = self.bot.get_emoji(emoji_id)
|
|
||||||
elif self.check_if_discord_unicode_emoji(emoji_id) is True:
|
|
||||||
emoji = emoji_id
|
|
||||||
autoreact_target = await self.config.guild(message.guild).autoreact_target()
|
|
||||||
if autoreact_target == 0:
|
|
||||||
return
|
return
|
||||||
if not message.author.id == autoreact_target:
|
math = round((tatsu_studs_int/25)*10)
|
||||||
|
output_from = f'{tatsu_studs_int:,}'
|
||||||
|
output_to = f'{math:,}'
|
||||||
|
embed = discord.Embed(color=await self.bot.get_embed_color(None))
|
||||||
|
embed.add_field(name="Tatsu Studs", value=f"{output_from}", inline=False)
|
||||||
|
embed.add_field(name="Polaris XP", value=f"{output_to}", inline=False)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def galaxyissues(self, ctx, target: discord.Member = None):
|
||||||
|
if ctx.me.id == 1070819799254438039:
|
||||||
|
embed = discord.Embed(title="Issue Reporting & Suggestions", color=await self.bot.get_embed_color(None), description="Have a problem or a suggestion for the Galaxy bot or GalaxyCogs? Read this!")
|
||||||
|
embed.add_field(name="Bot Issues & Suggestions", value="If you'd like to submit a suggestion or a bug report to the developers of the Galaxy bot, please do so [here](https://github.com/SeaswimmerTheFsh/GalaxyCogs/issues).\n**Please make sure whatever you're suggesting or reporting doesn't have an existing issue! If it does, you can comment on that issue with additional details if necessary.**")
|
||||||
|
else:
|
||||||
|
embed = discord.Embed(title="Issue Reporting & Suggestions", color=await self.bot.get_embed_color(None), description="Have a problem or a suggestion for GalaxyCogs? Read this!")
|
||||||
|
embed.add_field(name="Cog Issues & Suggestions", value="If you'd like to submit a suggestion or a bug report to the developers of GalaxyCogs, please do so [here](https://github.com/SeaswimmerTheFsh/GalaxyCogs/issues).\n**Please make sure whatever you're suggesting or reporting doesn't have an existing issue! If it does, you can comment on that issue with additional details if necessary.**")
|
||||||
|
if target:
|
||||||
|
await ctx.send(embed=embed, content=f"{target.mention}")
|
||||||
|
else:
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def lwaccess(self, ctx):
|
||||||
|
"""You shouldn't be able to see this!"""
|
||||||
|
role = ctx.guild.get_role(1083210988888784996)
|
||||||
|
if role in ctx.author.roles:
|
||||||
|
await ctx.author.remove_roles(role, reason="Requested through -lwaccess")
|
||||||
|
await ctx.send(content="Higher Access role removed.")
|
||||||
|
else:
|
||||||
|
await ctx.author.add_roles(role, reason="Requested through -lwaccess")
|
||||||
|
await ctx.send(content="Higher Access role added.")
|
||||||
|
|
||||||
|
@commands.Cog.listener('on_message')
|
||||||
|
async def cocoreact(self, message):
|
||||||
|
emoji = self.bot.get_emoji(await self.config.guild(message.guild).cocoemoji())
|
||||||
|
cocotarget = await self.config.guild(message.guild).cocotarget()
|
||||||
|
if cocotarget == 0:
|
||||||
|
return
|
||||||
|
if not message.author.id == cocotarget:
|
||||||
return
|
return
|
||||||
await message.add_reaction(emoji)
|
await message.add_reaction(emoji)
|
||||||
|
|
||||||
@commands.command(name='autoreact')
|
@commands.group(autohelp=False, invoke_without_command=True)
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
async def autoreact_list(self, ctx: commands.Context):
|
async def coco(self, ctx):
|
||||||
"""Checks Autoreact's settings."""
|
"""Checks who Coco is currently set to."""
|
||||||
emoji_id = await self.config.guild(ctx.guild).autoreact_emoji()
|
emoji = self.bot.get_emoji(await self.config.guild(ctx.guild).cocoemoji())
|
||||||
autoreact_target = await self.config.guild(ctx.guild).autoreact_target()
|
cocotarget = await self.config.guild(ctx.guild).cocotarget()
|
||||||
if self.check_if_discord_unicode_emoji(emoji_id) is True:
|
embed = discord.Embed(color=await self.bot.get_embed_color(None), description=f"Coco is currently set to <@{cocotarget}> ({cocotarget}).\nCoco's emoji is currently set to {emoji} ({await self.config.guild(ctx.guild).cocoemoji()}).")
|
||||||
emoji = emoji_id
|
|
||||||
embed = discord.Embed(color=await self.bot.get_embed_color(None), description=f"Autoreact is currently set to target <@{autoreact_target}> ({autoreact_target}).\nAutoreact's emoji is currently set to {emoji}.")
|
|
||||||
else:
|
|
||||||
emoji = self.bot.get_emoji(emoji_id)
|
|
||||||
embed = discord.Embed(color=await self.bot.get_embed_color(None), description=f"Autoreact is currently set to target <@{autoreact_target}> ({autoreact_target}).\nAutoreact's emoji is currently set to {emoji} ({await self.config.guild(ctx.guild).autoreact_emoji()}).")
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
autoreact = app_commands.Group(name='autoreact', guild_only=True, description="This group handles the autoreact functionality.")
|
@coco.command(name="emoji")
|
||||||
|
@checks.is_owner()
|
||||||
def check_if_discord_unicode_emoji(self, emoji: str):
|
async def coco_emoji_set(self, ctx, emoji: discord.Emoji = None):
|
||||||
emoji_ranges = [
|
"""Sets Coco's emoji."""
|
||||||
(0x1F600, 0x1F64F), # Emoticons
|
|
||||||
(0x1F300, 0x1F5FF), # Miscellaneous symbols and pictographs
|
|
||||||
(0x1F680, 0x1F6FF), # Transport and map symbols
|
|
||||||
(0x1F700, 0x1F77F), # Alchemical symbols
|
|
||||||
]
|
|
||||||
try:
|
|
||||||
for char in emoji:
|
|
||||||
code_point = ord(char)
|
|
||||||
for start, end in emoji_ranges:
|
|
||||||
if start <= code_point <= end:
|
|
||||||
return True
|
|
||||||
except TypeError:
|
|
||||||
return False
|
|
||||||
return False
|
|
||||||
|
|
||||||
def extract_id(self, input_string):
|
|
||||||
match = re.search(r'(?<=:)\d+(?=>)', input_string)
|
|
||||||
if match:
|
|
||||||
return int(match.group())
|
|
||||||
return input_string
|
|
||||||
|
|
||||||
@autoreact.command(name="emoji")
|
|
||||||
@app_commands.describe(emoji="Which emoji are you setting Autoreact to use?")
|
|
||||||
async def autoreact_emoji(self, interaction: discord.Interaction, emoji: str = None):
|
|
||||||
"""Sets Autoreact's emoji."""
|
|
||||||
if emoji:
|
if emoji:
|
||||||
if self.check_if_discord_unicode_emoji(emoji) is True:
|
await self.config.guild(ctx.guild).cocoemoji.set(emoji.id)
|
||||||
await self.config.guild(interaction.guild).autoreactemoji.set(emoji)
|
embed=discord.Embed(color=await self.bot.get_embed_color(None), description=f"Coco's emoji has been set to {emoji} ({emoji.id}).")
|
||||||
embed=discord.Embed(color=await self.bot.get_embed_color(None), description=f"Autoreact's emoji has been set to {emoji}.")
|
await ctx.send(embed=embed)
|
||||||
await interaction.response.send_message(embed=embed)
|
|
||||||
else:
|
else:
|
||||||
emoji_id = self.extract_id(input_string=emoji)
|
await self.config.guild(ctx.guild).cocoemoji.set(1028535684757209118)
|
||||||
for guild in self.bot.guilds:
|
emoji = self.bot.get_emoji(1028535684757209118)
|
||||||
emoji_to_find = discord.utils.get(guild.emojis, id=emoji_id)
|
embed=discord.Embed(color=await self.bot.get_embed_color(None), description=f"Coco's emoji has been set to {emoji} (1028535684757209118).")
|
||||||
if emoji_to_find:
|
await ctx.send(embed=embed)
|
||||||
emoji_obj = emoji_to_find
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
await interaction.response.send_message(content="You're trying to set the autoreact emoji to an emoji I don't have access to!", ephemeral=True)
|
|
||||||
return
|
|
||||||
await self.config.guild(interaction.guild).autoreact_emoji.set(emoji_obj.id)
|
|
||||||
embed=discord.Embed(color=await self.bot.get_embed_color(None), description=f"Autoreact's emoji has been set to {emoji_obj} ({emoji_obj.id}).")
|
|
||||||
await interaction.response.send_message(embed=embed)
|
|
||||||
else:
|
|
||||||
await self.config.guild(interaction.guild).autoreact_emoji.set('💀')
|
|
||||||
embed=discord.Embed(color=await self.bot.get_embed_color(None), description="Autoreact's emoji has been set to 💀.")
|
|
||||||
await interaction.response.send_message(embed=embed)
|
|
||||||
|
|
||||||
@autoreact.command(name="set")
|
@coco.command(name="set")
|
||||||
@app_commands.describe(member="Who are you targetting?")
|
@checks.is_owner()
|
||||||
async def autoreact_set(self, interaction: discord.Interaction, member: discord.Member):
|
async def coco_set(self, ctx, member: discord.Member):
|
||||||
"""Sets Autoreact's target."""
|
"""Sets Coco's target."""
|
||||||
if member:
|
if member:
|
||||||
await self.config.guild(interaction.guild).autoreact_target.set(member.id)
|
await self.config.guild(ctx.guild).cocotarget.set(member.id)
|
||||||
embed=discord.Embed(color=await self.bot.get_embed_color(None), description=f"Autoreact has been set to automatically react to {member.mention} ({member.id})'s messages.")
|
embed=discord.Embed(color=await self.bot.get_embed_color(None), description=f"Coco has been set to {member.mention} ({member.id}).")
|
||||||
await interaction.response.send_message(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
else:
|
else:
|
||||||
await interaction.response.send_message(content="That is not a valid argument!", ephemeral=True)
|
await ctx.send(content="That is not a valid argument!")
|
||||||
|
|
||||||
@autoreact.command(name="reset")
|
@coco.command(name="reset")
|
||||||
async def autoreact_reset(self, interaction: discord.Interaction):
|
@checks.is_owner()
|
||||||
"""Resets Autoreact's target."""
|
async def coco_reset(self, ctx):
|
||||||
await self.config.guild(interaction.guild).autoreact_target.set(0)
|
"""Resets Coco's target."""
|
||||||
embed=discord.Embed(color=await self.bot.get_embed_color(None), description="Autoreact's target has been reset.")
|
await self.config.guild(ctx.guild).cocotarget.set(0)
|
||||||
await interaction.response.send_message(embed=embed)
|
embed=discord.Embed(color=await self.bot.get_embed_color(None), description=f"Coco has been reset.")
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@commands.command()
|
@commands.command()
|
||||||
async def unix(self, ctx: commands.Context):
|
async def unix(self, ctx):
|
||||||
"""Posts the current Unix timestamp."""
|
"""Posts the current Unix timestamp."""
|
||||||
timestamp = int(datetime.timestamp(datetime.now()))
|
timestamp = int(datetime.timestamp(datetime.now()))
|
||||||
embed=discord.Embed(title="Current Time", url="https://www.unixtimestamp.com/", color=await self.bot.get_embed_color(None))
|
embed=discord.Embed(title="Current Time", color=await self.bot.get_embed_color(None), description=f"<t:{timestamp}>")
|
||||||
embed.add_field(name="Default", value=f"<t:{timestamp}>\n`<t:{timestamp}>`")
|
|
||||||
embed.add_field(name="Short Time", value=f"<t:{timestamp}:t>\n`<t:{timestamp}:t>`")
|
|
||||||
embed.add_field(name="Long Time", value=f"<t:{timestamp}:T>\n`<t:{timestamp}:T>`")
|
|
||||||
embed.add_field(name="Short Date/Time", value=f"<t:{timestamp}:f>\n`<t:{timestamp}:f>`")
|
|
||||||
embed.add_field(name="Short Date", value=f"<t:{timestamp}:d>\n`<t:{timestamp}:d>`")
|
|
||||||
embed.add_field(name="Long Date", value=f"<t:{timestamp}:D>\n`<t:{timestamp}:D>`")
|
|
||||||
embed.add_field(name="Long Date/Time", value=f"<t:{timestamp}:F>\n`<t:{timestamp}:F>`")
|
|
||||||
embed.add_field(name="Relative Time", value=f"<t:{timestamp}:R>\n`<t:{timestamp}:R>`")
|
|
||||||
embed.set_footer(text=f"{timestamp}")
|
embed.set_footer(text=f"{timestamp}")
|
||||||
|
embed.set_image(url="https://cdn.discordapp.com/attachments/1047347377348030494/1080048421127335956/image.png")
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
await ctx.message.delete()
|
await ctx.message.delete()
|
||||||
|
|
||||||
@commands.group(autohelp=True)
|
@commands.command()
|
||||||
async def insurance(self, ctx: commands.Context):
|
|
||||||
"""Calculates insurance.
|
|
||||||
Please only use the value of a ship (from ``/shipinfo``) to calculate insurance and **not** ship cost. Decimals do not work properly with this command, just remove them."""
|
|
||||||
|
|
||||||
async def _insurance(self, ship_class: str, value: str):
|
|
||||||
"""This function does the actual math and configures the embed.
|
|
||||||
|
|
||||||
Attributes
|
|
||||||
-----------
|
|
||||||
ship_class: Required[:class:`str`]
|
|
||||||
The class of the ship whose insurance you're checking.
|
|
||||||
|
|
||||||
value: Required[:class:`int`]
|
|
||||||
The value of the ship you're checking. This should be supplied by `/shipinfo`. Not the same as ship cost!"""
|
|
||||||
cleaned_value = int(''.join(char for char in value if char.isdigit()))
|
|
||||||
insurance_dict = {
|
|
||||||
"miner": 0.7,
|
|
||||||
"freighter": 0.65,
|
|
||||||
"frigate": 0.6,
|
|
||||||
"destroyer": 0.55,
|
|
||||||
"cruiser": 0.5,
|
|
||||||
"battlecruiser": 0.4,
|
|
||||||
"battleship": 0.35,
|
|
||||||
"dreadnought": 0.3,
|
|
||||||
"carrier": 0.3,
|
|
||||||
"super_capital": 0.25
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
insurance_dict[f'{ship_class}']
|
|
||||||
except KeyError as error:
|
|
||||||
raise ValueError("Received value is not a valid ship class!") from error
|
|
||||||
if ship_class == "super_capital":
|
|
||||||
humanized_class = ship_class.replace("_", " ").title()
|
|
||||||
else:
|
|
||||||
humanized_class = ship_class.capitalize()
|
|
||||||
insurance_amount = (f"{round(cleaned_value * insurance_dict[f'{ship_class}']):,}")
|
|
||||||
value_output = (f'{cleaned_value:,}')
|
|
||||||
embed = discord.Embed(title="Insurance Payout", color=await self.bot.get_embed_color(None))
|
|
||||||
embed.add_field(name="Ship Class", value=f"{humanized_class}", inline=False)
|
|
||||||
embed.add_field(name="Ship Value", value=f"{value_output}", inline=False)
|
|
||||||
embed.add_field(name="Insurance Amount", value=f"{insurance_amount}", inline=False)
|
|
||||||
return embed
|
|
||||||
|
|
||||||
@insurance.command()
|
|
||||||
async def miner(self, ctx: commands.Context, value):
|
|
||||||
"""Calculates insurance for miners. (70%)"""
|
|
||||||
await ctx.send(embed=await self._insurance('miner', value))
|
|
||||||
|
|
||||||
@insurance.command()
|
|
||||||
async def freighter(self, ctx: commands.Context, value):
|
|
||||||
"""Calculates insurance for freighters. (65%)"""
|
|
||||||
await ctx.send(embed=await self._insurance('freighter', value))
|
|
||||||
|
|
||||||
@insurance.command()
|
|
||||||
async def frigate(self, ctx: commands.Context, value):
|
|
||||||
"""Calculates insurance for frigates. (60%)"""
|
|
||||||
await ctx.send(embed=await self._insurance('frigate', value))
|
|
||||||
|
|
||||||
@insurance.command()
|
|
||||||
async def destroyer(self, ctx: commands.Context, value):
|
|
||||||
"""Calculates insurance for destroyers. (55%)"""
|
|
||||||
await ctx.send(embed=await self._insurance('destroyer', value))
|
|
||||||
|
|
||||||
@insurance.command()
|
|
||||||
async def cruiser(self, ctx: commands.Context, value):
|
|
||||||
"""Calculates insurance for cruisers. (50%)"""
|
|
||||||
await ctx.send(embed=await self._insurance('cruiser', value))
|
|
||||||
|
|
||||||
@insurance.command()
|
|
||||||
async def battlecruiser(self, ctx: commands.Context, value):
|
|
||||||
"""Calculates insurance for battlecruisers. (40%)"""
|
|
||||||
await ctx.send(embed=await self._insurance('battlecruiser', value))
|
|
||||||
|
|
||||||
@insurance.command()
|
|
||||||
async def battleship(self, ctx: commands.Context, value):
|
|
||||||
"""Calculates insurance for battleships. (35%)"""
|
|
||||||
await ctx.send(embed=await self._insurance('battleship', value))
|
|
||||||
|
|
||||||
@insurance.command()
|
|
||||||
async def dreadnought(self, ctx: commands.Context, value):
|
|
||||||
"""Calculates insurance for dreadnoughts. (30%)"""
|
|
||||||
await ctx.send(embed=await self._insurance('dreadnought', value))
|
|
||||||
|
|
||||||
@insurance.command()
|
|
||||||
async def carrier(self, ctx: commands.Context, value):
|
|
||||||
"""Calculates insurance for carriers. (30%)"""
|
|
||||||
await ctx.send(embed=await self._insurance('carrier', value))
|
|
||||||
|
|
||||||
@insurance.command()
|
|
||||||
async def supercapital(self, ctx: commands.Context, value):
|
|
||||||
"""Calculates insurance for super capitals. (25%)"""
|
|
||||||
await ctx.send(embed=await self._insurance('super_capital', value))
|
|
||||||
|
|
||||||
@commands.command(aliases=["wh"])
|
|
||||||
async def warehouse(self, ctx: commands.Context, lvlfrom: int = 1, lvlto: int = 38):
|
async def warehouse(self, ctx: commands.Context, lvlfrom: int = 1, lvlto: int = 38):
|
||||||
"""Calculates the total cost to upgrade your warehouse from a level to a level."""
|
"""Calculates the total cost to upgrade your warehouse from a level to a level."""
|
||||||
warehouse_levels = {1:0, 2:1000,3:2500,4:4500,5:7500,6:12500,7:20000,8:31500,9:46500,10:65500,11:87500,12:113500,13:143500,14:178500,15:218500,16:263500,17:313500,18:373500,19:443500,20:523500,21:613500,22:713500,23:823500,24:943500,25:1073500,26:1223500,27:1398500,28:1598500,29:1823500,30:2073500,31:2353500, 32:2663500, 33:3003500, 34:3373500, 35:3773500, 36:4193500, 37:4644500, 38:5093500}
|
warehouse_levels = {1:0, 2:1000,3:2500,4:4500,5:7500,6:12500,7:20000,8:31500,9:46500,10:65500,11:87500,12:113500,13:143500,14:178500,15:218500,16:263500,17:313500,18:373500,19:443500,20:523500,21:613500,22:713500,23:823500,24:943500,25:1073500,26:1223500,27:1398500,28:1598500,29:1823500,30:2073500,31:2353500, 32:2663500, 33:3003500, 34:3373500, 35:3773500, 36:4193500, 37:4644500, 38:5093500}
|
||||||
|
@ -271,78 +142,129 @@ class Galaxy(commands.Cog):
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
await ctx.message.delete()
|
await ctx.message.delete()
|
||||||
|
|
||||||
@app_commands.command()
|
@commands.group(autohelp=True)
|
||||||
@app_commands.describe(answer='Which answer are you trying to post?')
|
async def faq(self, ctx):
|
||||||
@app_commands.choices(answer=[
|
|
||||||
Choice(name='Important Links', value='links'),
|
|
||||||
Choice(name='DPS Calculations', value='dps'),
|
|
||||||
Choice(name='Reward Roles', value='reward_roles'),
|
|
||||||
Choice(name='NPC Intervals', value='npc_intervals'),
|
|
||||||
Choice(name='Linked Role', value='linked_role'),
|
|
||||||
Choice(name='RoPro', value='ropro')
|
|
||||||
])
|
|
||||||
async def faq(self, interaction: discord.Interaction, answer: Choice[str], member: discord.Member = None):
|
|
||||||
"""Posts answers to frequently asked questions."""
|
"""Posts answers to frequently asked questions."""
|
||||||
embed = None
|
|
||||||
embed_secondary = None
|
@faq.command(name="test")
|
||||||
if answer.value == 'dps':
|
@checks.admin()
|
||||||
embed = discord.Embed(title="DPS Calculations", color=await self.bot.get_embed_color(None), description="The ``/info`` command (and by extention ``/shipinfo`` from Odin) misreports DPS, due to it calculating DPS disregarding the turret's type (kinetic, laser), causing it to assume the target ship is both hulled and has shield simultaneously. It also ignores turret overrides, custom reloads, and custom damage values. If you'd like to check ship stats accurately, you can either use the ``/ship`` command in this channel or you can use the [Galaxy Info Website](https://info.galaxy.casa/ships). Alternatively, to check turret stats, you can use the [Galaxy Info Turrets Page](https://info.galaxy.casa/turrets).")
|
async def faq_test(self, ctx, member: discord.Member = None):
|
||||||
elif answer.value == 'links':
|
"""Testing FAQ"""
|
||||||
embed = discord.Embed(title="Important Links", color=await self.bot.get_embed_color(None))
|
embed=discord.Embed(title="Test Embed", color=await self.bot.get_embed_color(None), description="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer in faucibus odio, at mollis metus.")
|
||||||
|
embed.set_footer(text=ctx.author, icon_url=ctx.author.avatar_url_as(format="png", size=512))
|
||||||
|
if member:
|
||||||
|
await ctx.channel.send(embed=embed, content=member.mention)
|
||||||
|
else:
|
||||||
|
await ctx.channel.send(embed=embed)
|
||||||
|
await ctx.message.delete()
|
||||||
|
|
||||||
|
@faq.command(name="dps")
|
||||||
|
async def faq_dps(self, ctx, member: discord.Member = None):
|
||||||
|
"""DPS Calculations/Inaccuracy"""
|
||||||
|
embed=discord.Embed(title="DPS Calculations", color=await self.bot.get_embed_color(None), description="The ``/info`` command (and by extention ``/shipinfo`` from Odin) misreports DPS, due to it calculating DPS disregarding the turret's type (kinetic, laser), causing it to assume the target ship is both hulled and has shield simultaneously. It also ignores turret overrides, custom reloads, and custom damage values. If you'd like to check ship stats accurately, you can either use the ``/ship`` command in this channel or you can use the [Galaxy Info Website](https://galaxy.wingysam.xyz/ships). Alternatively, to check turret stats, you can use the [Galaxy Info Turrets Page](https://galaxy.wingysam.xyz/turrets).")
|
||||||
|
if member:
|
||||||
|
await ctx.channel.send(embed=embed, content=member.mention)
|
||||||
|
else:
|
||||||
|
await ctx.channel.send(embed=embed)
|
||||||
|
await ctx.message.delete()
|
||||||
|
|
||||||
|
@faq.command(name="links")
|
||||||
|
async def faq_links(self, ctx, member: discord.Member = None):
|
||||||
|
"""Posts important links, primarily invite links."""
|
||||||
|
embed=discord.Embed(title="Important Links", color=await self.bot.get_embed_color(None))
|
||||||
embed.add_field(name="Galaxy", value="[Galaxy Discord](https://discord.com/invite/robloxgalaxy)\n[Galaxy Support](https://discord.com/invite/ShWshkhYhZ)")
|
embed.add_field(name="Galaxy", value="[Galaxy Discord](https://discord.com/invite/robloxgalaxy)\n[Galaxy Support](https://discord.com/invite/ShWshkhYhZ)")
|
||||||
embed.add_field(name="Galaxypedia", value="[Galaxypedia Website](https://robloxgalaxy.wiki/wiki/Main_Page)\n[Galaxypedia Discord](https://discord.robloxgalaxy.wiki/)")
|
embed.add_field(name="Galaxypedia", value="[Galaxypedia Website](https://robloxgalaxy.wiki/wiki/Main_Page)\n[Galaxypedia Discord](https://discord.robloxgalaxy.wiki/)")
|
||||||
elif answer.value == 'npc_intervals':
|
if member:
|
||||||
embed = discord.Embed(title="NPC Spawn Intervals", color=await self.bot.get_embed_color(None), description="*Disclaimer: Spawn times may be different if EventID is active!*")
|
await ctx.channel.send(embed=embed, content=member.mention)
|
||||||
|
else:
|
||||||
|
await ctx.channel.send(embed=embed)
|
||||||
|
await ctx.message.delete()
|
||||||
|
|
||||||
|
@faq.command(name="ropro")
|
||||||
|
async def faq_ropro(self, ctx, member: discord.Member = None):
|
||||||
|
"""Posts a link to RoPro"""
|
||||||
|
embed=discord.Embed(title="RoPro", url="https://ropro.io", color=await self.bot.get_embed_color(None), description="""[RoPro](https://ropro.io) is a browser extension that tracks ROBLOX playtime, enhances your profile, and provides other useful utilities. **Please keep in mind that RoPro only tracks playtime from AFTER you install the extension.**""")
|
||||||
|
if member:
|
||||||
|
await ctx.channel.send(embed=embed, content=member.mention)
|
||||||
|
else:
|
||||||
|
await ctx.channel.send(embed=embed)
|
||||||
|
await ctx.message.delete()
|
||||||
|
|
||||||
|
@faq.command(name="polaris_ranks")
|
||||||
|
async def faq_polaris_ranks(self, ctx, member: discord.Member = None):
|
||||||
|
"""Lists required levels for certain roles."""
|
||||||
|
embed=discord.Embed(title="Polaris Ranks", color=await self.bot.get_embed_color(None))
|
||||||
|
embed.add_field(name="Picture Perms", value="Level 7", inline=False)
|
||||||
|
embed.add_field(name="Suggestions", value="Level 9", inline=False)
|
||||||
|
embed.add_field(name="DJ", value="Level 11", inline=False)
|
||||||
|
embed.add_field(name="Reaction Perms", value="Level 30", inline=False)
|
||||||
|
if member:
|
||||||
|
await ctx.channel.send(embed=embed, content=member.mention)
|
||||||
|
else:
|
||||||
|
await ctx.channel.send(embed=embed)
|
||||||
|
await ctx.message.delete()
|
||||||
|
|
||||||
|
@faq.command(name="polaris_switch")
|
||||||
|
@checks.admin()
|
||||||
|
async def faq_polaris_switch(self, ctx, member: discord.Member = None):
|
||||||
|
"""Posts an embed on the switch to the Polaris bot."""
|
||||||
|
embed=discord.Embed(title="Polaris FAQ", color=await self.bot.get_embed_color(None), description="As you probably know, we've decided to switch to the Polaris bot for leveling/xp, as opposed to Tatsu.\nThere are many reasons for this, which will be explained below.")
|
||||||
|
embed.add_field(name="Problems with Tatsu", value="1: Tatsu does not provide nearly as much configuration potential as Polaris does. An example of this is Polaris' customizable Level Curve.\n\n2: Tatsu does not have channel/role modifiers.\n\n3: Tatsu does not have actual levels, instead it has unconfigurable \"Global XP\", which gives \"Global Levels\". You cannot do anything with Global XP aside from blacklisting channels where people can gain it, like a bot-commands channel or something like that.\n\n4: Tatsu's leaderboard sucks, and only shows the top 10 on the web version.\n\n5: Tatsu has no XP management commands.\n\n6: Tatsu has TONS of bloat/useless commands, making the bot harder to configure.", inline=False)
|
||||||
|
embed.add_field(name="Polaris' Features", value="1: Polaris allows you to customize the level curve of your server, and provides presets to make the transition easier.\n\n2: Polaris has XP management commands.\n\n3: Polaris has way more configuration in terms of Reward Roles.\n\n4: Polaris allows you to customize the level-up message shown whenever people achieve the next level.\n\n5: Polaris has both role and channel modifiers.\n\n6: Polaris' leaderboard is excellent, showing the top 1,000 ranked users on the same webpage, and allowing you to see your own stats, progress towards your next reward role, and all 350 levels and your progress towards them.\n\n7: Polaris is **just** a leveling bot. You don't have to deal with any of the bloat of multi-purpose bots like Tatsu or MEE6, you only get what you actually need.", inline=False)
|
||||||
|
embed.add_field(name="Conclusion",value="With all of that said, you're probably wondering why we're putting so much effort into transferring peoples' data to the new bot.\n\nWell, Tatsu has been going since 2020, and I don't particularly favor the idea of clearing everyone's XP, especially when people have built up reward roles from Tatsu already, like Picture Perms, Suggestions access, and DJ.\n\nWith all this in mind, I hope this isn't too much of an inconvenience for you all, as I tried to make the process as seamless as possible without having to update all 10,000 people in the server.", inline=False)
|
||||||
|
if member:
|
||||||
|
await ctx.channel.send(embed=embed, content=member.mention)
|
||||||
|
else:
|
||||||
|
await ctx.channel.send(embed=embed)
|
||||||
|
await ctx.message.delete()
|
||||||
|
|
||||||
|
@faq.command(name="npc_intervals")
|
||||||
|
async def faq_npc_intervals(self, ctx, member: discord.Member = None):
|
||||||
|
"""Posts an embed containing NPC spawn intervals."""
|
||||||
|
embed=discord.Embed(title="NPC Spawn Intervals", color=await self.bot.get_embed_color(None), description="*Disclaimer: Spawn times may be different if EventID is active!*")
|
||||||
embed.add_field(name="Every 6.7 Minutes", value="[Dragoon](https://robloxgalaxy.wiki/wiki/Dragoon) *(80% Chance)*")
|
embed.add_field(name="Every 6.7 Minutes", value="[Dragoon](https://robloxgalaxy.wiki/wiki/Dragoon) *(80% Chance)*")
|
||||||
embed.add_field(name="Every 8.3 Minutes", value="[Swarmer](https://robloxgalaxy.wiki/wiki/Swarmer) *(33% Chance)*")
|
embed.add_field(name="Every 8.4 Minutes", value="[Swarmer](https://robloxgalaxy.wiki/wiki/Swarmer) *(33% Chance)*")
|
||||||
embed.add_field(name="Every 10 Minutes", value="[Jormungand](https://robloxgalaxy.wiki/wiki/Jormungand) *(75% Chance)*")
|
embed.add_field(name="Every 10 Minutes", value="[Jormungand](https://robloxgalaxy.wiki/wiki/Jormungand) *(75% Chance)*")
|
||||||
embed.add_field(name="Every 12.5 Minutes", value="[Bruiser](https://robloxgalaxy.wiki/wiki/Bruiser) *(50% Chance)*")
|
embed.add_field(name="Every 12.5 Minutes", value="[Bruiser](https://robloxgalaxy.wiki/wiki/Bruiser) *(50% Chance)*")
|
||||||
embed.add_field(name="Every 16.7 Minutes", value="[Outrider](https://robloxgalaxy.wiki/wiki/Outrider) *(50% Chance)*")
|
embed.add_field(name="Every 16.7 Minutes", value="[Outrider](https://robloxgalaxy.wiki/wiki/Outrider) *(50% Chance)*")
|
||||||
embed.add_field(name="Every 28.3 Minutes", value="[Punisher](https://robloxgalaxy.wiki/wiki/Punisher)")
|
embed.add_field(name="Every 28.5 Minutes", value="[Punisher](https://robloxgalaxy.wiki/wiki/Punisher)")
|
||||||
embed.add_field(name="Every 60 Minutes", value="[X-0](https://robloxgalaxy.wiki/wiki/X-0) *(45% Chance)*\n[Decimator](https://robloxgalaxy.wiki/wiki/Decimator)")
|
embed.add_field(name="Every 60 Minutes", value="[X-0](https://robloxgalaxy.wiki/wiki/X-0) *(45% Chance)*\n[Decimator](https://robloxgalaxy.wiki/wiki/Decimator)")
|
||||||
embed.add_field(name="Every 70 Minutes", value="[Galleon](https://robloxgalaxy.wiki/wiki/Galleon)")
|
embed.add_field(name="Every 70 Minutes", value="[Galleon](https://robloxgalaxy.wiki/wiki/Galleon)")
|
||||||
embed.add_field(name="Every 120 Minutes", value="[Kodiak](https://robloxgalaxy.wiki/wiki/Kodiak)")
|
embed.add_field(name="Every 120 Minutes", value="[Kodiak](https://robloxgalaxy.wiki/wiki/Kodiak)")
|
||||||
elif answer.value == 'linked_role':
|
if member:
|
||||||
embed = discord.Embed(title="Desktop / Web", color=await self.bot.get_embed_color(None), description="**Step 1:** Open the Server Dropdown menu in the top-left by clicking on the server's name.\n\n**Step 2:** Click the \"*Linked Roles*\" button.\n\n**Step 3:** Click on \"*Linked*.\"\n\n**Step 4:** Click \"*Finish*.\" You're done!\n*Note: You should already be Verified on Bloxlink. If you are not, go to the verification channel to verify.*")
|
await ctx.channel.send(embed=embed, content=member.mention)
|
||||||
embed.set_thumbnail(url="https://cdn.discordapp.com/attachments/1070838419212738621/1079927564421836930/image.png")
|
|
||||||
embed_secondary = discord.Embed(title="Mobile", color=await self.bot.get_embed_color(None), description="**Step 1:** Open the Server menu on the top of the channel list by tapping the server's name.\n\n**Step 2:** Scroll down and tap the \"*Linked Roles*\" button.\n\n**Step 3:** Tap on \"*Linked*.\"\n\n**Step 4:** Tap \"*Finish*.\" You're done!\n*Note: You should already be Verified on Bloxlink. If you are not, go to the verification channel to verify.*")
|
|
||||||
embed_secondary.set_thumbnail(url="https://cdn.discordapp.com/attachments/1047347377348030494/1079930169562771576/Screenshot_20230227_195338_Discord.jpg")
|
|
||||||
elif answer.value == 'reward_roles':
|
|
||||||
embed = discord.Embed(title="Reward Roles", color=await self.bot.get_embed_color(None))
|
|
||||||
embed.add_field(name="Picture Perms", value="Level 6")
|
|
||||||
embed.add_field(name="Suggestions", value="Level 8")
|
|
||||||
embed.add_field(name="DJ", value="Level 10")
|
|
||||||
embed.add_field(name="Reaction Perms", value="Level 20")
|
|
||||||
embed.add_field(name="External Emoji Perms", value="Level 30")
|
|
||||||
embed.set_footer(text="Use `-profile` to get your current level.")
|
|
||||||
elif answer.value == 'ropro':
|
|
||||||
embed = discord.Embed(title="RoPro", url="https://ropro.io", color=await self.bot.get_embed_color(None), description="""[RoPro](https://ropro.io) is a browser extension that tracks ROBLOX playtime, enhances your profile, and provides other useful utilities. **Please keep in mind that RoPro only tracks playtime from AFTER you install the extension.**""")
|
|
||||||
content = member.mention if member else None
|
|
||||||
await interaction.response.send_message(content="> The rigid requirement for bots to compulsorily respond to interactions in Discord, such as slash commands or application commands, is an irksome limitation that curtails the flexibility and natural flow of interactions. This forced response paradigm undermines the very essence of automation and intelligent design that bots were intended to offer. There are instances where silence or lack of response is not only acceptable but also desired, aligning with the nuanced dynamics of human communication. Discord's insistence on a response, even when it serves no purpose, imposes unnecessary complexity and verbosity, creating an environment where superfluous replies dilute the efficiency and elegance of bot-driven interactions. This constraint highlights the importance of granting bot developers the autonomy to determine the most suitable course of action based on context, contributing to a more seamless and user-centric experience within the Discord ecosystem.\n - ChatGPT", ephemeral=True)
|
|
||||||
response: discord.InteractionMessage = await interaction.original_response()
|
|
||||||
await response.delete()
|
|
||||||
if embed_secondary:
|
|
||||||
await interaction.channel.send(content=content, embeds=[embed, embed_secondary])
|
|
||||||
else:
|
else:
|
||||||
await interaction.channel.send(content=content, embed=embed)
|
await ctx.channel.send(embed=embed)
|
||||||
|
await ctx.message.delete()
|
||||||
|
|
||||||
# @faq.command(name="polaris_switch")
|
@faq.command(name="linked_role")
|
||||||
# @checks.admin()
|
async def faq_linked_role(self, ctx, member: discord.Member = None):
|
||||||
# async def faq_polaris_switch(self, ctx, member: discord.Member = None):
|
"""Posts an embed containing FAQ about Linked Role."""
|
||||||
# """Posts an embed on the switch to the Polaris bot."""
|
color=await self.bot.get_embed_color(None)
|
||||||
# embed=discord.Embed(title="Polaris FAQ", color=await self.bot.get_embed_color(None), description="As you probably know, we've decided to switch to the Polaris bot for leveling/xp, as opposed to Tatsu.\nThere are many reasons for this, which will be explained below.")
|
embed=discord.Embed(title="Linked Role", color=color, description="**Before reading this, please make sure your Discord client is updated! On Mobile, you can do this by going to your app store of choice and updating Discord manually. On the desktop app you can do this by clicking the green update button in the top right.**")
|
||||||
# embed.add_field(name="Problems with Tatsu", value="1: Tatsu does not provide nearly as much configuration potential as Polaris does. An example of this is Polaris' customizable Level Curve.\n\n2: Tatsu does not have channel/role modifiers.\n\n3: Tatsu does not have actual levels, instead it has unconfigurable \"Global XP\", which gives \"Global Levels\". You cannot do anything with Global XP aside from blacklisting channels where people can gain it, like a bot-commands channel or something like that.\n\n4: Tatsu's leaderboard sucks, and only shows the top 10 on the web version.\n\n5: Tatsu has no XP management commands.\n\n6: Tatsu has TONS of bloat/useless commands, making the bot harder to configure.", inline=False)
|
embed_desktop=discord.Embed(title="Desktop / Web", color=color, description="**Step 1:** Open the Server Dropdown menu in the top-left by clicking on the server's name.\n\n**Step 2:** Click the \"*Linked Roles*\" button.\n\n**Step 3:** Click on \"*Linked*.\"\n\n**Step 4:** Click \"*Finish*.\" You're done!\n*Note: You should already be Verified on Bloxlink. If you are not, go to the verification channel to verify.*")
|
||||||
# embed.add_field(name="Polaris' Features", value="1: Polaris allows you to customize the level curve of your server, and provides presets to make the transition easier.\n\n2: Polaris has XP management commands.\n\n3: Polaris has way more configuration in terms of Reward Roles.\n\n4: Polaris allows you to customize the level-up message shown whenever people achieve the next level.\n\n5: Polaris has both role and channel modifiers.\n\n6: Polaris' leaderboard is excellent, showing the top 1,000 ranked users on the same webpage, and allowing you to see your own stats, progress towards your next reward role, and all 350 levels and your progress towards them.\n\n7: Polaris is **just** a leveling bot. You don't have to deal with any of the bloat of multi-purpose bots like Tatsu or MEE6, you only get what you actually need.", inline=False)
|
embed_desktop.set_thumbnail(url="https://cdn.discordapp.com/attachments/1070838419212738621/1079927564421836930/image.png")
|
||||||
# embed.add_field(name="Conclusion",value="With all of that said, you're probably wondering why we're putting so much effort into transferring peoples' data to the new bot.\n\nWell, Tatsu has been going since 2020, and I don't particularly favor the idea of clearing everyone's XP, especially when people have built up reward roles from Tatsu already, like Picture Perms, Suggestions access, and DJ.\n\nWith all this in mind, I hope this isn't too much of an inconvenience for you all, as I tried to make the process as seamless as possible without having to update all 10,000 people in the server.", inline=False)
|
embed_mobile=discord.Embed(title="Mobile", color=color, description="**Step 1:** Open the Server menu on the top of the channel list by tapping the server's name.\n\n**Step 2:** Scroll down and tap the \"*Linked Roles*\" button.\n\n**Step 3:** Tap on \"*Linked*.\"\n\n**Step 4:** Tap \"*Finish*.\" You're done!\n*Note: You should already be Verified on Bloxlink. If you are not, go to the verification channel to verify.*")
|
||||||
# if member:
|
embed_mobile.set_thumbnail(url="https://cdn.discordapp.com/attachments/1047347377348030494/1079930169562771576/Screenshot_20230227_195338_Discord.jpg")
|
||||||
# await ctx.channel.send(embed=embed, content=member.mention)
|
if member:
|
||||||
# else:
|
await ctx.channel.send(embed=embed, content=member.mention)
|
||||||
# await ctx.channel.send(embed=embed)
|
else:
|
||||||
# await ctx.message.delete()
|
await ctx.channel.send(embed=embed)
|
||||||
|
await ctx.channel.send(embed=embed_desktop)
|
||||||
|
await ctx.channel.send(embed=embed_mobile)
|
||||||
|
await ctx.message.delete()
|
||||||
|
|
||||||
@warehouse.error
|
@warehouse.error
|
||||||
@unix.error
|
@unix.error
|
||||||
async def faq_handler(self, error):
|
@faq_test.error
|
||||||
|
@faq_linked_role.error
|
||||||
|
@faq_npc_intervals.error
|
||||||
|
@faq_links.error
|
||||||
|
@faq_dps.error
|
||||||
|
@faq_ropro.error
|
||||||
|
@faq_polaris_ranks.error
|
||||||
|
@faq_polaris_switch.error
|
||||||
|
async def faq_handler(self, ctx, error):
|
||||||
"""Error Handler for Galaxy."""
|
"""Error Handler for Galaxy."""
|
||||||
if isinstance(error, discord.NotFound):
|
if isinstance(error, discord.NotFound):
|
||||||
return
|
return
|
|
@ -1,10 +1,8 @@
|
||||||
{
|
{
|
||||||
"author" : ["cswimr"],
|
"author" : ["SeaswimmerTheFsh"],
|
||||||
"install_msg" : "Thank you for installing Galaxy!\nYou can find the source code of this cog here: https://coastalcommits.com/cswimr/GalaxyCogs",
|
"install_msg" : "Thank you for installing Galaxy!\nYou can find the source code of this cog here: https://github.com/SeaswimmerTheFsh/GalaxyCogs",
|
||||||
"name" : "Galaxy",
|
"name" : "Galaxy",
|
||||||
"short" : "Custom cog intended for use on the Galaxy discord server.",
|
"short" : "Custom cog intended for use on the Galaxy discord server.",
|
||||||
"description" : "Custom cog intended for use on the Galaxy discord server.",
|
"description" : "Custom cog intended for use on the Galaxy discord server.",
|
||||||
"end_user_data_statement" : "This cog does not store any End User Data.",
|
"end_user_data_statement" : "This cog does not store any End User Data."
|
||||||
"hidden": true,
|
|
||||||
"disabled": false
|
|
||||||
}
|
}
|
||||||
|
|
0
galaxy/temp.py
Normal file
0
galaxy/temp.py
Normal file
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"author": [
|
"author": [
|
||||||
"cswimr, yname, meelyman"
|
"SeaswimmerTheFsh, yname, meelyman"
|
||||||
],
|
],
|
||||||
"install_msg": "Thanks for installing my repo!\n\nIf you have any issues with any of the cogs, please create an issue here: https://coastalcommits.com/cswimr/GalaxyCogs/issues.",
|
"install_msg": "Thanks for installing my repo!\n\nIf you have any issues with any of the cogs, please create an issue here: https://github.com/SeaswimmerTheFsh/GalaxyCogs/issues.",
|
||||||
"name": "Galaxy",
|
"name": "Galaxy",
|
||||||
"short": "Cogs intended for use on the Galaxy discord server.",
|
"short": "Cogs intended for use on the Galaxy discord server.",
|
||||||
"description": "Custom cogs/cog modifications intended for the Galaxy discord server."
|
"description": "Custom cogs/cog modifications intended for the Galaxy discord server."
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from .info import Info
|
from .info import Info
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
def setup(bot):
|
||||||
await bot.add_cog(Info(bot))
|
bot.add_cog(Info(bot))
|
|
@ -1,10 +1,9 @@
|
||||||
{
|
{
|
||||||
"author" : ["cswimr"],
|
"author" : ["SeaswimmerTheFsh"],
|
||||||
"install_msg" : "Thank you for installing Info!\nYou can find the source code of this cog here: https://coastalcommits.com/cswimr/GalaxyCogs",
|
"install_msg" : "Thank you for installing Info!\nYou can find the source code of this cog here: https://github.com/SeaswimmerTheFsh/GalaxyCogs",
|
||||||
"name" : "Info",
|
"name" : "Info",
|
||||||
"short" : "Provides information on Discord objects.",
|
"short" : "Provides information on Discord objects.",
|
||||||
"description" : "Provides information on Discord objects. Most of this code is shamelessly ripped from <https://github.com/Cog-Creators/Red-DiscordBot/tree/V3/develop/redbot/cogs>.",
|
"description" : "Provides information on Discord objects. Most of this code is shamelessly ripped from <https://github.com/Cog-Creators/Red-DiscordBot/tree/V3/develop/redbot/cogs>.",
|
||||||
"end_user_data_statement" : "This cog does not store any End User Data.",
|
"end_user_data_statement" : "This cog does not store any End User Data."
|
||||||
"hidden": true,
|
|
||||||
"disabled": false
|
|
||||||
}
|
}
|
||||||
|
|
110
info/info.py
110
info/info.py
|
@ -1,13 +1,19 @@
|
||||||
import re
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import discord
|
import discord
|
||||||
from redbot.core import Config, app_commands, commands
|
from redbot.core import commands, checks, Config
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
from redbot.core.i18n import Translator, cog_i18n
|
from redbot.core.i18n import Translator, cog_i18n
|
||||||
from redbot.core.utils.chat_formatting import (bold, humanize_number,
|
import re
|
||||||
humanize_timedelta)
|
from redbot.core.utils.chat_formatting import (
|
||||||
|
bold,
|
||||||
|
humanize_number,
|
||||||
|
humanize_timedelta,
|
||||||
|
)
|
||||||
from redbot.core.utils.common_filters import (
|
from redbot.core.utils.common_filters import (
|
||||||
escape_spoilers_and_mass_mentions, filter_invites)
|
filter_invites,
|
||||||
|
escape_spoilers_and_mass_mentions
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
_ = T_ = Translator("General", __file__)
|
_ = T_ = Translator("General", __file__)
|
||||||
|
|
||||||
|
@ -28,14 +34,14 @@ class Info(commands.Cog):
|
||||||
self.config.register_user(**self.default_user_settings)
|
self.config.register_user(**self.default_user_settings)
|
||||||
self.cache: dict = {}
|
self.cache: dict = {}
|
||||||
|
|
||||||
async def red_delete_data_for_user(self):
|
async def red_delete_data_for_user(self, **kwargs):
|
||||||
"""Nothing to delete."""
|
"""Nothing to delete."""
|
||||||
return
|
return
|
||||||
|
|
||||||
@commands.command()
|
@commands.command()
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.bot_has_permissions(embed_links=True)
|
@commands.bot_has_permissions(embed_links=True)
|
||||||
async def serverinfo(self, ctx: commands.Context, details: bool = False):
|
async def serverinfo(self, ctx, details: bool = False):
|
||||||
"""
|
"""
|
||||||
Show server information.
|
Show server information.
|
||||||
|
|
||||||
|
@ -73,8 +79,8 @@ class Info(commands.Cog):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if guild.icon:
|
if guild.icon:
|
||||||
data.set_author(name=guild.name, icon_url=str(guild.icon.replace(format='png')))
|
data.set_author(name=guild.name, icon_url=str(guild.icon_url_as(format='png')))
|
||||||
data.set_thumbnail(url=str(guild.icon.replace(format='png')))
|
data.set_thumbnail(url=str(guild.icon_url_as(format='png')))
|
||||||
else:
|
else:
|
||||||
data.set_author(name=guild.name)
|
data.set_author(name=guild.name)
|
||||||
else:
|
else:
|
||||||
|
@ -82,16 +88,16 @@ class Info(commands.Cog):
|
||||||
def _size(num: int):
|
def _size(num: int):
|
||||||
for unit in ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]:
|
for unit in ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]:
|
||||||
if abs(num) < 1024.0:
|
if abs(num) < 1024.0:
|
||||||
return f"{num:.1f}{unit}"
|
return "{0:.1f}{1}".format(num, unit)
|
||||||
num /= 1024.0
|
num /= 1024.0
|
||||||
return f"{num:.1f}YB"
|
return "{0:.1f}{1}".format(num, "YB")
|
||||||
|
|
||||||
def _bitsize(num: int):
|
def _bitsize(num: int):
|
||||||
for unit in ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]:
|
for unit in ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]:
|
||||||
if abs(num) < 1000.0:
|
if abs(num) < 1000.0:
|
||||||
return f"{num:.1f}{unit}"
|
return "{0:.1f}{1}".format(num, unit)
|
||||||
num /= 1000.0
|
num /= 1000.0
|
||||||
return f"{num:.1f}YB"
|
return "{0:.1f}{1}".format(num, "YB")
|
||||||
|
|
||||||
shard_info = (
|
shard_info = (
|
||||||
_("\nShard ID: **{shard_id}/{shard_count}**").format(
|
_("\nShard ID: **{shard_id}/{shard_count}**").format(
|
||||||
|
@ -123,7 +129,7 @@ class Info(commands.Cog):
|
||||||
for emoji, value in online_stats.items():
|
for emoji, value in online_stats.items():
|
||||||
try:
|
try:
|
||||||
num = len([m for m in guild.members if value(m)])
|
num = len([m for m in guild.members if value(m)])
|
||||||
except Exception as error: # pylint: disable=broad-exception-caught
|
except Exception as error:
|
||||||
print(error)
|
print(error)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
@ -167,7 +173,7 @@ class Info(commands.Cog):
|
||||||
name=guild.name
|
name=guild.name
|
||||||
)
|
)
|
||||||
if guild.icon:
|
if guild.icon:
|
||||||
data.set_thumbnail(url=str(guild.icon.url))
|
data.set_thumbnail(url=str(guild.icon_url))
|
||||||
data.add_field(name=_("Members:"), value=member_msg)
|
data.add_field(name=_("Members:"), value=member_msg)
|
||||||
data.add_field(
|
data.add_field(
|
||||||
name=_("Channels:"),
|
name=_("Channels:"),
|
||||||
|
@ -254,7 +260,7 @@ class Info(commands.Cog):
|
||||||
)
|
)
|
||||||
data.add_field(name=_("Nitro Boost:"), value=nitro_boost)
|
data.add_field(name=_("Nitro Boost:"), value=nitro_boost)
|
||||||
if guild.splash:
|
if guild.splash:
|
||||||
data.set_image(url=str(guild.splash.replace(format='png')))
|
data.set_image(url=str(guild.splash_url_as(format='png')))
|
||||||
data.set_footer(text=joined_on)
|
data.set_footer(text=joined_on)
|
||||||
|
|
||||||
await ctx.send(embed=data)
|
await ctx.send(embed=data)
|
||||||
|
@ -267,7 +273,7 @@ class Info(commands.Cog):
|
||||||
c_status = None
|
c_status = None
|
||||||
if not a.name and not a.emoji:
|
if not a.name and not a.emoji:
|
||||||
return None, discord.ActivityType.custom
|
return None, discord.ActivityType.custom
|
||||||
if a.name and a.emoji:
|
elif a.name and a.emoji:
|
||||||
c_status = _("Custom: {emoji} {name}").format(emoji=a.emoji, name=a.name)
|
c_status = _("Custom: {emoji} {name}").format(emoji=a.emoji, name=a.name)
|
||||||
elif a.emoji:
|
elif a.emoji:
|
||||||
c_status = _("Custom: {emoji}").format(emoji=a.emoji)
|
c_status = _("Custom: {emoji}").format(emoji=a.emoji)
|
||||||
|
@ -341,7 +347,7 @@ class Info(commands.Cog):
|
||||||
self.handle_watching(user),
|
self.handle_watching(user),
|
||||||
self.handle_competing(user),
|
self.handle_competing(user),
|
||||||
]:
|
]:
|
||||||
status_string = a
|
status_string, status_type = a
|
||||||
if status_string is None:
|
if status_string is None:
|
||||||
continue
|
continue
|
||||||
string += f"{status_string}\n"
|
string += f"{status_string}\n"
|
||||||
|
@ -359,7 +365,7 @@ class Info(commands.Cog):
|
||||||
@commands.command()
|
@commands.command()
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.bot_has_permissions(embed_links=True)
|
@commands.bot_has_permissions(embed_links=True)
|
||||||
async def userinfo(self, ctx: commands.Context, *, member: discord.Member = None):
|
async def userinfo(self, ctx, *, member: discord.Member = None):
|
||||||
"""Show information about a member.
|
"""Show information about a member.
|
||||||
This includes fields for status, discord join date, server
|
This includes fields for status, discord join date, server
|
||||||
join date, voice state and previous names/nicknames.
|
join date, voice state and previous names/nicknames.
|
||||||
|
@ -471,54 +477,25 @@ class Info(commands.Cog):
|
||||||
if voice_state and voice_state.channel:
|
if voice_state and voice_state.channel:
|
||||||
data.add_field(
|
data.add_field(
|
||||||
name=_("Current voice channel"),
|
name=_("Current voice channel"),
|
||||||
value=f"{voice_state.channel.mention} ID: {voice_state.channel.id}",
|
value="{0.mention} ID: {0.id}".format(voice_state.channel),
|
||||||
inline=False,
|
inline=False,
|
||||||
)
|
)
|
||||||
data.set_footer(text=_(f"Member #{member_number} | User ID: {member.id}"))
|
data.set_footer(text=_("Member #{} | User ID: {}").format(member_number, member.id))
|
||||||
|
|
||||||
if member.discriminator == "0":
|
|
||||||
name = str(member.name)
|
|
||||||
else:
|
|
||||||
name = str(member)
|
name = str(member)
|
||||||
name = " ~ ".join((name, member.nick)) if member.nick else name
|
name = " ~ ".join((name, member.nick)) if member.nick else name
|
||||||
name = filter_invites(name)
|
name = filter_invites(name)
|
||||||
|
|
||||||
avatar = member.avatar.replace(format='png')
|
avatar = member.avatar_url_as(format='png')
|
||||||
data.set_author(name=f"{statusemoji} {name}", url=avatar)
|
data.set_author(name=f"{statusemoji} {name}", url=avatar)
|
||||||
data.set_thumbnail(url=avatar)
|
data.set_thumbnail(url=avatar)
|
||||||
|
|
||||||
await ctx.send(embed=data)
|
await ctx.send(embed=data)
|
||||||
|
|
||||||
async def fetch_twemoji(self, unicode_emoji):
|
@commands.command()
|
||||||
base_url = "https://cdn.jsdelivr.net/gh/jdecked/twemoji@latest/assets/72x72/"
|
@commands.guild_only()
|
||||||
emoji_codepoint = "-".join([hex(ord(char))[2:] for char in unicode_emoji])
|
async def roleinfo(self, ctx, role: discord.Role):
|
||||||
segments = emoji_codepoint.split("-")
|
"""Gives information on a specific role."""
|
||||||
valid_segments = [seg for seg in segments if len(seg) >= 4]
|
|
||||||
emoji_url = f"{base_url}{valid_segments[0]}.png"
|
|
||||||
return emoji_url
|
|
||||||
|
|
||||||
@app_commands.command()
|
|
||||||
@app_commands.guild_only()
|
|
||||||
async def roleinfo(self, interaction: discord.Interaction, role: discord.Role, list_permissions: bool = False):
|
|
||||||
"""Gives information on a given role.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
-----------
|
|
||||||
role: discord.Role
|
|
||||||
The role you're checking
|
|
||||||
list_permissions: bool
|
|
||||||
Whether or not to list permissions. Ignored if the role has Administrator.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
icon = role.display_icon
|
|
||||||
if isinstance(icon, discord.Asset):
|
|
||||||
icon_url = icon.url
|
|
||||||
elif isinstance(icon, str):
|
|
||||||
icon_url = await self.fetch_twemoji(unicode_emoji=icon)
|
|
||||||
else:
|
|
||||||
icon_url = None
|
|
||||||
except: # pylint: disable=bare-except
|
|
||||||
icon_url = None
|
|
||||||
permissions = role.permissions
|
permissions = role.permissions
|
||||||
if role.color.value == 0:
|
if role.color.value == 0:
|
||||||
colorint = 10070709
|
colorint = 10070709
|
||||||
|
@ -528,22 +505,9 @@ class Info(commands.Cog):
|
||||||
color = re.sub('#',"",str(role.color))
|
color = re.sub('#',"",str(role.color))
|
||||||
colorcodelink = f"https://www.color-hex.com/color/{color}"
|
colorcodelink = f"https://www.color-hex.com/color/{color}"
|
||||||
timestamp = int(datetime.timestamp(role.created_at))
|
timestamp = int(datetime.timestamp(role.created_at))
|
||||||
if role.managed is True:
|
if permissions.administrator:
|
||||||
managed_status = "True"
|
embed = discord.Embed(title=f"{role.name}", color=colorint, description=f"**ID:** {role.id}\n**Mention:** {role.mention}\n**Creation Date:** <t:{timestamp}>\n**Color:** [#{color}]({colorcodelink})\n**Hoisted:** {role.hoist}\n**Position:** {role.position}\n**Managed:** {role.managed}\n**Mentionable:** {role.mentionable}\n**Administrator:** {role.permissions.administrator}")
|
||||||
if role.is_premium_subscriber() is True:
|
|
||||||
managed_status += "\n**Management Type:** Nitro Booster"
|
|
||||||
if role.is_bot_managed() is True:
|
|
||||||
managed_status += "\n**Management Type:** Managed Bot Role"
|
|
||||||
if role.tags.is_guild_connection() is True:
|
|
||||||
managed_status +="\n**Management Type:** Guild Connection"
|
|
||||||
if role.tags.is_available_for_purchase() is True:
|
|
||||||
managed_status +="\n**Management Type:** Subscription"
|
|
||||||
else:
|
else:
|
||||||
managed_status = "False"
|
embed = discord.Embed(title=f"{role.name}", color=colorint, description=f"**ID:** {role.id}\n**Mention:** {role.mention}\n**Creation Date:** <t:{timestamp}>\n**Color:** [#{color}]({colorcodelink})\n**Hoisted:** {role.hoist}\n**Position:** {role.position}\n**Managed:** {role.managed}\n**Mentionable:** {role.mentionable}\n**Administrator:** {role.permissions.administrator}")
|
||||||
description = f"**ID:** {role.id}\n**Mention:** {role.mention}\n**Creation Date:** <t:{timestamp}>\n**Color:** [#{color}]({colorcodelink})\n**Hoisted:** {role.hoist}\n**Position:** {role.position}\n**Managed:** {managed_status}\n**Mentionable:** {role.mentionable}\n**Administrator:** {permissions.administrator}"
|
embed.add_field(name="Permissions", value=f"**Manage Server:** {permissions.manage_guild}\n**Manage Webhooks:** {permissions.manage_webhooks}\n**Manage Channels:** {permissions.manage_channels}\n**Manage Roles:** {permissions.manage_roles}\n**Manage Emojis:** {permissions.manage_emojis}\n**Manage Messages:** {permissions.manage_messages}\n**Manage Nicknames:** {permissions.manage_nicknames}\n**Mention @everyone**: {permissions.mention_everyone}\n**Ban Members:** {permissions.ban_members}\n**Kick Members:** {permissions.kick_members}")
|
||||||
embed = discord.Embed(title=f"{role.name}", color=colorint, description=description)
|
await ctx.send(embed=embed)
|
||||||
if icon_url:
|
|
||||||
embed.set_thumbnail(url=icon_url)
|
|
||||||
if permissions.administrator is False and list_permissions is True:
|
|
||||||
embed.add_field(name="Permissions", value=f"**Manage Server:** {permissions.manage_guild}\n**Manage Webhooks:** {permissions.manage_webhooks}\n**Manage Channels:** {permissions.manage_channels}\n**Manage Roles:** {permissions.manage_roles}\n**Create Expressions:** {permissions.create_expressions}\n**Manage Events:** {permissions.manage_events}\n**Manage Messages:** {permissions.manage_messages}\n**Manage Nicknames:** {permissions.manage_nicknames}\n**Mention @everyone**: {permissions.mention_everyone}\n**Ban Members:** {permissions.ban_members}\n**Kick Members:** {permissions.kick_members}\n**Timeout Members:** {permissions.moderate_members}\n**View Audit Log:** {permissions.view_audit_log}")
|
|
||||||
await interaction.response.send_message(embed=embed, ephemeral=True)
|
|
|
@ -1,5 +0,0 @@
|
||||||
from .issues import Issues
|
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
|
||||||
await bot.add_cog(Issues(bot))
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"author" : ["cswimr"],
|
|
||||||
"install_msg" : "Thank you for installing Issues!\nYou can find the source code of this cog here: https://coastalcommits.com/cswimr/GalaxyCogs",
|
|
||||||
"name" : "Issues",
|
|
||||||
"short" : "This cog allows you to create Gitea issues through a Discord modal.",
|
|
||||||
"description" : "This cog allows you to create Gitea issues through a Discord modal.",
|
|
||||||
"end_user_data_statement" : "This cog does not store any End User Data.",
|
|
||||||
"hidden": true,
|
|
||||||
"disabled": false
|
|
||||||
}
|
|
100
issues/issues.py
100
issues/issues.py
|
@ -1,100 +0,0 @@
|
||||||
import discord
|
|
||||||
from redbot.core import Config, app_commands, checks, commands
|
|
||||||
|
|
||||||
from . import modals
|
|
||||||
|
|
||||||
|
|
||||||
class Issues(commands.Cog):
|
|
||||||
"""This cog allows you to create Gitea issues through a Discord modal.
|
|
||||||
Developed by cswimr."""
|
|
||||||
|
|
||||||
def __init__(self, bot):
|
|
||||||
self.bot = bot
|
|
||||||
self.config = Config.get_conf(self, identifier=4285273314713, force_registration=True)
|
|
||||||
self.config.register_global(
|
|
||||||
request_channel = None,
|
|
||||||
gitea_root_url = None,
|
|
||||||
gitea_repository_owner = None,
|
|
||||||
gitea_repository = None,
|
|
||||||
gitea_token = None
|
|
||||||
)
|
|
||||||
|
|
||||||
@commands.command()
|
|
||||||
@checks.is_owner()
|
|
||||||
async def issuesconfig(self, ctx: commands.Context, channel: discord.TextChannel = None):
|
|
||||||
if channel:
|
|
||||||
await self.config.request_channel.set(channel.id)
|
|
||||||
await ctx.send(content=f"Channel set to {channel.mention}.\nRun this command again without a channel argument to configure the other settings.")
|
|
||||||
else:
|
|
||||||
await ctx.channel.send(content="Click the button below to configure the cog.", view=self.IssueConfigurationButton(self.config, ctx))
|
|
||||||
|
|
||||||
@app_commands.command()
|
|
||||||
async def issues(self, interaction: discord.Interaction):
|
|
||||||
"""Found a bug or have a suggestion for the Galaxy bot? Use this command."""
|
|
||||||
color = await self.bot.get_embed_color(None)
|
|
||||||
embed = discord.Embed(title="Issue Reporting & Suggestions", color=await self.bot.get_embed_color(None), description="Have a problem or a suggestion for the Galaxy bot or GalaxyCogs? Read this!")
|
|
||||||
embed.add_field(name="Bot Issues & Suggestions", value="If you'd like to submit a suggestion or a bug report to the developers of the Galaxy bot, please do so with the buttons below or by going [here](https://coastalcommits.com/cswimr/GalaxyCogs/issues/new/choose).\n**Please make sure whatever you're suggesting or reporting doesn't have an existing issue! If it does, you can comment on that issue with additional details if necessary.**")
|
|
||||||
embed.add_field(name="Cog Issues & Suggestions", value="If you'd like to submit a suggestion or a bug report to the developers of GalaxyCogs, please do so with the buttons below or by going [here](https://coastalcommits.com/cswimr/GalaxyCogs/issues/new/choose).\n**Please make sure whatever you're suggesting or reporting doesn't have an existing issue! If it does, you can comment on that issue with additional details if necessary.**")
|
|
||||||
await interaction.response.send_message(embed=embed, view=self.IssueButtons(color, self, interaction), ephemeral=True)
|
|
||||||
|
|
||||||
async def submit_issue_request(self, interaction: discord.Interaction, original_interaction: discord.Interaction, embed: discord.Embed):
|
|
||||||
channel = self.bot.get_channel(await self.config.request_channel())
|
|
||||||
if channel is None:
|
|
||||||
await original_interaction.edit_original_response(content="Command cancelled.", view=None)
|
|
||||||
await interaction.response.send_message(content="The cog is misconfigured, please report this error.", ephemeral=True)
|
|
||||||
try:
|
|
||||||
message = await channel.send(content=".")
|
|
||||||
await message.edit(content="", embed=embed, view=self.IssueResponseButtons(channel, message.id, interaction.user))
|
|
||||||
await original_interaction.edit_original_response(content="Issue request sent!", embed=embed, view=None)
|
|
||||||
await interaction.response.defer()
|
|
||||||
except (discord.HTTPException, discord.Forbidden) as error:
|
|
||||||
await original_interaction.edit_original_response(content="Command cancelled.", view=None)
|
|
||||||
await interaction.response.send_message(content=f"The cog is misconfigured, please report this error.\n```{error}```", ephemeral=True)
|
|
||||||
|
|
||||||
class IssueButtons(discord.ui.View):
|
|
||||||
def __init__(self, color, cog_instance, original_interaction):
|
|
||||||
super().__init__()
|
|
||||||
self.color = color
|
|
||||||
self.cog_instance = cog_instance
|
|
||||||
self.original_interaction = original_interaction
|
|
||||||
|
|
||||||
@discord.ui.button(label="Bot Bug", style=discord.ButtonStyle.danger)
|
|
||||||
async def issue_button_bot_bug(self, interaction: discord.Interaction, button: discord.ui.Button): # pylint: disable=unused-argument
|
|
||||||
await interaction.response.send_modal(modals.BotBugModal(self.color, self.cog_instance, self.original_interaction))
|
|
||||||
|
|
||||||
@discord.ui.button(label="Cog Bug", style=discord.ButtonStyle.danger)
|
|
||||||
async def issue_button_cog_bug(self, interaction: discord.Interaction, button: discord.ui.Button): # pylint: disable=unused-argument
|
|
||||||
await interaction.response.send_modal(modals.CogBugModal(self.color, self.cog_instance, self.original_interaction))
|
|
||||||
|
|
||||||
@discord.ui.button(label="Bot Suggestion", style=discord.ButtonStyle.blurple)
|
|
||||||
async def issue_button_bot_suggestion(self, interaction: discord.Interaction, button: discord.ui.Button): # pylint: disable=unused-argument
|
|
||||||
await interaction.response.send_modal(modals.BotSuggestionModal(self.color, self.cog_instance, self.original_interaction))
|
|
||||||
|
|
||||||
@discord.ui.button(label="Cog Suggestion", style=discord.ButtonStyle.blurple)
|
|
||||||
async def issue_button_cog_suggestion(self, interaction: discord.Interaction, button: discord.ui.Button): # pylint: disable=unused-argument
|
|
||||||
await interaction.response.send_modal(modals.CogSuggestionModal(self.color, self.cog_instance, self.original_interaction))
|
|
||||||
|
|
||||||
class IssueConfigurationButton(discord.ui.View):
|
|
||||||
def __init__(self, config, ctx):
|
|
||||||
super().__init__()
|
|
||||||
self.config = config
|
|
||||||
self.ctx = ctx
|
|
||||||
|
|
||||||
@discord.ui.button(label="Change Configuration", style=discord.ButtonStyle.blurple, row=0)
|
|
||||||
async def issue_configuration_button(self, interaction: discord.Interaction, button: discord.ui.Button): # pylint: disable=unused-argument
|
|
||||||
await interaction.response.send_modal(modals.IssuesConfigurationModal(self.config, self.ctx))
|
|
||||||
|
|
||||||
class IssueResponseButtons(discord.ui.View):
|
|
||||||
def __init__(self, channel, message_id, user):
|
|
||||||
super().__init__()
|
|
||||||
self.channel = channel
|
|
||||||
self.message_id = message_id
|
|
||||||
self.user = user
|
|
||||||
|
|
||||||
@discord.ui.button(label="Approve", style=discord.ButtonStyle.green)
|
|
||||||
async def issue_response_button_approve(self, interaction: discord.Interaction, button: discord.ui.Button): # pylint: disable=unused-argument
|
|
||||||
await interaction.response.send_modal(modals.IssueResponseModal(self.channel, self.message_id, self.user, True))
|
|
||||||
|
|
||||||
@discord.ui.button(label="Deny", style=discord.ButtonStyle.danger)
|
|
||||||
async def issue_response_button_deny(self, interaction: discord.Interaction, button: discord.ui.Button): # pylint: disable=unused-argument
|
|
||||||
await interaction.response.send_modal(modals.IssueResponseModal(self.channel, self.message_id, self.user, False))
|
|
382
issues/modals.py
382
issues/modals.py
|
@ -1,382 +0,0 @@
|
||||||
import aiohttp
|
|
||||||
import discord
|
|
||||||
from redbot.core import Config
|
|
||||||
|
|
||||||
#
|
|
||||||
# Misc. functions
|
|
||||||
#
|
|
||||||
|
|
||||||
def construct_embed(interaction: discord.Interaction, fields: list[discord.Embed.fields], color: str):
|
|
||||||
embed = discord.Embed(title="Issue Request", color=color)
|
|
||||||
for item in fields:
|
|
||||||
title = item.label
|
|
||||||
value = item.value
|
|
||||||
if value is not None:
|
|
||||||
if len(value) > 1024:
|
|
||||||
words = value.split()
|
|
||||||
split_value = []
|
|
||||||
current_part = ""
|
|
||||||
for word in words:
|
|
||||||
if len(current_part) + len(word) + 1 <= 1024:
|
|
||||||
current_part += word + " "
|
|
||||||
else:
|
|
||||||
split_value.append(current_part.strip())
|
|
||||||
current_part = word + " "
|
|
||||||
if current_part:
|
|
||||||
split_value.append(current_part.strip())
|
|
||||||
for i, part in enumerate(split_value):
|
|
||||||
embed.add_field(
|
|
||||||
name=title if i == 0 else "\u200b", value=part, inline=False
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
embed.add_field(name=title, value=value, inline=False)
|
|
||||||
if interaction.user.discriminator == "0":
|
|
||||||
username = interaction.user.name
|
|
||||||
else:
|
|
||||||
username = f"{interaction.user.name}#{interaction.user.discriminator}"
|
|
||||||
embed.set_footer(
|
|
||||||
text=f"Submitted by {username} ({interaction.user.id})",
|
|
||||||
icon_url=interaction.user.display_avatar.url,
|
|
||||||
)
|
|
||||||
return embed
|
|
||||||
|
|
||||||
#
|
|
||||||
# Modals for the core '/issues' command.
|
|
||||||
#
|
|
||||||
|
|
||||||
class BotBugModal(discord.ui.Modal, title="Creating issue..."):
|
|
||||||
def __init__(self, color, cog_instance, original_interaction):
|
|
||||||
super().__init__()
|
|
||||||
self.color = color
|
|
||||||
self.cog_instance = cog_instance
|
|
||||||
self.original_interaction = original_interaction
|
|
||||||
|
|
||||||
bug_description = discord.ui.TextInput(
|
|
||||||
label="Describe the bug",
|
|
||||||
placeholder="A clear and concise description of what the bug is.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=True,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
reproduction_steps = discord.ui.TextInput(
|
|
||||||
label="To Reproduce",
|
|
||||||
placeholder="What caused the bug?",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=True,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
expected_behavior = discord.ui.TextInput(
|
|
||||||
label="Expected Behavior",
|
|
||||||
placeholder="A clear and concise description of what you expected to happen.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=True,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
additional_context = discord.ui.TextInput(
|
|
||||||
label="Additional Context",
|
|
||||||
placeholder="Add any other context about the problem here.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=False,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
|
|
||||||
async def on_submit(self, interaction: discord.Interaction):
|
|
||||||
fields = [self.bug_description, self.reproduction_steps, self.expected_behavior, self.additional_context]
|
|
||||||
embed = construct_embed(interaction, fields, self.color)
|
|
||||||
embed.set_author(name="Bot Bug Report")
|
|
||||||
await self.cog_instance.submit_issue_request(interaction=interaction, original_interaction=self.original_interaction, embed=embed)
|
|
||||||
|
|
||||||
class CogBugModal(discord.ui.Modal, title="Creating issue..."):
|
|
||||||
def __init__(self, color, cog_instance, original_interaction):
|
|
||||||
super().__init__()
|
|
||||||
self.color = color
|
|
||||||
self.cog_instance = cog_instance
|
|
||||||
self.original_interaction = original_interaction
|
|
||||||
|
|
||||||
cog_name = discord.ui.TextInput(
|
|
||||||
label="What cog is causing this error?",
|
|
||||||
placeholder="If unsure, put \"GalaxyCogs\".",
|
|
||||||
style=discord.TextStyle.short,
|
|
||||||
required=True,
|
|
||||||
max_length=50
|
|
||||||
)
|
|
||||||
bug_description = discord.ui.TextInput(
|
|
||||||
label="Describe the bug",
|
|
||||||
placeholder="A clear and concise description of what the bug is.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=True,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
reproduction_steps = discord.ui.TextInput(
|
|
||||||
label="To Reproduce",
|
|
||||||
placeholder="What caused the bug?",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=True,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
expected_behavior = discord.ui.TextInput(
|
|
||||||
label="Expected Behavior",
|
|
||||||
placeholder="A clear and concise description of what you expected to happen.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=True,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
additional_context = discord.ui.TextInput(
|
|
||||||
label="Additional Context",
|
|
||||||
placeholder="Add any other context about the problem here.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=False,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
|
|
||||||
async def on_submit(self, interaction: discord.Interaction):
|
|
||||||
fields = [self.cog_name, self.bug_description, self.reproduction_steps, self.expected_behavior, self.additional_context]
|
|
||||||
embed = construct_embed(interaction, fields, self.color)
|
|
||||||
embed.set_author(name="Cog Bug Report")
|
|
||||||
await self.cog_instance.submit_issue_request(interaction=interaction, original_interaction=self.original_interaction, embed=embed)
|
|
||||||
|
|
||||||
class BotSuggestionModal(discord.ui.Modal, title="Creating issue..."):
|
|
||||||
def __init__(self, color, cog_instance, original_interaction):
|
|
||||||
super().__init__()
|
|
||||||
self.color = color
|
|
||||||
self.cog_instance = cog_instance
|
|
||||||
self.original_interaction = original_interaction
|
|
||||||
|
|
||||||
suggestion_description = discord.ui.TextInput(
|
|
||||||
label="Describe your suggestion.",
|
|
||||||
placeholder="A clear and concise description of what your suggestion is.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=True,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
alternatives = discord.ui.TextInput(
|
|
||||||
label="Describe alternatives you've considered.",
|
|
||||||
placeholder="A clear and concise description of any alternative solutions or features you've cnosidered.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=True,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
additional_context = discord.ui.TextInput(
|
|
||||||
label="Additional Context",
|
|
||||||
placeholder="Add any other context about your suggestion here.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=False,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
|
|
||||||
async def on_submit(self, interaction: discord.Interaction):
|
|
||||||
fields = [self.suggestion_description, self.alternatives, self.additional_context]
|
|
||||||
embed = construct_embed(interaction, fields, self.color)
|
|
||||||
embed.set_author(name="Cog Suggestion")
|
|
||||||
await self.cog_instance.submit_issue_request(interaction=interaction, original_interaction=self.original_interaction, embed=embed)
|
|
||||||
|
|
||||||
class CogSuggestionModal(discord.ui.Modal, title="Creating issue..."):
|
|
||||||
def __init__(self, color, cog_instance, original_interaction):
|
|
||||||
super().__init__()
|
|
||||||
self.color = color
|
|
||||||
self.cog_instance = cog_instance
|
|
||||||
self.original_interaction = original_interaction
|
|
||||||
|
|
||||||
cog_name = discord.ui.TextInput(
|
|
||||||
label="What cog is your suggestion for?",
|
|
||||||
placeholder="If unsure, put \"GalaxyCogs\".",
|
|
||||||
style=discord.TextStyle.short,
|
|
||||||
required=True,
|
|
||||||
max_length=50
|
|
||||||
)
|
|
||||||
suggestion_description = discord.ui.TextInput(
|
|
||||||
label="Describe your suggestion.",
|
|
||||||
placeholder="A clear and concise description of what your suggestion is.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=True,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
alternatives = discord.ui.TextInput(
|
|
||||||
label="Describe alternatives you've considered.",
|
|
||||||
placeholder="A clear and concise description of any alternative solutions or features you've cnosidered.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=True,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
additional_context = discord.ui.TextInput(
|
|
||||||
label="Additional Context",
|
|
||||||
placeholder="Add any other context about your suggestion here.",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=False,
|
|
||||||
max_length=2048
|
|
||||||
)
|
|
||||||
|
|
||||||
async def on_submit(self, interaction: discord.Interaction):
|
|
||||||
fields = [self.cog_name, self.suggestion_description, self.alternatives, self.additional_context]
|
|
||||||
embed = construct_embed(interaction, fields, self.color)
|
|
||||||
embed.set_author(name="Cog Suggestion")
|
|
||||||
await self.cog_instance.submit_issue_request(interaction=interaction, original_interaction=self.original_interaction, embed=embed)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Response modal
|
|
||||||
#
|
|
||||||
|
|
||||||
class IssueResponseModal(discord.ui.Modal, title="Sending response message..."):
|
|
||||||
def __init__(self, channel, message_id, user, approved):
|
|
||||||
super().__init__()
|
|
||||||
self.channel = channel
|
|
||||||
self.message_id = message_id
|
|
||||||
self.user = user
|
|
||||||
self.approved = approved
|
|
||||||
self.config = Config.get_conf(None, cog_name="Issues", identifier=4285273314713)
|
|
||||||
|
|
||||||
issue_title_input = discord.ui.TextInput(
|
|
||||||
label="Title",
|
|
||||||
placeholder="Only use this if you're accepting the issue request.",
|
|
||||||
style=discord.TextStyle.short,
|
|
||||||
required=False,
|
|
||||||
max_length=200,
|
|
||||||
)
|
|
||||||
response = discord.ui.TextInput(
|
|
||||||
label="Response",
|
|
||||||
placeholder="",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=False,
|
|
||||||
max_length=1024,
|
|
||||||
)
|
|
||||||
|
|
||||||
async def on_submit(self, interaction: discord.Interaction):
|
|
||||||
message: discord.Message = await self.channel.fetch_message(self.message_id)
|
|
||||||
embed = message.embeds[0]
|
|
||||||
field_values = []
|
|
||||||
field_names = []
|
|
||||||
|
|
||||||
if self.approved:
|
|
||||||
embed.color = 1226519
|
|
||||||
embed.title = "Issue Request Approved"
|
|
||||||
status = "accepted"
|
|
||||||
else:
|
|
||||||
embed.color = 15671552
|
|
||||||
embed.title = "Issue Request Denied"
|
|
||||||
status = "denied"
|
|
||||||
await interaction.response.send_message(content=f"Issue request {status}.", ephemeral=True)
|
|
||||||
|
|
||||||
if self.response.value != "":
|
|
||||||
embed.add_field(
|
|
||||||
name=f"Response from {interaction.user.name}",
|
|
||||||
value=self.response.value,
|
|
||||||
inline=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.approved:
|
|
||||||
for field in embed.fields:
|
|
||||||
field_names.append(f"**{field.name}**")
|
|
||||||
field_values.append(field.value)
|
|
||||||
|
|
||||||
if self.issue_title_input.value != "":
|
|
||||||
_issue_title = self.issue_title_input.value
|
|
||||||
else:
|
|
||||||
_issue_title = "Automatically generated issue"
|
|
||||||
|
|
||||||
if embed.author.name == "Bot Bug Report":
|
|
||||||
issue_title = f"[BOT BUG] {_issue_title}"
|
|
||||||
# desired_labels = ["bot", "bug"]
|
|
||||||
elif embed.author.name == "Bot Suggestion":
|
|
||||||
issue_title = f"[BOT SUGGESTION] {_issue_title}"
|
|
||||||
# desired_labels = ["bot", "enhancement"]
|
|
||||||
elif embed.author.name == "Cog Bug Report":
|
|
||||||
issue_title = f"[{field_values[0]}] {_issue_title}"
|
|
||||||
# desired_labels = ["cog", "bug"]
|
|
||||||
elif embed.author.name == "Cog Suggestion":
|
|
||||||
issue_title = f"[{field_values[0]}] {_issue_title}"
|
|
||||||
# desired_labels = ["cog", "enhancement"]
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"Authorization": f"Bearer {await self.config.gitea_token()}",
|
|
||||||
"Accept": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
url = f"{await self.config.gitea_root_url()}/api/v1/repos/{await self.config.gitea_repository_owner()}/{await self.config.gitea_repository()}/issues"
|
|
||||||
|
|
||||||
issue_body = "\n".join(
|
|
||||||
[f"{name}\n{value}" for name, value in zip(field_names, field_values)]
|
|
||||||
)
|
|
||||||
|
|
||||||
# async def fetch_labels():
|
|
||||||
# async with aiohttp.ClientSession(headers=headers) as session:
|
|
||||||
# async with session.post(url=f"{await self.config.gitea_root_url()}/api/v1/repos/{await self.config.gitea_repository_owner()}/{await self.config.gitea_repository()}/labels") as response:
|
|
||||||
# label_list = []
|
|
||||||
# for label in response.json():
|
|
||||||
# if label["name"] in desired_labels:
|
|
||||||
# label_list.append(label["id"])
|
|
||||||
# if label_list is None:
|
|
||||||
# print("Error! Labels are not properly configured on the target repository.")
|
|
||||||
# return await label_list
|
|
||||||
|
|
||||||
issue_labels = None
|
|
||||||
|
|
||||||
if issue_labels is None:
|
|
||||||
issue_data = {"title": issue_title, "body": issue_body}
|
|
||||||
else:
|
|
||||||
issue_data = {"title": issue_title, "body": issue_body, "labels": issue_labels}
|
|
||||||
|
|
||||||
async def create_issue():
|
|
||||||
async with aiohttp.ClientSession(headers=headers) as session:
|
|
||||||
async with session.post(url, json=issue_data) as response:
|
|
||||||
return await response.json(), response.status
|
|
||||||
|
|
||||||
response_json, status_code = await create_issue()
|
|
||||||
if status_code == 201:
|
|
||||||
await interaction.response.send_message(
|
|
||||||
content=f"Issue request {status}.\n[Issue successfully created.]({response_json.get('html_url')})",
|
|
||||||
ephemeral=True,
|
|
||||||
)
|
|
||||||
embed.url = response_json.get("html_url")
|
|
||||||
|
|
||||||
await message.edit(embed=embed, view=None)
|
|
||||||
await self.user.send(embed=embed)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Configuration modal
|
|
||||||
#
|
|
||||||
|
|
||||||
class IssuesConfigurationModal(discord.ui.Modal, title="Modifying configuration..."):
|
|
||||||
def __init__(self, config, ctx):
|
|
||||||
super().__init__()
|
|
||||||
self.config = config
|
|
||||||
self.ctx = ctx
|
|
||||||
|
|
||||||
gitea_root_url = discord.ui.TextInput(
|
|
||||||
label="Gitea Root URL",
|
|
||||||
placeholder="https://try.gitea.io",
|
|
||||||
style=discord.TextStyle.short,
|
|
||||||
required=False,
|
|
||||||
max_length=200
|
|
||||||
)
|
|
||||||
gitea_repository_owner = discord.ui.TextInput(
|
|
||||||
label="Gitea Repository Owner",
|
|
||||||
placeholder="foo",
|
|
||||||
style=discord.TextStyle.short,
|
|
||||||
required=False,
|
|
||||||
max_length=200
|
|
||||||
)
|
|
||||||
gitea_repository = discord.ui.TextInput(
|
|
||||||
label="Gitea Repository Name",
|
|
||||||
placeholder="bar",
|
|
||||||
style=discord.TextStyle.short,
|
|
||||||
required=False,
|
|
||||||
max_length=200
|
|
||||||
)
|
|
||||||
gitea_token = discord.ui.TextInput(
|
|
||||||
label="Gitea User Access Token",
|
|
||||||
placeholder="Generate one from your user settings page.",
|
|
||||||
style=discord.TextStyle.short,
|
|
||||||
required=False,
|
|
||||||
max_length=200
|
|
||||||
)
|
|
||||||
|
|
||||||
async def on_submit(self, interaction: discord.Interaction):
|
|
||||||
if self.gitea_token.value != "":
|
|
||||||
await self.config.gitea_token.set(self.gitea_token.value)
|
|
||||||
if self.gitea_root_url.value != "":
|
|
||||||
await self.config.gitea_root_url.set(self.gitea_root_url.value)
|
|
||||||
if self.gitea_repository_owner.value != "":
|
|
||||||
await self.config.gitea_repository_owner.set(self.gitea_repository_owner.value)
|
|
||||||
if self.gitea_repository.value != "":
|
|
||||||
await self.config.gitea_repository.set(self.gitea_repository.value)
|
|
||||||
await interaction.response.send_message(content="Configuration changed!")
|
|
|
@ -1,5 +1,5 @@
|
||||||
from .podcast import Podcast
|
from .podcast import Podcast
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
def setup(bot):
|
||||||
await bot.add_cog(Podcast(bot))
|
bot.add_cog(Podcast(bot))
|
|
@ -1,10 +1,9 @@
|
||||||
{
|
{
|
||||||
"author" : ["cswimr"],
|
"author" : ["SeaswimmerTheFsh"],
|
||||||
"install_msg" : "Thank you for installing Podcast!\nYou can find the source code of this cog here: https://coastalcommits.com/cswimr/GalaxyCogs",
|
"install_msg" : "Thank you for installing Podcast!\nYou can find the source code of this cog here: https://github.com/SeaswimmerTheFsh/GalaxyCogs",
|
||||||
"name" : "Podcast",
|
"name" : "Podcast",
|
||||||
"short" : "Provides a questions submission system.",
|
"short" : "Provides a questions submission system.",
|
||||||
"description" : "Provies a questions submission system.",
|
"description" : "Provies a questions submission system.",
|
||||||
"end_user_data_statement" : "This cog does not store any End User Data.",
|
"end_user_data_statement" : "This cog does not store any End User Data."
|
||||||
"hidden": true,
|
|
||||||
"disabled": true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
from redbot.core import Config, checks, commands
|
import discord
|
||||||
|
from datetime import datetime
|
||||||
|
from redbot.core.bot import Red
|
||||||
|
from redbot.core import commands, checks, Config, bot
|
||||||
|
|
||||||
class Podcast(commands.Cog):
|
class Podcast(commands.Cog):
|
||||||
"""Provides a questions submission system for podcasts.
|
"""Provides a questions submission system for podcasts.
|
||||||
Developed by cswimr."""
|
Developed by SeaswimmerTheFsh."""
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
@ -19,19 +21,20 @@ class Podcast(commands.Cog):
|
||||||
)
|
)
|
||||||
|
|
||||||
@commands.command()
|
@commands.command()
|
||||||
async def podcast(self, ctx: commands.Context, question: str):
|
async def podcast(self, ctx, question: str):
|
||||||
"""Submits a question to the Podcast."""
|
"""Submits a question to the Podcast."""
|
||||||
prefix = await self.bot.get_valid_prefixes()
|
prefix = await self.bot.get_valid_prefixes()
|
||||||
if await self.config.guild(ctx.guild).global_mode(True):
|
if await self.config.guild(ctx.guild).global_mode(True):
|
||||||
submission_channel = ctx.bot.get_channel(await self.config.global_submission_channel())
|
submission_channel = bot.get_channel(await self.config.global_submission_channel())
|
||||||
blacklisted_users = await self.config.global_blacklisted_users()
|
blacklisted_users = await self.config.global_blacklisted_users()
|
||||||
elif await self.config.guild(ctx.guild).global_mode(False):
|
elif await self.config.guild(ctx.guild).global_mode(False):
|
||||||
submission_channel = ctx.bot.get_channel(await self.config.guild(ctx.guild).submission_channel())
|
submission_channel = bot.get_channel(await self.config.guild(ctx.guild).submission_channel())
|
||||||
blacklisted_users = await self.config.guild(ctx.guild).blacklisted_users()
|
blacklisted_users = await self.config.guild(ctx.guild).blacklisted_users()
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
if ctx.author.id in blacklisted_users:
|
if ctx.author.id in blacklisted_users:
|
||||||
await ctx.author.send(content=f"You are blacklisted from ``{prefix}podcast``!")
|
await ctx.author.send(content=f"You are blacklisted from ``{prefix}podcast``!")
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
await submission_channel.send(content=f"{question}")
|
await submission_channel.send(content=f"{question}")
|
||||||
await ctx.send(content="Question submitted!")
|
await ctx.send(content="Question submitted!")
|
||||||
|
@ -45,10 +48,10 @@ class Podcast(commands.Cog):
|
||||||
@podcastset.command(name="global")
|
@podcastset.command(name="global")
|
||||||
async def set_global_mode(self, ctx, enabled: bool):
|
async def set_global_mode(self, ctx, enabled: bool):
|
||||||
"""Enables or disables global mode."""
|
"""Enables or disables global mode."""
|
||||||
if enabled is True:
|
if enabled == True:
|
||||||
await self.config.guild(ctx.guild).global_mode.set(True)
|
await self.config.guild(ctx.guild).global_mode.set(True)
|
||||||
await ctx.send(content="``global_mode`` has been enabled.")
|
await ctx.send(content="``global_mode`` has been enabled.")
|
||||||
elif enabled is False:
|
elif enabled == False:
|
||||||
await self.config.guild(ctx.guild).global_mode.set(False)
|
await self.config.guild(ctx.guild).global_mode.set(False)
|
||||||
await ctx.send(content="``global_mode`` has been disabled.")
|
await ctx.send(content="``global_mode`` has been disabled.")
|
||||||
else:
|
else:
|
||||||
|
|
2023
poetry.lock
generated
2023
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,28 +0,0 @@
|
||||||
[tool.poetry]
|
|
||||||
name = "galaxycogs"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Custom cogs/cog modifications intended for the Galaxy discord server."
|
|
||||||
authors = ["Galaxy Discord Management Team"]
|
|
||||||
license = "MPL 2"
|
|
||||||
readme = "README.md"
|
|
||||||
package-mode = false
|
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
|
||||||
python = ">=3.9,<3.12"
|
|
||||||
Red-DiscordBot = "^3.5.5"
|
|
||||||
pytimeparse2 = "^1.7.1"
|
|
||||||
prisma = "^0.10.0"
|
|
||||||
mysql-connector-python = "^8.1.0"
|
|
||||||
humanize = "^4.8.0"
|
|
||||||
pytube = "^15.0.0"
|
|
||||||
ruff = "^0.3.6"
|
|
||||||
|
|
||||||
[tool.poetry.group.dev]
|
|
||||||
optional = true
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
|
||||||
pylint = "^2.17.5"
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["poetry-core"]
|
|
||||||
build-backend = "poetry.core.masonry.api"
|
|
|
@ -1,5 +0,0 @@
|
||||||
from .send import Send
|
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
|
||||||
await bot.add_cog(Send(bot))
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"author" : ["cswimr"],
|
|
||||||
"install_msg" : "Thank you for installing Send!\nYou can find the source code of this cog here: https://coastalcommits.com/cswimr/GalaxyCogs",
|
|
||||||
"name" : "Send",
|
|
||||||
"short" : "Allows you to send messages as the bot user!",
|
|
||||||
"description" : "Allows you to send messages as the bot user!.",
|
|
||||||
"end_user_data_statement" : "This cog does not store any End User Data.",
|
|
||||||
"hidden": true,
|
|
||||||
"disabled": false
|
|
||||||
}
|
|
66
send/send.py
66
send/send.py
|
@ -1,66 +0,0 @@
|
||||||
from typing import Union
|
|
||||||
import discord
|
|
||||||
from redbot.core import commands, app_commands
|
|
||||||
|
|
||||||
class Send(commands.Cog):
|
|
||||||
"""Allows you to send messages as the bot account."""
|
|
||||||
|
|
||||||
def __init__(self, bot):
|
|
||||||
self.bot = bot
|
|
||||||
|
|
||||||
async def send_to_target(self, target: Union[discord.Member, discord.TextChannel], interaction: discord.Interaction, message: str, secondary_message: str = None):
|
|
||||||
if isinstance(target, discord.Member):
|
|
||||||
target_type = "member"
|
|
||||||
elif isinstance(target, discord.TextChannel):
|
|
||||||
target_type = "textchannel"
|
|
||||||
try:
|
|
||||||
await target.send(message)
|
|
||||||
if secondary_message is not None:
|
|
||||||
await target.send(secondary_message)
|
|
||||||
await interaction.response.send_message(content=f"Message sent to {target.mention}!\nMessage contents:\n```{message}```\n```{secondary_message}```", ephemeral=True)
|
|
||||||
else:
|
|
||||||
await interaction.response.send_message(content=f"Message sent to {target.mention}!\nMessage contents:\n```{message}```", ephemeral=True)
|
|
||||||
except (discord.HTTPException, discord.Forbidden):
|
|
||||||
if target_type == "member":
|
|
||||||
await interaction.response.send_message(content="That user has their direct messages closed!", ephemeral=True)
|
|
||||||
elif target_type == "textchannel":
|
|
||||||
await interaction.response.send_message(content="I cannot access that channel!", ephemeral=True)
|
|
||||||
|
|
||||||
class MessageModal(discord.ui.Modal, title="Sending message..."):
|
|
||||||
def __init__(self, target):
|
|
||||||
super().__init__()
|
|
||||||
self.target = target
|
|
||||||
message = discord.ui.TextInput(
|
|
||||||
label="Message Content",
|
|
||||||
placeholder="I'm contacting you about your cars extended warranty...",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
max_length=1750
|
|
||||||
)
|
|
||||||
secondary_message = discord.ui.TextInput(
|
|
||||||
label="Secondary Message Content",
|
|
||||||
placeholder="Typically used for images/image links.",
|
|
||||||
style=discord.TextStyle.short,
|
|
||||||
required=False,
|
|
||||||
max_length=200
|
|
||||||
)
|
|
||||||
|
|
||||||
async def on_submit(self, interaction: discord.Interaction):
|
|
||||||
await Send.send_to_target(self, self.target, interaction, self.message, self.secondary_message)
|
|
||||||
|
|
||||||
send = app_commands.Group(name="send", description="Send a message as the bot user!")
|
|
||||||
|
|
||||||
@send.command(name="user", description="Sends a direct message to a user.")
|
|
||||||
async def user(self, interaction: discord.Interaction, member: discord.Member, message: str = None):
|
|
||||||
"""Sends a direct message to a user."""
|
|
||||||
if message:
|
|
||||||
await Send.send_to_target(self, member, interaction, message)
|
|
||||||
else:
|
|
||||||
await interaction.response.send_modal(Send.MessageModal(member))
|
|
||||||
|
|
||||||
@send.command(name="channel", description="Sends a message to a channel.")
|
|
||||||
async def channel(self, interaction: discord.Interaction, channel: discord.TextChannel, message: str = None):
|
|
||||||
"""Sends a message to a channel."""
|
|
||||||
if message:
|
|
||||||
await Send.send_to_target(self, channel, interaction, message)
|
|
||||||
else:
|
|
||||||
await interaction.response.send_modal(Send.MessageModal(channel))
|
|
|
@ -1,5 +0,0 @@
|
||||||
from .shortmute import Shortmute
|
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
|
||||||
await bot.add_cog(Shortmute(bot))
|
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"author" : ["cswimr"],
|
|
||||||
"install_msg" : "Thank you for installing Shortmute!\nYou can find the source code of this cog here: https://coastalcommits.com/cswimr/GalaxyCogs",
|
|
||||||
"name" : "Shortmute",
|
|
||||||
"short" : "Allows staff members to shortmute individuals for up to 30 minutes.",
|
|
||||||
"description" : "Allows staff members to shortmute individuals for up to 30 minutes, using Discord's Timeouts feature.",
|
|
||||||
"tags" : ["moderation, mutes, timeouts"],
|
|
||||||
"end_user_data_statement": "This cog stores no end user data.",
|
|
||||||
"requirements": ["pytimeparse2"],
|
|
||||||
"hidden": true,
|
|
||||||
"disabled": false
|
|
||||||
}
|
|
|
@ -1,346 +0,0 @@
|
||||||
import discord
|
|
||||||
from discord import ui
|
|
||||||
from discord.ext.commands import Bot
|
|
||||||
from pytimeparse2 import disable_dateutil, parse
|
|
||||||
from redbot.core import Config, app_commands, commands
|
|
||||||
|
|
||||||
class Shortmute(commands.Cog):
|
|
||||||
"""Allows staff members to shortmute individuals for up to 30 minutes, using Discord's Timeouts feature."""
|
|
||||||
|
|
||||||
def __init__(self, bot) -> None:
|
|
||||||
self.bot = bot
|
|
||||||
self.config = Config.get_conf(self, identifier=25781647388294, force_registration=True)
|
|
||||||
self.config.register_guild(
|
|
||||||
dm = True,
|
|
||||||
confirm = True,
|
|
||||||
logging_channels = [],
|
|
||||||
immune_roles = [],
|
|
||||||
blacklisted_users = []
|
|
||||||
)
|
|
||||||
|
|
||||||
@app_commands.command()
|
|
||||||
@app_commands.rename(target='member')
|
|
||||||
async def shortmute(self, interaction: discord.Interaction, target: discord.Member, duration: int, reason: str, evidence_link: str = None, evidence_image: discord.Attachment = None, skip_confirmation: bool = None):
|
|
||||||
"""Shortmute someone for up to 30m.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
-----------
|
|
||||||
target: discord.Member
|
|
||||||
The member to shortmute
|
|
||||||
duration: int
|
|
||||||
The duration of the shortmute
|
|
||||||
reason: str
|
|
||||||
The reason for the shortmute
|
|
||||||
evidence_link: str = None
|
|
||||||
An image link to evidence for the shortmute, do not use with evidence_image
|
|
||||||
evidence_image: discord.Attachment = None
|
|
||||||
An image file used as evidence for the shortmute, do not use with evidence_link
|
|
||||||
skip_confirmation: bool = None
|
|
||||||
This allows you skip the confirmation prompt and immediately shortmute the user.
|
|
||||||
"""
|
|
||||||
disable_dateutil()
|
|
||||||
timedelta = parse(f'{duration} minutes', as_timedelta=True)
|
|
||||||
if evidence_image and evidence_link:
|
|
||||||
await interaction.response.send_message(content="You've provided both the `evidence_image` and the `evidence_link` arguments! Please only use one or the other.", ephemeral=True)
|
|
||||||
return
|
|
||||||
if evidence_link:
|
|
||||||
evidence = evidence_link
|
|
||||||
elif evidence_image:
|
|
||||||
evidence = str(evidence_image)
|
|
||||||
else:
|
|
||||||
evidence = None
|
|
||||||
if skip_confirmation is None:
|
|
||||||
skip_confirmation = not bool(await self.config.guild(interaction.guild).confirm())
|
|
||||||
passed_info = {
|
|
||||||
"target": target,
|
|
||||||
"timedelta": timedelta,
|
|
||||||
"reason": reason,
|
|
||||||
"interaction": interaction,
|
|
||||||
"color": await self.bot.get_embed_color(interaction.guild),
|
|
||||||
"evidence": evidence
|
|
||||||
}
|
|
||||||
blacklisted_users_list = await self.config.guild(interaction.guild).blacklisted_users()
|
|
||||||
for user_id in blacklisted_users_list:
|
|
||||||
if user_id == interaction.user.id:
|
|
||||||
await interaction.response.send_message(content="You are blacklisted from `/shortmute`!", ephemeral=True)
|
|
||||||
return
|
|
||||||
if target.bot is True:
|
|
||||||
await interaction.response.send_message(content="You cannot shortmute bots!", ephemeral=True)
|
|
||||||
return
|
|
||||||
if interaction.user.guild_permissions.administrator is False:
|
|
||||||
immune_roles_list = await self.config.guild(interaction.guild).immune_roles()
|
|
||||||
for role_id in immune_roles_list:
|
|
||||||
role = interaction.guild.get_role(role_id)
|
|
||||||
if role in target.roles:
|
|
||||||
await interaction.response.send_message(content="You're trying to shortmute someone who is immune from shortmuting.", ephemeral=True)
|
|
||||||
return
|
|
||||||
if target.guild_permissions.administrator is True:
|
|
||||||
await interaction.response.send_message(content="You cannot shortmute people with the Administrator permission!", ephemeral=True)
|
|
||||||
return
|
|
||||||
if duration in (1, -1):
|
|
||||||
readable_duration = f"{duration} minute"
|
|
||||||
else:
|
|
||||||
readable_duration = f"{duration} minutes"
|
|
||||||
passed_info.update({
|
|
||||||
"readable_duration": readable_duration
|
|
||||||
})
|
|
||||||
if duration > 30:
|
|
||||||
await interaction.response.send_message(content=f"{readable_duration} is longer than the 30 minutes you are allowed to shortmute users for.", ephemeral=True)
|
|
||||||
return
|
|
||||||
if duration < 1:
|
|
||||||
await interaction.response.send_message(content=f"Please shortmute the user for longer than {readable_duration}! The maximum duration is 30 minutes.", ephemeral=True)
|
|
||||||
return
|
|
||||||
if skip_confirmation is False:
|
|
||||||
embed = discord.Embed(title="Are you sure?", description=f"**Moderator:** {interaction.user.mention}\n**Target:** {target.mention}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`", color=await self.bot.get_embed_color(interaction.guild))
|
|
||||||
embed.set_footer(text="/shortmute")
|
|
||||||
if evidence:
|
|
||||||
embed.set_image(url=evidence)
|
|
||||||
await interaction.response.send_message(embed=embed, view=self.ShortmuteButtons(timeout=180, passed_info=passed_info), ephemeral=True)
|
|
||||||
elif skip_confirmation is True:
|
|
||||||
edit_embed = discord.Embed(title="Shortmute confirmed!", description=f"**Moderator:** {interaction.user.mention}\n**Target:** {target.mention}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`", color=await self.bot.get_embed_color(interaction.guild))
|
|
||||||
edit_embed.set_footer(text="/shortmute")
|
|
||||||
if evidence:
|
|
||||||
edit_embed.set_image(url=evidence)
|
|
||||||
message = await interaction.response.send_message(embed=edit_embed, ephemeral=True)
|
|
||||||
await target.timeout(timedelta, reason=f"User shortmuted for {readable_duration} by {interaction.user.name} ({interaction.user.id}) for: {reason}")
|
|
||||||
shortmute_msg = await interaction.channel.send(content=f"{target.mention} was shortmuted for {readable_duration} by {interaction.user.mention} for: `{reason}`")
|
|
||||||
if await self.config.guild(interaction.guild).dm() is True:
|
|
||||||
dm_embed = discord.Embed(title=f"You've been shortmuted in {interaction.guild.name}!", description=f"**Moderator:** {interaction.user.mention}\n**Target:** {target.mention}\n**Message:** {shortmute_msg.jump_url}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`", color=await self.bot.get_embed_color(interaction.guild))
|
|
||||||
dm_embed.set_footer(text="/shortmute")
|
|
||||||
if evidence:
|
|
||||||
dm_embed.set_image(url=evidence)
|
|
||||||
try:
|
|
||||||
await target.send(embed=dm_embed)
|
|
||||||
except discord.HTTPException:
|
|
||||||
await message.edit(content="Could not message the target, user most likely has Direct Messages disabled.")
|
|
||||||
logging_channels_list = await self.config.guild(interaction.guild).logging_channels()
|
|
||||||
if logging_channels_list:
|
|
||||||
logging_embed = discord.Embed(title="User Shortmuted", description=f"**Moderator:** {interaction.user.mention} ({interaction.user.id})\n**Target:** {target.mention} ({target.id})\n**Message:** {shortmute_msg.jump_url}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`\n**Confirmation Skipped:** True", color=await self.bot.get_embed_color(interaction.guild))
|
|
||||||
logging_embed.set_footer(text="/shortmute")
|
|
||||||
if evidence:
|
|
||||||
logging_embed.set_image(url=evidence)
|
|
||||||
for channel_id in logging_channels_list:
|
|
||||||
channel_obj = interaction.guild.get_channel(channel_id)
|
|
||||||
await channel_obj.send(embed=logging_embed)
|
|
||||||
|
|
||||||
class ShortmuteButtons(ui.View):
|
|
||||||
def __init__(self, timeout, passed_info: dict):
|
|
||||||
super().__init__()
|
|
||||||
self.timeout = timeout
|
|
||||||
self.passed_info = passed_info
|
|
||||||
self.config = Config.get_conf(None, cog_name='Shortmute', identifier=25781647388294)
|
|
||||||
|
|
||||||
@ui.button(label="Yes", style=discord.ButtonStyle.success)
|
|
||||||
async def shortmute_button_yes(self, button: ui.Button, interaction: discord.Interaction): # pylint: disable=unused-argument
|
|
||||||
disable_dateutil()
|
|
||||||
target: discord.Member = self.passed_info['target']
|
|
||||||
readable_duration = self.passed_info['readable_duration']
|
|
||||||
reason: str = self.passed_info['reason']
|
|
||||||
old_interaction: discord.Interaction = self.passed_info['interaction']
|
|
||||||
color = self.passed_info['color']
|
|
||||||
timedelta = self.passed_info['timedelta']
|
|
||||||
evidence = self.passed_info['evidence']
|
|
||||||
edit_embed = discord.Embed(title="Shortmute confirmed!", description=f"**Moderator:** {old_interaction.user.mention}\n**Target:** {target.mention}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`", color=color)
|
|
||||||
if evidence:
|
|
||||||
edit_embed.set_image(url=evidence)
|
|
||||||
old_message = await old_interaction.edit_original_response(embed=edit_embed, view=None)
|
|
||||||
await target.timeout(timedelta, reason=f"User shortmuted for {readable_duration} by {old_interaction.user.name} ({old_interaction.user.id}) for: {reason}")
|
|
||||||
await old_interaction.channel.send(content=f"{target.mention} was shortmuted for {readable_duration} by {old_interaction.user.mention} for: `{reason}`")
|
|
||||||
if await self.config.guild(old_interaction.guild).dm() is True:
|
|
||||||
dm_embed = discord.Embed(title=f"You've been shortmuted in {old_interaction.guild.name}!", description=f"**Moderator:** {old_interaction.user.mention}\n**Target:** {target.mention}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`", color=color)
|
|
||||||
dm_embed.set_footer(text="/shortmute")
|
|
||||||
if evidence:
|
|
||||||
dm_embed.set_image(url=evidence)
|
|
||||||
try:
|
|
||||||
await target.send(embed=dm_embed)
|
|
||||||
except discord.HTTPException:
|
|
||||||
await old_message.edit(content="Could not message the target, user most likely has Direct Messages disabled.")
|
|
||||||
logging_channels_list = await self.config.guild(old_interaction.guild).logging_channels()
|
|
||||||
if logging_channels_list:
|
|
||||||
logging_embed = discord.Embed(title="User Shortmuted", description=f"**Moderator:** {old_interaction.user.mention} ({old_interaction.user.id})\n**Target:** {target.mention} ({target.id})\n**Duration:** {readable_duration}\n**Reason:** `{reason}`\n**Confirmation Skipped:** False", color=color)
|
|
||||||
logging_embed.set_footer(text="/shortmute")
|
|
||||||
if evidence:
|
|
||||||
logging_embed.set_image(url=evidence)
|
|
||||||
for channel_id in logging_channels_list:
|
|
||||||
channel_obj = old_interaction.guild.get_channel(channel_id)
|
|
||||||
await channel_obj.send(embed=logging_embed)
|
|
||||||
|
|
||||||
@ui.button(label="No", style=discord.ButtonStyle.danger)
|
|
||||||
async def shortmute_button_no(self, button: ui.Button, interaction: discord.Interaction): # pylint: disable=unused-argument
|
|
||||||
message: discord.Message = await self.passed_info['interaction'].edit_original_response(content="Command cancelled.", view=None, embed=None)
|
|
||||||
await message.delete(delay=3)
|
|
||||||
|
|
||||||
@commands.group(name='shortmuteset', autohelp=True)
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config(self, ctx: commands.Context):
|
|
||||||
"""Used to configure the /shortmute command."""
|
|
||||||
|
|
||||||
@shortmute_config.group(name='channel', invoke_without_command=True, aliases=['channels'])
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config_channel(self, ctx: commands.Context):
|
|
||||||
"""Manages /shortmute logging."""
|
|
||||||
current_list = await self.config.guild(ctx.guild).logging_channels()
|
|
||||||
already_in_list = []
|
|
||||||
for channel_id in current_list:
|
|
||||||
channel_obj = ctx.guild.get_channel(channel_id)
|
|
||||||
if channel_obj:
|
|
||||||
already_in_list.append(channel_obj.mention)
|
|
||||||
if already_in_list:
|
|
||||||
await ctx.send("Channels already in the list:\n" + "\n".join(already_in_list))
|
|
||||||
else:
|
|
||||||
await ctx.send("No channels are currently in the logging list.")
|
|
||||||
|
|
||||||
@shortmute_config_channel.command(name='add')
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config_channel_add(self, ctx: commands.Context, channel: discord.TextChannel = None):
|
|
||||||
"""Adds a channel to the logging channels list."""
|
|
||||||
current_list: list = await self.config.guild(ctx.guild).logging_channels()
|
|
||||||
if channel:
|
|
||||||
if channel.id in current_list:
|
|
||||||
await ctx.send("This channel is already in the logging channel list!")
|
|
||||||
else:
|
|
||||||
current_list.append(channel.id)
|
|
||||||
await self.config.guild(ctx.guild).logging_channels.set(current_list)
|
|
||||||
await ctx.send(f"{channel.mention} has been added to the logging channels list.")
|
|
||||||
else:
|
|
||||||
await ctx.send("Please provide a valid channel!")
|
|
||||||
|
|
||||||
@shortmute_config_channel.command(name='remove')
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config_channel_remove(self, ctx: commands.Context, channel: discord.TextChannel = None):
|
|
||||||
"""Removes a channel from the logging channels list."""
|
|
||||||
current_list = await self.config.guild(ctx.guild).logging_channels()
|
|
||||||
if channel.id in current_list:
|
|
||||||
current_list.remove(channel.id)
|
|
||||||
await self.config.guild(ctx.guild).logging_channels.set(current_list)
|
|
||||||
await ctx.send(f"{channel.mention} has been removed from the logging channels list.")
|
|
||||||
else:
|
|
||||||
await ctx.send("Please provide a valid channel that exists in the logging channels list.")
|
|
||||||
|
|
||||||
@shortmute_config.group(name='role', invoke_without_command=True, aliases=['roles'])
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config_role(self, ctx: commands.Context):
|
|
||||||
"""Manages the immune roles list."""
|
|
||||||
current_list = await self.config.guild(ctx.guild).immune_roles()
|
|
||||||
already_in_list = []
|
|
||||||
for role_id in current_list:
|
|
||||||
role_obj = ctx.guild.get_role(role_id)
|
|
||||||
if role_obj:
|
|
||||||
already_in_list.append(role_obj.mention)
|
|
||||||
if already_in_list:
|
|
||||||
await ctx.send("Roles already in the immune roles list:\n" + "\n".join(already_in_list), allowed_mentions = discord.AllowedMentions(roles=False))
|
|
||||||
else:
|
|
||||||
await ctx.send("No roles are currently in the immune roles list.")
|
|
||||||
|
|
||||||
@shortmute_config_role.command(name='add')
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config_role_add(self, ctx: commands.Context, role: discord.Role = None):
|
|
||||||
"""Adds roles to the immune roles list."""
|
|
||||||
current_list = await self.config.guild(ctx.guild).immune_roles()
|
|
||||||
if role:
|
|
||||||
if role.id in current_list:
|
|
||||||
await ctx.send("This role is already in the immune roles list!")
|
|
||||||
else:
|
|
||||||
current_list.append(role.id)
|
|
||||||
await self.config.guild(ctx.guild).immune_roles.set(current_list)
|
|
||||||
await ctx.send(f"{role.mention} has been added to the immune roles list.", allowed_mentions = discord.AllowedMentions(roles=False))
|
|
||||||
else:
|
|
||||||
await ctx.send("Please provide a valid role.")
|
|
||||||
|
|
||||||
@shortmute_config_role.command(name='remove')
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config_role_remove(self, ctx: commands.Context, role: discord.Role = None):
|
|
||||||
"""Removes roles from the immune roles list."""
|
|
||||||
current_list = await self.config.guild(ctx.guild).immune_roles()
|
|
||||||
if role.id in current_list:
|
|
||||||
current_list.remove(role.id)
|
|
||||||
await self.config.guild(ctx.guild).immune_roles.set(current_list)
|
|
||||||
await ctx.send(f"{role.mention} has been removed from the immune roles list.", allowed_mentions = discord.AllowedMentions(roles=False))
|
|
||||||
else:
|
|
||||||
await ctx.send("Please provide a valid role that exists in the immune roles list.")
|
|
||||||
|
|
||||||
@shortmute_config.group(name='blacklist', invoke_without_command=True)
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config_blacklist(self, ctx: commands.Context):
|
|
||||||
"""Manages the blacklist."""
|
|
||||||
current_list = await self.config.guild(ctx.guild).blacklisted_users()
|
|
||||||
already_in_list = []
|
|
||||||
for user_id in current_list:
|
|
||||||
user_obj = await Bot.fetch_user(user_id) # pylint: disable=no-value-for-parameter
|
|
||||||
if user_obj:
|
|
||||||
already_in_list.append(user_obj.mention)
|
|
||||||
if already_in_list:
|
|
||||||
await ctx.send("Users already blacklisted:\n" + "\n".join(already_in_list), allowed_mentions = discord.AllowedMentions(users=False))
|
|
||||||
else:
|
|
||||||
await ctx.send("No users are currently blacklisted.")
|
|
||||||
|
|
||||||
@shortmute_config_blacklist.command(name='add')
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config_blacklist_add(self, ctx: commands.Context, user: discord.User = None):
|
|
||||||
"""Adds users to the /shortmute blacklist."""
|
|
||||||
current_list = await self.config.guild(ctx.guild).blacklisted_users()
|
|
||||||
if user:
|
|
||||||
if user.id in current_list:
|
|
||||||
await ctx.send("That user is already in the blacklisted users list!")
|
|
||||||
else:
|
|
||||||
current_list.append(user.id)
|
|
||||||
await self.config.guild(ctx.guild).blacklisted_users.set(current_list)
|
|
||||||
await ctx.send(f"{user.mention} has been blacklisted from using `/shortmute`.", allowed_mentions = discord.AllowedMentions(users=False))
|
|
||||||
else:
|
|
||||||
await ctx.send("Please provide a valid user.")
|
|
||||||
|
|
||||||
@shortmute_config_blacklist.command(name='remove')
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config_blacklist_remove(self, ctx: commands.Context, user: discord.User = None):
|
|
||||||
"""Removes users from the /shortmute blacklist."""
|
|
||||||
current_list = await self.config.guild(ctx.guild).blacklisted_users()
|
|
||||||
if user.id in current_list:
|
|
||||||
current_list.remove(user.id)
|
|
||||||
await self.config.guild(ctx.guild).blacklisted_users.set(current_list)
|
|
||||||
await ctx.send(f"{user.mention} has been removed from the `/shortmute` blacklist.", allowed_mentions = discord.AllowedMentions(users=False))
|
|
||||||
else:
|
|
||||||
await ctx.send("Please provide a valid user who is blacklisted from `/shortmute`.")
|
|
||||||
|
|
||||||
@shortmute_config.command(name='message')
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config_message(self, ctx: commands.Context, enabled: bool = None):
|
|
||||||
"""Manages if /shortmute Direct Messages its target.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
------------
|
|
||||||
enabled: bool (optional)
|
|
||||||
This parameter, if set, will toggle this setting to either True or False."""
|
|
||||||
old_value = await self.config.guild(ctx.guild).dm()
|
|
||||||
if enabled is None:
|
|
||||||
await ctx.send(content=f"Shortmute Direct Messages are currently {'enabled' if old_value else 'disabled'}!")
|
|
||||||
else:
|
|
||||||
await self.config.guild(ctx.guild).dm.set(enabled)
|
|
||||||
await ctx.send(content=f"Shortmute Direct Message setting changed!\nOld value: `{old_value}`\nNew value: `{enabled}`")
|
|
||||||
|
|
||||||
@shortmute_config.command(name='confirmation', aliases=['confirm'])
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.admin()
|
|
||||||
async def shortmute_config_confirmation(self, ctx: commands.Context, enabled: bool = None):
|
|
||||||
"""Manages if /shortmute has a confirmation prompt by default.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
------------
|
|
||||||
enabled: bool (optional)
|
|
||||||
This parameter, if set, will toggle this setting to either True or False."""
|
|
||||||
old_value = await self.config.guild(ctx.guild).confirm()
|
|
||||||
if enabled is None:
|
|
||||||
await ctx.send(content=f"Shortmute Confirmations are currently {'enabled' if old_value else 'disabled'} by default!")
|
|
||||||
else:
|
|
||||||
await self.config.guild(ctx.guild).confirm.set(enabled)
|
|
||||||
await ctx.send(content=f"Shortmute Confirmation setting changed!\nOld value: `{old_value}`\nNew value: `{enabled}`")
|
|
|
@ -1,12 +1,5 @@
|
||||||
from .suggestions import Suggestions, approve_context, deny_context
|
from .suggestions import Suggestions
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
def setup(bot):
|
||||||
await bot.add_cog(Suggestions(bot))
|
bot.add_cog(Suggestions(bot))
|
||||||
bot.tree.add_command(approve_context)
|
|
||||||
bot.tree.add_command(deny_context)
|
|
||||||
|
|
||||||
async def teardown(bot):
|
|
||||||
# We're removing the commands here to ensure they get unloaded properly when the cog is unloaded.
|
|
||||||
bot.tree.remove_command("approve_context", type=discord.AppCommandType.message) # pylint: disable=undefined-variable
|
|
||||||
bot.tree.remove_command("deny_context", type=discord.AppCommandType.message) # pylint: disable=undefined-variable
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
{
|
{
|
||||||
"author" : ["cswimr, meelyman"],
|
"author" : ["SeaswimmerTheFsh, meelyman"],
|
||||||
"install_msg" : "Thank you for installing Suggestions!\nYou can find the source code of this cog here: https://coastalcommits.com/cswimr/GalaxyCogs\nYou can find the original source code from SauriCogs here: <https://github.com/elijabesu/SauriCogs>",
|
"install_msg" : "Thank you for installing Suggestions!\nYou can find the source code of this cog here: https://github.com/SeaswimmerTheFsh/GalaxyCogs\nYou can find the original source code from SauriCogs here: <https://github.com/elijabesu/SauriCogs>",
|
||||||
"name" : "Suggestions",
|
"name" : "Suggestions",
|
||||||
"short" : "Simple suggestions system.",
|
"short" : "Simple suggestions system.",
|
||||||
"description" : "Per guild suggestions system.",
|
"description" : "Per guild suggestions system.",
|
||||||
"tags" : ["suggestions, suggestion, voting"],
|
"tags" : ["suggestions, suggestion, voting"],
|
||||||
"end_user_data_statement": "This cog stores user names, discriminators, and IDs upon sending a suggestion. This data is used solely to display user information in suggestions.",
|
"end_user_data_statement": "This cog stores user names, discriminators, and IDs upon sending a suggestion. This data is used solely to display user information in suggestions."
|
||||||
"hidden": true,
|
|
||||||
"disabled": false
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import re
|
|
||||||
import typing
|
|
||||||
import discord
|
import discord
|
||||||
from redbot.core import Config, app_commands, checks, commands
|
import datetime
|
||||||
|
import typing
|
||||||
|
|
||||||
|
from redbot.core import Config, checks, commands
|
||||||
|
from redbot.core.utils.chat_formatting import humanize_list
|
||||||
|
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,12 +44,7 @@ class Suggestions(commands.Cog):
|
||||||
rtext=None,
|
rtext=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
def check_discrim(self, user: discord.User):
|
async def red_delete_data_for_user(self, *, requester, user_id):
|
||||||
if user.discriminator == "0":
|
|
||||||
return user.name
|
|
||||||
return f"{user.name}#{user.discriminator}"
|
|
||||||
|
|
||||||
async def red_delete_data_for_user(self, *, requester, user_id: discord.User.id):
|
|
||||||
# per guild suggestions
|
# per guild suggestions
|
||||||
for guild in self.bot.guilds:
|
for guild in self.bot.guilds:
|
||||||
for suggestion_id in range(1, await self.config.guild(guild).next_id()):
|
for suggestion_id in range(1, await self.config.guild(guild).next_id()):
|
||||||
|
@ -62,13 +60,11 @@ class Suggestions(commands.Cog):
|
||||||
context = super().format_help_for_context(ctx)
|
context = super().format_help_for_context(ctx)
|
||||||
return f"{context}"
|
return f"{context}"
|
||||||
|
|
||||||
@commands.command(name='suggest')
|
@commands.command()
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@checks.bot_has_permissions(add_reactions=True)
|
@checks.bot_has_permissions(add_reactions=True)
|
||||||
async def suggest(self, ctx: commands.Context, *, suggestion: str):
|
async def suggest(self, ctx: commands.Context, *, suggestion: str):
|
||||||
"""Suggest something."""
|
"""Suggest something."""
|
||||||
if ctx.interaction is True:
|
|
||||||
await ctx.defer()
|
|
||||||
suggest_id = await self.config.guild(ctx.guild).suggest_id()
|
suggest_id = await self.config.guild(ctx.guild).suggest_id()
|
||||||
if not suggest_id:
|
if not suggest_id:
|
||||||
if not await self.config.toggle():
|
if not await self.config.toggle():
|
||||||
|
@ -82,9 +78,9 @@ class Suggestions(commands.Cog):
|
||||||
"Uh oh, looks like the Admins haven't added the required channel."
|
"Uh oh, looks like the Admins haven't added the required channel."
|
||||||
)
|
)
|
||||||
embed = discord.Embed(color=await ctx.embed_colour(), description=suggestion)
|
embed = discord.Embed(color=await ctx.embed_colour(), description=suggestion)
|
||||||
footer = [f"Suggested by {self.check_discrim(ctx.author)} • ({ctx.author.id})",
|
footer = [f"Suggested by {ctx.author.name}#{ctx.author.discriminator}",
|
||||||
ctx.author.display_avatar.url]
|
ctx.author.avatar_url]
|
||||||
author = [f"{ctx.author.display_name}", ctx.author.display_avatar.url]
|
author = [f"{ctx.author.name}#{ctx.author.discriminator} ({ctx.author.id})", ctx.author.avatar_url]
|
||||||
embed.set_footer(
|
embed.set_footer(
|
||||||
text=footer[0],
|
text=footer[0],
|
||||||
icon_url=footer[1]
|
icon_url=footer[1]
|
||||||
|
@ -135,7 +131,7 @@ class Suggestions(commands.Cog):
|
||||||
reason: typing.Optional[str],
|
reason: typing.Optional[str],
|
||||||
):
|
):
|
||||||
"""Approve a suggestion."""
|
"""Approve a suggestion."""
|
||||||
await self._finish_suggestion(ctx, suggestion_id, True, reason)
|
await self._finish_suggestion(ctx, suggestion_id, True, reason, ctx.author)
|
||||||
|
|
||||||
@checks.admin()
|
@checks.admin()
|
||||||
@commands.command()
|
@commands.command()
|
||||||
|
@ -149,7 +145,7 @@ class Suggestions(commands.Cog):
|
||||||
reason: typing.Optional[str],
|
reason: typing.Optional[str],
|
||||||
):
|
):
|
||||||
"""Deny a suggestion. Reason is optional."""
|
"""Deny a suggestion. Reason is optional."""
|
||||||
await self._finish_suggestion(ctx, suggestion_id, False, reason)
|
await self._finish_suggestion(ctx, suggestion_id, False, reason, ctx.author)
|
||||||
|
|
||||||
@checks.admin()
|
@checks.admin()
|
||||||
@commands.command()
|
@commands.command()
|
||||||
|
@ -187,8 +183,8 @@ class Suggestions(commands.Cog):
|
||||||
content = old_msg.content
|
content = old_msg.content
|
||||||
approved = "Approved" if approve else "Denied"
|
approved = "Approved" if approve else "Denied"
|
||||||
embed.title = f"Suggestion {approved} (#{suggestion_id})"
|
embed.title = f"Suggestion {approved} (#{suggestion_id})"
|
||||||
footer = [f"{approved} by {self.check_discrim(author)} • ({author.id})",
|
footer = [f"{approved} by {author.name}#{author.discriminator} ({author.id}",
|
||||||
author.display_avatar.replace(format="png", size=512)]
|
author.avatar_url_as(format="png", size=512)]
|
||||||
embed.set_footer(
|
embed.set_footer(
|
||||||
text=footer[0],
|
text=footer[0],
|
||||||
icon_url=footer[1]
|
icon_url=footer[1]
|
||||||
|
@ -370,7 +366,7 @@ class Suggestions(commands.Cog):
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
colour=await ctx.embed_colour()
|
colour=await ctx.embed_colour()
|
||||||
)
|
)
|
||||||
embed.set_author(name=ctx.guild.name, icon_url=ctx.guild.icon.url)
|
embed.set_author(name=ctx.guild.name, icon_url=ctx.guild.icon_url)
|
||||||
embed.title = "**Suggestion settings:**"
|
embed.title = "**Suggestion settings:**"
|
||||||
|
|
||||||
embed.add_field(name="Suggestions channel:", value=suggest_channel)
|
embed.add_field(name="Suggestions channel:", value=suggest_channel)
|
||||||
|
@ -393,7 +389,7 @@ class Suggestions(commands.Cog):
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_reaction_add(self, reaction: discord.Reaction, user: discord.Message):
|
async def on_reaction_add(self, reaction, user):
|
||||||
message = reaction.message
|
message = reaction.message
|
||||||
if user.id == self.bot.user.id:
|
if user.id == self.bot.user.id:
|
||||||
return
|
return
|
||||||
|
@ -408,7 +404,7 @@ class Suggestions(commands.Cog):
|
||||||
):
|
):
|
||||||
await message_reaction.remove(user)
|
await message_reaction.remove(user)
|
||||||
|
|
||||||
async def _get_results(self, ctx: commands.Context, message: discord.Message):
|
async def _get_results(self, ctx, message):
|
||||||
up_emoji, down_emoji = await self._get_emojis(ctx)
|
up_emoji, down_emoji = await self._get_emojis(ctx)
|
||||||
up_count = 0
|
up_count = 0
|
||||||
down_count = 0
|
down_count = 0
|
||||||
|
@ -421,7 +417,7 @@ class Suggestions(commands.Cog):
|
||||||
|
|
||||||
return f"{up_count}x {up_emoji}\n{down_count}x {down_emoji}"
|
return f"{up_count}x {up_emoji}\n{down_count}x {down_emoji}"
|
||||||
|
|
||||||
async def _get_emojis(self, ctx: typing.Union[commands.Context, discord.Interaction]):
|
async def _get_emojis(self, ctx):
|
||||||
up_emoji = self.bot.get_emoji(await self.config.guild(ctx.guild).up_emoji())
|
up_emoji = self.bot.get_emoji(await self.config.guild(ctx.guild).up_emoji())
|
||||||
if not up_emoji:
|
if not up_emoji:
|
||||||
up_emoji = "✅"
|
up_emoji = "✅"
|
||||||
|
@ -430,9 +426,8 @@ class Suggestions(commands.Cog):
|
||||||
down_emoji = "âŽ"
|
down_emoji = "âŽ"
|
||||||
return up_emoji, down_emoji
|
return up_emoji, down_emoji
|
||||||
|
|
||||||
async def _finish_suggestion(self, ctx: commands.Context, suggestion_id: int, approve: bool, reason: str):
|
async def _finish_suggestion(self, ctx, suggestion_id, approve, reason, author):
|
||||||
server = ctx.guild.id
|
server = ctx.guild.id
|
||||||
author = ctx.author
|
|
||||||
old_channel = ctx.guild.get_channel(
|
old_channel = ctx.guild.get_channel(
|
||||||
await self.config.guild(ctx.guild).suggest_id()
|
await self.config.guild(ctx.guild).suggest_id()
|
||||||
)
|
)
|
||||||
|
@ -462,8 +457,8 @@ class Suggestions(commands.Cog):
|
||||||
approved = "Approved" if approve else "Denied"
|
approved = "Approved" if approve else "Denied"
|
||||||
|
|
||||||
embed.title = f"Suggestion {approved} (#{suggestion_id})"
|
embed.title = f"Suggestion {approved} (#{suggestion_id})"
|
||||||
footer = [f"{approved} by {self.check_discrim(author)} • ({author.id})",
|
footer = [f"{approved} by {author.name}#{author.discriminator} ({author.id}",
|
||||||
author.display_avatar.replace(format="png", size=512)]
|
author.avatar_url_as(format="png", size=512)]
|
||||||
embed.set_footer(
|
embed.set_footer(
|
||||||
text=footer[0],
|
text=footer[0],
|
||||||
icon_url=footer[1]
|
icon_url=footer[1]
|
||||||
|
@ -509,162 +504,3 @@ class Suggestions(commands.Cog):
|
||||||
True
|
True
|
||||||
)
|
)
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
async def _interaction_get_results(self, interaction: discord.Interaction, message: discord.Message):
|
|
||||||
up_emoji, down_emoji = await self._get_emojis(interaction)
|
|
||||||
up_count = 0
|
|
||||||
down_count = 0
|
|
||||||
|
|
||||||
for reaction in message.reactions:
|
|
||||||
if reaction.emoji == up_emoji:
|
|
||||||
up_count = reaction.count - 1 # minus the bot
|
|
||||||
if reaction.emoji == down_emoji:
|
|
||||||
down_count = reaction.count - 1 # minus the bot
|
|
||||||
|
|
||||||
return f"{up_count}x {up_emoji}\n{down_count}x {down_emoji}"
|
|
||||||
|
|
||||||
async def _interaction_finish_suggestion(self, interaction: discord.Interaction, message: discord.Message, approve: bool, reason: str = None):
|
|
||||||
embed = message.embeds
|
|
||||||
title = embed[0].title
|
|
||||||
if not title.startswith("Suggestion #"):
|
|
||||||
await interaction.response.send_message(content="This message is not a suggestion!", ephemeral=True)
|
|
||||||
return
|
|
||||||
numbers = re.findall(r'\d+', title)
|
|
||||||
suggestion_id = ''.join(numbers)
|
|
||||||
author = interaction.user
|
|
||||||
server = interaction.guild.id
|
|
||||||
old_channel = interaction.guild.get_channel(
|
|
||||||
await self.config.guild(interaction.guild).suggest_id()
|
|
||||||
)
|
|
||||||
if approve:
|
|
||||||
channel = interaction.guild.get_channel(
|
|
||||||
await self.config.guild(interaction.guild).approve_id()
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
channel = interaction.guild.get_channel(
|
|
||||||
await self.config.guild(interaction.guild).denied_id()
|
|
||||||
)
|
|
||||||
msg_id = await self.config.custom("SUGGESTION", server, suggestion_id).msg_id()
|
|
||||||
if (
|
|
||||||
msg_id != 0
|
|
||||||
and await self.config.custom("SUGGESTION", server, suggestion_id).finished()
|
|
||||||
):
|
|
||||||
return await interaction.response.send_message(content="This suggestion has been finished already.", ephemeral=True)
|
|
||||||
try:
|
|
||||||
old_msg = await old_channel.fetch_message(msg_id)
|
|
||||||
except discord.NotFound:
|
|
||||||
return await interaction.response.send_message(content="Uh oh, message with this ID doesn't exist.", ephemeral=True)
|
|
||||||
if not old_msg:
|
|
||||||
return await interaction.response.send_message(content="Uh oh, message with this ID doesn't exist.", ephemeral=True)
|
|
||||||
embed = old_msg.embeds[0]
|
|
||||||
content = old_msg.content
|
|
||||||
|
|
||||||
approved = "Approved" if approve else "Denied"
|
|
||||||
|
|
||||||
embed.title = f"Suggestion {approved} (#{suggestion_id})"
|
|
||||||
footer = [f"{approved} by {self.check_discrim(author)} • ({author.id})",
|
|
||||||
author.display_avatar.replace(format="png", size=512)]
|
|
||||||
embed.set_footer(
|
|
||||||
text=footer[0],
|
|
||||||
icon_url=footer[1]
|
|
||||||
)
|
|
||||||
embed.add_field(
|
|
||||||
name="Results", value=await self._interaction_get_results(interaction, old_msg), inline=False
|
|
||||||
)
|
|
||||||
if reason:
|
|
||||||
embed.add_field(name="Reason", value=reason, inline=False)
|
|
||||||
await self.config.custom("SUGGESTION", server, suggestion_id).reason.set(
|
|
||||||
True
|
|
||||||
)
|
|
||||||
await self.config.custom("SUGGESTION", server, suggestion_id).rtext.set(
|
|
||||||
reason
|
|
||||||
)
|
|
||||||
|
|
||||||
if channel:
|
|
||||||
if not await self.config.guild(interaction.guild).same():
|
|
||||||
if await self.config.guild(interaction.guild).delete_suggestion():
|
|
||||||
await old_msg.delete()
|
|
||||||
nmsg = await channel.send(content=content, embed=embed)
|
|
||||||
await self.config.custom(
|
|
||||||
"SUGGESTION", server, suggestion_id
|
|
||||||
).msg_id.set(nmsg.id)
|
|
||||||
else:
|
|
||||||
await old_msg.edit(content=content, embed=embed)
|
|
||||||
else:
|
|
||||||
if not await self.config.guild(interaction.guild).same():
|
|
||||||
if await self.config.guild(interaction.guild).delete_suggestion():
|
|
||||||
await old_msg.delete()
|
|
||||||
await self.config.custom(
|
|
||||||
"SUGGESTION", server, suggestion_id
|
|
||||||
).msg_id.set(1)
|
|
||||||
else:
|
|
||||||
await old_msg.edit(content=content, embed=embed)
|
|
||||||
await self.config.custom("SUGGESTION", server, suggestion_id).finished.set(True)
|
|
||||||
if approve:
|
|
||||||
await self.config.custom("SUGGESTION", server, suggestion_id).approved.set(
|
|
||||||
True
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await self.config.custom("SUGGESTION", server, suggestion_id).denied.set(
|
|
||||||
True
|
|
||||||
)
|
|
||||||
return nmsg
|
|
||||||
|
|
||||||
# pylint: disable=protected-access
|
|
||||||
class SuggestionApproveModal(discord.ui.Modal, title="Approving suggestion..."):
|
|
||||||
def __init__(self, message):
|
|
||||||
super().__init__()
|
|
||||||
self.message: discord.Message = message
|
|
||||||
|
|
||||||
reason = discord.ui.TextInput(
|
|
||||||
label="Approval Reason",
|
|
||||||
placeholder="Why are you approving this suggestion?",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=False,
|
|
||||||
max_length=1024
|
|
||||||
)
|
|
||||||
|
|
||||||
async def on_submit(self, interaction: discord.Interaction):
|
|
||||||
cog = interaction.client.get_cog('Suggestions')
|
|
||||||
if self.reason.value != "":
|
|
||||||
nmsg = await Suggestions._interaction_finish_suggestion(cog, interaction, self.message, True, self.reason.value)
|
|
||||||
else:
|
|
||||||
nmsg = await Suggestions._interaction_finish_suggestion(cog, interaction, self.message, True, None)
|
|
||||||
msg = await interaction.response.send_message(content=f"Suggestion approved!\nJump Link: {nmsg.jump_url}", ephemeral=True)
|
|
||||||
await msg.delete(10)
|
|
||||||
|
|
||||||
class SuggestionDenyModal(discord.ui.Modal, title="Denying suggestion..."):
|
|
||||||
def __init__(self, message):
|
|
||||||
super().__init__()
|
|
||||||
self.message: discord.Message = message
|
|
||||||
|
|
||||||
reason = discord.ui.TextInput(
|
|
||||||
label="Denial Reason",
|
|
||||||
placeholder="Why are you denying this suggestion?",
|
|
||||||
style=discord.TextStyle.paragraph,
|
|
||||||
required=False,
|
|
||||||
max_length=1024
|
|
||||||
)
|
|
||||||
|
|
||||||
async def on_submit(self, interaction: discord.Interaction):
|
|
||||||
cog = interaction.client.get_cog('Suggestions')
|
|
||||||
if self.reason.value != "":
|
|
||||||
nmsg = await Suggestions._interaction_finish_suggestion(cog, interaction, self.message, False, self.reason.value)
|
|
||||||
else:
|
|
||||||
nmsg = await Suggestions._interaction_finish_suggestion(cog, interaction, self.message, False, None)
|
|
||||||
msg: discord.Message = await interaction.response.send_message(content=f"Suggestion denied!\nJump Link: {nmsg.jump_url}", ephemeral=True)
|
|
||||||
await msg.delete(10)
|
|
||||||
|
|
||||||
@app_commands.context_menu(name="Approve Suggestion")
|
|
||||||
async def approve_context(interaction: discord.Interaction, message: discord.Message):
|
|
||||||
if message.author.id == interaction.client.user.id and len(message.embeds) == 1 and message.embeds[0].title.startswith('Suggestion #'):
|
|
||||||
await interaction.response.send_modal(SuggestionApproveModal(message))
|
|
||||||
else:
|
|
||||||
await interaction.response.send_message(content="This is not a suggestion!", ephemeral=True)
|
|
||||||
|
|
||||||
@app_commands.context_menu(name="Deny Suggestion")
|
|
||||||
async def deny_context(interaction: discord.Interaction, message: discord.Message):
|
|
||||||
if message.author.id == interaction.client.user.id and len(message.embeds) == 1 and message.embeds[0].title.startswith('Suggestion #'):
|
|
||||||
await interaction.response.send_modal(SuggestionDenyModal(message))
|
|
||||||
else:
|
|
||||||
await interaction.response.send_message(content="This is not a suggestion!", ephemeral=True)
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
{
|
{
|
||||||
"author" : ["cswimr"],
|
"author" : ["SeaswimmerTheFsh"],
|
||||||
"install_msg" : "Thank you for installing SugonCredit!\n**Please load the Economy cog before loading this cog.**\nYou can find the source code of this cog here: https://coastalcommits.com/cswimr/GalaxyCogs.",
|
"install_msg" : "Thank you for installing SugonCredit!\n**Please load the Bank cog before loading this cog.**\nYou can find the source code of this cog here: https://github.com/SeaswimmerTheFsh/GalaxyCogs.",
|
||||||
"name" : "SugonCredit",
|
"name" : "SugonCredit",
|
||||||
"short" : "Simple points system.",
|
"short" : "Simple points system.",
|
||||||
"description" : "Implements a way for moderators to give out social-credit like points, dubbed 'sugoncredits' by the community.",
|
"description" : "Implements a way for moderators to give out social-credit like points, dubbed 'sugoncredits' by the community.",
|
||||||
"tags" : ["economy"],
|
"tags" : ["bank"],
|
||||||
"end_user_data_statement": "This cog stores no end user data.",
|
"end_user_data_statement": "This cog stores no end user data.",
|
||||||
"hidden": true,
|
"requirements": ["inflect", "tabulate"]
|
||||||
"disabled": false
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,61 +1,140 @@
|
||||||
|
import sqlite3
|
||||||
|
from sqlite3 import Error
|
||||||
import discord
|
import discord
|
||||||
from redbot.core import commands, bank, data_manager
|
from redbot.core import Config, checks, commands, data_manager
|
||||||
|
from tabulate import tabulate
|
||||||
|
|
||||||
|
|
||||||
class SugonCredit(commands.Cog):
|
class SugonCredit(commands.Cog):
|
||||||
"""Implements a way for moderators to give out social-credit like points, dubbed 'sugoncredits' by the community."""
|
"""Implements a way for moderators to give out social-credit like points, dubbed 'sugoncredits' by the community."""
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
self.config = Config.get_conf(self, identifier=47252584)
|
||||||
|
self.config.register_guild(
|
||||||
|
bank_name = "Social Credit Enforcement Agency",
|
||||||
|
currency_name = "Social Credit",
|
||||||
|
max_bal = 1000000000,
|
||||||
|
min_bal = -1000000000
|
||||||
|
)
|
||||||
|
self.data_path = data_manager.cog_data_path(self) / "credit.db"
|
||||||
|
con = sqlite3.connect(f'{self.data_path}')
|
||||||
|
con.commit()
|
||||||
|
con.close()
|
||||||
|
|
||||||
@commands.hybrid_group(autohelp=True, aliases=["sugoncredit"])
|
def pluralize(word, count):
|
||||||
|
if count == 1:
|
||||||
|
return word
|
||||||
|
elif word.endswith('s') or word.endswith('x') or word.endswith('z') or word.endswith('ch') or word.endswith('sh'):
|
||||||
|
return word + 'es'
|
||||||
|
elif word.endswith('y'):
|
||||||
|
# Change 'y' to 'ies' for words ending with a consonant + 'y'
|
||||||
|
return word[:-1] + 'ies'
|
||||||
|
else:
|
||||||
|
return word + 's'
|
||||||
|
|
||||||
|
def new_guild_generation(self, guild_id):
|
||||||
|
"""Adds a new table for a guild to the SQLite database."""
|
||||||
|
con = sqlite3.connect(self.data_path)
|
||||||
|
cur = con.cursor()
|
||||||
|
try:
|
||||||
|
cur.execute(f"SELECT 1 FROM '{guild_id}' LIMIT 1;")
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
cur.execute(f"CREATE TABLE '{guild_id}' (user_id TEXT, balance REAL);")
|
||||||
|
con.commit()
|
||||||
|
con.close()
|
||||||
|
|
||||||
|
def new_user_generation(self, guild_id, target):
|
||||||
|
"""Adds a new user to the SQLite database."""
|
||||||
|
con = sqlite3.connect(f'{self.data_path}')
|
||||||
|
cur = con.cursor()
|
||||||
|
cur.execute(f'''INSERT INTO {guild_id}
|
||||||
|
VALUES ({target.id}, 250);''')
|
||||||
|
con.commit()
|
||||||
|
con.close()
|
||||||
|
|
||||||
|
@commands.group(autohelp=True, aliases=["sugoncredit"])
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
async def credit(self, ctx: commands.Context):
|
async def credit(self, ctx):
|
||||||
"""Simple points system."""
|
"""Simple points system."""
|
||||||
|
|
||||||
@credit.command()
|
@credit.command()
|
||||||
async def balance(self, ctx: commands.Context, user: discord.Member = None):
|
@commands.guild_only()
|
||||||
"""Checks an account's balance."""
|
async def leaderboard(self, ctx, page: int = 1):
|
||||||
bank_name = await bank.get_bank_name(ctx.guild)
|
"""Shows the individuals with the highest balances."""
|
||||||
currency_name = await bank.get_currency_name(ctx.guild)
|
await ctx.send(content="This command isn't done yet!")
|
||||||
if user is None:
|
con = sqlite3.connect(f'{self.data_path}')
|
||||||
bal = await bank.get_balance(ctx.author)
|
cur = con.cursor()
|
||||||
target = ctx.author
|
await self.new_guild_generation(self, ctx.guild.id)
|
||||||
else:
|
bank_name = await self.config.guild(ctx.guild).bank_name()
|
||||||
bal = await bank.get_balance(user)
|
currency_name = await self.config.guild(ctx.guild).currency_name()
|
||||||
target = user
|
offset = (page - 1) * 10
|
||||||
output_bal = (f'{bal:,}')
|
raw_list = cur.execute(f'''SELECT user_id, balance FROM {ctx.guild.id}
|
||||||
if bal in (1, -1):
|
ORDER BY balance DESC
|
||||||
embed=discord.Embed(title=f"{bank_name} - Balance", color=await self.bot.get_embed_color(None), description=f"{target.mention} has {output_bal} {currency_name}.")
|
LIMIT 10 OFFSET {offset};''')
|
||||||
else:
|
await ctx.send(content=f"{raw_list}")
|
||||||
embed=discord.Embed(title=f"{bank_name} - Balance", color=await self.bot.get_embed_color(None), description=f"{target.mention} has {output_bal} {currency_name}s.")
|
|
||||||
await ctx.send(embed=embed)
|
|
||||||
|
|
||||||
@credit.command()
|
@credit.command()
|
||||||
|
@commands.guild_only()
|
||||||
|
async def balance(self, ctx, user: discord.Member = None):
|
||||||
|
"""Checks an account's balance."""
|
||||||
|
target = user if user else ctx.author
|
||||||
|
con = sqlite3.connect(self.data_path)
|
||||||
|
cur = con.cursor()
|
||||||
|
await self.new_guild_generation(ctx.guild.id)
|
||||||
|
bank_name = await self.config.guild(ctx.guild).get_raw('bank_name', default="Bank")
|
||||||
|
currency_name = await self.config.guild(ctx.guild).get_raw('currency_name', default="Credit")
|
||||||
|
cur.execute(f"SELECT user_id FROM {ctx.guild.id} WHERE user_id = ?;", (target.id,))
|
||||||
|
if not cur.fetchone():
|
||||||
|
await self.new_user_generation(ctx.guild.id, target)
|
||||||
|
cur.execute(f"SELECT balance FROM {ctx.guild.id} WHERE user_id = ?;", (target.id,))
|
||||||
|
bal = cur.fetchone()[0]
|
||||||
|
output_bal = f'{bal:,}'
|
||||||
|
pluralized_currency_name = await self.pluralize(currency_name, bal)
|
||||||
|
embed_title = f"{bank_name} - Balance"
|
||||||
|
embed_color = await self.bot.get_embed_color(None)
|
||||||
|
embed_description = f"{target.mention} has {output_bal} {pluralized_currency_name}."
|
||||||
|
embed = discord.Embed(title=embed_title, color=embed_color, description=embed_description)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
con.close()
|
||||||
|
|
||||||
|
@credit.command()
|
||||||
|
@commands.guild_only()
|
||||||
@commands.mod()
|
@commands.mod()
|
||||||
async def add(self, ctx: commands.Context, target: discord.Member, amount: int):
|
async def add(self, ctx, target: discord.Member, amount: int):
|
||||||
"""Adds credits to an account."""
|
"""Adds credits to an account."""
|
||||||
try:
|
try:
|
||||||
val = int(amount)
|
val = int(amount)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
await ctx.send(content="``amount`` must be a number! Please try again.")
|
await ctx.send(content="``amount`` must be a number! Please try again.")
|
||||||
return
|
return
|
||||||
|
con = sqlite3.connect(f'{self.data_path}')
|
||||||
|
cur = con.cursor()
|
||||||
|
await self.new_guild_generation({ctx.guild.id})
|
||||||
image = discord.File(fp=data_manager.bundled_data_path(self) / "add.png", filename="Add.png")
|
image = discord.File(fp=data_manager.bundled_data_path(self) / "add.png", filename="Add.png")
|
||||||
bank_name = await bank.get_bank_name(ctx.guild)
|
bank_name = await self.config.bank_name()
|
||||||
currency_name = await bank.get_currency_name(ctx.guild)
|
currency_name = await self.config.currency_name()
|
||||||
current_bal = await bank.get_balance(target)
|
max_bal = await self.config.max_bal()
|
||||||
max_bal = await bank.get_max_balance(ctx.guild)
|
min_bal = await self.config_min_bal()
|
||||||
|
current_bal = cur.execute(f'''SELECT balance FROM {ctx.guild.id}
|
||||||
|
WHERE user_id = {target.id};''')
|
||||||
new_bal = current_bal + amount
|
new_bal = current_bal + amount
|
||||||
output_amount = (f'{val:,}')
|
output_amount = (f'{val:,}')
|
||||||
output_new_bal = (f'{new_bal:,}')
|
output_new_bal = (f'{new_bal:,}')
|
||||||
output_max_bal = (f'{max_bal:,}')
|
output_max_bal = (f'{max_bal:,}')
|
||||||
|
output_min_bal = (f'{min_bal:,}')
|
||||||
if new_bal > max_bal:
|
if new_bal > max_bal:
|
||||||
await ctx.send(content=f"You are attempting to set {target.mention}'s balance to above {output_max_bal}. Please try again!")
|
await ctx.send(content=f"You are attempting to set {target.mention}'s balance to above {output_max_bal}. Please try again!")
|
||||||
elif new_bal < 0:
|
return
|
||||||
await ctx.send(content=f"You are attempting to set {target.mention}'s balance to below 0. Please try again!")
|
elif new_bal < min_bal:
|
||||||
|
await ctx.send(content=f"You are attempting to set {target.mention}'s balance to below {output_min_bal}. Please try again!")
|
||||||
elif ctx.guild.id == 204965774618656769:
|
elif ctx.guild.id == 204965774618656769:
|
||||||
logging_channel: discord.TextChannel = self.bot.get_channel(1082495815878189076)
|
logging_channel = self.bot.get_channel(1082495815878189076)
|
||||||
await bank.deposit_credits(target, amount=amount)
|
cur.execute(f'''UPDATE {ctx.guild.id}
|
||||||
|
SET balance = {new_bal}
|
||||||
|
WHERE user_id = {target.id};''')
|
||||||
await ctx.send(content=f"{target.mention} now has {output_amount} more SugonCredit, with a total of {output_new_bal}!")
|
await ctx.send(content=f"{target.mention} now has {output_amount} more SugonCredit, with a total of {output_new_bal}!")
|
||||||
if amount in (1, -1):
|
if amount == 1 or amount == -1:
|
||||||
await target.send(content=f"You gained {output_amount} SugonCredit! Good work community member! You now have {output_new_bal} SugonCredits.", file=image)
|
await target.send(content=f"You gained {output_amount} SugonCredit! Good work community member! You now have {output_new_bal} SugonCredits.", file=image)
|
||||||
else:
|
else:
|
||||||
await target.send(content=f"You gained {output_amount} SugonCredits! Good work community member! You now have {output_new_bal} SugonCredits.", file=image)
|
await target.send(content=f"You gained {output_amount} SugonCredits! Good work community member! You now have {output_new_bal} SugonCredits.", file=image)
|
||||||
|
@ -63,12 +142,17 @@ class SugonCredit(commands.Cog):
|
||||||
await logging_channel.send(embed=logging_embed)
|
await logging_channel.send(embed=logging_embed)
|
||||||
elif ctx.guild.id != 204965774618656769:
|
elif ctx.guild.id != 204965774618656769:
|
||||||
embed=discord.Embed(title=f"{bank_name} - Add", color=await self.bot.get_embed_color(None), description=f"{target.mention}'s {currency_name} balance has been increased by {output_amount}.\nCurrent balance is {output_new_bal}.")
|
embed=discord.Embed(title=f"{bank_name} - Add", color=await self.bot.get_embed_color(None), description=f"{target.mention}'s {currency_name} balance has been increased by {output_amount}.\nCurrent balance is {output_new_bal}.")
|
||||||
await bank.deposit_credits(target, amount=amount)
|
cur.execute(f'''UPDATE {ctx.guild.id}
|
||||||
|
SET balance = {new_bal}
|
||||||
|
WHERE user_id = {target.id};''')
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
con.commit()
|
||||||
|
con.close()
|
||||||
|
|
||||||
@credit.command()
|
@credit.command()
|
||||||
|
@commands.guild_only()
|
||||||
@commands.mod()
|
@commands.mod()
|
||||||
async def remove(self, ctx: commands.Context, target: discord.Member, amount: int):
|
async def remove(self, ctx, target: discord.Member, amount: int):
|
||||||
"""Removes credits from an account."""
|
"""Removes credits from an account."""
|
||||||
try:
|
try:
|
||||||
val = int(amount)
|
val = int(amount)
|
||||||
|
@ -76,19 +160,32 @@ class SugonCredit(commands.Cog):
|
||||||
await ctx.send(content="``amount`` must be a number. Please try again!")
|
await ctx.send(content="``amount`` must be a number. Please try again!")
|
||||||
return
|
return
|
||||||
image = discord.File(fp=data_manager.bundled_data_path(self) / "remove.mp4", filename="MEGA_BASE.mp4")
|
image = discord.File(fp=data_manager.bundled_data_path(self) / "remove.mp4", filename="MEGA_BASE.mp4")
|
||||||
bank_name = await bank.get_bank_name(ctx.guild)
|
data_path = data_manager.cog_data_path(self) / "credit.db"
|
||||||
currency_name = await bank.get_currency_name(ctx.guild)
|
con = sqlite3.connect(f'{data_path}')
|
||||||
current_bal = await bank.get_balance(target)
|
cur = con.cursor()
|
||||||
|
await self.new_guild_generation({ctx.guild.id})
|
||||||
|
bank_name = await self.config.bank_name()
|
||||||
|
currency_name = await self.config.currency_name()
|
||||||
|
max_bal = await self.config.max_bal()
|
||||||
|
min_bal = await self.config_min_bal()
|
||||||
|
current_bal = cur.execute(f'''SELECT balance FROM {ctx.guild.id}
|
||||||
|
WHERE user_id = {target.id};''')
|
||||||
new_bal = current_bal - amount
|
new_bal = current_bal - amount
|
||||||
output_amount = (f'{val:,}')
|
output_amount = (f'{val:,}')
|
||||||
output_new_bal = (f'{new_bal:,}')
|
output_new_bal = (f'{new_bal:,}')
|
||||||
if new_bal < 0:
|
output_max_bal = (f'{max_bal:,}')
|
||||||
await ctx.send(content=f"You are attempting to set {target.mention}'s balance to below 0. Please try again!")
|
output_min_bal = (f'{min_bal:,}')
|
||||||
|
if new_bal > max_bal:
|
||||||
|
await ctx.send(content=f"You are attempting to set {target.mention}'s balance to above {output_max_bal}. Please try again!")
|
||||||
|
elif new_bal < min_bal:
|
||||||
|
await ctx.send(content=f"You are attempting to set {target.mention}'s balance to below {output_min_bal}. Please try again!")
|
||||||
elif ctx.guild.id == 204965774618656769:
|
elif ctx.guild.id == 204965774618656769:
|
||||||
await bank.withdraw_credits(target, amount=amount)
|
cur.execute(f'''UPDATE {ctx.guild.id}
|
||||||
logging_channel: discord.TextChannel = self.bot.get_channel(1082495815878189076)
|
SET balance = {new_bal}
|
||||||
|
WHERE user_id = {target.id};''')
|
||||||
|
logging_channel = self.bot.get_channel(1082495815878189076)
|
||||||
await ctx.send(content=f"{target.mention} now has {output_amount} less SugonCredit, with a total of {output_new_bal}!\nIf this is a punishment, do better Galaxy Player! Re-education mods will be sent to your DM's if your SugonCredit drops to a substantially low amount!")
|
await ctx.send(content=f"{target.mention} now has {output_amount} less SugonCredit, with a total of {output_new_bal}!\nIf this is a punishment, do better Galaxy Player! Re-education mods will be sent to your DM's if your SugonCredit drops to a substantially low amount!")
|
||||||
if amount in (1, -1):
|
if amount == 1 or amount == -1:
|
||||||
await target.send(content=f"__MESSAGE FROM THE MINISTRY OF THE MEGA BASE__\n\n(我们的) {output_amount} SugonCredit has been taken from your account. Citizen, do not continue to preform bad actions! Glory to the Galaxy Communist Party!", file=image)
|
await target.send(content=f"__MESSAGE FROM THE MINISTRY OF THE MEGA BASE__\n\n(我们的) {output_amount} SugonCredit has been taken from your account. Citizen, do not continue to preform bad actions! Glory to the Galaxy Communist Party!", file=image)
|
||||||
else:
|
else:
|
||||||
await target.send(content=f"__MESSAGE FROM THE MINISTRY OF THE MEGA BASE__\n\n(我们的) {output_amount} SugonCredits have been taken from your account. Citizen, do not continue to preform bad actions! Glory to the Galaxy Communist Party!", file=image)
|
await target.send(content=f"__MESSAGE FROM THE MINISTRY OF THE MEGA BASE__\n\n(我们的) {output_amount} SugonCredits have been taken from your account. Citizen, do not continue to preform bad actions! Glory to the Galaxy Communist Party!", file=image)
|
||||||
|
@ -97,4 +194,8 @@ class SugonCredit(commands.Cog):
|
||||||
elif ctx.guild.id != 204965774618656769:
|
elif ctx.guild.id != 204965774618656769:
|
||||||
embed=discord.Embed(title=f"{bank_name} - Remove", color=await self.bot.get_embed_color(None), description=f"{target.mention}'s {currency_name} balance has been decreased by {output_amount}.\nCurrent balance is {output_new_bal}.")
|
embed=discord.Embed(title=f"{bank_name} - Remove", color=await self.bot.get_embed_color(None), description=f"{target.mention}'s {currency_name} balance has been decreased by {output_amount}.\nCurrent balance is {output_new_bal}.")
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
await bank.withdraw_credits(target, amount=val)
|
cur.execute(f'''UPDATE {ctx.guild.id}
|
||||||
|
SET balance = {new_bal}
|
||||||
|
WHERE user_id = {target.id};''')
|
||||||
|
con.commit()
|
||||||
|
con.close()
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
from .worldzero import WorldZero
|
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
|
||||||
await bot.add_cog(WorldZero(bot))
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"author" : ["cswimr"],
|
|
||||||
"install_msg" : "Thank you for installing World Zero!\nYou can find the source code of this cog here: https://coastalcommits.com/cswimr/GalaxyCogs",
|
|
||||||
"name" : "World Zero",
|
|
||||||
"short" : "This cog is meant to provide random functions for my crippling World Zero addiction!",
|
|
||||||
"description" : "This cog is meant to provide random functions for my crippling World Zero addiction!",
|
|
||||||
"end_user_data_statement" : "This cog does not store any End User Data.",
|
|
||||||
"hidden": true,
|
|
||||||
"disabled": false
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
import discord
|
|
||||||
from redbot.core import commands
|
|
||||||
|
|
||||||
|
|
||||||
class WorldZero(commands.Cog):
|
|
||||||
"""This cog is meant to provide random functions for my crippling World Zero addiction!
|
|
||||||
Developed by cswimr."""
|
|
||||||
|
|
||||||
def __init__(self, bot):
|
|
||||||
self.bot = bot
|
|
||||||
|
|
||||||
@commands.group(name="worldzero", invoke_without_command=True, aliases=['wz'])
|
|
||||||
async def worldzero(self, ctx: commands.Context):
|
|
||||||
"""Tells the user that this command doesn't do anything currently."""
|
|
||||||
await ctx.send("This command doesn't do anything currently, have you tried a subcommand?\nCurrent subcommands:\n- `-worldzero upgrade` - Checks what the Attack Power/Health of an item will be after upgrading it.\n - See `-help worldzero upgrade` for more information.")
|
|
||||||
|
|
||||||
@worldzero.command(name="upgrade")
|
|
||||||
async def worldzero_upgrade(self, ctx: commands.Context, power_amount: str, upgrade_amount: str):
|
|
||||||
"""Checks what the Attack Power/Health of an item will be after upgrading it.
|
|
||||||
|
|
||||||
|
|
||||||
**Arguments**
|
|
||||||
- The `power_amount` argument is the Attack Power/Health of the item you're looking to upgrade.
|
|
||||||
- The `upgrade_amount` argument is the number of times your item can be upgraded."""
|
|
||||||
try:
|
|
||||||
stat_int = int(f"{power_amount}".replace(",", ""))
|
|
||||||
upgrade_int = int(f"{upgrade_amount}".replace(",", ""))
|
|
||||||
except ValueError:
|
|
||||||
await ctx.send(content="Please input a number!")
|
|
||||||
return
|
|
||||||
math = round(stat_int + ((stat_int/15)*upgrade_int))
|
|
||||||
output_from = f'{stat_int:,}'
|
|
||||||
output_to = f'{math:,}'
|
|
||||||
embed = discord.Embed(color=await self.bot.get_embed_color(None))
|
|
||||||
embed.add_field(name="Default Power", value=f"{output_from}", inline=False)
|
|
||||||
embed.add_field(name="Upgraded Power", value=f"{output_to}", inline=False)
|
|
||||||
await ctx.send(embed=embed)
|
|
|
@ -1,5 +0,0 @@
|
||||||
from .youtubedownloader import YouTubeDownloader
|
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
|
||||||
await bot.add_cog(YouTubeDownloader(bot))
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"author" : ["cswimr"],
|
|
||||||
"install_msg" : "Thank you for installing YouTubeDownloader!\nYou can find the source code of this cog here: https://coastalcommits.com/cswimr/GalaxyCogs",
|
|
||||||
"name" : "YouTubeDownloader",
|
|
||||||
"short" : "Custom cog intended for use on the Galaxy discord server.",
|
|
||||||
"description" : "Custom cog intended for use on the Galaxy discord server.",
|
|
||||||
"end_user_data_statement" : "This cog does not store any End User Data.",
|
|
||||||
"requirements": ["pytube"],
|
|
||||||
"hidden": false,
|
|
||||||
"disabled": false
|
|
||||||
}
|
|
|
@ -1,160 +0,0 @@
|
||||||
import asyncio
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import discord
|
|
||||||
from redbot.core import Config, checks, commands, data_manager
|
|
||||||
from pytube import YouTube, exceptions
|
|
||||||
|
|
||||||
|
|
||||||
class YouTubeDownloader(commands.Cog):
|
|
||||||
def __init__(self, bot):
|
|
||||||
self.bot = bot
|
|
||||||
self.config = Config.get_conf(self, identifier=475728338)
|
|
||||||
self.config.register_global(
|
|
||||||
save_directory = str(data_manager.cog_data_path()) + f"{os.sep}YouTubeDownloader",
|
|
||||||
blacklisted_users = []
|
|
||||||
)
|
|
||||||
|
|
||||||
class UserBlacklisted(Exception):
|
|
||||||
def __init__(self, message="The user is blacklisted from using this command."):
|
|
||||||
super().__init__(message)
|
|
||||||
|
|
||||||
async def blacklist_checker(self, user_id):
|
|
||||||
blacklisted_users = await self.config.blacklisted_users()
|
|
||||||
for blacklisted_user_id in blacklisted_users:
|
|
||||||
if blacklisted_user_id == user_id:
|
|
||||||
raise self.UserBlacklisted
|
|
||||||
|
|
||||||
@commands.command()
|
|
||||||
@checks.is_owner()
|
|
||||||
async def change_data_path(self, ctx: commands.Context, *, data_path: str = None):
|
|
||||||
"""This command changes the data path the `[p]download` command outputs to."""
|
|
||||||
old_path = await self.config.save_directory()
|
|
||||||
if not data_path:
|
|
||||||
await ctx.send(f"The current data path is `{old_path}`.")
|
|
||||||
return
|
|
||||||
if os.path.isdir(data_path):
|
|
||||||
await self.config.save_directory.set(data_path)
|
|
||||||
embed=discord.Embed(color=await self.bot.get_embed_color(None), description=f"The save directory has been set to `{data_path}`.\n It was previously set to `{old_path}`.")
|
|
||||||
await ctx.send(embed=embed)
|
|
||||||
elif os.path.isfile(data_path):
|
|
||||||
await ctx.send("The path you've provided leads to a file, not a directory!")
|
|
||||||
elif os.path.exists(data_path) is False:
|
|
||||||
await ctx.send("The path you've provided doesn't exist!")
|
|
||||||
|
|
||||||
@commands.command(aliases=["dl"])
|
|
||||||
async def download(self, ctx: commands.Context, url: str, audio_only: bool = True, delete: bool = True, *, subfolder: str = None):
|
|
||||||
"""This command downloads a YouTube Video as an `m4a` (or `mp4`) and uploads the file to discord.
|
|
||||||
|
|
||||||
If you're considered a bot owner, you will be able to save downloaded files to the data path set in the `[p]change_data_path` command.
|
|
||||||
|
|
||||||
**Arguments**
|
|
||||||
|
|
||||||
- The `url` argument is just the url of the YouTube Video you're downloading.
|
|
||||||
|
|
||||||
- The `audio_only` argument determines if the video will be an `m4a` file or an `mp4` file.
|
|
||||||
|
|
||||||
- The `delete` argument will automatically delete the file after uploading it to Discord. If set to False, it will only save the file if you are a bot owner.
|
|
||||||
|
|
||||||
- The `subfolder` argument only does anything if `delete` is set to False, but it allows you to save to a subfolder in the data path you've set previously without having to change said data path manually."""
|
|
||||||
try:
|
|
||||||
await self.blacklist_checker(ctx.author.id)
|
|
||||||
except self.UserBlacklisted:
|
|
||||||
await ctx.send("You are blacklisted from running this command!")
|
|
||||||
return
|
|
||||||
def youtube_download(url: str, path: str):
|
|
||||||
"""This function does the actual downloading of the YouTube Video."""
|
|
||||||
yt = YouTube(url=url)
|
|
||||||
translation_table = dict.fromkeys(map(ord, r'<>:"/\|?*'), None)
|
|
||||||
filename = f"{yt.title.translate(translation_table)} ({yt.video_id})"
|
|
||||||
if audio_only:
|
|
||||||
stream = yt.streams.filter(only_audio=True, mime_type='audio/mp4')
|
|
||||||
stream = stream.order_by('abr')
|
|
||||||
filename_format = filename + ".m4a"
|
|
||||||
else:
|
|
||||||
stream = yt.streams.filter(progressive=True, mime_type='video/mp4')
|
|
||||||
stream = stream.order_by('resolution')
|
|
||||||
filename_format = filename + ".mp4"
|
|
||||||
previously_existed = bool(os.path.isfile(path + f"{os.sep}{filename_format}"))
|
|
||||||
return stream.desc().first().download(filename=filename, output_path=path), previously_existed, filename_format
|
|
||||||
data_path = await self.config.save_directory()
|
|
||||||
if subfolder and await self.bot.is_owner(ctx.author):
|
|
||||||
data_path = os.path.join(data_path, subfolder)
|
|
||||||
illegal_chars = r'<>:"/\|?*'
|
|
||||||
if any(char in illegal_chars for char in subfolder):
|
|
||||||
pattern = "[" + re.escape(illegal_chars) + "]"
|
|
||||||
modified_subfolder = re.sub(pattern, r'__**\g<0>**__', subfolder)
|
|
||||||
await ctx.send(f"Your subfolder contains illegal characters: `{modified_subfolder}`")
|
|
||||||
elif os.path.isfile(data_path):
|
|
||||||
await ctx.send("Your 'subfolder' is a file, not a directory!")
|
|
||||||
elif os.path.exists(data_path) is False:
|
|
||||||
message = await ctx.send("Your subfolder does not exist yet, would you like to continue? It will be automatically created.")
|
|
||||||
def check(message):
|
|
||||||
return message.author == ctx.author and message.content.lower() in ['yes', 'ye', 'y', '1']
|
|
||||||
try:
|
|
||||||
await self.bot.wait_for('message', check=check, timeout=60)
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
await message.edit("You took too long to respond.")
|
|
||||||
else:
|
|
||||||
await message.edit("Confirmed!")
|
|
||||||
try:
|
|
||||||
os.makedirs(data_path)
|
|
||||||
except OSError as e:
|
|
||||||
await message.edit(f"Encountered an error attempting to create the subfolder!\n`{e}`")
|
|
||||||
msg = message.edit
|
|
||||||
else:
|
|
||||||
msg = ctx.send
|
|
||||||
message = await msg("YouTube Downloader started!")
|
|
||||||
try:
|
|
||||||
output = youtube_download(url, data_path)
|
|
||||||
except exceptions.RegexMatchError:
|
|
||||||
await message.edit(content="Please provide a link to YouTube and not another site.")
|
|
||||||
return
|
|
||||||
while not os.path.isfile(output[0]):
|
|
||||||
await asyncio.sleep(0.2)
|
|
||||||
if os.path.isfile(output[0]):
|
|
||||||
with open(output[0], 'rb') as file:
|
|
||||||
try:
|
|
||||||
complete_message = await ctx.send(content="YouTube Downloader completed!\nDownloaded file:", file=discord.File(file, output[2]))
|
|
||||||
except ValueError:
|
|
||||||
complete_message = await ctx.send(content="YouTube Downloader completed, but the file was too large to upload.")
|
|
||||||
file.close()
|
|
||||||
if delete is True or await self.bot.is_owner(ctx.author) is False:
|
|
||||||
if output[1] is False:
|
|
||||||
os.remove(output[0])
|
|
||||||
await complete_message.edit(content="YouTube Downloader completed!\nFile has been deleted.\nDownloaded file:")
|
|
||||||
if output[1] is True:
|
|
||||||
await complete_message.edit(content="YouTube Downloader completed!\nFile has not been deleted, as it was previously downloaded and saved.\nDownloaded file:")
|
|
||||||
|
|
||||||
@commands.group(name="dl-blacklist", invoke_without_command=True)
|
|
||||||
async def blacklist(self, ctx: commands.Context, user: discord.User):
|
|
||||||
"""Group command for managing the blacklist."""
|
|
||||||
for user_id in await self.config.blacklisted_users():
|
|
||||||
if user_id == user.id:
|
|
||||||
await ctx.send(f"{user.mention} is in the blacklist.", allowed_mentions = discord.AllowedMentions(users=False))
|
|
||||||
return
|
|
||||||
await ctx.send(f"{user.mention} is not in the blacklist.", allowed_mentions = discord.AllowedMentions(users=False))
|
|
||||||
|
|
||||||
@blacklist.command(name='add')
|
|
||||||
@checks.is_owner()
|
|
||||||
async def blacklist_add(self, ctx: commands.Context, user: discord.User):
|
|
||||||
blacklisted_users: list = await self.config.blacklisted_users()
|
|
||||||
for user_id in blacklisted_users:
|
|
||||||
if user_id == user.id:
|
|
||||||
await ctx.send(f"{user.mention} is already in the blacklist.")
|
|
||||||
return
|
|
||||||
blacklisted_users.append(user.id)
|
|
||||||
await self.config.blacklisted_users.set(blacklisted_users)
|
|
||||||
await ctx.send(f"{user.mention} has been added to the blacklist.")
|
|
||||||
|
|
||||||
@blacklist.command(name='remove')
|
|
||||||
@checks.is_owner()
|
|
||||||
async def blacklist_remove(self, ctx: commands.Context, user: discord.User):
|
|
||||||
blacklisted_users: list = await self.config.blacklisted_users()
|
|
||||||
for user_id in blacklisted_users:
|
|
||||||
if user_id == user.id:
|
|
||||||
blacklisted_users.remove(user_id)
|
|
||||||
await self.config.blacklisted_users.set(blacklisted_users)
|
|
||||||
await ctx.send(f"{user.mention} has been removed from the blacklist.")
|
|
||||||
return
|
|
||||||
await ctx.send(f"{user.mention} is not in the blacklist.")
|
|
Loading…
Reference in a new issue