Merge remote-tracking branch 'origin/main' into dev-lavalink
Update branch with main
This commit is contained in:
commit
343818bb7e
26 changed files with 2016 additions and 632 deletions
7
.envexample
Normal file
7
.envexample
Normal file
|
@ -0,0 +1,7 @@
|
|||
TOKEN_DISCORD=
|
||||
TOKEN_GENIUS=
|
||||
TOKEN_REDDIT_CLIENT_ID=
|
||||
TOKEN_REDDIT_CLIENT_SECRET=
|
||||
TOKEN_REDDIT_USER_AGENT=
|
||||
TIMEZONE=
|
||||
PREFIX=
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,5 +1,5 @@
|
|||
.vscode/
|
||||
update/
|
||||
src/cogs/music_old.py
|
||||
src/cogs/__pycache__/
|
||||
.envrc
|
||||
__pycache__/
|
||||
.env
|
||||
*.sqlite3
|
||||
|
|
65
.gitlab-ci.yml
Normal file
65
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,65 @@
|
|||
###############################################################
|
||||
# Setting I use for cleaning up image tags #
|
||||
# - Running cleanup every week #
|
||||
# - Keeping 1 tag per image name matching : (?:v.\d+|dev) #
|
||||
# - Removing tags older than 7 days matching the default : .* #
|
||||
###############################################################
|
||||
|
||||
image: docker:stable
|
||||
|
||||
stages:
|
||||
- build
|
||||
- push
|
||||
|
||||
services:
|
||||
- docker:dind
|
||||
|
||||
before_script:
|
||||
- echo -n $CI_JOB_TOKEN | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY
|
||||
|
||||
Build:
|
||||
stage: build
|
||||
script:
|
||||
- docker pull $CI_REGISTRY_IMAGE:dev || true
|
||||
- >
|
||||
docker build
|
||||
--pull
|
||||
--build-arg VCS_REF=$CI_COMMIT_SHA
|
||||
--build-arg VCS_URL=$CI_PROJECT_URL
|
||||
--cache-from $CI_REGISTRY_IMAGE:dev
|
||||
--tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
.
|
||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
|
||||
Push latest:
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
stage: push
|
||||
only:
|
||||
- main
|
||||
script:
|
||||
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
|
||||
- docker push $CI_REGISTRY_IMAGE:latest
|
||||
|
||||
Push dev:
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
stage: push
|
||||
only:
|
||||
- dev
|
||||
script:
|
||||
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:dev
|
||||
- docker push $CI_REGISTRY_IMAGE:dev
|
||||
|
||||
Push tag:
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
stage: push
|
||||
only:
|
||||
- tags
|
||||
script:
|
||||
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
|
||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
|
13
.gitlab/issue_templates/bug.md
Normal file
13
.gitlab/issue_templates/bug.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
## Quick Information
|
||||
- **Python version:** <!-- python3 --version !-->
|
||||
- **Bot version:** <!-- Command info give you that !-->
|
||||
- **Client device where the bug occurred:** Computer / Mobile <!-- If needed !-->
|
||||
|
||||
## What Happened?
|
||||
...
|
||||
|
||||
## Expected result
|
||||
...
|
||||
|
||||
## Steps to reproduce
|
||||
...
|
|
@ -8,6 +8,7 @@ RUN pip install -r requirements.txt
|
|||
RUN apt update && \
|
||||
apt install -y --no-install-recommends ffmpeg
|
||||
|
||||
COPY README.md .
|
||||
COPY src .
|
||||
|
||||
CMD [ "python", "-u", "./main.py" ]
|
||||
|
|
201
LICENSE
Normal file
201
LICENSE
Normal file
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
48
README.md
48
README.md
|
@ -1,36 +1,46 @@
|
|||
# Bot developed with [discord.py](https://github.com/Rapptz/discord.py) (rewrite) - FRENCH
|
||||
|
||||
[![Version](https://img.shields.io/badge/version-1.0-green?style=for-the-badge)](https://github.com/Confrerie-du-Kassoulait/KassouBot/releases/latest)
|
||||
[![Docker Stars](https://img.shields.io/docker/stars/mylloon/kassoubot?style=for-the-badge)](https://hub.docker.com/repository/docker/mylloon/kassoubot)
|
||||
[![Docker Pulls](https://img.shields.io/docker/pulls/mylloon/kassoubot?style=for-the-badge)](https://hub.docker.com/repository/docker/mylloon/kassoubot)
|
||||
[![Github stars](https://img.shields.io/github/stars/Confrerie-du-Kassoulait/kassoubot?label=Github%20Stars&style=for-the-badge)](https://github.com/Confrerie-du-Kassoulait/KassouBot/stargazers)
|
||||
[![Github forks](https://img.shields.io/github/forks/Confrerie-du-Kassoulait/KassouBot?label=Github%20Forks&style=for-the-badge)](https://github.com/Confrerie-du-Kassoulait/KassouBot/network)
|
||||
[![Version](https://img.shields.io/badge/version-1.5-green?style=for-the-badge)](https://gitlab.com/ConfrerieDuKassoulait/KassouBot/-/releases)
|
||||
[![Build](https://img.shields.io/gitlab/pipeline/ConfrerieDuKassoulait/KassouBot/dev?style=for-the-badge)](https://gitlab.com/ConfrerieDuKassoulait/KassouBot/container_registry)
|
||||
## __Setting up__
|
||||
|
||||
You have to replace `TOKEN_DISCORD`, `TOKEN_GENIUS`, `TOKEN_REDDIT_CLIENT_ID`, `TOKEN_REDDIT_CLIENT_SECRET` and `TOKEN_REDDIT_USER_AGENT` with your desired values.
|
||||
With a [docker-compose](https://github.com/Confrerie-du-Kassoulait/KassouBot/blob/master/docker-compose.yml) or in command line:
|
||||
You have to replace `TOKEN_DISCORD`, `PREFIX`, `TOKEN_GENIUS`, `TOKEN_REDDIT_CLIENT_ID`, `TOKEN_REDDIT_CLIENT_SECRET`, `TOKEN_REDDIT_USER_AGENT` and [`TIMEZONE`](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) with your desired values. You must also specify a path to the folder where the database will be.\
|
||||
With a [docker-compose](https://gitlab.com/ConfrerieDuKassoulait/KassouBot/-/blob/main/docker-compose.yml) or in command line:
|
||||
|
||||
```
|
||||
docker run -d \
|
||||
--name="kassoubot" \
|
||||
mylloon/kassoubot \
|
||||
--TOKEN_DISCORD="yourValue" \
|
||||
--TOKEN_GENIUS="yourValue" \
|
||||
--TOKEN_REDDIT_CLIENT_ID="yourValue" \
|
||||
--TOKEN_REDDIT_CLIENT_SECRET="yourValue" \
|
||||
--TOKEN_REDDIT_USER_AGENT="yourValue"
|
||||
--name="KassouBot" \
|
||||
registry.gitlab.com/confreriedukassoulait/kassoubot \
|
||||
--TOKEN_DISCORD="yourTokenDiscord" \
|
||||
--TOKEN_GENIUS="yourTokenGenius" \
|
||||
--TOKEN_REDDIT_CLIENT_ID="yourRedditClientID" \
|
||||
--TOKEN_REDDIT_CLIENT_SECRET="yourRedditClientSecret" \
|
||||
--TOKEN_REDDIT_USER_AGENT="yourRedditUserAgent" \
|
||||
--TIMEZONE="yourTimezone" \
|
||||
--PREFIX="yourPrefix" \
|
||||
-v /here/your/path/:/db
|
||||
```
|
||||
|
||||
To find reddit tokens, go to [this site](https://www.reddit.com/prefs/apps) and here are the instructions: ![instructions](https://i.imgur.com/tEzYKDA.png)
|
||||
You can add the environment variable `DEACTIVATE` to disable some cogs (separate the cogs with commas and no spaces between).
|
||||
|
||||
To find reddit tokens, go to [this site](https://www.reddit.com/prefs/apps) and here are the instructions: ![instructions](https://i.imgur.com/tEzYKDA.png)
|
||||
*redirection uri (for copy/paste) : http://localhost:8080*
|
||||
|
||||
To find Genius token, go to [this site](https://genius.com/api-clients), `login to your account` and on the left select `New API Client`. Fill the field with what you want then click `Save`. Now your token is the `CLIENT ACCESS TOKEN`.
|
||||
|
||||
## __Add the bot to your server__
|
||||
|
||||
- [This site](https://discordapi.com/permissions.html) allows you to choose which permissions to add by default to the bot.
|
||||
- Choose *Administrator* so you don't get in over your head.
|
||||
- Copy and paste the ID of your bot in *Client ID* found [here](https://discord.com/developers/applications) and go to the link at the bottom of the page.
|
||||
- In the [Discord Dev Portal](https://discord.com/developers/applications) create an application, and make sure it's a `Bot` (third tab).
|
||||
- To invite it, go to the `OAuth2` (second tab) tab, select the scopes `bot` (required) and `applications.commands` (for the slashs commands) and in the bot permissions select `Administrator` (You can select manually at your own risk).
|
||||
- You have the link to copy above between the two blocks `scopes` and `permissions`.
|
||||
- If you need help, you can [join my Discord](https://discord.gg/Z5ePxH4).
|
||||
|
||||
## __Features__
|
||||
|
||||
Everything is explained by doing `.help`
|
||||
- Everything is explained by doing the `help` command.
|
||||
- Using SQLite for the database.
|
||||
|
||||
## __Launching locally__
|
||||
If you want to run it without Docker, create an .env file to store variables in the root folder (there is an example [here](https://gitlab.com/ConfrerieDuKassoulait/KassouBot/-/blob/main/.envexample)).
|
||||
Install ffmpeg by doing `sudo apt install ffmpeg` and all the requirements by doing `python3 -m pip install -r requirements.txt`
|
||||
Simply run `python3 main.py` inside the `src` folder to launch the bot in the repo folder.
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
version: "2.1"
|
||||
services:
|
||||
kassoubot:
|
||||
image: mylloon/kassoubot
|
||||
image: registry.gitlab.com/confreriedukassoulait/kassoubot
|
||||
container_name: KassouBot
|
||||
environment:
|
||||
- TOKEN_DISCORD=your-token-discord
|
||||
- TOKEN_GENIUS=your-token-genius
|
||||
- TOKEN_REDDIT_CLIENT_ID=your-reddit-client-id
|
||||
- TOKEN_REDDIT_CLIENT_SECRET=your-reddit-client-secret
|
||||
- TOKEN_REDDIT_USER_AGENT=your-reddit-user-agent
|
||||
- TOKEN_DISCORD=yourTokenDiscord
|
||||
- TOKEN_GENIUS=yourTokenGenius
|
||||
- TOKEN_REDDIT_CLIENT_ID=yourRedditClientID
|
||||
- TOKEN_REDDIT_CLIENT_SECRET=yourRedditClientSecret
|
||||
- TOKEN_REDDIT_USER_AGENT=yourRedditUserAgent
|
||||
- TIMEZONE=yourTimezone # More info here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
- PREFIX=yourPrefix
|
||||
volumes:
|
||||
- /here/your/path/:/db
|
||||
restart: unless-stopped
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
discord.py[voice]==1.6.0 # discord
|
||||
discord.py[voice]==1.7.3 # discord
|
||||
pytz==2021.1 # timezone
|
||||
praw==7.1.4 # reddit
|
||||
youtube-dl==2021.2.22 # music
|
||||
lyricsgenius==3.0.0 # lyrics
|
||||
feedparser==6.0.2 # rss feed (news)
|
||||
asyncpraw==7.3.0 # reddit
|
||||
youtube-dl==2021.6.6 # music
|
||||
lyricsgenius==3.0.1 # lyrics
|
||||
feedparser==6.0.8 # rss feed (news)
|
||||
discord-py-slash-command==2.0.1 # slash commands
|
||||
python_dotenv==0.19.0 # using .env file
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
from discord.ext import commands
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(Autopublish(client))
|
||||
|
||||
class Autopublish(commands.Cog):
|
||||
"""Autopublish."""
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
if message.author.id == 786897204816117771 and message.author.name == "GitHub" and message.author.bot:
|
||||
await message.publish()
|
91
src/cogs/citation.py
Normal file
91
src/cogs/citation.py
Normal file
|
@ -0,0 +1,91 @@
|
|||
import discord
|
||||
from re import findall
|
||||
from discord.ext import commands
|
||||
from utils.core import userOrNick
|
||||
from utils.time import timestampScreen
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(Citation(client))
|
||||
|
||||
class Citation(commands.Cog):
|
||||
"""Gère le système de citation."""
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
urls = findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', message.content)
|
||||
httpsString = "https://"
|
||||
channelsString = "discord.com/channels/"
|
||||
for i in range(len(urls)):
|
||||
if urls[i].startswith(f"{httpsString}{channelsString}") or urls[i].startswith(f"{httpsString}ptb.{channelsString}") or urls[i].startswith(f"{httpsString}canary.{channelsString}"):
|
||||
link = urls[i]
|
||||
linkURL = link
|
||||
if link.startswith(f"{httpsString}{channelsString}"):
|
||||
link = f'000{link}'
|
||||
if link.startswith(f"{httpsString}ptb.{channelsString}"):
|
||||
link = link[1:]
|
||||
if link.startswith(f"{httpsString}canary.{channelsString}"):
|
||||
link = link[4:]
|
||||
if "@me" in urls[i]:
|
||||
return await message.channel.send("Je ne cite pas les messages privés.", delete_after = 5)
|
||||
try:
|
||||
if int(link[32:-38]) == message.guild.id:
|
||||
msgID = await self.client.get_channel(int(link[51:-19])).fetch_message(int(link[70:]))
|
||||
couleur = 0x2f3136
|
||||
msgFiles = msgID.attachments
|
||||
imageExtensions = ["jpg", "jpeg", "png", "webp", "gif"]
|
||||
desc = msgID.content
|
||||
if len(msgFiles) > 1:
|
||||
listOfFiles = ""
|
||||
for i in range(0, len(msgFiles)):
|
||||
listOfFiles = f"{listOfFiles}, {msgFiles[i].filename}"
|
||||
listOfFiles = listOfFiles[2:]
|
||||
if len(msgID.content) > 0:
|
||||
desc = f"{msgID.content}\n\nIl y a plusieurs fichiers dans ce message : {listOfFiles}"
|
||||
else:
|
||||
desc = f"Il y a plusieurs fichiers dans ce message : {listOfFiles}"
|
||||
else:
|
||||
if len(msgFiles) == 1:
|
||||
if msgFiles[0].filename[-4:].split('.')[1] in imageExtensions:
|
||||
if not len(msgID.content) > 0:
|
||||
desc = f"Une image jointe : {msgFiles[0].filename}"
|
||||
else:
|
||||
linkFile = msgFiles[0].url
|
||||
if not len(msgID.content) > 0:
|
||||
desc = f"Un fichier joint : {msgFiles[0].filename}"
|
||||
embed = discord.Embed(description = desc, colour = couleur)
|
||||
auteur = "Auteur"
|
||||
if message.author == msgID.author:
|
||||
auteur = "Auteur & Citateur"
|
||||
embed.add_field(name = auteur, value = msgID.author.mention, inline=True)
|
||||
try:
|
||||
if len(msgFiles) == 1:
|
||||
if msgFiles[0].filename[-4:].split('.')[1] in imageExtensions:
|
||||
embed.set_image(url=msgFiles[0].url)
|
||||
else:
|
||||
embed.add_field(name = "Fichier", value = f"[Lien]({linkFile})", inline=True)
|
||||
except:
|
||||
pass
|
||||
embed.add_field(name = "Message", value = f"{msgID.channel.mention} - [Lien Message]({linkURL})", inline=True)
|
||||
embed.set_author(name = "Citation", icon_url = msgID.author.avatar_url)
|
||||
icon_url = message.author.avatar_url
|
||||
|
||||
if msgID.edited_at:
|
||||
edit = f" et modifié le {timestampScreen(msgID.edited_at)}"
|
||||
else:
|
||||
edit = ""
|
||||
messageDuBas = f"Posté le {timestampScreen(msgID.created_at)}{edit}"
|
||||
|
||||
if auteur == "Auteur":
|
||||
messageDuBas = messageDuBas + f"\nCité par {userOrNick(message.author)} le {timestampScreen(message.created_at)}"
|
||||
embed.set_footer(icon_url = icon_url, text = messageDuBas)
|
||||
if message.content == linkURL.replace(' ',''):
|
||||
await message.channel.send(embed = embed)
|
||||
await message.delete()
|
||||
else:
|
||||
await message.reply(embed = embed, mention_author = False)
|
||||
except Exception as e:
|
||||
e = str(e)
|
||||
if not "invalid literal for int() with base 10:" in e or not "404 Not Found (error code: 10008)" in e: # faute de frappe / message supprimé
|
||||
print(e)
|
106
src/cogs/confreriedukassoulait.py
Normal file
106
src/cogs/confreriedukassoulait.py
Normal file
|
@ -0,0 +1,106 @@
|
|||
import discord
|
||||
from re import findall
|
||||
from discord.ext import commands
|
||||
from random import choice
|
||||
from utils.core import userOrNick
|
||||
from utils.time import nowCustom, intToDatetime, nowUTC, timestampScreen
|
||||
from cogs.internet import Internet
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(ConfrerieDuKassoulait(client))
|
||||
|
||||
class ConfrerieDuKassoulait(commands.Cog):
|
||||
"""Unique pour le serveur Discord "La confrérie du Kassoulait"."""
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_member_join(self, member):
|
||||
if member.guild.id == 441208120644075520: # Confrérie du Kassoulait
|
||||
if member.bot == True:
|
||||
role = discord.utils.get(member.guild.roles, name = "Bot")
|
||||
else:
|
||||
role = discord.utils.get(member.guild.roles, name = "Copain")
|
||||
await member.add_roles(role)
|
||||
try: # DM possiblement fermé
|
||||
await member.send(f"Coucou **{member.name}** dans **{member.guild.name}** ! 🥰\n\nJ'te donne le rôle de **{role}** 💖!")
|
||||
except:
|
||||
pass
|
||||
channel = self.client.get_channel(741639570172674120) # salons des arrivées
|
||||
msgBienvenue = [
|
||||
f"Bienvenue, {member.mention}. On espère que tu as apporté de la pizza.",
|
||||
f"C'est un plaisir de te voir, {member.mention}.",
|
||||
f"{member.mention} vient juste d'arriver !",
|
||||
f"{member.mention} vient juste d'atterrir.",
|
||||
f"{member.mention} vient de se glisser dans le serveur.",
|
||||
f"{member.mention} a bondi dans le serveur.",
|
||||
f"Contents de te voir, {member.mention}.",
|
||||
f"{member.mention} est arrivé(e).",
|
||||
f"Tout le monde, accueillez comme il se doit {member.mention} !",
|
||||
f"Youhou, tu as réussi, {member.mention} !",
|
||||
f"{member.mention} a rejoint le groupe."
|
||||
]
|
||||
message = await channel.send("...") # évite d'envoyer une notification
|
||||
await message.edit(content = choice(msgBienvenue))
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_member_remove(self, member):
|
||||
if member.guild.id == 441208120644075520: # Confrérie du Kassoulait
|
||||
channel = self.client.get_channel(741639570172674120) # salons des arrivées
|
||||
await channel.send(f"{member.mention} ({member.name}) vient de quitter le serveur.")
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message_delete(self, message):
|
||||
try:
|
||||
if message.author.guild.id == 441208120644075520: # Confrérie du Kassoulait
|
||||
prefix = await self.client.get_prefix(message)
|
||||
if not (
|
||||
message.content.startswith(f"{prefix}note") or
|
||||
message.content.startswith(f"{prefix}memo") or
|
||||
len(findall(".com/channels/", message.content)) != 0 or
|
||||
self.client.user.id is message.author.id
|
||||
):
|
||||
user_suppressed = None
|
||||
|
||||
async for entry in message.guild.audit_logs(limit=1):
|
||||
if (intToDatetime(nowCustom()) - entry.created_at).seconds < 5 and str(entry.action) == 'AuditLogAction.message_delete':
|
||||
user_suppressed = entry.user
|
||||
|
||||
channel = self.client.get_channel(742588187456831659)
|
||||
embed = discord.Embed(description = f"{message.content}")
|
||||
|
||||
embed.set_author(name = userOrNick(message.author), icon_url = message.author.avatar_url)
|
||||
|
||||
if not user_suppressed:
|
||||
embed.set_footer(text = f"Channel: #{message.channel.name} | Date : {timestampScreen(message.created_at)}\nSupprimé le {timestampScreen(intToDatetime(nowUTC()))}")
|
||||
else:
|
||||
embed.set_footer(icon_url = user_suppressed.avatar_url, text = f"Channel: #{message.channel.name} | Date : {timestampScreen(message.created_at)}\nSupprimé par {userOrNick(user_suppressed)} le {timestampScreen(intToDatetime(nowUTC()))}")
|
||||
|
||||
await channel.send(embed = embed)
|
||||
# ne fonctionne pas quand un message a été supprimé avant que le bot ai démarré
|
||||
# info sur la personne qui a supprimé ne fonctionne pas si il a supprimé un message auparavant (les logs se rajoute a un log deja existant)
|
||||
except: # ignore error when deleting webhook message
|
||||
pass
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
if message.author.id == 869726667294248970 and message.author.bot: # Autopublish
|
||||
await message.publish()
|
||||
|
||||
# autre serveur
|
||||
if message.channel.id == 770805818487865404 or message.channel.id == 772239638240165928: # Le groupe de l'amour ❤❤ -- channel chien/chat
|
||||
chiens = ["dog", "chien", "potichien", "doggo"]
|
||||
chats = ["kat", "mace", "kater", "katze", "sinta", "minoos", "cat", "qitt", "besseh", "katu", "caun", "kazh",
|
||||
"bisig", "moggy", "kotka", "maow", "gat", "we'sa", "guigna", "kodkod", "mao", "koyangi", "ghjattu", "míw", "pussi",
|
||||
"gato", "gata", "kato", "kass", "domadh", "demmat", "kissa", "chat", "minou", "piscín", "cath", "k'at'a", "muca", "gali",
|
||||
"gatos", "popoki", "kike", "chatul", "chatula", "billa", "kat poes", "macska", "cica", "kutjing", "kucing", "köttur",
|
||||
"gatto", "gattina", "neko", "chma", "pising", "feles", "felix", "kakis", "katé", "qattus", "qattusa", "ngeru", "miz", "felino",
|
||||
"felina", "muur", "katt", "shimii", "billi", "gorbe", "pusa", "kot", "giat", "pisica", "koshka", "pusi", "macka", "mizhu",
|
||||
"kotsur", "bisad", "büsi", "chatz", "paka", "muc", "poonai", "puunay", "kocour", "kocka", "maa-oh", "kedi", "kit", "con mêo",
|
||||
"tchèt", "mouss", "ologbo", "kats", "猫", "кот", "고양이", "poticha", "😼", "ʇɐɥɔ", "chaton"]
|
||||
if message.content.lower() in chiens:
|
||||
for _ in range(0, 2):
|
||||
await Internet(self.client)._dog(self, await self.client.get_context(message))
|
||||
if message.content.lower() in chats:
|
||||
for _ in range(0, 2):
|
||||
await Internet(self.client)._cat(self, await self.client.get_context(message))
|
154
src/cogs/fun.py
154
src/cogs/fun.py
|
@ -1,47 +1,59 @@
|
|||
import discord, re
|
||||
import discord
|
||||
from re import findall
|
||||
from discord.ext import commands
|
||||
from random import randint, choice
|
||||
from datetime import timedelta
|
||||
from discord_slash import cog_ext
|
||||
from utils.core import retirerDoublons, mentionToUser, isSlash, mySendHidden
|
||||
from utils.time import intToDatetime
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(Fun(client))
|
||||
|
||||
class Fun(commands.Cog):
|
||||
"""Commandes plutôt fun."""
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
@commands.command(name='iq')
|
||||
async def _iq(self, ctx, *, user = '0'):
|
||||
"""Calcule ton IQ.\n ➡ Syntaxe: .iq [user]"""
|
||||
if user == '0':
|
||||
@commands.command(name='iq', aliases=["qi"])
|
||||
async def _iq(self, ctx, *user):
|
||||
"""Calcule ton QI.\n ➡ Syntaxe: {PREFIX}iq [user]"""
|
||||
_, fromSlash, user = isSlash(user)
|
||||
|
||||
if len(user) == 0:
|
||||
user = ctx.author
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(f"T'as {randint(randint(-100,0),220)} IQ {user.mention} !")
|
||||
else:
|
||||
try:
|
||||
user2 = user
|
||||
user2 = user2[2:-1]
|
||||
user2 = user2.replace("!","")
|
||||
user2 = int(user2)
|
||||
user2 = self.client.get_user(user2)
|
||||
KassouBot = self.client.get_user(740140888373854269)
|
||||
if user2.id == KassouBot.id:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(f"Bah... pas ouf... j'ai juste 100000 IQ :/")
|
||||
else:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
message = await ctx.send("...")
|
||||
return await message.edit(content = f"{user2.mention} a {randint(randint(-100,0),220)} IQ !")
|
||||
except:
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(f"T'as {randint(randint(-100, 0), 220)} de QI {user.mention} !")
|
||||
else:
|
||||
user = user[0]
|
||||
try:
|
||||
user2 = self.client.get_user(mentionToUser(user))
|
||||
if user2.id == self.client.user.id:
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(f"Bah euh... j'ai que (au moins) 100 000 de QI :/")
|
||||
else:
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
message = await ctx.send("...")
|
||||
return await message.edit(content = f"{user2.mention} a {randint(randint(-100,0),220)} de QI !")
|
||||
except:
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
message = await ctx.send("...")
|
||||
return await message.edit(content = f"{user} a {randint(randint(-100,0),220)} IQ !")
|
||||
return await message.edit(content = f"{user} a {randint(randint(-100, 0), 220)} de QI !")
|
||||
@cog_ext.cog_slash(name="iq", description = "Calcule ton QI.")
|
||||
async def __iq(self, ctx, user = None):
|
||||
if user == None:
|
||||
return await self._iq(ctx, True)
|
||||
else:
|
||||
return await self._iq(ctx, user, True)
|
||||
|
||||
@commands.command(name='love')
|
||||
async def _love(self, ctx, *users: discord.Member):
|
||||
"""Découvre la probabilité que ces deux personnes se mettent en couple.\n ➡ Syntaxe: .love <User1> <User2>"""
|
||||
"""Découvre la probabilité que ces deux personnes se mettent en couple.\n ➡ Syntaxe: {PREFIX}love <User1> <User2>"""
|
||||
_, fromSlash, users = isSlash(users)
|
||||
|
||||
if len(users) == 2 or len(users) == 1:
|
||||
UneDemande = False
|
||||
if len(users) == 1:
|
||||
|
@ -51,8 +63,9 @@ class Fun(commands.Cog):
|
|||
users.append(ctx.author)
|
||||
UneDemande = True
|
||||
if users[0] == users[1]:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send("Je suis sûr que cette personne s'aime ! :angry:")
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await mySendHidden(ctx, fromSlash, "Je suis sûr que cette personne s'aime ! :angry:")
|
||||
if users[0].nick:
|
||||
user1 = list(users[0].nick)
|
||||
else:
|
||||
|
@ -61,8 +74,8 @@ class Fun(commands.Cog):
|
|||
user2 = list(users[1].nick)
|
||||
else:
|
||||
user2 = list(users[1].name)
|
||||
user1_CALC = self._retirerDoublons([x.lower() for x in user1])
|
||||
user2_CALC = self._retirerDoublons([x.lower() for x in user2])
|
||||
user1_CALC = retirerDoublons([x.lower() for x in user1])
|
||||
user2_CALC = retirerDoublons([x.lower() for x in user2])
|
||||
coef_amour = 0
|
||||
if len(user1_CALC) > len(user2_CALC):
|
||||
taille_du_pls_grand = len(user1_CALC)
|
||||
|
@ -70,52 +83,56 @@ class Fun(commands.Cog):
|
|||
else:
|
||||
taille_du_pls_grand = len(user2_CALC)
|
||||
taille_du_ms_grand = len(user1_CALC)
|
||||
coef_amour = round(float(len(list(set(user1_CALC).intersection(user2_CALC))) / taille_du_pls_grand),1) * 100 + ((taille_du_pls_grand-taille_du_ms_grand) * 1.5) * 1.7
|
||||
coef_amour = round(float(len(list(set(user1_CALC).intersection(user2_CALC))) / taille_du_pls_grand), 1) * 100 + ((taille_du_pls_grand-taille_du_ms_grand) * 1.5) * 1.7
|
||||
if coef_amour > 100:
|
||||
coef_amour = 100
|
||||
if UneDemande == True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(f"Tu as {coef_amour}% de chance de te mettre en couple avec {''.join(user1)}")
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await ctx.send(f"{''.join(user1)} et {''.join(user2)} ont {coef_amour}% de chance de se mettre en couple !")
|
||||
else:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
await ctx.send("Erreur! Syntaxe : `.love <User1> [User2]`\n")
|
||||
def _retirerDoublons(self, liste):
|
||||
Newliste = []
|
||||
for element in liste:
|
||||
if element not in Newliste:
|
||||
Newliste.append(element)
|
||||
return Newliste
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
await ctx.send(f"Erreur! Syntaxe : `{ctx.prefix}love <User1> [User2]`\n")
|
||||
@_love.error
|
||||
async def _love_error(self, ctx, error):
|
||||
await ctx.send(str(error).replace('Member "', "Le membre **").replace('" not found', "** n'as pas été trouvé."))
|
||||
@cog_ext.cog_slash(name="love", description = "Découvre la probabilité que ces deux personnes se mettent en couple.")
|
||||
async def __love(self, ctx, user1: discord.Member, user2: discord.Member = None):
|
||||
if user2 != None:
|
||||
return await self._love(ctx, user1, user2, True)
|
||||
else:
|
||||
return await self._love(ctx, user1, True)
|
||||
|
||||
@commands.command(name='8ball', aliases=['8b', '8balls'])
|
||||
async def _8ball(self, ctx, *, question):
|
||||
"""Répond à ta question 🔮.\n ➡ Syntaxe: .8ball/8b <question>"""
|
||||
async def _8ball(self, ctx, fromSlash = None):
|
||||
"""Répond à ta question 🔮.\n ➡ Syntaxe: {PREFIX}8ball/8b"""
|
||||
if fromSlash != True:
|
||||
fromSlash = False
|
||||
reponses=["c'est sûr.","il en est décidément ainsi.","incontestablement.","oui sans aucun doute.","tu peux t'y fier.","tel que je le vois, oui.","c'est le plus probable.",
|
||||
"cela montre de bonnes perspectives.","certes.","les signes indiquent que oui.","ma réponse est oui.","ta question est trop floue, réessaie.","redemandes plus tard stp.",
|
||||
"je ferais mieux de pas te le dire maintenant...","je ne peux pas le prédire actuellement :/","concentre-toi et redemande.","n'y comptes pas trop.","ma réponse est non.",
|
||||
"mes sources disent que non.", "les perspectives ne sont pas si bonnes...","c'est très douteux."]
|
||||
await ctx.send(f"{ctx.author.mention}, {choice(reponses)}")
|
||||
if fromSlash != True:
|
||||
if fromSlash != True: await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(f"{ctx.author.mention}, {choice(reponses)}")
|
||||
@_8ball.error
|
||||
async def _8ball_error(self, ctx, error):
|
||||
if str(error) == "question is a required argument that is missing.":
|
||||
await ctx.send("Mauvaise syntaxe : `.8ball/8b/8balls <question>`.")
|
||||
|
||||
@commands.command(name='pileouface', aliases=['pf'])
|
||||
async def _pileouface(self, ctx):
|
||||
"""Pile ou face.\n ➡ Syntaxe: .pileouface/pf"""
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(f"{'Pile' if randint(0,1) == 1 else 'Face'} !")
|
||||
await ctx.send(f"Mauvaise syntaxe : `{ctx.prefix}8ball/8b/8balls <question>`.")
|
||||
@cog_ext.cog_slash(name="8ball", description = "Répond à ta question 🔮.")
|
||||
async def __8ball(self, ctx, question):
|
||||
await self._8ball(ctx, True)
|
||||
|
||||
@commands.command(name='mock')
|
||||
async def _mock(self, ctx):
|
||||
"""Se moque du message précédent"""
|
||||
"""Se moque du message précédent. - Slash command not available"""
|
||||
first = 0
|
||||
suite_auteur = None
|
||||
temps_limite = (await ctx.message.channel.history(limit = 2).flatten())[1].created_at - timedelta(minutes = 5)
|
||||
temps_limite = intToDatetime((await ctx.message.channel.history(limit = 2).flatten())[1].created_at.timestamp() - 300) # on retire 5 minutes (5 x 60 secondes)
|
||||
final_message = ""
|
||||
async for message in ctx.message.channel.history(limit = 20, after = temps_limite, oldest_first = False):
|
||||
if first == 0:
|
||||
|
@ -134,7 +151,7 @@ class Fun(commands.Cog):
|
|||
final_message = message.content
|
||||
suite_auteur = message.author
|
||||
|
||||
urls = re.findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', final_message)
|
||||
urls = findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', final_message)
|
||||
for i in range (0, len(urls)):
|
||||
final_message = final_message.replace(urls[i], '')
|
||||
|
||||
|
@ -150,3 +167,30 @@ class Fun(commands.Cog):
|
|||
return await ctx.send("".join(message).replace("\\N", "\n").replace("\\n", "\n"))
|
||||
else:
|
||||
return await ctx.send("Le message ne contient aucun texte.", delete_after = 5)
|
||||
|
||||
@commands.command(name='random', aliases=['randint'])
|
||||
async def _random(self, ctx, *n):
|
||||
"""Tire au hasard un chiffre entre 1 et n (par défaut n=10)\n ➡ Syntaxe: {PREFIX}random/randint [n]"""
|
||||
n, fromSlash, _ = isSlash(n)
|
||||
|
||||
if n:
|
||||
try:
|
||||
n = int(n)
|
||||
except:
|
||||
return await mySendHidden(ctx, fromSlash, "Veuillez renseigner un chiffre valide.")
|
||||
else:
|
||||
n = 10
|
||||
|
||||
x = 1
|
||||
if x > n:
|
||||
x, n = n, x
|
||||
resultat = randint(x, n)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(embed = discord.Embed().set_author(name = f"Tu as tiré le chiffre {resultat} !"))
|
||||
@cog_ext.cog_slash(name="random", description = "Tire au hasard un chiffre entre 1 et n (par défaut n=10)")
|
||||
async def __random(self, ctx, n: int = None):
|
||||
if n == None:
|
||||
await self._random(ctx, True)
|
||||
else:
|
||||
await self._random(ctx, n, True)
|
||||
|
|
|
@ -1,66 +1,74 @@
|
|||
import discord
|
||||
import asyncio
|
||||
from discord.ext import commands
|
||||
from random import randint, choice
|
||||
import asyncio
|
||||
from discord_slash import cog_ext
|
||||
from utils.core import isSlash, mySendHidden
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(Games(client))
|
||||
|
||||
class Games(commands.Cog):
|
||||
"""Commandes relatives aux jeux."""
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.guessing_game = {}
|
||||
|
||||
@commands.command(name='chifumi', aliases = ["shifumi", "ppc"])
|
||||
async def _chifumi(self, ctx, *, choix):
|
||||
"""Un simple Chifumi contre le bot.\n ➡ Syntaxe: .chifumi/shifumi/ppc <pierre/papier/ciseaux>"""
|
||||
async def _chifumi(self, ctx, *choix):
|
||||
"""Un simple Chifumi contre le bot.\n ➡ Syntaxe: {PREFIX}chifumi/shifumi/ppc <pierre/papier/ciseaux>"""
|
||||
choix, fromSlash, _ = isSlash(choix)
|
||||
if choix == None:
|
||||
raise ModuleNotFoundError
|
||||
|
||||
choix_jeu = ["Pierre ✊", "Papier 🧻", "Ciseaux ✂"]
|
||||
orditxt = choice(choix_jeu)
|
||||
ordi = choix_jeu.index(orditxt)
|
||||
|
||||
PIERRE = 0
|
||||
PAPIER = 1
|
||||
CISEAUX = 2
|
||||
pierre = 0
|
||||
papier = 1
|
||||
ciseaux = 2
|
||||
|
||||
choix = choix.lower()
|
||||
if choix == "pierre":
|
||||
choix = PIERRE
|
||||
if choix == "papier" or choix == "feuille":
|
||||
choix = PAPIER
|
||||
if choix == "ciseaux" or choix == "ciseau":
|
||||
choix = CISEAUX
|
||||
choix = pierre
|
||||
elif choix == "papier" or choix == "feuille":
|
||||
choix = papier
|
||||
elif choix == "ciseaux" or choix == "ciseau":
|
||||
choix = ciseaux
|
||||
else:
|
||||
return await mySendHidden(ctx, fromSlash, "Je n'ai pas compris ce que tu as joué, réessaie.")
|
||||
|
||||
description = (f"{choix_jeu[choix][:-1]} VS {choix_jeu[ordi][:-1]}\n\n**"
|
||||
f"{('Égalité !', 'Tu as perdu !', 'Tu as gagné !')[(choix != ordi) + ((choix > ordi and ordi +1 == choix) or (choix < ordi and choix + ordi == 2))]}**")
|
||||
|
||||
embed = discord.Embed(title = f"{choix_jeu[choix][-1:]}VS {choix_jeu[ordi][-1:]}", description = description)
|
||||
embed.set_author(name = ctx.author.name, icon_url = ctx.author.avatar_url)
|
||||
await ctx.send(embed = embed)
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(embed = embed)
|
||||
@_chifumi.error
|
||||
async def _chifumi_error(self, ctx, error):
|
||||
await ctx.send("Mauvaise syntaxe : `.chifumi/shifumi/ppc <pierre/papier/ciseaux>`.")
|
||||
|
||||
await ctx.send(f"Mauvaise syntaxe : `{ctx.prefix}chifumi/shifumi/ppc <pierre/papier/ciseaux>`.")
|
||||
@cog_ext.cog_slash(name="chifumi", description = "Un simple Chifumi contre le bot. <pierre/papier/ciseaux>")
|
||||
async def __chifumi(self, ctx, choix):
|
||||
return await self._chifumi(ctx, choix, True)
|
||||
|
||||
@commands.command(name='plusoumoins', aliases = ['+ou-', '+-'])
|
||||
async def _plusoumoins(self, ctx):
|
||||
"""Un plus ou moins entre 1 et 100.\n ➡ Syntaxe: .plusoumoins/+ou-/+-"""
|
||||
async def _plusoumoins(self, ctx, fromSlash = None):
|
||||
"""Un plus ou moins entre 1 et 100.\n ➡ Syntaxe: {PREFIX}plusoumoins/+ou-/+-"""
|
||||
if fromSlash != True:
|
||||
fromSlash = False
|
||||
if str(ctx.author.id) in self.guessing_game:
|
||||
return await ctx.send("Tu es déjà en partie.")
|
||||
return await mySendHidden(ctx, fromSlash, "Tu es déjà en partie.")
|
||||
guess = 5
|
||||
self.guessing_game[str(ctx.author.id)] = guess
|
||||
number = randint(1,100)
|
||||
number = randint(1, 100)
|
||||
message = f"Choisis un nombre entre 1 et 100 {ctx.author.mention}."
|
||||
await ctx.send(message)
|
||||
while self.guessing_game[str(ctx.author.id)] != 0:
|
||||
try:
|
||||
def check(message):
|
||||
if message.author.bot == False:
|
||||
return str(message.author.id) in self.guessing_game
|
||||
msg = await self.client.wait_for('message', check = check, timeout = 30)
|
||||
msg = await self.client.wait_for('message', check = lambda message: str(message.author.id) in self.guessing_game if message.author.bot == False else None, timeout = 30)
|
||||
except asyncio.TimeoutError:
|
||||
del self.guessing_game[str(ctx.author.id)]
|
||||
return await ctx.send(f"Tu as mis trop de temps a répondre {ctx.author.mention}. La réponse était {number}.")
|
||||
|
@ -91,3 +99,18 @@ class Games(commands.Cog):
|
|||
await ctx.send(f"Erreur dans la réponse {ctx.author.mention}, merci de n'écrire qu'un nombre. Tapez `stop` pour arrêter le jeu.")
|
||||
del self.guessing_game[str(ctx.author.id)]
|
||||
await ctx.send(f"T'as pas trouvé {ctx.author.mention}... dommage, c'était {number}.")
|
||||
@cog_ext.cog_slash(name="plusoumoins", description = "Un plus ou moins entre 1 et 100.")
|
||||
async def __plusoumoins(self, ctx):
|
||||
await self._plusoumoins(ctx, True)
|
||||
|
||||
@commands.command(name='pileouface', aliases=['pf'])
|
||||
async def _pileouface(self, ctx, fromSlash = None):
|
||||
"""Pile ou face.\n ➡ Syntaxe: {PREFIX}pileouface/pf"""
|
||||
if fromSlash != True:
|
||||
fromSlash = False
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(f"{'Pile' if randint(0, 1) == 1 else 'Face'} !")
|
||||
@cog_ext.cog_slash(name="pileouface", description = "Pile ou face.")
|
||||
async def __pileouface(self, ctx):
|
||||
await self._pileouface(ctx, True)
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
from discord_slash import cog_ext
|
||||
from utils.core import isSlash, mySendHidden
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(Help(client))
|
||||
|
||||
class Help(commands.Cog):
|
||||
"""Listes des commandes et/ou catégories."""
|
||||
|
||||
"""Commandes relatives à l'aide utilisateur."""
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.client.remove_command("help")
|
||||
|
||||
@commands.command(name='help')
|
||||
async def _help(self, ctx, *cog):
|
||||
"""Affiche toutes les commandes du bot.\n ➡ Syntaxe: .help [catégorie]"""
|
||||
if not cog:
|
||||
"""Liste des Cog"""
|
||||
halp=discord.Embed(title = 'Liste des catégories et commandes sans catégorie',
|
||||
"""Affiche toutes les commandes du bot.\n ➡ Syntaxe: {PREFIX}help [catégorie]"""
|
||||
_, fromSlash, cog = isSlash(cog)
|
||||
|
||||
erreur = False
|
||||
if not cog: # Liste des Cog
|
||||
halp = discord.Embed(title = 'Liste des catégories et commandes sans catégorie',
|
||||
description = f'Utilisez `{ctx.prefix}help [catégorie]` pour en savoir plus sur elles et leur commande.',
|
||||
color = discord.Colour.random())
|
||||
for name_cog in self.client.cogs:
|
||||
|
@ -27,7 +30,7 @@ class Help(commands.Cog):
|
|||
liste_cmds += f", `{ctx.prefix}{cmds.name}`"
|
||||
nb_cmds += 1
|
||||
if name_cog != "Help" and nb_cmds > 0:
|
||||
halp.add_field(name = f'**{name_cog} — {nb_cmds}**', value = liste_cmds[2:], inline = False)
|
||||
halp.add_field(name = f'**{name_cog} ({nb_cmds}) — {self.client.cogs[name_cog].__doc__}**', value = liste_cmds[2:], inline = False)
|
||||
cmds_desc = ''
|
||||
for y in self.client.walk_commands():
|
||||
if not y.cog_name and not y.hidden:
|
||||
|
@ -35,15 +38,15 @@ class Help(commands.Cog):
|
|||
|
||||
if len(cmds_desc) > 1:
|
||||
halp.add_field(name = 'Commandes sans catégorie', value = cmds_desc[0:len(cmds_desc)-1], inline = False)
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await ctx.send(embed = halp)
|
||||
else:
|
||||
"""Avertissement si il y a trop d'arguments dans la variable cog"""
|
||||
else: # Avertissement si il y a trop d'arguments dans la variable cog
|
||||
if len(cog) > 1:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
halp = discord.Embed(title = 'Erreur !', description = "Tu as renseigné trop d'arguments !", color = 0xC41B1B)
|
||||
await ctx.send(embed = halp)
|
||||
else:
|
||||
"""Liste des commandes avec cogs."""
|
||||
else: # Liste des commandes avec cogs.
|
||||
cog = [item.capitalize() for item in cog]
|
||||
found = False
|
||||
for x in self.client.cogs:
|
||||
|
@ -52,15 +55,37 @@ class Help(commands.Cog):
|
|||
halp = discord.Embed(title = f'{cog[0]} - Liste des commandes', description = self.client.cogs[cog[0]].__doc__, color = discord.Colour.random())
|
||||
for c in self.client.get_cog(y).get_commands():
|
||||
if not c.hidden:
|
||||
cmds_help = str(c.help).split("\n")
|
||||
cmds_help = str(c.help).replace("{PREFIX}", ctx.prefix).split("\n")
|
||||
del cmds_help[0]
|
||||
backslash = '\n'
|
||||
halp.add_field(name = f"`{ctx.prefix}{c.name}` - {str(c.help).split(backslash)[0]}", value = f"{''.join(cmds_help)}\u200b", inline = False)
|
||||
found = True
|
||||
if not found:
|
||||
"""Rappel si le cog n'existe pas."""
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
if not found: # Rappel si le cog n'existe pas.
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
halp = discord.Embed(title = 'Erreur !', description = f"Qu'est ce que {cog[0]} ?", color = 0xC41B1B)
|
||||
erreur = True
|
||||
else:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await ctx.send('', embed = halp)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await mySendHidden(ctx, erreur, embed = halp)
|
||||
@cog_ext.cog_slash(name="help", description = "Affiche toutes les commandes du bot.")
|
||||
async def __help(self, ctx, cog = None):
|
||||
ctx.prefix = "/"
|
||||
if cog == None:
|
||||
return await self._help(ctx, True)
|
||||
else:
|
||||
return await self._help(ctx, cog, True)
|
||||
|
||||
@commands.command(name='invite')
|
||||
async def _invite(self, ctx, fromSlash = None):
|
||||
"""Invite ce bot sur ton serveur !"""
|
||||
if fromSlash != True:
|
||||
fromSlash = False
|
||||
embed = discord.Embed(description = f"[Lien vers l'invitation Discord](https://discord.com/api/oauth2/authorize?client_id={self.client.user.id}&permissions=8&scope=bot%20applications.commands)").set_author(name="Invite moi !")
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(embed = embed)
|
||||
@cog_ext.cog_slash(name="invite", description = "Invite ce bot sur ton serveur !")
|
||||
async def __invite(self, ctx):
|
||||
return await self._invite(ctx, True)
|
||||
|
|
|
@ -1,145 +1,148 @@
|
|||
import discord, praw, json, requests, time, feedparser, os
|
||||
import discord
|
||||
from feedparser import parse
|
||||
from discord.ext import commands
|
||||
from random import randint, choice
|
||||
from random import choice
|
||||
from asyncpraw import Reddit
|
||||
from discord_slash import cog_ext
|
||||
from utils.core import randomImage, isSlash, mySendHidden, load
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(Internet(client))
|
||||
|
||||
class Internet(commands.Cog):
|
||||
"""Commandes relatives à ce qui provient d'internet."""
|
||||
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
if message.channel.id == 770805818487865404 or message.channel.id == 772239638240165928: # Le groupe de l'amour ❤❤ -- channel chien/chat
|
||||
chiens = ["dog", "chien", "potichien"]
|
||||
chats = ["kat", "mace", "kater", "katze", "sinta", "minoos", "cat", "qitt", "besseh", "katu", "caun", "kazh",
|
||||
"bisig", "moggy", "kotka", "maow", "gat", "we'sa", "guigna", "kodkod", "mao", "koyangi", "ghjattu", "míw", "pussi",
|
||||
"gato", "gata", "kato", "kass", "domadh", "demmat", "kissa", "chat", "minou", "piscín", "cath", "k'at'a", "muca", "gali",
|
||||
"gatos", "popoki", "kike", "chatul", "chatula", "billa", "kat poes", "macska", "cica", "kutjing", "kucing", "köttur",
|
||||
"gatto", "gattina", "neko", "chma", "pising", "feles", "felix", "kakis", "katé", "qattus", "qattusa", "ngeru", "miz", "felino",
|
||||
"felina", "muur", "katt", "shimii", "billi", "gorbe", "pusa", "kot", "giat", "pisica", "koshka", "pusi", "macka", "mizhu",
|
||||
"kotsur", "bisad", "büsi", "chatz", "paka", "muc", "poonai", "puunay", "kocour", "kocka", "maa-oh", "kedi", "kit", "con mêo",
|
||||
"tchèt", "mouss", "ologbo", "kats", "猫", "кот", "고양이", "poticha", "😼", "ʇɐɥɔ"]
|
||||
if message.content.lower() in chiens:
|
||||
await self._dog(await self.client.get_context(message))
|
||||
if message.content.lower() in chats:
|
||||
await self._cat(await self.client.get_context(message))
|
||||
self.keys = load(["TOKEN_REDDIT_CLIENT_ID", "TOKEN_REDDIT_CLIENT_SECRET", "TOKEN_REDDIT_USER_AGENT"])
|
||||
|
||||
@commands.command(name='memes', aliases = ['meme'])
|
||||
async def _memes(self, ctx, *, args = ""):
|
||||
"""Envois un meme de reddit.\n ➡ Syntaxe: .memes/meme [subreddit]"""
|
||||
async def _memes(self, ctx, *args):
|
||||
"""Envoie un meme de reddit.\n ➡ Syntaxe: {PREFIX}memes/meme [subreddit]"""
|
||||
args, fromSlash, _ = isSlash(args)
|
||||
|
||||
if args: # s'il y a un subreddit de défini
|
||||
subredditchoix = args
|
||||
else: # s'il n'y en a pas
|
||||
subredditchoix = choice(['memes', 'goodanimemes', 'dankmemes', 'DeepFried',
|
||||
'educationalmemes', 'funny', 'marvelmemes', 'me_irl', 'meme', 'MemeEconomy', 'Memes_Of_The_Dank', 'MinecraftMemes',
|
||||
'physicsmemes', 'blackpeopletwitter', 'metal_me_irl', '195', 'shittyadviceanimals', 'meirl',
|
||||
'2meirl4meirl', 'AdviceAnimals', 'weirdmemes', 'LeagueOfMemes'])
|
||||
|
||||
if fromSlash != None and subredditchoix == "nsfw": # demande de nsfw sans passé par la commande appropriée
|
||||
return await mySendHidden(ctx, fromSlash, f"Désolé, tu demandes du nsfw... Fais plutôt **{ctx.prefix}sexe**.")
|
||||
|
||||
try:
|
||||
reddit = praw.Reddit(client_id = os.environ['TOKEN_REDDIT_CLIENT_ID'], client_secret = os.environ['TOKEN_REDDIT_CLIENT_SECRET'], user_agent = f"disreddit /u/{os.environ['TOKEN_REDDIT_USER_AGENT']}, http://localhost:8080")
|
||||
async with Reddit(client_id = self.keys['TOKEN_REDDIT_CLIENT_ID'], client_secret = self.keys['TOKEN_REDDIT_CLIENT_SECRET'], user_agent = f"disreddit /u/{self.keys['TOKEN_REDDIT_USER_AGENT']}, http://localhost:8080") as reddit:
|
||||
subreddit = await reddit.subreddit(subredditchoix) # récupération du subreddit
|
||||
hot = subreddit.top(limit = 20) # récupération des memes avec une limite aux 10 premiers memes
|
||||
all_subs = [item async for item in hot] # liste des memes
|
||||
submission = choice(all_subs) # choix aléatoire
|
||||
|
||||
if args != "": # si il y a un arg différent d'un meme
|
||||
subredditchoix = args
|
||||
|
||||
else: # si il n'y a pas d'arguments
|
||||
subredditchoix = choice(['memes', 'anime_irl', 'goodanimemes', 'BikiniclienttomTwitter', 'dankmemes', 'DeepFriedMemes',
|
||||
'educationalmemes', 'funny', 'marvelmemes', 'me_irl', 'meme', 'MemeEconomy', 'Memes_Of_The_Dank', 'MinecraftMemes',
|
||||
'physicsmemes', 'reactiongifs', 'blackpeopletwitter', 'metal_me_irl', 'bee_irl', '195',
|
||||
'shittyadviceanimals', 'meirl', '2meirl4meirl', 'AdviceAnimals', 'weirdmemes'])
|
||||
|
||||
memes_submissions = reddit.subreddit(subredditchoix).hot()
|
||||
post_to_pick = randint(1, 10)
|
||||
for i in range(0, post_to_pick): # i pas important
|
||||
i = i #retire l'erreur sur vscode
|
||||
submission = next(x for x in memes_submissions if not x.stickied)
|
||||
|
||||
image = ["png", "jpg", "jpeg", "bmp", "gif"]
|
||||
image = ["png", "jpg", "jpeg", "bmp", "gif"] # gifv not working
|
||||
if submission.url[-3:] in image:
|
||||
embed = discord.Embed(title = f"r/{subredditchoix} pour {ctx.author.name}", color = discord.Colour.random(), description = f"[lien du meme]({submission.url})")
|
||||
embed.set_footer(text = f"Meme de Reddit")
|
||||
if fromSlash != None:
|
||||
footer = "Meme de Reddit"
|
||||
memeOuImage = "[lien du meme]"
|
||||
else:
|
||||
footer = "NSFW de Reddit"
|
||||
memeOuImage = "[lien de l'image]"
|
||||
embed = discord.Embed(title = f"r/{subredditchoix} pour {ctx.author.name}", color = discord.Colour.random(), description = f"{memeOuImage}(https://www.reddit.com{submission.permalink})")
|
||||
embed.set_footer(text = footer)
|
||||
embed.set_image(url = submission.url)
|
||||
message = await ctx.send(embed = embed)
|
||||
else:
|
||||
await ctx.send(f"```r/{subredditchoix} pour {ctx.author.name}```\n{submission.url}")
|
||||
message = await ctx.send("```Meme de Reddit```")
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await message.add_reaction('👍')
|
||||
return await message.add_reaction('👎')
|
||||
if fromSlash != None:
|
||||
message = await ctx.send(f"`r/{subredditchoix} pour {ctx.author.name}`\n{submission.url}")
|
||||
else:
|
||||
message = await ctx.send(f"`{subredditchoix.capitalize()} pour {ctx.author.name}`\n{submission.url}")
|
||||
if fromSlash != True and fromSlash != None:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
if fromSlash != None:
|
||||
for emoji in ['🔺', '🔻']:
|
||||
await message.add_reaction(emoji)
|
||||
|
||||
except Exception as error:
|
||||
print(f"args: {args}, subreddit: {subredditchoix}, error: {error}")
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
return await ctx.send(f"Ce subreddit est interdit, mis en quarantaine ou n'existe pas. ({subredditchoix})")
|
||||
|
||||
def _random_image(self, link):
|
||||
temps_requete = int(round(time.time() * 1000))
|
||||
try:
|
||||
request_data = requests.get(link)
|
||||
except Exception as e:
|
||||
raise Exception(f"Une erreur s'est produite lors de la tentative de demande de l'API {link} : {e}")
|
||||
|
||||
if not request_data.status_code == 200:
|
||||
raise Exception(f"Code HTTP {request_data.status_code} au lieu de HTTP 200 à l'appel de {link} : {request_data.text}")
|
||||
|
||||
try:
|
||||
json_data = json.loads(request_data.text)
|
||||
except Exception as e:
|
||||
raise Exception(f"Erreur lors de la transformation les données de {link} en json : {e}")
|
||||
|
||||
temps_requete = int(round(time.time() * 1000)) - temps_requete
|
||||
return (json_data, temps_requete)
|
||||
print(f"Error in _memes command = args: {args}, subreddit: {subredditchoix}, error: {error}")
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
return await mySendHidden(ctx, fromSlash, f"Ce subreddit est interdit, mis en quarantaine ou n'existe pas. ({subredditchoix})")
|
||||
@cog_ext.cog_slash(name="meme", description = "Envoie un meme de reddit.")
|
||||
async def __memes(self, ctx, subreddit = None):
|
||||
ctx.prefix = "/"
|
||||
if subreddit == None:
|
||||
return await self._memes(ctx, True)
|
||||
else:
|
||||
return await self._memes(ctx, subreddit, True)
|
||||
|
||||
@commands.command(name='cat', aliases = ['chat'])
|
||||
async def _cat(self, ctx):
|
||||
"""Te montre un magnifique chat\n ➡ Syntaxe: .cat/chat"""
|
||||
async def _cat(self, ctx, fromSlash = None):
|
||||
"""Te montre un magnifique chat.\n ➡ Syntaxe: {PREFIX}cat/chat"""
|
||||
if fromSlash != True:
|
||||
fromSlash = False
|
||||
|
||||
if ctx.author.nick:
|
||||
name = f"{ctx.author.nick} ({ctx.author.name}#{ctx.author.discriminator})"
|
||||
else:
|
||||
name = f"{ctx.author.name}"
|
||||
embed = discord.Embed(title = f"Poticha pour {name}", colour = discord.Colour.random())
|
||||
cat = self._random_image("http://aws.random.cat/meow")
|
||||
cat = randomImage("http://aws.random.cat/meow")
|
||||
embed.set_image(url = cat[0]['file'])
|
||||
embed.set_footer(text = f"random.cat a pris {cat[1]} ms.")
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
message = await ctx.send(embed=embed)
|
||||
return await message.add_reaction('❤️')
|
||||
@cog_ext.cog_slash(name="cat", description = "Te montre un magnifique chat.")
|
||||
async def __cat(self, ctx):
|
||||
return await self._cat(ctx, True)
|
||||
|
||||
@commands.command(name='dog', aliases = ['chien'])
|
||||
async def _dog(self, ctx):
|
||||
"""Te montre un magnifique chien\n ➡ Syntaxe: .dog/chien"""
|
||||
async def _dog(self, ctx, fromSlash = None):
|
||||
"""Te montre un magnifique chien.\n ➡ Syntaxe: {PREFIX}dog/chien"""
|
||||
if fromSlash != True:
|
||||
fromSlash = False
|
||||
|
||||
if ctx.author.nick:
|
||||
name = f"{ctx.author.nick} ({ctx.author.name}#{ctx.author.discriminator})"
|
||||
else:
|
||||
name = f"{ctx.author.name}"
|
||||
embed = discord.Embed(title = f"Potichien pour {name}", colour = discord.Colour.random())
|
||||
dog = self._random_image("https://dog.ceo/api/breeds/image/random")
|
||||
dog = randomImage("https://dog.ceo/api/breeds/image/random")
|
||||
embed.set_image(url = dog[0]['message'])
|
||||
embed.set_footer(text = f"dog.ceo a pris {dog[1]} ms.")
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
message = await ctx.send(embed=embed)
|
||||
return await message.add_reaction('❤️')
|
||||
@cog_ext.cog_slash(name="dog", description = "Te montre un magnifique chien.")
|
||||
async def __dog(self, ctx):
|
||||
return await self._dog(ctx, True)
|
||||
|
||||
@commands.command(name='sexe', aliases=['sexes', 'nude', 'nudes', 'nsfw'])
|
||||
async def _sexe(self, ctx, *, choice_of_nsfw = None):
|
||||
"""Envois une image coquine. (NSFW)\n ➡ Syntaxe: .sexe/sexes/nude/nudes [butts/boobs]"""
|
||||
liste_hot = ['butts', 'boobs']
|
||||
if choice_of_nsfw in liste_hot:
|
||||
pass
|
||||
else:
|
||||
choice_of_nsfw = choice(liste_hot)
|
||||
async def _sexe(self, ctx, fromSlash = None):
|
||||
"""Envois une image coquine. (NSFW)\n ➡ Syntaxe: {PREFIX}sexe/sexes/nude/nudes"""
|
||||
if fromSlash != True:
|
||||
fromSlash = False
|
||||
if ctx.channel.is_nsfw():
|
||||
embed = discord.Embed(title = f"{choice_of_nsfw.capitalize()} pour {ctx.author.name}", colour = discord.Colour.random())
|
||||
nsfw = self._random_image(f'http://api.o{choice_of_nsfw}.ru/noise/')
|
||||
embed.set_image(url = f"http://media.o{choice_of_nsfw}.ru/{nsfw[0][0]['preview']}")
|
||||
embed.set_footer(text = f"o{choice_of_nsfw}.ru a pris {nsfw[1]} ms.")
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await ctx.send(embed = embed)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
else:
|
||||
ctx.prefix = "/"
|
||||
return await self._memes(ctx, "nsfw", None)
|
||||
else:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
await ctx.send(f"Désolé mais je n'envois ce genre de message seulement dans les salons NSFW !")
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
await mySendHidden(ctx, fromSlash, f"Désolé mais je n'envois ce genre de message seulement dans les salons NSFW !")
|
||||
@cog_ext.cog_slash(name="sexe", description = "Envois une image coquine. (NSFW)")
|
||||
async def __sexe(self, ctx):
|
||||
return await self._sexe(ctx, True)
|
||||
|
||||
@commands.command(name='news', aliases=['rss'])
|
||||
async def _news(self, ctx, *, arg = ""):
|
||||
"""Info random dans le domaine de l'informatique\n ➡ Syntaxe: .news/rss [site/liste]"""
|
||||
async def _news(self, ctx, *arg):
|
||||
"""Info random dans le domaine de l'informatique\n ➡ Syntaxe: {PREFIX}news/rss [site/liste]"""
|
||||
arg, fromSlash, _ = isSlash(arg)
|
||||
if arg == None:
|
||||
arg = ""
|
||||
|
||||
rss_website = {
|
||||
"anandtech": "https://www.anandtech.com/rss/",
|
||||
|
@ -170,7 +173,7 @@ class Internet(commands.Cog):
|
|||
embed = discord.Embed(title = "Liste des sources", color = discord.Colour.random(), description = ", ".join([key.capitalize() for key in rss_website.keys()]))
|
||||
return await ctx.send(embed = embed)
|
||||
|
||||
newsfeed = feedparser.parse(rss_website[choix_site])
|
||||
newsfeed = parse(rss_website[choix_site])
|
||||
info = choice([newsfeed.entries[i] for i in range(0, 10 if len(newsfeed.entries) > 10 else len(newsfeed.entries))])
|
||||
|
||||
desc = "Pas de description trouvée." if "<p>" in info.description or "</a>" in info.description else info.description
|
||||
|
@ -181,4 +184,11 @@ class Internet(commands.Cog):
|
|||
pass
|
||||
embed.set_footer(text = f"News de {choix_site.capitalize()}")
|
||||
await ctx.send(embed = embed)
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
@cog_ext.cog_slash(name="news", description = "Info random dans le domaine de l'informatique, met commme arg liste pour la liste des sources dispo.")
|
||||
async def __news(self, ctx, source = None):
|
||||
if source == None:
|
||||
return await self._news(ctx, True)
|
||||
else:
|
||||
return await self._news(ctx, source, True)
|
||||
|
|
|
@ -18,10 +18,13 @@ from async_timeout import timeout
|
|||
from discord.ext import commands
|
||||
|
||||
# Genius API
|
||||
import lyricsgenius
|
||||
import time
|
||||
import os
|
||||
genius = lyricsgenius.Genius(os.environ['TOKEN_GENIUS'])
|
||||
from lyricsgenius import Genius
|
||||
from utils.core import ligneFormatage, userOrNick, load
|
||||
from utils.time import nowCustom
|
||||
|
||||
from re import sub
|
||||
genius = Genius(load(["TOKEN_GENIUS"])["TOKEN_GENIUS"])
|
||||
genius.response_format = "markdown"
|
||||
|
||||
# Silence useless bug reports messages
|
||||
youtube_dl.utils.bug_reports_message = lambda: ''
|
||||
|
@ -270,7 +273,7 @@ class VoiceState:
|
|||
|
||||
|
||||
class Music(commands.Cog):
|
||||
"""Commandes relatives à la musique - © vbe0201."""
|
||||
"""Commandes relatives à la musique © vbe0201. (slash commands not working)"""
|
||||
def __init__(self, client: commands.bot):
|
||||
self.client = client
|
||||
self.voice_states = {}
|
||||
|
@ -299,9 +302,9 @@ class Music(commands.Cog):
|
|||
async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError):
|
||||
await ctx.send(f"Une erreur est survenue : {str(error)}")
|
||||
|
||||
@commands.command(name='join', aliases=['j'], invoke_without_subcommand=True)
|
||||
@commands.command(name='join', aliases=['j', 'connect'], invoke_without_subcommand=True)
|
||||
async def _summon(self, ctx: commands.Context, *, channel: discord.VoiceChannel = None):
|
||||
"""Se connecte au salon vocal.\n ➡ Syntaxe: .connect/join"""
|
||||
"""Se connecte au salon vocal.\n ➡ Syntaxe: {PREFIX}connect/join"""
|
||||
|
||||
if not channel and not ctx.author.voice:
|
||||
await ctx.send("Aucun channel à rejoindre. Connecte toi dans un vocal ou donne-moi son id.")
|
||||
|
@ -314,13 +317,14 @@ class Music(commands.Cog):
|
|||
return
|
||||
|
||||
ctx.voice_state.voice = await destination.connect()
|
||||
await ctx.guild.change_voice_state(channel = destination, self_mute = False, self_deaf = True)
|
||||
|
||||
@commands.command(name='stop', aliases=['disconnect', 'dc'])
|
||||
async def _leave(self, ctx: commands.Context):
|
||||
"""Arrête la chanson en cours de lecture et quitte le salon vocal.\n ➡ Syntaxe: .disconnect/dc/stop"""
|
||||
"""Arrête la chanson en cours de lecture et quitte le salon vocal.\n ➡ Syntaxe: {PREFIX}disconnect/dc/stop"""
|
||||
|
||||
if not ctx.voice_state.voice:
|
||||
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose ou `.join [id]` pour me connecter à un salon vocal.", color = 0xC41B1B)
|
||||
embed = discord.Embed(description = f"Tape `{ctx.prefix}play <chanson>` pour jouer quelque chose ou `{ctx.prefix}join [id]` pour me connecter à un salon vocal.", color = 0xC41B1B)
|
||||
embed.set_author(name = "Je ne suis connecté à aucun vocal.")
|
||||
return await ctx.send(embed = embed)
|
||||
|
||||
|
@ -330,7 +334,7 @@ class Music(commands.Cog):
|
|||
|
||||
@commands.command(name='volume', aliases=['vol'])
|
||||
async def _volume(self, ctx: commands.Context, *, volume: int = False):
|
||||
"""Modifie le volume du bot (entre 1 et 100).\n ➡ Syntaxe: .volume/vol [1;100]"""
|
||||
"""Modifie le volume du bot (entre 1 et 100).\n ➡ Syntaxe: {PREFIX}volume/vol [1;100]"""
|
||||
|
||||
if not ctx.voice_state.is_playing:
|
||||
return await ctx.send("Rien n'est joué pour le moment.")
|
||||
|
@ -346,7 +350,7 @@ class Music(commands.Cog):
|
|||
|
||||
@commands.command(name='now', aliases=['current', 'playing', 'np'])
|
||||
async def _now(self, ctx: commands.Context):
|
||||
"""Affiche des informations sur la chanson en cours de lecture.\n ➡ Syntaxe: .now/current/playing/np"""
|
||||
"""Affiche des informations sur la chanson en cours de lecture.\n ➡ Syntaxe: {PREFIX}now/current/playing/np"""
|
||||
|
||||
await ctx.send(embed=ctx.voice_state.current.create_embed())
|
||||
|
||||
|
@ -359,7 +363,7 @@ class Music(commands.Cog):
|
|||
await ctx.message.add_reaction('⏯')
|
||||
await ctx.send(f"**`{ctx.author}`** met en pause la chanson en cours.")
|
||||
else:
|
||||
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
|
||||
embed = discord.Embed(description = f"Tape `{ctx.prefix}play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
|
||||
embed.set_author(name = "Je ne joue rien en ce moment !")
|
||||
return await ctx.send(embed = embed)
|
||||
|
||||
|
@ -373,20 +377,20 @@ class Music(commands.Cog):
|
|||
await ctx.send(f"**`{ctx.author}`** relance la chanson.")
|
||||
else:
|
||||
if ctx.voice_state.is_playing:
|
||||
embed = discord.Embed(description = "Tape `.pause` pour mettre en pause la chanson.", color = 0xC41B1B)
|
||||
embed = discord.Embed(description = f"Tape `{ctx.prefix}pause` pour mettre en pause la chanson.", color = 0xC41B1B)
|
||||
embed.set_author(name = "Je suis déjà en lecture !")
|
||||
return await ctx.send(embed = embed)
|
||||
else:
|
||||
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose ou `.join [id]` pour me connecter à un salon vocal.", color = 0xC41B1B)
|
||||
embed = discord.Embed(description = f"Tape `{ctx.prefix}play <chanson>` pour jouer quelque chose ou `{ctx.prefix}join [id]` pour me connecter à un salon vocal.", color = 0xC41B1B)
|
||||
embed.set_author(name = "Je ne suis connecté à aucun vocal.")
|
||||
return await ctx.send(embed = embed)
|
||||
|
||||
@commands.command(name='skip', aliases=['s'])
|
||||
async def _skip(self, ctx: commands.Context):
|
||||
"""Passe la chanson.\n ➡ Syntaxe: .skip/s"""
|
||||
"""Passe la chanson.\n ➡ Syntaxe: {PREFIX}skip/s"""
|
||||
|
||||
if not ctx.voice_state.is_playing:
|
||||
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
|
||||
embed = discord.Embed(description = f"Tape `{ctx.prefix}play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
|
||||
embed.set_author(name = "Je ne joue rien en ce moment !")
|
||||
return await ctx.send(embed = embed)
|
||||
|
||||
|
@ -396,10 +400,10 @@ class Music(commands.Cog):
|
|||
|
||||
@commands.command(name='queue', aliases=['q', 'playlist'])
|
||||
async def _queue(self, ctx: commands.Context, *, page: int = 1):
|
||||
"""Affiche la file d'attente des chansons à venir.\n ➡ Syntaxe: .queue/q/playlist [page]"""
|
||||
"""Affiche la file d'attente des chansons à venir.\n ➡ Syntaxe: {PREFIX}queue/q/playlist [page]"""
|
||||
|
||||
if len(ctx.voice_state.songs) == 0:
|
||||
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
|
||||
embed = discord.Embed(description = f"Tape `{ctx.prefix}play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
|
||||
embed.set_author(name = "Il n'y a plus de chanson à venir dans la playlist.")
|
||||
return await ctx.send(embed = embed)
|
||||
|
||||
|
@ -407,7 +411,7 @@ class Music(commands.Cog):
|
|||
pages = math.ceil(len(ctx.voice_state.songs) / items_per_page)
|
||||
|
||||
if page > pages:
|
||||
embed = discord.Embed(description = "Tape `.play <chanson>` pour rajouter encore de la musique.", color = 0xC41B1B)
|
||||
embed = discord.Embed(description = f"Tape `{ctx.prefix}play <chanson>` pour rajouter encore de la musique.", color = 0xC41B1B)
|
||||
embed.set_author(name = "Il n'y a pas autant de pages")
|
||||
return await ctx.send(embed = embed)
|
||||
|
||||
|
@ -427,7 +431,7 @@ class Music(commands.Cog):
|
|||
"""Mélange la file d'attente."""
|
||||
|
||||
if len(ctx.voice_state.songs) == 0:
|
||||
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
|
||||
embed = discord.Embed(description = f"Tape `{ctx.prefix}play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
|
||||
embed.set_author(name = "La file est vide.")
|
||||
return await ctx.send(embed = embed)
|
||||
|
||||
|
@ -447,10 +451,10 @@ class Music(commands.Cog):
|
|||
|
||||
@commands.command(name='loop', aliases=['repeat'])
|
||||
async def _loop(self, ctx: commands.Context):
|
||||
"""Répète la chanson actuellement en lecture.\n ➡ Syntaxe: .loop/repeat"""
|
||||
"""Répète la chanson actuellement en lecture.\n ➡ Syntaxe: {PREFIX}loop/repeat"""
|
||||
|
||||
if not ctx.voice_state.is_playing:
|
||||
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
|
||||
embed = discord.Embed(description = f"Tape `{ctx.prefix}play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
|
||||
embed.set_author(name = "Je ne joue rien en ce moment !")
|
||||
return await ctx.send(embed = embed)
|
||||
|
||||
|
@ -461,7 +465,7 @@ class Music(commands.Cog):
|
|||
|
||||
@commands.command(name='play', aliases=['p'])
|
||||
async def _play(self, ctx: commands.Context, *, search: str):
|
||||
"""Recherche une chanson sur les sites compatibles avec YoutubeDL si aucun URL n'est donné et l'ajoute à la file d'attente.\n ➡ Syntaxe: .play/p"""
|
||||
"""Recherche une chanson sur les sites compatibles avec YoutubeDL si aucun URL n'est donné et l'ajoute à la file d'attente.\n ➡ Syntaxe: {PREFIX}play/p"""
|
||||
|
||||
if not ctx.voice_state.voice:
|
||||
await ctx.invoke(self._summon)
|
||||
|
@ -489,22 +493,23 @@ class Music(commands.Cog):
|
|||
|
||||
@commands.command(name='lyrics', aliases = ['l', 'lyric'])
|
||||
async def _lyrics(self, ctx, *, song: str = None):
|
||||
"""Affiche les paroles de la musique en cours, ou de la chanson spécifiée.\n ➡ Syntaxe: .lyrics/lyric/l (musique)"""
|
||||
"""Affiche les paroles de la musique en cours, ou de la chanson spécifiée.\n ➡ Syntaxe: {PREFIX}lyrics/lyric/l (musique)"""
|
||||
if song or ctx.voice_state.is_playing:
|
||||
if not song:
|
||||
song = f"{ctx.voice_state.current.title()}"
|
||||
song = sub(r"(\ )?\(.*\)", "", ctx.voice_state.current.title())
|
||||
if " romanized" in song:
|
||||
message = await ctx.send(f":mag: **Cherche les paroles romanisées de ** `{song.replace(' romanized', '')}`")
|
||||
else:
|
||||
message = await ctx.send(f":mag: **Cherche les paroles de ** `{song}`")
|
||||
temps_requete = int(round(time.time() * 1000))
|
||||
temps_requete = int(round(nowCustom() * 1000))
|
||||
song_genius = genius.search_song(song)
|
||||
couleur_embed = discord.Colour.random()
|
||||
try:
|
||||
paroles = song_genius.lyrics
|
||||
except:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
return await message.edit(content = f"Pas de résultats trouvés pour `{song}`.")
|
||||
return await message.edit(content = f"Pas de résultats trouvés pour `{song}`.")
|
||||
paroles = sub(r"3?EmbedShare URLCopyEmbedCopy", "", paroles) # Fix temporaire bug Genius
|
||||
lignetotal = ""
|
||||
premierembed = True
|
||||
if len(paroles) > 7500:
|
||||
|
@ -518,7 +523,7 @@ class Music(commands.Cog):
|
|||
type_de_comptage = "\n"
|
||||
for ligne in paroles.split(type_de_comptage):
|
||||
if len(f"{lignetotal}{type_de_comptage}{ligne}") < 1900:
|
||||
lignetotal = f"{lignetotal}{type_de_comptage}{self.ligne_formatage(ligne)}"
|
||||
lignetotal = f"{lignetotal}{type_de_comptage}{ligneFormatage(ligne)}"
|
||||
else:
|
||||
if premierembed == True:
|
||||
premierembed = False
|
||||
|
@ -528,10 +533,10 @@ class Music(commands.Cog):
|
|||
else:
|
||||
embed = discord.Embed(description = lignetotal, color = couleur_embed)
|
||||
await ctx.send(embed = embed)
|
||||
lignetotal = f"{self.ligne_formatage(ligne)}"
|
||||
lignetotal = f"{ligneFormatage(ligne)}"
|
||||
|
||||
temps_requete = int(round(time.time() * 1000)) - temps_requete
|
||||
footer_embed = f"Pour {self.user_or_nick(ctx.author)} par Genius en {round(temps_requete / 1000, 2)} s."
|
||||
temps_requete = int(round(nowCustom() * 1000)) - temps_requete
|
||||
footer_embed = f"Pour {userOrNick(ctx.author)} par Genius en {round(temps_requete / 1000, 2)} s."
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
if premierembed == True:
|
||||
premierembed = False
|
||||
|
@ -544,21 +549,10 @@ class Music(commands.Cog):
|
|||
return await ctx.send(embed = embed)
|
||||
else:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
await ctx.send("Aucune musique demandé... `.lyrics/l/lyrics <song>`.")
|
||||
def ligne_formatage(self, ligne):
|
||||
liste_balise = [
|
||||
('[Hook', '[Accroche'), ('[Verse', '[Couplet'), ('[Chorus', '[Chœur'),
|
||||
('[Bridge', '[Pont'),('[Pre-Chorus', '[Pré-chœur'), ('[Post-Chorus', '[Post-chœur')
|
||||
]
|
||||
for balises in liste_balise:
|
||||
ligne = ligne.replace(balises[0], balises[1])
|
||||
return ligne
|
||||
def user_or_nick(self, user):
|
||||
if user.nick:
|
||||
return f"{user.nick} ({user.name}#{user.discriminator})"
|
||||
else:
|
||||
return f"{user.name}#{user.discriminator}"
|
||||
await ctx.send(f"Aucune musique demandé... `{ctx.prefix}lyrics/l/lyrics <song>`.")
|
||||
|
||||
@commands.command(name='lyricsromanized', aliases = ['lr', 'lyricromanized'], hidden = True)
|
||||
async def _lyricsromanized(self, ctx, *, song: str = None):
|
||||
if not song and ctx.voice_state.is_playing:
|
||||
song = sub(r"(\ )?\(.*\)", "", ctx.voice_state.current.title())
|
||||
await ctx.invoke(self.client.get_command("lyrics"), song = f"{song} romanized" if song else song)
|
||||
|
|
206
src/cogs/reminder.py
Normal file
206
src/cogs/reminder.py
Normal file
|
@ -0,0 +1,206 @@
|
|||
import discord
|
||||
from discord.ext import commands, tasks
|
||||
from discord_slash import cog_ext
|
||||
from utils.reminder import Reminder, embedListe, listReaction
|
||||
from utils.core import getURLsInString, getMentionInString, isSlash, mySendHidden, mentionToUser, cleanCodeStringWithMentionAndURLs
|
||||
from utils.time import stringTempsVersSecondes, nowUTC, intToDatetime, timedeltaToString
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(ReminderDiscord(client))
|
||||
|
||||
class ReminderDiscord(commands.Cog):
|
||||
"""Commandes relatives aux reminder."""
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self._reminderLoop.start()
|
||||
|
||||
@tasks.loop(minutes = 1)
|
||||
async def _reminderLoop(self):
|
||||
"""Méthode qui se répète toute les minutes pour vérifier si des rappels n'ont pas expirés, si expirés, les envoient."""
|
||||
expiration = Reminder().recuperationExpiration(int(nowUTC())) # on récupères les éléments expirés
|
||||
for expired in expiration: # on regarde tout les éléments expirés
|
||||
reminder = expired[2] # message
|
||||
userID = expired[4] # personne qui a fait le rappel
|
||||
channel = self.client.get_channel(expired[0]) # salon du message
|
||||
finalEmbed = discord.Embed(description = cleanCodeStringWithMentionAndURLs(reminder), timestamp = intToDatetime(expired[3]), color = discord.Colour.random())
|
||||
if expired[1] == 2: # s'il faut envoyer en DM le message
|
||||
user = self.client.get_user(userID)
|
||||
if user == None: # si l'utilisateur n'est pas trouvé
|
||||
return Reminder().suppressionReminder(expired[5]) # suppression du rappel
|
||||
channel = await user.create_dm() # envoie en DM
|
||||
userID = None # plus de mention
|
||||
sourceMessage = None # plus de message source
|
||||
elif channel == None: # si le salon n'existe plus
|
||||
user = self.client.get_user(userID)
|
||||
if user == None: # si l'utilisateur n'est pas trouvé
|
||||
return Reminder().suppressionReminder(expired[5]) # suppression du rappel
|
||||
channel = await user.create_dm() # envoie en DM
|
||||
userID = None # plus de mention
|
||||
sourceMessage = None # plus de message source
|
||||
finalEmbed.add_field(name = "Info", value = "Message envoyé en DM car le salon n'est plus disponible.")
|
||||
else:
|
||||
sourceMessage = expired[6]
|
||||
if sourceMessage != None: # vérification message avec slash command et que si c'est pas en DM
|
||||
try:
|
||||
sourceMessage = await channel.fetch_message(sourceMessage) # récupération message
|
||||
except:
|
||||
sourceMessage = None # message a été supprimé
|
||||
if sourceMessage != None:
|
||||
await sourceMessage.add_reaction(emoji = '✅') # ajout réaction
|
||||
finalEmbed.set_footer(text=f"Message d'il y a {timedeltaToString(int(nowUTC()) - expired[3])}")
|
||||
links = ""
|
||||
findedURLs = getURLsInString(reminder)
|
||||
for i in range(0, len(findedURLs)): # ajout de field "lien" pour pouvoir cliquer sur les liens facilement
|
||||
links += f"[Lien {i + 1}]({findedURLs[i]}) · "
|
||||
if len(findedURLs) > 0:
|
||||
finalEmbed.add_field(name = f"Lien{'s' if len(findedURLs) > 1 else ''}", value = links[:-3])
|
||||
message = ""
|
||||
if userID != None: # metion de l'utilisateur si le message n'est pas en DM
|
||||
message = f"<@{userID}>"
|
||||
if expired[1] == 1: # s'il faut mentionner les personnes dans le message
|
||||
mentionList = getMentionInString(reminder)
|
||||
for i in mentionList:
|
||||
message += f" {i}"
|
||||
try:
|
||||
await channel.send(message, embed = finalEmbed) # envoie du rappel
|
||||
except: # les DM sont fermés
|
||||
pass
|
||||
Reminder().suppressionReminder(expired[5]) # suppression du rappel
|
||||
@_reminderLoop.before_loop
|
||||
async def __avant_reminderLoop(self):
|
||||
await self.client.wait_until_ready()
|
||||
|
||||
@commands.command(name='reminder', aliases=["remind", "remindme", "rappel"])
|
||||
async def _reminder(self, ctx, time, *reminder):
|
||||
"""Met en place un rappel.\n ➡ Syntaxe: {PREFIX}reminder/remind/remindme/rappel <temps>[@] [message]"""
|
||||
_, fromSlash, reminder = isSlash(reminder)
|
||||
if len(reminder) > 0:
|
||||
reminder = " ".join(reminder)
|
||||
else:
|
||||
reminder = None
|
||||
|
||||
embed = discord.Embed(color = 0xC41B1B)
|
||||
extrarg = 0
|
||||
guildID = ctx.guild.id # can be set to 0 if its a DM message, so it can be see from anywhere
|
||||
destination = "dans ce salon"
|
||||
if not reminder:
|
||||
reminder = "Notification"
|
||||
if time == "help":
|
||||
seconds = 0
|
||||
else:
|
||||
if time.endswith("@"):
|
||||
time = time[:-1]
|
||||
extrarg = 1
|
||||
if time.lower().endswith("p"):
|
||||
time = time[:-1]
|
||||
extrarg = 2
|
||||
guildID = 0
|
||||
destination = "en MP"
|
||||
seconds = stringTempsVersSecondes(time)
|
||||
if type(seconds) != int:
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '❓')
|
||||
return await mySendHidden(ctx, fromSlash, seconds)
|
||||
if seconds == 0:
|
||||
embed.add_field(name="Informations", value=
|
||||
"Format pour le temps : `y` ou `a` pour année, `w` pour semaine, `d` ou `j` pour jour, \
|
||||
\n`h` pour heure, `m` pour minute, `s` pour seconde (légères variances acceptés aussi).\n \
|
||||
\nMet un `@` accolée aux temps pour mentionner les gens mentionner dans ton message. \
|
||||
\nMet un `P` accolée au temps pour que le bot te DM au lieu de t'envoyer un message dans ce salon."
|
||||
)
|
||||
elif seconds > (50 * (86400 * 365.242)): # 50 ans
|
||||
embed.add_field(name="Attention", value="Tu as spécifié une durée trop longue, la durée maximum étant de 50 ans.")
|
||||
else:
|
||||
now = int(nowUTC())
|
||||
messageID = None
|
||||
if fromSlash != True:
|
||||
messageID = ctx.message.id
|
||||
reminderID = Reminder().ajoutReminder(messageID, ctx.channel.id, extrarg, reminder, now, now + seconds, ctx.author.id, guildID)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await mySendHidden(ctx, fromSlash, f"Reminder **`#{reminderID[0][0]}`** enrengistré ! Notification {destination} dans {timedeltaToString(seconds)}{'' if seconds >= 3600 else ' (avec 1m de retard maximum)'}.")
|
||||
await mySendHidden(ctx, fromSlash, embed = embed)
|
||||
@_reminder.error
|
||||
async def _reminder_error(self, ctx, error):
|
||||
if 'time is a required argument that is missing.' in str(error):
|
||||
await ctx.send("Tu n'as pas spécifié de durée.")
|
||||
@cog_ext.cog_slash(name="reminder", description = "Met en place un rappel.")
|
||||
async def __reminder(self, ctx, time, reminder = None):
|
||||
if reminder == None:
|
||||
return await self._reminder(ctx, time, True)
|
||||
else:
|
||||
return await self._reminder(ctx, time, reminder, True)
|
||||
|
||||
@commands.command(name='reminderlist', aliases=["remindlist", "rl", "rappeliste"])
|
||||
async def _reminderlist(self, ctx, *arg):
|
||||
"""Affiche la liste des rappels d'un utilisateur.\n ➡ Syntaxe: {PREFIX}reminderlist/rl/remindlist/rappeliste [utilisateur]"""
|
||||
_, fromSlash, arg = isSlash(arg)
|
||||
utilisateur = ctx.author
|
||||
page = 1
|
||||
erreur = False
|
||||
if len(arg) > 0:
|
||||
for i in range(0, len(arg)):
|
||||
try:
|
||||
utilisateur = self.client.get_user(mentionToUser(getMentionInString(arg[i])[0]))
|
||||
except:
|
||||
try:
|
||||
page = int(arg[i])
|
||||
except:
|
||||
erreur = True
|
||||
if erreur == True:
|
||||
return await mySendHidden(ctx, fromSlash, "Veuillez renseigné un utilisateur ou un numéro de page valide.")
|
||||
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
|
||||
embed, pageMAX, refresh = await embedListe(utilisateur, ctx.guild.id, page)
|
||||
message = await ctx.send(embed = embed)
|
||||
if refresh:
|
||||
await message.add_reaction("🔄")
|
||||
elif pageMAX > 1:
|
||||
for emoji in ["⬅️", "➡️"]:
|
||||
await message.add_reaction(emoji)
|
||||
@cog_ext.cog_slash(name="reminderlist", description = "Affiche la liste des rappels d'un utilisateur.")
|
||||
async def __reminderlist(self, ctx, userorpage = None):
|
||||
if userorpage == None:
|
||||
return await self._reminderlist(ctx, True)
|
||||
else:
|
||||
return await self._reminderlist(ctx, userorpage, True)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_raw_reaction_add(self, payload):
|
||||
message, embed = await listReaction(self.client, payload)
|
||||
if message:
|
||||
await message.edit(embed = embed)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_raw_reaction_remove(self, payload):
|
||||
message, embed = await listReaction(self.client, payload)
|
||||
if message:
|
||||
await message.edit(embed = embed)
|
||||
|
||||
@commands.command(name='reminderdelete', aliases=["reminddelete", "rd"])
|
||||
async def _reminderdelete(self, ctx, *id):
|
||||
"""Suppprime un rappel.\n ➡ Syntaxe: {PREFIX}reminderdelete/rd <id>"""
|
||||
id, fromSlash, _ = isSlash(id)
|
||||
if id:
|
||||
try:
|
||||
id = int(id)
|
||||
except:
|
||||
return await mySendHidden(ctx, fromSlash, "L'ID renseigné n'est pas valide.")
|
||||
else:
|
||||
return await ctx.send("Veuillez renseigner un ID.")
|
||||
|
||||
verification = Reminder().appartenanceReminder(ctx.author.id, id, ctx.guild.id)
|
||||
if verification:
|
||||
Reminder().suppressionReminder(id)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await mySendHidden(ctx, fromSlash, f"Reminder **#{id}** supprimé !")
|
||||
else:
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
return await mySendHidden(ctx, fromSlash, "Rappel non trouvé, pas sur le bon serveur ou qui ne vous appartiens pas.")
|
||||
@cog_ext.cog_slash(name="reminderdelete", description = "Suppprime un rappel.")
|
||||
async def __reminderdelete(self, ctx, id):
|
||||
return await self._reminderdelete(ctx, id, True)
|
80
src/cogs/school.py
Normal file
80
src/cogs/school.py
Normal file
|
@ -0,0 +1,80 @@
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
from discord_slash import cog_ext
|
||||
from utils.core import isSlash, mySendHidden
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(School(client))
|
||||
|
||||
class School(commands.Cog):
|
||||
"""Commandes relatives aux cours."""
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
@commands.command(name='appel')
|
||||
# @commands.has_any_role("Professeur", "professeur", "Prof", "prof")
|
||||
async def _appel(self, ctx, *voice_channel: int):
|
||||
"""Fais l'appel.\n ➡ Syntaxe: {PREFIX}appel [ID salon vocal]"""
|
||||
voice_channel, fromSlash, _ = isSlash(voice_channel)
|
||||
|
||||
voice_channels = []
|
||||
voice_channels.extend(ctx.guild.voice_channels)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = "✅")
|
||||
limite_voice_channels = 7
|
||||
if len(voice_channels) > limite_voice_channels and not voice_channel:
|
||||
return await mySendHidden(ctx, fromSlash, f"""Désolé mais il y a plus de {limite_voice_channels} salons vocaux sur ce serveur, utilisez plutôt `{ctx.prefix}appel {{ID salon vocal}}`.
|
||||
\nPour savoir comment récuperer l'id d'un salon vous pouvez faire `{ctx.prefix}getid`.""")
|
||||
if voice_channel:
|
||||
canal = self.client.get_channel(voice_channel)
|
||||
if canal.type.__str__() == "voice":
|
||||
voice_channels = [canal]
|
||||
else:
|
||||
return await mySendHidden(ctx, fromSlash, "Tu as spécifié un channel textuelle et non vocal.")
|
||||
if len(voice_channels) > 0:
|
||||
embed = discord.Embed(title = "Réagissez à ce message avec ✋ pour signaler votre présence.", description = f"(attention, je réagis aussi) — Demandeur : {ctx.author.mention}")
|
||||
for channel in voice_channels:
|
||||
prof = []
|
||||
for role in ["Professeur", "professeur", "Prof", "prof"]:
|
||||
role = discord.utils.get(ctx.guild.roles, name=role)
|
||||
for user in channel.members:
|
||||
if role in user.roles and user not in prof:
|
||||
prof.append(user)
|
||||
eleve = channel.members
|
||||
for user in channel.members:
|
||||
if user in prof:
|
||||
eleve.remove(user)
|
||||
value = f"**{len(channel.members)}** personne{'s' if len(channel.members)>1 else ''} connectée{'s' if len(channel.members)>1 else ''}.\nDont {len(eleve)} élève{'s' if len(eleve)>1 else ''} et {len(prof)} professeur{'s' if len(prof)>1 else ''}."
|
||||
embed.add_field(name = f"🔊 {channel.name}", value = value, inline = False)
|
||||
message = await ctx.send(embed = embed)
|
||||
else:
|
||||
message = await ctx.send("Aucun salon vocal dans ce serveur, réagissez à ce message avec ✋ pour signaler votre présence (attention, je réagis aussi).")
|
||||
await message.add_reaction(emoji = "✋")
|
||||
@_appel.error
|
||||
async def _appel_error(self, ctx, _):
|
||||
# if isinstance(error, commands.CheckFailure):
|
||||
# await ctx.send("Tu n'as pas la permission de faire cette commande, demande à un professeur.")
|
||||
# else:
|
||||
await ctx.send(f"Une erreur est survenue, syntaxe: `{ctx.prefix}appel [ID salon vocal]`.")
|
||||
@cog_ext.cog_slash(name="appel", description = "Fais l'appel.")
|
||||
async def __appel(self, ctx, voice_channel_id = None):
|
||||
ctx.prefix = "/"
|
||||
if voice_channel_id == None:
|
||||
return await self._appel(ctx, True)
|
||||
else:
|
||||
try:
|
||||
return await self._appel(ctx, int(voice_channel_id), True)
|
||||
except:
|
||||
pass
|
||||
|
||||
@commands.command(name='getid', hidden = True)
|
||||
async def _getid(self, ctx, fromSlash = None):
|
||||
"""Tuto vidéo sur comment récupérer l'ID d'un utilisateur/salon"""
|
||||
if fromSlash != True:
|
||||
fromSlash = False
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await mySendHidden(ctx, fromSlash, "Explication sur comment récuperer l'ID d'un utilisateur/salon : https://cdn.discordapp.com/attachments/640312926892195842/780802253258358834/GetID.mp4")
|
||||
@cog_ext.cog_slash(name="getid", description = "Tuto vidéo sur comment récupérer l'ID d'un utilisateur/salon")
|
||||
async def __getid(self, ctx):
|
||||
return await self._getid(ctx, True)
|
|
@ -1,51 +1,81 @@
|
|||
import discord, pytz, time
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from random import randint, shuffle
|
||||
from datetime import datetime
|
||||
from pytz import timezone
|
||||
import re
|
||||
from re import findall
|
||||
from discord_slash import cog_ext
|
||||
from utils.core import map_list_among_us, cleanCodeStringWithMentionAndURLs, cleanUser, userOrNick
|
||||
from utils.core import mySendHidden, mentionToUser, getChangelogs, getActualVersion, isSlash, load, devOrStableChannel
|
||||
from utils.time import nowUTC, intToDatetime, timestampScreen, getAge, ageLayout, nowCustom
|
||||
|
||||
def setup(client):
|
||||
client.add_cog(Utils(client))
|
||||
|
||||
class Utils(commands.Cog):
|
||||
"""Commandes essentielles."""
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
self.customTimezone = load(["TIMEZONE"])["TIMEZONE"]
|
||||
|
||||
@commands.command(name='ping')
|
||||
async def _ping(self, ctx, *, question = '0'):
|
||||
"""Affiche mon ping.\n ➡ Syntaxe: .ping [help]"""
|
||||
if question == 'help':
|
||||
return await ctx.send(embed = discord.Embed(color = discord.Colour.random(), description = ":hourglass: correspond au temps entre deux battements de cœurs (en millisecondes)\n\n:stopwatch: correspond au temps que met le client a calculer le ping (en millisecondes)\n\n:heartbeat: correspond au temps que met le client a réagir au messages (en millisecondes)"))
|
||||
async def _ping(self, ctx, *arg):
|
||||
arg, fromSlash, _ = isSlash(arg)
|
||||
|
||||
if arg == 'help':
|
||||
return await mySendHidden(ctx, fromSlash, embed = discord.Embed(color = discord.Colour.random(), description =
|
||||
":hourglass: correspond au temps entre deux battements de cœurs\n\n \
|
||||
:heartbeat: correspond au temps que met le client a réagir au messages (0 est normal lors de l'utilisation d'une commande slash)\n\n \
|
||||
:stopwatch: correspond au temps que met le client a calculer le ping"
|
||||
))
|
||||
else:
|
||||
now = int(round(time.time() * 1000))
|
||||
ping = now - int(round(ctx.message.created_at.timestamp() * 1000))
|
||||
now = int(round(nowCustom() * 1000))
|
||||
if fromSlash != True:
|
||||
ping = now - int(round(ctx.message.created_at.timestamp() * 1000))
|
||||
else:
|
||||
ping = now - int(round(ctx.slash_created_at * 1000))
|
||||
embed = discord.Embed(description = 'Pinging...')
|
||||
message = await ctx.send(embed = embed)
|
||||
ping2 = int(round(time.time() * 1000)) - now
|
||||
await message.edit(embed = discord.Embed(color = discord.Colour.random(), description = f':hourglass: {round(self.client.latency * 1000)}ms\n\n:stopwatch: {ping2}ms\n\n:heartbeat: {ping}ms'))
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
ping2 = int(round(nowCustom() * 1000)) - now
|
||||
await message.edit(embed = discord.Embed(color = discord.Colour.random(), description = f':hourglass: {round(self.client.latency * 1000)} ms\n\n:heartbeat: {ping} ms\n\n:stopwatch: {ping2} ms'))
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
@cog_ext.cog_slash(name="ping", description = "Affiche mon ping, mettre 'help' en argument pour connaître à quoi correspond les données.")
|
||||
async def __ping(self, ctx, arg = None):
|
||||
ctx.slash_created_at = nowCustom()
|
||||
if arg == None:
|
||||
return await self._ping(ctx, True)
|
||||
else:
|
||||
return await self._ping(ctx, arg, True)
|
||||
|
||||
@commands.command(name='avatar')
|
||||
async def _avatar(self, ctx, *, user = '0'):
|
||||
"""Affiche ton avatar ou celui que tu mentionnes.\n ➡ Syntaxe: .avatar [user]"""
|
||||
if user == '0':
|
||||
async def _avatar(self, ctx, *user):
|
||||
"""Affiche ton avatar ou celui que tu mentionnes.\n ➡ Syntaxe: {PREFIX}avatar [user]"""
|
||||
user, fromSlash, _ = isSlash(user)
|
||||
|
||||
if user == None:
|
||||
user = ctx.author
|
||||
else:
|
||||
user = self.client.get_user(int(user[2:-1].replace("!","")))
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
user = self.client.get_user(mentionToUser(user))
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
embed = discord.Embed(description = f"[lien vers la photo de profil]({user.avatar_url}) de {user.mention}", color = discord.Colour.random())
|
||||
embed.set_author(name = f"Photo de profil de {user.name}")
|
||||
embed.set_image(url = user.avatar_url)
|
||||
await ctx.send(embed = embed)
|
||||
@cog_ext.cog_slash(name="avatar", description = "Affiche ton avatar ou celui que tu mentionnes.")
|
||||
async def __avatar(self, ctx, user = None):
|
||||
if user == None:
|
||||
return await self._avatar(ctx, True)
|
||||
else:
|
||||
return await self._avatar(ctx, user, True)
|
||||
|
||||
@commands.command(name='calc')
|
||||
async def _calc(self, ctx, *, msg):
|
||||
"""Calculatrice.\n ➡ Syntaxe: .calc <calcul>"""
|
||||
equation = msg.replace('^', '**').replace('x', '*').replace('×', '*').replace('÷', '/').replace('≥', '>=').replace('≤', '<=')
|
||||
async def _calc(self, ctx, *calcul):
|
||||
"""Calculatrice.\n ➡ Syntaxe: {PREFIX}calc <calcul>"""
|
||||
calcul, fromSlash, _ = isSlash(calcul)
|
||||
if calcul == None:
|
||||
raise ModuleNotFoundError
|
||||
|
||||
equation = calcul.replace('^', '**').replace('x', '*').replace('×', '*').replace('÷', '/').replace('≥', '>=').replace('≤', '<=')
|
||||
try:
|
||||
try:
|
||||
if '=' in equation:
|
||||
|
@ -64,9 +94,9 @@ class Utils(commands.Cog):
|
|||
else:
|
||||
answer = str(eval(equation))
|
||||
except ZeroDivisionError:
|
||||
return await ctx.send("Tu ne peux pas divisé par 0.")
|
||||
return await mySendHidden(ctx, fromSlash, "Tu ne peux pas diviser par 0.")
|
||||
except TypeError:
|
||||
return await ctx.send("Requête de calcul invalide.")
|
||||
return await mySendHidden(ctx, fromSlash, "Requête de calcul invalide.")
|
||||
if '.' in answer:
|
||||
aftercomma = answer.split(".")[1]
|
||||
if len(aftercomma) > 2:
|
||||
|
@ -74,86 +104,115 @@ class Utils(commands.Cog):
|
|||
equation = f"'{equation}' arrondi à 2"
|
||||
equation = equation.replace('*', '×').replace('/', '÷').replace('>=', '≥').replace('<=', '≤')
|
||||
embed = discord.Embed(color = discord.Colour.random(), title = 'Calculatrice')
|
||||
embed.set_footer(text = ctx.author)
|
||||
embed.set_footer(text = userOrNick(ctx.author), icon_url = ctx.author.avatar_url)
|
||||
|
||||
embed.add_field(name = 'Calcul :', value = equation, inline = False)
|
||||
embed.add_field(name = 'Réponse :', value = answer.replace('False', 'Faux').replace('True', 'Vrai'), inline = False)
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await ctx.send(content = None, embed = embed)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await ctx.send(embed = embed)
|
||||
@_calc.error
|
||||
async def _calc_error(self, ctx, error):
|
||||
async def _calc_error(self, ctx, _):
|
||||
await ctx.send("Tu n'as pas spécifié de calcul.")
|
||||
@cog_ext.cog_slash(name="calc", description = "Calculatrice.")
|
||||
async def __calc(self, ctx, calcul):
|
||||
return await self._calc(ctx, calcul, True)
|
||||
|
||||
@commands.command(name='syntax')
|
||||
async def _syntax(self, ctx):
|
||||
async def _syntax(self, ctx, fromSlash = None):
|
||||
"""Informations pour bien éditer son texte."""
|
||||
syntaxe = "-----------------------------------------------------\n"
|
||||
syntaxe += discord.utils.escape_markdown("```Js\n")
|
||||
if fromSlash != True:
|
||||
fromSlash = False
|
||||
separateur = "-----------------------------------------------------\n"
|
||||
syntaxe = separateur
|
||||
syntaxe += discord.utils.escape_markdown("```js\n")
|
||||
syntaxe += discord.utils.escape_markdown("//code en js (possible de remplacer 'js' par d'autres languages . adaptez le !)\n")
|
||||
syntaxe += discord.utils.escape_markdown('console.log("hi");\n')
|
||||
syntaxe += discord.utils.escape_markdown("```\n")
|
||||
syntaxe += "```Js\n"
|
||||
syntaxe += "```js\n"
|
||||
syntaxe += "//code en js (possible de remplacer 'js' par d'autres languages . adaptez le !)\n"
|
||||
syntaxe += 'console.log("hi");\n'
|
||||
syntaxe += "```\n"
|
||||
syntaxe += "Si ton code est trop long, mets le sur <https://pastebin.com/>\n"
|
||||
syntaxe += "-----------------------------------------------------\n"
|
||||
syntaxe += separateur
|
||||
syntaxe += discord.utils.escape_markdown("`code sur une seule ligne`\n")
|
||||
syntaxe += "`code sur une seule ligne`\n"
|
||||
syntaxe += "-----------------------------------------------------\n"
|
||||
syntaxe += separateur
|
||||
syntaxe += discord.utils.escape_markdown("*texte en italique*\n")
|
||||
syntaxe += "*texte en italique*\n"
|
||||
syntaxe += "-----------------------------------------------------\n"
|
||||
syntaxe += separateur
|
||||
syntaxe += discord.utils.escape_markdown("**text en gras**\n")
|
||||
syntaxe += "**text en gras**\n"
|
||||
syntaxe += "-----------------------------------------------------\n"
|
||||
syntaxe += separateur
|
||||
syntaxe += discord.utils.escape_markdown("<<https://www.youtube.com/watch?v=GhuYKL5NUYg>>\n")
|
||||
syntaxe += "Un lien entre crochet, ça empêche Discord de rajouté son intégration automatique (mais le lien fonctionnera toujours).\n"
|
||||
syntaxe += "-----------------------------------------------------\n"
|
||||
syntaxe += separateur
|
||||
syntaxe += discord.utils.escape_markdown("__texte souligné__\n")
|
||||
syntaxe += "__texte souligné__\n"
|
||||
syntaxe += "-----------------------------------------------------\n"
|
||||
syntaxe += separateur
|
||||
syntaxe += discord.utils.escape_markdown("~~texte barré~~\n")
|
||||
syntaxe += "~~texte barré~~\n"
|
||||
syntaxe += "-----------------------------------------------------\n"
|
||||
syntaxe += separateur
|
||||
syntaxe += discord.utils.escape_markdown("~~__***text en italique-gras-souligné-barré***__~~\n")
|
||||
syntaxe += "~~__***text en italique-gras-souligné-barré***__~~\n"
|
||||
syntaxe += "-----------------------------------------------------\n"
|
||||
syntaxe += separateur
|
||||
syntaxe += discord.utils.escape_markdown("\:joy: <- l'emoji ne va pas fonctionné grâce au \ \n")
|
||||
syntaxe += "\:joy: <- l'emoji ne va pas fonctionné grâce au \ \n"
|
||||
syntaxe += "-----------------------------------------------------\n"
|
||||
syntaxe += separateur
|
||||
syntaxe += discord.utils.escape_markdown("> cette ligne est cité\npas celle là\n")
|
||||
syntaxe += "> cette ligne est cité\npas celle là\n"
|
||||
syntaxe += "-----------------------------------------------------\n"
|
||||
syntaxe += separateur
|
||||
syntaxe += discord.utils.escape_markdown(">>> cette ligne est cité\ncelle là aussi (et elles le seront toutes!)\n")
|
||||
syntaxe += ">>> cette ligne est cité\ncelle là aussi (et elles le seront toutes!)\n"
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await ctx.send(syntaxe)
|
||||
try:
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
except:
|
||||
pass
|
||||
await mySendHidden(ctx, fromSlash, syntaxe)
|
||||
@cog_ext.cog_slash(name="syntax", description = "Informations pour bien éditer son texte.")
|
||||
async def __syntax(self, ctx):
|
||||
return await self._syntax(ctx, True)
|
||||
|
||||
@commands.command(name='memo', aliases = ['note'])
|
||||
async def _memo(self, ctx, *, text):
|
||||
"""T'envoie un petit memo par message privé.\n ➡ Syntaxe: .memo/note <message>"""
|
||||
if len(text) <= 5:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
return await ctx.send("Ta note doit au moins faire 5 caractères.")
|
||||
elif len(text) >= 2048:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
return await ctx.send("Ta note doit faire moins de 2048 caractères.")
|
||||
async def _memo(self, ctx, *text):
|
||||
"""T'envoie un petit memo par message privé.\n ➡ Syntaxe: {PREFIX}memo/note <message>"""
|
||||
_, fromSlash, text = isSlash(text)
|
||||
if len(text) > 0:
|
||||
text = " ".join(text)
|
||||
else:
|
||||
await ctx.message.delete()
|
||||
raise ModuleNotFoundError
|
||||
|
||||
if len(text) <= 5:
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
return await mySendHidden(ctx, fromSlash, "Ta note doit au moins faire 5 caractères.")
|
||||
elif len(text) >= 2048:
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
return await ctx.send(ctx, fromSlash, "Ta note doit faire moins de 2048 caractères.")
|
||||
else:
|
||||
if fromSlash != True:
|
||||
await ctx.message.delete()
|
||||
embed = discord.Embed(description = text, color = discord.Colour.random())
|
||||
embed.set_author(name = f"Mémo noté depuis {ctx.guild.name}", icon_url = ctx.author.avatar_url)
|
||||
embed.set_footer(text = f'📝 le {datetime.now(pytz.timezone("Europe/Paris")).strftime("%d/%m/%Y à %H:%M:%S")}')
|
||||
embed.set_footer(text = f'📝 le {timestampScreen(intToDatetime(nowUTC()))}')
|
||||
await ctx.author.send(embed = embed)
|
||||
return await ctx.send("Tu viens de recevoir ton mémo !", delete_after = 5)
|
||||
|
||||
return await mySendHidden(ctx, fromSlash, "Tu viens de recevoir ton mémo !", delete_after = 5)
|
||||
@_memo.error
|
||||
async def _note_error(self, ctx, error):
|
||||
async def _memo_error(self, ctx, error):
|
||||
if str(error) == "text is a required argument that is missing.":
|
||||
await ctx.send("Vous devez renseigner un message : `.note/memo <message>`.")
|
||||
await ctx.send(f"Vous devez renseigner un message : `{ctx.prefix}memo/note <message>`.")
|
||||
@cog_ext.cog_slash(name="note", description = "T'envoie un petit memo par message privé.")
|
||||
async def __memo(self, ctx, memo):
|
||||
return await self._memo(ctx, memo, True)
|
||||
|
||||
@commands.command(name='infos', aliases = ['info'])
|
||||
async def _infos(self, ctx):
|
||||
"""Donne des infos sur le bot.\n ➡ Syntaxe: .infos/info"""
|
||||
async def _infos(self, ctx, fromSlash = None):
|
||||
"""Donne des infos sur le bot.\n ➡ Syntaxe: {PREFIX}infos/info"""
|
||||
if fromSlash != True:
|
||||
fromSlash = False
|
||||
appinfo = await self.client.application_info()
|
||||
|
||||
embed = discord.Embed(color = discord.Colour.random())
|
||||
|
@ -171,71 +230,101 @@ class Utils(commands.Cog):
|
|||
|
||||
text = len(text_channels)
|
||||
voice = len(voice_channels)
|
||||
nombreServeur = len(self.client.guilds)
|
||||
|
||||
version = getActualVersion()
|
||||
|
||||
embed.add_field(name = "Dev", value = f"[{appinfo.owner}](https://github.com/Mylloon)")
|
||||
embed.add_field(name = "Serveurs", value = len(self.client.guilds))
|
||||
embed.add_field(name = "Membres", value = f"{total_unique} au total\n{total_online} en ligne")
|
||||
embed.add_field(name = "Channels", value = f"{text} textuelles\n{voice} vocales")
|
||||
dev = self.client.get_user(158260864623968257)
|
||||
|
||||
devOrMain = devOrStableChannel()
|
||||
|
||||
embed.add_field(name = "Dev", value = f"[{dev}](https://discord.gg/Z5ePxH4)")
|
||||
embed.add_field(name = "Hébergeur", value = appinfo.owner.mention)
|
||||
embed.add_field(name = f"Serveur{'s' if nombreServeur > 1 else ''}", value = f"`{nombreServeur}`")
|
||||
embed.add_field(name = f"Membre{'s' if total_unique > 1 else ''}", value = f"`{total_unique}` au total\n`{total_online}` en ligne")
|
||||
embed.add_field(name = f"Salon{'s' if (text + voice) > 1 else ''}", value = f"`{text}` textuel{'s' if text > 1 else ''}\n`{voice}` voca{'ux' if voice > 1 else 'l'}")
|
||||
embed.add_field(name = "Prefix", value = f"`{ctx.prefix}`")
|
||||
embed.add_field(name = "Code source", value = f"[Lien Gitlab](https://gitlab.com/ConfrerieDuKassoulait/KassouBot/-/tree/{devOrMain})")
|
||||
embed.add_field(name = "Timezone", value = f"`{self.customTimezone}`")
|
||||
changes = getChangelogs(version)
|
||||
version = f"`{version}`"
|
||||
if changes[0] == 200:
|
||||
version = f"[{version}]({changes[1]})"
|
||||
embed.add_field(name = "Version", value = f"{version} ({devOrMain.replace('main', 'stable')})")
|
||||
embed.set_footer(text = f"Basé sur discord.py {discord.__version__}")
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
try:
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
except:
|
||||
pass
|
||||
await ctx.send(embed = embed)
|
||||
@cog_ext.cog_slash(name="infos", description = "Donne des infos sur le bot.")
|
||||
async def __infos(self, ctx):
|
||||
ctx.prefix = "/"
|
||||
return await self._infos(ctx, True)
|
||||
|
||||
def _map_list_among_us(self, map):
|
||||
maps = {}
|
||||
maps["skeld"] = ["skeld", "the skeld", "theskeld"]
|
||||
maps["mira"] = ["mira", "mira hq", "mirahq"]
|
||||
maps["polus"] = ["polus"]
|
||||
maps["airship"] = ["airship", "air ship"]
|
||||
if map == "all":
|
||||
return maps["skeld"] + maps["mira"] + maps["polus"] + maps["airship"]
|
||||
return maps[map]
|
||||
|
||||
@commands.command(name='amongus')
|
||||
async def _amongus(self, ctx, *map):
|
||||
"""Affiche la carte voulue d'Among Us.\n ➡ Syntaxe: {PREFIX}amongus <mira/polus/skeld/airship>"""
|
||||
_, fromSlash, map = isSlash(map)
|
||||
if len(map) > 0:
|
||||
map = " ".join(map)
|
||||
else:
|
||||
map = "0"
|
||||
|
||||
if map.lower() in map_list_among_us("mira"):
|
||||
image = "https://i.imgur.com/6ijrH1h.jpg"
|
||||
embed = discord.Embed(title = f"Map Mira HQ d'Among Us", color = discord.Colour.random(), description = f"[lien de l'image]({image})")
|
||||
embed.set_image(url = image)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await ctx.send(embed = embed)
|
||||
elif map.lower() in map_list_among_us("polus"):
|
||||
image = "https://i.imgur.com/mhFmcw3.jpg"
|
||||
embed = discord.Embed(title = f"Map Polus d'Among Us", color = discord.Colour.random(), description = f"[lien de l'image]({image})")
|
||||
embed.set_image(url = image)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await ctx.send(embed = embed)
|
||||
elif map.lower() in map_list_among_us("skeld"):
|
||||
image = "https://i.imgur.com/OSXI4Zv.jpg"
|
||||
embed = discord.Embed(title = f"Map The Skeld d'Among Us", color = discord.Colour.random(), description = f"[lien de l'image]({image})")
|
||||
embed.set_image(url = image)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await ctx.send(embed = embed)
|
||||
elif map.lower() in map_list_among_us("airship"):
|
||||
image = "https://i.imgur.com/cm8Wogw.png"
|
||||
embed = discord.Embed(title = f"Map Airship d'Among Us", color = discord.Colour.random(), description = f"[lien de l'image]({image})")
|
||||
embed.set_image(url = image)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
await ctx.send(embed = embed)
|
||||
else:
|
||||
await mySendHidden(ctx, fromSlash, f"`{ctx.prefix}amongus <mira/polus/skeld/airship>`")
|
||||
@commands.command(name='among', hidden = True)
|
||||
async def _among(self, ctx, *, args = ""):
|
||||
"""Raccourci à la commande amongus"""
|
||||
if not args == "":
|
||||
args = args.split()
|
||||
del args[0]
|
||||
args = " ".join(args)
|
||||
if args.lower() in self._map_list_among_us("all"):
|
||||
if args.lower() in map_list_among_us("all"):
|
||||
await ctx.invoke(self.client.get_command("amongus"), map=args)
|
||||
else:
|
||||
await ctx.invoke(self.client.get_command("amongus"))
|
||||
else:
|
||||
await ctx.message.add_reaction(emoji = '❓')
|
||||
|
||||
@commands.command(name='amongus')
|
||||
async def _amongus(self, ctx, *, map = "0"):
|
||||
"""Affiche la carte voulue d'Among Us.\n ➡ Syntaxe: .amongus <carte>"""
|
||||
if map.lower() in self._map_list_among_us("mira"):
|
||||
image = "https://i.imgur.com/6ijrH1h.jpg"
|
||||
embed = discord.Embed(title = f"Map Mira HQ d'Among Us", color = discord.Colour.random(), description = f"[lien de l'image]({image})")
|
||||
embed.set_image(url = image)
|
||||
await ctx.send(embed = embed)
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
elif map.lower() in self._map_list_among_us("polus"):
|
||||
image = "https://i.imgur.com/mhFmcw3.jpg"
|
||||
embed = discord.Embed(title = f"Map Polus d'Among Us", color = discord.Colour.random(), description = f"[lien de l'image]({image})")
|
||||
embed.set_image(url = image)
|
||||
await ctx.send(embed = embed)
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
elif map.lower() in self._map_list_among_us("skeld"):
|
||||
image = "https://i.imgur.com/OSXI4Zv.jpg"
|
||||
embed = discord.Embed(title = f"Map The Skeld d'Among Us", color = discord.Colour.random(), description = f"[lien de l'image]({image})")
|
||||
embed.set_image(url = image)
|
||||
await ctx.send(embed = embed)
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
elif map.lower() in self._map_list_among_us("airship"):
|
||||
image = "https://i.imgur.com/CYbPlQ6.png"
|
||||
embed = discord.Embed(title = f"Map Airship d'Among Us", color = discord.Colour.random(), description = f"[lien de l'image]({image})")
|
||||
embed.set_image(url = image)
|
||||
await ctx.send(embed = embed)
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
else:
|
||||
await ctx.send("`.amongus <mira/polus/skeld/airship>`")
|
||||
@cog_ext.cog_slash(name="amongus", description = "Affiche la carte voulue d'Among Us. Carte dispo : <mira/polus/skeld/airship>")
|
||||
async def __amongus(self, ctx, map):
|
||||
ctx.prefix = "/"
|
||||
return await self._amongus(ctx, map, True)
|
||||
|
||||
@commands.command(name='whois')
|
||||
async def _whois(self, ctx, *user: discord.Member):
|
||||
"""Affiche les infos sur l'utilisateur.\n ➡ Syntaxe: .whois [user]"""
|
||||
"""Affiche les infos sur l'utilisateur.\n ➡ Syntaxe: {PREFIX}whois [user]"""
|
||||
_, fromSlash, user = isSlash(user)
|
||||
|
||||
if len(user) <= 1:
|
||||
if user == ():
|
||||
user = [ctx.author]
|
||||
|
@ -246,64 +335,39 @@ class Utils(commands.Cog):
|
|||
|
||||
embed.add_field(name = "ID", value = user[0].id)
|
||||
|
||||
value = str(user[0].created_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').split()
|
||||
embed.add_field(name = "Compte créé le", value = f"{value[0][8:]}/{value[0][5:-3]}/{value[0][:4]} à {value[1]}")
|
||||
embed.add_field(name = "Compte créé le", value = timestampScreen(user[0].created_at))
|
||||
|
||||
embed.add_field(name = "Âge du compte", value = self._age_layout(self._get_age(user[0].created_at)))
|
||||
embed.add_field(name = "Âge du compte", value = ageLayout(getAge(user[0].created_at)))
|
||||
|
||||
embed.add_field(name = "Mention", value = user[0].mention)
|
||||
|
||||
value = str(user[0].joined_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').split()
|
||||
embed.add_field(name = "Serveur rejoint le", value = f"{value[0][8:]}/{value[0][5:-3]}/{value[0][:4]} à {value[1]}")
|
||||
embed.add_field(name = "Serveur rejoint le", value = timestampScreen(user[0].joined_at))
|
||||
|
||||
embed.add_field(name = "Est sur le serveur depuis", value = self._age_layout(self._get_age(user[0].joined_at)))
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
embed.add_field(name = "Est sur le serveur depuis", value = ageLayout(getAge(user[0].joined_at)))
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send(embed = embed)
|
||||
await ctx.send("Tu mentionnes trop d'utilisateurs : `.whois [@Membre]`")
|
||||
def _get_age(self, date):
|
||||
joursRestants = datetime.now() - date
|
||||
years = joursRestants.total_seconds() / (365.242 * 24 * 3600)
|
||||
months = (years - int(years)) * 12
|
||||
days = (months - int(months)) * (365.242 / 12)
|
||||
hours = (days - int(days)) * 24
|
||||
minutes = (hours - int(hours)) * 60
|
||||
seconds = (minutes - int(minutes)) * 60
|
||||
return (int(years), int(months), int(days), int(hours), int(minutes), int(seconds))
|
||||
def _age_layout(self, tuple):
|
||||
time = {}
|
||||
time[0], time[1], time[2], time[3], time[4], time[5] = "an", "mois", "jour", "heure", "minute", "seconde"
|
||||
for i in range(len(tuple)):
|
||||
if tuple[i] > 1 and i != 1:
|
||||
time[i] = time[i] + "s"
|
||||
message = ""
|
||||
if tuple[5] > 0: # pour les secondes
|
||||
affichage = [5] # on affiche que : seconde
|
||||
if tuple[4] > 0:
|
||||
affichage = [4, 5] # on affiche : minute + seconde
|
||||
if tuple[3] > 0:
|
||||
affichage = [3, 4, 5] # on affiche : heure + minute + seconde
|
||||
if tuple[2] > 0:
|
||||
affichage = [2, 3, 4] # on affiche : jour + heure + minute
|
||||
if tuple[1] > 0:
|
||||
affichage = [1, 2, 3] # on affiche : mois + jour + heure
|
||||
if tuple[0] > 0:
|
||||
affichage = [0, 1, 3] # on affiche : an + mois + heure
|
||||
for i in affichage:
|
||||
message = message + f", {tuple[i]} {time[i]}"
|
||||
return message[2:]
|
||||
return await ctx.send(f"Tu mentionnes trop d'utilisateurs : `{ctx.prefix}whois [@membre]`")
|
||||
@cog_ext.cog_slash(name="whois", description = "Affiche les infos sur l'utilisateur.")
|
||||
async def __whois(self, ctx, user: discord.Member = None):
|
||||
ctx.prefix = "/" # pas sûr que ce soit utile
|
||||
if user == None:
|
||||
return await self._whois(ctx, True)
|
||||
else:
|
||||
return await self._whois(ctx, user, True)
|
||||
|
||||
@commands.command(name='sondage')
|
||||
async def _sondage(self, ctx, *args):
|
||||
"""Fais un sondage.\n ➡ Syntaxe: .sondage "<Question>" "<Proposition1>" "<Proposition...>" "<Proposition20>" """
|
||||
"""Fais un sondage.\n ➡ Syntaxe: {PREFIX}sondage "<Question>" "<Proposition1>" "<Proposition...>" "<Proposition20>" """
|
||||
_, fromSlash, args = isSlash(args)
|
||||
if type(args[0]) == list:
|
||||
args = args[0]
|
||||
|
||||
args = list(args)
|
||||
if len(args) > 2:
|
||||
question = args[0].replace("<@!", "").replace(">", "").replace("<@", "")
|
||||
for i in re.findall(r'\d+', question):
|
||||
ii = self.user_or_nick(ctx.author.guild.get_member(int(i)))
|
||||
try:
|
||||
question = question.replace(i, ii)
|
||||
except:
|
||||
pass
|
||||
question = args[0]
|
||||
for i in findall(r'\d+', question):
|
||||
question = cleanUser(ctx, question, i)
|
||||
propositions = args[1:]
|
||||
if len(propositions) <= 20:
|
||||
message = ""
|
||||
|
@ -327,17 +391,103 @@ class Utils(commands.Cog):
|
|||
shuffle(emojis_chosen)
|
||||
for i in range(len(args[1:])):
|
||||
message += f"{emojis_chosen[i]} -> {propositions[i]}\n"
|
||||
embed = discord.Embed(title = question, description = message,color = discord.Colour.random()).set_footer(text = self.user_or_nick(ctx.author), icon_url = ctx.author.avatar_url)
|
||||
embed = discord.Embed(title = question, description = message, color = discord.Colour.random()).set_footer(text = f"Sondage de {userOrNick(ctx.author)}", icon_url = ctx.author.avatar_url)
|
||||
sondage = await ctx.send(embed = embed)
|
||||
for i in range(len(args[1:])):
|
||||
await sondage.add_reaction(emoji = emojis_chosen[i])
|
||||
return await ctx.message.add_reaction(emoji = '✅')
|
||||
if fromSlash != True:
|
||||
return await ctx.message.add_reaction(emoji = '✅')
|
||||
else:
|
||||
return await ctx.send(f"Désolé, mais tu as mis trop de possibilités (maximum : 20)")
|
||||
else:
|
||||
return await ctx.send(f'Désolé, mais il manque des arguments : `.sondage "<Question>" "<Proposition1>" "<Proposition...>" "<Proposition20>"`')
|
||||
def user_or_nick(self, user):
|
||||
if user.nick:
|
||||
return f"{user.nick} ({user.name}#{user.discriminator})"
|
||||
return await ctx.send(f'Désolé, mais il manque des arguments : `{ctx.prefix}sondage "<Question>" "<Proposition1>" "<Proposition...>" "<Proposition20>"`')
|
||||
@cog_ext.cog_slash(name="sondage", description = "Fais un sondage.")
|
||||
async def __sondage(self, ctx, question, prop1, prop2, prop3 = None, prop4 = None,
|
||||
prop5 = None, prop6 = None, prop7 = None, prop8 = None, prop9 = None, prop10 = None,
|
||||
prop11 = None, prop12 = None, prop13 = None, prop14 = None, prop15 = None, prop16 = None,
|
||||
prop17 = None, prop18 = None, prop19 = None, prop20 = None):
|
||||
ctx.prefix = "/"
|
||||
args = [question, prop1, prop2, prop3, prop4, prop5, prop6, prop7, prop8,
|
||||
prop9, prop10, prop11, prop12, prop13, prop14, prop15, prop16,
|
||||
prop17, prop18, prop19, prop20]
|
||||
for i in range(3, 20): # suppression des None
|
||||
if args[i] == None:
|
||||
args = args[:i]
|
||||
break
|
||||
return await self._sondage(ctx, args, True)
|
||||
|
||||
@commands.command(name='avis', aliases=['vote'])
|
||||
async def _avis(self, ctx, *args):
|
||||
"""Demande un avis.\n ➡ Syntaxe: {PREFIX}avis/vote "[Titre]" "<Demande>" """
|
||||
_, fromSlash, args = isSlash(args)
|
||||
if type(args[0]) == list:
|
||||
args = args[0]
|
||||
|
||||
args = list(args)
|
||||
if len(args) > 2 or len(args) == 0:
|
||||
return await ctx.send("Désolé, la syntaxe est mauvaise.")
|
||||
else:
|
||||
return f"{user.name}#{user.discriminator}"
|
||||
if len(args) == 1: # si aucun titre défini
|
||||
titre = "Nouveau vote"
|
||||
else: # si titre défini
|
||||
titre = args[0]
|
||||
for findedId in findall(r'\d+', titre): # récupération mention dans titre
|
||||
titre = cleanUser(ctx, titre, findedId)
|
||||
args = args[1:]
|
||||
embed = discord.Embed(title = titre, description = cleanCodeStringWithMentionAndURLs(args[0]), color = discord.Colour.random()).set_footer(text = f"Sondage de {userOrNick(ctx.author)}", icon_url = ctx.author.avatar_url)
|
||||
message = await ctx.send(embed = embed)
|
||||
reactions = ['✅', '🤷', '❌']
|
||||
for i in reactions:
|
||||
await message.add_reaction(emoji = i)
|
||||
if fromSlash != True:
|
||||
return await ctx.message.delete()
|
||||
@cog_ext.cog_slash(name="avis", description = "Demande un avis, si 2 arguments, alors l'argument 1 est le titre, sinon c'est la demande.")
|
||||
async def __avis(self, ctx, titreoudemande, demande = None):
|
||||
args = [titreoudemande, demande]
|
||||
if args[1] == None:
|
||||
args = args[:1]
|
||||
return await self._avis(ctx, args, True)
|
||||
|
||||
@commands.command(name='changelogs', aliases=["changelog", "changement", "changements"])
|
||||
async def _changelogs(self, ctx, *version):
|
||||
"""Affiche les changements de la dernière version ou d'une version précise.\n ➡ Syntaxe: {PREFIX}changelogs/changelog/changement/changements [version]"""
|
||||
version, fromSlash, _ = isSlash(version)
|
||||
if not version:
|
||||
version = 'actual'
|
||||
changes = getChangelogs(version.replace(',', '.'))
|
||||
if changes[0] != 200:
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '❌')
|
||||
if changes[0] == 404:
|
||||
message = "Veuillez renseigner un numéro de version valide et existant. Peut-être que vous utilisez une version de développement."
|
||||
elif changes[0] == 429:
|
||||
message = "Trop de requêtes sur l'API de Gitlab, réessayez plus tard."
|
||||
else:
|
||||
message = f"Erreur API inconnue ({changes[0]})."
|
||||
return await mySendHidden(ctx, fromSlash, message)
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
changements = changes[3].replace("## ", "◦ ").replace("# ", "• ")
|
||||
if len(changements) > 2048:
|
||||
changements = f"{changements[:1900]}..."
|
||||
embed = discord.Embed(description = f"[lien vers la page Gitlab]({changes[1]})\n\n{changements}", color = discord.Colour.random())
|
||||
embed.set_author(name = f"Changements de la v{changes[2]}")
|
||||
await ctx.send(embed = embed)
|
||||
@cog_ext.cog_slash(name="changelogs", description = "Affiche les changements de la dernière version ou d'une version précise.")
|
||||
async def __changelogs(self, ctx, version = None):
|
||||
if version == None:
|
||||
return await self._changelogs(ctx, True)
|
||||
else:
|
||||
return await self._changelogs(ctx, version, True)
|
||||
|
||||
@commands.command(name='minecraft', aliases=["codecouleurminecraft", "minecraftcodecouleur"])
|
||||
async def _minecraft(self, ctx, fromSlash = None):
|
||||
"""Affiche le code couleur utilisé dans Minecraft.\n ➡ Syntaxe: {PREFIX}minecraft/codecouleurminecraft/minecraftcodecouleur"""
|
||||
if fromSlash != True:
|
||||
fromSlash = False
|
||||
if fromSlash != True:
|
||||
await ctx.message.add_reaction(emoji = '✅')
|
||||
return await ctx.send("https://imgr.search.brave.com/5-k6Lgh0OyRI8IVwhiBrNRmlY94utGxSX0k9tvtpqiA/fit/590/150/no/1/aHR0cDovL2kuaW1n/dXIuY29tL3Azd2lz/OVAucG5n")
|
||||
@cog_ext.cog_slash(name="minecraft", description = "Affiche le code couleur utilisé dans Minecraft.")
|
||||
async def __minecraft(self, ctx):
|
||||
return await self._minecraft(ctx, True)
|
||||
|
|
0
src/db/.gitkeep
Normal file
0
src/db/.gitkeep
Normal file
226
src/main.py
226
src/main.py
|
@ -1,214 +1,68 @@
|
|||
print("Connexion à Discord...")
|
||||
print("Chargement des extensions & librairie...", end = " ")
|
||||
|
||||
import discord, re, pytz, os
|
||||
import discord
|
||||
from os import listdir, rename, getcwd
|
||||
from discord_slash import SlashCommand
|
||||
from discord.ext import commands
|
||||
from random import choice
|
||||
from datetime import datetime
|
||||
from pytz import timezone
|
||||
from utils.reminder import Reminder
|
||||
from utils.core import load
|
||||
keys = load(["PREFIX", "TOKEN_DISCORD", "DEACTIVATE"])
|
||||
customPrefix = keys["PREFIX"]
|
||||
|
||||
client = commands.Bot(command_prefix = ".", case_insensitive = True, intents = discord.Intents.all())
|
||||
client = commands.Bot(command_prefix = customPrefix, case_insensitive = True, intents = discord.Intents.all())
|
||||
slash = SlashCommand(client, sync_commands = True)
|
||||
|
||||
print("Chargement des extensions & librairie...")
|
||||
client.load_extension("cogs.help")
|
||||
client.load_extension("cogs.utils")
|
||||
client.load_extension("cogs.internet")
|
||||
client.load_extension("cogs.music")
|
||||
client.load_extension("cogs.games")
|
||||
client.load_extension("cogs.fun")
|
||||
client.load_extension("cogs.autopublish")
|
||||
if keys["DEACTIVATE"] != "None":
|
||||
path = getcwd()
|
||||
for file in keys["DEACTIVATE"]:
|
||||
try:
|
||||
rename(f"{path}/cogs/{file}.py", f"{path}/cogs/-{file}.py") # désactivation
|
||||
except:
|
||||
print(f"No file {file} found, check your \"DEACTIVATE\" variable.")
|
||||
exit(1)
|
||||
|
||||
for file in listdir("cogs"):
|
||||
if file.endswith(".py") and file.startswith("-") == False:
|
||||
client.load_extension(f"cogs.{file[:-3]}")
|
||||
print("Terminé !")
|
||||
|
||||
@client.event
|
||||
async def on_connect():
|
||||
print(f"Connecté.")
|
||||
print(f"Connecté !")
|
||||
|
||||
@client.event
|
||||
async def on_disconnect():
|
||||
print(f"Déconnecté.")
|
||||
|
||||
@client.event
|
||||
async def on_resumed():
|
||||
print(f"Reconnecté !")
|
||||
|
||||
@client.event
|
||||
async def on_ready():
|
||||
await client.change_presence(status = discord.Status.online, activity = discord.Activity(name = ".help", type = discord.ActivityType.playing))
|
||||
await client.change_presence(status = discord.Status.online, activity = discord.Activity(name = f"{customPrefix}help", type = discord.ActivityType.playing))
|
||||
Reminder().creationTable()
|
||||
print("Bot prêt.")
|
||||
channel = client.get_channel(742564480050790512)
|
||||
await channel.send("Le bot a bien démarré.")
|
||||
|
||||
@client.event
|
||||
async def on_member_join(member):
|
||||
if member.guild.id == 441208120644075520: # Confrérie du Kassoulait
|
||||
if member.bot == True:
|
||||
role = discord.utils.get(member.guild.roles, name = "Bot")
|
||||
else:
|
||||
role = discord.utils.get(member.guild.roles, name = "Copain")
|
||||
await member.add_roles(role)
|
||||
try:
|
||||
await member.send(f"Coucou **{member.name}** sur {member.guild.name} ! 🥰\n\nTu as le rôle **{role}** 💖!")
|
||||
except:
|
||||
pass
|
||||
channel = client.get_channel(741639570172674120) # salons des arrivées
|
||||
switch = [
|
||||
f"Bienvenue, {member.mention}. On espère que tu as apporté de la pizza.",
|
||||
f"C'est un plaisir de te voir, {member.mention}.",
|
||||
f"{member.mention} vient juste d'arriver !",
|
||||
f"{member.mention} vient juste d'atterrir.",
|
||||
f"{member.mention} vient de se glisser dans le serveur.",
|
||||
f"{member.mention} a bondi dans le serveur.",
|
||||
f"Contents de te voir, {member.mention}.",
|
||||
f"{member.mention} est arrivé(e).",
|
||||
f"Tout le monde, accueillez comme il se doit {member.mention} !",
|
||||
f"Youhou, tu as réussi, {member.mention} !",
|
||||
f"{member.mention} a rejoint le groupe."
|
||||
]
|
||||
message = await channel.send("...") # évite d'envoyer une notification
|
||||
await message.edit(content = choice(switch))
|
||||
|
||||
@client.event
|
||||
async def on_member_remove(member):
|
||||
if member.guild.id == 441208120644075520: # Confrérie du Kassoulait
|
||||
channel = client.get_channel(741639570172674120) # salons des arrivées
|
||||
await channel.send(f"{member.mention} vient de quitter le serveur.")
|
||||
|
||||
@client.event
|
||||
async def on_raw_reaction_add(payload):
|
||||
if payload.message_id == 644922358745792512: # Règles de la Confrérie du Kassoulait
|
||||
if payload.emoji.name == '✅':
|
||||
role = discord.utils.get(payload.member.guild.roles, name="règles-acceptés")
|
||||
await payload.member.add_roles(role)
|
||||
|
||||
@client.event
|
||||
async def on_raw_reaction_remove(payload):
|
||||
if payload.message_id == 644922358745792512: # Règles de la Confrérie du Kassoulait
|
||||
if payload.emoji.name == '✅':
|
||||
guild = discord.utils.find(lambda g : g.id == payload.guild_id, client.guilds)
|
||||
member = discord.utils.find(lambda m: m.id == payload.user_id, guild.members)
|
||||
role = discord.utils.get(guild.roles, name="règles-acceptés")
|
||||
await member.remove_roles(role)
|
||||
|
||||
@client.event
|
||||
async def on_command_error(ctx, error):
|
||||
if not ctx.invoked_with.startswith('.'):
|
||||
if not ctx.invoked_with.startswith(customPrefix):
|
||||
print(error)
|
||||
await ctx.message.add_reaction(emoji = '❓')
|
||||
if ctx.message:
|
||||
await ctx.message.add_reaction(emoji = '❓')
|
||||
|
||||
@client.event
|
||||
async def on_message(message):
|
||||
await client.process_commands(message)
|
||||
|
||||
|
||||
if message.author == client.user:
|
||||
return
|
||||
|
||||
"""informations concernant le bot lorsqu'il est mentionner"""
|
||||
if client.user.mention == message.content.replace("!",""):
|
||||
ctx = await client.get_context(message)
|
||||
prefix = await client.get_prefix(message)
|
||||
await ctx.send(f">>> Coucou !\nMon préfix est `{prefix}` et ma commande d'aide est `{prefix}help`")
|
||||
|
||||
urls = re.findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', message.content)
|
||||
for i in range(len(urls)):
|
||||
if urls[i].startswith("https://discordapp.com/channels/") or urls[i].startswith("https://discord.com/channels/") or urls[i].startswith("https://ptb.discordapp.com/"):
|
||||
link = urls[i]
|
||||
linkURL = link
|
||||
if link.startswith("https://discord.com/channels/"):
|
||||
link = f'000{link}'
|
||||
if link.startswith("https://ptb.discordapp.com/"):
|
||||
link = link[4:]
|
||||
if "@me" in urls[i]:
|
||||
return await message.channel.send("Je ne cite pas les messages privés.", delete_after = 5)
|
||||
try:
|
||||
if int(link[32:-38]) == message.guild.id:
|
||||
msgID = await client.get_channel(int(link[51:-19])).fetch_message(int(link[70:]))
|
||||
couleur = 0x2f3136
|
||||
msgFiles = msgID.attachments
|
||||
imageExtensions = ["jpg", "jpeg", "png", "webp", "gif"]
|
||||
desc = msgID.content
|
||||
if len(msgFiles) > 1:
|
||||
listOfFiles = ""
|
||||
for i in range(0, len(msgFiles)):
|
||||
listOfFiles = f"{listOfFiles}, {msgFiles[i].filename}"
|
||||
listOfFiles = listOfFiles[2:]
|
||||
if len(msgID.content) > 0:
|
||||
desc = f"{msgID.content}\n\nIl y a plusieurs fichiers dans ce message : {listOfFiles}"
|
||||
else:
|
||||
desc = f"Il y a plusieurs fichiers dans ce message : {listOfFiles}"
|
||||
else:
|
||||
if len(msgFiles) == 1:
|
||||
if msgFiles[0].filename[-4:].split('.')[1] in imageExtensions:
|
||||
if not len(msgID.content) > 0:
|
||||
desc = f"Une image jointe : {msgFiles[0].filename}"
|
||||
else:
|
||||
linkFile = msgFiles[0].url
|
||||
if not len(msgID.content) > 0:
|
||||
desc = f"Un fichier joint : {msgFiles[0].filename}"
|
||||
embed = discord.Embed(description = desc, colour = couleur)
|
||||
auteur = "Auteur"
|
||||
if message.author == msgID.author:
|
||||
auteur = "Auteur & Citateur"
|
||||
embed.add_field(name = auteur, value = msgID.author.mention, inline=True)
|
||||
try:
|
||||
if len(msgFiles) == 1:
|
||||
if msgFiles[0].filename[-4:].split('.')[1] in imageExtensions:
|
||||
embed.set_image(url=msgFiles[0].url)
|
||||
else:
|
||||
embed.add_field(name = "Fichier", value = f"[Lien]({linkFile})", inline=True)
|
||||
except:
|
||||
pass
|
||||
embed.add_field(name = "Message", value = f"{msgID.channel.mention} - [Lien Message]({linkURL})", inline=True)
|
||||
embed.set_author(name = "Citation", icon_url = msgID.author.avatar_url)
|
||||
icon_url = message.author.avatar_url
|
||||
|
||||
date_1 = str(msgID.created_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').split()
|
||||
edit = ""
|
||||
if msgID.edited_at:
|
||||
date_edit = str(msgID.edited_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').split()
|
||||
edit = f"(Dernier edit : {date_edit[0][8:]}/{date_edit[0][5:-3]}/{date_edit[0][:4]} à {date_edit[1]})"
|
||||
message_1 = f"Date : {date_1[0][8:]}/{date_1[0][5:-3]}/{date_1[0][:4]} à {date_1[1]} {edit}"
|
||||
|
||||
date_2 = str(message.created_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').split()
|
||||
date_2 = f"{date_2[0][8:]}/{date_2[0][5:-3]}/{date_2[0][:4]} à {date_2[1]}"
|
||||
|
||||
cite = ""
|
||||
if auteur == "Auteur":
|
||||
cite = f"\nCité par {user_or_nick(message.author)} le {date_2}"
|
||||
embed.set_footer(icon_url = icon_url, text = f"{message_1}{cite}")
|
||||
if message.content == linkURL.replace(' ',''):
|
||||
await message.channel.send(embed = embed)
|
||||
await message.delete()
|
||||
else:
|
||||
await message.reply(embed = embed)
|
||||
except Exception as e:
|
||||
e = str(e)
|
||||
if not "invalid literal for int() with base 10:" in e or not "404 Not Found (error code: 10008)" in e: # faute de frappe / message supprimé
|
||||
print(e)
|
||||
|
||||
@client.event
|
||||
async def on_message_delete(message):
|
||||
if message.author.guild.id == 441208120644075520: # Confrérie du Kassoulait
|
||||
prefix = await client.get_prefix(message)
|
||||
if not (
|
||||
message.content.startswith(f"{prefix}note") or
|
||||
message.content.startswith(f"{prefix}memo") or
|
||||
len(re.findall(".com/channels/", message.content)) != 0 or
|
||||
client.user.id is message.author.id
|
||||
):
|
||||
user_suppressed = None
|
||||
|
||||
async for entry in message.guild.audit_logs(limit=1):
|
||||
if (datetime.now() - entry.created_at).seconds < 5 and str(entry.action) == 'AuditLogAction.message_delete':
|
||||
user_suppressed = entry.user
|
||||
|
||||
channel = client.get_channel(742588187456831659)
|
||||
embed = discord.Embed(description = f"{message.content}")
|
||||
|
||||
embed.set_author(name = user_or_nick(message.author), icon_url = message.author.avatar_url)
|
||||
|
||||
if not user_suppressed:
|
||||
embed.set_footer(text = f"Channel: #{message.channel.name} | Date : {str(message.created_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').replace(' ', ' à ')}\nSupprimé le {datetime.now(pytz.timezone('Europe/Paris')).strftime('%d/%m/%Y à %H:%M:%S')}")
|
||||
else:
|
||||
embed.set_footer(icon_url = user_suppressed.avatar_url, text = f"Channel: #{message.channel.name} | Date : {str(message.created_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').replace(' ', ' à ')}\nSupprimé par {user_or_nick(user_suppressed)} le {datetime.now(pytz.timezone('Europe/Paris')).strftime('%d/%m/%Y à %H:%M:%S')}")
|
||||
|
||||
await channel.send(embed = embed)
|
||||
# ne fonctionne pas quand un message a été supprimé avant que le bot ai démarré
|
||||
# info sur la personne qui a supprimé ne fonctionne pas si il a supprimé un message auparavant (les logs se rajoute a un log deja existant)
|
||||
|
||||
def user_or_nick(user):
|
||||
if user.nick:
|
||||
return f"{user.nick} ({user.name}#{user.discriminator})"
|
||||
else:
|
||||
return f"{user.name}#{user.discriminator}"
|
||||
|
||||
client.run(os.environ['TOKEN_DISCORD'])
|
||||
print("Connexion à Discord...", end = " ")
|
||||
client.run(keys["TOKEN_DISCORD"])
|
||||
|
|
185
src/utils/core.py
Normal file
185
src/utils/core.py
Normal file
|
@ -0,0 +1,185 @@
|
|||
import json
|
||||
import requests
|
||||
from re import findall
|
||||
from time import time
|
||||
from os import environ, path
|
||||
from dotenv import load_dotenv
|
||||
|
||||
def map_list_among_us(map):
|
||||
"""Sélecteur de map pour la commande amongus"""
|
||||
maps = {}
|
||||
maps["skeld"] = ["skeld", "the skeld", "theskeld"]
|
||||
maps["mira"] = ["mira", "mira hq", "mirahq"]
|
||||
maps["polus"] = ["polus"]
|
||||
maps["airship"] = ["airship", "air ship"]
|
||||
if map == "all":
|
||||
return maps["skeld"] + maps["mira"] + maps["polus"] + maps["airship"]
|
||||
return maps[map]
|
||||
|
||||
def userOrNick(user):
|
||||
"""Affiche le pseudo et/ou le surnom"""
|
||||
if user == None:
|
||||
return "Utilisateur inconnu" # Mauvais copié/collé -> changement d'ID
|
||||
if user.nick:
|
||||
return f"{user.nick} ({user.name}#{user.discriminator})"
|
||||
else:
|
||||
return f"{user.name}#{user.discriminator}"
|
||||
|
||||
def cleanUser(ctx, stringMessage, stringID):
|
||||
"""récupère l'utilisateur avec son id"""
|
||||
stringMessage = stringMessage.replace("<@!", "").replace(">", "").replace("<@", "") # améliorer ça avec du regex
|
||||
if len(str(stringMessage)) not in (17, 18): # si ce n'est pas un ID valide
|
||||
return stringMessage
|
||||
associatedID = userOrNick(ctx.author.guild.get_member(int(stringID)))
|
||||
try:
|
||||
stringMessage = stringMessage.replace(stringID, associatedID)
|
||||
except:
|
||||
pass
|
||||
return stringMessage
|
||||
|
||||
def cleanCodeStringWithMentionAndURLs(string):
|
||||
"""formate un string avec des ` tout en gardant les mention et les liens"""
|
||||
string = f"`{removeStartEndSpacesString(string)}`"
|
||||
|
||||
findedMention = getMentionInString(string)
|
||||
for i in range(0, len(findedMention)):
|
||||
string = string.replace(findedMention[i], f"`{findedMention[i]}`") # conserve la mention dans le message
|
||||
|
||||
if string.startswith("``<@"): # conserve le format quand mention au début de la string
|
||||
string = string[2:]
|
||||
if string.endswith(">``"): # conserve le format quand mention à la fin de la string
|
||||
string = string[:-2]
|
||||
string = string.replace("``", "") # conserve le format quand deux mentions sont collés
|
||||
return string
|
||||
|
||||
def getMentionInString(string):
|
||||
"""récupère les mentions dans un string"""
|
||||
findedMention = []
|
||||
for findingMention in findall(r'<@[!]?\d*>', string): # récupération mention dans le string
|
||||
findedMention.append(findingMention)
|
||||
findedMention = list(dict.fromkeys(findedMention)) # suppression doublon de mention dans la liste
|
||||
return findedMention
|
||||
|
||||
def getURLsInString(string):
|
||||
"""récupère les liens dans un string"""
|
||||
findedURLs = []
|
||||
for findingMention in findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', string): # récupération URLs dans le string
|
||||
findedURLs.append(findingMention)
|
||||
return findedURLs
|
||||
|
||||
def removeStartEndSpacesString(string):
|
||||
"""Retire les espaces en trop au début et à la fin d'un string"""
|
||||
while string.startswith(" "):
|
||||
string = string[1:]
|
||||
while string.endswith(" "):
|
||||
string = string[:-1]
|
||||
return string
|
||||
|
||||
def randomImage(link):
|
||||
"""Récupération d'une image aléatoirement"""
|
||||
temps_requete = int(round(time() * 1000))
|
||||
try:
|
||||
request_data = requests.get(link)
|
||||
except Exception as e:
|
||||
raise Exception(f"Une erreur s'est produite lors de la tentative de demande de l'API {link} : {e}")
|
||||
|
||||
if not request_data.status_code == 200:
|
||||
raise Exception(f"Code HTTP {request_data.status_code} au lieu de HTTP 200 à l'appel de {link} : {request_data.text}")
|
||||
|
||||
try:
|
||||
json_data = json.loads(request_data.text)
|
||||
except Exception as e:
|
||||
raise Exception(f"Erreur lors de la transformation les données de {link} en json : {e}")
|
||||
|
||||
temps_requete = int(round(time() * 1000)) - temps_requete
|
||||
return (json_data, temps_requete)
|
||||
|
||||
def retirerDoublons(liste):
|
||||
"""Supprime les doublons d'une liste"""
|
||||
Newliste = []
|
||||
for element in liste:
|
||||
if element not in Newliste:
|
||||
Newliste.append(element)
|
||||
return Newliste
|
||||
|
||||
def ligneFormatage(ligne):
|
||||
"""Traduit en français les balises dans les lyrics d'une chanson"""
|
||||
liste_balise = [
|
||||
('[Hook', '[Accroche'), ('[Verse', '[Couplet'), ('[Chorus', '[Chœur'),
|
||||
('[Bridge', '[Pont'),('[Pre-Chorus', '[Pré-chœur'), ('[Post-Chorus', '[Post-chœur')
|
||||
]
|
||||
for balises in liste_balise:
|
||||
ligne = ligne.replace(balises[0], balises[1])
|
||||
return ligne
|
||||
|
||||
def mentionToUser(mention: str):
|
||||
"""Récupère une mention et renvois son ID"""
|
||||
return int(mention[2:-1].replace("!",""))
|
||||
|
||||
def getChangelogs(version = 'actual'):
|
||||
"""Récupère les changements d'une version (par défaut, la dernière en date) et renvois dans l'ordre : url, n° version, changements"""
|
||||
if version == 'actual':
|
||||
version = getActualVersion()
|
||||
changements = requests.get(f"https://gitlab.com/api/v4/projects/28424435/releases/v{version}")
|
||||
|
||||
if changements.status_code != 200: # si pas valide
|
||||
return [changements.status_code]
|
||||
else:
|
||||
code = 200
|
||||
|
||||
changements = changements.json()
|
||||
return [code, changements["_links"]["self"], changements["tag_name"][1:], changements["description"]]
|
||||
|
||||
def getActualVersion():
|
||||
with open(path.join(path.dirname(path.dirname(path.dirname(__file__))), "README.md"), "r") as file:
|
||||
return findall(r'https:\/\/img.shields.io\/badge\/version-(\d+\.\d+)-green\?style=for-the-badge\)', file.readlines()[2])[0]
|
||||
|
||||
def devOrStableChannel():
|
||||
with open(path.join(path.dirname(path.dirname(path.dirname(__file__))), "README.md"), "r") as file:
|
||||
return findall(r'https:\/\/img.shields.io\/gitlab\/pipeline\/ConfrerieDuKassoulait\/KassouBot\/([a-z]+)\?style=for-the-badge\)]', file.readlines()[3])[0]
|
||||
|
||||
def isSlash(arg):
|
||||
"""Regarde si la commande viens d'un slash ou pas, retourne l'argument sans le 'True' si c'est le cas"""
|
||||
fromSlash = False
|
||||
fullarg = arg
|
||||
if len(arg) > 0:
|
||||
if arg[-1] == True or arg[-1] == None:
|
||||
fromSlash = arg[-1]
|
||||
fullarg = arg[:-1]
|
||||
if len(fullarg) == 0:
|
||||
arg = None
|
||||
else:
|
||||
arg = arg[0]
|
||||
|
||||
return (arg, fromSlash, fullarg)
|
||||
|
||||
async def mySendHidden(
|
||||
ctx, fromSlash, message = None, tts = False, embed = None, file = None, files = None,
|
||||
delete_after = None, allowed_mentions = None):
|
||||
if fromSlash == True: # can't delete hidden message
|
||||
await ctx.send( # sending hidden message
|
||||
content = message, tts = tts, embed = embed, file = file, files = files,
|
||||
delete_after = None, allowed_mentions = allowed_mentions, hidden = fromSlash)
|
||||
else:
|
||||
await ctx.send( # sending normal message
|
||||
content = message, tts = tts, embed = embed, file = file, files = files,
|
||||
delete_after = delete_after, allowed_mentions = allowed_mentions)
|
||||
|
||||
def load(variables):
|
||||
"""Load env variables"""
|
||||
keys = {}
|
||||
load_dotenv() # load .env file
|
||||
for var in variables:
|
||||
try:
|
||||
res = environ[var]
|
||||
if var == "DEACTIVATE":
|
||||
res = list(set(res.split(',')) - {""}) # create a list for the cogs we need to deactivate and remove blank channels and doubles
|
||||
keys[var] = res
|
||||
except KeyError:
|
||||
if var == "DEACTIVATE":
|
||||
keys[var] = "None"
|
||||
else:
|
||||
print(f"Please set the environment variable {var} (.env file supported)")
|
||||
exit(1)
|
||||
|
||||
return keys
|
50
src/utils/db.py
Normal file
50
src/utils/db.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
import sqlite3
|
||||
|
||||
class Database:
|
||||
def __init__(self, urlDatabase: str):
|
||||
self.connexion = self.createConnection(urlDatabase)
|
||||
|
||||
def createConnection(self, path):
|
||||
"""Connexion à une base de donnée SQLite"""
|
||||
if not self.isFileExists(path):
|
||||
open(path, "x")
|
||||
connnexion = None
|
||||
try:
|
||||
connnexion = sqlite3.connect(path)
|
||||
except sqlite3.Error as e:
|
||||
print(e)
|
||||
return connnexion
|
||||
|
||||
def isFileExists(self, path):
|
||||
"""Vérifie qu'un fichier existe"""
|
||||
try:
|
||||
open(path, "r")
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def requete(self, requete, valeurs = None):
|
||||
"""Envois une requête vers la base de données"""
|
||||
try:
|
||||
curseur = self.connexion.cursor()
|
||||
if valeurs:
|
||||
if type(valeurs) not in [list, tuple]:
|
||||
valeurs = [valeurs]
|
||||
curseur.execute(requete, valeurs)
|
||||
else:
|
||||
curseur.execute(requete)
|
||||
self.connexion.commit()
|
||||
return (curseur, curseur.lastrowid)
|
||||
except sqlite3.Error as e:
|
||||
print(e)
|
||||
|
||||
def affichageResultat(self, curseur):
|
||||
"""Affiche le résultat d'une requête"""
|
||||
tableau = []
|
||||
if curseur == None:
|
||||
return tableau
|
||||
lignes = curseur[0].fetchall()
|
||||
for ligne in lignes:
|
||||
tableau.append(ligne)
|
||||
return tableau
|
161
src/utils/reminder.py
Normal file
161
src/utils/reminder.py
Normal file
|
@ -0,0 +1,161 @@
|
|||
from utils.db import Database
|
||||
from discord import Embed, Colour
|
||||
from utils.time import nowUTC, intToDatetime, timedeltaToString, timestampScreen
|
||||
from re import findall
|
||||
|
||||
class Reminder(Database):
|
||||
def __init__(self):
|
||||
super().__init__(r"db/bot.sqlite3")
|
||||
|
||||
def creationTable(self):
|
||||
"""Créer la table qui stocker les reminders."""
|
||||
requete = """
|
||||
CREATE TABLE IF NOT EXISTS reminder (
|
||||
id INTEGER PRIMARY KEY,
|
||||
message_id INTEGER,
|
||||
channel_id INTEGER,
|
||||
extrarg_id INTEGER,
|
||||
reminder_str TEXT,
|
||||
creation_int INTEGER,
|
||||
expiration_int INTEGER,
|
||||
user_id INTEGER,
|
||||
guild_id INTEGER
|
||||
);
|
||||
"""
|
||||
self.requete(requete)
|
||||
|
||||
def ajoutReminder(self, messageID: int, channelID: int, extrarg: int, reminder: str, creation: int, expiration: int, userID: int, guildID: int):
|
||||
"""Ajoute un reminder."""
|
||||
requete = """
|
||||
INSERT INTO reminder (
|
||||
message_id, channel_id, extrarg_id, reminder_str, creation_int, expiration_int, user_id, guild_id
|
||||
) VALUES (
|
||||
?, ?, ?, ?, ?, ?, ?, ?
|
||||
);
|
||||
"""
|
||||
self.requete(requete, [messageID, channelID, extrarg, reminder, creation, expiration, userID, guildID])
|
||||
return self.affichageResultat(self.requete("SELECT last_insert_rowid();"))
|
||||
|
||||
def suppressionReminder(self, id: int):
|
||||
"""Supprime un reminder."""
|
||||
requete = """
|
||||
DELETE FROM reminder
|
||||
WHERE id = ?
|
||||
"""
|
||||
self.requete(requete, id)
|
||||
|
||||
def listeReminder(self, userID: int, guildID: int):
|
||||
"""Retourne la liste des reminders d'un utilisateur."""
|
||||
requete = """
|
||||
SELECT reminder_str, creation_int, expiration_int, id FROM reminder
|
||||
WHERE user_id = ? AND (guild_id = ? OR guild_id = 0)
|
||||
"""
|
||||
return self.affichageResultat(self.requete(requete, [userID, guildID]))
|
||||
|
||||
def recuperationExpiration(self, time: int):
|
||||
"""Récupère les reminders qui sont arrivés à expiration et ses infos."""
|
||||
requete = """
|
||||
SELECT channel_id, extrarg_id, reminder_str, creation_int, user_id, id, message_id FROM reminder
|
||||
WHERE expiration_int < ?
|
||||
"""
|
||||
return self.affichageResultat(self.requete(requete, time))
|
||||
|
||||
def appartenanceReminder(self, userID: int, id: int, guildID: int):
|
||||
"""Vérifie qu'un rappel appartiens à un utilisateur et que la guilde soit la bonne. Renvois False si le rappel n'existe pas."""
|
||||
requete = """
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM reminder
|
||||
WHERE id = ? AND user_id = ? AND (guild_id = ? OR guild_id = 0)
|
||||
)
|
||||
"""
|
||||
return True if self.affichageResultat(self.requete(requete, [id, userID, guildID]))[0][0] == 1 else False
|
||||
|
||||
async def embedListe(utilisateur, guildID, page, color = None, refresh_message = None):
|
||||
"""Fais l'embed d'une page pour l'affichage de la liste des reminders d'un utilisateur."""
|
||||
reminders = Reminder().listeReminder(utilisateur.id, guildID)
|
||||
pageMAX = -(-len(reminders) // 5)
|
||||
|
||||
if refresh_message:
|
||||
if len(reminders) > 0:
|
||||
if pageMAX > 1 and refresh_message.reactions[0] != "⬅️":
|
||||
for emoji in ["⬅️", "➡️"]:
|
||||
await refresh_message.add_reaction(emoji)
|
||||
else:
|
||||
return (False, False, False)
|
||||
|
||||
if pageMAX > 1:
|
||||
refresh = False
|
||||
else:
|
||||
refresh = True
|
||||
if color == None:
|
||||
color = Colour.random()
|
||||
embed = Embed(description = f"**Rappel{'s' if len(reminders) > 1 else ''} de {utilisateur.mention}** • Page {page}/{pageMAX}", color = color)
|
||||
embed.set_thumbnail(url = utilisateur.avatar_url_as(size = 64))
|
||||
limit = 5 * page
|
||||
if len(reminders) > 0 and page <= pageMAX:
|
||||
curseur = limit - 4
|
||||
for reminder in reminders[limit - 5:]:
|
||||
if curseur <= limit:
|
||||
texte = reminder[0]
|
||||
if len(texte) > 1024:
|
||||
texte = f"{texte[:1021]}..."
|
||||
expiration = reminder[2] - int(nowUTC())
|
||||
if expiration > 0:
|
||||
expiration = f"Expire dans {timedeltaToString(expiration)}"
|
||||
else:
|
||||
expiration = f"A déjà expiré."
|
||||
embed.add_field(value = texte, name = f"#{reminder[3]} • Fais le {timestampScreen(intToDatetime(reminder[1]))}\n{expiration}", inline = False)
|
||||
curseur += 1
|
||||
else:
|
||||
embed.add_field(name = "\u200b", value = f"L'utilisateur n'a aucun rappel en attente ou page n°{page} vide !")
|
||||
embed.set_footer(text = "Les rappels qui ont déjà expirés vont apparaître dans quelques instants.\nIls peuvent avoir jusqu'à 1 minute de retard maximum.")
|
||||
return (embed, pageMAX, refresh)
|
||||
|
||||
async def listReaction(client, payload):
|
||||
"""Gère le changement de page du reminderlist avec les réactions."""
|
||||
if payload.emoji.name in ["⬅️", "🔄", "➡️"]:
|
||||
if payload.event_type == "REACTION_ADD":
|
||||
if payload.member.bot == True: # vérifie que c'est pas un bot qui a réagit
|
||||
return False, False
|
||||
channel = client.get_channel(payload.channel_id)
|
||||
message = await channel.fetch_message(payload.message_id)
|
||||
if message.author.id != client.user.id or len(message.embeds) == 0: # vérification message du bot + au moins 1 embed
|
||||
return False, False
|
||||
embed = message.embeds[0].to_dict()
|
||||
if "description" in embed: # si c'est un embed avec une description
|
||||
if len(findall(r"\*\*Rappels? de <@\!?\d+>\*\* • Page \d+\/\d+", embed["description"])) == 1: # si c'est le bon embed
|
||||
infoDescription = findall(r"\*\*Rappels? de <@\!?(\d+)>\*\* • Page (\d+)\/(\d+)", embed["description"])[0]
|
||||
utilisateur = client.get_user(int(infoDescription[0]))
|
||||
page = int(infoDescription[1])
|
||||
refresh_message = None
|
||||
if payload.emoji.name == "⬅️":
|
||||
if page > 1:
|
||||
page -= 1
|
||||
else:
|
||||
if int(infoDescription[2]) > 1:
|
||||
page = int(infoDescription[2])
|
||||
else:
|
||||
return False, False
|
||||
if payload.emoji.name == "➡️":
|
||||
if page + 1 <= int(infoDescription[2]):
|
||||
page += 1
|
||||
else:
|
||||
if page > 1:
|
||||
page = 1
|
||||
else:
|
||||
return False, False
|
||||
if payload.emoji.name == "🔄":
|
||||
refresh_message = message
|
||||
embed, _, refresh = await embedListe(utilisateur, payload.guild_id, page, embed["color"], refresh_message)
|
||||
if embed == False:
|
||||
return False, False
|
||||
if refresh == True:
|
||||
await message.add_reaction("🔄")
|
||||
else:
|
||||
for reaction in message.reactions:
|
||||
if str(reaction) == "🔄":
|
||||
users = await reaction.users().flatten()
|
||||
for user in users:
|
||||
await message.remove_reaction("🔄", user)
|
||||
return message, embed
|
||||
return False, False
|
117
src/utils/time.py
Normal file
117
src/utils/time.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
from pytz import timezone
|
||||
from datetime import datetime, timedelta
|
||||
from re import findall, sub
|
||||
from utils.core import load
|
||||
|
||||
myTimezone = load(["TIMEZONE"])["TIMEZONE"]
|
||||
|
||||
def stringTempsVersSecondes(time):
|
||||
"""Convertis une durée rentrée par un utilisateur en string vers des secondes en int"""
|
||||
conversionTemps = {
|
||||
"31536000 ": ["y", "a"],
|
||||
"604800": ["w"],
|
||||
"86400": ["j", "d"],
|
||||
"3600": ["h"],
|
||||
"60": ["m"],
|
||||
"1": ["s", ""]
|
||||
}
|
||||
valeursMultiplicateur = ""
|
||||
for i in conversionTemps.values():
|
||||
for j in i:
|
||||
valeursMultiplicateur += f"{j}|"
|
||||
match = findall(f'([0-9]+)({valeursMultiplicateur[:-1]})?', time)
|
||||
|
||||
if not match:
|
||||
return "Veuillez entrer un temps valide."
|
||||
|
||||
remindertime = 0
|
||||
for i in match:
|
||||
for tempsEnSeconde, nomCommun in conversionTemps.items():
|
||||
if i[1] in nomCommun:
|
||||
remindertime += int(tempsEnSeconde) * int(i[0])
|
||||
|
||||
return remindertime
|
||||
|
||||
def nowCustom():
|
||||
"""Heure de maintenant avec fuseau horaire local en float"""
|
||||
return datetime.now(timezone(myTimezone)).timestamp()
|
||||
|
||||
def nowUTC():
|
||||
"""Heure de maintenant en UTC en float"""
|
||||
return datetime.utcnow().timestamp()
|
||||
|
||||
def UTCDatetimeToCustomDatetime(datetime):
|
||||
"""Conversion d'une timestamp UTC en timestamp local en datetime"""
|
||||
return timezone(myTimezone).fromutc(datetime)
|
||||
|
||||
def intToDatetime(intOrFloat):
|
||||
"""Convertis un int ou float en Datetime"""
|
||||
return datetime.fromtimestamp(intOrFloat)
|
||||
|
||||
def timestampScreen(timestamp):
|
||||
"""Affichage d'une timestamp"""
|
||||
date_edit = str(UTCDatetimeToCustomDatetime(timestamp)).replace('-', '/').split(' ')
|
||||
date = date_edit[0]
|
||||
heure = date_edit[1].split('+')[0]
|
||||
return f"{date[8:]}/{date[5:-3]}/{date[:4]} à {heure.split('.')[0]}"
|
||||
|
||||
def timedeltaToString(time):
|
||||
"""Différence entre une heure en seconde et maintenant"""
|
||||
age = sub(r' days?, ', ':', str(timedelta(seconds = time))).split(':')
|
||||
affichage = [1, 1, 1, 1]
|
||||
if len(age) == 3:
|
||||
affichage = [0, 1, 1, 1]
|
||||
age.insert(0, None)
|
||||
for i in range(1, len(affichage)):
|
||||
if int(age[i]) == 0:
|
||||
affichage[i] = 0
|
||||
if affichage[0] == 1:
|
||||
day = int(age[0]) # récupération du nombre de jour
|
||||
year = day // 365 # ajout du nombre d'année
|
||||
day -= year * 365 # suppression des années dans le nombre de jour
|
||||
week = day // 7 # ajout du nombres de semaines
|
||||
day -= week * 7 # suppression des semaines dans le nombre du jour
|
||||
yearINT = year # besoin pour le message age[0] final
|
||||
year = f"{year} an{'s' if year > 1 else ''}" if year > 0 else ""
|
||||
weekINT = week # besoin pour le message age[0] final
|
||||
week = f"{week} semaine{'s' if week > 1 else ''}" if week > 0 else ""
|
||||
day = f"{day} jour{'s' if day > 1 else ''}" if day > 0 else ""
|
||||
age[0] = f"{year}{', ' if yearINT > 0 else ''}{week}{', ' if weekINT > 0 else ''}{day}"
|
||||
else:
|
||||
age[0] = ""
|
||||
age[1] = f"{age[1]}h" if affichage[1] == 1 else ''
|
||||
age[2] = f"{age[2]}m" if affichage[2] == 1 else ''
|
||||
age[3] = f"{age[3]}s" if affichage[3] == 1 else ''
|
||||
while "" in age:
|
||||
age.remove("")
|
||||
return ', '.join(age).strip(' ')
|
||||
|
||||
def getAge(date):
|
||||
"""Décompose la différence entre une date et maintenant avec les bons timezone"""
|
||||
joursRestants = UTCDatetimeToCustomDatetime(intToDatetime(nowUTC())) - UTCDatetimeToCustomDatetime(date)
|
||||
years = joursRestants.total_seconds() / (365.242 * 24 * 60 * 60)
|
||||
months = (years - int(years)) * 12
|
||||
days = (months - int(months)) * (365.242 / 12)
|
||||
hours = (days - int(days)) * 24
|
||||
minutes = (hours - int(hours)) * 60
|
||||
seconds = (minutes - int(minutes)) * 60
|
||||
return (int(years), int(months), int(days), int(hours), int(minutes), int(seconds))
|
||||
|
||||
def ageLayout(tuple):
|
||||
"""Avec la méthode `getAge`, permet de mettre en forme un âge"""
|
||||
time = {}
|
||||
time[0], time[1], time[2], time[3], time[4], time[5] = "an", "mois", "jour", "heure", "minute", "seconde"
|
||||
for i in range(len(tuple)):
|
||||
if tuple[i] > 1 and i != 1:
|
||||
time[i] = time[i] + "s"
|
||||
message = ""
|
||||
if tuple[5] > 0:
|
||||
affichage = [5]
|
||||
if tuple[4] > 0:
|
||||
affichage = [4, 5]
|
||||
for i in range(3, -1, -1):
|
||||
if tuple[i] > 0:
|
||||
affichage = [i, i + 1, i + 2]
|
||||
for i in affichage:
|
||||
message = message + f", {tuple[i]} {time[i]}"
|
||||
return message[2:]
|
Reference in a new issue