Compare commits

..

1 commit
dev ... main

Author SHA1 Message Date
54ab6d4dd5 use the main repo for the pipeline badge status 2021-09-20 09:11:34 +02:00
12 changed files with 38 additions and 164 deletions

View file

@ -1,8 +1,7 @@
# Bot Discord # Bot Discord
[![Version](https://img.shields.io/badge/version-1.7-green?style=for-the-badge)](https://gitlab.com/ConfrerieDuKassoulait/KassouBot/-/releases) [![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/dev?style=for-the-badge)](https://gitlab.com/ConfrerieDuKassoulait/KassouBot/container_registry) [![Build](https://img.shields.io/gitlab/pipeline/ConfrerieDuKassoulait/KassouBot/main?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__ ## __Features__
@ -10,7 +9,7 @@
- Slash commands support (use [Discord Interactions](https://github.com/goverfl0w/discord-interactions)). - 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)). - 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). - Music support (use [Lavalink](https://github.com/freyacodes/Lavalink) with the [Wavelink](https://github.com/PythonistaGuild/Wavelink) client).
- Reminders and ToDos list support (with a weekly reminder of the ToDos list in DM). - Reminders and Todos list support.
- Poll support. - Poll support.
- Meme from reddit and NSFW pictures 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. - Basics commands and simple games, don't mind on opening an issue if you wan't your idea to be added to the bot.
@ -78,22 +77,19 @@ To find Genius token, go to [this site](https://genius.com/api-clients), `login
## __Launching locally__ ## __Launching locally__
If you want to run it without Docker, clone the repo and his submodules by doing this command in the git folder: If you want to run it without Docker, clone the repo and his submodules by doing this command in the git folder:
```batch ```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 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)). 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). 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, I recommand using [SDKMAN](https://sdkman.io/): 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:
```bash ```bash
curl -s "https://get.sdkman.io" | bash wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | sudo apt-key add -
source "$HOME/.sdkman/bin/sdkman-init.sh" sudo add-apt-repository --yes https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/
sdk install java 17.0.1-tem sudo apt update -y
sudo apt install adoptopenjdk-16-openj9 -y
``` ```
On Windows just go [to their site](https://adoptium.net/archive.html) and choose the latest version of Temurin 17 (LTS). On Windows just go [to their site](https://adoptopenjdk.net/?variant=openjdk16&jvmVariant=openj9).
Then, simply run `start.bat` if you are on Windows or `start.sh` if on Debian-based distro to launch the bot. Then, simply run `start.bat` if you are on Windows or `start.sh` if on Debian-based distro to launch the bot.

View file

@ -7,4 +7,4 @@ feedparser==6.0.8 # rss feed (news)
discord-py-slash-command==3.0.1 # slash commands discord-py-slash-command==3.0.1 # slash commands
python_dotenv==0.19.0 # using .env file python_dotenv==0.19.0 # using .env file
wavelink==0.9.10 # music | to know the version of lavalink used, see the repo wavelink==0.9.10 # music | to know the version of lavalink used, see the repo
discord-together==1.2.1 # for the party games discord-together==1.1.1 # for the party games

View file

@ -15,31 +15,20 @@ class ConfrerieDuKassoulait(commands.Cog):
def __init__(self, client): def __init__(self, client):
self.client = client self.client = client
self.messageDictAndEmojiToRoles = { self.messageDictAndEmojiToRoles = {
# {MessageID: { 882785207235788800:
# Emoji(ID): RoleID {
# }} 882783004706095194: 882616261626970112, # elephant - l1
882785207235788800: { 882783004697714789: 882616188830629998, # gorilla - l2
"🟡": 882616261626970112, # l1 882783004416675881: 882616082022670387, # cat - - l3
"🔵": 882616188830629998, # l2 882783005108744202: 882616475918147654, # rabbit - visiteurs
"🟣": 882616082022670387, # l3 882783004911624212: 882616714133635093 # dog - alumni
"🟠": 882616475918147654, # visiteurs
"🟢": 882616714133635093, # alumni
"💛": 882721538770624562, # référent l1
"💙": 882721619041198190, # référent l2
"💜": 882721700465246218 # référent l3
}, },
888001335105036329: { 888001335105036329:
"1": 887999417892880474, # étudiant {
"2": 887999473513549845 # professeur "1": 887999417892880474, # 1 - étudiant
}, "2": 887999473513549845, # 2 - professeur
979497142085357568: {
949037346207170571: 947652446497423382, # cartouche
"🦝": 947650819078099006, # racoon
"🎹": 979493581289042020 # musical_keyboard
} }
} }
@commands.Cog.listener() @commands.Cog.listener()
async def on_member_join(self, member): async def on_member_join(self, member):
"""Triggered when a member join a guild""" """Triggered when a member join a guild"""
@ -144,9 +133,7 @@ class ConfrerieDuKassoulait(commands.Cog):
await payload.member.add_roles(payload.member.guild.get_role(self.messageDictAndEmojiToRoles[payload.message_id][payload.emoji.id])) await payload.member.add_roles(payload.member.guild.get_role(self.messageDictAndEmojiToRoles[payload.message_id][payload.emoji.id]))
except: except:
await payload.member.add_roles(payload.member.guild.get_role(self.messageDictAndEmojiToRoles[payload.message_id][str(payload.emoji)])) await payload.member.add_roles(payload.member.guild.get_role(self.messageDictAndEmojiToRoles[payload.message_id][str(payload.emoji)]))
except KeyError: # mauvais message ou réaction except KeyError:
return
except AttributeError: # reaction en DM
return return
@commands.Cog.listener() @commands.Cog.listener()
@ -161,19 +148,3 @@ class ConfrerieDuKassoulait(commands.Cog):
await member.remove_roles(guild.get_role(self.messageDictAndEmojiToRoles[payload.message_id][str(payload.emoji)])) await member.remove_roles(guild.get_role(self.messageDictAndEmojiToRoles[payload.message_id][str(payload.emoji)]))
except KeyError: except KeyError:
return 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("💜") """

View file

@ -210,9 +210,8 @@ class Internet(commands.Cog):
if "tiktok.com" not in url: if "tiktok.com" not in url:
return return
url_embed = url.replace("tiktok.com", "dstn.to") url_embed = url.replace("tiktok.com", "dstn.to")
mergeUrls = f"{url_embed} | <{url}>"
if message.content == url.replace(" ", ""): if message.content == url.replace(" ", ""):
await message.channel.send(f"Tiktok partagé par {message.author.mention}{mergeUrls}") await message.channel.send(f"Tiktok partagé par {message.author.mention}{url.replace('tiktok.com', 'dstn.to')}")
await message.delete() await message.delete()
else: else:
await message.reply(f"{mergeUrls}", mention_author = False) await message.reply(f"{url_embed}", mention_author = False)

View file

@ -711,7 +711,7 @@ class Music(commands.Cog, wavelink.WavelinkMixin):
await addReaction(ctx.message, 2) await addReaction(ctx.message, 2)
return await mySendHidden(ctx, fromSlash, "Seuls le DJ ou les admins peuvent modifier le volume.") return await mySendHidden(ctx, fromSlash, "Seuls le DJ ou les admins peuvent modifier le volume.")
if vol == None: if not vol:
await mySendHidden(ctx, fromSlash, f"Le volume est actuellement réglé à **{player.volume}%**.") await mySendHidden(ctx, fromSlash, f"Le volume est actuellement réglé à **{player.volume}%**.")
if fromSlash != True: if fromSlash != True:
return await addReaction(ctx.message, 0) return await addReaction(ctx.message, 0)

View file

@ -1,7 +1,8 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
import discordTogether
from discord_slash import cog_ext from discord_slash import cog_ext
from discord_together import errors as dte from discordTogether import DiscordTogether
from utils.core import mySendHidden from utils.core import mySendHidden
def setup(client): def setup(client):
@ -12,15 +13,13 @@ class PartyGames(commands.Cog, name="Partygames"):
"""Discord beta "party games" dispo uniquement sur PC.""" """Discord beta "party games" dispo uniquement sur PC."""
def __init__(self, client): def __init__(self, client):
self.client = client self.client = client
self.togetherControl = DiscordTogether(client)
self.appList = { # appNameForDiscord - (AppNameForConsumer, AppImage) self.appList = { # appNameForDiscord - (AppNameForConsumer, AppImage)
"youtube": ("Youtube Together", "https://logo-logos.com/wp-content/uploads/2016/11/YouTube_icon_logo.png"), "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"), "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"), "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"), "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) @commands.command(name='app', hidden = True)
@ -36,16 +35,16 @@ class PartyGames(commands.Cog, name="Partygames"):
except: except:
pass pass
try: try:
link = await self.client.togetherControl.create_link(ctx.author.voice.channel.id, app) link = await self.togetherControl.create_link(ctx.author.voice.channel.id, app)
except AttributeError: except AttributeError:
return await mySendHidden(ctx, fromSlash, "Vous devez d'abord être dans un salon vocal avant de faire cette commande.") return await mySendHidden(ctx, fromSlash, "Vous devez d'abord être dans un salon vocal avant de faire cette commande.")
except dte.InvalidArgument: except discordTogether.errors.InvalidActivityChoice:
return await mySendHidden(ctx, fromSlash, "Cette application n'est pas reconnu par Discord.") return await mySendHidden(ctx, fromSlash, "Cette application n'est pas reconnu par Discord.")
embed = discord.Embed(title = "Party Games", description = f"[Lancer *{appName}*]({link}) !") embed = discord.Embed(title = "Party Games", description = f"[Lancer *{appName}*]({link}) !")
if appImage: if appImage:
embed.set_thumbnail(url = appImage) embed.set_thumbnail(url = appImage)
embed.set_footer(text = "Ne fonctionne que sur PC pour le moment.") embed.set_footer(text = "Ne fonctionne que sur PC pour le moment.")
return await mySendHidden(ctx, fromSlash, embed = embed) return await ctx.send(embed = embed)
@commands.command(name='youtube') @commands.command(name='youtube')
@ -92,30 +91,3 @@ class PartyGames(commands.Cog, name="Partygames"):
async def __fishing(self, ctx): async def __fishing(self, ctx):
"""Slash command""" """Slash command"""
return await self._fishing(ctx, True) 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)

View file

@ -1,9 +1,9 @@
from discord.ext import commands, tasks from discord.ext import commands
from discord_slash import cog_ext from discord_slash import cog_ext
from utils.todo import ToDo, embedListeToDo from utils.todo import ToDo, embedListeToDo
from utils.core import getMentionInString, isSlash, mySendHidden from utils.core import getMentionInString, isSlash, mySendHidden
from utils.core import addReaction, mentionToUser from utils.core import addReaction, mentionToUser
from utils.time import nowUTC, timeBeforeNextSaturdayAtNineHours from utils.time import nowUTC
def setup(client): def setup(client):
"""Adding Cog to bot""" """Adding Cog to bot"""
@ -13,46 +13,8 @@ class ToDoDiscord(commands.Cog, name="Todo"):
"""Commandes relatives aux To Do.""" """Commandes relatives aux To Do."""
def __init__(self, client): def __init__(self, client):
self.client = client self.client = client
self._todoLoop.start()
ToDo().creationTable() 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') @commands.command(name='todo')
async def _todo(self, ctx, *todo): async def _todo(self, ctx, *todo):
"""Met en place un To Do.\n ➡ Syntaxe: {PREFIX}todo <message>""" """Met en place un To Do.\n ➡ Syntaxe: {PREFIX}todo <message>"""
@ -74,7 +36,7 @@ class ToDoDiscord(commands.Cog, name="Todo"):
todoID = ToDo().ajout(messageID, todo, now, ctx.author.id) todoID = ToDo().ajout(messageID, todo, now, ctx.author.id)
if fromSlash != True: if fromSlash != True:
await addReaction(ctx.message, 0) await addReaction(ctx.message, 0)
return await mySendHidden(ctx, fromSlash, f"To Do **`#{todoID[0][0]}`** enregistré !") return await mySendHidden(ctx, fromSlash, f"To Do **`#{todoID[0][0]}`** enrengistré !")
@cog_ext.cog_slash(name="todo", description = "Met en place un To Do.") @cog_ext.cog_slash(name="todo", description = "Met en place un To Do.")
async def __todo(self, ctx, todo): async def __todo(self, ctx, todo):
"""Slash command""" """Slash command"""

@ -1 +1 @@
Subproject commit e05be4c3fa886268cef3d19bec568c28999e03ea Subproject commit 570730f3ae83dab0c4a8c61dde1c9094957c6ad4

View file

@ -6,7 +6,6 @@ from discord_slash import SlashCommand
from discord.ext import commands from discord.ext import commands
from utils.core import load, addReaction from utils.core import load, addReaction
from utils.page import listReaction from utils.page import listReaction
from discord_together import DiscordTogether
keys = load(["PREFIX", "TOKEN_DISCORD", "DEACTIVATE"]) keys = load(["PREFIX", "TOKEN_DISCORD", "DEACTIVATE"])
customPrefix = keys["PREFIX"] customPrefix = keys["PREFIX"]
@ -49,7 +48,6 @@ async def on_ready(update_changePresence = False):
"""Triggered when the bot is ready to operate""" """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)) 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: if update_changePresence == False:
client.togetherControl = await DiscordTogether(keys["TOKEN_DISCORD"])
print("Bot prêt.") print("Bot prêt.")
@client.event @client.event

View file

@ -9,12 +9,8 @@ async def listReaction(client, payload):
""" """
if payload.emoji.name in ["⬅️", "🔄", "➡️"]: if payload.emoji.name in ["⬅️", "🔄", "➡️"]:
if payload.event_type == "REACTION_ADD": if payload.event_type == "REACTION_ADD":
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 if payload.member.bot == True: # vérifie que c'est pas un bot qui a réagit
return False, False 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) channel = client.get_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_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 if message.author.id != client.user.id or len(message.embeds) == 0: # vérification message du bot + au moins 1 embed

View file

@ -129,16 +129,3 @@ def ageLayout(tuple):
for i in affichage: for i in affichage:
message = message + f", {tuple[i]} {time[i]}" message = message + f", {tuple[i]} {time[i]}"
return message[2:] 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())

View file

@ -47,13 +47,6 @@ class ToDo(Database):
""" """
return self.affichageResultat(self.requete(requete, userID)) 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): 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.""" """Vérifie qu'un To Do appartiens à un utilisateur. Renvois False si le To Do n'existe pas."""
requete = """ requete = """