Compare commits
20 commits
Author | SHA1 | Date | |
---|---|---|---|
f27fd93e78 | |||
8ce59cc541 | |||
05b9e359c7 | |||
a0eef4bfe5 | |||
4234730041 | |||
90e5d6a1e9 | |||
ecd00568fe | |||
036cb69518 | |||
7f98ae2793 | |||
e78a5f371d | |||
c3e11519c4 | |||
ce7ad42bb9 | |||
7d30eae1f2 | |||
8c35af16ff | |||
ef1816be20 | |||
abd62d7c6d | |||
dac6ed6112 | |||
1b7b4d0507 | |||
be47cc43b0 | |||
f9c02e6c95 |
12 changed files with 164 additions and 38 deletions
22
README.md
22
README.md
|
@ -1,7 +1,8 @@
|
|||
# Bot Discord
|
||||
|
||||
[![Version](https://img.shields.io/badge/version-1.6-green?style=for-the-badge)](https://gitlab.com/ConfrerieDuKassoulait/KassouBot/-/releases)
|
||||
[![Build](https://img.shields.io/gitlab/pipeline/ConfrerieDuKassoulait/KassouBot/main?style=for-the-badge)](https://gitlab.com/ConfrerieDuKassoulait/KassouBot/container_registry)
|
||||
[![Version](https://img.shields.io/badge/version-1.7-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)
|
||||
[![Mirror](https://img.shields.io/badge/Mirror-brightgreen?style=for-the-badge)](https://git.kennel.ml/ConfrerieDuKassoulait/KassouBot)
|
||||
|
||||
## __Features__
|
||||
|
||||
|
@ -9,7 +10,7 @@
|
|||
- Slash commands support (use [Discord Interactions](https://github.com/goverfl0w/discord-interactions)).
|
||||
- Party games activities support (use [Discord Together](https://github.com/apurv-r/discord-together)).
|
||||
- Music support (use [Lavalink](https://github.com/freyacodes/Lavalink) with the [Wavelink](https://github.com/PythonistaGuild/Wavelink) client).
|
||||
- Reminders and Todos list support.
|
||||
- Reminders and ToDos list support (with a weekly reminder of the ToDos list in DM).
|
||||
- Poll support.
|
||||
- Meme from reddit and NSFW pictures support.
|
||||
- Basics commands and simple games, don't mind on opening an issue if you wan't your idea to be added to the bot.
|
||||
|
@ -77,19 +78,22 @@ To find Genius token, go to [this site](https://genius.com/api-clients), `login
|
|||
## __Launching locally__
|
||||
If you want to run it without Docker, clone the repo and his submodules by doing this command in the git folder:
|
||||
```batch
|
||||
git clone git@gitlab.com:ConfrerieDuKassoulait/KassouBot.git --recursive
|
||||
```
|
||||
If you already cloned the repo without the `--recursive` arg you can do that in the git folder :
|
||||
```batch
|
||||
git submodule update --force --recursive --init --remote
|
||||
```
|
||||
Then 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 all the requirements by doing `python3 -m pip install -r requirements.txt` (I recommend using virtualenv to not interfere with your system).
|
||||
|
||||
If you need to install Java, there is some step to have the same as the [Docker image built for the project](https://gitlab.com/ConfrerieDuKassoulait/lavalink/), on Debian-based distro:
|
||||
If you need to install Java, there is some step to have the same as the [Docker image built for the project](https://gitlab.com/ConfrerieDuKassoulait/lavalink/), on Debian-based distro, I recommand using [SDKMAN](https://sdkman.io/):
|
||||
```bash
|
||||
wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | sudo apt-key add -
|
||||
sudo add-apt-repository --yes https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/
|
||||
sudo apt update -y
|
||||
sudo apt install adoptopenjdk-16-openj9 -y
|
||||
curl -s "https://get.sdkman.io" | bash
|
||||
source "$HOME/.sdkman/bin/sdkman-init.sh"
|
||||
sdk install java 17.0.1-tem
|
||||
```
|
||||
On Windows just go [to their site](https://adoptopenjdk.net/?variant=openjdk16&jvmVariant=openj9).
|
||||
On Windows just go [to their site](https://adoptium.net/archive.html) and choose the latest version of Temurin 17 (LTS).
|
||||
|
||||
Then, simply run `start.bat` if you are on Windows or `start.sh` if on Debian-based distro to launch the bot.
|
||||
|
|
|
@ -7,4 +7,4 @@ feedparser==6.0.8 # rss feed (news)
|
|||
discord-py-slash-command==3.0.1 # slash commands
|
||||
python_dotenv==0.19.0 # using .env file
|
||||
wavelink==0.9.10 # music | to know the version of lavalink used, see the repo
|
||||
discord-together==1.1.1 # for the party games
|
||||
discord-together==1.2.1 # for the party games
|
||||
|
|
|
@ -15,20 +15,31 @@ class ConfrerieDuKassoulait(commands.Cog):
|
|||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.messageDictAndEmojiToRoles = {
|
||||
882785207235788800:
|
||||
{
|
||||
882783004706095194: 882616261626970112, # elephant - l1
|
||||
882783004697714789: 882616188830629998, # gorilla - l2
|
||||
882783004416675881: 882616082022670387, # cat - - l3
|
||||
882783005108744202: 882616475918147654, # rabbit - visiteurs
|
||||
882783004911624212: 882616714133635093 # dog - alumni
|
||||
# {MessageID: {
|
||||
# Emoji(ID): RoleID
|
||||
# }}
|
||||
882785207235788800: {
|
||||
"🟡": 882616261626970112, # l1
|
||||
"🔵": 882616188830629998, # l2
|
||||
"🟣": 882616082022670387, # l3
|
||||
"🟠": 882616475918147654, # visiteurs
|
||||
"🟢": 882616714133635093, # alumni
|
||||
|
||||
"💛": 882721538770624562, # référent l1
|
||||
"💙": 882721619041198190, # référent l2
|
||||
"💜": 882721700465246218 # référent l3
|
||||
},
|
||||
888001335105036329:
|
||||
{
|
||||
"1️⃣": 887999417892880474, # 1 - étudiant
|
||||
"2️⃣": 887999473513549845, # 2 - professeur
|
||||
888001335105036329: {
|
||||
"1️⃣": 887999417892880474, # étudiant
|
||||
"2️⃣": 887999473513549845 # professeur
|
||||
},
|
||||
979497142085357568: {
|
||||
949037346207170571: 947652446497423382, # cartouche
|
||||
"🦝": 947650819078099006, # racoon
|
||||
"🎹": 979493581289042020 # musical_keyboard
|
||||
}
|
||||
}
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_member_join(self, member):
|
||||
"""Triggered when a member join a guild"""
|
||||
|
@ -133,7 +144,9 @@ class ConfrerieDuKassoulait(commands.Cog):
|
|||
await payload.member.add_roles(payload.member.guild.get_role(self.messageDictAndEmojiToRoles[payload.message_id][payload.emoji.id]))
|
||||
except:
|
||||
await payload.member.add_roles(payload.member.guild.get_role(self.messageDictAndEmojiToRoles[payload.message_id][str(payload.emoji)]))
|
||||
except KeyError:
|
||||
except KeyError: # mauvais message ou réaction
|
||||
return
|
||||
except AttributeError: # reaction en DM
|
||||
return
|
||||
|
||||
@commands.Cog.listener()
|
||||
|
@ -148,3 +161,19 @@ class ConfrerieDuKassoulait(commands.Cog):
|
|||
await member.remove_roles(guild.get_role(self.messageDictAndEmojiToRoles[payload.message_id][str(payload.emoji)]))
|
||||
except KeyError:
|
||||
return
|
||||
except AttributeError: # reaction en DM
|
||||
return
|
||||
|
||||
""" @commands.command()
|
||||
async def test(self, _):
|
||||
# Test command to add some emojis to a message.
|
||||
channel = self.client.get_channel(882785037236445245)
|
||||
message = await channel.fetch_message(882785207235788800)
|
||||
await message.add_reaction("🟡")
|
||||
await message.add_reaction("🔵")
|
||||
await message.add_reaction("🟣")
|
||||
await message.add_reaction("🟠")
|
||||
await message.add_reaction("🟢")
|
||||
await message.add_reaction("💛")
|
||||
await message.add_reaction("💙")
|
||||
await message.add_reaction("💜") """
|
||||
|
|
|
@ -210,8 +210,9 @@ class Internet(commands.Cog):
|
|||
if "tiktok.com" not in url:
|
||||
return
|
||||
url_embed = url.replace("tiktok.com", "dstn.to")
|
||||
mergeUrls = f"{url_embed} | <{url}>"
|
||||
if message.content == url.replace(" ", ""):
|
||||
await message.channel.send(f"Tiktok partagé par {message.author.mention} • {url.replace('tiktok.com', 'dstn.to')}")
|
||||
await message.channel.send(f"Tiktok partagé par {message.author.mention} • {mergeUrls}")
|
||||
await message.delete()
|
||||
else:
|
||||
await message.reply(f"⬇ {url_embed} ⬇", mention_author = False)
|
||||
await message.reply(f"⬇ {mergeUrls} ⬇", mention_author = False)
|
||||
|
|
|
@ -711,7 +711,7 @@ class Music(commands.Cog, wavelink.WavelinkMixin):
|
|||
await addReaction(ctx.message, 2)
|
||||
return await mySendHidden(ctx, fromSlash, "Seuls le DJ ou les admins peuvent modifier le volume.")
|
||||
|
||||
if not vol:
|
||||
if vol == None:
|
||||
await mySendHidden(ctx, fromSlash, f"Le volume est actuellement réglé à **{player.volume}%**.")
|
||||
if fromSlash != True:
|
||||
return await addReaction(ctx.message, 0)
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
import discordTogether
|
||||
from discord_slash import cog_ext
|
||||
from discordTogether import DiscordTogether
|
||||
from discord_together import errors as dte
|
||||
from utils.core import mySendHidden
|
||||
|
||||
def setup(client):
|
||||
|
@ -13,13 +12,15 @@ class PartyGames(commands.Cog, name="Partygames"):
|
|||
"""Discord beta "party games" dispo uniquement sur PC."""
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.togetherControl = DiscordTogether(client)
|
||||
self.appList = { # appNameForDiscord - (AppNameForConsumer, AppImage)
|
||||
"youtube": ("Youtube Together", "https://logo-logos.com/wp-content/uploads/2016/11/YouTube_icon_logo.png"),
|
||||
"poker": ("Poker Night", "https://images.launchbox-app.com/21782afd-4f83-492a-b199-38404d743e57.png"),
|
||||
"chess": ("Chess in the Park", "https://images.discordapp.net/avatars/716382796108660826/e52b79451f4d00cb04a4aca3099210a7.png?size=512"),
|
||||
"betrayal": ("Betrayal.io", "https://1.bp.blogspot.com/-uaqT13tY30Q/X_kqsiBJqTI/AAAAAAAADRw/R5ekQuGsO08dlBlgzXZbHktF3ioHmwmPQCLcBGAsYHQ/w1200-h630-p-k-no-nu/icon%2B%25283%2529.png"),
|
||||
"fishing": ("Fishington.io", None)
|
||||
"fishing": ("Fishington.io", None),
|
||||
"letter-tile": ("Letter Tile", None),
|
||||
"word-snack": ("Word Snack", "https://image.winudf.com/v2/image/Y29tLmFwbmF4LndvcmRzbmFja19zY3JlZW5fNF8xNTM3NzE5OTkzXzAxNg/screen-4.jpg?fakeurl=1&type=.jpg"),
|
||||
"doodle-crew": ("Doodle Crew", None)
|
||||
}
|
||||
|
||||
@commands.command(name='app', hidden = True)
|
||||
|
@ -35,16 +36,16 @@ class PartyGames(commands.Cog, name="Partygames"):
|
|||
except:
|
||||
pass
|
||||
try:
|
||||
link = await self.togetherControl.create_link(ctx.author.voice.channel.id, app)
|
||||
link = await self.client.togetherControl.create_link(ctx.author.voice.channel.id, app)
|
||||
except AttributeError:
|
||||
return await mySendHidden(ctx, fromSlash, "Vous devez d'abord être dans un salon vocal avant de faire cette commande.")
|
||||
except discordTogether.errors.InvalidActivityChoice:
|
||||
except dte.InvalidArgument:
|
||||
return await mySendHidden(ctx, fromSlash, "Cette application n'est pas reconnu par Discord.")
|
||||
embed = discord.Embed(title = "Party Games", description = f"[Lancer *{appName}*]({link}) !")
|
||||
if appImage:
|
||||
embed.set_thumbnail(url = appImage)
|
||||
embed.set_footer(text = "Ne fonctionne que sur PC pour le moment.")
|
||||
return await ctx.send(embed = embed)
|
||||
return await mySendHidden(ctx, fromSlash, embed = embed)
|
||||
|
||||
|
||||
@commands.command(name='youtube')
|
||||
|
@ -91,3 +92,30 @@ class PartyGames(commands.Cog, name="Partygames"):
|
|||
async def __fishing(self, ctx):
|
||||
"""Slash command"""
|
||||
return await self._fishing(ctx, True)
|
||||
|
||||
@commands.command(name='letter-tile')
|
||||
async def _letterTile(self, ctx, fromSlash = None):
|
||||
"""Créer une instance "Letter Tile"."""
|
||||
return await self._linkCreator(ctx, "letter-tile", fromSlash)
|
||||
@cog_ext.cog_slash(name="letter-tile", description = "Créer une instance \"Letter Tile\".")
|
||||
async def __letterTile(self, ctx):
|
||||
"""Slash command"""
|
||||
return await self._letterTile(ctx, True)
|
||||
|
||||
@commands.command(name='word-snack')
|
||||
async def _wordSnack(self, ctx, fromSlash = None):
|
||||
"""Créer une instance "Word Snack"."""
|
||||
return await self._linkCreator(ctx, "word-snack", fromSlash)
|
||||
@cog_ext.cog_slash(name="word-snack", description = "Créer une instance \"Word Snack\".")
|
||||
async def __wordSnack(self, ctx):
|
||||
"""Slash command"""
|
||||
return await self._wordSnack(ctx, True)
|
||||
|
||||
@commands.command(name='doodle-crew')
|
||||
async def _doodleCrew(self, ctx, fromSlash = None):
|
||||
"""Créer une instance "Doodle Crew"."""
|
||||
return await self._linkCreator(ctx, "doodle-crew", fromSlash)
|
||||
@cog_ext.cog_slash(name="doodle-crew", description = "Créer une instance \"Doodle Crew\".")
|
||||
async def __doodleCrew(self, ctx):
|
||||
"""Slash command"""
|
||||
return await self._doodleCrew(ctx, True)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from discord.ext import commands
|
||||
from discord.ext import commands, tasks
|
||||
from discord_slash import cog_ext
|
||||
from utils.todo import ToDo, embedListeToDo
|
||||
from utils.core import getMentionInString, isSlash, mySendHidden
|
||||
from utils.core import addReaction, mentionToUser
|
||||
from utils.time import nowUTC
|
||||
from utils.time import nowUTC, timeBeforeNextSaturdayAtNineHours
|
||||
|
||||
def setup(client):
|
||||
"""Adding Cog to bot"""
|
||||
|
@ -13,8 +13,46 @@ class ToDoDiscord(commands.Cog, name="Todo"):
|
|||
"""Commandes relatives aux To Do."""
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self._todoLoop.start()
|
||||
ToDo().creationTable()
|
||||
|
||||
@tasks.loop(minutes = 1) # ce temps est ignoré
|
||||
async def _todoLoop(self):
|
||||
"""Méthode qui se répète toute les samedis pour envoyer un récapitulatif des Todos."""
|
||||
if self._todoLoop.current_loop in (0, 2): # ignore des boucles non voulue (#1 se lance au démarrage et #3 au changement de l'intervalle)
|
||||
return
|
||||
elif self._todoLoop.current_loop == 1: # premier vrai lancement
|
||||
self._todoLoop.change_interval(hours = 168) # prochain lancement dans 1 semaine
|
||||
todos = []
|
||||
listIDs = []
|
||||
for todo in ToDo().listAll():
|
||||
if todo[0] in listIDs:
|
||||
pass
|
||||
else:
|
||||
todos.append(todo)
|
||||
listIDs.append(todo[0])
|
||||
for todo in todos:
|
||||
user = self.client.get_user(todo[0])
|
||||
if user == None: # si l'utilisateur n'est pas trouvé
|
||||
pass # on ignore l'utilisateur
|
||||
channel = await user.create_dm() # envoie en DM
|
||||
embed, pageMAX = await embedListeToDo(user, 1)
|
||||
try:
|
||||
message = await channel.send("Récapitulatif hebdomadaire de vos To Do's", embed = embed)
|
||||
except: # Les DM sont fermés
|
||||
pass # on ignore l'envoie du récap
|
||||
if pageMAX > 1:
|
||||
for emoji in ["⬅️", "➡️"]:
|
||||
await message.add_reaction(emoji)
|
||||
else:
|
||||
await message.add_reaction("🔄")
|
||||
|
||||
@_todoLoop.before_loop
|
||||
async def __avant_todoLoop(self):
|
||||
"""Wait to start the loop until the whole bot is ready"""
|
||||
await self.client.wait_until_ready()
|
||||
self._todoLoop.change_interval(seconds = timeBeforeNextSaturdayAtNineHours())
|
||||
|
||||
@commands.command(name='todo')
|
||||
async def _todo(self, ctx, *todo):
|
||||
"""Met en place un To Do.\n ➡ Syntaxe: {PREFIX}todo <message>"""
|
||||
|
@ -36,7 +74,7 @@ class ToDoDiscord(commands.Cog, name="Todo"):
|
|||
todoID = ToDo().ajout(messageID, todo, now, ctx.author.id)
|
||||
if fromSlash != True:
|
||||
await addReaction(ctx.message, 0)
|
||||
return await mySendHidden(ctx, fromSlash, f"To Do **`#{todoID[0][0]}`** enrengistré !")
|
||||
return await mySendHidden(ctx, fromSlash, f"To Do **`#{todoID[0][0]}`** enregistré !")
|
||||
@cog_ext.cog_slash(name="todo", description = "Met en place un To Do.")
|
||||
async def __todo(self, ctx, todo):
|
||||
"""Slash command"""
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 570730f3ae83dab0c4a8c61dde1c9094957c6ad4
|
||||
Subproject commit e05be4c3fa886268cef3d19bec568c28999e03ea
|
|
@ -6,6 +6,7 @@ from discord_slash import SlashCommand
|
|||
from discord.ext import commands
|
||||
from utils.core import load, addReaction
|
||||
from utils.page import listReaction
|
||||
from discord_together import DiscordTogether
|
||||
keys = load(["PREFIX", "TOKEN_DISCORD", "DEACTIVATE"])
|
||||
customPrefix = keys["PREFIX"]
|
||||
|
||||
|
@ -48,6 +49,7 @@ async def on_ready(update_changePresence = False):
|
|||
"""Triggered when the bot is ready to operate"""
|
||||
await client.change_presence(status = discord.Status.online, activity = discord.Activity(name = f"{customPrefix}help · {len(client.guilds)} serveur{'s' if len(client.guilds) > 1 else ''}", type = discord.ActivityType.playing))
|
||||
if update_changePresence == False:
|
||||
client.togetherControl = await DiscordTogether(keys["TOKEN_DISCORD"])
|
||||
print("Bot prêt.")
|
||||
|
||||
@client.event
|
||||
|
|
|
@ -9,8 +9,12 @@ async def listReaction(client, payload):
|
|||
"""
|
||||
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
|
||||
if payload.member: # check car pas de member en DM
|
||||
if payload.member.bot == True: # vérifie que c'est pas un bot qui a réagit
|
||||
return False, False
|
||||
else:
|
||||
if client.get_user(payload.user_id).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
|
||||
|
|
|
@ -129,3 +129,16 @@ def ageLayout(tuple):
|
|||
for i in affichage:
|
||||
message = message + f", {tuple[i]} {time[i]}"
|
||||
return message[2:]
|
||||
|
||||
def timeBeforeNextSaturdayAtNineHours() -> int:
|
||||
"""Envoie le nombre de secondes qu'il y a avant le prochain Samedi à 9h"""
|
||||
date = datetime.today()
|
||||
now = date
|
||||
# prochain 9h
|
||||
while date.hour != 9:
|
||||
date = date + timedelta(hours = 1)
|
||||
# prochain samedi
|
||||
while date.strftime("%A") != "Saturday":
|
||||
date = date + timedelta(days = 1)
|
||||
delta = date - now
|
||||
return int(delta.total_seconds())
|
||||
|
|
|
@ -47,6 +47,13 @@ class ToDo(Database):
|
|||
"""
|
||||
return self.affichageResultat(self.requete(requete, userID))
|
||||
|
||||
def listAll(self):
|
||||
"""Retourne la liste de tout les To Do."""
|
||||
requete = """
|
||||
SELECT user_id, id, todo_str, creation_int FROM todo
|
||||
"""
|
||||
return self.affichageResultat(self.requete(requete))
|
||||
|
||||
def appartenance(self, userID: int, id: int):
|
||||
"""Vérifie qu'un To Do appartiens à un utilisateur. Renvois False si le To Do n'existe pas."""
|
||||
requete = """
|
||||
|
|
Reference in a new issue