Rifat Azad commited on
Commit
702d428
·
1 Parent(s): 0dbbc1a
Files changed (1) hide show
  1. pydvpl_bot.py +156 -118
pydvpl_bot.py CHANGED
@@ -3,7 +3,6 @@ import time
3
  import json
4
  import asyncio
5
  import psutil
6
- import socket
7
  import discord
8
  import requests
9
  from datetime import datetime
@@ -35,7 +34,7 @@ load_dotenv()
35
  # DEFINES ------------------------------------------------------ START
36
 
37
 
38
- BOT_VERSION = '1.3.1'
39
 
40
  AUTHORIZED_USER_ID = os.getenv('AUTHORIZED_ID')
41
 
@@ -98,9 +97,9 @@ async def list_feedback(ctx, folder_path, title):
98
  inline=False
99
  )
100
  if feedback_embed.fields:
101
- await ctx.send(embed=feedback_embed)
102
  else:
103
- await ctx.send("No feedback found.")
104
 
105
 
106
 
@@ -109,15 +108,18 @@ async def list_feedback(ctx, folder_path, title):
109
 
110
  async def clean_directory(ctx, directory):
111
  try:
 
 
 
112
  file_count = 0
113
  for filename in os.listdir(directory):
114
  file_path = os.path.join(directory, filename)
115
  if os.path.isfile(file_path):
116
  os.remove(file_path)
117
  file_count += 1
118
- await ctx.send(f"All files cleaned successfully in {directory}. Total files cleaned: {file_count}.")
119
  except Exception as e:
120
- await ctx.send(f"An error occurred while cleaning files: {e}")
121
 
122
 
123
 
@@ -218,7 +220,7 @@ async def on_command(ctx):
218
  @bot.event
219
  async def on_command_error(ctx, error):
220
  if isinstance(error, commands.CommandNotFound):
221
- await ctx.send("Sorry, I couldn't find that command. Use `/help` or `>>help` to see the list of available commands.")
222
 
223
  else:
224
  print(f'An error occurred: {error}')
@@ -326,9 +328,9 @@ async def help(ctx):
326
  # embed.set_footer(value="Use /help or >>help <command> for more details on a specific command.")
327
 
328
  # Send the embed as an ephemeral message
329
- await ctx.send(embed=embed, ephemeral=True)
330
 
331
- await ctx.send(f"The command `help` was executed by - {ctx.author.mention}")
332
 
333
 
334
  # FUNCTION ------------------------------------------------------ SPLIT
@@ -339,30 +341,33 @@ async def compress(ctx , attachments: discord.Attachment):
339
  attachments = ctx.message.attachments
340
 
341
  if not attachments:
342
- await ctx.send("No file attached.")
343
- await ctx.send(f"The command `compress` was executed by - {ctx.author.mention}")
344
 
345
  return
346
 
347
  for attachment in attachments:
348
  file_path = os.path.join(COMPRESS_FOLDER, attachment.filename)
349
 
 
 
350
  # Check if the file is already in .dvpl format, if so, skip it
351
  if file_path.endswith(".dvpl"):
352
- await ctx.send(f"File {attachment.filename} is already in .dvpl format. Skipping.")
353
 
354
  continue
355
 
356
  await attachment.save(file_path)
357
  compressed_file_path = await compress_file(file_path)
358
  if compressed_file_path:
359
- await ctx.send(file=discord.File(compressed_file_path))
 
360
  os.remove(file_path) # Delete the original file
361
  os.remove(compressed_file_path) # Delete the compressed file
362
  else:
363
- await ctx.send("Failed to `compress` the file.")
364
 
365
- await ctx.send(f"The command `compress` was executed by - {ctx.author.mention}")
366
 
367
 
368
 
@@ -374,58 +379,86 @@ async def decompress(ctx, attachments: discord.Attachment):
374
  attachments = ctx.message.attachments
375
 
376
  if not attachments:
377
- await ctx.send("No file attached.")
378
- await ctx.send(f"The command `decompress` was executed by - {ctx.author.mention}")
379
 
380
  return
381
 
382
  for attachment in attachments:
383
  file_path = os.path.join(DECOMPRESS_FOLDER, attachment.filename)
384
 
 
 
385
  # Check if the file is not in .dvpl format, if so, skip it
386
  if not file_path.endswith(".dvpl"):
387
- await ctx.send(f"File {attachment.filename} is not in .dvpl format. Skipping.")
388
  continue
389
 
390
  await attachment.save(file_path)
391
  decompressed_file_path = await decompress_file(file_path)
392
  if decompressed_file_path:
393
- await ctx.send(file=discord.File(decompressed_file_path))
 
394
  os.remove(file_path) # Delete the original file
395
  os.remove(decompressed_file_path) # Delete the decompressed file
396
  else:
397
- await ctx.send("Failed to decompress the file.")
398
 
399
- await ctx.send(f"The command `decompress` was executed by - {ctx.author.mention}")
400
 
401
 
402
 
403
  # FUNCTION ------------------------------------------------------ SPLIT
404
-
405
 
406
  @bot.hybrid_command(help="Pings to check bot's latency")
407
  async def ping(ctx):
408
- latency = round(bot.latency * 1000) # latency in milliseconds
409
- await ctx.send(f"Pong! Bot latency is {latency}ms.")
410
 
411
- await ctx.send(f"The command `ping` was executed by - {ctx.author.mention}")
412
 
 
 
 
 
 
 
 
 
 
 
413
 
414
  # FUNCTION ------------------------------------------------------ SPLIT
415
 
416
 
417
- @bot.hybrid_command(help="Pings custom nameservers")
418
- async def pinger(ctx, nameservers: str):
419
- if not nameservers:
420
- await ctx.send("Please provide at least one nameserver to ping.")
421
- return
422
 
