aboutsummaryrefslogtreecommitdiff
path: root/code/cogs
diff options
context:
space:
mode:
Diffstat (limited to 'code/cogs')
-rw-r--r--code/cogs/blackjack.py257
-rw-r--r--code/cogs/coinflip.py62
-rw-r--r--code/cogs/count.py40
-rw-r--r--code/cogs/covid.py68
-rw-r--r--code/cogs/crypto.py126
-rw-r--r--code/cogs/gambling_helpers.py139
-rw-r--r--code/cogs/handlers.py124
-rw-r--r--code/cogs/help.py158
-rw-r--r--code/cogs/info.py77
-rw-r--r--code/cogs/modals.py102
-rw-r--r--code/cogs/moderation.py96
-rw-r--r--code/cogs/music.py584
-rw-r--r--code/cogs/mute.py282
-rw-r--r--code/cogs/owner_info_commands.py52
-rw-r--r--code/cogs/profile.py691
-rw-r--r--code/cogs/slots.py81
-rw-r--r--code/cogs/socketfix.py35
-rw-r--r--code/cogs/tree_sync.py33
-rw-r--r--code/cogs/warnings.py121
19 files changed, 3128 insertions, 0 deletions
diff --git a/code/cogs/blackjack.py b/code/cogs/blackjack.py
new file mode 100644
index 0000000..3912993
--- /dev/null
+++ b/code/cogs/blackjack.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/coinflip.py b/code/cogs/coinflip.py
new file mode 100644
index 0000000..9771cbd
--- /dev/null
+++ b/code/cogs/coinflip.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/count.py b/code/cogs/count.py
new file mode 100644
index 0000000..67e0139
--- /dev/null
+++ b/code/cogs/count.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/covid.py b/code/cogs/covid.py
new file mode 100644
index 0000000..bc26432
--- /dev/null
+++ b/code/cogs/covid.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/crypto.py b/code/cogs/crypto.py
new file mode 100644
index 0000000..9ef8984
--- /dev/null
+++ b/code/cogs/crypto.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/gambling_helpers.py b/code/cogs/gambling_helpers.py
new file mode 100644
index 0000000..5579df3
--- /dev/null
+++ b/code/cogs/gambling_helpers.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/handlers.py b/code/cogs/handlers.py
new file mode 100644
index 0000000..d9c374f
--- /dev/null
+++ b/code/cogs/handlers.py
@@ -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))
diff --git a/code/cogs/help.py b/code/cogs/help.py
new file mode 100644
index 0000000..4c6fd82
--- /dev/null
+++ b/code/cogs/help.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/info.py b/code/cogs/info.py
new file mode 100644
index 0000000..f115cd3
--- /dev/null
+++ b/code/cogs/info.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/modals.py b/code/cogs/modals.py
new file mode 100644
index 0000000..e6252f7
--- /dev/null
+++ b/code/cogs/modals.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/moderation.py b/code/cogs/moderation.py
new file mode 100644
index 0000000..ea99866
--- /dev/null
+++ b/code/cogs/moderation.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/music.py b/code/cogs/music.py
new file mode 100644
index 0000000..e6f9ef0
--- /dev/null
+++ b/code/cogs/music.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/mute.py b/code/cogs/mute.py
new file mode 100644
index 0000000..cf7381e
--- /dev/null
+++ b/code/cogs/mute.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/owner_info_commands.py b/code/cogs/owner_info_commands.py
new file mode 100644
index 0000000..aae0fd4
--- /dev/null
+++ b/code/cogs/owner_info_commands.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/profile.py b/code/cogs/profile.py
new file mode 100644
index 0000000..4f76c66
--- /dev/null
+++ b/code/cogs/profile.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/slots.py b/code/cogs/slots.py
new file mode 100644
index 0000000..466ccb7
--- /dev/null
+++ b/code/cogs/slots.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/socketfix.py b/code/cogs/socketfix.py
new file mode 100644
index 0000000..9dfbf29
--- /dev/null
+++ b/code/cogs/socketfix.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/tree_sync.py b/code/cogs/tree_sync.py
new file mode 100644
index 0000000..d3f8307
--- /dev/null
+++ b/code/cogs/tree_sync.py
@@ -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)) \ No newline at end of file
diff --git a/code/cogs/warnings.py b/code/cogs/warnings.py
new file mode 100644
index 0000000..f9d84bc
--- /dev/null
+++ b/code/cogs/warnings.py
@@ -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)) \ No newline at end of file