edenbot/bot.py

244 lines
9.3 KiB
Python

import aiosqlite
import discord
import logging
import requests
import random
from datetime import datetime
from discord.ext import commands, tasks
import os
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
MENTION_ROLE = str(os.getenv('MENTION_ROLE'))
THRESHOLD = float(os.getenv('THRESHOLD'))
API_ENDPOINT = 'http://api-mainnet.magiceden.dev/v2/'
NFT_LINKS = [
"https://monkelabs.nyc3.digitaloceanspaces.com/public/assets/LabMonke_Brown.gif",
"https://monkelabs.nyc3.digitaloceanspaces.com/public/assets/LabMonke_Orangutan.gif",
"https://monkelabs.nyc3.digitaloceanspaces.com/public/assets/LabMonke_Green.gif",
"https://monkelabs.nyc3.digitaloceanspaces.com/public/assets/LabMonke_Blue.gif",
"https://monkelabs.nyc3.digitaloceanspaces.com/public/assets/LabMonke_Gorilla.gif"
"https://monkelabs.nyc3.digitaloceanspaces.com/public/assets/LabMonke_Arctic.gif",
"https://smr-volume-1.s3.amazonaws.com/assets/4713.png",
"https://smr-volume-1.s3.amazonaws.com/assets/1739.png",
"https://smr-volume-1.s3.amazonaws.com/assets/5275.png",
"https://smr-volume-1.s3.amazonaws.com/assets/5796.png",
"https://www.arweave.net/shJMjP9y9mwFwmaTet0Jcok-dG1TEr8t7E362zeS6uM?ext=png"
"https://arweave.net/teqvJFiNG-_i7OHDwfeb5ISsGzN_SkU3jNQ7uzelJLo?ext=png",
"https://arweave.net/giVsTWye2PILj1wZe3uP3VNRwvVbbLz-9-FJ94ToNv0?ext=png",
"https://www.arweave.net/GciyPdeivlARIjnpQtFnFMVIVZTVUGEFt28ui-Yem9k?ext=png"
]
# Bot
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='$', intents=intents)
# Logging
logger = logging.getLogger('discord')
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w')
handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
logger.addHandler(handler)
# Database
schema = [
'''CREATE TABLE IF NOT EXISTS collections (
id integer PRIMARY KEY,
symbol text,
image text,
name text,
description text,
last_price integer
)''',
'''CREATE TABLE IF NOT EXISTS guilds (
id integer PRIMARY KEY,
guild_id integer
)''',
'''CREATE TABLE IF NOT EXISTS lists (
collection_id integer,
guild_id integer
)'''
]
async def create_db():
for query in schema:
await db.execute (query)
await db.commit()
print('Database ready')
@bot.event
async def on_ready():
global db
db = await aiosqlite.connect('db.sqlite3')
await create_db()
print('We have logged in as {0.user}'.format(bot))
update_prices.start()
await bot.change_presence(activity=discord.Game(name="The NFT Market"))
@bot.event
async def on_guild_join(guild):
await db.execute('INSERT INTO guilds (guild_id) VALUES (?)', (guild.id,))
await db.commit()
print(f"Joined guild {guild.name}")
@bot.event
async def on_guild_remove(guild):
await db.execute('DELETE FROM guilds (guild_id) VALUES (?)', (guild.id,))
await db.execute('DELETE FROM lists (guild_id) VALUES (?)', (guild.id,))
await db.commit()
print(f"Left guild {guild.name}")
@bot.command(help='Lists all of your collections')
async def list(ctx):
async with await db.execute("SELECT id from guilds WHERE guild_id=69 LIMIT 1") as cursor:
print(cursor.rowcount)
embed = discord.Embed(title='Here is a list of all your tracked collections', color=0x6106D0)
embed.set_image(url=str(random.choice(NFT_LINKS)))
async with await db.execute("SELECT id from guilds WHERE guild_id=? LIMIT 1", (ctx.guild.id,)) as cursor:
async for row in cursor:
guild_id = row[0]
collections = []
async with await db.execute("SELECT collection_id from lists WHERE guild_id=?", (guild_id,)) as cursor:
async for collection in cursor:
collections.append(collection[0])
print(collections)
for collection_id in collections:
async with await db.execute("SELECT symbol,name,last_price from collections WHERE id=? LIMIT 1", (collection_id,)) as cursor:
async for collection in cursor:
embed.add_field(name=collection[1], value=f'`{collection[0]}` - {format_price(collection[2])}', inline=False)
await ctx.send(embed=embed)
@bot.command(brief='Add a collection to your list', help='Add a collection to your list, pass a symbol: magiceden.io/marketplace/SYMBOL', usage='SYMBOL')
async def add(ctx, symbol):
data = requests.get(API_ENDPOINT + 'collections/' + symbol)
if data.status_code != 200:
await ctx.send(f'Could not find collection with symbol `{symbol}`')
else:
price_data = requests.get(API_ENDPOINT + 'collections/' + symbol + '/stats').json()
price = int(str(price_data['floorPrice'])[:-7])
made = False
async with await db.execute("SELECT id from collections WHERE symbol=?", (symbol,)) as cursor:
async for row in cursor:
made = True
if not made:
await db.execute('INSERT INTO collections (symbol,image,name,last_price) VALUES (?,?,?,?)', (symbol,data.json()['image'],data.json()['name'],price))
await db.commit()
async with await db.execute("SELECT id FROM collections WHERE symbol=? LIMIT 1", (symbol,)) as cursor:
async for row in cursor:
collection_id = row[0]
async with await db.execute("SELECT id from guilds WHERE guild_id=? LIMIT 1", (ctx.guild.id,)) as cursor:
async for row in cursor:
guild_id = row[0]
await db.execute('REPLACE INTO lists (guild_id, collection_id) VALUES (?,?)', (guild_id, collection_id))
await db.commit()
await ctx.send(f'Added `{symbol}`({format_price(price)} ◎) to your list')
@bot.command(brief='Remove a collection from your list', help='Remove a collection from your list, pass a symbol: magiceden.io/marketplace/SYMBOL', usage='SYMBOL')
async def remove(ctx, symbol):
collection = None
async with await db.execute("SELECT id from collections WHERE symbol=?", (symbol,)) as cursor:
async for row in cursor:
collection = row[0]
if collection is None:
await ctx.send(f'Could not find collection with symbol `{symbol}`')
else:
await db.execute('DELETE FROM lists WHERE collection_id=?', (collection,))
await db.commit()
await ctx.send(f'Removed `{symbol}` from your list')
@tasks.loop(seconds=10, minutes=0, hours=0, count=None)
async def update_prices():
collections = []
async with await db.execute("SELECT id,symbol,last_price,name from collections") as cursor:
async for row in cursor:
collections.append(row)
prices = []
changes = []
for collection in collections:
data = requests.get(API_ENDPOINT + 'collections/' + collection[1] + '/stats').json()
price = int(str(data['floorPrice'])[:-7])
prices.append((collection, price))
if float(abs(price - collection[2])) > THRESHOLD*100:
changes.append((collection, price))
if len(changes) > 0:
print("We have a change!")
embed = discord.Embed(title='Price changes', color=0x6106D0)
embed.set_footer(text=f'Sent at {datetime.now().strftime("%d/%m/%Y %H:%M:%S")}', icon_url="https://imagedelivery.net/E-VnZk4fwouzlzwX_qz4fg/532afb9b-8805-424d-8f85-da5c3e0f8600/public")
g_ids = []
for change in changes:
if change[1] - change[0][2] > 0:
embed.add_field(name=f'{change[0][3]} (`{change[0][1]}`)', value=f'{format_price(change[0][2])} ◎ :arrow_right: {format_price(change[1])}\n:chart_with_upwards_trend:Change: {format_price(change[1] - change[0][2])}', inline=False)
else:
embed.add_field(name=f'{change[0][3]} (`{change[0][1]}`)', value=f'{format_price(change[0][2])} ◎ :arrow_right: {format_price(change[1])}\n:chart_with_downwards_trend:Change: {format_price(change[1] - change[0][2])}', inline=False)
collection_id = change[0][0]
async with await db.execute("SELECT guild_id from lists WHERE collection_id=?", (collection_id,)) as cursor:
async for row in cursor:
g_ids.append(row[0])
g_ids = set(g_ids)
guilds = []
for g_id in g_ids:
async with await db.execute("SELECT guild_id from guilds WHERE id=?", (g_id,)) as cursor:
async for row in cursor:
guilds.append(row[0])
print("Sending to:", guilds)
for g_id in guilds:
guild = bot.get_guild(g_id)
channel_id = None
for c in guild.channels:
if c.name == 'fp-changes':
channel_id = c.id
channel = bot.get_channel(channel_id)
if channel_id is not None:
await channel.send(embed=embed)
mention_role = discord.utils.get(guild.roles, name=MENTION_ROLE)
if mention_role is not None:
await channel.send(f'{mention_role.mention} `({", ".join([changes[i][0][1] for i in range(len(changes))])})`')
for price in prices:
await db.execute('UPDATE collections SET last_price=? WHERE id=?', (price[1], price[0][0]))
await db.commit()
def format_price(price):
if price == None: return 'NULL'
return f'{price/100}'
bot.run(TOKEN)