This commit is contained in:
Parker M. 2025-01-25 22:58:41 -06:00
commit 3c18d552c2
Signed by: parker
GPG Key ID: 505ED36FC12B5D5E
117 changed files with 3714 additions and 0 deletions

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
config.yml
config.ini
.DS_STORE
__pycache__
count.db
.vscode
winning_reels
losing_reels_1
losing_reels_2
losing_reels_3
losing_reels_4
losing_reels_5

BIN
AquaBot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

24
LICENSE Normal file
View File

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>

82
README.md Normal file
View File

@ -0,0 +1,82 @@
<h1 align="center">
<br>
<img src="AquaBot.png" width="250" alt="Aqua Bot Image"></a>
<br>
Aqua Bot<br>
</h1>
<h3 align="center">
Multipurpse Discord bot made on d.py
</h3>
<p align="center">
<a href="https://github.com/Rapptz/discord.py/">
<img src="https://img.shields.io/badge/discord-py-blue.svg" alt="discord.py">
</a>
</p>
# Aqua Bot
Aqua Bot is a great multipurpose Discord bot that is open source and offers all features for free. A list of the features for Aqua Bot can be found below.
Aqua Bot is no longer under development and does not run anymore. Attention has been switched to the music only Discord bot, Guava, which can be found [here](https://github.com/packetparker/guava)
### Features
- Music - Play music from YouTube, Spotify, SoundCloud, Deezer, and Bandcamp
- Moderation - Kick, ban, mute, tempmute, warn, etc.
- Economy - Global leaderboard to show who has the most money, and buy ranks to show off to others
- Gambling - Gamble your money at the blackjack table or on the slot machines, or flip a coin
- Random - Get crypto price data, information on a users Discord account, etc.
<br>
## Selfhost
If you want to selfhost your own version of Aqua Bot, follow the instructions below.
Downlooad the code and install the necessary dependencies using pip (ex: `pip install -r requirements.txt`)
On first run, you will likely get a critical warning in your console, don't worry, this is excepted. It will automatically create a `config.ini` file for you in the root of the directory with all of the necessary configuration options.
Fill out all of the configuration options, ALL options must be filled out. For help on what each option does, look at the table below.
### BOT_INFO Configuration
Field | Description
--- | ---
TOKEN | The token for your bot
BONUS_COOLDOWN | Cooldown time, in hours, between uses of the `/add` command, which gives users $10,000
BOT_COLOR | Hex color code for the color used on most of the message embeds
BUG_CHANNEL_ID | Channel ID for the bug reporting channel
FEEDBACK_CHANNEL_ID | Channel ID for the feedback message channel
### CRYPTO_COMPARE Configuration
Field | Description
--- | ---
API_KEY | API key from your CryptoCompare account. Can be aquired [here](https://min-api.cryptocompare.com/).
### POSTGESQL Configuration
Field | Description
--- | ---
USERNAME | Username for login
PASSWORD | Password for login
HOST | Host for connecting to database
PORT | Port for connecting to database
DATABASE | Name of the database to be used
### LAVALINK Configuration
Field | Description
--- | ---
HOST | Host for connecting to Lavalink
PORT | Port for connecting to Lavalink
PASSWORD | Password for login
### SPOTIFY CONFIGURATION
Field | Description
--- | ---
CLIENT_ID | Client ID given to you from Spotify Developer Dashboard
CLIENT_SECRET | Client Secret, found in the same place
Once all options are properly configured, you must also setup a Lavalink server in order for the music features to work. For help on setting up a Lavalnk server, follow the docs [here](https://lavalink.dev/getting-started/).
Once your Lavalink server has been configured, you can now, finally, start the bot again by running the `bot.py` file and everything should work.

75
code/bot.py Normal file
View File

@ -0,0 +1,75 @@
import discord
from discord.ext import commands, tasks
import os
import zipfile
import tqdm
import requests
from validate_config import create_config
from database import init_database
from global_variables import LOG, BOT_TOKEN, SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET
def unpack_reels():
# Files ending in .zip within /code/utils, extract it to /code/utils
for file in os.listdir("code/utils"):
# If folders exist, don't unpack
if (os.path.exists("code/utils/winning_reels") and
os.path.exists("code/utils/losing_reels_1") and
os.path.exists("code/utils/losing_reels_2") and
os.path.exists("code/utils/losing_reels_3") and
os.path.exists("code/utils/losing_reels_4") and
os.path.exists("code/utils/losing_reels_5")):
break
if file.endswith(".zip"):
with zipfile.ZipFile(f"code/utils/{file}", 'r') as zip_ref:
for member in tqdm.tqdm(iterable=zip_ref.namelist(), total=len(zip_ref.namelist()), desc=f"Unpacking {file}..."):
zip_ref.extract(member, "code/utils")
class MyBot(commands.Bot):
def __init__(self):
super().__init__(
command_prefix='***',
activity = discord.Game(name="Ping Me For Help!"),
intents = discord.Intents.default()
)
async def setup_hook(self):
unpack_reels()
create_config()
get_access_token.start()
await init_database()
for ext in os.listdir('./code/cogs'):
if ext.endswith('.py'):
await self.load_extension(f'cogs.{ext[:-3]}')
bot = MyBot()
bot.count_hold = 0
bot.remove_command('help')
@bot.event
async def on_ready():
LOG.info(f"{bot.user} has connected to Discord.")
@tasks.loop(minutes=45)
async def get_access_token():
auth_url = 'https://accounts.spotify.com/api/token'
data = {
'grant_type': 'client_credentials',
'client_id': SPOTIFY_CLIENT_ID,
'client_secret': SPOTIFY_CLIENT_SECRET
}
response = requests.post(auth_url, data=data)
access_token = response.json()['access_token']
bot.access_token = access_token
class InsufficientFundsException(Exception):
def __init__(self) -> None:
super().__init__()
if __name__ == '__main__':
bot.run(BOT_TOKEN)

257
code/cogs/blackjack.py Normal file
View File

@ -0,0 +1,257 @@
import asyncio
import os
import random
from typing import List, Tuple
import discord
from discord.ext import commands
from PIL import Image
from discord import app_commands
from bot import InsufficientFundsException
from database import Database
"""NOTE: This code was found somewhere on GitHub a long time ago. I changed it a bit to work for
discord.py 2.0 and for my needs. If anyone knows who wrote this, please let me know so I can
give them credit."""
Entry = Tuple[int, int]
class Card:
suits = ["clubs", "diamonds", "hearts", "spades"]
def __init__(self, suit: str, value: int, down=False):
self.suit = suit
self.value = value
self.down = down
self.symbol = self.name[0].upper()
@property
def name(self) -> str:
"""The name of the card value."""
if self.value <= 10: return str(self.value)
else: return {
11: 'jack',
12: 'queen',
13: 'king',
14: 'ace',
}[self.value]
@property
def image(self):
return (
f"{self.symbol if self.name != '10' else '10'}"\
f"{self.suit[0].upper()}.png" \
if not self.down else "red_back.png"
)
def flip(self):
self.down = not self.down
return self
def __str__(self) -> str:
return f'{self.name.title()} of {self.suit.title()}'
def __repr__(self) -> str:
return str(self)
class Blackjack(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.economy = Database(bot)
async def check_bet(
self,
interaction: discord.Interaction,
bet
):
bet = int(bet)
if bet <= 0:
raise commands.errors.BadArgument()
current = (await self.economy.get_entry(interaction.user.id))[1]
if bet > current:
raise InsufficientFundsException()
@staticmethod
def hand_to_images(hand: List[Card]) -> List[Image.Image]:
return ([
Image.open(f'./code/utils/cards/{card.image}')
for card in hand
])
@staticmethod
def center(*hands: Tuple[Image.Image]) -> Image.Image:
"""Creates blackjack table with cards placed"""
bg: Image.Image = Image.open('./code/utils/table.png')
bg_center_x = bg.size[0] // 2
bg_center_y = bg.size[1] // 2
img_w = hands[0][0].size[0]
img_h = hands[0][0].size[1]
start_y = bg_center_y - (((len(hands)*img_h) + \
((len(hands) - 1) * 15)) // 2)
for hand in hands:
start_x = bg_center_x - (((len(hand)*img_w) + \
((len(hand) - 1) * 10)) // 2)
for card in hand:
bg.alpha_composite(card, (start_x, start_y))
start_x += img_w + 10
start_y += img_h + 15
return bg
def output(self, name, *hands: Tuple[List[Card]]) -> None:
self.center(*map(self.hand_to_images, hands)).save(f'./code/players/tables/{name}.png')
@staticmethod
def calc_hand(hand: List[List[Card]]) -> int:
"""Calculates the sum of the card values and accounts for aces"""
non_aces = [c for c in hand if c.symbol != 'A']
aces = [c for c in hand if c.symbol == 'A']
sum = 0
for card in non_aces:
if not card.down:
if card.symbol in 'JQK': sum += 10
else: sum += card.value
for card in aces:
if not card.down:
if sum <= 10: sum += 11
else: sum += 1
return sum
@app_commands.command()
@app_commands.describe(bet='Amount of money to bet')
async def blackjack(
self,
interaction: discord.Interaction,
bet: app_commands.Range[int, 1, None]
):
"Bet your money on a blackjack game vs. the dealer"
if f"{interaction.user.id}.png" in os.listdir("./code/players/tables"):
await interaction.response.send_message(f"{interaction.user.mention}, It appears you have a game already running in this server or another, please finish that game before starting a new one.", ephemeral=True)
else:
await self.check_bet(interaction, bet)
deck = [Card(suit, num) for num in range(2,15) for suit in Card.suits]
random.shuffle(deck) # Generate deck and shuffle it
player_hand: List[Card] = []
dealer_hand: List[Card] = []
player_hand.append(deck.pop())
dealer_hand.append(deck.pop())
player_hand.append(deck.pop())
dealer_hand.append(deck.pop().flip())
player_score = self.calc_hand(player_hand)
dealer_score = self.calc_hand(dealer_hand)
async def out_table(**kwargs) -> discord.Interaction:
self.output(f'{interaction.user.id}', dealer_hand, player_hand)
embed = discord.Embed(**kwargs)
file = discord.File(
f"./code/players/tables/{interaction.user.id}.png", filename=f"{interaction.user.id}.png"
)
embed.set_image(url=f"attachment://{interaction.user.id}.png")
try:
msg = await interaction.response.send_message(file=file, embed=embed)
except:
msg = await interaction.edit_original_response(attachments=[file], embed=embed)
reac = await interaction.original_response()
await reac.clear_reactions()
return msg
standing = False
while True:
player_score = self.calc_hand(player_hand)
dealer_score = self.calc_hand(dealer_hand)
if player_score == 21: # win condition
await self.economy.add_money(interaction.user.id, bet*2)
result = (f"Blackjack! - you win ${bet*2:,}", 'won')
break
elif player_score > 21: # losing condition
await self.economy.add_money(interaction.user.id, bet*-1)
result = (f"Player busts - you lose ${bet:,}", 'lost')
break
msg = await out_table(
title="Your Turn",
description=f"Your hand: {player_score}\n" \
f"Dealer's hand: {dealer_score}"
)
reac = await interaction.original_response()
await reac.add_reaction("🇭")
await reac.add_reaction("🇸")
buttons = {"🇭", "🇸"}
try:
reaction, _ = await self.bot.wait_for(
'reaction_add', check=lambda reaction, user:user == interaction.user and reaction.emoji in buttons, timeout=60
)
except asyncio.TimeoutError:
os.remove(f'./code/players/tables/{interaction.user.id}.png')
await interaction.followup.send(f"{interaction.user.mention} your game timed out. No money was lost or gained.")
return
if str(reaction.emoji) == "🇭":
player_hand.append(deck.pop())
continue
elif str(reaction.emoji) == "🇸":
standing = True
break
if standing:
dealer_hand[1].flip()
player_score = self.calc_hand(player_hand)
dealer_score = self.calc_hand(dealer_hand)
while dealer_score < 17: # dealer draws until 17 or greater
dealer_hand.append(deck.pop())
dealer_score = self.calc_hand(dealer_hand)
if dealer_score == 21: # winning/losing conditions
await self.economy.add_money(interaction.user.id, bet*-1)
result = (f"Dealer blackjack - you lose ${bet:,}", 'lost')
elif dealer_score > 21:
await self.economy.add_money(interaction.user.id, bet*2)
result = (f"Dealer busts - you win ${bet*2:,}", 'won')
elif dealer_score == player_score:
result = (f"Tie - you keep your money", 'kept')
elif dealer_score > player_score:
await self.economy.add_money(interaction.user.id, bet*-1)
result = (f"You lose ${bet:,}", 'lost')
elif dealer_score < player_score:
await self.economy.add_money(interaction.user.id, bet*2)
result = (f"You win ${bet*2:,}", 'won')
color = (
discord.Color.red() if result[1] == 'lost'
else discord.Color.green() if result[1] == 'won'
else discord.Color.blue()
)
if result[1] == 'won':
description=(
f"**You won ${bet*2:,}**\nYour hand: {player_score}\n" +
f"Dealer's hand: {dealer_score}"
)
elif result[1] == 'lost':
description=(
f"**You lost ${bet:,}**\nYour hand: {player_score}\n" +
f"Dealer's hand: {dealer_score}"
)
msg = await out_table(
title=result[0],
color=color,
)
os.remove(f'./code/players/tables/{interaction.user.id}.png')
async def setup(bot: commands.Bot):
await bot.add_cog(Blackjack(bot))

62
code/cogs/coinflip.py Normal file
View File

@ -0,0 +1,62 @@
import discord
from discord.ext import commands
from discord import app_commands
import random
from bot import InsufficientFundsException
from database import Database
class CoinFlip(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.economy = Database(bot)
async def check_bet(
self,
interaction: discord.Interaction,
bet
):
bet = int(bet)
if bet <= 0:
raise commands.errors.BadArgument()
current = (await self.economy.get_entry(interaction.user.id))[1]
if bet > current:
raise InsufficientFundsException()
@app_commands.command()
@app_commands.checks.cooldown(1, 2)
@app_commands.describe(bet="The amount of money you want to bet")
async def coinflip(
self,
interaction: discord.Interaction,
bet: int
):
"Bet money on a coinflip (heads=win, tails=lose)"
await self.check_bet(interaction, bet)
if random.randint(0, 2) == 0:
await self.economy.add_money(interaction.user.id, bet*2)
embed = discord.Embed(
title=f"You won ${bet*2:,}!",
description="You flipped heads!",
color=discord.Color.green()
)
return await interaction.response.send_message(embed=embed)
else:
await self.economy.add_money(interaction.user.id, bet*-1)
embed = discord.Embed(
title=f"You lost ${bet:,}!",
description="You flipped tails!",
color=discord.Color.red()
)
return await interaction.response.send_message(embed=embed)
async def setup(bot: commands.Bot):
await bot.add_cog(CoinFlip(bot))

40
code/cogs/count.py Normal file
View File

@ -0,0 +1,40 @@
from discord.ext import commands, tasks
import aiosqlite
import sqlite3
class Count(commands.Cog):
def __init__(self, bot):
self.bot = bot
async def cog_load(self):
self.dump_count.start()
@tasks.loop(seconds=5)
async def dump_count(self):
try:
cur = await aiosqlite.connect("./code/count/count.db")
count = await cur.execute("SELECT count FROM count")
count = await count.fetchone()
if count is None:
await cur.execute("INSERT INTO count (count) VALUES (?)", (self.bot.count_hold,))
else:
await cur.execute("UPDATE count SET count = count + ?", (self.bot.count_hold,))
await cur.commit()
await cur.close()
self.bot.count_hold = 0
except sqlite3.OperationalError:
try:
await cur.commit()
await cur.close()
except:
pass
@commands.Cog.listener()
async def on_app_command_completion(self, interaction, command):
self.bot.count_hold += 1
async def setup(bot):
await bot.add_cog(Count(bot))

68
code/cogs/covid.py Normal file
View File

@ -0,0 +1,68 @@
import discord
from discord.ext import commands, tasks
from discord import app_commands
import requests
covid_dict = {'total_cases':0, 'total_deaths':0, 'total_recovered':0, 'active_cases':0,
'critical_cases':0, 'cases_today':0, 'deaths_today':0, 'tests':0}
class Covid(commands.Cog):
def __init__(self, bot):
self.bot = bot
async def cog_load(self):
self.update_covid.start()
@tasks.loop(seconds=300)
async def update_covid(self):
response = requests.get("https://disease.sh/v3/covid-19/all")
if response.status_code == 200:
data = response.json()
cases = int(data["cases"])
deaths = int(data["deaths"])
recovered = int(data["recovered"])
active = int(data["active"])
critical = int(data["critical"])
cases_today = int(data["todayCases"])
deaths_today = int(data["todayDeaths"])
tests = int(data["tests"])
else:
return
update_crypto_dict = {'total_cases':cases, 'total_deaths':deaths,
'total_recovered':recovered, 'active_cases':active, 'critical_cases':critical,
'cases_today':cases_today, 'deaths_today':deaths_today, 'tests':tests}
covid_dict.update(update_crypto_dict)
@app_commands.command()
async def covid(
self,
interaction: discord.Interaction
):
"Get current global Covid-19 data"
embed = discord.Embed(
title = "World COVID-19 Data",
description = "Data is updated once every 5 minutes"
)
embed.add_field(name="Total Cases", value=f"```{covid_dict['total_cases']:,}```", inline=True)
embed.add_field(name="Total Deaths", value=f"```{covid_dict['total_deaths']:,}```", inline=True)
embed.add_field(name="Total Recovered", value=f"```{covid_dict['total_recovered']:,}```", inline=True)
embed.add_field(name="Active Cases", value=f"```{covid_dict['active_cases']:,}```", inline=True)
embed.add_field(name="Critical Cases", value=f"```{covid_dict['critical_cases']:,}```", inline=True)
embed.add_field(name="Cases Today", value=f"```{covid_dict['cases_today']:,}```", inline=True)
embed.add_field(name="Deaths Today", value=f"```{covid_dict['deaths_today']:,}```", inline=True)
embed.add_field(name="Tests", value=f"```{covid_dict['tests']:,}```", inline=True)
embed.set_footer(text="Information provided from: https://disease.sh/v3/covid-19/all")
file = discord.File("./code/utils/covid.png", filename="covid.png")
embed.set_thumbnail(url="attachment://covid.png")
await interaction.response.send_message(embed=embed, file=file)
async def setup(bot):
await bot.add_cog(Covid(bot))

126
code/cogs/crypto.py Normal file
View File

@ -0,0 +1,126 @@
import discord
from discord.ext import commands, tasks
from discord import app_commands
from typing import Literal
from decimal import Decimal
import requests
from global_variables import CRYPTO_COMPARE_API_KEY
master_dict = {'Bitcoin (BTC)':'0:0:0:0:0:0', 'Ethereum (ETH)':'0:0:0:0:0:0',
'Binance Coin (BNB)':'0:0:0:0:0:0', 'Solana (SOL)':'0:0:0:0:0:0', 'Cardano (ADA)':'0:0:0:0:0:0',
'XRP (XRP)':'0:0:0:0:0:0', 'Polkadot (DOT)':'0:0:0:0:0:0','Dogecoin (DOGE)':'0:0:0:0:0:0',
'Avalanche (AVAX)':'0:0:0:0:0:0', 'SHIBA INU (SHIB)':'0:0:0:0:0:0', 'Terra (LUNA)':'0:0:0:0:0:0',
'Litecoin (LTC)':'0:0:0:0:0:0', 'Uniswap (UNI)':'0:0:0:0:0:0', 'Chainlink (LINK)':'0:0:0:0:0:0',
'Polygon (MATIC)':'0:0:0:0:0:0', 'Algorand (ALGO)':'0:0:0:0:0:0', 'Bitcoin Cash (BCH)':'0:0:0:0:0:0',
'VeChain (VET)':'0:0:0:0:0:0', 'Stellar (XLM)':'0:0:0:0:0:0', 'Internet Computer (ICP)':'0:0:0:0:0:0'}
currencies = ['Bitcoin (BTC)', 'Ethereum (ETH)', 'Binance Coin (BNB)', 'Solana (SOL)',
'Cardano (ADA)', 'XRP (XRP)', 'Polkadot (DOT)', 'Dogecoin (DOGE)', 'Avalanche (AVAX)',
'SHIBA INU (SHIB)', 'Terra (LUNA)', 'Litecoin (LTC)', 'Uniswap (UNI)', 'Chainlink (LINK)',
'Polygon (MATIC)', 'Algorand (ALGO)', 'Bitcoin Cash (BCH)', 'VeChain (VET)', 'Stellar (XLM)',
'Internet Computer (ICP)']
connect_color_dict = {'Bitcoin (BTC)':0xf7931a, 'Ethereum (ETH)':0x627eea,
'Binance Coin (BNB)':0xf3ba2f, 'Solana (SOL)':0x27dcb8, 'Cardano (ADA)':0x3cc8c8,
'XRP (XRP)':0x00aae4, 'Polkadot (DOT)':0xf0047f,'Dogecoin (DOGE)':0xc3a634,
'Avalanche (AVAX)':0xe84142, 'SHIBA INU (SHIB)':0xe93b24, 'Terra (LUNA)':0x5494f8,
'Litecoin (LTC)':0x345d9d, 'Uniswap (UNI)':0xff027d, 'Chainlink (LINK)':0x335dd2,
'Polygon (MATIC)':0x2bbdf7, 'Algorand (ALGO)':0x000000, 'Bitcoin Cash (BCH)':0x8dc351,
'VeChain (VET)':0x15bdff, 'Stellar (XLM)':0x14b6e7, 'Internet Computer (ICP)':0xf15a24}
connect_icon_dict = {'Bitcoin (BTC)':'bitcoin', 'Ethereum (ETH)':'ethereum',
'Binance Coin (BNB)':'binance', 'Solana (SOL)':'solana', 'Cardano (ADA)':'cardano',
'XRP (XRP)':'xrp', 'Polkadot (DOT)':'polkadot','Dogecoin (DOGE)':'dogecoin',
'Avalanche (AVAX)':'avalanche', 'SHIBA INU (SHIB)':'shiba', 'Terra (LUNA)':'terra',
'Litecoin (LTC)':'litecoin', 'Uniswap (UNI)':'uniswap', 'Chainlink (LINK)':'chainlink',
'Polygon (MATIC)':'polygon', 'Algorand (ALGO)':'algorand', 'Bitcoin Cash (BCH)':'bitcoin_cash',
'VeChain (VET)':'vechain', 'Stellar (XLM)':'stellar', 'Internet Computer (ICP)':'internet_computer'}
class Crypto(commands.Cog):
def __init__(self, bot):
self.bot = bot
async def cog_load(self):
self.update_crypto.start()
def update_dicts_for_currency(self, response, cut_currency, currency):
round_num = 8 if cut_currency == 'SHIB' else 3 if cut_currency == 'DOGE' else 3 if cut_currency == 'VET' else 3 if cut_currency == 'XLM' else 2
market = response.json()['RAW'][cut_currency]['USD']['LASTMARKET']
price = round(Decimal(response.json()['RAW'][cut_currency]['USD']['PRICE']), round_num)
change_24h = round(Decimal(response.json()['RAW'][cut_currency]['USD']['CHANGEPCT24HOUR']), 2)
high = round(Decimal(response.json()['RAW'][cut_currency]['USD']['HIGH24HOUR']), round_num)
low = round(Decimal(response.json()['RAW'][cut_currency]['USD']['LOW24HOUR']), round_num)
mktcap = round(Decimal(response.json()['RAW'][cut_currency]['USD']['MKTCAP']), 2)
master_dict[currency] = f'{market}:{price}:{change_24h}:{high}:{low}:{mktcap}'
@tasks.loop(seconds=60)
async def update_crypto(self):
response = requests.get(
f'https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC,ETH,BNB,SOL,ADA,XRP,DOT,DOGE,AVAX,SHIB,LUNA,LTC,UNI,LINK,MATIC,ALGO,BCH,VET,XLM,ICP&tsyms=USD&api_key={CRYPTO_COMPARE_API_KEY}'
)
for currency in currencies:
cut_currency = currency[currency.find("(")+1:currency.find(")")]
self.update_dicts_for_currency(response, cut_currency, currency)
@app_commands.command()
async def prices(
self,
interaction: discord.Interaction,
):
"See the current crypto prices"
embed = discord.Embed(
title="Current Crpytocurrency Price",
description=f"**In order to see more information on a specific cryptocurrency, do `/crypto <ticker>` to show price, percentage change, and more.** \n\nPrices are updated every 60 seconds. \nLetters following the name within () are known as the ticker. \nExample: Bitcoin (BTC) - The ticker is BTC",
color=discord.Color.gold()
)
for key in master_dict:
price = master_dict[key].split(':')[1]
embed.add_field(name = f"{key}", value = f"```${Decimal(price):,}```", inline=True)
await interaction.response.send_message(embed=embed)
@app_commands.command()
@app_commands.describe(currency="Pick what cryptocurrency you want to see more information on.")
async def crypto(
self,
interaction: discord.Interaction,
currency: Literal['Bitcoin (BTC)', 'Ethereum (ETH)', 'Binance Coin (BNB)', 'Solana (SOL)',
'Cardano (ADA)', 'XRP (XRP)', 'Polkadot (DOT)', 'Dogecoin (DOGE)', 'Avalanche (AVAX)',
'SHIBA INU (SHIB)', 'Terra (LUNA)', 'Litecoin (LTC)', 'Uniswap (UNI)', 'Chainlink (LINK)',
'Polygon (MATIC)', 'Algorand (ALGO)', 'Bitcoin Cash (BCH)', 'VeChain (VET)', 'Stellar (XLM)',
'Internet Computer (ICP)']
):
"Send more information on a certain cryptocurrency"
icon_name = connect_icon_dict.get(currency)
color = connect_color_dict.get(currency)
market = master_dict[currency].split(':')[0]
price = master_dict[currency].split(':')[1]
price_change = master_dict[currency].split(':')[2]
high = master_dict[currency].split(':')[3]
low = master_dict[currency].split(':')[4]
mktcap = master_dict[currency].split(':')[5]
embed = discord.Embed(
title=currency,
description="Information is updated every 60 seconds",
color=color
)
embed.add_field(name="Market", value = f"```{market}```")
embed.add_field(name="Current Price", value=f"```${Decimal(price):,}```")
embed.add_field(name="24 Hour Change", value=f"```{Decimal(price_change):,}%```")
embed.add_field(name="24 Hour High", value=f"```${Decimal(high):,}```")
embed.add_field(name="24 Hour Low", value=f"```${Decimal(low):,}```")
embed.add_field(name="Market Cap", value=f"```${Decimal(mktcap):,}```")
file = discord.File(f"./code/utils/crypto_icons/{icon_name}.png", filename=f"{icon_name}.png")
embed.set_thumbnail(url=f"attachment://{icon_name}.png")
await interaction.response.send_message(embed=embed, file=file)
async def setup(bot):
await bot.add_cog(Crypto(bot))

View File

@ -0,0 +1,139 @@
import discord
from discord.ext import commands
from discord import app_commands
import random
from bot import InsufficientFundsException
from global_variables import BOT_COLOR, BONUS_COOLDOWN
from database import Database
class GamblingHelpers(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.economy = Database(bot)
async def check_bet(
self,
interaction: discord.Interaction,
bet
):
bet = int(bet)
if bet <= 0:
raise commands.errors.BadArgument()
current = (await self.economy.get_entry(interaction.user.id))[1]
if bet > current:
raise InsufficientFundsException()
# This is only here temporarily, because I accidentally deleted the database
@commands.command()
@commands.is_owner()
@commands.dm_only()
async def refund(
self,
ctx: commands.Context,
id,
amount: int
):
user = await self.bot.fetch_user(id)
if user:
await self.economy.add_money(id, amount)
await ctx.send(f"Refunded {user} ${amount:,}")
else:
await ctx.send("User not found")
@app_commands.command()
@app_commands.checks.cooldown(1, BONUS_COOLDOWN*3600)
async def add(
self,
interaction: discord.Interaction
):
f"Add $10,000 to your balance every {BONUS_COOLDOWN} hours"
amount = 10000
await self.economy.add_money(interaction.user.id, amount)
embed = discord.Embed(
title="I've added $10,000 to you balance",
description=f"Come back again in {BONUS_COOLDOWN} hours.",
color=BOT_COLOR
)
await interaction.response.send_message(embed=embed, ephemeral=True)
@app_commands.command()
@app_commands.checks.cooldown(1, 120)
async def work(
self,
interaction: discord.Interaction
):
"Work for a randomized amount of money every 2 minutes"
a = random.randint(500, 2500)
b = random.randint(500, 2500)
if a == b:
num = 50000000
else:
num = a + b
await self.economy.add_money(interaction.user.id, num)
embed = discord.Embed(
title=f"You worked and earned ${num:,}",
description="Come back again in 2 minutes.",
color=BOT_COLOR
)
await interaction.response.send_message(embed=embed, ephemeral=True)
@app_commands.command()
async def leaderboard(
self,
interaction: discord.Interaction
):
"Show the global currency leaderboard"
entries = await self.economy.top_entries(5)
embed = discord.Embed(
title="Global Economy Leaderboard:",
description="",
color=discord.Color.gold()
)
for i, entry in enumerate(entries):
id = entry[0]
name = f"<@{id}>"
embed.description += f"**`{i+1}.` {name}**\n${entry[1]:,}\n\n"
await interaction.response.send_message(embed=embed)
@app_commands.command()
@app_commands.describe(user="The user to give money to")
@app_commands.describe(amount="The amount of money to give the user")
async def give(
self,
interaction: discord.Interaction,
user: discord.Member,
amount: app_commands.Range[int, 1, None]
):
"Give money to another user"
if user == interaction.user:
embed = discord.Embed(
title="Self Error",
description="You cannot give money to yourself, please try again with a different user.",
color=BOT_COLOR
)
return await interaction.response.send_message(embed=embed, ephemeral=True)
else:
await self.check_bet(interaction, amount)
await self.economy.add_money(user.id, amount)
await self.economy.add_money(interaction.user.id, amount*-1)
embed = discord.Embed(
title="Gift Success",
description=f"You have successfully given {user.mention} ${amount:,}!",
color=discord.Color.green()
)
return await interaction.response.send_message(embed=embed)
async def setup(bot: commands.Bot):
await bot.add_cog(GamblingHelpers(bot))

124
code/cogs/handlers.py Normal file
View File

@ -0,0 +1,124 @@
import discord
from discord.ext import commands
from discord.ext.commands.errors import *
from bot import InsufficientFundsException
from global_variables import BOT_COLOR
class slash_handlers(commands.Cog):
def __init__(self, bot):
self.bot = bot
bot.tree.on_error = self.on_error
async def on_error(self, interaction: discord.Interaction, error):
error = getattr(error, 'original', error)
if isinstance(error, CommandNotFound):
return
elif isinstance(error, ZeroDivisionError):
return
elif isinstance(error, AttributeError):
return
elif isinstance(error, InsufficientFundsException):
embed = discord.Embed(
title="Insufficient Funds!",
description=f"You do not have enough money to use that command. You can use `/add` to add more money. You can also check your current balance with `/profile`",
color=BOT_COLOR
)
await interaction.response.send_message(embed=embed, ephemeral=True)
elif isinstance(error, BadArgument):
embed = discord.Embed(
title="Bad Argument!",
description=f"The arguments you provided in the command are invalid. Please try again.",
color=BOT_COLOR
)
await interaction.response.send_message(embed=embed, ephemeral=True)
elif isinstance(error, discord.app_commands.errors.MissingPermissions):
embed = discord.Embed(
title="Missing Permissions!",
description=f"{error}",
color=BOT_COLOR
)
await interaction.response.send_message(embed=embed, ephemeral=True)
elif isinstance(error, discord.app_commands.errors.BotMissingPermissions):
embed = discord.Embed(
title="Bot Missing Permissions!",
description=f"{error}",
color=BOT_COLOR
)
await interaction.response.send_message(embed=embed, ephemeral=True)
elif isinstance(error, discord.app_commands.errors.CommandOnCooldown) and interaction.command.name != "slots":
s = int(error.retry_after)
s = s % (24 * 3600)
h = s // 3600
s %= 3600
m = s // 60
s %= 60
embed = discord.Embed(
title="Command On Cooldown!",
description=f"Please wait another {h}hrs {m}min {s}sec before trying that command again.",
color=BOT_COLOR
)
await interaction.response.send_message(embed=embed, ephemeral=True)
elif isinstance(error, discord.app_commands.errors.CommandOnCooldown) and interaction.command.name == "slots":
embed = discord.Embed(
title="Slots Cooldown!",
description="To prevent spamming, the slots command in on a 4 second cooldown. Sorry for the inconvenience.",
color=BOT_COLOR
)
await interaction.response.send_message(embed=embed, ephemeral=True)
elif isinstance(error, UnboundLocalError):
await interaction.response.send_message(f"{interaction.user.mention}, your game timed out, no money was lost or gained.", ephemeral=True)
elif isinstance(error, discord.errors.Forbidden) and interaction.command.name in ('kick', 'ban', 'softban'):
embed = discord.Embed(
title="Forbidden Error",
description=f"Moderation actions cannot be performed on the bot, or on members above the bot (like owners or administrators), please try again on users below me.",
color=BOT_COLOR
)
await interaction.response.send_message(embed=embed, ephemeral=True)
elif isinstance(error, discord.errors.Forbidden) and interaction.command.name in ('mute', 'tempmute', 'unmute'):
embed = discord.Embed(
title="Forbidden Error",
description=f"I cannot mute or unmute members with a role that is above mine. Please double check that my roles are listed above your servers muted role.",
color=BOT_COLOR
)
await interaction.response.send_message(embed=embed, ephemeral=True)
elif isinstance(error, discord.errors.Forbidden) and interaction.command.name == 'purge':
embed = discord.Embed(
title="Permissions Error",
description=f"It appears im missing the `manage messages` permissions needed to be able to run the `purge` command..",
color=BOT_COLOR
)
await interaction.response.send_message(embed=embed, ephemeral=True)
else:
raise error
@commands.Cog.listener()
async def on_command_error(self, ctx, error):
return
async def setup(bot: commands.Bot):
await bot.add_cog(slash_handlers(bot))

158
code/cogs/help.py Normal file
View File

@ -0,0 +1,158 @@
import discord
from discord.ext import commands
import re
from discord import app_commands
from global_variables import BOT_COLOR
class HelpDropdown(discord.ui.Select):
def __init__(self):
options = [
discord.SelectOption(label='Economy', description='add, profile, shop, blackjack, slots, leaderboard', emoji="💰"),
discord.SelectOption(label='Moderation', description='mute, tempmute, unmute, kick, ban, softban, purge', emoji="⚔️"),
discord.SelectOption(label='Info', description='prices, crypto, covid, invite, userinfo, botinfo, vote, bug, feedback, ping', emoji=""),
discord.SelectOption(label='Music', description='play, skip, queue, remove, stop, clear, repeat, shuffle, nowplaying, pause, remove', emoji='🎵'),
discord.SelectOption(label='Admin', description='setmute, muterole, delmute', emoji="⚙️"),
]
super().__init__(placeholder='Choose a category...', min_values=1, max_values=1, options=options)
async def callback(self, interaction: discord.Interaction):
if self.values[0] == 'Economy':
embed = discord.Embed(
title=":moneybag: - Economy Help",
description="**Options in `<>` are mandatory**",
color=BOT_COLOR
)
embed.add_field(name="**Add**", value=f"**Usage: `/add`**\nGives you $10,000. Can be run every 2 hours", inline=False)
embed.add_field(name="**Work**", value=f"**Usage: `/Work`**\nGives you an amount of money between $1,000 and $5,000.", inline=False)
embed.add_field(name="**Shop**", value=f"**Usage: `/shop`**\nGives you the shop menus so that you can buy items", inline=False)
embed.add_field(name="**Blackjack**", value=f"**Usage: `/blackjack <bet>`**\nAllows you to play blackjack with the amount of money bet", inline=False)
embed.add_field(name="**Slots**", value=f"**Usage: `/slots <bet>`**\nTake your chances on the slots with a bet of your choice.", inline=False)
embed.add_field(name="**Profile**", value=f"**Usage: `/profile <member>`**\nShows the amount of money and ranks that a user has", inline=False),
embed.add_field(name="**Leaderboard**", value=f"**Usage: `/leaderboard` **\nShows the top 5 players with the most money. This is a global leaderboard and not per server.", inline=False)
await interaction.response.edit_message(embed=embed)
if self.values[0] == 'Moderation':
embed = discord.Embed(
title=":crossed_swords: - Moderation Help",
description="**Options in `<>` are mandatory**",
color=BOT_COLOR
)
embed.add_field(name="**Warn**", value=f"**Usage: `/warn <member> <reason>`** \nWarn a member for doing something against the rules.", inline=True)
embed.add_field(name="**Delwarn**", value=f"**Usage: `/delwarn <warn ID>`** \nDelete a warning from a member so that it is no longer on their record.", inline=True)
embed.add_field(name="**Warnings**", value=f"**Usage: `/warnings <member>`** \nSee all of the warnings for a member. Also includes when they were warned, and who warned them.", inline=True)
embed.add_field(name="**Mute**", value=f"**Usage: `/mute <member> <time>`** \nMute a member so they can't send anymore messages.", inline=True)
embed.add_field(name="**Tempmute**", value=f"**Usage: `/tempmute <member> <time - in hours>` \nExample: `/tempmute @bob 2`** \nMutes the member temporarily, they will be unmuted once the specified time has passed.", inline=True)
embed.add_field(name="**Unmute**", value=f"**Usage: `/unmute <member>`** \nUnmute a member so they are able to send messages again.", inline=True)
embed.add_field(name="**Purge**", value=f"**Usage: `/purge <amount>`** \nDelete messages from your server. Max amount that can be deleted at one time is `100` messages.")
embed.add_field(name="**Kick**", value=f"**Usage: `/kick <member> <reason>`** \nKick a member from your server. They will be able to join back with a new invite.", inline=True)
embed.add_field(name="**Ban**", value=f"**Usage: `/ban <member> <reason>`** \nBan a member from your server. They will not be able to join back until they are unbanned.", inline=True)
embed.add_field(name="**Softban**", value=f"**Usage: `/softban <member> <reason>`** \nThis command will ban and then immediately unban the member in order to get rid of their message history.", inline=True)
await interaction.response.edit_message(embed=embed)
if self.values[0] == "Info":
embed = discord.Embed(
title=":question: - Info Help",
description="**Options in `<>` are mandatory**",
color=BOT_COLOR
)
embed.add_field(name="**Prices**", value=f"**Usage: `/prices`** \nShows the prices for the 20 cryptocurrencies that we currently list", inline=True)
embed.add_field(name="**Crypto**", value=f"**Usage: `/crypto <ticker>`** \nShows expanded information on the specific currency given its ticker.", inline=True)
embed.add_field(name="**Covid**", value=f"**Usage: `/covid` **\nSends the current global COVID-19 data.", inline=True)
embed.add_field(name="**Invite**", value=f"**Usage: `/invite` **\nSends the invite for the bot.", inline=True)
embed.add_field(name="**User Info**", value=f"**Usage: `/userinfo <member>`** \nGives information on a member in your server. Information includes account creation date, when they joined your server, and some more.", inline=True)
embed.add_field(name="**Bot Info**", value=f"**Usage: `/botinfo`** \nGives information on the bot.", inline=True)
embed.add_field(name="**Vote**", value=f"**Usage: `/vote`** \nSends the link for you to vote for our bot on top.gg", inline=True)
embed.add_field(name="**Bug**", value=f"**Usage: `/bug`** \nShows a form to be filled out to notify the developer of a bug", inline=True)
embed.add_field(name="**Feedback**", value=f"**Usage: `/feedback`** \nShows a form to be filled out to show the developer feedback on the both", inline=True)
embed.add_field(name="**Ping**", value=f"**Usage: `/ping` **\nGives the current ping of the bot.", inline=True)
await interaction.response.edit_message(embed=embed)
if self.values[0] == "Music":
embed = discord.Embed(
title=f":musical_note: - Music Help \n*NOTE - These commands are still in beta. Please report bugs using `/contact`",
description="**Options in `<>` are mandatory**",
color=BOT_COLOR
)
embed.add_field(name="**Play**", value=f"**Usage: `/play <name/URL>` **\nSearches YouTube, and then plays the top song.", inline=True)
embed.add_field(name="**Skip**", value=f"**Usage: `/skip` **\nSkips the song that is currently playing.", inline=True)
embed.add_field(name="**Queue**", value=f"**Usage: `/queue`** \nSends all of the songs that are in the queue.", inline=True)
embed.add_field(name="**Remove**", value=f"**Usage: `/remove <song #>` **\nRemoves the specified song from the queue.", inline=True)
embed.add_field(name="**Stop**", value=f"**Usage: `/stop`** \nStops music, clears queue, and leaves VC.", inline=True),
embed.add_field(name="**Clear**", value=f"**Usage: `/clear` **\nRemoves ALL songs in the queue.", inline=True)
embed.add_field(name="**Repeat**", value=f"**Usage: `/remove`** \nRepeats the song that is playing. Run the command again to stop repeating.", inline=True)
embed.add_field(name="**Shuffle**", value=f"**Usage: `/shuffle`** \nWill play a random song in the queue. Run the command again to stop shuffling.", inline=True)
embed.add_field(name="**NowPlaying**", value=f"**Usage: `/np` **\nSends the song that is currently playing.", inline=True)
embed.add_field(name="**Pause**", value=f"**Usage: `/pause`** \nPauses the currently playing song.", inline=True)
embed.add_field(name="**Resume**", value=f"**Usage: `/resume` **\nResumes the paused song.", inline=True)
await interaction.response.edit_message(embed=embed)
if self.values[0] == "Admin":
embed = discord.Embed(
title=":gear: - Admin Help",
description="**Options in `<>` are mandatory**",
color=BOT_COLOR
)
embed.add_field(name="**Setmute**", value = f"**Usage: `/setmute <name of role>` **\nSets the role that will be given to users whenever you use the `/mute` command.", inline=True)
embed.add_field(name="**Delmute**", value = f"**Usage: `/delmute` **\nDeletes the muted role from our database.", inline=True)
embed.add_field(name="**Muterole**", value = f"**Usage: `/muterole`** \nSends the current role that is assigned as the muted role for your server.", inline=True)
await interaction.response.edit_message(embed=embed)
else:
return
class HelpView(discord.ui.View):
def __init__(self, timeout=180.0):
super().__init__(timeout=timeout)
self.value = None
self.add_item(HelpDropdown())
url = "https://discord.com/api/oauth2/authorize?client_id=889027125275922462&permissions=8&scope=bot%20applications.commands"
self.add_item(discord.ui.Button(label="Invite Me", url=url, row=2))
@discord.ui.button(label='Main Page', style=discord.ButtonStyle.blurple, row=2)
async def main_page(self, interaction: discord.Interaction, button: discord.ui.Button):
embed = discord.Embed(
title="Help",
description=f"**IMPORTANT - A lot of stuff changed, please use the `new` command to see all of the changes** \n\nFor extended information on commands and categories, please choose an option from the dropdown menu below.",
color=BOT_COLOR
)
await interaction.response.edit_message(embed=embed)
class Help(commands.Cog):
def __init__(self, bot):
self.bot = bot
@app_commands.command()
async def help(
self,
interaction: discord.Interaction
):
"Sends the bots commands and features"
embed = discord.Embed(
title="Help",
description=f"**IMPORTANT - All commands are now slash commands, and a few changes have been made. Please use `/new` to see any alterations.",
color=BOT_COLOR
)
view = HelpView()
await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
@commands.Cog.listener()
async def on_message(self, message: discord.Message) -> None:
if re.fullmatch(rf"<@!?{self.bot.user.id}>", message.content):
embed = discord.Embed(
title=f"All commands are now slash commands!",
description=f"**Use `/help` in order to get help on what commands are available.**",
color=BOT_COLOR
)
await message.reply(embed=embed)
async def setup(bot):
await bot.add_cog(Help(bot))

77
code/cogs/info.py Normal file
View File

@ -0,0 +1,77 @@
import time
import discord
from discord.ext import commands
import datetime
from discord import app_commands
from global_variables import BOT_COLOR
class Info(commands.Cog):
def __init__(self, bot):
self.bot = bot
@app_commands.command()
@app_commands.describe(member="Member whose information you want to view")
async def userinfo(
self,
interaction: discord.Interaction,
member: discord.Member
):
"Send account information for the given user"
embed = discord.Embed(
title=f"User Information For {member}",
color=BOT_COLOR
)
roles = [role for role in member.roles]
roles = f" ".join([f"{role.mention}, " for role in roles])
embed.set_thumbnail(url = member.avatar.url)
embed.add_field(name="Account name: ", value=f"`{str(member)}`")
embed.add_field(name="Discord ID: ", value=f"`{str(member.id)}`")
embed.add_field(name="Nickname: ", value=f"`{member.nick}`" or "`No nickname!`")
embed.add_field(name="Account created at: ", value=f"`{member.created_at.strftime('%Y-%m-%d')}`")
embed.add_field(name="Joined server at: ", value=f"`{member.joined_at.strftime('%Y-%m-%d')}`")
if member.bot is True:
embed.add_field(name="Discord bot? ", value="`🤖 = ✅`")
else:
embed.add_field(name="Discord bot?", value="`🤖 = ❌`")
embed.add_field(name="Top role: ", value=f"{member.top_role.mention}")
embed.add_field(name="Roles: ", inline=False, value=roles)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
try:
await interaction.response.send_message(embed=embed)
except discord.errors.HTTPException:
embed.remove_field(7)
await interaction.response.send_message(embed=embed)
@app_commands.command()
async def botinfo(
self,
interaction: discord.Interaction
):
"Get information about the bot. i.e. number of servers, creation date, etc."
embed = discord.Embed(
title=f"Bot Information",
color=BOT_COLOR
)
#embed.set_thumbnail(url=self.bot.user.avatar.url)
embed.add_field(name="Servers: ", value = f"`{len(self.bot.guilds):,}`"),
embed.add_field(name="Account name: ", value=f"`{str(self.bot.user.name)}`")
embed.add_field(name="Discord ID: ", value=f"`{str(self.bot.user.id)}`")
embed.add_field(name="Bot created at: ", value=f"`{self.bot.user.created_at.strftime('%Y-%m-%d')}`"),
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
async def setup(bot):
await bot.add_cog(Info(bot))

102
code/cogs/modals.py Normal file
View File

@ -0,0 +1,102 @@
from discord.ext import commands
import discord
from discord import app_commands
from global_variables import BUG_CHANNEL_ID, BOT_COLOR, FEEDBACK_CHANNEL_ID
class BugReport(discord.ui.Modal, title='Report a bug'):
def __init__(self, bot):
super().__init__()
self.bot = bot
name = discord.ui.TextInput(
label='Discord name & tag',
placeholder='EX: Bob#0001...',
)
command = discord.ui.TextInput(
label='Command with error',
placeholder='EX: blackjack...',
required=True
)
report = discord.ui.TextInput(
label='A detailed report of the bug',
style=discord.TextStyle.long,
placeholder='Type your report here...',
required=True,
max_length=500,
)
async def on_submit(self, interaction: discord.Interaction):
await interaction.response.send_message(f'Thanks for your bug report. We will get back to you as soon as possible', ephemeral=True)
channel = self.bot.get_channel(BUG_CHANNEL_ID)
embed = discord.Embed(
title="Bug Report",
description=f"Submitted by {self.name}",
color=BOT_COLOR
)
embed.add_field(name="Command with issue:", value=f"{self.command}", inline=False)
embed.add_field(name="Report:", value=f"{self.report}", inline=False)
await channel.send(embed=embed)
class FeedbackForm(discord.ui.Modal, title='Give feedback about the bot'):
def __init__(self, bot):
super().__init__()
self.bot = bot
name = discord.ui.TextInput(
label='Discord name & tag',
placeholder='EX: Bob#0001...',
)
positive = discord.ui.TextInput(
label='What do you like about the bot?',
style=discord.TextStyle.long,
placeholder='Your response here...',
required=True,
max_length = 500
)
negative = discord.ui.TextInput(
label='What should be changed about the bot?',
style=discord.TextStyle.long,
placeholder='Your response here...',
required=True,
max_length=500
)
async def on_submit(self, interaction: discord.Interaction):
await interaction.response.send_message(f'Thank you for your feedback. We love hearing from users!', ephemeral=True)
channel = self.bot.get_channel(FEEDBACK_CHANNEL_ID)
embed = discord.Embed(
title="Bot Feedback",
description=f"Submitted by {self.name}",
color=BOT_COLOR
)
embed.add_field(name = "Positive:", value = f"{self.positive}", inline=False)
embed.add_field(name = "Negative:", value = f"{self.negative}", inline=False)
await channel.send(embed=embed)
class Modals(commands.Cog):
def __init__(self, bot):
self.bot = bot
@app_commands.command()
async def bug(self, interaction: discord.Interaction):
"Send a bug report to the developer"
await interaction.response.send_modal(BugReport(self.bot))
@app_commands.command()
async def feedback(self, interaction: discord.Interaction):
"Send bot feeback to the developer"
await interaction.response.send_modal(FeedbackForm(self.bot))
async def setup(bot):
await bot.add_cog(Modals(bot))

96
code/cogs/moderation.py Normal file
View File

@ -0,0 +1,96 @@
import discord
from discord.ext import commands
import datetime
from discord import app_commands
class Moderation(commands.Cog):
def __init__(self, bot):
self.bot = bot
@app_commands.default_permissions(manage_messages=True)
@app_commands.command()
@app_commands.checks.has_permissions(manage_messages=True)
@app_commands.describe(amount='Number of messages you would like deleted')
async def purge(
self,
interaction: discord.Interaction,
amount: app_commands.Range[int, 1, 100]
):
"Delete the specified number of messages from the channel"
await interaction.channel.purge(limit=amount+1)
await interaction.response.send_message(f"{amount} {'messages' if amount > 1 else 'message'} deleted")
@app_commands.default_permissions(kick_members=True)
@app_commands.command()
@app_commands.checks.has_permissions(kick_members=True)
@app_commands.describe(member='Member you would like to kick')
@app_commands.describe(reason='Reason for kicking the member')
async def kick(
self,
interaction: discord.Interaction,
member: discord.Member,
reason: str
):
"Kick a member from your server"
await member.kick(reason=reason)
embed = discord.Embed(
title=f"{member} Kicked",
description=f"{interaction.user.mention} has kicked {member.mention} for `\"{reason}\"`.",
color=discord.Color.orange()
)
embed.set_thumbnail(url=member.avatar.url)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.default_permissions(ban_members=True)
@app_commands.command()
@app_commands.checks.has_permissions(ban_members=True)
@app_commands.describe(member='Member you would like to ban')
@app_commands.describe(reason='Reason for banning the member')
async def ban(
self,
interaction: discord.Interaction,
member: discord.Member,
reason: str
):
"Ban a member from your server"
await member.ban(reason=reason)
embed = discord.Embed(
title=f"{member} Banned",
description=f"{interaction.user.mention} has banned {member.mention} for `\"{reason}\"`.",
color=discord.Color.red()
)
embed.set_thumbnail(url=member.avatar.url)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.default_permissions(kick_members=True)
@app_commands.command()
@app_commands.checks.has_permissions(kick_members=True)
@app_commands.describe(member='Member you would like to softban')
@app_commands.describe(reason='Reason for softbanning the member')
async def softban(
self,
interaction: discord.Interaction,
member: discord.Member,
reason: str
):
"Ban and then immediately unban a member"
await member.ban(reason=reason)
await member.unban()
embed = discord.Embed(
title=f"{member} Softbanned",
description=f"{interaction.user.mention} has softbanned {member.mention} for `\"{reason}\"`.",
color=discord.Color.orange()
)
embed.set_thumbnail(url=member.avatar.url)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
async def setup(bot):
await bot.add_cog(Moderation(bot))

584
code/cogs/music.py Normal file
View File

@ -0,0 +1,584 @@
import re
import discord
import lavalink
from discord.ext import commands
import math
import requests
import datetime
from discord import app_commands
from custom_source import CustomSource
from global_variables import BOT_COLOR
url_rx = re.compile(r'https?://(?:www\.)?.+')
class LavalinkVoiceClient(discord.VoiceClient):
"""
This is the preferred way to handle external voice sending
This client will be created via a cls in the connect method of the channel
see the following documentation:
https://discordpy.readthedocs.io/en/latest/api.html#voiceprotocol
"""
def __init__(self, client: commands.Bot, channel: discord.abc.Connectable):
self.client = client
self.channel = channel
if hasattr(self.client, 'lavalink'):
self.lavalink = self.client.lavalink
else:
self.client.lavalink = lavalink.Client(client.user.id)
self.client.lavalink.add_node(
'127.0.0.1',
2333,
'youshallnotpass',
'us-central',
'default-node'
)
self.lavalink = self.client.lavalink
async def on_voice_server_update(self, data):
lavalink_data = {
't': 'VOICE_SERVER_UPDATE',
'd': data
}
await self.lavalink.voice_update_handler(lavalink_data)
async def on_voice_state_update(self, data):
lavalink_data = {
't': 'VOICE_STATE_UPDATE',
'd': data
}
await self.lavalink.voice_update_handler(lavalink_data)
async def connect(self, *, timeout: float, reconnect: bool, self_deaf: bool = True, self_mute: bool = False) -> None:
self.lavalink.player_manager.create(guild_id=self.channel.guild.id)
await self.channel.guild.change_voice_state(channel=self.channel, self_mute=self_mute, self_deaf=self_deaf)
async def disconnect(self, *, force: bool) -> None:
player = self.lavalink.player_manager.get(self.channel.guild.id)
if not force and not player.is_connected:
return
await self.channel.guild.change_voice_state(channel=None)
player.channel_id = None
self.cleanup()
class Music(commands.Cog):
def __init__(self, bot):
self.bot = bot
if not hasattr(bot, 'lavalink'): # This ensures the client isn't overwritten during cog reloads.
bot.lavalink = lavalink.Client(self.bot.user.id)
bot.lavalink.add_node(
'127.0.0.1',
2333,
'youshallnotpass',
'us-central',
'default-node'
) # Host, Port, Password, Region, Name
self.lavalink: lavalink.Client = bot.lavalink
self.lavalink.add_event_hooks(self.track_hook)
def cog_unload(self):
""" Cog unload handler. This removes any event hooks that were registered. """
self.lavalink._event_hooks.clear()
async def ensure_before(self, interaction):
""" Command before-invoke handler. """
guild_check = interaction.guild is not None
if guild_check:
await self.ensure_voice(interaction)
return guild_check
async def ensure_voice(self, interaction: discord.Interaction):
""" This check ensures that the bot and command author are in the same voicechannel. """
player = self.lavalink.player_manager.create(interaction.guild.id)
should_connect = interaction.command.name in ('play',)
if not interaction.user.voice or not interaction.user.voice.channel:
await interaction.response.send_message('Join a voicechannel first.', ephemeral=True)
raise ZeroDivisionError
if not player.is_connected:
if not should_connect:
await interaction.response.send_message('Not connected.', ephemeral=True)
raise ZeroDivisionError
permissions = interaction.user.voice.channel.permissions_for(interaction.user)
if not permissions.connect or not permissions.speak:
await interaction.response.send_message('I need the `CONNECT` and `SPEAK` permissions.', ephemeral=True)
raise ZeroDivisionError
player.store('channel', interaction.channel.id)
await interaction.user.voice.channel.connect(cls=LavalinkVoiceClient)
else:
if int(player.channel_id) != interaction.user.voice.channel.id:
await interaction.response.send_message('You need to be in my voicechannel.', ephemeral=True)
raise ZeroDivisionError
async def track_hook(self, event):
if isinstance(event, lavalink.events.QueueEndEvent):
guild_id = event.player.guild_id
guild = self.bot.get_guild(guild_id)
await guild.voice_client.disconnect(force=True)
@commands.Cog.listener()
async def on_voice_state_update(self, member, before, after):
if before.channel and member == self.bot.user:
if after.channel is None:
player = self.lavalink.player_manager.get(member.guild.id)
player.queue.clear()
await player.stop()
guild = member.guild
try:
await guild.voice_client.disconnect(force=True)
player.shuffle = not player.shuffle if player.shuffle else player.shuffle
except AttributeError:
pass
@app_commands.command()
@app_commands.describe(name="Name or link of song")
async def play(
self,
interaction: discord.Interaction,
name: str
):
"Play a song from your favorite music provider"
await self.ensure_before(interaction)
player = self.lavalink.player_manager.get(interaction.guild.id)
query = name
# Below begins the start of the search for Spotify links - we must check for playlist, albums, and tracks
# We use a custom source in order to provide us with the correct information and streams
if "open.spotify.com/playlist" in query:
playlist_id = query.split("playlist/")[1].split("?si=")[0]
playlist_url = f"https://api.spotify.com/v1/playlists/{playlist_id}"
headers = {"Authorization": f"Bearer {self.bot.access_token}"}
response = requests.get(playlist_url, headers=headers)
if response.status_code == 200:
playlist = response.json()
embed = discord.Embed(
title = "Playlist Queued",
description = f"**{playlist['name']}** from **{playlist['owner']['display_name']}**\n` {len(playlist['tracks']['items'])} ` tracks\n\nQueued by: {interaction.user.mention}",
color=BOT_COLOR
)
embed.set_thumbnail(url=playlist['images'][0]['url'])
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
tracks = await CustomSource.load_playlist(self, interaction.user, playlist)
for track in tracks['tracks']:
player.add(requester=interaction.user, track=track)
if "open.spotify.com/album" in query:
album_id = query.split("album/")[1]
album_url = f"https://api.spotify.com/v1/albums/{album_id}"
headers = {"Authorization": f"Bearer {self.bot.access_token}"}
response = requests.get(album_url, headers=headers)
if response.status_code == 200:
album = response.json()
embed = discord.Embed(
title = "Album Queued",
description = f"**{album['name']}** by **{album['artists'][0]['name']}**\n` {len(album['tracks']['items'])} ` tracks\n\nQueued by: {interaction.user.mention}",
color=BOT_COLOR
)
embed.set_thumbnail(url=album['images'][0]['url'])
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
tracks = await CustomSource.load_album(self, interaction.user, album)
for track in tracks['tracks']:
player.add(requester=interaction.user, track=track)
if "open.spotify.com/track" in query:
track_id = query.split("track/")[1]
track_url = f"https://api.spotify.com/v1/tracks/{track_id}"
headers = {"Authorization": f"Bearer {self.bot.access_token}"}
response = requests.get(track_url, headers=headers)
if response.status_code == 200:
track = response.json()
embed = discord.Embed(
title = "Track Queued",
description = f"**{track['name']}** by **{track['artists'][0]['name']}**\n\nQueued by: {interaction.user.mention}",
color=BOT_COLOR
)
embed.set_thumbnail(url=track['album']['images'][0]['url'])
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
track_ = await CustomSource.load_item(self, interaction.user, track)
player.add(requester=interaction.user, track=track_.tracks[0])
if 'open.spotify.com/artists' in query:
return await interaction.response.send_message("Sorry, I can't play artists. You must provide a song/album/playlist.", ephemeral=True)
if 'open.spotify.com' in query:
if not player.is_playing:
await player.play()
return
# Now begins the soundcloud section, this can be just like the youtube section
if not url_rx.match(query):
query = f'ytsearch:{query}'
results = await player.node.get_tracks(query)
# Below is for YouTube search, which is the default and is used when no link is provided
if not url_rx.match(query) and not results or not results['tracks']:
query = f'scsearch:{query}'
results = await player.node.get_tracks(query)
if not results or not results['tracks']:
return await interaction.response.send_message('Nothing found!', ephemeral=True)
embed = discord.Embed(color=BOT_COLOR)
if results['loadType'] == 'PLAYLIST_LOADED':
tracks = results['tracks']
for track in tracks:
track_ = lavalink.AudioTrack(track, interaction.user.id, extra=f"https://img.youtube.com/vi/{track['info']['identifier']}/hqdefault.jpg")
player.add(requester=interaction.user, track=track_)
embed.title = 'Playlist Queued!'
embed.description = f"**{results['playlistInfo']['name']}**\n` {len(tracks)} ` tracks\n\nQueued by: {interaction.user.mention}"
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
else:
track = results['tracks'][0]
embed.title = 'Track Queued'
embed.description = f"**{track['info']['title']}** by **{track['info']['author']}**\n\nQueued by: {interaction.user.mention}"
embed.set_thumbnail(url=f"https://img.youtube.com/vi/{track['info']['identifier']}/hqdefault.jpg")
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
track_ = lavalink.AudioTrack(track, interaction.user.id, recommended=True, extra=f"https://img.youtube.com/vi/{track['info']['identifier']}/hqdefault.jpg")
player.add(requester=interaction.user, track=track_)
await interaction.response.send_message(embed=embed)
# We don't want to call .play() if the player is playing as that will
# effectively skip the current track
if not player.is_playing:
await player.play()
@app_commands.command()
async def stop(
self,
interaction: discord.Interaction
):
"Disconnects the bot from the voice channel and clears the queue"
await self.ensure_before(interaction)
player = self.lavalink.player_manager.get(interaction.guild.id)
if not player.is_connected:
embed = discord.Embed(
title="No Channel",
description="I am not currently connected to any voice channel.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed, ephemeral=True)
player.queue.clear()
await player.stop()
player.shuffle = not player.shuffle if player.shuffle else player.shuffle
guild = interaction.guild
await guild.voice_client.disconnect(force=True)
embed = discord.Embed(
title="Queue Cleared and Music Stopped",
description=f"Thank you for using Aqua Bot :wave:\n\nIssued by: {interaction.user.mention}",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.command()
async def clear(
self,
interaction: discord.Interaction
):
"Clear the current queue of songs"
await self.ensure_before(interaction)
player = self.lavalink.player_manager.get(interaction.guild.id)
if not player.is_connected:
embed = discord.Embed(
title="No Channel",
description="I am not currently connected to any voice channel.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed, ephemeral=True)
player.queue.clear()
embed = discord.Embed(
title="Queue Cleared",
description = f"The queue has been cleared of all songs!\n\nIssued by: {interaction.user.mention}",
color=0x0088a9
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.command()
async def skip(
self,
interaction: discord.Interaction
):
"Skips the song that is currently playing"
await self.ensure_before(interaction)
player = self.lavalink.player_manager.get(interaction.guild.id)
if not player.is_playing:
embed = discord.Embed(
title="Nothing Playing",
description="Nothing is currently playing, so I can't skip anything.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed, ephemeral=True)
await player.skip()
if not player.is_playing:
embed = discord.Embed(
title="Track Skipped",
description=f"The queue is now empty, so I have left the voice channel. Thank you for using Aqua Bot.\n\nIssued by: {interaction.user.mention}",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed)
embed = discord.Embed(
title="Track Skipped",
description = f"**Now Playing: [{player.current.title}]({player.current.uri})**\n\nQueued by: {player.current.requester.mention}",
color=BOT_COLOR
)
embed.set_thumbnail(url=player.current.extra['extra'])
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.command()
async def pause(
self,
interaction: discord.Interaction
):
"Pauses the song that is currently playing"
await self.ensure_before(interaction)
player = self.lavalink.player_manager.get(interaction.guild.id)
if not player.is_playing:
embed = discord.Embed(
title="Nothing Playing",
description="Nothing is currently playing, so I can't pause anything.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed, ephemeral=True)
await player.set_pause(pause=True)
embed = discord.Embed(
title = f"Music Now Paused ⏸️",
description = f"**[{player.current.title}]({player.current.uri})**\n\nQueued by: {player.current.requester.mention}",
color=BOT_COLOR
)
embed.set_thumbnail(url=player.current.extra['extra'])
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.command()
async def resume(
self,
interaction: discord.Interaction
):
"Resumes the paused song"
await self.ensure_before(interaction)
player = self.lavalink.player_manager.get(interaction.guild.id)
if not player.is_playing:
embed = discord.Embed(
title="Nothing Paused",
description="Nothing is currently paused, so I can't resume anything.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed, ephemeral=True)
await player.set_pause(pause=False)
embed = discord.Embed(
title=f"Music Now Resumed ⏯️",
description=f"**[{player.current.title}]({player.current.uri})**\n\nQueued by: {player.current.requester.mention}",
color=BOT_COLOR
)
embed.set_thumbnail(url=player.current.extra['extra'])
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.command()
@app_commands.describe(page="Queue page number - leave blank if you are unsure")
async def queue(
self,
interaction: discord.Interaction,
page: int = 1
):
"See the current queue of songs"
await self.ensure_before(interaction)
player = self.lavalink.player_manager.get(interaction.guild.id)
if not player.queue:
embed = discord.Embed(
title="Nothing Queued",
description="Nothing is currently in the queue, add a song with the `/play` command.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed, ephemeral=True)
items_per_page = 10
pages = math.ceil(len(player.queue) / items_per_page)
start = (page - 1) * items_per_page
end = start + items_per_page
queue_list = ''
for index, track in enumerate(player.queue[start:end], start=start):
# Change ms duration to hour, min, sec in the format of 00:00:00
track_duration = lavalink.utils.format_time(track.duration)
# If the track is less than an hour, remove the hour from the duration
if track_duration.split(':')[0] == '00':
track_duration = track_duration[3:]
queue_list += f"`{index+1}. ` [{track.title}]({track.uri}) - {track.author} `({track_duration})`\n"
embed = discord.Embed(
title=f"Queue for {interaction.guild.name}",
description=f'**{len(player.queue)} tracks total**\n\n{queue_list}',
color=BOT_COLOR
)
embed.set_footer(text=f'Viewing page {page}/{pages}')
await interaction.response.send_message(embed=embed)
@app_commands.command()
async def np(
self,
interaction: discord.Interaction
):
"Show what song is currently playing"
await self.ensure_before(interaction)
player = self.lavalink.player_manager.get(interaction.guild.id)
if not player.is_playing:
embed = discord.Embed(
title="Nothing Playing",
description="Nothing is currently playing, play a song with the `/play` command.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed, ephemeral=True)
time_in = str(datetime.timedelta(milliseconds=player.position))[:-7]
total_duration = lavalink.utils.format_time(player.current.duration)
# If total_duration has no hours, then remove the hour part from both times
if total_duration.split(":")[0] == "00":
time_in = time_in[2:]
total_duration = total_duration[3:]
embed= discord.Embed(
title="Now Playing 🎶",
description=f"**[{player.current.title}]({player.current.uri})**\n{f'` {time_in}/{total_duration} `'}\n\nQueued by: {player.current.requester.mention}",
color=BOT_COLOR
)
embed.set_thumbnail(url=player.current.extra['extra'])
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.command()
@app_commands.describe(number='Song number to have removed')
async def remove(
self,
interaction: discord.Interaction,
number: int
):
"Removes the specified song from the queue"
await self.ensure_before(interaction)
player = self.lavalink.player_manager.get(interaction.guild.id)
if not player.queue:
embed = discord.Embed(
title="Nothing Queued",
description="Nothing is currently in the queue, so there is nothing for me to remove.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed)
if number > len(player.queue) or number < 1:
return await interaction.response.send_message('The number entered is not a number within the queue - please try again!', ephemeral=True)
index = number - 1
removed_title = player.queue[index].title
removed_url = player.queue[index].uri
player.queue.pop(index)
embed = discord.Embed(
title="Song Removed from Queue",
description=f"**Song Removed - [{removed_title}]({removed_url})**\n\nIssued by: {interaction.user.mention}",
color=BOT_COLOR
)
embed.set_thumbnail(url=player.current.extra['extra'])
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.command()
async def shuffle(
self,
interaction: discord.Interaction
):
"Plays the songs in the queue in a randomized order, until turned off"
await self.ensure_before(interaction)
player = self.lavalink.player_manager.get(interaction.guild.id)
if not player.is_playing:
embed = discord.Embed(
title="Nothing Playing",
description="Nothing is currently playing, therefore I cannot shuffle the music.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed, ephemeral=True)
player.shuffle = not player.shuffle
embed = discord.Embed(
title=f"{'Shuffle Enabled 🔀' if player.shuffle else 'Shuffle Disabled 🔀'}",
description=f"{'All music will now be shuffled.' if player.shuffle else 'Music will no longer be shuffled.'}",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
async def setup(bot):
await bot.add_cog(Music(bot))

282
code/cogs/mute.py Normal file
View File

@ -0,0 +1,282 @@
import discord
from discord.ext import commands, tasks
import datetime
from discord import app_commands
from global_variables import CONNECTION, BOT_COLOR
class Mute(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
def cog_load(self):
self.mute_check.start()
@tasks.loop(seconds=60)
async def mute_check(self):
cur = CONNECTION.cursor()
cur.execute("SELECT * FROM tempmute WHERE time < %s", (datetime.datetime.now(),))
data = cur.fetchall()
for row in data:
try:
guild_id = row[0]
user_id = row[1]
role_id = row[2]
guild = await self.bot.fetch_guild(guild_id)
user = await guild.fetch_member(user_id)
role = guild.get_role(role_id)
await user.remove_roles(role)
cur.execute("DELETE FROM tempmute WHERE guild_id = %s AND user_id = %s", (guild_id, user_id))
CONNECTION.commit()
except:
pass
@app_commands.default_permissions(manage_roles=True)
@app_commands.command()
@app_commands.checks.has_permissions(manage_roles=True)
@app_commands.describe(role_name='Name of your servers muted role')
async def setmute(
self,
interaction: discord.Interaction,
role_name: discord.Role
):
"Set the role for users to be given when muted"
guild_id = interaction.user.guild.id
role = role_name
role_id = role.id
cur = CONNECTION.cursor()
cur.execute("SELECT role_id FROM mute WHERE guild_id = %s", (guild_id,))
role_id = cur.fetchone()
if role_id != None:
cur.execute("UPDATE mute SET role_id = %s WHERE guild_id = %s", (role.id, guild_id))
CONNECTION.commit()
else:
cur.execute("INSERT INTO mute (role_id, guild_id) VALUES(%s, %s)", (role.id, guild_id))
CONNECTION.commit()
embed = discord.Embed(
title = "Mute Role Set",
description = f"The mute role for {interaction.guild.name} has been set to: <@&{role.id}>",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.default_permissions(manage_roles=True)
@app_commands.command()
@app_commands.checks.has_permissions(manage_roles=True)
async def delmute(
self,
interaction: discord.Interaction
):
"Delete the role set to be given to muted users"
guild_id = interaction.user.guild.id
cur = CONNECTION.cursor()
cur.execute("SELECT role_id FROM mute WHERE guild_id = %s", (guild_id,))
data = cur.fetchone()
if data:
cur.execute("DELETE FROM mute WHERE guild_id = %s", (guild_id,))
CONNECTION.commit()
embed = discord.Embed(
title = "Mute Role Deleted",
description = f"The mute role for {interaction.user.guild.name} has been deleted from my database.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
else:
embed = discord.Embed(
title = "Mute Role Not Set",
description = f"The mute role is not set, therefore there is no role I can delete.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed, ephemeral=True)
@app_commands.default_permissions(manage_roles=True)
@app_commands.command()
@app_commands.checks.has_permissions(manage_roles=True)
async def muterole(
self,
interaction: discord.Interaction
):
"See the current role set for when users are muted"
guild_id = interaction.user.guild.id
cur = CONNECTION.cursor()
cur.execute("SELECT role_id FROM mute WHERE guild_id = %s", (guild_id,))
data = cur.fetchone()
if data:
role = interaction.guild.get_role(data[0])
if role:
embed = discord.Embed(
title=f"Mute Role for {interaction.user.guild.name}",
description=f"The role given to members who are muted in this server is: <@&{role.id}>",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed)
else:
embed = discord.Embed(
title="Mute Role Not Found",
description=f"You have previously set a mute role, but it seems that the role you set has since been deleted. Please add a new mute role with the `/setmute` command.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
return await interaction.response.send_message(embed=embed)
else:
embed = discord.Embed(
title = "No Role Set",
description = f"It seems you haven't set a muted role yet. Please go do that with `/setmute` before running this command.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed, ephemeral=True)
@app_commands.default_permissions(manage_roles=True)
@app_commands.command()
@app_commands.checks.has_permissions(manage_roles=True)
@app_commands.describe(member='Name of the member you want to temporarily mute')
@app_commands.describe(time='Amount of time (in hours) to mute the member')
async def tempmute(
self,
interaction: discord.Interaction,
member: discord.Member,
time: app_commands.Range[int, 1, None]
):
"Mute a user for a specified amount of time"
try:
guild_id = interaction.user.guild.id
cur = CONNECTION.cursor()
cur.execute("SELECT role_id FROM mute WHERE guild_id = %s", (guild_id,))
data = cur.fetchone()
role_id = data[0]
role_name = interaction.user.guild.get_role(role_id)
role = discord.utils.get(interaction.user.guild.roles, name=f"{role_name}")
await member.add_roles(role)
embed = discord.Embed(
title=f"Temporarily Muted {member}",
description=f"{interaction.user.mention} has temporarily muted {member.mention} for {time} hours.",
color=discord.Color.orange()
)
embed.set_thumbnail(url=member.avatar.url)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
cur = CONNECTION.cursor()
cur.execute("INSERT INTO tempmute (guild_id, user_id, role_id, time) VALUES (%s, %s, %s, %s)", (guild_id, member.id, role.id, (datetime.datetime.now() + datetime.timedelta(hours=time))))
CONNECTION.commit()
except TypeError:
embed = discord.Embed(
title = "No Role Set",
description = f"It seems you haven't set a muted role yet. Please go do that with `/setmute` before running this command.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed, ephemeral=True)
@app_commands.default_permissions(manage_roles=True)
@app_commands.command()
@app_commands.checks.has_permissions(manage_roles=True)
@app_commands.describe(member='Name of the member you want to mute')
@app_commands.describe(reason='Reason for muting the member')
async def mute(
self,
interaction: discord.Interaction,
member: discord.Member,
reason: str
):
"Mutes a user for an indefinite amount of time"
try:
guild_id = interaction.user.guild.id
cur = CONNECTION.cursor()
cur.execute("SELECT role_id FROM mute WHERE guild_id = %s", (guild_id,))
data = cur.fetchone()
role_id = data[0]
role_name = interaction.user.guild.get_role(role_id)
role = discord.utils.get(interaction.user.guild.roles, name=f"{role_name}")
await member.add_roles(role)
embed = discord.Embed(
title=f"Muted {member}",
description=f"{interaction.user.mention} has successfully muted {member.mention} for `\"{reason}\"`.",
color=discord.Color.red()
)
embed.set_thumbnail(url=member.avatar.url)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
except TypeError or AttributeError:
embed = discord.Embed(
title = "No Role Set",
description = f"It seems you haven't set a muted role yet. Please go do that with `/setmute` before running this command.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed, ephemeral=True)
@app_commands.default_permissions(manage_roles=True)
@app_commands.command()
@app_commands.checks.has_permissions(manage_roles=True)
@app_commands.describe(member='Name of the member you want to unmute')
async def unmute(
self,
interaction: discord.Interaction,
member: discord.Member
):
"Unmute a specified member"
try:
guild_id = interaction.user.guild.id
cur = CONNECTION.cursor()
cur.execute("SELECT role_id FROM mute WHERE guild_id = %s", (guild_id,))
data = cur.fetchone()
role_id = data[0]
role_name = interaction.user.guild.get_role(role_id)
role = discord.utils.get(interaction.user.guild.roles, name=f"{role_name}")
if role in member.roles:
await member.remove_roles(role)
embed = discord.Embed(
title=f"Unmuted {member}",
description=f"{interaction.user.mention} has successfully unmuted {member.mention}.",
color=discord.Color.green()
)
embed.set_thumbnail(url=member.avatar.url)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
else:
embed = discord.Embed(
title="User Isn't Muted",
description=f"{member.mention} isn't muted, therefore I cannot unmute them. Maybe you meant to mute them with the `mute` command?",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed, ephemeral=True)
except TypeError or AttributeError:
embed = discord.Embed(
title="No Role Set",
description=f"It seems you haven't set a muted role yet. Please go do that with `/setmute` before running this command.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed, ephemeral=True)
async def setup(bot):
await bot.add_cog(Mute(bot))

View File

@ -0,0 +1,52 @@
from discord.ext import commands
import discord
import aiosqlite
from global_variables import BOT_COLOR
class UserCount(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.command()
@commands.dm_only()
@commands.is_owner()
async def info(self, ctx: commands.Context):
total_guilds = {}
for guild in self.bot.guilds:
total_guilds[guild.name] = guild.member_count
# Sort the dictionary by value descending
total_guilds = dict(sorted(total_guilds.items(), key=lambda item: item[1], reverse=True))
total_members = 0
for guild in total_guilds:
total_members += total_guilds[guild]
cur = await aiosqlite.connect("./code/count/count.db")
count = await cur.execute("SELECT count FROM count")
count = await count.fetchone()
await cur.close()
if count is None:
count = 0
else:
count = count[0]
embed = discord.Embed(
title="User Count",
description=f"Total Members: `{total_members:,}`\nTotal Guilds: `{len(self.bot.guilds):,}`\nTotal Commands Run: `{count:,}`",
color=BOT_COLOR
)
# Add the top 5 guilds to the embed
for guild in list(total_guilds)[:5]:
embed.add_field(name=guild, value=f"```{total_guilds[guild]:,}```", inline=False)
await ctx.send(embed=embed)
async def setup(bot):
await bot.add_cog(UserCount(bot))

691
code/cogs/profile.py Normal file
View File

@ -0,0 +1,691 @@
import discord
import datetime
from discord.ext import commands
import psycopg2
from discord import app_commands
from global_variables import CONNECTION, BOT_COLOR
from bot import InsufficientFundsException
from database import Database
class Economy:
def __init__(self, bot):
self.bot = bot
self.economy = Database(bot)
async def check_bet(
self,
user_id,
bet,
):
bet = int(bet)
if bet <= 0:
raise commands.errors.BadArgument()
current = (await self.economy.get_entry(user_id))[1]
if bet > current:
raise InsufficientFundsException()
#BEGIN CODE FOR RANK PURCHASING
class AfterRankPurchase(discord.ui.View):
def __init__(self, bot, *, timeout = 180.0):
super().__init__(timeout=timeout)
self.bot = bot
self.economy = Database(bot)
self.value = None
@discord.ui.button(label='Main Page', style=discord.ButtonStyle.blurple, row=2)
async def main_page(self, interaction: discord.Interaction, button: discord.ui.Button):
user_id = interaction.user.id
profile = await self.economy.get_entry(user_id)
balance = profile[1]
cur = CONNECTION.cursor()
cur.execute("SELECT rank_name FROM profile WHERE user_id = %s ORDER BY rank_int DESC", (user_id,))
data = cur.fetchall()
if data:
names = ', '.join([str(i[0]) for i in data])
else:
names = "No ranks"
embed = discord.Embed(
title="Shop",
description=f"Choose from one of the categories below in order to shop for items \n\nBalance: **${balance:,}** \n\nRanks: **{names}**",
color=BOT_COLOR
)
view = ShopView(self.bot)
await interaction.response.edit_message(embed=embed, view=view)
class ConfirmRankPurchase(discord.ui.View):
def __init__(self, bot, bet, rank_value, rank_name, *, timeout = 180.0):
super().__init__(timeout=timeout)
self.bot = bot
self.bet = bet
self.rank_int = int(rank_value)
self.rank_name = str(rank_name)
self.check = Economy(bot)
self.economy = Database(bot)
self.add_item(RankDropdown(bot))
@discord.ui.button(label='Yes', style=discord.ButtonStyle.green, row=2)
async def yes(self, interaction: discord.Interaction, button: discord.ui.Button):
user_id = interaction.user.id
cur = CONNECTION.cursor()
try:
await self.check.check_bet(user_id, self.bet)
cur.execute("INSERT INTO profile (user_id, rank_name, rank_int) VALUES(%s,%s,%s)", (user_id, self.rank_name, self.rank_int))
CONNECTION.commit()
await self.economy.add_money(user_id, self.bet*-1)
embed = discord.Embed(
title="Purchase Successful",
description=f"Your purchase was successful. In order to purchase more items, please click the main page button below.",
color=BOT_COLOR
)
view = AfterRankPurchase(self.bot)
await interaction.response.edit_message(embed=embed, view=view)
except psycopg2.errors.UniqueViolation:
embed = discord.Embed(
title="Rank Already Owned",
description=f"You already have that rank and therefore cannot buy it again. Try purchasing another rank.",
color=BOT_COLOR
)
view = RankView(self.bot)
return await interaction.response.edit_message(embed=embed, view=view)
except InsufficientFundsException:
embed = discord.Embed(
title="Not Enough Money",
description=f"You do not have enough money to make that purchase, come back once you've earned some more money.",
color=BOT_COLOR
)
view = RankView(self.bot)
return await interaction.response.edit_message(embed=embed, view=view)
@discord.ui.button(label='No', style=discord.ButtonStyle.red, row=2)
async def no(self, interaction: discord.Interaction, button: discord.ui.Button):
embed = discord.Embed(
title="Purchase Cancelled, Taken Back to Shop",
description=f"Choose from one of the categories below in order to shop for items.",
color=BOT_COLOR
)
view = ShopView(self.bot)
await interaction.response.edit_message(embed=embed, view=view)
class RankDropdown(discord.ui.Select):
def __init__(self, bot):
self.bot = bot
options = [
discord.SelectOption(label='Copper III', description="100,000", emoji = "<:copper_3:908535582534299688>"),
discord.SelectOption(label='Copper II', description="200,000", emoji = "<:copper_2:908535594714558524>"),
discord.SelectOption(label='Copper I', description="300,000", emoji = "<:copper_1:908535605644918895>"),
discord.SelectOption(label='Bronze III', description="100,000,000", emoji = "<:bronze_3:908535616650760222>"),
discord.SelectOption(label='Bronze II', description="200,000,000", emoji = "<:bronze_2:908535628503863296>"),
discord.SelectOption(label='Bronze I', description="300,000,000", emoji = "<:bronze_1:908535639606198292>"),
discord.SelectOption(label='Silver III', description="100,000,000,000", emoji = "<:silver_3:908535654667911168>"),
discord.SelectOption(label='Silver II', description="200,000,000,000", emoji = "<:silver_2:908535667263434782>"),
discord.SelectOption(label='Silver I', description="300,000,000,000", emoji = "<:silver_1:908535680064442398>"),
discord.SelectOption(label='Gold III', description="100,000,000,000,000", emoji = "<:gold_3:908535691137388554>"),
discord.SelectOption(label='Gold II', description="200,000,000,000,000", emoji = "<:gold_2:908535705154764870>"),
discord.SelectOption(label='Gold I', description="300,000,000,000,000", emoji = "<:gold_1:908535742224027758>"),
discord.SelectOption(label='Platinum III', description="100,000,000,000,000,000", emoji = "<:platinum_3:908535751900282880>"),
discord.SelectOption(label='Platinum II', description="200,000,000,000,000,000", emoji = "<:platinum_2:908535764629999656>"),
discord.SelectOption(label='Platinum I', description="300,000,000,000,000,000", emoji = "<:platinum_1:908535773689679932>"),
discord.SelectOption(label='Diamond', description="123,456,789,000,000,000,000", emoji = "<:diamond:908535791700037702>"),
discord.SelectOption(label='Champion', description="999,999,999,999,999,999,999,999,999", emoji = "<:champion:908535801338540042>"),
]
super().__init__(placeholder='Choose a rank...', min_values=1, max_values=1, options=options)
async def callback(self, interaction: discord.Interaction):
if self.values[0] == 'Copper III':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Copper III` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 1
rank_name = 'Copper III'
bet = 100000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Copper II':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Copper II` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 2
rank_name = 'Copper II'
bet = 200000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Copper I':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Copper I` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 3
rank_name = 'Copper I'
bet = 300000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Bronze III':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Bronze III` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 4
rank_name = 'Bronze III'
bet = 100000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Bronze II':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Bronze II` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 5
rank_name = 'Bronze II'
bet = 200000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Bronze I':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Bronze I` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 6
rank_name = 'Bronze I'
bet = 300000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Silver III':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Silver III` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 7
rank_name = 'Silver III'
bet = 100000000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Silver II':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Silver II` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 8
rank_name = 'Silver II'
bet = 200000000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Silver I':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Silver I` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 9
rank_name = 'Silver I'
bet = 300000000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Gold III':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Gold III` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 10
rank_name = 'Gold III'
bet = 100000000000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Gold II':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Gold II` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 11
rank_name = 'Gold II'
bet = 200000000000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Gold I':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Gold I` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 12
rank_name = 'Gold I'
bet = 300000000000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Platinum III':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Platinum III` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 13
rank_name = 'Platinum III'
bet = 100000000000000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Platinum II':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Platinum II` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 14
rank_name = 'Platinum II'
bet = 200000000000000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Platinum I':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Platinum I` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 15
rank_name = 'Platinum I'
bet = 300000000000000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Diamond':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Diamond` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 16
rank_name = 'Diamond'
bet = 123456789000000000000
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
if self.values[0] == 'Champion':
embed = discord.Embed(
title="Please Confirm Your Purchase",
description="If you are sure you would like to purchase the `Champion` rank, please click the 'Yes' button below, otherwise click the 'No' button.",
color=BOT_COLOR
)
rank_value = 17
rank_name = 'Champion'
bet = 999999999999999999999999999
view = ConfirmRankPurchase(self.bot, bet, rank_value, rank_name)
await interaction.response.edit_message(embed=embed, view=view)
class RankView(discord.ui.View):
def __init__(self, bot, *, timeout = 180.0):
super().__init__(timeout=timeout)
self.bot = bot
self.economy = Database(bot)
self.add_item(RankDropdown(bot))
@discord.ui.button(label='Main Page', style=discord.ButtonStyle.blurple, row=2)
async def main_page(self, interaction: discord.Interaction, button: discord.ui.Button):
user_id = interaction.user.id
profile = await self.economy.get_entry(user_id)
balance = profile[1]
cur = CONNECTION.cursor()
cur.execute("SELECT rank_name FROM profile WHERE user_id = %s ORDER BY rank_int DESC", (user_id,))
data = cur.fetchall()
if data:
names = ', '.join([str(i[0]) for i in data])
else:
names = "No ranks"
embed = discord.Embed(
title="Shop",
description=f"Choose from one of the categories below in order to shop for items \n\nBalance: **${balance:,}** \n\nRanks: **{names}**",
color=BOT_COLOR
)
view = ShopView(self.bot)
await interaction.response.edit_message(embed=embed, view=view)
##END RANK AND BEGIN PROFILE AND OTHER MAIN SHOP VIEWING
class ShopDropdown(discord.ui.Select):
def __init__(self, bot):
self.bot = bot
options = [
discord.SelectOption(label='Ranks', description='Buy ranks and show off your wealth'),
]
super().__init__(placeholder='Choose a category...', min_values=1, max_values=1, options=options)
async def callback(self, interaction: discord.Interaction):
user_id = interaction.user.id
cur = CONNECTION.cursor()
cur.execute("SELECT rank_name FROM profile WHERE user_id = %s ORDER BY rank_int DESC", (user_id,))
data = cur.fetchall()
if data:
names = ([str(i[0]) for i in data])
if "Copper III" in names:
copper_iii = "~~Copper III~~ - OWNED"
else:
copper_iii = "Copper III"
if "Copper II" in names:
copper_ii = "~~Copper II~~ - OWNED"
else:
copper_ii = "Copper II"
if "Copper I" in names:
copper_i = "~~Copper I~~ - OWNED"
else:
copper_i = "Copper I"
if "Bronze III" in names:
bronze_iii = "~~Bronze III~~ - OWNED"
else:
bronze_iii = "Bronze III"
if "Bronze II" in names:
bronze_ii = "~~Bronze II~~ - OWNED"
else:
bronze_ii = "Bronze II"
if "Bronze I" in names:
bronze_i = "~~Bronze I~~ - OWNED"
else:
bronze_i = "Bronze I"
if "Silver III" in names:
silver_iii = "~~Silver III~~ - OWNED"
else:
silver_iii = "Silver III"
if "Silver II" in names:
silver_ii = "~~Silver II~~ - OWNED"
else:
silver_ii = "Silver II"
if "Silver I" in names:
silver_i = "~~Silver I~~ - OWNED"
else:
silver_i = "Silver I"
if "Gold III" in names:
gold_iii = "~~Gold III~~ - OWNED"
else:
gold_iii = "Gold III"
if "Gold II" in names:
gold_ii = "~~Gold II~~ - OWNED"
else:
gold_ii = "Gold II"
if "Gold I" in names:
gold_i = "~~Gold I~~ - OWNED"
else:
gold_i = "Gold I"
if "Platinum III" in names:
platinum_iii = "~~Platinum III~~ - OWNED"
else:
platinum_iii = "Platinum III"
if "Platinum II" in names:
platinum_ii = "~~Platinum II~~ - OWNED"
else:
platinum_ii = "Platinum II"
if "Platinum I" in names:
platinum_i = "~~Platinum I~~ - OWNED"
else:
platinum_i = "Platinum I"
if "Diamond" in names:
diamond = "~~Diamond~~ - OWNED"
else:
diamond = "Diamond"
if "Champion" in names:
champion = "~~Champion~~ - OWNED"
else:
champion = "Champion"
else:
copper_iii = "Copper III"
copper_ii = "Copper II"
copper_i = "Copper I"
bronze_iii = "Bronze III"
bronze_ii = "Bronze II"
bronze_i = "Bronze I"
silver_iii = "Silver III"
silver_ii = "Silver II"
silver_i = "Silver I"
gold_iii = "Gold III"
gold_ii = "Gold II"
gold_i = "Gold I"
platinum_iii = "Platinum III"
platinum_ii = "Platinum II"
platinum_i = "Platinum I"
diamond = "Diamond"
champion = "Champion"
if self.values[0] == 'Ranks':
embed = discord.Embed(
title="Ranks \nSpend your money in order to get more ranks.",
description="**Purchase a rank by clicking on one of the dropdown menus below, and then confirming your purchase.**",
color=BOT_COLOR
)
embed.add_field(name=f"{copper_iii}", value=f"```100,000```", inline=True)
embed.add_field(name=f"{copper_ii}", value=f"```200,000```", inline=True)
embed.add_field(name=f"{copper_i}", value=f"```300,000```", inline=True)
embed.add_field(name=f"{bronze_iii}", value=f"```100,000,000```", inline=True)
embed.add_field(name=f"{bronze_ii}", value=f"```200,000,000```", inline=True)
embed.add_field(name=f"{bronze_i}", value=f"```300,000,000```", inline=True)
embed.add_field(name=f"{silver_iii}", value=f"```100,000,000,000\n(100 bil.)```", inline=True)
embed.add_field(name=f"{silver_ii}", value=f"```200,000,000,000\n(200 bil.)```", inline=True)
embed.add_field(name=f"{silver_i}", value=f"```300,000,000,000\n(300 bil.)```", inline=True)
embed.add_field(name=f"{gold_iii}", value=f"```100,000,000,000,\n000 (100 tril.)```", inline=True)
embed.add_field(name=f"{gold_ii}", value=f"```200,000,000,000,\n000 (200 tril.)```", inline=True)
embed.add_field(name=f"{gold_i}", value=f"```300,000,000,000,\n000 (300 tril.)```", inline=True)
embed.add_field(name=f"{platinum_iii}", value=f"```100,000,000,000,000,000 (100 quad.)```", inline=True)
embed.add_field(name=f"{platinum_ii}", value=f"```200,000,000,000,000,000 (200 quad.)```", inline=True)
embed.add_field(name=f"{platinum_i}", value=f"```300,000,000,000,000,000 (300 quad.)```", inline=True)
embed.add_field(name=f"{diamond}", value=f"```123,456,789,000,000,000,000\n(<123 quint.)```", inline=True)
embed.add_field(name=f"{champion}", value=f"```999,999,999,999,999,999,999,\n999,999 (<999 sept.)```", inline=True)
view = RankView(self.bot)
await interaction.response.edit_message(embed=embed, view=view)
class ShopView(discord.ui.View):
def __init__(self, bot, *, timeout = 180.0):
super().__init__(timeout=timeout)
self.economy = Database(bot)
self.bot = bot
self.add_item(ShopDropdown(bot))
@discord.ui.button(label='Main Page', style=discord.ButtonStyle.blurple, row=2)
async def main_page(self, interaction: discord.Interaction, button: discord.ui.Button):
user_id = interaction.user.id
profile = await self.economy.get_entry(user_id)
balance = profile[1]
cur = CONNECTION.cursor()
cur.execute("SELECT rank_name FROM profile WHERE user_id = %s ORDER BY rank_int DESC", (user_id,))
data = cur.fetchall()
if data:
names = ', '.join([str(i[0]) for i in data])
else:
names = "No ranks"
embed = discord.Embed(
title="Shop",
description=f"Choose from one of the categories below in order to shop for items \n\nBalance: **${balance:,}** \n\nRanks: **{names}**",
color=BOT_COLOR
)
view = ShopView(self.bot)
await interaction.response.edit_message(embed=embed, view=view)
#BEGIN CODE FOR PROFILE VIEWING
class Profile(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.economy = Database(bot)
@app_commands.command()
@app_commands.describe(user='User whose profile you would like to view')
async def profile(
self,
interaction: discord.Interaction,
user: discord.Member
):
"Show the profile for the given user"
user_id = user.id if user else interaction.user.id
profile = await self.economy.get_entry(user_id)
balance = profile[1]
cur = CONNECTION.cursor()
cur.execute("SELECT rank_name FROM profile WHERE user_id = %s ORDER BY rank_int DESC", (user_id,))
data = cur.fetchall()
if data:
names = ', '.join([str(i[0]) for i in data])
else:
names = "No ranks"
embed = discord.Embed(
title=f"Profile For - {await self.bot.fetch_user(user_id)}",
description=f"Below will show all economy information for this user",
color=BOT_COLOR
)
embed.add_field(name="Money Balance:", value=f"${balance:,}", inline=False)
embed.add_field(name="Ranks:", value=f"{names}", inline=False)
embed.set_thumbnail(url = user.avatar.url)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.command()
async def shop(
self,
interaction: discord.Interaction
):
"Shows the shop so that you can buy items"
user_id = interaction.user.id
profile = await self.economy.get_entry(user_id)
balance = profile[1]
cur = CONNECTION.cursor()
cur.execute("SELECT rank_name FROM profile WHERE user_id = %s ORDER BY rank_int DESC", (user_id,))
data = cur.fetchall()
if data:
names = ', '.join([str(i[0]) for i in data])
else:
names = "No ranks"
embed = discord.Embed(
title="Shop",
description=f"Choose from one of the categories below in order to shop for items \n\nBalance: **${balance:,}** \n\nRanks: **{names}**",
color=BOT_COLOR
)
view = ShopView(self.bot)
await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
async def setup(bot):
await bot.add_cog(Profile(bot))

81
code/cogs/slots.py Normal file
View File

@ -0,0 +1,81 @@
import os
import random
import datetime
import discord
from discord.ext import commands
from discord import app_commands
from bot import InsufficientFundsException
from database import Database
"""NOTE: The code to create the slot reels was found on GitHub a while ago, same person who
made the blackjack stuff (still don't know who it was). I ended up modifying it quite a lot with my own images, and changed
the code a bit so that I could have it generate the slot reels and put them in the correct folders
I premade the slot reels as it uses less resources to just load them from the folder than to
generate them every time someone uses the command."""
class Slots(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.economy = Database(bot)
async def check_bet(
self,
interaction: discord.Interaction,
bet
):
bet = int(bet)
if bet <= 0:
raise commands.errors.BadArgument()
current = (await self.economy.get_entry(interaction.user.id))[1]
if bet > current:
raise InsufficientFundsException()
@app_commands.command()
@app_commands.checks.cooldown(1, 4)
@app_commands.describe(bet='Amount of money to bet')
async def slots(
self,
interaction: discord.Interaction,
bet: app_commands.Range[int, 1, None]
):
"Bet a specified amount of money on the slot machines"
await self.check_bet(interaction, bet)
win_rate = 5/100
multiplier_dict = {"seven": 80, "diamond": 40, "bar": 25, "clover": 10, "grape": 5, "lemon": 4}
if random.random() < win_rate:
# Pick a random word
word = random.choice(["seven", "diamond", "bar", "clover", "grape", "lemon"])
multiplier = multiplier_dict[word]
# Pick one of the 10 images of the winning reel type (seven, diamond, etc.)
image_path = f"code/utils/winning_reels/{word}_{random.randint(1, 10)}.gif"
amount = bet * multiplier
else:
# Pick a random number 1-5, this will decide which losing folder we pick a reel from
folder = f"code/utils/losing_reels_{random.randint(1, 5)}"
# Pick a random image from the folder
image_path = f"{folder}/{random.choice(os.listdir(folder))}"
amount = bet * -1
await self.economy.add_money(interaction.user.id, amount)
current = (await self.economy.get_entry(interaction.user.id))[1]
file = discord.File(image_path, "slot_machine.gif")
embed = discord.Embed(
title=f"You {'won' if amount > 0 else 'lost'} {abs(amount):,} {'dollar' if abs(amount) == 1 else 'dollars'}!",
description=f"You now have {current:,} {'dollar' if current == 1 else 'dollars'}",
color=discord.Color.green() if amount > 0 else discord.Color.red()
)
embed.set_image(url="attachment://slot_machine.gif")
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed, file=file)
async def setup(bot: commands.Bot):
await bot.add_cog(Slots(bot))

35
code/cogs/socketfix.py Normal file
View File

@ -0,0 +1,35 @@
import zlib
import discord
from discord.ext import commands
class SocketFix(commands.Cog):
def __init__(self, bot):
self.bot = bot
self._zlib = zlib.decompressobj()
self._buffer = bytearray()
@commands.Cog.listener()
async def on_socket_raw_receive(self, msg):
if type(msg) is bytes:
self._buffer.extend(msg)
if len(msg) < 4 or msg[-4:] != b'\x00\x00\xff\xff':
return
try:
msg = self._zlib.decompress(self._buffer)
except Exception:
self._buffer = bytearray() # Reset buffer on fail just in case...
return
msg = msg.decode('utf-8')
self._buffer = bytearray()
msg = discord.utils._from_json(msg)
self.bot.dispatch('on_socket_response', msg)
async def setup(bot):
await bot.add_cog(SocketFix(bot))

33
code/cogs/tree_sync.py Normal file
View File

@ -0,0 +1,33 @@
from discord.ext import commands
from discord import Object
class TreeSync(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.command()
@commands.dm_only()
@commands.is_owner()
async def sync(self, ctx: commands.Context, *, guild: Object=None) -> None:
if not guild or guild == None:
await self.bot.tree.sync()
await ctx.author.send("Synced commands globally")
return
elif guild != None:
self.bot.tree.copy_global_to(guild=guild)
await self.bot.tree.sync(guild=guild)
await ctx.author.send(f"Synced the tree to 1 test guild.")
@sync.error
async def error_sync(self, ctx, error):
if isinstance(error, commands.errors.PrivateMessageOnly):
pass
else:
await ctx.author.send("That is not a valid guild ID")
async def setup(bot):
await bot.add_cog(TreeSync(bot))

121
code/cogs/warnings.py Normal file
View File

@ -0,0 +1,121 @@
import discord
from discord.ext import commands
import datetime
from discord import app_commands
from global_variables import CONNECTION, BOT_COLOR
class Warnings(commands.Cog):
def __init__(self, bot):
self.bot = bot
@app_commands.default_permissions(manage_messages=True)
@app_commands.command()
@app_commands.checks.has_permissions(manage_messages=True)
@app_commands.describe(member='The member you would like to warn')
@app_commands.describe(reason='Reason for warning the member')
async def warn(
self,
interaction: discord.Interaction,
member: discord.Member,
reason: str
):
"Warn a member for a given reason"
guild_id = interaction.user.guild.id
user_id = member.id
warn_id = interaction.id
warn_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
warned_by = interaction.user.id
cur = CONNECTION.cursor()
cur.execute("INSERT INTO warnings (warn_id, guild_id, user_id, warning, warn_time, warned_by) VALUES (%s, %s, %s, %s, %s, %s)", (warn_id, guild_id, user_id, reason, warn_time, warned_by))
CONNECTION.commit()
embed = discord.Embed(
title=f"`{member.name}#{member.discriminator}` Has Been Warned in {interaction.guild}",
description=f"Reason: {reason}",
color=discord.Color.orange()
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.default_permissions(manage_messages=True)
@app_commands.command()
@app_commands.checks.has_permissions(manage_messages=True)
@app_commands.describe(member='The member whose warnings you want to see')
async def warnings(
self,
interaction: discord.Interaction,
member: discord.Member
):
"Show all warnings for a given user"
guild_id = interaction.user.guild.id
user_id = member.id
cur = CONNECTION.cursor()
cur.execute("SELECT * FROM warnings WHERE guild_id = %s AND user_id = %s", (guild_id, user_id))
data = cur.fetchall()
if data:
embed=discord.Embed(
title=f"Warnings for `{member.name}#{member.discriminator}` in {interaction.guild}",
description="",
color=discord.Color.orange()
)
for entry in data:
embed.description += f"**Reason - `\"{entry[3]}\"` | ID: `{entry[0]}`**\nWarned By: <@{entry[5]}> | Date: {entry[4]}\n\n"
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
else:
embed = discord.Embed(
title="No Warnings",
description=f"{member.mention} has not been warned in the past, or all of their warnings have been deleted.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
@app_commands.default_permissions(manage_messages=True)
@app_commands.command()
@app_commands.checks.has_permissions(manage_messages=True)
@app_commands.describe(id='ID of the warning you would like to delete')
async def delwarn(
self,
interaction: discord.Interaction,
id: str
):
"Delete a warning from a user with the warning ID"
cur = CONNECTION.cursor()
cur.execute("SELECT warn_id FROM warnings WHERE warn_id = %s", (id,))
data = cur.fetchone()
if data:
cur.execute("DELETE FROM warnings WHERE warn_id = %s", (id,))
CONNECTION.commit()
embed = discord.Embed(
title="Warning Deleted",
description=f"{interaction.user.mention} has deleted the warning identified by `{id}` .",
color=discord.Color.orange()
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed)
else:
embed = discord.Embed(
title="Invalid ID",
description="That ID is not associated with any warnings in this server.",
color=BOT_COLOR
)
embed.set_footer(text=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')+" UTC")
await interaction.response.send_message(embed=embed, ephemeral=True)
async def setup(bot):
await bot.add_cog(Warnings(bot))

0
code/count/PLACEHOLDER Normal file
View File

74
code/custom_source.py Normal file
View File

@ -0,0 +1,74 @@
from lavalink import LoadResult, LoadType, Source, DeferredAudioTrack, PlaylistInfo
class LoadError(Exception): # We'll raise this if we have trouble loading our track.
pass
class CustomAudioTrack(DeferredAudioTrack):
# A DeferredAudioTrack allows us to load metadata now, and a playback URL later.
# This makes the DeferredAudioTrack highly efficient, particularly in cases
# where large playlists are loaded.
async def load(self, client): # Load our 'actual' playback track using the metadata from this one.
result: LoadResult = await client.get_tracks('ytsearch:{0.title} {0.author} audio'.format(self)) # Search for our track on YouTube.
if result.load_type != LoadType.SEARCH or not result.tracks: # We're expecting a 'SEARCH' due to our 'ytsearch' prefix above.
raise LoadError
first_track = result.tracks[0] # Grab the first track from the results.
base64 = first_track.track # Extract the base64 string from the track.
self.track = base64 # We'll store this for later, as it allows us to save making network requests
# if this track is re-used (e.g. repeat).
return base64
class CustomSource(Source):
def __init__(self):
super().__init__(name='custom') # Initialising our custom source with the name 'custom'.
async def load_item(self, user, metadata):
track = CustomAudioTrack({ # Create an instance of our CustomAudioTrack.
'identifier': metadata['id'], # Fill it with metadata that we've obtained from our source's provider.
'isSeekable': True,
'author': metadata['artists'][0]['name'],
'length': metadata['duration_ms'],
'isStream': False,
'title': metadata['name'],
'uri': metadata['external_urls']['spotify'],
'duration': metadata['duration_ms'],
}, requester=user, extra=metadata['album']['images'][0]['url'])
return LoadResult(LoadType.TRACK, [track], playlist_info=PlaylistInfo.none())
async def load_album(self, user, metadata):
tracks = []
for track in metadata['tracks']['items']: # Loop through each track in the album.
tracks.append(CustomAudioTrack({ # Create an instance of our CustomAudioTrack.
'identifier': track['id'], # Fill it with metadata that we've obtained from our source's provider.
'isSeekable': True,
'author': track['artists'][0]['name'],
'length': track['duration_ms'],
'isStream': False,
'title': track['name'],
'uri': track['external_urls']['spotify'],
'duration': track['duration_ms'],
}, requester=user, extra=metadata['images'][0]['url']))
return LoadResult(LoadType.PLAYLIST, tracks, playlist_info=PlaylistInfo.none())
async def load_playlist(self, user, metadata):
tracks = []
for track in metadata['tracks']['items']: # Loop through each track in the playlist.
tracks.append(CustomAudioTrack({ # Create an instance of our CustomAudioTrack.
'identifier': track['track']['id'], # Fill it with metadata that we've obtained from our source's provider.
'isSeekable': True,
'author': track['track']['artists'][0]['name'],
'length': track['track']['duration_ms'],
'isStream': False,
'title': track['track']['name'],
'uri': track['track']['external_urls']['spotify'],
'duration': track['track']['duration_ms'],
}, requster=user, extra=track['track']['album']['images'][0]['url']))
return LoadResult(LoadType.PLAYLIST, tracks, playlist_info=PlaylistInfo.none())

74
code/database.py Normal file
View File

@ -0,0 +1,74 @@
import aiosqlite
import random
from typing import Tuple, List
from global_variables import CONNECTION
async def init_database():
cur = CONNECTION.cursor()
cur.execute("CREATE TABLE IF NOT EXISTS guildData (guild_id BIGINT, user_id BIGINT, exp BIGINT, PRIMARY KEY (guild_id, user_id))")
cur.execute("CREATE TABLE IF NOT EXISTS mute (guild_id BIGINT, role_id BIGINT, PRIMARY KEY (guild_id, role_id))")
cur.execute("CREATE TABLE IF NOT EXISTS tempmute (guild_id BIGINT, user_id BIGINT, role_id BIGINT, time TIMESTAMP, PRIMARY KEY (guild_id, user_id))")
cur.execute("CREATE TABLE IF NOT EXISTS warnings (warn_id BIGINT, guild_id BIGINT, user_id BIGINT, warning TEXT, warn_time DATE, warned_by BIGINT, PRIMARY KEY (warn_id))")
cur.execute("CREATE TABLE IF NOT EXISTS economy (user_id BIGINT NOT NULL PRIMARY KEY, money BIGINT NOT NULL DEFAULT 0)")
cur.execute("CREATE TABLE IF NOT EXISTS profile (user_id BIGINT, rank_name TEXT, rank_int BIGINT, UNIQUE (user_id, rank_name, rank_int))")
CONNECTION.commit()
cur = await aiosqlite.connect("code/count/count.db")
await cur.execute("CREATE TABLE IF NOT EXISTS count (count INTEGER)")
await cur.commit()
await cur.close()
Entry = Tuple[int, int]
class Database:
def __init__(self, bot):
self.bot = bot
async def get_entry(self, user_id: int) -> Entry:
cur = CONNECTION.cursor()
cur.execute("SELECT * FROM economy WHERE user_id = %s", (user_id,))
result = cur.fetchone()
if result:
return result
return await self.new_entry(user_id)
async def new_entry(self, user_id: int) -> Entry:
try:
cur = CONNECTION.cursor()
cur.execute("INSERT INTO economy(user_id, money) VALUES(%s, %s)", (user_id, 0))
CONNECTION.commit()
return await self.get_entry(user_id)
except:
return await self.get_entry(user_id)
async def remove_entry(self, user_id: int) -> None:
cur = CONNECTION.cursor()
cur.execute("DELETE FROM economy WHERE user_id = %s", (user_id,))
CONNECTION.commit()
async def set_money(self, user_id: int, money: int) -> Entry:
cur = CONNECTION.cursor()
cur.execute("UPDATE economy SET money = %s WHERE user_id = %s", (money, user_id))
CONNECTION.commit()
return await self.get_entry(user_id)
async def add_money(self, user_id: int, money_to_add: int) -> Entry:
money = (await self.get_entry(user_id))[1]
total = money + money_to_add
if total < 0:
total = 0
await self.set_money(user_id, total)
return await self.get_entry(user_id)
async def random_entry(self) -> Entry:
cur = CONNECTION.cursor()
cur.execute("SELECT * FROM economy")
return random.choice(cur.fetchall())
async def top_entries(self, n: int=0) -> List[Entry]:
cur = CONNECTION.cursor()
cur.execute("SELECT * FROM economy ORDER BY money DESC")
return cur.fetchmany(n) if n else cur.fetchall()

49
code/global_variables.py Normal file
View File

@ -0,0 +1,49 @@
import configparser
import logging
from colorlog import ColoredFormatter
import psycopg2
import discord
log_level = logging.DEBUG
log_format = " %(log_color)s%(levelname)-8s%(reset)s | %(log_color)s%(message)s%(reset)s"
logging.root.setLevel(log_level)
formatter = ColoredFormatter(log_format)
stream = logging.StreamHandler()
stream.setLevel(log_level)
stream.setFormatter(formatter)
LOG = logging.getLogger('pythonConfig')
LOG.setLevel(log_level)
LOG.addHandler(stream)
with open('config.ini', 'r')as f:
file_contents = f.read()
config = configparser.ConfigParser()
config.read_string(file_contents)
BOT_TOKEN = config['BOT_INFO']['TOKEN']
BONUS_COOLDOWN = int(config['BOT_INFO']['BONUS_COOLDOWN'])
BOT_COLOR = discord.Color(int((config['BOT_INFO']['BOT_COLOR']).replace('#', ""), 16))
BUG_CHANNEL_ID = int(config['BOT_INFO']['BUG_CHANNEL_ID'])
FEEDBACK_CHANNEL_ID = int(config['BOT_INFO']['FEEDBACK_CHANNEL_ID'])
CRYPTO_COMPARE_API_KEY = config['CRYPTO_COMPARE']['API_KEY']
username = config['POSTGRESQL']['USERNAME']
password = config['POSTGRESQL']['PASSWORD']
host = config['POSTGRESQL']['HOST']
port = config['POSTGRESQL']['PORT']
database = config['POSTGRESQL']['DATABASE']
connection_string = f"postgresql://{username}:{password}@{host}:{port}/{database}"
CONNECTION = psycopg2.connect(connection_string)
LAVALINK_HOST = config['LAVALINK']['HOST']
LAVALINK_PORT = config['LAVALINK']['PORT']
LAVALINK_PASSWORD = config['LAVALINK']['PASSWORD']
SPOTIFY_CLIENT_ID = config['SPOTIFY']['CLIENT_ID']
SPOTIFY_CLIENT_SECRET = config['SPOTIFY']['CLIENT_SECRET']

View File

View File

BIN
code/utils/AquaBot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
code/utils/cards/10C.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
code/utils/cards/10D.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
code/utils/cards/10H.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
code/utils/cards/10S.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

BIN
code/utils/cards/2C.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
code/utils/cards/2D.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
code/utils/cards/2H.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
code/utils/cards/2S.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
code/utils/cards/3C.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
code/utils/cards/3D.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
code/utils/cards/3H.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
code/utils/cards/3S.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
code/utils/cards/4C.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
code/utils/cards/4D.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
code/utils/cards/4H.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
code/utils/cards/4S.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
code/utils/cards/5C.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
code/utils/cards/5D.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
code/utils/cards/5H.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
code/utils/cards/5S.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
code/utils/cards/6C.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
code/utils/cards/6D.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
code/utils/cards/6H.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
code/utils/cards/6S.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
code/utils/cards/7C.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
code/utils/cards/7D.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
code/utils/cards/7H.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
code/utils/cards/7S.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
code/utils/cards/8C.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
code/utils/cards/8D.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
code/utils/cards/8H.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
code/utils/cards/8S.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
code/utils/cards/9C.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
code/utils/cards/9D.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
code/utils/cards/9H.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
code/utils/cards/9S.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
code/utils/cards/AC.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
code/utils/cards/AD.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
code/utils/cards/AH.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
code/utils/cards/AS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
code/utils/cards/JC.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
code/utils/cards/JD.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
code/utils/cards/JH.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
code/utils/cards/JS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
code/utils/cards/KC.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
code/utils/cards/KD.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
code/utils/cards/KH.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
code/utils/cards/KS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
code/utils/cards/QC.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
code/utils/cards/QD.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
code/utils/cards/QH.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
code/utils/cards/QS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
code/utils/cards/aces.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
code/utils/covid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Some files were not shown because too many files have changed in this diff Show More