REF: Made sure everything conforms to Flake8's standards
FIX: Fixed the Permission issues with logger FEAT: Changed how the XP system works. Now does a scaling curve with xp being 1-5
This commit is contained in:
parent
4d9214e378
commit
39603b1e06
@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
13
main.py
13
main.py
@ -1,7 +1,9 @@
|
|||||||
import discord
|
|
||||||
import config
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
import discord
|
||||||
|
|
||||||
|
import config
|
||||||
|
|
||||||
# Set up logging
|
# Set up logging
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
@ -37,11 +39,14 @@ class Selena(discord.Client):
|
|||||||
await self.load_extension(extension)
|
await self.load_extension(extension)
|
||||||
|
|
||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
print(f'Logged in as {self.user} (ID: {self.user.id})')
|
print(f"Logged in as {self.user} (ID: {self.user.id})")
|
||||||
print('------')
|
print("------")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# Enable message content intent
|
||||||
intents = discord.Intents.default()
|
intents = discord.Intents.default()
|
||||||
|
intents.message_content = True
|
||||||
|
|
||||||
client = Selena(intents=intents)
|
client = Selena(intents=intents)
|
||||||
client.run(config.DISCORD_TOKEN)
|
client.run(config.DISCORD_TOKEN)
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
# modules/admin/logger_module.py
|
# modules/admin/logger_module.py
|
||||||
import discord
|
|
||||||
import logging
|
import logging
|
||||||
import logging.config
|
import logging.config
|
||||||
|
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
|
||||||
from .logging_config import logging_config
|
from .logging_config import logging_config
|
||||||
|
|
||||||
|
|
||||||
@ -10,20 +13,52 @@ class LoggerModule:
|
|||||||
self.bot = bot
|
self.bot = bot
|
||||||
logging.config.dictConfig(logging_config)
|
logging.config.dictConfig(logging_config)
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
|
self.add_logging_commands()
|
||||||
|
|
||||||
def add_logging_commands(self):
|
def add_logging_commands(self):
|
||||||
@self.bot.tree.command(name="log_test",
|
@self.bot.tree.command(name="log_test", description="Test the logging system") # noqa: E501
|
||||||
description="Test the logging system")
|
|
||||||
async def log_test(interaction: discord.Interaction):
|
async def log_test(interaction: discord.Interaction):
|
||||||
self.logger.debug("This is a debug message")
|
self.logger.debug("This is a debug message")
|
||||||
self.logger.info("This is an info message")
|
self.logger.info("This is an info message")
|
||||||
self.logger.warning("This is a warning message")
|
self.logger.warning("This is a warning message")
|
||||||
self.logger.error("This is an error message")
|
self.logger.error("This is an error message")
|
||||||
self.logger.critical("This is a critical message")
|
self.logger.critical("This is a critical message")
|
||||||
await interaction.response.send_message("Logging test completed."
|
await interaction.response.send_message(
|
||||||
"Check the logs!")
|
"Logging test completed. Check the logs!"
|
||||||
|
)
|
||||||
|
|
||||||
|
@self.bot.tree.command(
|
||||||
|
name="set_log_level", description="Set the logging level (Owner/Admin only)" # noqa: E501
|
||||||
|
)
|
||||||
|
@app_commands.choices(
|
||||||
|
level=[
|
||||||
|
app_commands.Choice(name="DEBUG", value="DEBUG"),
|
||||||
|
app_commands.Choice(name="INFO", value="INFO"),
|
||||||
|
app_commands.Choice(name="WARNING", value="WARNING"),
|
||||||
|
app_commands.Choice(name="ERROR", value="ERROR"),
|
||||||
|
app_commands.Choice(name="CRITICAL", value="CRITICAL"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
async def set_log_level(
|
||||||
|
interaction: discord.Interaction, level: app_commands.Choice[str]
|
||||||
|
):
|
||||||
|
guild = interaction.guild
|
||||||
|
if guild is not None and (
|
||||||
|
interaction.user.id == guild.owner_id
|
||||||
|
or any(
|
||||||
|
role.permissions.administrator for role in interaction.user.roles # noqa: E501
|
||||||
|
)
|
||||||
|
):
|
||||||
|
logging.getLogger().setLevel(level.value)
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"Logging level set to {level.value}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"You do not have permission to set the logging level.",
|
||||||
|
ephemeral=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
async def setup(bot):
|
||||||
logger_module = LoggerModule(bot)
|
LoggerModule(bot)
|
||||||
logger_module.add_logging_commands()
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# modules/admin/logging_config.py
|
# modules/admin/logging_config.py
|
||||||
|
|
||||||
import logging
|
|
||||||
import logging.handlers
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
LOG_DIR = "logs"
|
LOG_DIR = "logs"
|
||||||
@ -14,9 +12,7 @@ logging_config = {
|
|||||||
"version": 1,
|
"version": 1,
|
||||||
"disable_existing_loggers": False,
|
"disable_existing_loggers": False,
|
||||||
"formatters": {
|
"formatters": {
|
||||||
"standard": {
|
"standard": {"format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s"},
|
||||||
"format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"handlers": {
|
"handlers": {
|
||||||
"console": {
|
"console": {
|
||||||
@ -29,7 +25,7 @@ logging_config = {
|
|||||||
"class": "logging.handlers.RotatingFileHandler",
|
"class": "logging.handlers.RotatingFileHandler",
|
||||||
"formatter": "standard",
|
"formatter": "standard",
|
||||||
"filename": LOG_FILE,
|
"filename": LOG_FILE,
|
||||||
"maxBytes": 1024*1024*5, # 5 MB
|
"maxBytes": 1024 * 1024 * 5, # 5 MB
|
||||||
"backupCount": 3,
|
"backupCount": 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
import logging
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ class PolicyModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Privacy Policy",
|
title="Privacy Policy",
|
||||||
description=privacy_policy_text,
|
description=privacy_policy_text,
|
||||||
color=discord.Color.blue()
|
color=discord.Color.blue(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"User {interaction.user.id} viewed the privacy policy")
|
logger.info(f"User {interaction.user.id} viewed the privacy policy")
|
||||||
@ -93,7 +94,7 @@ class PolicyModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Terms of Service",
|
title="Terms of Service",
|
||||||
description=tos_text,
|
description=tos_text,
|
||||||
color=discord.Color.blue()
|
color=discord.Color.blue(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"User {interaction.user.id} viewed the terms of service")
|
logger.info(f"User {interaction.user.id} viewed the terms of service")
|
||||||
|
@ -2,56 +2,68 @@ import sqlite3
|
|||||||
|
|
||||||
|
|
||||||
def initialize_db():
|
def initialize_db():
|
||||||
conn = sqlite3.connect('selena.db')
|
conn = sqlite3.connect("selena.db")
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
# Birthdays table
|
# Birthdays table
|
||||||
cursor.execute('''
|
cursor.execute(
|
||||||
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS birthdays (
|
CREATE TABLE IF NOT EXISTS birthdays (
|
||||||
user_id TEXT PRIMARY KEY,
|
user_id TEXT PRIMARY KEY,
|
||||||
birthday TEXT
|
birthday TEXT
|
||||||
)
|
)
|
||||||
''')
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
# Currency table
|
# Currency table
|
||||||
cursor.execute('''
|
cursor.execute(
|
||||||
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS currency (
|
CREATE TABLE IF NOT EXISTS currency (
|
||||||
user_id TEXT PRIMARY KEY,
|
user_id TEXT PRIMARY KEY,
|
||||||
balance INTEGER,
|
balance INTEGER,
|
||||||
last_earned TIMESTAMP
|
last_earned TIMESTAMP
|
||||||
)
|
)
|
||||||
''')
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
# Followed channels table
|
# Followed channels table
|
||||||
cursor.execute('''
|
cursor.execute(
|
||||||
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS followed_channels (
|
CREATE TABLE IF NOT EXISTS followed_channels (
|
||||||
twitch_name TEXT PRIMARY KEY,
|
twitch_name TEXT PRIMARY KEY,
|
||||||
discord_channel_id INTEGER
|
discord_channel_id INTEGER
|
||||||
)
|
)
|
||||||
''')
|
"""
|
||||||
cursor.execute('''
|
)
|
||||||
|
cursor.execute(
|
||||||
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS followed_youtube_channels (
|
CREATE TABLE IF NOT EXISTS followed_youtube_channels (
|
||||||
youtube_channel_id TEXT PRIMARY KEY,
|
youtube_channel_id TEXT PRIMARY KEY,
|
||||||
discord_channel_id INTEGER
|
discord_channel_id INTEGER
|
||||||
)
|
)
|
||||||
''')
|
"""
|
||||||
cursor.execute('''
|
)
|
||||||
|
cursor.execute(
|
||||||
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS youtube_status (
|
CREATE TABLE IF NOT EXISTS youtube_status (
|
||||||
youtube_channel_id TEXT PRIMARY KEY,
|
youtube_channel_id TEXT PRIMARY KEY,
|
||||||
last_video_id TEXT
|
last_video_id TEXT
|
||||||
)
|
)
|
||||||
''')
|
"""
|
||||||
cursor.execute('''
|
)
|
||||||
|
cursor.execute(
|
||||||
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS user_xp (
|
CREATE TABLE IF NOT EXISTS user_xp (
|
||||||
user_id INTEGER PRIMARY KEY,
|
user_id INTEGER PRIMARY KEY,
|
||||||
xp INTEGER,
|
xp INTEGER,
|
||||||
level INTEGER
|
level INTEGER
|
||||||
)
|
)
|
||||||
''')
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def get_connection():
|
def get_connection():
|
||||||
return sqlite3.connect('selena.db')
|
return sqlite3.connect("selena.db")
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import app_commands
|
|
||||||
import spotipy
|
import spotipy
|
||||||
|
from discord import app_commands
|
||||||
from spotipy.oauth2 import SpotifyOAuth
|
from spotipy.oauth2 import SpotifyOAuth
|
||||||
|
|
||||||
import config
|
import config
|
||||||
|
|
||||||
# Set up logging
|
# Set up logging
|
||||||
@ -21,7 +23,7 @@ class SpotifyModule:
|
|||||||
scope=(
|
scope=(
|
||||||
"user-library-read user-read-playback-state "
|
"user-library-read user-read-playback-state "
|
||||||
"user-modify-playback-state user-read-currently-playing"
|
"user-modify-playback-state user-read-currently-playing"
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.add_commands()
|
self.add_commands()
|
||||||
@ -39,7 +41,7 @@ class SpotifyModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Current Track",
|
title="Current Track",
|
||||||
description="No song is currently playing",
|
description="No song is currently playing",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info("No song is currently playing")
|
logger.info("No song is currently playing")
|
||||||
@ -49,15 +51,16 @@ class SpotifyModule:
|
|||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="Current Track",
|
title="Current Track",
|
||||||
description=f"{track['name']} by {artist}",
|
description=f"{track['name']} by {artist}",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
embed.add_field(
|
embed.add_field(
|
||||||
name="Album", value=track['album']['name'],
|
name="Album", value=track["album"]["name"], inline=False
|
||||||
inline=False
|
|
||||||
)
|
)
|
||||||
embed.set_thumbnail(url=track['album']['images'][0]['url'])
|
embed.set_thumbnail(url=track["album"]["images"][0]["url"])
|
||||||
await interaction.followup.send(embed=embed)
|
await interaction.followup.send(embed=embed)
|
||||||
logger.info(f"Currently playing: {track['name']} by {artist}") # noqa: E501
|
logger.info(
|
||||||
|
f"Currently playing: {track['name']} by {artist}"
|
||||||
|
) # noqa: E501
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await interaction.followup.send(f"An error occurred: {e}")
|
await interaction.followup.send(f"An error occurred: {e}")
|
||||||
logger.error(f"Error in current_track command: {e}")
|
logger.error(f"Error in current_track command: {e}")
|
||||||
@ -74,7 +77,7 @@ class SpotifyModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Play Track",
|
title="Play Track",
|
||||||
description="No results found",
|
description="No results found",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"No results found for query: {query}")
|
logger.info(f"No results found for query: {query}")
|
||||||
@ -90,7 +93,7 @@ class SpotifyModule:
|
|||||||
title="Play Track",
|
title="Play Track",
|
||||||
description="No active devices found."
|
description="No active devices found."
|
||||||
"Please open Spotify on a device.",
|
"Please open Spotify on a device.",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info("No active devices found for playback")
|
logger.info("No active devices found for playback")
|
||||||
@ -100,22 +103,23 @@ class SpotifyModule:
|
|||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="Now Playing",
|
title="Now Playing",
|
||||||
description=f"{track['name']} by {', '.join([a['name'] for a in track['artists']])}", # noqa: E501
|
description=f"{track['name']} by {', '.join([a['name'] for a in track['artists']])}", # noqa: E501
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
embed.add_field(
|
embed.add_field(
|
||||||
name="Album", value=track['album']['name'], inline=False
|
name="Album", value=track["album"]["name"], inline=False
|
||||||
)
|
)
|
||||||
embed.set_thumbnail(url=track['album']['images'][0]['url'])
|
embed.set_thumbnail(url=track["album"]["images"][0]["url"])
|
||||||
await interaction.followup.send(embed=embed)
|
await interaction.followup.send(embed=embed)
|
||||||
logger.info(f"Now playing: {track['name']} by {', '.join([a['name'] for a in track['artists']])}") # noqa: E501
|
logger.info(
|
||||||
|
f"Now playing: {track['name']} by {', '.join([a['name'] for a in track['artists']])}"
|
||||||
|
) # noqa: E501
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await interaction.followup.send(f"An error occurred: {e}")
|
await interaction.followup.send(f"An error occurred: {e}")
|
||||||
logger.error(f"Error in play_track command: {e}")
|
logger.error(f"Error in play_track command: {e}")
|
||||||
|
|
||||||
@app_commands.command(
|
@app_commands.command(
|
||||||
name="play_playlist",
|
name="play_playlist",
|
||||||
description="Play a playlist by searching for it"
|
description="Play a playlist by searching for it" "or providing a link",
|
||||||
"or providing a link"
|
|
||||||
)
|
)
|
||||||
async def play_playlist(interaction: discord.Interaction, query: str):
|
async def play_playlist(interaction: discord.Interaction, query: str):
|
||||||
await interaction.response.defer()
|
await interaction.response.defer()
|
||||||
@ -132,7 +136,7 @@ class SpotifyModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Play Playlist",
|
title="Play Playlist",
|
||||||
description="No results found",
|
description="No results found",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"No results found for query: {query}")
|
logger.info(f"No results found for query: {query}")
|
||||||
@ -147,7 +151,7 @@ class SpotifyModule:
|
|||||||
title="Play Playlist",
|
title="Play Playlist",
|
||||||
description="No active devices found."
|
description="No active devices found."
|
||||||
"Please open Spotify on a device.",
|
"Please open Spotify on a device.",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info("No active devices found for playback")
|
logger.info("No active devices found for playback")
|
||||||
@ -156,13 +160,19 @@ class SpotifyModule:
|
|||||||
self.sp.start_playback(context_uri=uri)
|
self.sp.start_playback(context_uri=uri)
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="Now Playing Playlist",
|
title="Now Playing Playlist",
|
||||||
description=f"{playlist['name']} by {playlist['owner']['display_name']}" if not query.startswith("https://open.spotify.com/playlist/") else "Playing playlist", # noqa: E501
|
description=(
|
||||||
color=discord.Color.green()
|
f"{playlist['name']} by {playlist['owner']['display_name']}"
|
||||||
|
if not query.startswith("https://open.spotify.com/playlist/")
|
||||||
|
else "Playing playlist"
|
||||||
|
), # noqa: E501
|
||||||
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
if not query.startswith("https://open.spotify.com/playlist/"):
|
if not query.startswith("https://open.spotify.com/playlist/"):
|
||||||
embed.set_thumbnail(url=playlist['images'][0]['url'])
|
embed.set_thumbnail(url=playlist["images"][0]["url"])
|
||||||
await interaction.followup.send(embed=embed)
|
await interaction.followup.send(embed=embed)
|
||||||
logger.info(f"Now playing playlist: {playlist['name']} by {playlist['owner']['display_name']}") # noqa: E501
|
logger.info(
|
||||||
|
f"Now playing playlist: {playlist['name']} by {playlist['owner']['display_name']}"
|
||||||
|
) # noqa: E501
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await interaction.followup.send(f"An error occurred: {e}")
|
await interaction.followup.send(f"An error occurred: {e}")
|
||||||
logger.error(f"Error in play_playlist command: {e}")
|
logger.error(f"Error in play_playlist command: {e}")
|
||||||
@ -178,7 +188,7 @@ class SpotifyModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Pause",
|
title="Pause",
|
||||||
description="Playback paused.",
|
description="Playback paused.",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info("Playback paused")
|
logger.info("Playback paused")
|
||||||
@ -197,7 +207,7 @@ class SpotifyModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Resume",
|
title="Resume",
|
||||||
description="Playback resumed.",
|
description="Playback resumed.",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info("Playback resumed")
|
logger.info("Playback resumed")
|
||||||
@ -205,9 +215,7 @@ class SpotifyModule:
|
|||||||
await interaction.followup.send(f"An error occurred: {e}")
|
await interaction.followup.send(f"An error occurred: {e}")
|
||||||
logger.error(f"Error in resume command: {e}")
|
logger.error(f"Error in resume command: {e}")
|
||||||
|
|
||||||
@app_commands.command(
|
@app_commands.command(name="next", description="Skip to the next track")
|
||||||
name="next", description="Skip to the next track"
|
|
||||||
)
|
|
||||||
async def next_track(interaction: discord.Interaction):
|
async def next_track(interaction: discord.Interaction):
|
||||||
await interaction.response.defer()
|
await interaction.response.defer()
|
||||||
try:
|
try:
|
||||||
@ -216,7 +224,7 @@ class SpotifyModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Next Track",
|
title="Next Track",
|
||||||
description="Skipped to the next track.",
|
description="Skipped to the next track.",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info("Skipped to the next track")
|
logger.info("Skipped to the next track")
|
||||||
@ -235,7 +243,7 @@ class SpotifyModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Previous Track",
|
title="Previous Track",
|
||||||
description="Returned to the previous track.",
|
description="Returned to the previous track.",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info("Returned to the previous track")
|
logger.info("Returned to the previous track")
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
# Flake8:noqa: E501
|
# Flake8:noqa: E501
|
||||||
import discord
|
|
||||||
from discord import app_commands
|
|
||||||
import sqlite3
|
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from modules.data.db import initialize_db, get_connection
|
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
|
||||||
|
from modules.data.db import get_connection, initialize_db
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
initialize_db()
|
initialize_db()
|
||||||
@ -19,18 +20,18 @@ class CurrencyModule:
|
|||||||
self.add_commands()
|
self.add_commands()
|
||||||
|
|
||||||
def add_commands(self):
|
def add_commands(self):
|
||||||
@app_commands.command(
|
@app_commands.command(name="earn_kibble", description="Earn Kibble")
|
||||||
name="earn_kibble", description="Earn Kibble"
|
|
||||||
)
|
|
||||||
async def earn_kibble(interaction: discord.Interaction):
|
async def earn_kibble(interaction: discord.Interaction):
|
||||||
await interaction.response.defer()
|
await interaction.response.defer()
|
||||||
try:
|
try:
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
user_id = str(interaction.user.id)
|
user_id = str(interaction.user.id)
|
||||||
|
|
||||||
# Check cooldown
|
# Check cooldown
|
||||||
cursor.execute('SELECT last_earned FROM currency WHERE user_id = ?', (user_id,))
|
cursor.execute(
|
||||||
|
"SELECT last_earned FROM currency WHERE user_id = ?", (user_id,)
|
||||||
|
)
|
||||||
result = cursor.fetchone()
|
result = cursor.fetchone()
|
||||||
if result and result[0]:
|
if result and result[0]:
|
||||||
last_earned = datetime.fromisoformat(result[0])
|
last_earned = datetime.fromisoformat(result[0])
|
||||||
@ -39,30 +40,40 @@ class CurrencyModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Earn Kibble",
|
title="Earn Kibble",
|
||||||
description="You are on cooldown. Please try again later.",
|
description="You are on cooldown. Please try again later.",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
conn.close()
|
conn.close()
|
||||||
logger.info(f"User {user_id} attempted to earn Kibble but is on cooldown.")
|
logger.info(
|
||||||
|
f"User {user_id} attempted to earn Kibble but is on cooldown."
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
amount = random.choices([random.randint(1, 10), 100], [0.99, 0.01])[0]
|
amount = random.choices([random.randint(1, 10), 100], [0.99, 0.01])[0]
|
||||||
cursor.execute('INSERT OR IGNORE INTO currency (user_id, balance, last_earned) VALUES (?, ?, ?)',
|
cursor.execute(
|
||||||
(user_id, 0, datetime.now().isoformat()))
|
"INSERT OR IGNORE INTO currency (user_id, balance, last_earned) VALUES (?, ?, ?)",
|
||||||
cursor.execute('UPDATE currency SET balance = balance + ?, last_earned = ? WHERE user_id = ?',
|
(user_id, 0, datetime.now().isoformat()),
|
||||||
(amount, datetime.now().isoformat(), user_id))
|
)
|
||||||
|
cursor.execute(
|
||||||
|
"UPDATE currency SET balance = balance + ?, last_earned = ? WHERE user_id = ?",
|
||||||
|
(amount, datetime.now().isoformat(), user_id),
|
||||||
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
cursor.execute('SELECT balance FROM currency WHERE user_id = ?', (user_id,))
|
cursor.execute(
|
||||||
|
"SELECT balance FROM currency WHERE user_id = ?", (user_id,)
|
||||||
|
)
|
||||||
new_balance = cursor.fetchone()[0]
|
new_balance = cursor.fetchone()[0]
|
||||||
conn.close()
|
conn.close()
|
||||||
await interaction.followup.send(
|
await interaction.followup.send(
|
||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Earn Kibble",
|
title="Earn Kibble",
|
||||||
description=f"You have earned {amount} Kibble. Your new balance is {new_balance}.",
|
description=f"You have earned {amount} Kibble. Your new balance is {new_balance}.",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"User {user_id} earned {amount} Kibble. New balance: {new_balance}")
|
logger.info(
|
||||||
|
f"User {user_id} earned {amount} Kibble. New balance: {new_balance}"
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await interaction.followup.send(f"An error occurred: {e}")
|
await interaction.followup.send(f"An error occurred: {e}")
|
||||||
logger.error(f"Error in earn_kibble command: {e}")
|
logger.error(f"Error in earn_kibble command: {e}")
|
||||||
@ -75,7 +86,10 @@ class CurrencyModule:
|
|||||||
try:
|
try:
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute('SELECT balance FROM currency WHERE user_id = ?', (str(interaction.user.id),))
|
cursor.execute(
|
||||||
|
"SELECT balance FROM currency WHERE user_id = ?",
|
||||||
|
(str(interaction.user.id),),
|
||||||
|
)
|
||||||
result = cursor.fetchone()
|
result = cursor.fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
if result:
|
if result:
|
||||||
@ -83,16 +97,18 @@ class CurrencyModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Check Balance",
|
title="Check Balance",
|
||||||
description=f"Your current balance is {result[0]} Kibble.",
|
description=f"Your current balance is {result[0]} Kibble.",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"User {interaction.user.id} checked balance: {result[0]}")
|
logger.info(
|
||||||
|
f"User {interaction.user.id} checked balance: {result[0]}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
await interaction.followup.send(
|
await interaction.followup.send(
|
||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Check Balance",
|
title="Check Balance",
|
||||||
description="You have no Kibble.",
|
description="You have no Kibble.",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"User {interaction.user.id} has no Kibble.")
|
logger.info(f"User {interaction.user.id} has no Kibble.")
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
from twitchAPI.twitch import Twitch
|
|
||||||
from twitchAPI.helper import first
|
from twitchAPI.helper import first
|
||||||
import logging
|
from twitchAPI.twitch import Twitch
|
||||||
|
|
||||||
import config
|
import config
|
||||||
import asyncio
|
|
||||||
from modules.data.db import get_connection
|
from modules.data.db import get_connection
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -13,8 +15,7 @@ logger = logging.getLogger(__name__)
|
|||||||
class TwitchModule:
|
class TwitchModule:
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.twitch = Twitch(config.TWITCH_CLIENT_ID,
|
self.twitch = Twitch(config.TWITCH_CLIENT_ID, config.TWITCH_CLIENT_SECRET)
|
||||||
config.TWITCH_CLIENT_SECRET)
|
|
||||||
self.bot.loop.create_task(self.authenticate_twitch())
|
self.bot.loop.create_task(self.authenticate_twitch())
|
||||||
self.bot.loop.create_task(self.check_live_streams())
|
self.bot.loop.create_task(self.check_live_streams())
|
||||||
self.add_commands()
|
self.add_commands()
|
||||||
@ -26,15 +27,17 @@ class TwitchModule:
|
|||||||
while True:
|
while True:
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute('''
|
c.execute(
|
||||||
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS live_status (
|
CREATE TABLE IF NOT EXISTS live_status (
|
||||||
twitch_name TEXT PRIMARY KEY,
|
twitch_name TEXT PRIMARY KEY,
|
||||||
is_live BOOLEAN
|
is_live BOOLEAN
|
||||||
)
|
)
|
||||||
''')
|
"""
|
||||||
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
c.execute('SELECT twitch_name, discord_channel_id FROM followed_channels')
|
c.execute("SELECT twitch_name, discord_channel_id FROM followed_channels")
|
||||||
followed_channels = c.fetchall()
|
followed_channels = c.fetchall()
|
||||||
|
|
||||||
for twitch_name, discord_channel_id in followed_channels:
|
for twitch_name, discord_channel_id in followed_channels:
|
||||||
@ -47,7 +50,10 @@ class TwitchModule:
|
|||||||
streams = await first(self.twitch.get_streams(user_id=[user_id]))
|
streams = await first(self.twitch.get_streams(user_id=[user_id]))
|
||||||
is_live = streams is not None
|
is_live = streams is not None
|
||||||
|
|
||||||
c.execute('SELECT is_live FROM live_status WHERE twitch_name = ?', (twitch_name,))
|
c.execute(
|
||||||
|
"SELECT is_live FROM live_status WHERE twitch_name = ?",
|
||||||
|
(twitch_name,),
|
||||||
|
)
|
||||||
row = c.fetchone()
|
row = c.fetchone()
|
||||||
was_live = row[0] if row else False
|
was_live = row[0] if row else False
|
||||||
|
|
||||||
@ -61,18 +67,26 @@ class TwitchModule:
|
|||||||
f"**Game:** {streams.game_name}\n"
|
f"**Game:** {streams.game_name}\n"
|
||||||
f"**Viewers:** {streams.viewer_count}"
|
f"**Viewers:** {streams.viewer_count}"
|
||||||
),
|
),
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
embed.set_thumbnail(
|
embed.set_thumbnail(
|
||||||
url=streams.thumbnail_url.replace('{width}', '320').replace('{height}', '180')
|
url=streams.thumbnail_url.replace(
|
||||||
|
"{width}", "320"
|
||||||
|
).replace("{height}", "180")
|
||||||
)
|
)
|
||||||
await channel.send(embed=embed)
|
await channel.send(embed=embed)
|
||||||
|
|
||||||
c.execute('INSERT OR REPLACE INTO live_status (twitch_name, is_live) VALUES (?, ?)', (twitch_name, is_live))
|
c.execute(
|
||||||
|
"INSERT OR REPLACE INTO live_status (twitch_name, is_live) VALUES (?, ?)",
|
||||||
|
(twitch_name, is_live),
|
||||||
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error checking live status for {twitch_name}: {e}", exc_info=True)
|
logger.error(
|
||||||
|
f"Error checking live status for {twitch_name}: {e}",
|
||||||
|
exc_info=True,
|
||||||
|
)
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
await asyncio.sleep(300) # Check every 5 minutes
|
await asyncio.sleep(300) # Check every 5 minutes
|
||||||
@ -80,15 +94,19 @@ class TwitchModule:
|
|||||||
def add_commands(self):
|
def add_commands(self):
|
||||||
@app_commands.command(
|
@app_commands.command(
|
||||||
name="follow_twitch",
|
name="follow_twitch",
|
||||||
description="Follow a Twitch channel to get live alerts"
|
description="Follow a Twitch channel to get live alerts",
|
||||||
)
|
)
|
||||||
async def follow_twitch(interaction: discord.Interaction, twitch_name: str, channel: discord.TextChannel = None):
|
async def follow_twitch(
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
twitch_name: str,
|
||||||
|
channel: discord.TextChannel = None,
|
||||||
|
):
|
||||||
channel = channel or interaction.channel
|
channel = channel or interaction.channel
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute(
|
c.execute(
|
||||||
'INSERT OR REPLACE INTO followed_channels (twitch_name, discord_channel_id) VALUES (?, ?)',
|
"INSERT OR REPLACE INTO followed_channels (twitch_name, discord_channel_id) VALUES (?, ?)",
|
||||||
(twitch_name, channel.id)
|
(twitch_name, channel.id),
|
||||||
)
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
@ -96,40 +114,34 @@ class TwitchModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Followed Twitch Channel",
|
title="Followed Twitch Channel",
|
||||||
description=f"Now following {twitch_name}. Alerts will be sent to {channel.mention}.",
|
description=f"Now following {twitch_name}. Alerts will be sent to {channel.mention}.",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"Now following {twitch_name} for alerts in {channel.name}")
|
logger.info(f"Now following {twitch_name} for alerts in {channel.name}")
|
||||||
|
|
||||||
@app_commands.command(
|
@app_commands.command(
|
||||||
name="unfollow_twitch",
|
name="unfollow_twitch", description="Unfollow a Twitch channel"
|
||||||
description="Unfollow a Twitch channel"
|
|
||||||
)
|
)
|
||||||
async def unfollow_twitch(interaction: discord.Interaction, twitch_name: str):
|
async def unfollow_twitch(interaction: discord.Interaction, twitch_name: str):
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute(
|
c.execute(
|
||||||
'DELETE FROM followed_channels WHERE twitch_name = ?',
|
"DELETE FROM followed_channels WHERE twitch_name = ?", (twitch_name,)
|
||||||
(twitch_name,)
|
|
||||||
)
|
|
||||||
c.execute(
|
|
||||||
'DELETE FROM live_status WHERE twitch_name = ?',
|
|
||||||
(twitch_name,)
|
|
||||||
)
|
)
|
||||||
|
c.execute("DELETE FROM live_status WHERE twitch_name = ?", (twitch_name,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
await interaction.response.send_message(
|
await interaction.response.send_message(
|
||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Unfollowed Twitch Channel",
|
title="Unfollowed Twitch Channel",
|
||||||
description=f"No longer following {twitch_name}.",
|
description=f"No longer following {twitch_name}.",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"No longer following {twitch_name}")
|
logger.info(f"No longer following {twitch_name}")
|
||||||
|
|
||||||
@app_commands.command(
|
@app_commands.command(
|
||||||
name="twitch_live",
|
name="twitch_live", description="Check if a Twitch streamer is live"
|
||||||
description="Check if a Twitch streamer is live"
|
|
||||||
)
|
)
|
||||||
async def twitch_live(interaction: discord.Interaction, streamer: str):
|
async def twitch_live(interaction: discord.Interaction, streamer: str):
|
||||||
await interaction.response.defer()
|
await interaction.response.defer()
|
||||||
@ -141,7 +153,7 @@ class TwitchModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Twitch Live Check",
|
title="Twitch Live Check",
|
||||||
description=f"Streamer {streamer} not found.",
|
description=f"Streamer {streamer} not found.",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"Streamer {streamer} not found.")
|
logger.info(f"Streamer {streamer} not found.")
|
||||||
@ -158,10 +170,12 @@ class TwitchModule:
|
|||||||
f"**Game:** {streams.game_name}\n"
|
f"**Game:** {streams.game_name}\n"
|
||||||
f"**Viewers:** {streams.viewer_count}"
|
f"**Viewers:** {streams.viewer_count}"
|
||||||
),
|
),
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
embed.set_thumbnail(
|
embed.set_thumbnail(
|
||||||
url=streams.thumbnail_url.replace('{width}', '320').replace('{height}', '180')
|
url=streams.thumbnail_url.replace("{width}", "320").replace(
|
||||||
|
"{height}", "180"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
await interaction.followup.send(embed=embed)
|
await interaction.followup.send(embed=embed)
|
||||||
logger.info(f"Streamer {streamer} is live.")
|
logger.info(f"Streamer {streamer} is live.")
|
||||||
@ -170,7 +184,7 @@ class TwitchModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title=f"{streamer} is not live",
|
title=f"{streamer} is not live",
|
||||||
description=f"{streamer} is currently offline.",
|
description=f"{streamer} is currently offline.",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"Streamer {streamer} is offline.")
|
logger.info(f"Streamer {streamer} is offline.")
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
# modules/social/youtube_module.py
|
# modules/social/youtube_module.py
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
from googleapiclient.discovery import build
|
from googleapiclient.discovery import build
|
||||||
import logging
|
|
||||||
import config
|
import config
|
||||||
import asyncio
|
|
||||||
from modules.data.db import get_connection
|
from modules.data.db import get_connection
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -13,7 +15,7 @@ logger = logging.getLogger(__name__)
|
|||||||
class YouTubeModule:
|
class YouTubeModule:
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.youtube = build('youtube', 'v3', developerKey=config.YOUTUBE_API_KEY)
|
self.youtube = build("youtube", "v3", developerKey=config.YOUTUBE_API_KEY)
|
||||||
self.bot.loop.create_task(self.check_youtube_channels())
|
self.bot.loop.create_task(self.check_youtube_channels())
|
||||||
self.add_commands()
|
self.add_commands()
|
||||||
|
|
||||||
@ -21,34 +23,38 @@ class YouTubeModule:
|
|||||||
while True:
|
while True:
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute('SELECT youtube_channel_id, discord_channel_id FROM followed_youtube_channels')
|
c.execute(
|
||||||
|
"SELECT youtube_channel_id, discord_channel_id FROM followed_youtube_channels"
|
||||||
|
)
|
||||||
followed_channels = c.fetchall()
|
followed_channels = c.fetchall()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
for youtube_channel_id, discord_channel_id in followed_channels:
|
for youtube_channel_id, discord_channel_id in followed_channels:
|
||||||
try:
|
try:
|
||||||
request = self.youtube.channels().list(
|
request = self.youtube.channels().list(
|
||||||
part='contentDetails',
|
part="contentDetails", id=youtube_channel_id
|
||||||
id=youtube_channel_id
|
|
||||||
)
|
)
|
||||||
response = request.execute()
|
response = request.execute()
|
||||||
if 'items' in response and len(response['items']) > 0:
|
if "items" in response and len(response["items"]) > 0:
|
||||||
uploads_playlist_id = response['items'][0]['contentDetails']['relatedPlaylists']['uploads']
|
uploads_playlist_id = response["items"][0]["contentDetails"][
|
||||||
|
"relatedPlaylists"
|
||||||
|
]["uploads"]
|
||||||
|
|
||||||
request = self.youtube.playlistItems().list(
|
request = self.youtube.playlistItems().list(
|
||||||
part='snippet',
|
part="snippet", playlistId=uploads_playlist_id, maxResults=1
|
||||||
playlistId=uploads_playlist_id,
|
|
||||||
maxResults=1
|
|
||||||
)
|
)
|
||||||
response = request.execute()
|
response = request.execute()
|
||||||
if 'items' in response and len(response['items']) > 0:
|
if "items" in response and len(response["items"]) > 0:
|
||||||
latest_video = response['items'][0]['snippet']
|
latest_video = response["items"][0]["snippet"]
|
||||||
video_id = latest_video['resourceId']['videoId']
|
video_id = latest_video["resourceId"]["videoId"]
|
||||||
title = latest_video['title']
|
title = latest_video["title"]
|
||||||
publish_time = latest_video['publishedAt']
|
latest_video["publishedAt"]
|
||||||
thumbnail_url = latest_video['thumbnails']['high']['url']
|
thumbnail_url = latest_video["thumbnails"]["high"]["url"]
|
||||||
|
|
||||||
c.execute('SELECT last_video_id FROM youtube_status WHERE youtube_channel_id = ?', (youtube_channel_id,))
|
c.execute(
|
||||||
|
"SELECT last_video_id FROM youtube_status WHERE youtube_channel_id = ?",
|
||||||
|
(youtube_channel_id,),
|
||||||
|
)
|
||||||
row = c.fetchone()
|
row = c.fetchone()
|
||||||
last_video_id = row[0] if row else None
|
last_video_id = row[0] if row else None
|
||||||
|
|
||||||
@ -58,15 +64,21 @@ class YouTubeModule:
|
|||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title=f"New Video from {youtube_channel_id}",
|
title=f"New Video from {youtube_channel_id}",
|
||||||
description=f"{title}\n[Watch now](https://www.youtube.com/watch?v={video_id})",
|
description=f"{title}\n[Watch now](https://www.youtube.com/watch?v={video_id})",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
embed.set_thumbnail(url=thumbnail_url)
|
embed.set_thumbnail(url=thumbnail_url)
|
||||||
await channel.send(embed=embed)
|
await channel.send(embed=embed)
|
||||||
|
|
||||||
c.execute('INSERT OR REPLACE INTO youtube_status (youtube_channel_id, last_video_id) VALUES (?, ?)', (youtube_channel_id, video_id))
|
c.execute(
|
||||||
|
"INSERT OR REPLACE INTO youtube_status (youtube_channel_id, last_video_id) VALUES (?, ?)",
|
||||||
|
(youtube_channel_id, video_id),
|
||||||
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error checking YouTube channel {youtube_channel_id}: {e}", exc_info=True)
|
logger.error(
|
||||||
|
f"Error checking YouTube channel {youtube_channel_id}: {e}",
|
||||||
|
exc_info=True,
|
||||||
|
)
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
await asyncio.sleep(300) # Check every 5 minutes
|
await asyncio.sleep(300) # Check every 5 minutes
|
||||||
@ -74,15 +86,19 @@ class YouTubeModule:
|
|||||||
def add_commands(self):
|
def add_commands(self):
|
||||||
@app_commands.command(
|
@app_commands.command(
|
||||||
name="follow_youtube",
|
name="follow_youtube",
|
||||||
description="Follow a YouTube channel to get video updates"
|
description="Follow a YouTube channel to get video updates",
|
||||||
)
|
)
|
||||||
async def follow_youtube(interaction: discord.Interaction, youtube_channel_id: str, channel: discord.TextChannel = None):
|
async def follow_youtube(
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
youtube_channel_id: str,
|
||||||
|
channel: discord.TextChannel = None,
|
||||||
|
):
|
||||||
channel = channel or interaction.channel
|
channel = channel or interaction.channel
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute(
|
c.execute(
|
||||||
'INSERT OR REPLACE INTO followed_youtube_channels (youtube_channel_id, discord_channel_id) VALUES (?, ?)',
|
"INSERT OR REPLACE INTO followed_youtube_channels (youtube_channel_id, discord_channel_id) VALUES (?, ?)",
|
||||||
(youtube_channel_id, channel.id)
|
(youtube_channel_id, channel.id),
|
||||||
)
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
@ -90,25 +106,28 @@ class YouTubeModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Followed YouTube Channel",
|
title="Followed YouTube Channel",
|
||||||
description=f"Now following {youtube_channel_id}. Alerts will be sent to {channel.mention}.",
|
description=f"Now following {youtube_channel_id}. Alerts will be sent to {channel.mention}.",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"Now following {youtube_channel_id} for video updates in {channel.name}")
|
logger.info(
|
||||||
|
f"Now following {youtube_channel_id} for video updates in {channel.name}"
|
||||||
|
)
|
||||||
|
|
||||||
@app_commands.command(
|
@app_commands.command(
|
||||||
name="unfollow_youtube",
|
name="unfollow_youtube", description="Unfollow a YouTube channel"
|
||||||
description="Unfollow a YouTube channel"
|
|
||||||
)
|
)
|
||||||
async def unfollow_youtube(interaction: discord.Interaction, youtube_channel_id: str):
|
async def unfollow_youtube(
|
||||||
|
interaction: discord.Interaction, youtube_channel_id: str
|
||||||
|
):
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute(
|
c.execute(
|
||||||
'DELETE FROM followed_youtube_channels WHERE youtube_channel_id = ?',
|
"DELETE FROM followed_youtube_channels WHERE youtube_channel_id = ?",
|
||||||
(youtube_channel_id,)
|
(youtube_channel_id,),
|
||||||
)
|
)
|
||||||
c.execute(
|
c.execute(
|
||||||
'DELETE FROM youtube_status WHERE youtube_channel_id = ?',
|
"DELETE FROM youtube_status WHERE youtube_channel_id = ?",
|
||||||
(youtube_channel_id,)
|
(youtube_channel_id,),
|
||||||
)
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
@ -116,7 +135,7 @@ class YouTubeModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Unfollowed YouTube Channel",
|
title="Unfollowed YouTube Channel",
|
||||||
description=f"No longer following {youtube_channel_id}.",
|
description=f"No longer following {youtube_channel_id}.",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"No longer following {youtube_channel_id}")
|
logger.info(f"No longer following {youtube_channel_id}")
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
# Flake8:noqa: E501
|
# Flake8:noqa: E501
|
||||||
|
import logging
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
import sqlite3
|
|
||||||
import logging
|
from modules.data.db import get_connection, initialize_db
|
||||||
from modules.data.db import initialize_db, get_connection
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
initialize_db()
|
initialize_db()
|
||||||
@ -15,23 +16,23 @@ class BirthdayModule:
|
|||||||
self.add_commands()
|
self.add_commands()
|
||||||
|
|
||||||
def add_commands(self):
|
def add_commands(self):
|
||||||
@app_commands.command(
|
@app_commands.command(name="add_birthday", description="Add your birthday")
|
||||||
name="add_birthday", description="Add your birthday"
|
|
||||||
)
|
|
||||||
async def add_birthday(interaction: discord.Interaction, date: str):
|
async def add_birthday(interaction: discord.Interaction, date: str):
|
||||||
await interaction.response.defer()
|
await interaction.response.defer()
|
||||||
try:
|
try:
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute('INSERT OR REPLACE INTO birthdays (user_id, birthday) VALUES (?, ?)',
|
cursor.execute(
|
||||||
(str(interaction.user.id), date))
|
"INSERT OR REPLACE INTO birthdays (user_id, birthday) VALUES (?, ?)",
|
||||||
|
(str(interaction.user.id), date),
|
||||||
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
await interaction.followup.send(
|
await interaction.followup.send(
|
||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Add Birthday",
|
title="Add Birthday",
|
||||||
description=f"Your birthday {date} has been added.",
|
description=f"Your birthday {date} has been added.",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"Birthday added for user {interaction.user.id}: {date}")
|
logger.info(f"Birthday added for user {interaction.user.id}: {date}")
|
||||||
@ -39,15 +40,16 @@ class BirthdayModule:
|
|||||||
await interaction.followup.send(f"An error occurred: {e}")
|
await interaction.followup.send(f"An error occurred: {e}")
|
||||||
logger.error(f"Error in add_birthday command: {e}")
|
logger.error(f"Error in add_birthday command: {e}")
|
||||||
|
|
||||||
@app_commands.command(
|
@app_commands.command(name="view_birthday", description="View your birthday")
|
||||||
name="view_birthday", description="View your birthday"
|
|
||||||
)
|
|
||||||
async def view_birthday(interaction: discord.Interaction):
|
async def view_birthday(interaction: discord.Interaction):
|
||||||
await interaction.response.defer()
|
await interaction.response.defer()
|
||||||
try:
|
try:
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute('SELECT birthday FROM birthdays WHERE user_id = ?', (str(interaction.user.id),))
|
cursor.execute(
|
||||||
|
"SELECT birthday FROM birthdays WHERE user_id = ?",
|
||||||
|
(str(interaction.user.id),),
|
||||||
|
)
|
||||||
result = cursor.fetchone()
|
result = cursor.fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
if result:
|
if result:
|
||||||
@ -55,16 +57,18 @@ class BirthdayModule:
|
|||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="View Birthday",
|
title="View Birthday",
|
||||||
description=f"Your birthday is {result[0]}.",
|
description=f"Your birthday is {result[0]}.",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"Birthday viewed for user {interaction.user.id}: {result[0]}")
|
logger.info(
|
||||||
|
f"Birthday viewed for user {interaction.user.id}: {result[0]}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
await interaction.followup.send(
|
await interaction.followup.send(
|
||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="View Birthday",
|
title="View Birthday",
|
||||||
description="You have not set a birthday yet.",
|
description="You have not set a birthday yet.",
|
||||||
color=discord.Color.red()
|
color=discord.Color.red(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"Birthday not found for user {interaction.user.id}")
|
logger.info(f"Birthday not found for user {interaction.user.id}")
|
||||||
@ -80,14 +84,17 @@ class BirthdayModule:
|
|||||||
try:
|
try:
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute('DELETE FROM birthdays WHERE user_id = ?', (str(interaction.user.id),))
|
cursor.execute(
|
||||||
|
"DELETE FROM birthdays WHERE user_id = ?",
|
||||||
|
(str(interaction.user.id),),
|
||||||
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
await interaction.followup.send(
|
await interaction.followup.send(
|
||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="Remove Birthday",
|
title="Remove Birthday",
|
||||||
description="Your birthday has been removed.",
|
description="Your birthday has been removed.",
|
||||||
color=discord.Color.green()
|
color=discord.Color.green(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.info(f"Birthday removed for user {interaction.user.id}")
|
logger.info(f"Birthday removed for user {interaction.user.id}")
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
|
import logging
|
||||||
|
import random
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
import logging
|
|
||||||
from modules.data.db import get_connection
|
from modules.data.db import get_connection
|
||||||
from datetime import datetime, timedelta
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -12,25 +15,30 @@ class XPModule:
|
|||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.cooldown = {} # Dictionary to store cooldowns
|
self.cooldown = {} # Dictionary to store cooldowns
|
||||||
self.add_commands()
|
self.add_commands()
|
||||||
|
self.setup_event_listeners()
|
||||||
|
|
||||||
async def on_message(self, message):
|
async def on_message(self, message):
|
||||||
|
logger.debug(f"Received message from {message.author.id}")
|
||||||
if message.author.bot:
|
if message.author.bot:
|
||||||
|
logger.debug("Message is from a bot, ignoring")
|
||||||
return
|
return
|
||||||
|
|
||||||
user_id = message.author.id
|
user_id = message.author.id
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
|
|
||||||
if user_id in self.cooldown:
|
if user_id in self.cooldown and now < self.cooldown[user_id]:
|
||||||
if now < self.cooldown[user_id]:
|
logger.debug(f"User {user_id} is on cooldown, ignoring")
|
||||||
return # User is on cooldown
|
return # User is on cooldown
|
||||||
|
|
||||||
self.give_xp(user_id, 10) # Give 10 XP for a message
|
xp = random.randint(1, 5) # Award between 1 and 5 XP for a message
|
||||||
self.cooldown[user_id] = now + timedelta(seconds=60) # 1 minute cooldown
|
logger.debug(f"Awarding {xp} XP to user {user_id}")
|
||||||
|
self.give_xp(user_id, xp)
|
||||||
|
self.cooldown[user_id] = now + timedelta(seconds=60) # 1 minute cooldown # noqa: E501
|
||||||
|
|
||||||
def give_xp(self, user_id, xp):
|
def give_xp(self, user_id, xp):
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute('SELECT xp, level FROM user_xp WHERE user_id = ?', (user_id,))
|
c.execute("SELECT xp, level FROM user_xp WHERE user_id = ?", (user_id,)) # noqa: E501
|
||||||
row = c.fetchone()
|
row = c.fetchone()
|
||||||
|
|
||||||
if row:
|
if row:
|
||||||
@ -39,45 +47,55 @@ class XPModule:
|
|||||||
new_level = current_level
|
new_level = current_level
|
||||||
|
|
||||||
# Level up logic
|
# Level up logic
|
||||||
if new_xp >= self.xp_for_next_level(current_level):
|
while new_xp >= self.xp_for_next_level(new_level):
|
||||||
|
new_xp -= self.xp_for_next_level(new_level)
|
||||||
new_level += 1
|
new_level += 1
|
||||||
new_xp = new_xp - self.xp_for_next_level(current_level)
|
|
||||||
logger.info(f"User {user_id} leveled up to {new_level}")
|
logger.info(f"User {user_id} leveled up to {new_level}")
|
||||||
|
|
||||||
c.execute('UPDATE user_xp SET xp = ?, level = ? WHERE user_id = ?', (new_xp, new_level, user_id))
|
c.execute(
|
||||||
|
"UPDATE user_xp SET xp = ?, level = ? WHERE user_id = ?",
|
||||||
|
(new_xp, new_level, user_id),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
c.execute('INSERT INTO user_xp (user_id, xp, level) VALUES (?, ?, ?)', (user_id, xp, 1))
|
c.execute(
|
||||||
|
"INSERT INTO user_xp (user_id, xp, level) VALUES (?, ?, ?)",
|
||||||
|
(user_id, xp, 1),
|
||||||
|
)
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
logger.debug(f"Updated XP for user {user_id}")
|
||||||
|
|
||||||
def xp_for_next_level(self, level):
|
def xp_for_next_level(self, level):
|
||||||
return 100 * level # Example leveling curve
|
return int(
|
||||||
|
100 * (1.5 ** (level - 1))
|
||||||
|
) # Exponential scaling for XP required to level up
|
||||||
|
|
||||||
def add_commands(self):
|
def add_commands(self):
|
||||||
@app_commands.command(name='xp', description='Check your XP and level')
|
@app_commands.command(name="xp", description="Check your XP and level")
|
||||||
async def check_xp(interaction: discord.Interaction):
|
async def check_xp(interaction: discord.Interaction):
|
||||||
user_id = interaction.user.id
|
user_id = interaction.user.id
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute('SELECT xp, level FROM user_xp WHERE user_id = ?', (user_id,))
|
c.execute("SELECT xp, level FROM user_xp WHERE user_id = ?", (user_id,)) # noqa: E501
|
||||||
row = c.fetchone()
|
row = c.fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
if row:
|
if row:
|
||||||
xp, level = row
|
xp, level = row
|
||||||
await interaction.response.send_message(f"You have {xp} XP and are level {level}.")
|
await interaction.response.send_message(
|
||||||
|
f"You have {xp} XP and are level {level}."
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
await interaction.response.send_message("You have no XP yet.")
|
await interaction.response.send_message("You have no XP yet.")
|
||||||
|
|
||||||
self.bot.tree.add_command(check_xp)
|
self.bot.tree.add_command(check_xp)
|
||||||
|
|
||||||
|
def setup_event_listeners(self):
|
||||||
|
@self.bot.event
|
||||||
|
async def on_message(message):
|
||||||
|
await self.on_message(message)
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
async def setup(bot):
|
||||||
xp_module = XPModule(bot)
|
XPModule(bot)
|
||||||
|
|
||||||
@bot.event
|
|
||||||
async def on_message(message):
|
|
||||||
if not message.author.bot: # Ensure the bot doesn't earn XP
|
|
||||||
await xp_module.on_message(message)
|
|
||||||
await bot.process_commands(message) # Process commands after the XP check
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user