bhagatsuryainatom commited on
Commit
62543a2
Β·
verified Β·
1 Parent(s): f6825ed

Create main.py

Browse files
Files changed (1) hide show
  1. main.py +277 -0
main.py ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import discord
3
+ from discord.ext import commands, tasks
4
+ from collections import defaultdict
5
+ import json
6
+ import os
7
+ from dotenv import load_dotenv
8
+ import os
9
+ load_dotenv()
10
+
11
+ intents = discord.Intents.default()
12
+ intents.messages = True
13
+ intents.message_content = True
14
+ intents.voice_states = True
15
+ intents.reactions = True
16
+
17
+ bot = commands.Bot(command_prefix='!', intents=intents)
18
+
19
+ # Place your bot's token here
20
+ TOKEN = os.getenv('TOKEN')
21
+ YOUR_CHANNEL_ID= os.getenv('YOUR_CHANNEL_ID')
22
+
23
+ # Initialize the sessions and pending_messages dictionaries
24
+ sessions = {}
25
+ pending_messages = {}
26
+
27
+ class Session:
28
+ def __init__(self):
29
+ self.camera_required = False
30
+ self.time_without_video = defaultdict(int)
31
+ self.warnings_given = defaultdict(int)
32
+ self.exemptions = set()
33
+ self.instructions_sent = False # Flag to track if instructions have been sent
34
+
35
+ def to_dict(self):
36
+ # Convert sets of Member IDs to lists for JSON serialization
37
+ return {
38
+ "camera_required": self.camera_required,
39
+ "time_without_video": {str(member_id): time for member_id, time in self.time_without_video.items()},
40
+ "warnings_given": {str(member_id): warnings for member_id, warnings in self.warnings_given.items()},
41
+ "exemptions": list(self.exemptions) # Assuming this already stores member IDs
42
+ }
43
+
44
+ @classmethod
45
+ def from_dict(cls, data):
46
+ session = cls()
47
+ session.camera_required = data.get("camera_required", False)
48
+ session.time_without_video = defaultdict(int, data.get("time_without_video", {}))
49
+ session.warnings_given = defaultdict(int, data.get("warnings_given", {}))
50
+ session.exemptions = set(data.get("exemptions", []))
51
+ session.instructions_sent = data.get("instructions_sent", False)
52
+ return session
53
+
54
+
55
+ def save_sessions():
56
+ with open('sessions.json', 'w') as f:
57
+ json.dump({str(vc_id): session.to_dict() for vc_id, session in sessions.items()}, f, ensure_ascii=False, indent=4)
58
+ def correct_and_load_json(path):
59
+ try:
60
+ with open(path, 'r') as file:
61
+ return json.load(file)
62
+ except json.JSONDecodeError:
63
+ print("JSON format error detected. Attempting to correct.")
64
+ with open(path, 'r') as file:
65
+ file_content = file.read()
66
+ corrected_content = file_content.replace("'", '"') # Replace single quotes with double quotes
67
+ # Implement other corrections here as needed
68
+ with open(path, 'w') as file:
69
+ file.write(corrected_content)
70
+ with open(path, 'r') as file:
71
+ return json.load(file) # Attempt to load corrected content
72
+
73
+
74
+ def load_sessions():
75
+ if os.path.exists('sessions.json') and os.path.getsize('sessions.json') > 0:
76
+ try:
77
+ session_data = correct_and_load_json('sessions.json')
78
+ for vc_id, data in session_data.items():
79
+ sessions[int(vc_id)] = Session.from_dict(data)
80
+ except json.JSONDecodeError:
81
+ print("Failed to correct JSON file. Please check the file format manually.")
82
+ else:
83
+ print("Session file not found or is empty, starting fresh.")
84
+ @bot.event
85
+ async def on_ready():
86
+ load_sessions()
87
+ print(f'Logged in as {bot.user.name}')
88
+ check_camera_status.start()
89
+ # Ensure save_sessions_task starts properly within the on_ready event
90
+ if not save_sessions_task.is_running():
91
+ save_sessions_task.start()
92
+
93
+
94
+ @bot.command()
95
+ async def test(ctx):
96
+ await ctx.send("Test successful!")
97
+
98
+
99
+ @tasks.loop(seconds=30)
100
+ async def check_camera_status():
101
+ for vc_id, session in sessions.items():
102
+ if not session.camera_required:
103
+ continue
104
+ vc = bot.get_channel(vc_id)
105
+ if vc is None:
106
+ continue
107
+ for member in vc.members:
108
+ if member.id in session.exemptions:
109
+ continue
110
+ if not member.voice.self_video:
111
+ session.time_without_video[member] += 30
112
+ if session.time_without_video[member] == 30:
113
+ session.warnings_given[member] = 1
114
+ await member.send("Warning 1: Please turn on your camera within the next 30 seconds.")
115
+ elif session.time_without_video[member] >= 60:
116
+ session.warnings_given[member] = 2
117
+ await member.send("Final Warning: You are being removed for not turning on your camera.")
118
+ await member.move_to(None)
119
+ # Reset the member's session data
120
+ session.time_without_video.pop(member, None)
121
+ session.warnings_given.pop(member, None)
122
+ else:
123
+ # Reset the member's session data if their camera is on
124
+ session.time_without_video.pop(member, None)
125
+ session.warnings_given.pop(member, None)
126
+
127
+ @tasks.loop(minutes=5) # Save sessions every 5 minutes
128
+ async def save_sessions_task():
129
+ save_sessions()
130
+ print("Sessions saved.")
131
+
132
+ @save_sessions_task.before_loop
133
+ async def before_save_sessions():
134
+ await bot.wait_until_ready()
135
+
136
+
137
+ @bot.event
138
+ async def on_voice_state_update(member, before, after):
139
+ if member.bot:
140
+ return
141
+
142
+ if after.channel and (not before.channel or before.channel.id != after.channel.id):
143
+ session = sessions.get(after.channel.id)
144
+ if session is None:
145
+ session = Session()
146
+ sessions[after.channel.id] = session
147
+
148
+ if any(role.name == "Admin" for role in member.roles):
149
+ other_admins_in_channel = [m for m in after.channel.members if m != member and any(role.name == "Admin" for role in m.roles)]
150
+
151
+ if not other_admins_in_channel:
152
+ # Replace "YOUR_CHANNEL_ID" with your actual general channel ID
153
+ general_channel_id = YOUR_CHANNEL_ID
154
+ general_channel = member.guild.get_channel(int(general_channel_id))
155
+ if not general_channel:
156
+ print(f"Couldn't find the channel with ID: {general_channel_id}.")
157
+ return
158
+
159
+ message_content = f"Admin {member.mention}, do you require cameras to be ON for this session in {after.channel.name}? React with πŸ“· for YES or ❌ for NO."
160
+
161
+ try:
162
+ message = await general_channel.send(message_content)
163
+ pending_messages[message.id] = after.channel.id
164
+
165
+ await message.add_reaction("πŸ“·")
166
+ await message.add_reaction("❌")
167
+ except discord.DiscordException as e:
168
+ print(f"Failed to send message or add reactions due to: {e}")
169
+
170
+
171
+ @bot.command()
172
+ @commands.has_permissions(manage_channels=True)
173
+ async def setperms(ctx, channel: discord.TextChannel = None):
174
+ channel = channel or ctx.channel
175
+ if not channel.permissions_for(ctx.guild.me).manage_channels:
176
+ await ctx.send("I don't have permission to manage channels here.")
177
+ return
178
+ bot_member = ctx.guild.get_member(bot.user.id)
179
+ overwrites = {
180
+ ctx.guild.default_role: discord.PermissionOverwrite(read_messages=False),
181
+ bot_member: discord.PermissionOverwrite(read_messages=True, send_messages=True, manage_messages=True, add_reactions=True)
182
+ }
183
+ try:
184
+ await channel.set_permissions(ctx.guild.default_role, read_messages=False)
185
+ await channel.set_permissions(bot_member, **overwrites)
186
+ await ctx.send(f"Permissions set for {channel.mention} successfully!")
187
+ except Exception as e:
188
+ await ctx.send(f"Failed to set permissions for {channel.mention} due to: {e}")
189
+
190
+ @bot.event
191
+ async def on_reaction_add(reaction, user):
192
+ await process_reaction(reaction, user)
193
+
194
+ @bot.event
195
+ async def on_reaction_remove(reaction, user):
196
+ await process_reaction(reaction, user)
197
+
198
+ async def process_reaction(reaction, user):
199
+ if reaction.message.id in pending_messages and not user.bot:
200
+ channel_id = pending_messages[reaction.message.id]
201
+ session = sessions.get(channel_id)
202
+
203
+ if session and any(role.name == "Admin" for role in user.roles):
204
+ if str(reaction.emoji) == "πŸ“·":
205
+ session.camera_required = True
206
+ session.exemptions.clear()
207
+ elif str(reaction.emoji) == "❌":
208
+ session.camera_required = False
209
+ session.exemptions.clear()
210
+
211
+ # Edit the message to reflect the updated session status
212
+ await reaction.message.edit(content=f"Camera requirement for {reaction.message.channel.guild.get_channel(channel_id).name} has been {'UPDATED to ON' if session.camera_required else 'UPDATED to OFF'}.")
213
+
214
+ # Send instructions only if they haven't been sent before
215
+ if not session.instructions_sent:
216
+ follow_up_message = (
217
+ "**Next Steps for Admins:**\n"
218
+ "- Use `#camoff @user` to exempt any specific user from the camera requirement.\n"
219
+ "- Use `#camoff` to exempt yourself if actively participating in the session.\n"
220
+ "- Use `#end` to conclude the session and reset all settings.\n"
221
+ "**Note:** These commands work within the context of the current voice session."
222
+ )
223
+ await reaction.message.channel.send(follow_up_message)
224
+ session.instructions_sent = True # Update the flag to prevent re-sending
225
+
226
+ # Cleanup
227
+ del pending_messages[reaction.message.id]
228
+
229
+ def dummy_function(input_text):
230
+ return "This is a dummy function for the Gradio UI."
231
+
232
+ iface = gr.Interface(fn=dummy_function,
233
+ inputs=gr.inputs.Textbox(label="Input"),
234
+ outputs=gr.outputs.Textbox(label="Output"),
235
+ title="Discord Bot",
236
+ description="This Space runs a Discord bot in the background.")
237
+
238
+
239
+ @bot.event
240
+ async def on_message(message):
241
+ # Skip bot messages and non-admin users
242
+ if message.author.bot or not any(role.name == "Admin" for role in message.author.roles):
243
+ await bot.process_commands(message) # Ensure other commands are still processed
244
+ return
245
+
246
+ # Process commands only if the author is in a voice channel
247
+ if message.author.voice:
248
+ vc_id = message.author.voice.channel.id
249
+ session = sessions.get(vc_id)
250
+
251
+ if not session:
252
+ await message.channel.send("No active session found for this voice channel.")
253
+ await bot.process_commands(message)
254
+ return
255
+
256
+ # Admin commands
257
+ if "#camoff" in message.content:
258
+ # If no users are mentioned, exempt the author; otherwise, exempt mentioned users
259
+ users_to_exempt = message.mentions if message.mentions else [message.author]
260
+ for user in users_to_exempt:
261
+ session.exemptions.add(user.id)
262
+ await message.channel.send(f"{user.display_name} is now exempt from the camera requirement.")
263
+ elif "#end" in message.content:
264
+ # Clear exemptions and reset camera requirement
265
+ session.exemptions.clear()
266
+ session.camera_required = False
267
+ await message.channel.send("Session ended: Camera requirements and exemptions have been reset.")
268
+
269
+ await bot.process_commands(message) # Ensure this is at the end to process other commands
270
+
271
+ # Process other commands
272
+ await bot.process_commands(message)
273
+ @check_camera_status.before_loop
274
+ async def before_camera_check():
275
+ await bot.wait_until_ready()
276
+ iface.launch(inline=False, share=True)
277
+ bot.run(TOKEN)