423
- for nameserver in nameservers:
424
- try:
425
- response = await bot.loop.run_in_executor(None, lambda: socket.gethostbyname(nameserver))
426
- await ctx.send(f"Ping to {nameserver} successful. IP Address: {response}")
427
- except socket.gaierror:
428
- await ctx.send(f"Unable to resolve {nameserver}.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
 
430
 
431
 
@@ -457,11 +490,11 @@ async def invite(ctx):
457
  # Send the invite link to the user's DM
458
  try:
459
  await ctx.author.send(f"Invite link for PyDVPL: {invite_link}")
460
- await ctx.send(f"Sent the invite link to your DM. {ctx.author.mention}")
461
  except discord.Forbidden:
462
- await ctx.send(f"Failed to send the invite link to your DM. {ctx.author.mention} Please make sure your DMs are open.")
463
 
464
- await ctx.send(f"The command `invite` was executed by - {ctx.author.mention}")
465
 
466
 
467
 
@@ -472,7 +505,7 @@ async def invite(ctx):
472
  @bot.hybrid_command(help="Send feedback or report issues", usage="<requests/issues> <message>")
473
  async def feedback(ctx, category: str, *, message: str):
474
  if category.lower() not in ["requests", "issues"]:
475
- await ctx.send("Invalid category. Please choose 'requests' or 'issues'.")
476
  return
477
 
478
  feedback_data = {
@@ -496,9 +529,9 @@ async def feedback(ctx, category: str, *, message: str):
496
  with open(file_path, "w") as f:
497
  json.dump(data, f, indent=4)
498
 
499
- await ctx.send(f"Thank you for your {category.lower()}. It has been recorded.")
500
 
501
- await ctx.send(f"The command `feedback` was executed by - {ctx.author.mention}")
502
 
503
 
504
 
@@ -511,7 +544,7 @@ async def uptime(ctx):
511
 
512
  if activity_start_time == 0:
513
  bot_mention = ctx.me.mention
514
- await ctx.send("{bot_mention}'s activity hasn't been set yet.")
515
 
516
  return
517
 
@@ -522,9 +555,9 @@ async def uptime(ctx):
522
 
523
  bot_mention = ctx.me.mention
524
  uptime_message = f"{bot_mention} has been playing for - {hours} hours, {minutes} minutes, {seconds} seconds."
525
- await ctx.send(uptime_message)
526
 
527
- await ctx.send(f"The command `uptime` was executed by - {ctx.author.mention}")
528
 
529
 
530
  # FUNCTION ------------------------------------------------------ SPLIT
@@ -546,9 +579,9 @@ async def version(ctx):
546
  embed.add_field(name="Craiyon Lib Version:", value=f"``{craiyon.__version__}``", inline=False)
547
 
548
  # Send the embed message
549
- await ctx.send(embed=embed)
550
 
551
- await ctx.send(f"The command `version` was executed by - {ctx.author.mention}")
552
 
553
 
554
  # FUNCTION ------------------------------------------------------ SPLIT
@@ -561,9 +594,9 @@ async def clock(ctx):
561
  # Format the date and time
562
  formatted_now = now.strftime("%Y-%m-%d %H:%M:%S")
563
 
564
- await ctx.send(f"Current date and time: `{formatted_now}`")
565
 
566
- await ctx.send(f"The command `clock` was executed by - {ctx.author.mention}")
567
 
568
 
569
  # FUNCTION ------------------------------------------------------ SPLIT
@@ -573,9 +606,11 @@ async def clock(ctx):
573
  async def chat(ctx, model, *, message):
574
 
575
  if str(ctx.author.id) not in AUTHORIZED_AI_ACCESS_ID:
576
- await ctx.send("You are not authorized to use this command. Only `@rifsxd`'s server boosters & special permitted users can enjoy free `ChatGPT` access.")
577
 
578
  return
 
 
579
 
580
  if model.lower() == "phind":
581
  bot = phind.PHIND()
@@ -584,13 +619,13 @@ async def chat(ctx, model, *, message):
584
  elif model.lower() == "blackboxai":
585
  bot = blackboxai.BLACKBOXAI()
586
  else:
587
- await ctx.send("Invalid model. Please choose 'phind' or 'chatgpt' or 'blackboxai'.")
588
  return
589
 
590
  response = bot.chat(message)
591
- await ctx.send(response)
592
 
593
- await ctx.send(f"The command `chat` was executed by - {ctx.author.mention}")
594
 
595
 
596
  # FUNCTION ------------------------------------------------------ SPLIT
@@ -600,11 +635,11 @@ async def chat(ctx, model, *, message):
600
  async def image(ctx, *, prompt: str):
601
  # Check if the user is authorized to use the command
602
  if str(ctx.author.id) not in AUTHORIZED_AI_ACCESS_ID:
603
- await ctx.send("You are not authorized to use this command.")
604
  return
605
 
606
  # Inform the user that the generation process has started
607
- await ctx.send(f"Generating images for prompt: `{prompt}`. Please be patient...")
608
 
609
  try:
610
  generator = Craiyon()
@@ -620,15 +655,16 @@ async def image(ctx, *, prompt: str):
620
  image_file = discord.File(img_bytes, filename=f"result{index}.webp")
621
  images.append(image_file)
622
 
 
623
  # Send images to the user
624
  await ctx.reply(files=images)
625
 
626
  except Exception as e:
627
  # Print the specific exception message for debugging
628
  print(f"An error occurred while generating images: {e}")
629
- await ctx.send("An error occurred while generating images. Please try again later.")
630
 
631
- await ctx.send(f"The command `image` was executed by - {ctx.author.mention}")
632
 
633
 
634
 
@@ -642,7 +678,7 @@ async def image(ctx, *, prompt: str):
642
  async def clean(ctx, clean_mode):
643
  # Check if the author is authorized to use this command
644
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
645
- await ctx.send("You are not authorized to use this command.")
646
 
647
  return
648
 
@@ -655,7 +691,7 @@ async def clean(ctx, clean_mode):
655
  elif clean_mode.lower() == 'requests':
656
  await clean_directory(ctx, REQUESTS_FOLDER)
657
  else:
658
- await ctx.send("Invalid clean mode. Please choose 'received_to_compress', 'received_to_decompress', 'feedback_issues', or 'feedback_requests'.")
659
 
660
 
661
  # FUNCTION ------------------------------------------------------ SPLIT
@@ -665,11 +701,11 @@ async def clean(ctx, clean_mode):
665
  async def online(ctx):
666
  # Check if the author is authorized to use this command
667
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
668
- await ctx.send("You are not authorized to use this command.")
669
 
670
  return
671
  await bot.change_presence(activity=discord.Game(name=playing_time_activity))
672
- await ctx.send("Bot's presence set to online.")
673
 
674
 
675
 
@@ -680,11 +716,11 @@ async def online(ctx):
680
  async def dnd(ctx):
681
  # Check if the author is authorized to use this command
682
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
683
- await ctx.send("You are not authorized to use this command.")
684
 
685
  return
686
  await bot.change_presence(status=discord.Status.dnd)
687
- await ctx.send("Bot's presence set to Do Not Disturb.")
688
 
689
 
690
 
@@ -695,11 +731,11 @@ async def dnd(ctx):
695
  async def offline(ctx):
696
  # Check if the author is authorized to use this command
697
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
698
- await ctx.send("You are not authorized to use this command.")
699
 
700
  return
701
  await bot.change_presence(status=discord.Status.offline)
702
- await ctx.send("Bot's presence set to offline.")
703
 
704
 
705
 
@@ -710,7 +746,7 @@ async def offline(ctx):
710
  async def activity(ctx, activity_type, *, activity_text=None):
711
  # Check if the author is authorized to use this command
712
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
713
- await ctx.send("You are not authorized to use this command.")
714
 
715
  return
716
 
@@ -721,17 +757,17 @@ async def activity(ctx, activity_type, *, activity_text=None):
721
  elif activity_type.lower() == 'playing':
722
  activity = discord.Activity(type=discord.ActivityType.playing, name=activity_text)
723
  else:
724
- await ctx.send('Invalid activity type. Please choose either "listening", "playing" or "watching".')
725
 
726
  return
727
 
728
  if not activity_text:
729
- await ctx.send('Please provide an activity text.')
730
 
731
  return
732
 
733
  await bot.change_presence(activity=activity)
734
- await ctx.send(f'Activity set to {activity_type} {activity_text}')
735
 
736
 
737
 
@@ -742,72 +778,72 @@ async def activity(ctx, activity_type, *, activity_text=None):
742
  async def say(ctx, destination_type, *, id, message):
743
  # Check if the author is authorized to use this command
744
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
745
- await ctx.send("You are not authorized to use this command.")
746
  return
747
 
748
  if destination_type.lower() == 'channel':
749
  try:
750
  channel_id = int(id)
751
  except ValueError:
752
- await ctx.send("Channel ID must be a valid integer.")
753
  return
754
  channel = bot.get_channel(channel_id)
755
  if channel:
756
  await channel.send(message)
757
- await ctx.send(f"Message `{message}` sent to channel `{channel.name}`.")
758
  else:
759
- await ctx.send("Channel not found.")
760
 
761
  elif destination_type.lower() == 'server':
762
  try:
763
  server_id = int(id)
764
  except ValueError:
765
- await ctx.send("Server ID must be a valid integer.")
766
  return
767
  server = bot.get_guild(server_id)
768
  if server:
769
  announcement_channel = discord.utils.get(server.channels, name="important-announcements")
770
  if announcement_channel:
771
  await announcement_channel.send(message)
772
- await ctx.send(f"Message `{message}` sent to server `{server.name}` in `important-announcements` channel.")
773
  else:
774
  announcements_channel = discord.utils.get(server.channels, name="announcements")
775
  if announcements_channel:
776
  await announcements_channel.send(message)
777
- await ctx.send(f"Message `{message}` sent to server `{server.name}` in `announcements` channel.")
778
  else:
779
  public_updates_channel = server.public_updates_channel
780
  if public_updates_channel:
781
  await public_updates_channel.send(message)
782
- await ctx.send(f"Message `{message}` sent to server `{server.name}` in `public updates` channel.")
783
  else:
784
  default_channel = server.system_channel or server.text_channels[0] # Default to the first text channel
785
  if default_channel:
786
  await default_channel.send(message)
787
- await ctx.send(f"Message `{message}` sent to server `{server.name}` in the default channel.")
788
  else:
789
- await ctx.send("No announcement channels found in the server. Also, no default `public updates` neither `default` channels found.")
790
  else:
791
- await ctx.send("Server not found.")
792
 
793
  elif destination_type.lower() == 'user':
794
  try:
795
  user_id = int(id)
796
  except ValueError:
797
- await ctx.send("User ID must be a valid integer.")
798
  return
799
  user = bot.get_user(user_id)
800
  if user:
801
  try:
802
  await user.send(message)
803
- await ctx.send(f"Message `{message}` sent to user '{user.display_name}'.")
804
  except discord.Forbidden:
805
- await ctx.send(f"Couldn't send message to `{user.display_name}`. Their DMs are closed.")
806
  else:
807
- await ctx.send("User not found.")
808
 
809
  else:
810
- await ctx.send("Invalid destination type. Use either 'channel', 'server', or 'user'.")
811
 
812
 
813
 
@@ -818,7 +854,7 @@ async def say(ctx, destination_type, *, id, message):
818
  async def announce(ctx, *, message):
819
  # Check if the author is authorized to use this command
820
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
821
- await ctx.send("You are not authorized to use this command.")
822
 
823
  return
824
 
@@ -829,26 +865,26 @@ async def announce(ctx, *, message):
829
  announcement_channel = discord.utils.get(server.channels, name="important-announcements")
830
  if announcement_channel:
831
  await announcement_channel.send(embed=embed)
832
- await ctx.send(f"Message `{message}` sent to server `{server.name}` in `important-announcements` channel.")
833
  else:
834
  # If no "important-announcements" channel, check for "announcements" channel
835
  announcements_channel = discord.utils.get(server.channels, name="announcements")
836
  if announcements_channel:
837
  await announcements_channel.send(embed=embed)
838
- await ctx.send(f"Message `{message}` sent to server `{server.name}` in `announcements` channel.")
839
  else:
840
  # If neither channel exists, send to the default channel or public updates channel
841
  public_updates_channel = server.public_updates_channel
842
  if public_updates_channel:
843
  await public_updates_channel.send(embed=embed)
844
- await ctx.send(f"Message `{message}` sent to server `{server.name}` in `public updates` channel.")
845
  else:
846
  default_channel = server.system_channel or server.text_channels[0]
847
  if default_channel:
848
  await default_channel.send(embed=embed)
849
- await ctx.send(f"Message `{message}` sent to server `{server.name}` in `defaults` channel.")
850
  else:
851
- await ctx.send(f"No suitable announcement channel found in server `{server.name}`.")
852
 
853
  # Delete the original command message
854
 
@@ -861,9 +897,11 @@ async def announce(ctx, *, message):
861
  async def stats(ctx):
862
  # Check if the author is authorized to use this command
863
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
864
- await ctx.send("You are not authorized to use this command.")
865
 
866
  return
 
 
867
 
868
  guild_count = len(bot.guilds)
869
  member_count = len(set(bot.get_all_members()))
@@ -891,7 +929,7 @@ async def stats(ctx):
891
  f"CPU Usage: {cpu_usage}%\n"
892
  f"Memory Usage: {memory_usage}%"
893
  )
894
- await ctx.send(stats_message)
895
 
896
 
897
  # FUNCTION ------------------------------------------------------ SPLIT
@@ -901,20 +939,20 @@ async def stats(ctx):
901
  async def list(ctx, list_type):
902
  # Check if the author is authorized to use this command
903
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
904
- await ctx.send("You are not authorized to use this command.")
905
 
906
  return
907
 
908
  if list_type.lower() == 'servers':
909
  servers_info = "\n".join([f"{server.name} - ID: {server.id}" for server in bot.guilds])
910
- await ctx.send(f"List of servers the bot is on:\n```{servers_info}```")
911
 
912
  elif list_type.lower() == 'issues':
913
  await list_feedback(ctx, ISSUES_FOLDER, "List of issues:")
914
  elif list_type.lower() == 'requests':
915
  await list_feedback(ctx, REQUESTS_FOLDER, "List of requests:")
916
  else:
917
- await ctx.send("Invalid list type. Please choose 'servers', 'issues', or 'requests'.")
918
 
919
 
920
  # FUNCTION ------------------------------------------------------ SPLIT
@@ -924,23 +962,23 @@ async def list(ctx, list_type):
924
  async def update(ctx, pkg_name):
925
  # Check if the author is authorized to use this command
926
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
927
- await ctx.send("You are not authorized to use this command.")
928
  return
929
 
930
  try:
931
 
932
- await ctx.send(f"Updating package `{pkg_name}`...")
933
 
934
  # Run pip install command to upgrade the package
935
  process = subprocess.Popen(['pip', 'install', pkg_name, '--upgrade'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
936
  output, error = process.communicate()
937
 
938
  if error:
939
- await ctx.send(f"Failed to update package `{pkg_name}`. Error: {error.decode('utf-8')}")
940
  else:
941
- await ctx.send(f"Package `{pkg_name}` successfully updated.")
942
  except Exception as e:
943
- await ctx.send(f"An error occurred while updating package `{pkg_name}`: {e}")
944
 
945
 
946
  # FUNCTION ------------------------------------------------------ SPLIT
@@ -950,15 +988,15 @@ async def update(ctx, pkg_name):
950
  async def ip(ctx):
951
  # Check if the author is authorized to use this command
952
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
953
- await ctx.send("You are not authorized to use this command.")
954
 
955
  return
956
 
957
  response = requests.get('https://api.ipify.org')
958
  if response.status_code == 200:
959
- await ctx.send(f'Your IP address is: `{response.text}`')
960
  else:
961
- await ctx.send('Failed to fetch IP address.')
962
 
963
 
964
  # UTILITY ADMIN_CMD ------------------------------------------------------ END
@@ -983,16 +1021,16 @@ async def kick(ctx, member: discord.Member, *, reason=None):
983
  dm_message += f" for the following reason: `{reason}`"
984
  await member.send(dm_message)
985
  except discord.Forbidden:
986
- await ctx.send(f"Failed to send a direct message to {member}.")
987
 
988
  # Kick the member from the server
989
  await member.kick(reason=reason)
990
- await ctx.send(f"{member} has been kicked from the server.")
991
  else:
992
- await ctx.send("You do not have permission to kick this member.")
993
 
994
  else:
995
- await ctx.send("You do not have permission to use this command.")
996
 
997
 
998
  # FUNCTION ------------------------------------------------------ SPLIT
@@ -1011,16 +1049,16 @@ async def ban(ctx, member: discord.Member, *, reason=None):
1011
  dm_message += f" for the following reason: `{reason}`"
1012
  await member.send(dm_message)
1013
  except discord.Forbidden:
1014
- await ctx.send(f"Failed to send a direct message to {member}.")
1015
 
1016
  # Ban the member from the server
1017
  await member.ban(reason=reason)
1018
- await ctx.send(f"{member} has been banned from the server.")
1019
  else:
1020
- await ctx.send("You do not have permission to ban this member.")
1021
 
1022
  else:
1023
- await ctx.send("You do not have permission to use this command.")
1024
 
1025
 
1026
 
@@ -1044,7 +1082,7 @@ async def timeout(ctx, member: discord.Member, duration: int, *, reason=None):
1044
  # Timeout the member by removing all roles
1045
  await member.edit(roles=[], reason=reason)
1046
 
1047
- await ctx.send(f"`{member}` has been timed out for `{duration} seconds`. Reason: `{reason}`")
1048
 
1049
  # Construct the message to be sent as a DM
1050
  dm_message_init = f"You have been timed out in the server `{ctx.guild.name}` for `{duration} seconds`"
@@ -1056,10 +1094,10 @@ async def timeout(ctx, member: discord.Member, duration: int, *, reason=None):
1056
  await member.send(dm_message_init)
1057
  except discord.Forbidden:
1058
  # If unable to send DM, log the error and continue
1059
- await ctx.send(f"Failed to send DM to `{member}` for timeout.")
1060
 
1061
  except Exception as e:
1062
- await ctx.send(f"An error occurred: {e}")
1063
  return # Stop execution if there's an error
1064
 
1065
  # Wait for the duration of the timeout
@@ -1080,13 +1118,13 @@ async def timeout(ctx, member: discord.Member, duration: int, *, reason=None):
1080
  await member.send(dm_message_exit)
1081
  except discord.Forbidden:
1082
  # If unable to send DM, log the error and continue
1083
- await ctx.send(f"Failed to send DM to `{member}` to notify timeout expiration.")
1084
 
1085
  else:
1086
- await ctx.send("You do not have permission to timeout this member.")
1087
 
1088
  else:
1089
- await ctx.send("You do not have permission to use this command.")
1090
 
1091
 
1092
  # UTILITY MODERATOR_CMD ------------------------------------------------------ END
 
3
  import json
4
  import asyncio
5
  import psutil
 
6
  import discord
7
  import requests
8
  from datetime import datetime
 
34
  # DEFINES ------------------------------------------------------ START
35
 
36
 
37
+ BOT_VERSION = '1.3.2'
38
 
39
  AUTHORIZED_USER_ID = os.getenv('AUTHORIZED_ID')
40
 
 
97
  inline=False
98
  )
99
  if feedback_embed.fields:
100
+ await ctx.reply(embed=feedback_embed)
101
  else:
102
+ await ctx.reply("No feedback found.")
103
 
104
 
105
 
 
108
 
109
  async def clean_directory(ctx, directory):
110
  try:
111
+
112
+ msg = await ctx.reply("Cleaning...")
113
+
114
  file_count = 0
115
  for filename in os.listdir(directory):
116
  file_path = os.path.join(directory, filename)
117
  if os.path.isfile(file_path):
118
  os.remove(file_path)
119
  file_count += 1
120
+ await msg.edit(content=f"All files cleaned successfully in {directory}. Total files cleaned: {file_count}.")
121
  except Exception as e:
122
+ await msg.edit(content=f"An error occurred while cleaning files: {e}")
123
 
124
 
125
 
 
220
  @bot.event
221
  async def on_command_error(ctx, error):
222
  if isinstance(error, commands.CommandNotFound):
223
+ await ctx.reply("Sorry, I couldn't find that command. Use `/help` or `>>help` to see the list of available commands.")
224
 
225
  else:
226
  print(f'An error occurred: {error}')
 
328
  # embed.set_footer(value="Use /help or >>help <command> for more details on a specific command.")
329
 
330
  # Send the embed as an ephemeral message
331
+ await ctx.reply(embed=embed, ephemeral=True)
332
 
333
+ await ctx.reply(f"The command `help` was executed by - {ctx.author.mention}")
334
 
335
 
336
  # FUNCTION ------------------------------------------------------ SPLIT
 
341
  attachments = ctx.message.attachments
342
 
343
  if not attachments:
344
+ await ctx.reply("No file attached.")
345
+ await ctx.reply(f"The command `compress` was executed by - {ctx.author.mention}")
346
 
347
  return
348
 
349
  for attachment in attachments:
350
  file_path = os.path.join(COMPRESS_FOLDER, attachment.filename)
351
 
352
+ msg = await ctx.reply("Compressing...")
353
+
354
  # Check if the file is already in .dvpl format, if so, skip it
355
  if file_path.endswith(".dvpl"):
356
+ await ctx.reply(f"File {attachment.filename} is already in .dvpl format. Skipping.")
357
 
358
  continue
359
 
360
  await attachment.save(file_path)
361
  compressed_file_path = await compress_file(file_path)
362
  if compressed_file_path:
363
+ await msg.edit(content=f"File {attachment.filename} has succesfully compressed.")
364
+ await ctx.reply(file=discord.File(compressed_file_path))
365
  os.remove(file_path) # Delete the original file
366
  os.remove(compressed_file_path) # Delete the compressed file
367
  else:
368
+ await ctx.reply("Failed to `compress` the file.")
369
 
370
+ await msg.edit(content=f"The command `compress` was executed by - {ctx.author.mention}")
371
 
372
 
373
 
 
379
  attachments = ctx.message.attachments
380
 
381
  if not attachments:
382
+ await ctx.reply("No file attached.")
383
+ await ctx.reply(f"The command `decompress` was executed by - {ctx.author.mention}")
384
 
385
  return
386
 
387
  for attachment in attachments:
388
  file_path = os.path.join(DECOMPRESS_FOLDER, attachment.filename)
389
 
390
+ msg = await ctx.reply("Decompressing...")
391
+
392
  # Check if the file is not in .dvpl format, if so, skip it
393
  if not file_path.endswith(".dvpl"):
394
+ await ctx.reply(f"File {attachment.filename} is not in .dvpl format. Skipping.")
395
  continue
396
 
397
  await attachment.save(file_path)
398
  decompressed_file_path = await decompress_file(file_path)
399
  if decompressed_file_path:
400
+ await msg.edit(content=f"File {attachment.filename} has succesfully decompressed.")
401
+ await ctx.reply(file=discord.File(decompressed_file_path))
402
  os.remove(file_path) # Delete the original file
403
  os.remove(decompressed_file_path) # Delete the decompressed file
404
  else:
405
+ await ctx.reply("Failed to decompress the file.")
406
 
407
+ await msg.edit(content=f"The command `decompress` was executed by - {ctx.author.mention}")
408
 
409
 
410
 
411
  # FUNCTION ------------------------------------------------------ SPLIT
412
+
413
 
414
  @bot.hybrid_command(help="Pings to check bot's latency")
415
  async def ping(ctx):
 
 
416
 
417
+ msg = await ctx.reply("Pinging...")
418
 
419
+ # Calculate client latency
420
+ client_latency = (ctx.message.created_at - ctx.message.created_at).total_seconds() * 1000
421
+
422
+ # Calculate shared latency
423
+ shared_latency = round((bot.latency * 1000) - client_latency)
424
+
425
+ await msg.edit(content=f"Pong! Client latency is {client_latency:.2f}ms. - Shared latency is {shared_latency}ms.")
426
+
427
+ await ctx.reply(f"The command `ping` was executed by - {ctx.author.mention}")
428
+
429
 
430
  # FUNCTION ------------------------------------------------------ SPLIT
431
 
432
 
433
+ @bot.command()
434
+ async def pinger(ctx, address):
435
+ try:
 
 
436
 
437
+ msg = await ctx.reply("Pinging...")
438
+
439
+ # Pinging the given address
440
+ process = subprocess.Popen(['ping', '-c', '4', address], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
441
+ stdout, stderr = process.communicate()
442
+
443
+
444
+ # Extracting latency from the output
445
+ output = stdout.decode('utf-8')
446
+ lines = output.split('\n')
447
+ latency_line = lines[-2] # assuming the second last line contains latency information
448
+ latency_values = latency_line.split('=')[-1].split('/')
449
+ min_latency = latency_values[0]
450
+ avg_latency = latency_values[1]
451
+ max_latency = latency_values[2]
452
+ mdev_latency = latency_values[3].split(' ')[0] # remove 'ms' from the end
453
+
454
+ # Sending latency to the channel
455
+ await msg.edit(content=f'Latency for {address}: Min={min_latency} ms, Avg={avg_latency} ms, Max={max_latency} ms, StdDev={mdev_latency} ms')
456
+
457
+ except Exception as e:
458
+ await msg.edit(content=f'Error occurred: {e}')
459
+
460
+ # Send the author information
461
+ await ctx.reply(f"The command `ping` was executed by - {ctx.author.mention}")
462
 
463
 
464
 
 
490
  # Send the invite link to the user's DM
491
  try:
492
  await ctx.author.send(f"Invite link for PyDVPL: {invite_link}")
493
+ await ctx.reply(f"Sent the invite link to your DM. {ctx.author.mention}")
494
  except discord.Forbidden:
495
+ await ctx.reply(f"Failed to send the invite link to your DM. {ctx.author.mention} Please make sure your DMs are open.")
496
 
497
+ await ctx.reply(f"The command `invite` was executed by - {ctx.author.mention}")
498
 
499
 
500
 
 
505
  @bot.hybrid_command(help="Send feedback or report issues", usage="<requests/issues> <message>")
506
  async def feedback(ctx, category: str, *, message: str):
507
  if category.lower() not in ["requests", "issues"]:
508
+ await ctx.reply("Invalid category. Please choose 'requests' or 'issues'.")
509
  return
510
 
511
  feedback_data = {
 
529
  with open(file_path, "w") as f:
530
  json.dump(data, f, indent=4)
531
 
532
+ await ctx.reply(f"Thank you for your {category.lower()}. It has been recorded.")
533
 
534
+ await ctx.reply(f"The command `feedback` was executed by - {ctx.author.mention}")
535
 
536
 
537
 
 
544
 
545
  if activity_start_time == 0:
546
  bot_mention = ctx.me.mention
547
+ await ctx.reply("{bot_mention}'s activity hasn't been set yet.")
548
 
549
  return
550
 
 
555
 
556
  bot_mention = ctx.me.mention
557
  uptime_message = f"{bot_mention} has been playing for - {hours} hours, {minutes} minutes, {seconds} seconds."
558
+ await ctx.reply(uptime_message)
559
 
560
+ await ctx.reply(f"The command `uptime` was executed by - {ctx.author.mention}")
561
 
562
 
563
  # FUNCTION ------------------------------------------------------ SPLIT
 
579
  embed.add_field(name="Craiyon Lib Version:", value=f"``{craiyon.__version__}``", inline=False)
580
 
581
  # Send the embed message
582
+ await ctx.reply(embed=embed)
583
 
584
+ await ctx.reply(f"The command `version` was executed by - {ctx.author.mention}")
585
 
586
 
587
  # FUNCTION ------------------------------------------------------ SPLIT
 
594
  # Format the date and time
595
  formatted_now = now.strftime("%Y-%m-%d %H:%M:%S")
596
 
597
+ await ctx.reply(f"Current date and time: `{formatted_now}`")
598
 
599
+ await ctx.reply(f"The command `clock` was executed by - {ctx.author.mention}")
600
 
601
 
602
  # FUNCTION ------------------------------------------------------ SPLIT
 
606
  async def chat(ctx, model, *, message):
607
 
608
  if str(ctx.author.id) not in AUTHORIZED_AI_ACCESS_ID:
609
+ await ctx.reply("You are not authorized to use this command. Only `@rifsxd`'s server boosters & special permitted users can enjoy free `ChatGPT` access.")
610
 
611
  return
612
+
613
+ msg = await ctx.reply("Responding...")
614
 
615
  if model.lower() == "phind":
616
  bot = phind.PHIND()
 
619
  elif model.lower() == "blackboxai":
620
  bot = blackboxai.BLACKBOXAI()
621
  else:
622
+ await ctx.reply("Invalid model. Please choose 'phind' or 'chatgpt' or 'blackboxai'.")
623
  return
624
 
625
  response = bot.chat(message)
626
+ await msg.edit(content=response)
627
 
628
+ await ctx.reply(f"The command `chat` was executed by - {ctx.author.mention}")
629
 
630
 
631
  # FUNCTION ------------------------------------------------------ SPLIT
 
635
  async def image(ctx, *, prompt: str):
636
  # Check if the user is authorized to use the command
637
  if str(ctx.author.id) not in AUTHORIZED_AI_ACCESS_ID:
638
+ await ctx.reply("You are not authorized to use this command.")
639
  return
640
 
641
  # Inform the user that the generation process has started
642
+ msg = await ctx.reply(f"Generating images for prompt: `{prompt}`. Please be patient...")
643
 
644
  try:
645
  generator = Craiyon()
 
655
  image_file = discord.File(img_bytes, filename=f"result{index}.webp")
656
  images.append(image_file)
657
 
658
+ await msg.edit(content=f"Sucessfully generated {prompt} images.")
659
  # Send images to the user
660
  await ctx.reply(files=images)
661
 
662
  except Exception as e:
663
  # Print the specific exception message for debugging
664
  print(f"An error occurred while generating images: {e}")
665
+ await ctx.reply("An error occurred while generating images. Please try again later.")
666
 
667
+ await ctx.reply(f"The command `image` was executed by - {ctx.author.mention}")
668
 
669
 
670
 
 
678
  async def clean(ctx, clean_mode):
679
  # Check if the author is authorized to use this command
680
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
681
+ await ctx.reply("You are not authorized to use this command.")
682
 
683
  return
684
 
 
691
  elif clean_mode.lower() == 'requests':
692
  await clean_directory(ctx, REQUESTS_FOLDER)
693
  else:
694
+ await ctx.reply("Invalid clean mode. Please choose 'received_to_compress', 'received_to_decompress', 'feedback_issues', or 'feedback_requests'.")
695
 
696
 
697
  # FUNCTION ------------------------------------------------------ SPLIT
 
701
  async def online(ctx):
702
  # Check if the author is authorized to use this command
703
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
704
+ await ctx.reply("You are not authorized to use this command.")
705
 
706
  return
707
  await bot.change_presence(activity=discord.Game(name=playing_time_activity))
708
+ await ctx.reply("Bot's presence set to online.")
709
 
710
 
711
 
 
716
  async def dnd(ctx):
717
  # Check if the author is authorized to use this command
718
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
719
+ await ctx.reply("You are not authorized to use this command.")
720
 
721
  return
722
  await bot.change_presence(status=discord.Status.dnd)
723
+ await ctx.reply("Bot's presence set to Do Not Disturb.")
724
 
725
 
726
 
 
731
  async def offline(ctx):
732
  # Check if the author is authorized to use this command
733
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
734
+ await ctx.reply("You are not authorized to use this command.")
735
 
736
  return
737
  await bot.change_presence(status=discord.Status.offline)
738
+ await ctx.reply("Bot's presence set to offline.")
739
 
740
 
741
 
 
746
  async def activity(ctx, activity_type, *, activity_text=None):
747
  # Check if the author is authorized to use this command
748
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
749
+ await ctx.reply("You are not authorized to use this command.")
750
 
751
  return
752
 
 
757
  elif activity_type.lower() == 'playing':
758
  activity = discord.Activity(type=discord.ActivityType.playing, name=activity_text)
759
  else:
760
+ await ctx.reply('Invalid activity type. Please choose either "listening", "playing" or "watching".')
761
 
762
  return
763
 
764
  if not activity_text:
765
+ await ctx.reply('Please provide an activity text.')
766
 
767
  return
768
 
769
  await bot.change_presence(activity=activity)
770
+ await ctx.reply(f'Activity set to {activity_type} {activity_text}')
771
 
772
 
773
 
 
778
  async def say(ctx, destination_type, *, id, message):
779
  # Check if the author is authorized to use this command
780
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
781
+ await ctx.reply("You are not authorized to use this command.")
782
  return
783
 
784
  if destination_type.lower() == 'channel':
785
  try:
786
  channel_id = int(id)
787
  except ValueError:
788
+ await ctx.reply("Channel ID must be a valid integer.")
789
  return
790
  channel = bot.get_channel(channel_id)
791
  if channel:
792
  await channel.send(message)
793
+ await ctx.reply(f"Message `{message}` sent to channel `{channel.name}`.")
794
  else:
795
+ await ctx.reply("Channel not found.")
796
 
797
  elif destination_type.lower() == 'server':
798
  try:
799
  server_id = int(id)
800
  except ValueError:
801
+ await ctx.reply("Server ID must be a valid integer.")
802
  return
803
  server = bot.get_guild(server_id)
804
  if server:
805
  announcement_channel = discord.utils.get(server.channels, name="important-announcements")
806
  if announcement_channel:
807
  await announcement_channel.send(message)
808
+ await ctx.reply(f"Message `{message}` sent to server `{server.name}` in `important-announcements` channel.")
809
  else:
810
  announcements_channel = discord.utils.get(server.channels, name="announcements")
811
  if announcements_channel:
812
  await announcements_channel.send(message)
813
+ await ctx.reply(f"Message `{message}` sent to server `{server.name}` in `announcements` channel.")
814
  else:
815
  public_updates_channel = server.public_updates_channel
816
  if public_updates_channel:
817
  await public_updates_channel.send(message)
818
+ await ctx.reply(f"Message `{message}` sent to server `{server.name}` in `public updates` channel.")
819
  else:
820
  default_channel = server.system_channel or server.text_channels[0] # Default to the first text channel
821
  if default_channel:
822
  await default_channel.send(message)
823
+ await ctx.reply(f"Message `{message}` sent to server `{server.name}` in the default channel.")
824
  else:
825
+ await ctx.reply("No announcement channels found in the server. Also, no default `public updates` neither `default` channels found.")
826
  else:
827
+ await ctx.reply("Server not found.")
828
 
829
  elif destination_type.lower() == 'user':
830
  try:
831
  user_id = int(id)
832
  except ValueError:
833
+ await ctx.reply("User ID must be a valid integer.")
834
  return
835
  user = bot.get_user(user_id)
836
  if user:
837
  try:
838
  await user.send(message)
839
+ await ctx.reply(f"Message `{message}` sent to user '{user.display_name}'.")
840
  except discord.Forbidden:
841
+ await ctx.reply(f"Couldn't send message to `{user.display_name}`. Their DMs are closed.")
842
  else:
843
+ await ctx.reply("User not found.")
844
 
845
  else:
846
+ await ctx.reply("Invalid destination type. Use either 'channel', 'server', or 'user'.")
847
 
848
 
849
 
 
854
  async def announce(ctx, *, message):
855
  # Check if the author is authorized to use this command
856
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
857
+ await ctx.reply("You are not authorized to use this command.")
858
 
859
  return
860
 
 
865
  announcement_channel = discord.utils.get(server.channels, name="important-announcements")
866
  if announcement_channel:
867
  await announcement_channel.send(embed=embed)
868
+ await ctx.reply(f"Message `{message}` sent to server `{server.name}` in `important-announcements` channel.")
869
  else:
870
  # If no "important-announcements" channel, check for "announcements" channel
871
  announcements_channel = discord.utils.get(server.channels, name="announcements")
872
  if announcements_channel:
873
  await announcements_channel.send(embed=embed)
874
+ await ctx.reply(f"Message `{message}` sent to server `{server.name}` in `announcements` channel.")
875
  else:
876
  # If neither channel exists, send to the default channel or public updates channel
877
  public_updates_channel = server.public_updates_channel
878
  if public_updates_channel:
879
  await public_updates_channel.send(embed=embed)
880
+ await ctx.reply(f"Message `{message}` sent to server `{server.name}` in `public updates` channel.")
881
  else:
882
  default_channel = server.system_channel or server.text_channels[0]
883
  if default_channel:
884
  await default_channel.send(embed=embed)
885
+ await ctx.reply(f"Message `{message}` sent to server `{server.name}` in `defaults` channel.")
886
  else:
887
+ await ctx.reply(f"No suitable announcement channel found in server `{server.name}`.")
888
 
889
  # Delete the original command message
890
 
 
897
  async def stats(ctx):
898
  # Check if the author is authorized to use this command
899
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
900
+ await ctx.reply("You are not authorized to use this command.")
901
 
902
  return
903
+
904
+ msg = await ctx.reply("Monitoring...")
905
 
906
  guild_count = len(bot.guilds)
907
  member_count = len(set(bot.get_all_members()))
 
929
  f"CPU Usage: {cpu_usage}%\n"
930
  f"Memory Usage: {memory_usage}%"
931
  )
932
+ await msg.edit(content=stats_message)
933
 
934
 
935
  # FUNCTION ------------------------------------------------------ SPLIT
 
939
  async def list(ctx, list_type):
940
  # Check if the author is authorized to use this command
941
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
942
+ await ctx.reply("You are not authorized to use this command.")
943
 
944
  return
945
 
946
  if list_type.lower() == 'servers':
947
  servers_info = "\n".join([f"{server.name} - ID: {server.id}" for server in bot.guilds])
948
+ await ctx.reply(f"List of servers the bot is on:\n```{servers_info}```")
949
 
950
  elif list_type.lower() == 'issues':
951
  await list_feedback(ctx, ISSUES_FOLDER, "List of issues:")
952
  elif list_type.lower() == 'requests':
953
  await list_feedback(ctx, REQUESTS_FOLDER, "List of requests:")
954
  else:
955
+ await ctx.reply("Invalid list type. Please choose 'servers', 'issues', or 'requests'.")
956
 
957
 
958
  # FUNCTION ------------------------------------------------------ SPLIT
 
962
  async def update(ctx, pkg_name):
963
  # Check if the author is authorized to use this command
964
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
965
+ await ctx.reply("You are not authorized to use this command.")
966
  return
967
 
968
  try:
969
 
970
+ msg = await ctx.reply("Updating package `{pkg_name}`...")
971
 
972
  # Run pip install command to upgrade the package
973
  process = subprocess.Popen(['pip', 'install', pkg_name, '--upgrade'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
974
  output, error = process.communicate()
975
 
976
  if error:
977
+ await msg.edit(content=f"Failed to update package `{pkg_name}`. Error: {error.decode('utf-8')}")
978
  else:
979
+ await msg.edit(content=f"Package `{pkg_name}` successfully updated.")
980
  except Exception as e:
981
+ await msg.edit(content=f"An error occurred while updating package `{pkg_name}`: {e}")
982
 
983
 
984
  # FUNCTION ------------------------------------------------------ SPLIT
 
988
  async def ip(ctx):
989
  # Check if the author is authorized to use this command
990
  if str(ctx.author.id) != AUTHORIZED_USER_ID:
991
+ await ctx.reply("You are not authorized to use this command.")
992
 
993
  return
994
 
995
  response = requests.get('https://api.ipify.org')
996
  if response.status_code == 200:
997
+ await ctx.reply(f'Your IP address is: `{response.text}`')
998
  else:
999
+ await ctx.reply('Failed to fetch IP address.')
1000
 
1001
 
1002
  # UTILITY ADMIN_CMD ------------------------------------------------------ END
 
1021
  dm_message += f" for the following reason: `{reason}`"
1022
  await member.send(dm_message)
1023
  except discord.Forbidden:
1024
+ await ctx.reply(f"Failed to send a direct message to {member}.")
1025
 
1026
  # Kick the member from the server
1027
  await member.kick(reason=reason)
1028
+ await ctx.reply(f"{member} has been kicked from the server.")
1029
  else:
1030
+ await ctx.reply("You do not have permission to kick this member.")
1031
 
1032
  else:
1033
+ await ctx.reply("You do not have permission to use this command.")
1034
 
1035
 
1036
  # FUNCTION ------------------------------------------------------ SPLIT
 
1049
  dm_message += f" for the following reason: `{reason}`"
1050
  await member.send(dm_message)
1051
  except discord.Forbidden:
1052
+ await ctx.reply(f"Failed to send a direct message to {member}.")
1053
 
1054
  # Ban the member from the server
1055
  await member.ban(reason=reason)
1056
+ await ctx.reply(f"{member} has been banned from the server.")
1057
  else:
1058
+ await ctx.reply("You do not have permission to ban this member.")
1059
 
1060
  else:
1061
+ await ctx.reply("You do not have permission to use this command.")
1062
 
1063
 
1064
 
 
1082
  # Timeout the member by removing all roles
1083
  await member.edit(roles=[], reason=reason)
1084
 
1085
+ await ctx.reply(f"`{member}` has been timed out for `{duration} seconds`. Reason: `{reason}`")
1086
 
1087
  # Construct the message to be sent as a DM
1088
  dm_message_init = f"You have been timed out in the server `{ctx.guild.name}` for `{duration} seconds`"
 
1094
  await member.send(dm_message_init)
1095
  except discord.Forbidden:
1096
  # If unable to send DM, log the error and continue
1097
+ await ctx.reply(f"Failed to send DM to `{member}` for timeout.")
1098
 
1099
  except Exception as e:
1100
+ await ctx.reply(f"An error occurred: {e}")
1101
  return # Stop execution if there's an error
1102
 
1103
  # Wait for the duration of the timeout
 
1118
  await member.send(dm_message_exit)
1119
  except discord.Forbidden:
1120
  # If unable to send DM, log the error and continue
1121
+ await ctx.reply(f"Failed to send DM to `{member}` to notify timeout expiration.")
1122
 
1123
  else:
1124
+ await ctx.reply("You do not have permission to timeout this member.")
1125
 
1126
  else:
1127
+ await ctx.reply("You do not have permission to use this command.")
1128
 
1129
 
1130
  # UTILITY MODERATOR_CMD ------------------------------------------------------ END