-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbot.py
More file actions
129 lines (105 loc) · 3.7 KB
/
bot.py
File metadata and controls
129 lines (105 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import os
import sys
import logging
import signal
import discord
from discord.ext import commands
from dotenv import load_dotenv
import asyncio
load_dotenv()
# Validate token early
DISCORD_TOKEN = os.getenv("DISCORD_TOKEN")
if not DISCORD_TOKEN:
print("ERROR: DISCORD_TOKEN environment variable is not set.")
print("Create a .env file with: DISCORD_TOKEN=your_token_here")
sys.exit(1)
# Set up logging to file only (no console output)
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
handlers=[
logging.FileHandler('bot.log', mode='w', encoding='utf-8')
]
)
logger = logging.getLogger('discord-bot')
intents = discord.Intents.default()
intents.message_content = True
intents.voice_states = True
bot = commands.Bot(command_prefix="?", intents=intents)
_cleanup_done = False
@bot.event
async def on_ready():
logger.info(f"{bot.user} is now online!")
print(f"{bot.user} is now online!")
await bot.change_presence(activity=discord.Activity(
type=discord.ActivityType.listening,
name="/play"
))
print("Bot ready!")
@bot.command(name="sync")
@commands.is_owner()
async def sync_commands(ctx):
"""Owner-only command to sync slash commands with Discord"""
try:
synced = await bot.tree.sync()
await ctx.send(f"Synced {len(synced)} slash commands.")
logger.info(f"Synced {len(synced)} slash commands")
except Exception as e:
await ctx.send(f"Failed to sync: {e}")
logger.error(f"Failed to sync commands: {e}", exc_info=True)
@bot.event
async def on_command_error(ctx, error):
if isinstance(error, commands.CommandNotFound):
return
elif isinstance(error, commands.NotOwner):
return
elif isinstance(error, commands.MissingRequiredArgument):
await ctx.send(f"Missing argument: {error.param.name}")
elif isinstance(error, commands.BadArgument):
await ctx.send(f"Invalid argument provided.")
else:
await ctx.send(f"An error occurred: {str(error)}")
logger.error(f"Command error: {error}", exc_info=True)
@bot.tree.error
async def on_app_command_error(interaction: discord.Interaction, error):
logger.error(f"Slash command error in /{interaction.command.name}: {error}", exc_info=True)
if interaction.response.is_done():
await interaction.followup.send(f"An error occurred: {str(error)}", ephemeral=True)
else:
await interaction.response.send_message(f"An error occurred: {str(error)}", ephemeral=True)
async def cleanup():
"""Clean up all player messages before shutdown"""
global _cleanup_done
if _cleanup_done:
return
_cleanup_done = True
logger.info("Cleaning up before shutdown...")
music_cog = bot.get_cog('Music')
if music_cog:
for guild_id in list(music_cog.players.keys()):
await music_cog.cleanup_player(guild_id)
logger.info("Cleanup complete")
print("Bot shutting down...")
async def main():
loop = asyncio.get_running_loop()
def signal_handler():
logger.info("Received shutdown signal")
print("Received shutdown signal...")
asyncio.create_task(shutdown())
async def shutdown():
await cleanup()
await bot.close()
# Only set signal handlers on Unix-like systems
if sys.platform != 'win32':
for sig in (signal.SIGTERM, signal.SIGINT):
loop.add_signal_handler(sig, signal_handler)
async with bot:
await bot.load_extension("cogs.music")
try:
await bot.start(DISCORD_TOKEN)
except asyncio.CancelledError:
pass
finally:
await cleanup()
if __name__ == "__main__":
asyncio.run(main())