main.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. import os
  2. from dotenv import load_dotenv
  3. import discord
  4. from discord.ext import commands
  5. from discord.commands import Option
  6. from discord.commands import slash_command
  7. from datetime import datetime, time
  8. import configparser
  9. import mysql.connector
  10. import asyncio
  11. intents = discord.Intents.default()
  12. intents.message_content = True
  13. intents.members = True
  14. intents.guilds = True
  15. intents.reactions = True
  16. client = discord.Client(intents=intents)
  17. #---------------------------------#
  18. #Load .env file
  19. load_dotenv()
  20. token = os.getenv("TOKEN")
  21. if token is None:
  22. raise ValueError("TOKEN not found in .env file")
  23. debug_guilds_up = []
  24. server_token = os.getenv("SERVER").split(",")
  25. for i in range(len(server_token)):
  26. debug_guilds_up.append(int(server_token[i]))
  27. dbhost = os.getenv("HOST")
  28. if dbhost is None:
  29. raise ValueError("HOST not found in .env file")
  30. dbname = os.getenv("NAME")
  31. if dbname is None:
  32. raise ValueError("NAME not found in .env file")
  33. dbpsswd = os.getenv("PASSWORD")
  34. if dbpsswd is None:
  35. raise ValueError("PASSWORD not found in .env file")
  36. dbdb = os.getenv("DATABASE")
  37. if dbdb is None:
  38. raise ValueError("DATABASE not found in .env file")
  39. #---------------------------------#
  40. #ConfigParser
  41. config = configparser.RawConfigParser()
  42. configFilePath = r'config.cfg'
  43. config.read_file(open(configFilePath))
  44. label_rules = config.get('Reactionroles Rules', 'label_rules')
  45. role_rules = config.get('Reactionroles Rules', 'rules_role')
  46. channel_status_log = config.get('Logs', 'status_log')
  47. channel_mod_log = config.get('Logs', 'mod_log')
  48. team_role_id = config.get('Team Roles', 'team_role_id')
  49. #---------------------------------#
  50. #Database initialization
  51. conn = mysql.connector.connect(
  52. host=dbhost,
  53. user=dbname,
  54. password=dbpsswd,
  55. charset='utf8mb4',
  56. collation='utf8mb4_unicode_ci'
  57. )
  58. cursor = conn.cursor()
  59. conn.database = dbdb
  60. cursor.execute("""
  61. CREATE TABLE IF NOT EXISTS User (
  62. userid BIGINT UNIQUE PRIMARY KEY,
  63. discordname VARCHAR(100),
  64. rolesnumber INT,
  65. Roles TEXT
  66. )
  67. """)
  68. cursor.execute("""
  69. CREATE TABLE IF NOT EXISTS Team (
  70. userid BIGINT UNIQUE PRIMARY KEY,
  71. discordname VARCHAR(100),
  72. Roles TEXT,
  73. Permissions TEXT
  74. )
  75. """)
  76. cursor.execute("""
  77. CREATE TABLE IF NOT EXISTS Warns (
  78. id INT AUTO_INCREMENT PRIMARY KEY,
  79. userid BIGINT,
  80. username VARCHAR(100),
  81. moderatorname VARCHAR(100),
  82. reason VARCHAR(250),
  83. date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  84. )
  85. """)
  86. cursor.execute("""
  87. CREATE TABLE IF NOT EXISTS Bans (
  88. id INT AUTO_INCREMENT PRIMARY KEY,
  89. userid BIGINT,
  90. username VARCHAR(100),
  91. moderatorname VARCHAR(100),
  92. reason VARCHAR(250),
  93. date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  94. )
  95. """)
  96. cursor.execute("""
  97. CREATE TABLE IF NOT EXISTS Unbans (
  98. id INT AUTO_INCREMENT PRIMARY KEY,
  99. userid BIGINT,
  100. username VARCHAR(100),
  101. moderatorname VARCHAR(100),
  102. reason VARCHAR(250),
  103. date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  104. )
  105. """
  106. )
  107. cursor.execute("""
  108. CREATE TABLE IF NOT EXISTS Kick (
  109. id INT AUTO_INCREMENT PRIMARY KEY,
  110. userid BIGINT,
  111. username VARCHAR(100),
  112. moderatorname VARCHAR(100),
  113. reason VARCHAR(250),
  114. date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  115. )
  116. """)
  117. #---------------------------------#
  118. #Initialize Bot
  119. bot = commands.Bot(
  120. command_prefix=commands.when_mentioned_or("!"),
  121. description="VicePD Bot",
  122. intents=intents,
  123. debug_guilds=debug_guilds_up if debug_guilds_up else None
  124. )
  125. #Loading Cogs
  126. def load_extensions():
  127. cogs_dir = "./cogs"
  128. if not os.path.exists(cogs_dir):
  129. print(f"Cogs directory '{cogs_dir}' not found!")
  130. return
  131. for filename in os.listdir(cogs_dir):
  132. if filename.endswith(".py"):
  133. cog_list = os.path.splitext(filename)[0]
  134. try:
  135. bot.load_extension(f"cogs.{cog_list}")
  136. print(f"Loaded cog: {cog_list}")
  137. except Exception as e:
  138. print(f"Failed to load cog {cog_list}: {e}")
  139. class Admin(commands.Cog):
  140. def __init__(self, bot):
  141. self.bot = bot
  142. #---------------------------------#
  143. #Print in Log if error occurs
  144. @bot.event
  145. async def on_application_command_error(ctx, error):
  146. channel = discord.utils.get(ctx.guild.channels, id=int(channel_status_log))
  147. if channel:
  148. await channel.send(f"Error occurred: {str(error)}")
  149. #---------------------------------#
  150. #Bot Online Console
  151. @bot.event
  152. async def on_ready():
  153. print("------------------------")
  154. print(f"{bot.user} is online")
  155. print("------------------------")
  156. if bot.guilds:
  157. channel = discord.utils.get(bot.guilds[0].channels, id=int(channel_status_log))
  158. if channel:
  159. await channel.send(f"{bot.user} is online")
  160. bot.add_view(PersistentRoleView()) #loading reactionrole memory
  161. print("Registrierte Slash-Commands:")
  162. command_list = "\n".join([f"- /{command.name}" for command in bot.pending_application_commands])
  163. for command in bot.pending_application_commands:
  164. print(f" - {command.name}")
  165. if channel and command_list:
  166. await channel.send(f"Registered Slash-Commands:\n{command_list}")
  167. bot.loop.create_task(update_users_periodically())
  168. #---------------------------------------------------------------------------------------#
  169. #DONT Touch anything above this line, unless you know what you are doing!#
  170. #---------------------------------------------------------------------------------------#
  171. #_________________________________#
  172. #BAN SYSTEM
  173. #---------------------------------#
  174. ##Ban
  175. @bot.slash_command(name="ban", description="Ban a user from this Server")
  176. async def ban(
  177. ctx,
  178. user: Option(discord.User, description = "Select User", required=True), # type: ignore
  179. reason: Option(str, description = "Reason for the ban", default="No reason provided") # type: ignore
  180. ):
  181. if not ctx.author.guild_permissions.ban_members:
  182. await ctx.respond("Error: You don't have the permission to ban Members!", ephemeral=True)
  183. return
  184. if user == bot.user:
  185. await ctx.respond("Error: I can't ban myself!", ephemeral=True)
  186. return
  187. if user == ctx.author:
  188. await ctx.respond("Error: You can't ban yourself!", ephemeral=True)
  189. return
  190. channel= discord.utils.get(ctx.guild.channels, id = int(channel_mod_log))
  191. embed = discord.Embed(
  192. title=f"Ban of **{user.name}**",
  193. description=f"User {user.mention} has been banned from the Server",
  194. color=discord.Color.red()
  195. )
  196. time = discord.utils.format_dt(datetime.now(), "f")
  197. embed.add_field(name="Ban Date", value=time, inline=False)
  198. embed.add_field(name="Moderator", value=f"{ctx.author}", inline=False)
  199. embed.add_field(name="Reason", value=reason, inline=False)
  200. embed.add_field(name="User ID", value=user.id)
  201. embed.set_thumbnail(url=user.display_avatar.url)
  202. embed.set_author(name="VicePD", icon_url="https://i.imgur.com/6QteFrg.png")
  203. embed.set_footer(text="VicePD - Bot | Made by BaumSplitter41")
  204. embed_dm = discord.Embed(
  205. title=f"You have been banned from {ctx.guild.name}",
  206. description=f"Reason: {reason}\n\nIf you believe this was a mistake, please contact the moderators.",
  207. color=discord.Color.red()
  208. )
  209. embed_dm.add_field(name="Ban Date", value=time, inline=False)
  210. embed_dm.set_author(name="VicePD", icon_url="https://i.imgur.com/6QteFrg.png")
  211. embed_dm.set_footer(text="VicePD - Bot | Made by BaumSplitter41")
  212. try:
  213. await user.send(embed=embed_dm)
  214. await ctx.guild.ban(user, reason=reason)
  215. await ctx.respond(f"User {user.mention} has been banned from this Server!", ephemeral=True)
  216. await channel.send(embed=embed)
  217. cursor.execute(
  218. "INSERT INTO Bans (userid, username, moderatorname, reason) VALUES (%s, %s, %s, %s)",
  219. (user.id, str(user), str(ctx.author), reason)
  220. )
  221. conn.commit()
  222. except discord.Forbidden:
  223. await ctx.respond("Error: I don't have permission to ban this user.", ephemeral=True)
  224. except discord.HTTPException as e:
  225. await ctx.respond(f"Error: Could not ban User {user.mention}. Reason: {e}", ephemeral=True)
  226. except Exception as e:
  227. await ctx.respond(f"Unexpected error: {e}", ephemeral=True)
  228. #---------------------------------#
  229. #Unban
  230. @bot.slash_command(name="unban", description="Unban a user from this Server")
  231. async def unban(
  232. ctx,
  233. user: Option(discord.User, description = "Insert User ID", required=True), # type: ignore
  234. reason: Option(str, description = "Reason for the unbanning", default="No reason provided") # type: ignore
  235. ):
  236. if not ctx.author.guild_permissions.ban_members:
  237. await ctx.respond("Error: You don't have the permission to unban Members!", ephemeral=True)
  238. return
  239. if user == bot.user:
  240. await ctx.respond("Error: I can't unban myself!", ephemeral=True)
  241. return
  242. if user == ctx.author:
  243. await ctx.respond("Error: You can't unban yourself!", ephemeral=True)
  244. return
  245. if user in ctx.guild.members:
  246. await ctx.respond("Error: This user is not banned!", ephemeral=True)
  247. return
  248. channel= discord.utils.get(ctx.guild.channels, id = int(channel_mod_log))
  249. embed = discord.Embed(
  250. title=f"Unban of **{user.name}**",
  251. description=f"User {user.mention} was unbanned from this server.",
  252. color=discord.Color.green()
  253. )
  254. time = discord.utils.format_dt(datetime.now(), "f")
  255. embed.add_field(name="Unban Date", value=time, inline=False)
  256. embed.add_field(name="Moderator", value=f"{ctx.author}", inline=False)
  257. embed.add_field(name="Reason", value=reason, inline=False)
  258. embed.add_field(name="User ID", value=user.id)
  259. embed.set_thumbnail(url=user.display_avatar.url)
  260. embed.set_author(name="VicePD", icon_url="https://i.imgur.com/6QteFrg.png")
  261. embed.set_footer(text="VicePD - Bot | Made by BaumSplitter41")
  262. try:
  263. await ctx.guild.unban(user, reason=reason)
  264. await ctx.respond(f"User {user.mention} is now unbanned!", ephemeral=True)
  265. await channel.send(embed=embed)
  266. cursor.execute(
  267. "INSERT INTO Unbans (userid, username, moderatorname, reason) VALUES (%s, %s, %s, %s)",
  268. (user.id, str(user), str(ctx.author), reason)
  269. )
  270. conn.commit()
  271. except discord.Forbidden:
  272. await ctx.respond("Error: I don't have permission to unban this user.", ephemeral=True)
  273. except discord.HTTPException as e:
  274. await ctx.respond(f"Error: Could not unban User {user.mention}. Reason: {e}", ephemeral=True)
  275. except Exception as e:
  276. await ctx.respond(f"Unexpected error: {e}", ephemeral=True)
  277. #---------------------------------#
  278. #_________________________________#
  279. #---------------------------------#
  280. #Kick
  281. @bot.slash_command(name="kick", description="Kick a user from this Server")
  282. async def kick(
  283. ctx,
  284. user: Option(discord.User, description = "Select User", required=True), # type: ignore
  285. reason: Option(str, description = "Reason for the ban", default="No reason provided") # type: ignore
  286. ):
  287. if not ctx.author.guild_permissions.kick_members:
  288. await ctx.respond("Error: You don't have the permission to kick Members!", ephemeral=True)
  289. return
  290. if user == bot.user:
  291. await ctx.respond("Error: I can't kick myself!", ephemeral=True)
  292. return
  293. if user == ctx.author:
  294. await ctx.respond("Error: You can't kick yourself!", ephemeral=True)
  295. return
  296. channel= discord.utils.get(ctx.guild.channels, id = int(channel_mod_log))
  297. embed = discord.Embed(
  298. title=f"Kick of **{user.name}**",
  299. description=f"User {user.mention} has been kicked from the Server",
  300. color=discord.Color.red()
  301. )
  302. time = discord.utils.format_dt(datetime.now(), "f")
  303. embed.add_field(name="Kick Date", value=time, inline=False)
  304. embed.add_field(name="Moderator", value=f"{ctx.author}", inline=False)
  305. embed.add_field(name="Reason", value=reason, inline=False)
  306. embed.add_field(name="User ID", value=user.id)
  307. embed.set_thumbnail(url=user.display_avatar.url)
  308. embed.set_author(name="VicePD", icon_url="https://i.imgur.com/6QteFrg.png")
  309. embed.set_footer(text="VicePD - Bot | Made by BaumSplitter41")
  310. #DM to user
  311. embed_dm = discord.Embed(
  312. title=f"You have been kicked from {ctx.guild.name}",
  313. description=f"Reason: {reason}\n\nIf you believe this was a mistake, please contact the moderators.",
  314. color=discord.Color.red()
  315. )
  316. embed_dm.add_field(name="Kick Date", value=time, inline=False)
  317. embed_dm.set_author(name="VicePD", icon_url="https://i.imgur.com/6QteFrg.png")
  318. embed_dm.set_footer(text="VicePD - Bot | Made by BaumSplitter41")
  319. try:
  320. await user.send(embed=embed_dm)
  321. await ctx.guild.kick(user, reason=reason)
  322. await ctx.respond(f"User {user.mention} has been kicked from this Server!", ephemeral=True)
  323. cursor.execute(
  324. "INSERT INTO Kick (userid, username, moderatorname, reason) VALUES (%s, %s, %s, %s)",
  325. (int(user.id), str(user), str(ctx.author), reason)
  326. )
  327. conn.commit()
  328. await channel.send(embed=embed)
  329. except discord.Forbidden:
  330. await ctx.respond("Error: I don't have permission to kick this user.", ephemeral=True)
  331. except discord.HTTPException as e:
  332. await ctx.respond(f"Error: Could not kick User {user.mention}. Reason: {e}", ephemeral=True)
  333. except Exception as e:
  334. await ctx.respond(f"Unexpected error: {e}", ephemeral=True)
  335. #---------------------------------#
  336. #---------------------------------#
  337. #Warn
  338. @bot.slash_command(name="warn", description="Warn a user from this Server")
  339. async def warn(
  340. ctx,
  341. user: Option(discord.User, required=True), # type: ignore
  342. reason: Option(str, default="No reason provided") # type: ignore
  343. ):
  344. await ctx.defer(ephemeral=True)
  345. if not ctx.author.guild_permissions.kick_members:
  346. await ctx.followup.send("No permission.", ephemeral=True)
  347. return
  348. if user in (bot.user, ctx.author):
  349. await ctx.followup.send("Invalid target.", ephemeral=True)
  350. return
  351. #DM to user
  352. embed_dm = discord.Embed(
  353. title=f"You have been warned on {ctx.guild.name}",
  354. description=f"Reason: {reason}\n\nIf you believe this was a mistake, please contact the moderators.",
  355. color=discord.Color.red()
  356. )
  357. embed_dm.add_field(name="Warn Date", value=time, inline=False)
  358. embed_dm.set_author(name="VicePD", icon_url="https://i.imgur.com/6QteFrg.png")
  359. embed_dm.set_footer(text="VicePD - Bot | Made by BaumSplitter41")
  360. try:
  361. await user.send(embed=embed_dm)
  362. except discord.Forbidden:
  363. await ctx.respond("Error: I can't send a DM to this user. The user was warned without a information.", ephemeral=True)
  364. pass # User has DMs closed or blocked the bot
  365. cursor.execute(
  366. "INSERT INTO Warns (userid, username, moderatorname, reason) VALUES (%s, %s, %s, %s)",
  367. (user.id, str(user), str(ctx.author), reason)
  368. )
  369. conn.commit()
  370. await ctx.followup.send(
  371. f"User {user.mention} has been warned for: {reason}",
  372. ephemeral=True
  373. )
  374. #---------------------------------#
  375. #Modinfo
  376. @bot.slash_command(name="modinfo", description="Shows the moderative history of a user from this Server")
  377. async def modinfo(
  378. ctx,
  379. user: Option(discord.User, required=True) # type: ignore
  380. ):
  381. await ctx.defer(ephemeral=False)
  382. if not ctx.author.guild_permissions.kick_members:
  383. await ctx.followup.send("No permission.", ephemeral=True)
  384. return
  385. embed = discord.Embed(
  386. title=f"__Moderation History for {user.name}__",
  387. color=discord.Color.orange()
  388. )
  389. # Collect all events with timestamps
  390. events = []
  391. cursor.execute("SELECT moderatorname, reason, date FROM Warns WHERE userid = %s", (user.id,))
  392. for moderatorname, reason, date in cursor.fetchall():
  393. events.append(("Warned", moderatorname, reason, date))
  394. cursor.execute("SELECT moderatorname, reason, date FROM Kick WHERE userid = %s", (user.id,))
  395. for moderatorname, reason, date in cursor.fetchall():
  396. events.append(("Kicked", moderatorname, reason, date))
  397. cursor.execute("SELECT moderatorname, reason, date FROM Bans WHERE userid = %s", (user.id,))
  398. for moderatorname, reason, date in cursor.fetchall():
  399. events.append(("Banned", moderatorname, reason, date))
  400. cursor.execute("SELECT moderatorname, reason, date FROM Unbans WHERE userid = %s", (user.id,))
  401. for moderatorname, reason, date in cursor.fetchall():
  402. events.append(("Unbanned", moderatorname, reason, date))
  403. if not events:
  404. await ctx.followup.send(f"User `{user.name}` has no moderation history.", ephemeral=True)
  405. return
  406. # Sort chronologically: oldest -> newest
  407. events.sort(key=lambda e: e[3])
  408. # Add fields in chronological order
  409. for action, moderatorname, reason, date in events:
  410. embed.add_field(
  411. name=f"{action} by {moderatorname} on {date.strftime('%Y-%m-%d %H:%M:%S')}",
  412. value=f"Reason: {reason}",
  413. inline=False
  414. )
  415. embed.set_thumbnail(url=user.display_avatar.url)
  416. embed.set_author(name="VicePD", icon_url="https://i.imgur.com/6QteFrg.png")
  417. embed.set_footer(text="VicePD - Bot | Made by BaumSplitter41")
  418. await ctx.followup.send(embed=embed, ephemeral=False)
  419. #_________________________________#
  420. ## Reaction role system
  421. #---------------------------------#
  422. #reaction role verfiy
  423. class PersistentRoleView(discord.ui.View):
  424. def __init__(self):
  425. super().__init__(timeout=None)
  426. @discord.ui.button(
  427. label=label_rules,
  428. style=discord.ButtonStyle.success,
  429. emoji="✅",
  430. custom_id="persistent_view:role_verify"
  431. )
  432. async def verify_callback(self, button: discord.ui.Button, interaction: discord.Interaction):
  433. role = interaction.guild.get_role(int(role_rules))
  434. if role is None:
  435. await interaction.response.send_message("Error: The konfigured role was not found", ephemeral=True)
  436. return
  437. if role in interaction.user.roles:
  438. await interaction.user.remove_roles(role)
  439. await interaction.response.send_message(f"Rolle **{role.name}** wurde entfernt.", ephemeral=True)
  440. else:
  441. await interaction.user.add_roles(role)
  442. await interaction.response.send_message(f"Du hast die Rolle **{role.name}** erhalten!", ephemeral=True)
  443. @bot.slash_command(name="verify_message", description="Send the reactionrole message| This is for setup only!")
  444. async def setup_rr(
  445. ctx: discord.ApplicationContext,
  446. channel: discord.TextChannel,
  447. title: str,
  448. description: str
  449. ):
  450. if not ctx.author.guild_permissions.administrator:
  451. await ctx.respond("You dont have the permissions to do that..", ephemeral=True)
  452. return
  453. embed = discord.Embed(
  454. title=title,
  455. description=f"{description}\n\nViel Spass auf dem Server!",
  456. color=discord.Color.red()
  457. )
  458. embed.set_image(url="https://i.imgur.com/FoF791J.png")
  459. try:
  460. await channel.send(embed=embed, view=PersistentRoleView())
  461. await ctx.respond(f"Message was succesfully sent in {channel.mention}!", ephemeral=True)
  462. except discord.Forbidden:
  463. await ctx.respond("I dont have permissions to write in this channel", ephemeral=True)
  464. #---------------------------------#
  465. #_________________________________#
  466. #--------------------------------#
  467. #Get all Users in Database periodically
  468. async def update_users_periodically():
  469. await bot.wait_until_ready()
  470. while not bot.is_closed():
  471. try:
  472. for guild in bot.guilds:
  473. batch_count = 0
  474. async for member in guild.fetch_members(limit=None):
  475. role_ids_string = ",".join([str(role.id) for role in member.roles])
  476. cursor.execute(
  477. """INSERT INTO User (userid, discordname, rolesnumber, roles)
  478. VALUES (%s, %s, %s, %s)
  479. ON DUPLICATE KEY UPDATE discordname=%s, rolesnumber=%s, roles=%s""",
  480. (member.id, str(member), len(member.roles), role_ids_string,
  481. str(member), len(member.roles), role_ids_string)
  482. )
  483. batch_count += 1
  484. if batch_count >= 100:
  485. conn.commit()
  486. batch_count = 0
  487. if batch_count > 0:
  488. conn.commit()
  489. if team_role_id:
  490. for guild in bot.guilds:
  491. team_role = guild.get_role(int(team_role_id))
  492. if team_role is None:
  493. continue
  494. batch_count = 0
  495. async for member in guild.fetch_members(limit=None):
  496. if team_role in member.roles:
  497. role_ids_string = ",".join([str(role.id) for role in member.roles])
  498. cursor.execute(
  499. """INSERT INTO Team (userid, discordname, Roles)
  500. VALUES (%s, %s, %s)
  501. ON DUPLICATE KEY UPDATE discordname=%s, Roles=%s""",
  502. (member.id, str(member), role_ids_string,
  503. str(member), role_ids_string)
  504. )
  505. batch_count += 1
  506. if batch_count >= 100:
  507. conn.commit()
  508. batch_count = 0
  509. if batch_count > 0:
  510. conn.commit()
  511. #print(f"[✓] {datetime.now().strftime('%H:%M:%S')} - Datenbank mit Discord-Rollen synchronisiert.")
  512. except Exception as e:
  513. print(f"[!] Fehler beim Update der User: {e}")
  514. await asyncio.sleep(60) # Update every minute
  515. #_________________________________#
  516. ## TXADMIN ROLE PERMISSIONS
  517. #---------------------------------#
  518. #Run function
  519. load_extensions()
  520. bot.run(token)
  521. #---------------------------------#