-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbot.py
More file actions
152 lines (127 loc) · 5.28 KB
/
bot.py
File metadata and controls
152 lines (127 loc) · 5.28 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!./.venv/bin/python
# Copyright 2025 Lupsa Alexandra
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import discord # base discord module
import code # code.interact
import os # environment variables
import inspect # call stack inspection
import random # dumb random number generator
import argparse
from discord.ext import commands # Bot class and utils
################################################################################
############################### HELPER FUNCTIONS ###############################
################################################################################
# log_msg - fancy print
# @msg : string to print
# @level : log level from {'debug', 'info', 'warning', 'error'}
def log_msg(msg: str, level: str):
# user selectable display config (prompt symbol, color)
dsp_sel = {
'debug' : ('\033[34m', '-'),
'info' : ('\033[32m', '*'),
'warning' : ('\033[33m', '?'),
'error' : ('\033[31m', '!'),
}
# internal ansi codes
_extra_ansi = {
'critical' : '\033[35m',
'bold' : '\033[1m',
'unbold' : '\033[2m',
'clear' : '\033[0m',
}
# get information about call site
caller = inspect.stack()[1]
# input sanity check
if level not in dsp_sel:
print('%s%s[@] %s:%d %sBad log level: "%s"%s' % \
(_extra_ansi['critical'], _extra_ansi['bold'],
caller.function, caller.lineno,
_extra_ansi['unbold'], level, _extra_ansi['clear']))
return
# print the damn message already
print('%s%s[%s] %s:%d %s%s%s' % \
(_extra_ansi['bold'], *dsp_sel[level],
caller.function, caller.lineno,
_extra_ansi['unbold'], msg, _extra_ansi['clear']))
################################################################################
############################## BOT IMPLEMENTATION ##############################
################################################################################
parser = argparse.ArgumentParser()
parser.add_argument('-t', '--token', help='Bot token')
args = parser.parse_args()
token = args.token or os.getenv('TOKEN')
# bot instantiation
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='!', intents=intents)
# on_ready - called after connection to server is established
@bot.event
async def on_ready():
log_msg('logged on as <%s>' % bot.user, 'info')
# on_message - called when a new message is posted to the server
# @msg : discord.message.Message
@bot.event
async def on_message(msg):
# filter out our own messages
if msg.author == bot.user:
return
log_msg('message from <%s>: "%s"' % (msg.author, msg.content), 'debug')
# overriding the default on_message handler blocks commands from executing
# manually call the bot's command processor on given message
await bot.process_commands(msg)
# roll - rng chat command
# @ctx : command invocation context
# @max_val : upper bound for number generation (must be at least 1)
@bot.command()
async def join(ctx):
if ctx.author.voice is None:
await ctx.send("You need to be in a voice channel to join!")
else:
channel = ctx.author.voice.channel
await channel.connect()
@bot.command()
async def play(ctx):
if ctx.voice_client is None:
if ctx.author.voice is None:
await ctx.send("You need to be in a voice channel to join!")
log_msg("User is not in a voice channel.", "error")
return
else:
log_msg(f"User is in channel: {ctx.author.voice.channel}", "info")
channel = ctx.author.voice.channel
await channel.connect()
source = discord.FFmpegPCMAudio("Don Toliver - No Pole [Official Visualizer] [ ezmp3.cc ].mp3")
ctx.voice_client.play(source)
@bot.command()
async def disc(ctx):
await ctx.voice_client.disconnect()
@bot.command(brief='Generate random number between 1 and <arg>')
async def roll(ctx, max_val: int):
# argument sanity check
if max_val < 1:
raise Exception('argument <max_val> must be at least 1')
await ctx.send(random.randint(1, max_val))
# roll_error - error handler for the <roll> command
# @ctx : command that crashed invocation context
# @error : ...
@roll.error
async def roll_error(ctx, error):
await ctx.send(str(error))
################################################################################
############################# PROGRAM ENTRY POINT ##############################
################################################################################
if __name__ == '__main__':
# check that token exists in environment
# launch bot (blocking operation)
bot.run(token)