Compare commits

..

No commits in common. "master" and "31-ajouter-la-commande-schizo-pour-que-le-bot-change-de-personnalite-kabot-gaspard-by-zuzen" have entirely different histories.

34 changed files with 1161 additions and 865 deletions

View file

@ -1,29 +0,0 @@
stages:
- login
- build
- push
- deploy
variables:
GL_TOKEN: $GL_TOKEN
VERSION: '0.2.18'
deploy:
stage: deploy
script : sudo docker-compose --env-file /data/docker/compose-files/others.env -f /data/docker/compose-files/others.yml up -d
build:
stage: build
script:
- sudo docker build -t hub.0w.tf/milka64/kabot:$VERSION .
- sudo docker build -t hub.0w.tf/milka64/kabot:latest .
push:
stage: push
script:
- sudo docker push hub.0w.tf/milka64/kabot:$VERSION
- sudo docker push hub.0w.tf/milka64/kabot:latest
login:
stage: login
script: sudo docker login -u milka64 -p $GL_TOKEN hub.0w.tf

2
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
# Default ignored files
/workspace.xml

View file

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

8
.idea/kabot.iml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.7 (kivy_tuto)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

4
.idea/misc.xml Normal file
View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (kivy_tuto)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/kabot.iml" filepath="$PROJECT_DIR$/.idea/kabot.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View file

@ -1,12 +1,14 @@
FROM python:3.11
FROM alpine
WORKDIR /usr/src/kabot
ENV CONFIG_FILE=/data/config.ini
COPY kabot ./
COPY config.ini.sample /data/config.ini
COPY entrypoint.sh /
RUN apt update && apt install -y ffmpeg
RUN apt clean
RUN pip install --no-cache-dir /usr/src/kabot/
WORKDIR /app
VOLUME /data
CMD [ "/entrypoint.sh" ]
RUN apk add --update musl-dev python3-dev gcc python3 py3-pip git py3-lxml libxml2 libxml2-dev py3-pynacl ffmpeg\
&& pip3 install --upgrade pip \
&& pip3 install bs4 requests giphy_client discord.py python-gitlab\
&& git clone https://git.0w.tf/Milka64/kabot.git
WORKDIR /app/kabot
RUN pip3 install kabot/
RUN mkdir -p /var/log/kabot/
RUN chmod 777 /var/log/kabot
CMD kabot -c /data/config.ini

210
bootstrap-buildout.py Normal file
View file

