added first slashcommand and refactored the preview cog as result of breaking changes in slashcommand

This commit is contained in:
2024-07-17 15:52:39 +02:00
parent ab1fca82dc
commit fa2e4a78cd
9 changed files with 211 additions and 94 deletions

6
.gitignore vendored
View File

@@ -1,9 +1,9 @@
jeevesbot/env.py
jeevesbot/secret.json
jeevesbot/databases/*
jeevesbot/__pycache__/*
logs/
__init__.py
*.pyc
__pycache__/*
cogs/__pycache__/*
jeevesbot/__pycache__/*
.vscode/
.vscode/

View File

@@ -1,4 +1,3 @@
import discord
from discord.ext import commands
from logging import getLogger
import typing

View File

@@ -1,69 +1,74 @@
import discord
from discord.ext import commands
from jeevesbot import functions
from jeevesbot import functions, env
from logging import getLogger
import re
import pytube
from pytube.exceptions import RegexMatchError
from pytube.exceptions import RegexMatchError, VideoUnavailable, ExtractError
# setup logging
log = getLogger(__name__)
e = discord.Embed()
class Preview(commands.Cog):
""" Ensures that high-risk channels don't display embedded links, but only gifs and youtube previews."""
def __init__(self, bot):
self.bot = bot
self.video_id_regex = re.compile(r'(?:youtube\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/|m\.youtube\.com/(?:watch\?v=|embed/|v/))([^"&?/ ]{11})')
self.e = discord.Embed()
@commands.Cog.listener()
async def on_message(self, message):
if message.author.bot:
return # Ignore messages from bots
if message.content.startswith('https://tenor.com/'):
roles = functions.checkrole(message.author.roles)
channel = functions.checkchannel(message.channel.id)
is_admin = message.author.guild_permissions.administrator
is_high_risk_channel = self.check_channel(message.channel.id)
embed_url = message.content
follow_url = embed_url + '.gif'
full_url = await functions.resolve(follow_url)
gif_url = full_url.split('?')[0]
embed = e.set_image(url=gif_url)
if channel is True:
if roles is not True:
await message.channel.send(embed=embed)
logline = (str(message.author) + ' requested a gif: ' + str(gif_url))
log.info(logline)
if message.content.endswith('.gif'):
roles = functions.checkrole(message.author.roles)
channel = functions.checkchannel(message.channel.id)
embed_url = message.content
embed = e.set_image(url=embed_url)
if channel is True:
if roles is not True:
await message.channel.send(embed=embed)
logline = (str(message.author) + ' requested a gif: ' + str(embed_url))
log.info(logline)
embed = self.e.set_image(url=gif_url)
if is_high_risk_channel and not is_admin:
await message.channel.send(embed=embed)
logline = (str(message.author) + ' requested a gif: ' + str(gif_url))
log.info(logline)
if message.content.startswith('https://giphy.com/'):
roles = functions.checkrole(message.author.roles)
channel = functions.checkchannel(message.channel.id)
is_admin = message.author.guild_permissions.administrator
is_high_risk_channel = self.check_channel(message.channel.id)
embed_url = message.content
image_code = embed_url.split('-')[-1]
gif_url = 'https://media.giphy.com/media/' + image_code + '/giphy.gif'
embed = e.set_image(url=gif_url)
if channel is True:
if roles is not True:
await message.channel.send(embed=embed)
logline = (str(message.author) + ' requested a gif: ' + str(gif_url))
log.info(logline)
if 'https://youtu' or 'https://m.youtu' or 'https://www.youtu' in message.content():
roles = functions.checkrole(message.author.roles)
channel = functions.checkchannel(message.channel.id)
if channel is True:
if roles is not True:
url = message.content
embed = self.e.set_image(url=gif_url)
if is_high_risk_channel and not is_admin:
await message.channel.send(embed=embed)
logline = (str(message.author) + ' requested a gif: ' + str(gif_url))
log.info(logline)
if message.content.endswith('.gif'):
is_admin = message.author.guild_permissions.administrator
is_high_risk_channel = self.check_channel(message.channel.id)
embed_url = message.content
embed = self.e.set_image(url=embed_url)
if is_high_risk_channel and not is_admin:
await message.channel.send(embed=embed)
logline = (str(message.author) + ' requested a gif: ' + str(embed_url))
log.info(logline)
if 'https://youtu' in message.content or 'https://m.youtu' in message.content or 'https://www.youtu' in message.content:
is_admin = message.author.guild_permissions.administrator
is_high_risk_channel = self.check_channel(message.channel.id)
if is_high_risk_channel and not is_admin:
url = message.content
try:
youtube = pytube.YouTube(url)
video_title = youtube.title
video_author = youtube.author
@@ -71,12 +76,19 @@ class Preview(commands.Cog):
if video_id:
embed = discord.Embed()
embed.set_image(url=f"https://img.youtube.com/vi/{video_id}/hqdefault.jpg")
embed.set_author(name=f"{video_author}")
embed.add_field(name=f"", value=f"[{video_title}]({url})")
embed.set_author(name=video_author)
embed.add_field(name="", value=f"[{video_title}]({url})")
await message.channel.send(embed=embed)
log.info(f'User {message.author} requested preview for {url}')
except (VideoUnavailable, ExtractError, KeyError) as e:
log.error(f'Error extracting YouTube video details for {url}: {e}')
await message.channel.send('Sorry, there was an error retrieving the YouTube video details.')
def check_channel(self, channel_id):
high_risk_channels = env.PREVIEWCHANNELS
return channel_id in high_risk_channels
def extract_video_id(self, url):
try:
match = self.video_id_regex.search(url)

41
cogs/reminders.py Normal file
View File

@@ -0,0 +1,41 @@
import discord
from discord.ext import commands
from jeevesbot import env
import datetime
from jeevesbot.database import add_reminder
from logging import getLogger
# setup logging
log = getLogger(__name__)
class Reminders(commands.Cog):
""" Reminder command"""
def __init__(self, bot):
self.bot = bot
@discord.app_commands.command(name='remindme', description='Set a reminder - Use YY-MM-DD HH:MM:SS notation')
@discord.app_commands.guilds(discord.Object(id=env.GUILD_ID))
async def remindme(self, interaction: discord.Interaction, time: str, message: str):
try:
reminder_time = datetime.datetime.strptime(time, '%Y-%m-%d %H:%M:%S')
add_reminder(interaction.user.id, message, reminder_time.isoformat())
await interaction.response.send_message(f'Reminder set for {reminder_time}')
log.info(f'Reminder set by {interaction.user} for {reminder_time}: {message}')
except ValueError:
await interaction.response.send_message('Invalid time format. Use YYYY-MM-DD HH:MM:SS', ephemeral=True)
log.warn(f'Reminder set by {interaction.user} went wrong.')
@commands.Cog.listener()
async def on_ready(self):
log.info(f'module active')
async def setup(bot):
await bot.add_cog(Reminders(bot))
log.info(f'Added Reminders.remindme as command')

112
jeeves.py
View File

@@ -1,66 +1,108 @@
#!/usr/bin/env python3.8
import discord
from discord.ext import commands
from discord.ext import commands, tasks
from jeevesbot import env
from jeevesbot.database import init_db, get_due_reminders
import os
import log
import logging.config
from logging import getLogger
import datetime
import asyncio
# setup root logger handlers
logging.config.dictConfig(log.LOGGING)
# Initialize the database
init_db()
# setup logging
logging.config.dictConfig(log.LOGGING)
log = getLogger(__name__)
# setup discord.py bot
intents = discord.Intents().all()
bot = commands.Bot(command_prefix='!', intents=intents, help_command=None)
intents.message_content = True
e = discord.Embed()
@bot.command(name='load', hidden=True)
@commands.has_permissions(administrator=True)
async def load(ctx, extension):
bot.load_extension(f'cogs.{extension}')
log.info(f'{ctx.message.author} loaded the {extension} module')
class Jeeves(commands.Bot):
def __init__(self):
super().__init__(command_prefix='!', intents=intents, help_command=None)
self.guild_ids = [env.GUILD_ID]
@bot.command(name='unload', hidden=True)
@commands.has_permissions(administrator=True)
async def unload(ctx, extension):
bot.unload_extension(f'cogs.{extension}')
log.info(f'{ctx.message.author} unloaded the {extension} module')
@commands.command(name='load', hidden=True)
@commands.has_permissions(administrator=True)
async def load(self, ctx, extension):
self.load_extension(f'cogs.{extension}')
log.info(f'{ctx.message.author} loaded the {extension} module')
@bot.command(name='reload', hidden=True)
@commands.has_permissions(administrator=True)
async def reload(ctx, extension):
bot.unload_extension(f'cogs.{extension}')
bot.load_extension(f'cogs.{extension}')
log.info(f'{ctx.message.author} reloaded the {extension} module')
@commands.command(name='unload', hidden=True)
@commands.has_permissions(administrator=True)
async def unload(self, ctx, extension):
self.unload_extension(f'cogs.{extension}')
log.info(f'{ctx.message.author} unloaded the {extension} module')
async def load_extensions():
for filename in os.listdir('./cogs'):
if filename.endswith('.py'):
await bot.load_extension(f'cogs.{filename[:-3]}')
@commands.command(name='reload', hidden=True)
@commands.has_permissions(administrator=True)
async def reload(self, ctx, extension):
self.unload_extension(f'cogs.{extension}')
self.load_extension(f'cogs.{extension}')
log.info(f'{ctx.message.author} reloaded the {extension} module')
@bot.event
async def on_ready():
log.info(f'Active with ID:{bot.user.id} as {bot.user.name}')
activity = discord.Activity(name='!help', type=discord.ActivityType.listening)
await bot.change_presence(activity=activity)
async def load_extensions(self):
for filename in os.listdir('./cogs'):
if filename.endswith('.py'):
await self.load_extension(f'cogs.{filename[:-3]}')
@tasks.loop(seconds=60)
async def check_reminders(self):
now = datetime.datetime.now().isoformat()
reminders = get_due_reminders(now)
for reminder in reminders:
user = self.get_user(reminder[1])
if user:
try:
await user.send(reminder[2])
except Exception as e:
log.error(f'Error sending reminder to user {reminder[1]}: {e}')
async def on_ready(self):
log.info(f'Active with ID:{self.user.id} as {self.user.name}')
activity = discord.Activity(name='!help', type=discord.ActivityType.listening)
await self.change_presence(activity=activity)
# Sync commands for all guilds
for guild_id in self.guild_ids:
guild = discord.Object(id=guild_id)
try:
await self.tree.sync(guild=guild)
log.info(f'Successfully synced commands for guild {guild_id}')
except discord.errors.Forbidden as e:
log.error(f'Failed to sync commands for guild {guild_id}: {e}')
# Start the reminder check loop
if not self.check_reminders.is_running():
self.check_reminders.start()
async def on_command_error(self, ctx, error):
if isinstance(error, commands.CommandNotFound):
await ctx.send('Command not found.')
log.warning(f'Command not found: {ctx.message.content}')
else:
await ctx.send('An error occurred.')
log.error(f'An error occurred: {error}')
async def main():
async with bot:
await load_extensions()
await bot.start(env.TOKEN)
bot = Jeeves()
await bot.load_extensions()
await bot.start(env.TOKEN)
asyncio.run(main())
if __name__ == "__main__":
asyncio.run(main())

34
jeevesbot/database.py Normal file
View File

@@ -0,0 +1,34 @@
#!/usr/bin/env python3
import sqlite3
def init_db():
conn = sqlite3.connect(r"jeevesbot/databases/reminders.db")
c = conn.cursor()
c.execute('''
CREATE TABLE IF NOT EXISTS reminders (
id INTEGER PRIMARY KEY,
user_id INTEGER,
message TEXT,
reminder_time TIMESTAMP
)
''')
conn.commit()
conn.close()
def add_reminder(user_id, message, reminder_time):
conn = sqlite3.connect(r"jeevesbot/databases/reminders.db")
c = conn.cursor()
c.execute('INSERT INTO reminders (user_id, message, reminder_time) VALUES (?, ?, ?)', (user_id, message, reminder_time))
conn.commit()
conn.close()
def get_due_reminders(current_time):
conn = sqlite3.connect(r"jeevesbot/databases/reminders.db")
c = conn.cursor()
c.execute('SELECT id, user_id, message FROM reminders WHERE reminder_time <= ?', (current_time,))
reminders = c.fetchall()
c.execute('DELETE FROM reminders WHERE reminder_time <= ?', (current_time,))
conn.commit()
conn.close()
return reminders

View File

@@ -2,4 +2,5 @@
TOKEN = 'discord-bot-token-here'
ADMIN_ROLE = 'role-to-exclude-from-gifbot'
PREVIEWCHANNELS = [add-channel-ids-for-bot-to-work-in]
GUILD_ID = 'id-of-guild'
PREVIEWCHANNELS = ['add-channel-ids-for-bot-to-work-in']

View File

@@ -17,16 +17,3 @@ def roll(notation):
result = int(roll)
return roll,result
# check if user has admin role and output True if it's the case.
def checkrole(roles):
for role in roles:
if str(role) == env.ADMIN_ROLE:
return True
# check if the source channel is in the list of channels that are watched by the bot.
def checkchannel(channelid):
if channelid in env.PREVIEWCHANNELS:
return True
else:
return False

View File

@@ -2,13 +2,14 @@
aiohttp
async-timeout
dice
discord.py
discord.py[voice]
docopt
multidict
pyparsing
typing-extensions
pylint
pytube
sqlite3
# needs this version, otherwise TypeErrors will break stuff
yarl==1.4.2