566 lines
22 KiB
Python
566 lines
22 KiB
Python
import asyncio
|
||
import json
|
||
import os
|
||
import os.path
|
||
import platform
|
||
import random
|
||
import sys
|
||
import aiohttp
|
||
import aiosqlite
|
||
|
||
import random
|
||
from random import randint
|
||
|
||
import requests
|
||
from requests import get
|
||
|
||
import time
|
||
import datetime
|
||
from datetime import datetime, timedelta, timezone
|
||
|
||
import discord
|
||
from discord.ext import commands, tasks
|
||
from discord.ext.commands import Bot, Context
|
||
from discord.utils import get
|
||
|
||
import exceptions
|
||
|
||
from helpers import checks
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Loads config.json
|
||
# ---------------------------------------------------------------------------------------
|
||
if not os.path.isfile("config.json"):
|
||
sys.exit("'config.json' not found! Please add it and try again.")
|
||
else:
|
||
with open("config.json") as file:
|
||
config = json.load(file)
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Intents Listing
|
||
# ---------------------------------------------------------------------------------------
|
||
intents = discord.Intents.all()
|
||
intents.members = True
|
||
intents.message_content = True
|
||
intents.messages = True # `message_content` is required to get the content of the messages
|
||
intents.presences = True
|
||
intents.bans = True
|
||
intents.dm_messages = True
|
||
intents.dm_reactions = True
|
||
intents.dm_typing = True
|
||
intents.emojis = True
|
||
intents.emojis_and_stickers = True
|
||
intents.guild_messages = True
|
||
intents.guild_reactions = True
|
||
intents.guild_scheduled_events = True
|
||
intents.guild_typing = True
|
||
intents.guilds = True
|
||
intents.integrations = True
|
||
intents.invites = True
|
||
intents.reactions = True
|
||
intents.typing = True
|
||
intents.voice_states = True
|
||
intents.webhooks = True
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Def what happend on mention or msg
|
||
# ---------------------------------------------------------------------------------------
|
||
bot = Bot(command_prefix=commands.when_mentioned_or(
|
||
config["prefix"]), intents=intents, help_command=None)
|
||
bot.config = config
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# DB Set
|
||
# ---------------------------------------------------------------------------------------
|
||
|
||
async def init_db():
|
||
async with aiosqlite.connect(f"{os.path.realpath(os.path.dirname(__file__))}/database/database.db") as db:
|
||
with open(f"{os.path.realpath(os.path.dirname(__file__))}/database/schema.sql") as file:
|
||
await db.executescript(file.read())
|
||
await db.commit()
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Webhook Logs
|
||
# ---------------------------------------------------------------------------------------
|
||
url = config["webhook"]
|
||
|
||
def weblogsend(msg):
|
||
data = {
|
||
"content" : msg,
|
||
"username": {context.author}
|
||
}
|
||
result = requests.post(url, json = data)
|
||
try:
|
||
result.raise_for_status()
|
||
except requests.exceptions.HTTPError as err:
|
||
print(err)
|
||
else:
|
||
print("Payload delivered successfully, code {}.".format(result.status_code))
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Bot Ready Start
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.event
|
||
async def on_ready() -> None:
|
||
guilds = [guild.id for guild in bot.guilds]
|
||
print("--------------------------------------")
|
||
print(f"Logged in as {bot.user.name}")
|
||
print(f"discord.py API version: {discord.__version__}")
|
||
print(f"Python version: {platform.python_version()}")
|
||
print(f"Running on: {platform.system()} {platform.release()} ({os.name})")
|
||
print("--------------------------------------")
|
||
print(f"The {bot.user.name} bot is in {len(guilds)} Guilds.\nThe guilds ids list : {guilds}")
|
||
print("--------------------------------------")
|
||
status_task.start()
|
||
if config["sync_commands_globally"]:
|
||
print("Syncing commands globally...")
|
||
await bot.tree.sync()
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Presence Loop
|
||
# ---------------------------------------------------------------------------------------
|
||
@tasks.loop(minutes=5)
|
||
async def status_task() -> None:
|
||
activity = discord.Activity(name=f"over {len(bot.guilds)} guilds\nand {len(bot.users)} users!", type=discord.ActivityType.watching)
|
||
await bot.change_presence(activity=activity)
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# User joins guild events
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.event
|
||
async def on_member_join(member) -> None:
|
||
role = member.guild.get_role(1061402091542806648) #
|
||
await member.add_roles(role, reason="Automatic role by bot")
|
||
embed = (
|
||
(f"|| <@&MENTION_ROLE_ID> ||\nHello {member.mention}") # MENTION_ROLE_ID = ID of role the will be mentioned on [member.guild_join]
|
||
)
|
||
discord.Embed(
|
||
description=(f"Welcome to 🐱🚀{member.guild.name}!\nHope you enjoy your time here."),
|
||
color=0x9C84EF
|
||
)
|
||
embed.set_author(
|
||
name="Welcome"
|
||
)
|
||
embed.add_field(
|
||
name="Embed Field Name",
|
||
value="`➖➖➖➖➖➖➖➖➖`\n> **Frostbite Hosting**\n`🔗` [DISCORD SERVER](<https://discord.gg/uj9QFBuqCx>)\n`➖➖➖➖➖➖➖➖➖`\n> **Frostbite Hosting**\n`🔗` [Free Bot Hosting](<https://dashboard.fb-hosting.ga/register?ref=nMHytd8d>)\n`➖➖➖➖➖➖➖➖➖`",
|
||
inline=False
|
||
)
|
||
channel = await bot.fetch_channel(GUILD_WELCOME_CHANNEL_ID) # Replace GUILD_WELCOME_CHANNEL_ID with to the channel ID where it should announce the embed.
|
||
await channel.send(embed=embed)
|
||
await member.send(embed=embed)
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# The code in this event is executed every time someone sends a message, with or without the prefix
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.event
|
||
async def on_message(message: discord.Message):
|
||
|
||
if message.author.id == bot.user.id or message.author.bot:
|
||
return
|
||
if not message.guild:
|
||
logchannel = bot.get_guild(guild_id).get_channel(channel_id) # Define the log channel when someone DM's the bot with [guild ID] and [channel ID]
|
||
embed = discord.Embed(
|
||
title="User MSG BOT DMs ",
|
||
colour=0x000,
|
||
description=f"**From:** {message.author.mention}\n\n*{message.content}*"
|
||
)
|
||
embed.set_footer(
|
||
text=message.author,
|
||
icon_url=message.author.avatar.url
|
||
)
|
||
await logchannel.send(embed=embed)
|
||
await bot.process_commands(message)
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Error handling
|
||
# This is global error handling, if you for instance want to except every CommandOnCooldown exception, you can do it like this
|
||
# ---------------------------------------------------------------------------------------
|
||
# on_command_completion
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.event
|
||
async def on_command_completion(context: Context) -> None:
|
||
|
||
full_command_name = context.command.qualified_name
|
||
split = full_command_name.split(" ")
|
||
executed_command = str(split[0])
|
||
if context.guild is not None:
|
||
print(
|
||
f"Executed {executed_command} command in {context.guild.name} (ID: {context.guild.id}) by {context.author} (ID: {context.author.id})")
|
||
else:
|
||
print(
|
||
f"Executed {executed_command} command by {context.author} (ID: {context.author.id}) in DMs")
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# on_command_error
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.event
|
||
async def on_command_error(context: Context, error) -> None:
|
||
|
||
if isinstance(error, commands.CommandOnCooldown):
|
||
minutes, seconds = divmod(error.retry_after, 60)
|
||
hours, minutes = divmod(minutes, 60)
|
||
hours = hours % 24
|
||
embed = discord.Embed(
|
||
title="Hey, Stop that . you will break me",
|
||
description=f"You can use this command again in {f'{round(hours)} hours' if round(hours) > 0 else ''} {f'{round(minutes)} minutes' if round(minutes) > 0 else ''} {f'{round(seconds)} seconds' if round(seconds) > 0 else ''}.",
|
||
color=0xE02B2B
|
||
)
|
||
await context.send(embed=embed)
|
||
elif isinstance(error, exceptions.UserBlacklisted):
|
||
embed = discord.Embed(
|
||
title="Error!",
|
||
description="You are blacklisted from using the bot.",
|
||
color=0xE02B2B
|
||
)
|
||
await context.send(embed=embed)
|
||
elif isinstance(error, exceptions.UserNotOwner):
|
||
embed = discord.Embed(
|
||
title="Error!",
|
||
description="You are not the owner of the bot!",
|
||
color=0xE02B2B
|
||
)
|
||
await context.send(embed=embed)
|
||
elif isinstance(error, commands.MissingPermissions):
|
||
embed = discord.Embed(
|
||
title="Error!",
|
||
description="You are missing the permission(s) `" + ", ".join(
|
||
error.missing_permissions) + "` to execute this command!",
|
||
color=0xE02B2B
|
||
)
|
||
await context.send(embed=embed)
|
||
elif isinstance(error, commands.MissingRequiredArgument):
|
||
embed = discord.Embed(
|
||
title="Error!",
|
||
# We need to capitalize because the command arguments have no capital letter in the code.
|
||
description=str(error).capitalize(),
|
||
color=0xE02B2B
|
||
)
|
||
await context.send(embed=embed)
|
||
raise error
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Load COGS for this bot
|
||
# ---------------------------------------------------------------------------------------
|
||
async def load_cogs() -> None:
|
||
for file in os.listdir(f"./cogs"):
|
||
if file.endswith(".py"):
|
||
extension = file[:-3]
|
||
try:
|
||
await bot.load_extension(f"cogs.{extension}")
|
||
print(f"Loaded extension '{extension}'")
|
||
except Exception as e:
|
||
exception = f"{type(e).__name__}: {e}"
|
||
print(f"Failed to load extension {extension}\n{exception}")
|
||
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# LEGACY BOT COMMANDS
|
||
# ---------------------------------------------------------------------------------------
|
||
# [perfix]groupDM {<@&role>} (message)
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
@checks.is_owner()
|
||
async def groupDM(context, role: discord.Role, *, message: str) -> None:
|
||
for member in role.members:
|
||
await member.send(message)
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# LIST categories, text channels, voice channels, all channels + categories
|
||
# ---------------------------------------------------------------------------------------
|
||
# Categories
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
@checks.is_owner()
|
||
async def cata(context) -> None: # async def cat(context):
|
||
for category in context.message.guild.categories: # for category in context.message.guild.categories:
|
||
await context.send(f"`{category.id}` - <#{category.id}>") # print(category.name)
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Text channels
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
@checks.is_owner()
|
||
async def txtChannel(context) -> None:
|
||
for text_channel in context.message.guild.text_channels:
|
||
await context.send(f"`{text_channel.id}` - <#{text_channel.id}>")
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Voice channels
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
@checks.is_owner()
|
||
async def vc(context) -> None:
|
||
for voice_channel in context.message.guild.voice_channels:
|
||
await context.send(f"`{voice_channel.id}` - <#{voice_channel.id}>")
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# All Channels + Categories
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
@checks.is_owner()
|
||
async def channels(context) -> None:
|
||
for channel in context.message.guild.channels:
|
||
await context.send(f"`{channel.id}` - <#{channel.id}>")
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# BOT logs on_guild_join
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.event
|
||
async def on_guild_join(guild) -> None:
|
||
print(guild.name)
|
||
print(guild.id)
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# BOT logs on_guild_leave
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.event
|
||
async def on_guild_leave(guild) -> None:
|
||
print(guild.name)
|
||
print(guild.id)
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# verify into the server
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
async def verifyme(context, member=None) -> None:
|
||
|
||
verifyrole = discord.utils.get(context.guild.roles, name="ROLE_NAME") # YOU MUST SPECIFY THE ROLE NAME
|
||
try:
|
||
await context.author.add_roles(verifyrole)
|
||
except Exception as errortoaddroles:
|
||
await context.send(f'Error in add roles\n```py\n{errortoaddroles}```')
|
||
await context.message.delete()
|
||
await member.send(f'{context.author} | {context.author.id} Should now be verified.')
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Countdown/timer
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
async def countdown(ctx, t: int):
|
||
await ctx.send(f"Counting down from {t}s")
|
||
|
||
while t > 0:
|
||
t -= 1
|
||
# Sleep for 1 second
|
||
await asyncio.sleep(1)
|
||
|
||
await ctx.send("Countdown end reached")
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Creating a role, only specifying it's name
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
async def create_role(ctx, *, name):
|
||
# Create the role
|
||
await ctx.guild.create_role(name=name)
|
||
await ctx.send(f"Created role with name {name}")
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Adding a role to everybody in the server
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
async def addroles(ctx, *, role: discord.Role):
|
||
for m in ctx.guild.members:
|
||
await m.add_roles(role)
|
||
await asyncio.sleep(1)
|
||
await ctx.send("Added roles")
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# You can also specify specific users to add a role to:
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
async def addrole(ctx, role: discord.Role, *members: discord.Member):
|
||
for m in members:
|
||
await m.add_roles(role)
|
||
print(f":white_check_mark: Role {role} added to {m.mention}")
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Sending messages *, arg is useful if you want to consume all as a string
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
async def echo(ctx, *, message):
|
||
# Delete message that invokes command
|
||
await ctx.delete()
|
||
|
||
# Repeat back the input and auto delete after 20 seconds
|
||
await ctx.send(message, delete_after=20)
|
||
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Sending messages You can loop over each text channel in a guild, and send a message
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
async def sendToAll(ctx, *, message):
|
||
for channel in ctx.guild.text_channels:
|
||
await channel.send(message)
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# User info
|
||
# ---------------------------------------------------------------------------------------
|
||
def getstatus(m):
|
||
if str(m.status) == "dnd":
|
||
return "do not disturb"
|
||
return m.status
|
||
|
||
@bot.command()
|
||
async def userinfo(ctx, member: discord.Member):
|
||
c_delta = datetime.utcnow()
|
||
c_at = member.created_at.strftime("%c")
|
||
join_pos = sorted(ctx.guild.members, key=lambda member: member.joined_at).index(member) + 1
|
||
|
||
embed = discord.Embed(
|
||
title=f"{member.name}#{member.discriminator}",
|
||
timestamp=datetime.utcnow(),
|
||
colour=0x000
|
||
)
|
||
embed.add_field(
|
||
name="Status:",
|
||
value=getstatus(member),
|
||
inline=True
|
||
)
|
||
embed.add_field(
|
||
name="Guild name:",
|
||
value=member.display_name,
|
||
inline=True
|
||
)
|
||
embed.add_field(
|
||
name="Join position:",
|
||
value=f"{join_pos}/{len(ctx.guild.members)}",
|
||
inline=True
|
||
)
|
||
embed.add_field(
|
||
name="Created at:",
|
||
value=f"{c_at}",
|
||
inline=True
|
||
)
|
||
embed.add_field(
|
||
name="ID:",
|
||
value=member.id,
|
||
inline=True
|
||
)
|
||
embed.add_field(
|
||
name="Bot:",
|
||
value="✅ Yes" if member.bot else "❌ No",
|
||
inline=True
|
||
)
|
||
# Setting the thumbnail as the users profile picture
|
||
embed.set_thumbnail(
|
||
url=member.avatar
|
||
)
|
||
# Setting a footer
|
||
embed.set_footer(
|
||
text=f"Requested by {ctx.author.name}",
|
||
icon_url=ctx.author.avatar
|
||
)
|
||
await ctx.send(embed=embed)
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Background task and command group
|
||
# We can make command groups which will allow us make subcommands
|
||
# ---------------------------------------------------------------------------------------
|
||
@tasks.loop(seconds=60) # Loop every 60 seconds
|
||
async def loop_function(ctx, message):
|
||
await ctx.send(message)
|
||
|
||
@bot.group(invoke_without_command=True) # Specify that we don't want the 'first' command called when we use a subcommand
|
||
async def loop(ctx):
|
||
await ctx.send("**1.** Start loop: `.loop start {message}`\n**2.** Stop loop: `.loop stop`")
|
||
|
||
@loop.command() # Subcommand named 'start', so called like this: "PREFIXloop start message goes here"
|
||
async def start(ctx, *, message):
|
||
await ctx.send("**Starting loop...**")
|
||
# Starting the loop function
|
||
loop_function.start(ctx, message)
|
||
|
||
@loop.command() # Subcommand named stop
|
||
async def stop(ctx):
|
||
await ctx.send("**Stopping loop...**")
|
||
# Stopping the loop
|
||
loop_function.stop()
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Getting online members/offline members
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
async def online(ctx):
|
||
online_m, offline_m = [], []
|
||
# Loop over each member in guild.members
|
||
for m in ctx.guild.members:
|
||
# Add to list of online members (online_m) if status is online/dnd, else add to offline_m
|
||
(online_m if str(m.status) in ("online", "dnd") else offline_m).append(str(m))
|
||
await ctx.send(f"Online: {', '.join(online_m)}\nOffline: {', '.join(offline_m)}")
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Fetching audit log
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command()
|
||
async def logs(ctx):
|
||
actions = []
|
||
async for entry in ctx.guild.audit_logs(limit = 10):
|
||
time = entry.created_at.strftime("%d-%m-%Y %H:%M:%S")
|
||
actions.append(f"`{entry.user}` did `{entry.action}` at `{time}` to `{entry.target}`\n\n")
|
||
|
||
embed = discord.Embed(
|
||
title="Audit log",
|
||
description=''.join(actions),
|
||
colour=0x000
|
||
)
|
||
await ctx.send(embed=embed)
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# Evaluates customized code
|
||
# ---------------------------------------------------------------------------------------
|
||
@bot.command(aliases=['e', 'evaluate'])
|
||
@commands.is_owner()
|
||
async def eval(context, *, code):
|
||
"""Evaluates customized code"""
|
||
language_specifiers = ["python", "py", "javascript", "js", "html", "css", "php", "md", "markdown", "go", "golang", "c", "c++", "cpp", "c#", "cs", "csharp", "java", "ruby", "rb", "coffee-script", "coffeescript", "coffee", "bash", "shell", "sh", "json", "http", "pascal", "perl", "rust", "sql", "swift", "vim", "xml", "yaml"]
|
||
loops = 0
|
||
while code.startswith("`"):
|
||
code = "".join(list(code)[1:])
|
||
loops += 1
|
||
if loops == 3:
|
||
loops = 0
|
||
break
|
||
for language_specifier in language_specifiers:
|
||
if code.startswith(language_specifier):
|
||
code = code.lstrip(language_specifier)
|
||
try:
|
||
while code.endswith("`"):
|
||
code = "".join(list(code)[0:-1])
|
||
loops += 1
|
||
if loops == 3:
|
||
break
|
||
code = "\n".join(f" {i}" for i in code.splitlines())
|
||
code = f"async def eval_expr():\n{code}"
|
||
def send(text):
|
||
bot.loop.create_task(context.send(text))
|
||
env = {
|
||
"bot": bot,
|
||
"client": bot,
|
||
"context": context,
|
||
"print": send,
|
||
"_author": context.author,
|
||
"_message": context.message,
|
||
"_channel": context.channel,
|
||
"_guild": context.guild,
|
||
"_me": context.me
|
||
}
|
||
env.update(globals())
|
||
exec(code, env)
|
||
eval_expr = env["eval_expr"]
|
||
result = await eval_expr()
|
||
await context.message.add_reaction("\N{WHITE HEAVY CHECK MARK}")
|
||
if result:
|
||
await context.send(result)
|
||
except Exception as learntofuckingcode:
|
||
await context.message.add_reaction("\N{WARNING SIGN}")
|
||
await context.send(f'**Error**```py\n{learntofuckingcode}```')
|
||
|
||
# ---------------------------------------------------------------------------------------
|
||
# RUN BOT
|
||
# ---------------------------------------------------------------------------------------
|
||
asyncio.run(init_db())
|
||
asyncio.run(load_cogs())
|
||
bot.run(config["token"]) |