@ -0,0 +1,210 @@
##############################################################################
#
# Copyright (c) 2006 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Bootstrap a buildout-based project
Simply run this script in a directory containing a buildout.cfg.
The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file.
"""
import os
import shutil
import sys
import tempfile
from optparse import OptionParser
__version__ = '2015-07-01'
# See zc.buildout's changelog if this version is up to date.
tmpeggs = tempfile.mkdtemp(prefix='bootstrap-')
usage = '''\
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
Bootstraps a buildout-based project.
Simply run this script in a directory containing a buildout.cfg, using the
Python that you want bin/buildout to use.
Note that by using --find-links to point to local resources, you can keep
this script from going over the network.
'''
parser = OptionParser(usage=usage)
parser.add_option("--version",
action="store_true", default=False,
help=("Return bootstrap.py version."))
parser.add_option("-t", "--accept-buildout-test-releases",
dest='accept_buildout_test_releases',
action="store_true", default=False,
help=("Normally, if you do not specify a --version, the "
"bootstrap script and buildout gets the newest "
"*final* versions of zc.buildout and its recipes and "
"extensions for you. If you use this flag, "
"bootstrap and buildout will get the newest releases "
"even if they are alphas or betas."))
parser.add_option("-c", "--config-file",
help=("Specify the path to the buildout configuration "
"file to be used."))
parser.add_option("-f", "--find-links",
help=("Specify a URL to search for buildout releases"))
parser.add_option("--allow-site-packages",
action="store_true", default=False,
help=("Let bootstrap.py use existing site packages"))
parser.add_option("--buildout-version",
help="Use a specific zc.buildout version")
parser.add_option("--setuptools-version",
help="Use a specific setuptools version")
parser.add_option("--setuptools-to-dir",
help=("Allow for re-use of existing directory of "
"setuptools versions"))
options, args = parser.parse_args()
if options.version:
print("bootstrap.py version %s" % __version__)
sys.exit(0)
######################################################################
# load/install setuptools
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
ez = {}
if os.path.exists('ez_setup.py'):
exec(open('ez_setup.py').read(), ez)
else:
exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
if not options.allow_site_packages:
# ez_setup imports site, which adds site packages
# this will remove them from the path to ensure that incompatible versions
# of setuptools are not in the path
import site
# inside a virtualenv, there is no 'getsitepackages'.
# We can't remove these reliably
if hasattr(site, 'getsitepackages'):
for sitepackage_path in site.getsitepackages():
# Strip all site-packages directories from sys.path that
# are not sys.prefix; this is because on Windows
# sys.prefix is a site-package directory.
if sitepackage_path != sys.prefix:
sys.path[:] = [x for x in sys.path
if sitepackage_path not in x]
setup_args = dict(to_dir=tmpeggs, download_delay=0)
if options.setuptools_version is not None:
setup_args['version'] = options.setuptools_version
if options.setuptools_to_dir is not None:
setup_args['to_dir'] = options.setuptools_to_dir
ez['use_setuptools'](**setup_args)
import setuptools
import pkg_resources
# This does not (always?) update the default working set. We will
# do it.
for path in sys.path:
if path not in pkg_resources.working_set.entries:
pkg_resources.working_set.add_entry(path)
######################################################################
# Install buildout
ws = pkg_resources.working_set
setuptools_path = ws.find(
pkg_resources.Requirement.parse('setuptools')).location
# Fix sys.path here as easy_install.pth added before PYTHONPATH
cmd = [sys.executable, '-c',
'import sys; sys.path[0:0] = [%r]; ' % setuptools_path +
'from setuptools.command.easy_install import main; main()',
'-mZqNxd', tmpeggs]
find_links = os.environ.get(
'bootstrap-testing-find-links',
options.find_links or
('http://downloads.buildout.org/'
if options.accept_buildout_test_releases else None)
)
if find_links:
cmd.extend(['-f', find_links])
requirement = 'zc.buildout'
version = options.buildout_version
if version is None and not options.accept_buildout_test_releases:
# Figure out the most recent final version of zc.buildout.
import setuptools.package_index
_final_parts = '*final-', '*final'
def _final_version(parsed_version):
try:
return not parsed_version.is_prerelease
except AttributeError:
# Older setuptools
for part in parsed_version:
if (part[:1] == '*') and (part not in _final_parts):
return False
return True
index = setuptools.package_index.PackageIndex(
search_path=[setuptools_path])
if find_links:
index.add_find_links((find_links,))
req = pkg_resources.Requirement.parse(requirement)
if index.obtain(req) is not None:
best = []
bestv = None
for dist in index[req.project_name]:
distv = dist.parsed_version
if _final_version(distv):
if bestv is None or distv > bestv:
best = [dist]
bestv = distv
elif distv == bestv:
best.append(dist)
if best:
best.sort()
version = best[-1].version
if version:
requirement = '=='.join((requirement, version))
cmd.append(requirement)
import subprocess
if subprocess.call(cmd) != 0:
raise Exception(
"Failed to execute command:\n%s" % repr(cmd)[1:-1])
######################################################################
# Import and run buildout
ws.add_entry(tmpeggs)
ws.require(requirement)
import zc.buildout.buildout
if not [a for a in args if '=' not in a]:
args.append('bootstrap')
# if -c was provided, we push it back into args for buildout' main function
if options.config_file is not None:
args[0:0] = ['-c', options.config_file]
zc.buildout.buildout.main(args)
shutil.rmtree(tmpeggs)

45
buildout.cfg Normal file
View file

@ -0,0 +1,45 @@
[buildout]
show-picked-versions = true
extends = pinned.cfg
package = kabot
develop =
kabot
mr-dev/discord
mr-dev/giphy
parts +=
kabot
doc
extensions = mr.developer
sources-dir = mr-dev
auto-checkout =
discord
giphy
[kabot]
recipe = zc.recipe.egg
eggs =
${buildout:package}
cookiecutter
discord.py
PyNaCl
requests
giphy_client
python-gitlab
interpreter = python
[doc]
recipe = zc.recipe.egg
eggs =
${buildout:package}
[sources]
discord = git https://github.com/Rapptz/discord.py.git
giphy = git https://github.com/Giphy/giphy-python-client.git
[logging]
logger_root_level = DEBUG

View file

@ -1,6 +1,6 @@
[DEFAULT]
logs = /var/log/kabot.log
logs = /var/log/kabot/kabot.log
audio_path = /tmp/
voice_channel = channel_name
text_channel = channel_name

View file

@ -1,3 +0,0 @@
#!/bin/sh
kabot -c $CONFIG_FILE

15
kabot/.github/ISSUE_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,15 @@
* Kabot version:
* Python version:
* Operating System:
### Description
Describe what you were trying to get done.
Tell us what happened, what went wrong, and what you expected to happen.
### What I Did
```
Paste the command(s) you ran and the output.
If there was a crash, please include the traceback here.
```

View file

@ -3,7 +3,6 @@ include CONTRIBUTING.rst
include HISTORY.rst
include LICENSE
include README.rst
include kabot/utils/ressources/*
recursive-include tests *
recursive-exclude * __pycache__

88
kabot/Makefile Normal file
View file

@ -0,0 +1,88 @@
.PHONY: clean clean-test clean-pyc clean-build docs help
.DEFAULT_GOAL := help
define BROWSER_PYSCRIPT
import os, webbrowser, sys
try:
from urllib import pathname2url
except:
from urllib.request import pathname2url
webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1])))
endef
export BROWSER_PYSCRIPT
define PRINT_HELP_PYSCRIPT
import re, sys
for line in sys.stdin:
match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line)
if match:
target, help = match.groups()
print("%-20s %s" % (target, help))
endef
export PRINT_HELP_PYSCRIPT
BROWSER := python -c "$$BROWSER_PYSCRIPT"
help:
@python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)
clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts
clean-build: ## remove build artifacts
rm -fr build/
rm -fr dist/
rm -fr .eggs/
find . -name '*.egg-info' -exec rm -fr {} +
find . -name '*.egg' -exec rm -f {} +
clean-pyc: ## remove Python file artifacts
find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +
find . -name '__pycache__' -exec rm -fr {} +
clean-test: ## remove test and coverage artifacts
rm -fr .tox/
rm -f .coverage
rm -fr htmlcov/
rm -fr .pytest_cache
lint: ## check style with flake8
flake8 kabot tests
test: ## run tests quickly with the default Python
python setup.py test
test-all: ## run tests on every Python version with tox
tox
coverage: ## check code coverage quickly with the default Python
coverage run --source kabot setup.py test
coverage report -m
coverage html
$(BROWSER) htmlcov/index.html
docs: ## generate Sphinx HTML documentation, including API docs
rm -f docs/kabot.rst
rm -f docs/modules.rst
sphinx-apidoc -o docs/ kabot
$(MAKE) -C docs clean
$(MAKE) -C docs html
$(BROWSER) docs/_build/html/index.html
servedocs: docs ## compile the docs watching for changes
watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .
release: dist ## package and upload a release
twine upload dist/*
dist: clean ## builds source and wheel package
python setup.py sdist
python setup.py bdist_wheel
ls -l dist
install: clean ## install the package to the active Python's site-packages
python setup.py install

View file

@ -1,40 +1,590 @@
# This example requires the 'message_content' privileged intent to function.
# -*- coding: utf-8 -*-
"""Main module."""
from __future__ import unicode_literals
import aiocron
import asyncio
import discord
import yt_dlp as youtube_dl
import giphy_client
import gitlab
import logging
import lxml
import os
import random
import requests
import youtube_dl
import configparser
import argparse
import typing
import functools
from discord.ext import commands
from kabot.utils.audio import *
from kabot.utils.texte import *
from bs4 import BeautifulSoup as bs
from discord.ext import tasks, commands
from giphy_client.rest import ApiException
from logging.handlers import RotatingFileHandler
from pathlib import Path
from subprocess import *
from sys import argv,exit, exc_info
here = os.path.dirname(os.path.abspath(__file__))
## création de l'objet logger
logger = logging.getLogger()
## definition du log level
logger.setLevel(logging.INFO)
## format du log
formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')
## definition de l'affichage des logs dans la console
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
logger.addHandler(stream_handler)
class Mybot(commands.Cog):
#Fonctions necesaires pour Kabot.
def __init__(
self,
bot,
gl_url=None,
gl_token=None,
gif_token=None,
audio_path=None,
nickname=None,
voice_channel=None,
text_channel=None,
):
self.gl_url = gl_url
self.audio_path = audio_path
self.gl_token = gl_token
self.gif_token = gif_token
self.voice_channel = voice_channel
self.text_channel = text_channel
self.bot = bot
self.sounds = []
self.nickname = nickname
self.sounds_history = []
self.play_next.start()
intents = discord.Intents.all()
intents.message_content = True
@tasks.loop(seconds=1.5)
async def play_next(self):
if self.sounds:
audio_file, ctx = self.sounds[0]
source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(audio_file))
if not ctx.voice_client.is_playing() and ctx.voice_client.is_connected():
ctx.voice_client.play(source, after=lambda e: print('Player error: %s' % e) if e else None)
self.sounds.pop(0)
self.sounds_history.reverse()
self.sounds_history.append((audio_file, ctx))
self.sounds_history.reverse()
if len(self.sounds_history) > 5:
self.sounds_history = self.sounds_history[:5]
#Fin des fonctions necesaire pour Kabot.
bot = commands.Bot(
command_prefix="!",
description='''A ROULEEEEETTES !!
HOULA... J'l'ai un peu trop gueulé ça, non ?
A roulettes.''',
intents=intents,
)
#Les commandes pour interagir avec Kabot.
@commands.command(help='Clear sound queue')
async def clear(self, ctx):
self.sounds = []
@commands.command(help='list des commits')
async def commits(self, ctx, number = 5):
if self.gl_url and self.gl_token:
number = int(number)
gl = gitlab.Gitlab(self.gl_url, self.gl_token)
gl.auth()
projects = gl.projects.list(search='Kabot')[0]
commits = projects.commits.list(all=True)[:number]
for commit in commits:
detail = commit.attributes
await ctx.channel.send("__" + detail['author_name'] + "__: " + detail['title'] + '\n' + detail['web_url'])
else:
await ctx.channel.send("-_-")
@bot.event
async def on_ready():
print(f'Logged in as {bot.user} (ID: {bot.user.id})')
print('------')
@commands.command(help='clear cache youtube dl')
async def cache_clear(self, ctx):
fichiers = os.listdir('/tmp')
for fichier in fichiers:
if fichier.startswith('discord'):
os.remove("/tmp/" + fichier)
@commands.command()
async def leave(self, ctx):
if ctx.voice_client and ctx.voice_client.is_connected():
await ctx.guild.voice_client.disconnect()
@commands.command(help="Interrogation issues \n Args: list, search[mot clé] et add[nom de l'issue]")
async def issue(self, ctx, *args):
if self.gl_url and self.gl_token:
if args:
args = list(args)
gl = gitlab.Gitlab(self.gl_url, self.gl_token)
gl.auth()
if args[0] == 'list':
projects = gl.projects.list(search='Kabot')[0]
issues = projects.issues.list()
for issue in issues:
if "closed" == issue.state:
pass
else:
await ctx.channel.send('#' + str(issue.id) + ": " + issue.title + '\n' + issue.web_url)
elif args[0] == 'search':
query = ''.join(args[1:])
project = gl.projects.list(search='Kabot')[0]
find_issues = project.search("issues", query)
for issue in find_issues:
await ctx.channel.send("#" + str(issue['id']) + ": " + issue['title'] + '\n' + issue['web_url'])
elif args[0] == 'add':
title = ' '.join(args[1:])
author = title + ' - By ' + ctx.message.author.name
projects = gl.projects.list()
for project in projects:
if "Kabot" == project.name:
issue = project.issues.create({'title': author})
logger.info("Issue created : %s" % issue.web_url)
else:
await ctx.channel.send('unknown command')
@commands.command()
async def join(self, ctx):
channel = [x for x in self.bot.get_all_channels() if x.name == self.voice_channel][0]
await channel.connect()
await asyncio.sleep(2)
@commands.command(help="detail du dernier son joué")
async def last(self, ctx, number = 1):
number = int(number)
for sound in self.sounds_history[0:number]:
await ctx.channel.send("```"+str(sound[0])+"```")
@commands.command(help='count lines numbers in quote file')
async def lines(self, ctx):
path = '/data/log/%s.log' % ctx.channel
with open(path, 'r') as f:
lines = f.read().splitlines()
nb_lines = len(lines)
with ctx.channel.typing():
await asyncio.sleep(0.5)
await ctx.channel.send("j'ai %s lignes dans mon stock" % nb_lines)
@commands.command(help='check if bot always online')
async def ping(self, message):
await message.channel.send('pong')
@commands.command(help='Restart Bot')
async def restart(self, ctx):
cmd = self.bot.get_command('leave')
await cmd.invoke(ctx)
await self.bot.close()
exit()
@commands.command(help='Update local repo')
async def update(self, message):
output = Popen('git pull'.split(), stdout=PIPE).communicate()[0]
cmd_audio = "git -C %s pull" % self.audio_path
output += Popen(cmd_audio.split(), stdout=PIPE).communicate()[0]
await message.channel.send(output.decode('utf-8'))
#Fin des commandes pour interagir avec Kabot.
#Les commandes pour faire mumuse avec Kabot.
@commands.command(help="randomsur l'avenir des gens.")
async def avenir(self, ctx):
list_mot = ("tu seras curé, tu t'occuperas plus spécialement du catéchisme. ",
"tu seras animateur de soirées pour les gays pride. ",
"tu seras gynecologue dans une maison de retraite.",
"tu iras vivre en thaïland à cause de ton job. car tu seras ladyboy dans un bar.",
"tu sera DSI chez jacky et Michel",
"tu seras arroseur de plante aquatique.")
choix = random.choice(list_mot)
with ctx.channel.typing():
await asyncio.sleep(len(choix) / 4)
await ctx.channel.send(choix)
@commands.command(help='Faire des choix')
async def choice(self, ctx, *words):
choices = random.choice(words)
await ctx.channel.send(choices)
@commands.command(help="optionnal args : ")
async def contrepeterie(self, ctx, *args):
response = None
path = here + '/ressources/contrepeteries.txt'
with open(path) as file:
lines = file.read().splitlines()
myline = random.choice(lines)
question, reponse = myline.split(";")
try:
response = '''Question ! : %s Réponse : ||%s||''' % (question, reponse)
except:
response = "Unknow error, try: !contrepeterie [mot clef]"
await ctx.send(response)
@commands.command(help='Gif me')
async def gif(self, ctx):
query = ctx.message.content.replace('!gif ', '')
api_instance = giphy_client.DefaultApi()
api_key = self.gif_token
lang = 'fr'
if api_key:
try:
api_response = api_instance.gifs_search_get(api_key, query, lang=lang, limit=15)
api_response.to_dict()['data'][0]
get_url = random.choice(api_response.to_dict()['data'])
get_url['url']
await ctx.channel.send(get_url['url'])
except ApiException as e:
await ctx.channel.send("Exception when calling DefaultApi->gifs_search_get: %s\n" % e)
else:
await ctx.channel.send("Exception : No api key found")
@commands.guild_only()
@commands.command()
async def joke(self, ctx, folder=None):
try:
user = ctx.message.author.name
if not folder or not ctx.message.content:
audio_file = random.choice([f"{f}" for f in Path(self.audio_path + '/').glob('**/*.mp3')])
else:
folder = folder.lower()
audio_file = [f"{f}" for f in Path(self.audio_path + '/').glob('**/*.mp3') if folder in str(f).lower()]
if not audio_file:
ctx.channel.send("%s not found" % folder)
else:
audio_file = random.choice(audio_file)
self.sounds.append((audio_file, ctx))
except:
e = exc_info()[0]
await ctx.channel.send("Exception when calling joke: %s\n" % e)
async def main():
## création de l'objet logger
logger = logging.getLogger()
## definition du log level
logger.setLevel(logging.INFO)
@commands.command(help="optionnal args : [livre] [character]")
async def kaamelott(self, ctx, *args):
response = None
url = 'https://kaamelott.chaudie.re/api/random'
if args and ctx.message.content:
args = list(args)
if args[0].isdigit():
livre = int(args[0])
args.pop(0)
elif args[-1].isdigit():
livre = int(args[-1])
args.pop(-1)
else:
livre = None
if args:
perso = ' '.join(args)
if perso and livre:
url = 'https://kaamelott.chaudie.re/api/random/livre/%s/personnage/%s' % (livre, perso)
elif perso:
url = 'https://kaamelott.chaudie.re/api/random/personnage/%s' % perso
else:
url = 'https://kaamelott.chaudie.re/api/random/livre/%s' % livre
try:
citation = requests.get(url).json()['citation']
response = "%s :\n```\n%s\n```" % (citation['infos']['personnage'], citation['citation'])
except:
response = "Unknow error, try: !kaamelott [livre] [character]"
await ctx.send(response)
@commands.command(help="Je menotte une cornemuse et je fume Eddy Malou")
async def kamoulox(self, ctx):
sans_verbe = get_word('nom').text + " " + get_word('complement').get('m') + " et " + get_word('nom').text + " " + get_word('complement').get('m') + "."
nom1 = get_word('nom')
nom2 = get_word('nom')
un1 = "un"
un2 = "un"
if nom1.get('gender') == 'F':
un1 = "une"
if nom2.get('gender') == 'F':
un2 = "une"
phrase1 = get_word('verbe').text + " " + un1 + " " + nom1.text + " " + random.choice([get_word('complement').get('m'), ""])
phrase2 = get_word('verbe').text + " " + un2 + " " + nom2.text + " " + random.choice([get_word('complement').get('m'), ""])
avec_verbe = phrase1 + " et " + phrase2 + "."
piece = random.choice(['pile', 'face'])
if piece == "pile":
result = sans_verbe
elif piece == "face":
result = avec_verbe
with ctx.channel.typing():
await asyncio.sleep(len(result)/6)
await ctx.send(result)
@commands.command(help="Toi tu fermes ta gueule! Tu la fermes définitivement")
async def mute(self, ctx, member: discord.Member=None, mute_time = 10):
if member.voice.mute:
with ctx.channel.typing():
await asyncio.sleep(1)
await ctx.channel.send("Tu ne vas pas m'avoir si facilement")
return
if not member:
with ctx.channel.typing():
await asyncio.sleep(1)
await ctx.channel.send("Qui veux-tu mute?")
return
if mute_time > 60:
with ctx.channel.typing():
await asyncio.sleep(1)
await ctx.channel.send("Doucement sur le temps!")
return
member = ctx.message.mentions[0]
await member.edit(mute=True)
with ctx.channel.typing():
await asyncio.sleep(1)
await ctx.send("Tu sors %s!" % member.mention)
await asyncio.sleep(mute_time)
await member.edit(mute=False)
with ctx.channel.typing():
await asyncio.sleep(1)
await ctx.channel.send("Tu peux reparler %s!" % member.mention)
@commands.command(help="Jouer un song a partir d'une video")
async def play(self, ctx, url):
ydl_opts = {'format': 'bestaudio/mp3', 'outtmpl': '/tmp/discord_%(title)s-%(id)s.%(ext)s',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
info_dict = ydl.extract_info(url, download=False)
out_file = ydl.prepare_filename(info_dict)
extension = out_file.split('.')[-1]
out_file = out_file.replace(extension, 'mp3')
if not os.path.isfile(out_file):
await asyncio.get_running_loop().run_in_executor(None, ydl.download,[url])
self.sounds.append((out_file, ctx))
@commands.command()
async def repeat(self, ctx):
# if ctx.message.author.name == self.bot.user.name:
# return
user = ctx.message.author.name
source = self.sounds_history[0]
self.sounds.append(source)
@commands.command(help="Appuie sur la detente PUSSY!")
async def roulette(self, ctx):
mute_time = 60
member = ctx.message.author
barillet = [False, False, True, False, False]
bullet = random.choice(barillet)
await self.joke(ctx, "spinning_and_closed.mp3")
if bullet == True:
await self.joke(ctx, "omawa_shindeiru.mp3")
await asyncio.sleep(2)
await member.edit(mute=True)
with ctx.channel.typing():
await asyncio.sleep(3)
await ctx.channel.send("Perdu, tu es mute pendant 60 secondes!")
else:
await self.joke(ctx, "hammer_and_dry.mp3")
with ctx.channel.typing():
await asyncio.sleep(3)
await ctx.channel.send("Gagné, tu ne seras pas mute!")
return
await asyncio.sleep(mute_time)
await member.edit(mute=False)
with ctx.channel.typing():
await asyncio.sleep(0.5)
await ctx.channel.send("Tu peux reparler %s!" % member.mention)
@commands.dm_only()
@commands.command(help="Faire dire des choses au bot")
async def say(self, ctx, *message):
sentence = ' '.join(message)
channel = [x for x in self.bot.get_all_channels() if x.name == self.text_channel][0]
guild = self.bot.guilds[0]
if sentence.startswith('!'):
command_name = sentence.split()[0].replace('!', '')
cmd = self.bot.get_command(command_name)
ctx.channel = channel
ctx.guild = guild
for word in sentence.split():
if word.startswith('@'):
members = guild.members
for member in members:
if member.name == word[1:]:
sentence = sentence.replace(word, member.mention)
ctx.message = sentence
await cmd.invoke(ctx)
else:
for word in sentence.split():
if word.startswith('@'):
members = guild.members
for member in members:
if member.name == word[1:]:
sentence = sentence.replace(word, member.mention)
await channel.send(sentence)
@commands.command(help='Who the fuck am i?')
async def schizo(self, ctx, *names):
name = ' '.join(names)
list_name = ["Kabot", "Gaspard et Balthazar", "Bender", "Zoidberg", "Gunther"]
try:
current_name = self.bot.user.name
list_name.remove(current_name)
except:
pass
if not name:
name = random.choice(list_name)
lower_names = [x.lower() for x in list_name]
if name.lower() in lower_names:
if name:
correct_name = [x for x in list_name if x.lower() in name.lower()][0]
name = correct_name
await self.bot.user.edit(username=name)
else:
name = "404"
await self.bot.user.edit(username="Error 404 name not found!")
await ctx.channel.send("Liste des noms = %s" % list_name)
img = open(here + "/ressources/avatar_bot/%s.jpg" % name, 'rb')
await self.bot.user.edit(avatar=img.read())
await self.joke(ctx, name)
@commands.command(help='slap this ass')
async def slap(self, ctx, user=None):
slap_multiple = [
"%s prend un coup de pied au cul",
"Descente du coude sur %s",
"%s est propulsé par dessus la TROISIEME CORDE!",
"Le mec en rose, c'est moi et le mec en jaune c'est %s! https://giphy.com/gifs/gSIz6gGLhguOY",
]
if not user or not ctx.message.mentions:
online_members = []
members = ctx.guild.members
for member in members:
if str(member.status) == "online":
online_members.append(member)
user = random.choice(online_members)
user = user.mention
elif ctx.message.mentions:
user = ctx.message.mentions[0]
user = user.mention
if user == self.bot.user.mention:
with ctx.channel.typing():
await asyncio.sleep(0.5)
await ctx.channel.send("je tribuche par terre et je sais pas comment")
else:
with ctx.channel.typing():
await asyncio.sleep(len(slap_multiple) / 4)
await ctx.channel.send(random.choice(slap_multiple) % user)
@commands.command()
async def welcome(self, ctx):
# if ctx.message.author.name == self.bot.user.name:
# return
user = ctx.message.author.name
print(user)
try:
audio_file = random.choice([f for f in os.listdir(self.audio_path + '/%s/' % user) if f.endswith('.mp3')])
audio_file = self.audio_path + '/%s/' % user + audio_file
except:
audio_file = random.choice([f"{f}" for f in Path(self.audio_path + '/').glob('**/*.mp3')])
self.sounds.append((audio_file, ctx))
#Fin des commandes pour faire mumuse avec Kabot.
#Commandes pour troll.
@commands.command(help='Troll commands', hidden=True)
async def jke(self, ctx):
await ctx.channel.send(trollpower())
@commands.command(help='Troll commands', hidden=True)
async def joe(self, ctx):
await ctx.channel.send(trollpower())
@commands.command(help='Troll commands', hidden=True)
async def jok(self, ctx):
await ctx.channel.send(trollpower())
@commands.command(help='Troll commands', hidden=True)
async def joker(self, ctx):
await ctx.channel.send(trollpower(too_long=True))
@commands.command(help='Troll commands', hidden=True)
async def oke(self, ctx):
await ctx.channel.send(trollpower())
@commands.command(help='Troll commands', hidden=True)
async def okre(self, ctx):
await self.joke(ctx, "tu_dois_tout_donner.mp3")
#Fin des commandes pour troll.
def trollpower(too_long=None):
if too_long:
return("Bah alors, on sait plus écrire, je te donne un indice: t'as une lettre en trop! :sweat_drops: :tongue:")
return('Bah alors, on sait plus écrire, je te donne un indice: il te manque une lettre! :sweat_drops: :tongue:')
def get_word(word_type):
"""Chercher les mots pour la fonction kamoulox dans le fichier xml"""
content = []
with open(here + "/ressources/base_kml.xml", "r", encoding="ISO-8859-1") as file:
content = file.readlines()
content = "".join(content)
bs_content = bs(content, 'lxml')
if word_type == 'nom':
nom = bs_content.resources.nom.find_all('word')
result = random.choice(nom)
return result
elif word_type == 'nom_propre':
nom_propre = bs_content.resources.nompropre.find_all('word')
result = random.choice(nom_propre)
return result
elif word_type == 'verbe':
verbe = bs_content.resources.verbe.find_all('word')
result = random.choice(verbe)
return result
elif word_type == 'complement':
complement = bs_content.resources.complement.find_all('word')
result = random.choice(complement)
return result
elif word_type == 'nom_special':
nom_special = bs_content.resources.complement.find_all('word')
result = random.choice(nom_special)
return result
elif word_type == 'prenom':
prenom = bs_content.resources.prenom.find_all('word')
result = random.choice(prenom)
return result
elif word_type == 'prescuse':
prescuse = bs_content.resources.prescuse.find_all('word')
result = random.choice(prescuse)
return result
elif word_type == 'scuse1':
scuse1 = bs_content.resources.scuse1.find_all('word')
result = random.choice(scuse1)
return result
elif word_type == 'scuse2':
scuse2 = bs_content.resources.scuse2.find_all('word')
result = random.choice(scuse2)
return result
elif word_type == 'presulte':
presulte = bs_content.resources.presulte.find_all('word')
result = random.choice(presulte)
return result
elif word_type == 'sulte':
sulte = bs_content.resources.sulte.find_all('word')
result = random.choice(sulte)
return result
elif word_type == 'postsulte':
postsulte = bs_content.resources.presulte.find_all('word')
result = random.choice(postsulte)
return result
elif word_type == 'mail':
mail = bs_content.resources.mail.find_all('word')
result = random.choice(mail)
return result
else:
result = 'Nique bien ta mère!'
return result
#Le do[main]e de Kabot.
def main():
logger.info("Initialisation de Kabot")
parser = argparse.ArgumentParser()
parser.add_argument(
"-c",
@ -51,7 +601,6 @@ async def main():
log_file = config['DEFAULT']['logs']
## definition du fichier de log (chemin, level, etc ...)
formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')
file_handler = RotatingFileHandler(log_file, 'a', 1000000, 1)
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(formatter)
@ -74,28 +623,118 @@ async def main():
gl_url = config['gitlab']['url']
gl_token = config['gitlab']['token']
gif_token = config['giphy']['token']
async with bot:
await bot.add_cog(
Audio(
bot,
voice_chan=voice_channel,
text_chan=text_channel,
audio_path=audio_path,
)
)
await bot.add_cog(
Texte(
bot,
gif_token=gif_token,
gl_token=gl_token,
gl_url=gl_url,
text_chan=text_channel,
)
)
await bot.start(token)
bot = commands.Bot(
command_prefix='!',
)
test = False
if "test" in argv[-1]:
test=True
@aiocron.crontab('50 9-23/1 * * *')
async def kron():
kron_choice = random.choice(["kaamelott", "slap", "kamoulox", "contrepeterie", "schizo", False, False, False, False, False, False])
if kron_choice:
await asyncio.sleep(random.choice(range(3550)))
for channel in bot.get_all_channels():
if channel.name == text_channel:
current_chan = channel
ctx = await bot.get_context(current_chan.last_message)
ctx.message.content = ""
print(ctx.message.content)
random_cmd = bot.get_command(kron_choice)
await random_cmd.invoke(ctx)
@bot.event
async def on_message(message):
print(message.content)
if message.author == bot.user:
return
else:
if bot.user in message.mentions \
and len(message.mentions) < 3 \
and len(message.content.splitlines()) == 1:
path = '/data/log/%s.log' % message.channel
with open(path, 'r') as f:
lines = f.read().splitlines()
if not message.content in lines:
with open(path, 'a') as f:
f.write(message.content + '\n')
response = random.choice(lines).replace(str(bot.user.id), str(message.author.id))
if response.startswith('!'):
command_name = response.split()[0].replace('!', '')
cmd = bot.get_command(command_name)
await cmd.invoke(message)
else:
with message.channel.typing():
if "http" in response:
await asyncio.sleep(len(response) / 8)
else:
await asyncio.sleep(len(response) / 6)
await message.channel.send(response)
await bot.process_commands(message)
@bot.event
async def on_ready():
print('yeah baby!')
if test:
await bot.close()
for channel in bot.get_all_channels():
if channel.name == text_channel:
current_chan = channel
if nickname:
await bot.user.edit(nick=nickname)
await current_chan.send('Le troll est dans la place !')
ctx = await bot.get_context(current_chan.last_message)
join = bot.get_command('join')
await join.invoke(ctx)
for channel in bot.get_all_channels():
if channel.name == voice_channel:
for member in channel.members:
await member.edit(mute=False)
@bot.event
async def on_voice_state_update(member, before, after):
if before.channel is None and after.channel:
for channel in bot.get_all_channels():
if channel.name == text_channel:
current_chan = channel
ctx = await bot.get_context(current_chan.last_message)
ctx.message.author = member
welcome = bot.get_command('welcome')
await asyncio.sleep(2)
await welcome.invoke(ctx)
@aiocron.crontab('*/5 * * * *')
async def pipelette():
for channel in bot.get_all_channels():
if channel.name == voice_channel and\
len(channel.members) > 1 and\
random.choice([True,True,True]):
for channel in bot.get_all_channels():
if channel.name == text_channel:
current_chan = channel
await asyncio.sleep(random.choice(range(350)))
ctx = await bot.get_context(current_chan.last_message)
ctx.message.content = ""
joke = bot.get_command('joke')
await joke.invoke(ctx)
bot.add_cog(
Mybot(
bot,
gl_url=gl_url,
gl_token=gl_token,
gif_token=gif_token,
audio_path=audio_path,
nickname=nickname,
voice_channel=voice_channel,
text_channel=text_channel,
)
)
bot.run(token)
def run():
asyncio.run(main())
if __name__ == "__main__":
run()
main()

View file

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View file

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

View file

@ -1 +0,0 @@
##

View file

@ -1,317 +0,0 @@
# This example requires the 'message_content' privileged intent to function.
import asyncio
import discord
import yt_dlp as youtube_dl
import random
import os
from discord.ext import commands, tasks
from pathlib import Path
# Suppress noise about console usage from errors
youtube_dl.utils.bug_reports_message = lambda: ''
ytdl_format_options = {
'format': 'bestaudio/mp3',
'outtmpl': '/tmp/discord_%(title)s-%(id)s.%(ext)s',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}]
}
ffmpeg_options = {
'options': '-vn',
}
ytdl = youtube_dl.YoutubeDL(ytdl_format_options)
class YTDLSource(discord.PCMVolumeTransformer):
def __init__(self, source, *, data, volume=0.5):
super().__init__(source, volume)
self.data = data
self.title = data.get('title')
self.url = data.get('url')
@classmethod
async def from_url(cls, url, *, loop=None, stream=False):
loop = loop or asyncio.get_event_loop()
data = await loop.run_in_executor(None, lambda: ytdl.extract_info(url, download=not stream))
if 'entries' in data:
# take first item from a playlist
data = data['entries'][0]
filename = data['url'] if stream else ytdl.prepare_filename(data)
extension = filename.split('.')[-1]
filename = filename.replace(extension, 'mp3')
return cls(discord.FFmpegPCMAudio(filename, **ffmpeg_options), data=data)
@classmethod
async def from_file(cls, audio_file, ctx, *, loop=None, stream=False):
source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(audio_file,**ffmpeg_options))
ctx.voice_client.play(source, after=lambda e: print('Player error: %s' % e) if e else None)
class Audio(commands.Cog, name="Commandes Audio"):
def __init__(
self,
bot,
audio_path=None,
voice_chan=None,
text_chan=None):
self.bot = bot
self.sounds = []
self.voice_chan = voice_chan
self.text_chan = text_chan
self.audio_path = audio_path
self.sounds_history = []
@commands.Cog.listener()
async def on_voice_state_update(self, member, before, after):
if before.channel is None and after.channel:
for channel in self.bot.get_all_channels():
if channel.name == self.text_chan:
current_chan = channel
async for msg in current_chan.history(limit=1):
last_message = msg
ctx = await self.bot.get_context(last_message)
ctx.message.author = member
#welcome = bot.get_command('welcome')
await asyncio.sleep(2)
await self.welcome(ctx, member.display_name)
@commands.Cog.listener()
async def on_ready(self):
self.play_next.start()
self.pipelette.start()
if self.voice_chan:
await self.join(self.voice_chan)
#await self.welcome(None, 'kabot')
@commands.command(help="Toi tu fermes ta gueule! Tu la fermes définitivement")
async def mute(self, ctx, member: discord.Member=None, mute_time = 10):
if member.voice.mute:
async with ctx.channel.typing():
await asyncio.sleep(1)
await ctx.channel.send("Tu ne vas pas m'avoir si facilement")
return
if not member:
async with ctx.channel.typing():
await asyncio.sleep(1)
await ctx.channel.send("Qui veux-tu mute?")
return
if mute_time > 60:
async with ctx.channel.typing():
await asyncio.sleep(1)
await ctx.channel.send("Doucement sur le temps!")
return
member = ctx.message.mentions[0]
await member.edit(mute=True)
async with ctx.channel.typing():
await asyncio.sleep(1)
await ctx.send("Tu sors %s!" % member.mention)
await asyncio.sleep(mute_time)
await member.edit(mute=False)
async with ctx.channel.typing():
await asyncio.sleep(1)
await ctx.channel.send("Tu peux reparler %s!" % member.mention)
@commands.command(help="Appuie sur la detente PUSSY!")
async def roulette(self, ctx):
mute_time = 60
member = ctx.message.author
if not member.voice:
async with ctx.typing():
await ctx.channel.send("You're not in voice channel")
return
barillet = [False, False, True, False, False]
bullet = random.choice(barillet)
await self.joke(ctx, "spinning_and_closed.mp3")
if bullet == True:
await self.joke(ctx, "omawa_shindeiru.mp3")
await asyncio.sleep(2)
await member.edit(mute=True)
async with ctx.typing():
await asyncio.sleep(3)
await ctx.channel.send("Perdu, tu es mute pendant 60 secondes!")
else:
await self.joke(ctx, "hammer_and_dry.mp3")
async with ctx.typing():
await asyncio.sleep(3)
await ctx.channel.send("Gagné, tu ne seras pas mute!")
return
await asyncio.sleep(mute_time)
await member.edit(mute=False)
async with ctx.typing():
await asyncio.sleep(0.5)
await ctx.channel.send("Tu peux reparler %s!" % member.mention)
@tasks.loop(seconds=300)
async def pipelette(self):
for channel in self.bot.get_all_channels():
if channel.name == self.voice_chan and\
len(channel.members) > 1 and\
random.choice([True,True,True]):
for chan in self.bot.get_all_channels():
if chan.name == self.text_chan:
current_chan = chan
await asyncio.sleep(random.choice(range(305)))
async for msg in current_chan.history(limit=1):
last_message = msg
ctx = await self.bot.get_context(last_message)
ctx.message.content = ""
await self.joke(ctx)
@tasks.loop(seconds=1)
async def play_next(self):
connected_voice = [chan for chan in self.bot.voice_clients if chan.is_connected()]
if connected_voice:
if not [chan for chan in connected_voice if chan.is_playing()]:
if self.sounds:
audio_type, audio_file, ctx = self.sounds[0]
if 'url' in audio_type:
player = await YTDLSource.from_url(audio_file, loop=self.bot.loop)
ctx.voice_client.play(player, after=lambda e: print(f'Player error: {e}') if e else None)
elif 'file' in audio_type:
player = await YTDLSource.from_file(audio_file, ctx)
last_audio = self.sounds.pop(0)
self.sounds_history.reverse()
self.sounds_history.append(last_audio)
self.sounds_history.reverse()
if len(self.sounds_history) > 5:
self.sounds_history = self.sounds_history[:5]
@commands.command(help='Troll commands', hidden=True)
async def okre(self, ctx):
await self.joke(ctx, "tu_dois_tout_donner.mp3")
@commands.command(help='Clear sound queue')
async def clear(self, ctx):
self.sounds = []
@commands.command()
async def welcome(self, ctx, user=None):
"""Joue le son d'accueil de l'utilisateur"""
if not user:
user = ctx.message.author.name
try:
audio_file = random.choice([f for f in os.listdir(self.audio_path + '%s/' % user) if f.endswith('.mp3')])
audio_file = self.audio_path + '/%s/' % user + audio_file
except:
audio_file = random.choice([f for f in Path(self.audio_path + '/').glob('**/*.mp3')])
self.sounds.append(('file', audio_file, ctx))
@commands.command()
async def repeat(self, ctx):
"""Rejouer le dernier son joué"""
user = ctx.message.author.name
source = self.sounds_history[0]
self.sounds.append(source)
@commands.command(help="detail du dernier son joué")
async def last(self, ctx, number = 1):
number = int(number)
for sound in self.sounds_history[0:number]:
await ctx.channel.send("```"+str(sound[1])+"```")
@commands.command()
async def join(self, chan_name: discord.VoiceChannel):
"""Joins a voice channel"""
#if ctx.voice_client is not None:
# return await ctx.voice_client.move_to(channel)
channel = [x for x in self.bot.get_all_channels() if x.name == chan_name][0]
return await channel.connect()
await channel.connect()
@commands.command()
async def play(self, ctx, *, url):
"""Plays from a url (almost anything youtube_dl supports)"""
self.sounds.append(('url',url,ctx))
@commands.command()
async def stream(self, ctx, *, url):
"""Streams from a url (same as yt, but doesn't predownload)"""
async with ctx.typing():
player = await YTDLSource.from_url(url, loop=self.bot.loop, stream=True)
ctx.voice_client.play(player, after=lambda e: print(f'Player error: {e}') if e else None)
await ctx.send(f'Now playing: {player.title}')
@commands.command()
async def stop(self, ctx):
"""Stoppe la lecture en cours"""
await ctx.voice_client.stop()
@commands.command()
async def volume(self, ctx, volume: int):
"""Changes the player's volume"""
if ctx.voice_client is None:
return await ctx.send("Not connected to a voice channel.")
ctx.voice_client.source.volume = volume / 100
await ctx.send(f"Changed volume to {volume}%")
@commands.command()
async def leave(self, ctx):
"""Stops and disconnects the bot from voice"""
await ctx.voice_client.disconnect()
@commands.command()
async def find(self, ctx, query):
"""Cherche un son dans la bibliothèque (5 resultat max)"""
query = query.lower()
audio_files = [f for f in Path(self.audio_path + '/').glob('**/*.mp3') if query in str(f).lower()]
if not audio_files:
await ctx.channel.send("%s not found" % query)
else:
for file in audio_files[:6]:
await ctx.channel.send("```"+str(file)+"```")
@commands.command()
async def joke(self, ctx, folder=None):
"""Joue un son (aléatoire par défaut)"""
try:
user = ctx.message.author.name
if not folder or not ctx.message.content:
audio_file = random.choice([f"{f}" for f in Path(self.audio_path + '/').glob('**/*.mp3')])
elif folder:
folder = folder.lower()
audio_files = [f for f in Path(self.audio_path + '/').glob('**/*.mp3') if folder in str(f).lower()]
if not audio_files:
await ctx.channel.send("%s not found" % folder)
return
else:
audio_file = random.choice(audio_files)
self.sounds.append(('file', audio_file, ctx))
except:
e = exc_info()[0]
await ctx.channel.send("Exception when calling joke: %s\n" % e)
@play.before_invoke
@joke.before_invoke
@repeat.before_invoke
@stream.before_invoke
async def ensure_voice(self, ctx):
if ctx.voice_client is None:
if ctx.author.voice:
await ctx.author.voice.channel.connect()
else:
await ctx.send("You are not connected to a voice channel.")
raise commands.CommandError("Author not connected to a voice channel.")
elif ctx.voice_client.is_playing():
pass

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

View file

@ -1,449 +0,0 @@
# -*- coding: utf-8 -*-
"""Main module."""
from __future__ import unicode_literals
import aiocron
import asyncio
import discord
import giphy_client
import gitlab
import logging
import lxml
import os
import random
import requests
import configparser
import argparse
import typing
import functools
from bs4 import BeautifulSoup as bs
from discord.ext import tasks, commands
from giphy_client.rest import ApiException
from logging.handlers import RotatingFileHandler
from pathlib import Path
from subprocess import *
from sys import argv,exit, exc_info
here = os.path.dirname(os.path.abspath(__file__))
class Texte(commands.Cog):
#class Mybot(discord.Client):
#Fonctions necesaires pour Kabot.
def __init__(
self,
bot,
intents=None,
gl_url=None,
gl_token=None,
gif_token=None,
audio_path=None,
nickname=None,
voice_chan=None,
text_chan=None,
):
self.gl_url = gl_url
self.gl_token = gl_token
self.gif_token = gif_token
self.voice_chan = voice_chan
self.text_chan = text_chan
self.bot = bot
self.nickname = nickname
@commands.Cog.listener()
async def on_ready(self):
for channel in self.bot.get_all_channels():
if channel.name == self.text_chan:
current_chan = channel
if self.nickname:
await self.bot.user.edit(nick=self.nickname)
await current_chan.send('Le troll est dans la place !')
self.kron.start()
@commands.Cog.listener()
async def on_message(self, message):
if message.author == self.bot.user and message.content.startswith('!'):
if message.content.startswith('!'):
ctx = await self.bot.get_context(message)
await self.bot.invoke(ctx)
return
else:
if self.bot.user in message.mentions \
and len(message.mentions) < 3 \
and len(message.content.splitlines()) == 1:
path = '/data/log/%s.log' % message.channel
with open(path, 'r') as f:
lines = f.read().splitlines()
if not message.content in lines:
with open(path, 'a') as f:
f.write(message.content + '\n')
response = random.choice(lines).replace(str(self.bot.user.id), str(message.author.id))
async with message.channel.typing():
if "http" in response:
await asyncio.sleep(len(response) / 8)
else:
await asyncio.sleep(len(response) / 6)
await message.channel.send(response)
#await self.bot.process_commands(message)
@commands.command(help='list des commits')
async def commits(self, ctx, number = 5):
try:
if self.gl_url and self.gl_token:
number = int(number)
gl = gitlab.Gitlab(self.gl_url, self.gl_token)
gl.auth()
projects = gl.projects.list(search='Kabot')[0]
commits = projects.commits.list(all=True)[:number]
for commit in commits:
detail = commit.attributes
await ctx.channel.send("__" + detail['author_name'] + "__: " + detail['title'] + '\n' + detail['web_url'])
else:
await ctx.channel.send("-_-")
except:
await ctx.channel.send("-_-")
@commands.command(help="Interrogation issues \n Args: list, search[mot clé] et add[nom de l'issue]")
async def issue(self, ctx, *args):
if self.gl_url and self.gl_token:
if args:
args = list(args)
gl = gitlab.Gitlab(self.gl_url, self.gl_token)
gl.auth()
if args[0] == 'list':
projects = gl.projects.list(search='Kabot')[0]
issues = projects.issues.list()
for issue in issues:
if "closed" == issue.state:
pass
else:
await ctx.channel.send('#' + str(issue.id) + ": " + issue.title + '\n' + issue.web_url)
elif args[0] == 'search':
query = ''.join(args[1:])
project = gl.projects.list(search='Kabot')[0]
find_issues = project.search("issues", query)
for issue in find_issues:
await ctx.channel.send("#" + str(issue['id']) + ": " + issue['title'] + '\n' + issue['web_url'])
elif args[0] == 'add':
title = ' '.join(args[1:])
author = title + ' - By ' + ctx.message.author.name
projects = gl.projects.list()
for project in projects:
if "Kabot" == project.name:
issue = project.issues.create({'title': author})
logger.info("Issue created : %s" % issue.web_url)
else:
await ctx.channel.send('unknown command')
@commands.command(help='count lines numbers in quote file')
async def lines(self, ctx):
path = '/data/log/%s.log' % ctx.channel
with open(path, 'r') as f:
lines = f.read().splitlines()
nb_lines = len(lines)
async with ctx.channel.typing():
await asyncio.sleep(0.5)
await ctx.channel.send("j'ai %s lignes dans mon stock" % nb_lines)
@commands.command(help='check if bot always online')
async def ping(self, message):
await message.channel.send('pong')
@commands.command(help='Restart Bot')
async def restart(self, ctx):
cmd = self.bot.get_command('leave')
await cmd.invoke(ctx)
await self.bot.close()
exit()
@commands.command(help='Update local repo')
async def update(self, message):
output = Popen('git pull'.split(), stdout=PIPE).communicate()[0]
cmd_audio = "git -C %s pull" % self.audio_path
output += Popen(cmd_audio.split(), stdout=PIPE).communicate()[0]
await message.channel.send(output.decode('utf-8'))
@commands.command(help="randomsur l'avenir des gens.")
async def avenir(self, ctx):
list_mot = ("tu seras curé, tu t'occuperas plus spécialement du catéchisme. ",
"tu seras animateur de soirées pour les gays pride. ",
"tu seras gynecologue dans une maison de retraite.",
"tu iras vivre en thaïland à cause de ton job. car tu seras ladyboy dans un bar.",
"tu sera DSI chez jacky et Michel",
"tu seras arroseur de plante aquatique.")
choix = random.choice(list_mot)
async with ctx.channel.typing():
await asyncio.sleep(len(choix) / 4)
await ctx.channel.send(choix)
@commands.command(help="j'adore la cuisine")
async def ciboulette(self, ctx):
cmd = self.bot.get_command('gif')
ctx.message.content = "!gif ciboulette"
await cmd.invoke(ctx)
@commands.command(help='Faire des choix')
async def choice(self, ctx, *words):
choices = random.choice(words)
await ctx.channel.send(choices)
@commands.command(help="optionnal args : ")
async def contrepeterie(self, ctx, *args):
response = None
path = here + '/ressources/contrepeteries.txt'
with open(path) as file:
lines = file.read().splitlines()
myline = random.choice(lines)
question, reponse = myline.split(";")
try:
response = '''Question ! : %s Réponse : ||%s||''' % (question, reponse)
except:
response = "Unknow error, try: !contrepeterie [mot clef]"
await ctx.send(response)
@commands.command(help='Gif me')
async def gif(self, ctx):
query = ctx.message.content.replace('!gif ', '')
api_instance = giphy_client.DefaultApi()
api_key = self.gif_token
lang = 'fr'
if api_key:
try:
api_response = api_instance.gifs_search_get(api_key, query, lang=lang, limit=15)
api_response.to_dict()['data'][0]
get_url = random.choice(api_response.to_dict()['data'])
get_url['url']
await ctx.channel.send(get_url['url'])
except ApiException as e:
await ctx.channel.send("Exception when calling DefaultApi->gifs_search_get: %s\n" % e)
else:
await ctx.channel.send("Exception : No api key found")
@commands.command(help="optionnal args : [livre] [character]")
async def kaamelott(self, ctx, *args):
response = None
url = 'https://kaamelott.chaudie.re/api/random'
if args and ctx.message.content:
args = list(args)
if args[0].isdigit():
livre = int(args[0])
args.pop(0)
elif args[-1].isdigit():
livre = int(args[-1])
args.pop(-1)
else:
livre = None
if args:
perso = ' '.join(args)
if perso and livre:
url = 'https://kaamelott.chaudie.re/api/random/livre/%s/personnage/%s' % (livre, perso)
elif perso:
url = 'https://kaamelott.chaudie.re/api/random/personnage/%s' % perso
else:
url = 'https://kaamelott.chaudie.re/api/random/livre/%s' % livre
try:
citation = requests.get(url).json()['citation']
response = "%s :\n```\n%s\n```" % (citation['infos']['personnage'], citation['citation'])
except:
response = "Unknow error, try: !kaamelott [livre] [character]"
await ctx.send(response)
@commands.command(help="Je menotte une cornemuse et je fume Eddy Malou")
async def kamoulox(self, ctx):
sans_verbe = get_word('nom').text + " " + get_word('complement').get('m') + " et " + get_word('nom').text + " " + get_word('complement').get('m') + "."
nom1 = get_word('nom')
nom2 = get_word('nom')
un1 = "un"
un2 = "un"
if nom1.get('gender') == 'F':
un1 = "une"
if nom2.get('gender') == 'F':
un2 = "une"
phrase1 = get_word('verbe').text + " " + un1 + " " + nom1.text + " " + random.choice([get_word('complement').get('m'), ""])
phrase2 = get_word('verbe').text + " " + un2 + " " + nom2.text + " " + random.choice([get_word('complement').get('m'), ""])
avec_verbe = phrase1 + " et " + phrase2 + "."
piece = random.choice(['pile', 'face'])
if piece == "pile":
result = sans_verbe
elif piece == "face":
result = avec_verbe
async with ctx.channel.typing():
await asyncio.sleep(len(result)/6)
await ctx.send(result)
@commands.dm_only()
@commands.command(help="Faire dire des choses au bot")
async def say(self, ctx, *message):
sentence = ' '.join(message)
channel = [x for x in self.bot.get_all_channels() if x.name == self.text_chan][0]
guild = self.bot.guilds[0]
for word in sentence.split():
if word.startswith('@'):
members = guild.members
for member in members:
if member.display_name.lower() in word.lower():
sentence = sentence.replace(word, member.mention)
await channel.send(sentence)
@commands.command(help='Who the fuck am i?')
async def schizo(self, ctx, *names):
name = ' '.join(names)
list_name = ["Kabot", "Gaspard et Balthazar", "Bender", "Zoidberg", "Gunther", "MissSaugnacEtCambran2022"]
try:
current_name = self.bot.user.name
list_name.remove(current_name)
except:
pass
if not name:
name = random.choice(list_name)
lower_names = [x.lower() for x in list_name]
if name.lower() in lower_names:
if name:
correct_name = [x for x in list_name if x.lower() in name.lower()][0]
name = correct_name
await self.bot.user.edit(username=name)
else:
name = "404"
await self.bot.user.edit(username="Error 404 name not found!")
await ctx.channel.send("Liste des noms = %s" % list_name)
img = open(here + "/ressources/avatar_bot/%s.jpg" % name, 'rb')
await self.bot.user.edit(avatar=img.read())
await self.joke(ctx, name)
@tasks.loop(seconds=3600)
async def kron(self):
kron_choice = random.choice([self.kaamelott, self.slap, self.kamoulox, self.contrepeterie, self.schizo, None, None, None, None, None, None, None,None,None,None,None,None,None])
if kron_choice != None:
await asyncio.sleep(random.choice(range(3550)))
for channel in self.bot.get_all_channels():
if channel.name == self.text_chan:
current_chan = channel
async for msg in current_chan.history(limit=1):
last_message = msg
ctx = await self.bot.get_context(last_message)
ctx.message.content = ""
await kron_choice(ctx)
@commands.command(help='slap this ass')
async def slap(self, ctx, user=None):
slap_multiple = [
"%s prend un coup de pied au cul",
"Descente du coude sur %s",
"%s est propulsé par dessus la TROISIEME CORDE!",
"Le mec en rose, c'est moi et le mec en jaune c'est %s! https://giphy.com/gifs/gSIz6gGLhguOY",
]
if not user or not ctx.message.mentions:
online_members = []
members = ctx.guild.members
for member in members:
if str(member.status) == "online":
online_members.append(member)
user = random.choice(online_members)
user = user.mention
elif ctx.message.mentions:
user = ctx.message.mentions[0]
user = user.mention
if user == self.bot.user.mention:
async with ctx.channel.typing():
await asyncio.sleep(0.5)
await ctx.channel.send("je tribuche par terre et je sais pas comment")
else:
async with ctx.channel.typing():
await asyncio.sleep(len(slap_multiple) / 4)
await ctx.channel.send(random.choice(slap_multiple) % user)
#Commandes pour troll.
@commands.command(help='Troll commands', hidden=True)
async def jke(self, ctx):
await ctx.channel.send(trollpower())
@commands.command(help='Troll commands', hidden=True)
async def joe(self, ctx):
await ctx.channel.send(trollpower())
@commands.command(help='Troll commands', hidden=True)
async def jok(self, ctx):
await ctx.channel.send(trollpower())
@commands.command(help='Troll commands', hidden=True)
async def joker(self, ctx):
await ctx.channel.send(trollpower(too_long=True))
@commands.command(help='Troll commands', hidden=True)
async def oke(self, ctx):
await ctx.channel.send(trollpower())
def trollpower(too_long=None):
if too_long:
return("Bah alors, on sait plus écrire, je te donne un indice: t'as une lettre en trop! :sweat_drops: :tongue:")
return('Bah alors, on sait plus écrire, je te donne un indice: il te manque une lettre! :sweat_drops: :tongue:')
def get_word(word_type):
"""Chercher les mots pour la fonction kamoulox dans le fichier xml"""
content = []
with open(here + "/ressources/base_kml.xml", "r", encoding="ISO-8859-1") as file:
content = file.readlines()
content = "".join(content)
bs_content = bs(content, 'lxml')
if word_type == 'nom':
nom = bs_content.resources.nom.find_all('word')
result = random.choice(nom)
return result
elif word_type == 'nom_propre':
nom_propre = bs_content.resources.nompropre.find_all('word')
result = random.choice(nom_propre)
return result
elif word_type == 'verbe':
verbe = bs_content.resources.verbe.find_all('word')
result = random.choice(verbe)
return result
elif word_type == 'complement':
complement = bs_content.resources.complement.find_all('word')
result = random.choice(complement)
return result
elif word_type == 'nom_special':
nom_special = bs_content.resources.complement.find_all('word')
result = random.choice(nom_special)
return result
elif word_type == 'prenom':
prenom = bs_content.resources.prenom.find_all('word')
result = random.choice(prenom)
return result
elif word_type == 'prescuse':
prescuse = bs_content.resources.prescuse.find_all('word')
result = random.choice(prescuse)
return result
elif word_type == 'scuse1':
scuse1 = bs_content.resources.scuse1.find_all('word')
result = random.choice(scuse1)
return result
elif word_type == 'scuse2':
scuse2 = bs_content.resources.scuse2.find_all('word')
result = random.choice(scuse2)
return result
elif word_type == 'presulte':
presulte = bs_content.resources.presulte.find_all('word')
result = random.choice(presulte)
return result
elif word_type == 'sulte':
sulte = bs_content.resources.sulte.find_all('word')
result = random.choice(sulte)
return result
elif word_type == 'postsulte':
postsulte = bs_content.resources.presulte.find_all('word')
result = random.choice(postsulte)
return result
elif word_type == 'mail':
mail = bs_content.resources.mail.find_all('word')
result = random.choice(mail)
return result
else:
result = 'Nique bien ta mère!'
return result

View file

@ -0,0 +1,10 @@
pip==19.2.3
bump2version==0.5.11
wheel==0.33.6
watchdog==0.9.0
flake8==3.7.8
tox==3.14.0
coverage==4.5.4
Sphinx==1.8.5
twine==1.14.0

View file

@ -18,9 +18,7 @@ requirements = [
'aiocron',
'python-gitlab',
'giphy_client',
'yt-dlp',
'lxml',
'BeautifulSoup4',
'youtube_dl',
]
setup_requirements = [ ]
@ -30,7 +28,7 @@ test_requirements = [ ]
setup(
author="Michaël Ricart",
author_email='michael.ricart@0w.tf',
python_requires='>=3.11',
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Intended Audience :: Developers',
@ -46,14 +44,13 @@ setup(
description="kabot for discord",
entry_points={
'console_scripts': [
'kabot=kabot.kabot:run',
'kabot=kabot.kabot:main',
],
},
install_requires=requirements,
license="BSD license",
long_description=readme + '\n\n' + history,
include_package_data=True,
package_data={'ressources': ['kabot/utils/ressources/*']},
keywords='kabot',
name='kabot',
packages=find_packages(include=['kabot', 'kabot.*']),
@ -61,6 +58,6 @@ setup(
test_suite='tests',
tests_require=test_requirements,
url='https://github.com/None/kabot',
version='0.2.18',
version='0.1.0',
zip_safe=False,
)

20
kabot/tox.ini Normal file
View file

@ -0,0 +1,20 @@
[tox]
envlist = py27, py35, py36, py37 flake8
[travis]
python =
3.7: py37
3.6: py36
3.5: py35
2.7: py27
[testenv:flake8]
basepython = python
deps = flake8
commands = flake8 kabot
[testenv]
setenv =
PYTHONPATH = {toxinidir}
commands = python setup.py test

36
pinned.cfg Normal file
View file

@ -0,0 +1,36 @@
[versions]
Click = 7.0
Jinja2 = 2.10.1
MarkupSafe = 1.1.1
async-timeout = 3.0.1
attrs = 19.1.0
binaryornot = 0.4.4
certifi = 2019.9.11
chardet = 3.0.4
cookiecutter = 1.6.0
future = 0.17.1
idna = 2.8
jinja2-time = 0.2.0
mr.developer = 2.0.0
multidict = 4.5.2
poyo = 0.5.0
requests = 2.22.0
urllib3 = 1.25.6
websockets = 6.0
whichcraft = 0.6.1
yarl = 1.3.0
zc.buildout = 2.13.2
zc.recipe.egg = 2.0.7
# Required by:
# jinja2-time==0.2.0
arrow = 0.15.2
# Required by:
# arrow==0.15.2
python-dateutil = 2.8.0
# Required by:
# mr.developer==2.0.0
six = 1.12.0