DISCORD.PY How to stop giveaway without asyncio.sleep - python

I need to "sleep" the giveaway without the asyncio.sleep , because if the bot goes off it wont continue where it left (i know i need to store the other data as well , however time is needed for this one)
here is the code again :
import aiosqlite
import time
import datetime
import discord
from discord.ext import commands
import asyncio
import os
import random
class Start(commands.Cog):
def __init__(self, client):
self.client = client
def convert(self, timer):
pos = ["s", "m", "h", "d"]
time_dict = {"s" : 1, "m" : 60, "h" : 3600, "d" : 3600*24}
unit = timer[-1]
if unit not in pos:
return -1
try:
val = int(timer[:-1])
except:
return -2
return val * time_dict[unit]
#commands.command()
async def start(self, ctx, duration, winners: str, *, prize):
timer = (self.convert(duration))
winners = int(winners.replace("w",""))
await ctx.message.delete()
timestamp = time.time() + timer
epoch_time = int((time.time() + timer))
embed = discord.Embed(title = f"{prize}", description = f'React with 🎉 to enter\nEnds: <t:{epoch_time}:R> (<t:{epoch_time}>)\nHosted by {ctx.author.mention}\n', color =
ctx.author.color, timestamp=(datetime.datetime.utcfromtimestamp(timestamp)))
embed.set_footer(text=f'Winners : {winners} | Ends at \u200b')
gaw_msg = await ctx.send(content = "<:spadess:939938117736091678> **GIVEAWAY** <:spadess:939938117736091678>",embed=embed)
await gaw_msg.add_reaction("🎉")
db = await aiosqlite.connect("main.db")
cursor = await db.cursor()
await cursor.execute(f'SELECT * FROM storingStuff WHERE msgID = {gaw_msg.id}')
data = await cursor.fetchone()
if data is None:
await cursor.execute(f'INSERT INTO storingStuff (msgID, guildID) VALUES({gaw_msg.guild.id} , {gaw_msg.id})')
await db.commit()
await asyncio.sleep(timer)
new_msg = await ctx.channel.fetch_message(gaw_msg.id)
users_mention = []
for i in range(winners):
users = await new_msg.reactions[0].users().flatten()
users.pop(users.index(self.client.user))
winner = random.choice(users)
users_mention.append(winner.mention)
users.remove(winner)
displayed_winners = ",".join(users_mention)
endembed = discord.Embed(title=f"{prize}", description=f"Winner: {displayed_winners}\nHosted by: {ctx.author.mention}", color = ctx.author.color, timestamp=(datetime.datetime.utcfromtimestamp(timestamp)))
endembed.set_footer(text= 'Ended at \u200b')
await gaw_msg.edit(content = "<:done:939940228746072096> **GIVEAWAY ENDED** <:done:939940228746072096>",embed=endembed)
await ctx.send(f"Congragulations {displayed_winners}! You won the **{prize}**.\n{gaw_msg.jump_url}")
def setup(client):
client.add_cog(Start(client))
Any help is appreciated

Related

Discord.py ctx.author.id is not woring

So here's my code, some part are messy because im so angry, error message in the end:
from discord.ext import commands
import discord
import random
from keep_alive import keep_alive
import json
import os
import asyncio
#Game variables and list:
bot = commands.Bot(command_prefix='.')
#Game code here:
def o_acc(ctx):
users = await gbd()
if str(ctx.author.id) in users:
return False
else:
users[str(ctx.author.id)] = {}
users[str(ctx.author.id)]["Wallet"] = 10000
with open("user.json", 'w') as f:
json.dump(users, f)
return True
def gbd():
users = json.load(open("user.json", 'r'))
return users
#Check balance command
#bot.command(name='bal')
async def balance(ctx):
await o_acc(ctx.author)
users = await gbd()
em = discord.Embed(title = f"{ctx.message.author.name}'s balance'")
em.add_field(name = 'Wallet balance', value = users[str(ctx.message.author.id)]['wallet'])
await ctx.send(embed = em)
#These commands should be keep in the end!!!!
bot.run('token(bot showing')
Error message:File "main.py", line 32, in balance await o_acc(ctx.author) File "main.py", line 15, in o_acc if str(ctx.author.id) in users: AttributeError: 'Member' object has no attribute 'author'
Just pass in ctx instead of ctx.author as the argument for o_acc().
#Check balance command
#bot.command(name='bal')
async def balance(ctx):
await o_acc(ctx)
users = await gbd()
em = discord.Embed(title = f"{ctx.message.author.name}'s balance'")
em.add_field(name = 'Wallet balance', value = users[str(ctx.message.author.id)]['wallet'])
await ctx.send(embed = em)

manipulating websocket values

I'm trying to handling websockets with python for the first time.
I created two clients and I want to do some calculate with these two results.
(which is realtime crypto price)
Is it possible to add or multiply numbers of theses result?
import websockets
import asyncio
import json
from binance import AsyncClient, BinanceSocketManager
async def upbit_ws_client():
uri = "wss://api.upbit.com/websocket/v1"
async with websockets.connect(uri) as websocket:
subscribe_fmt = [
{"ticket": "test"},
{
"type": "ticker",
"codes": ["KRW-BTC"],
"isOnlyRealtime": True
},
{"format": "SIMPLE"}
]
subscribe_data = json.dumps(subscribe_fmt)
await websocket.send(subscribe_data)
while True:
data = await websocket.recv()
data = json.loads(data)
print(data['cd'], data['hp'])
async def binance_ws_client():
client = await AsyncClient.create()
bm = BinanceSocketManager(client)
ts = bm.symbol_book_ticker_socket("BTCUSDT")
async with ts as tscm:
while True:
res = await tscm.recv()
print(res['b'], res['a'])
if __name__ == '__main__':
my_loop = asyncio.get_event_loop()
my_loop.run_until_complete(asyncio.gather(*[upbit_ws_client(), binance_ws_client()]))
my_loop.close()
The results are strings so you need to convert them to floats first in order to have a data type which you can calculate:
a = float(res['a'])
b = float(res['b'])
Then you can substract a and b:
result = a - b
print(result)
which you can add to your code like below:
import websockets
import asyncio
import json
from binance import AsyncClient, BinanceSocketManager
async def upbit_ws_client():
uri = "wss://api.upbit.com/websocket/v1"
async with websockets.connect(uri) as websocket:
subscribe_fmt = [
{"ticket": "test"},
{
"type": "ticker",
"codes": ["KRW-BTC"],
"isOnlyRealtime": True
},
{"format": "SIMPLE"}
]
subscribe_data = json.dumps(subscribe_fmt)
await websocket.send(subscribe_data)
while True:
data = await websocket.recv()
data = json.loads(data)
print(data['cd'], data['hp'])
async def binance_ws_client():
client = await AsyncClient.create()
bm = BinanceSocketManager(client)
ts = bm.symbol_book_ticker_socket("BTCUSDT")
async with ts as tscm:
while True:
res = await tscm.recv()
print(res['b'], res['a'])
a = float(res['a'])
b = float(res['b'])
result = a - b
print(result)
if __name__ == '__main__':
my_loop = asyncio.get_event_loop()
my_loop.run_until_complete(asyncio.gather(*[upbit_ws_client(), binance_ws_client()]))
my_loop.close()

Need Advice me complete a rank command with discord.py rewrite and json

so far I build a working rank(r2[prints level and exp]) and leaderboard(levels[prints the first 20 ranks on the server]) command.
Now I want my users.json to also save someones rank(place) on the server and not only the exp and level. So there dont have to use the leaderboard everytime.
Is there anyway that this is possible?
My code:
import asyncio
import discord
import json
import random
import time
from discord.ext import commands
from discord import Guild
intents = discord.Intents.default()
intents.members = True
intents.typing = True
client = client = discord.Client(intents=intents)
client = commands.Bot(command_prefix = 'sco!')
#client.event
async def on_member_join(member):
with open('users.json', 'r') as f:
users = json.load(f)
await update_data(users, member)
with open('users.json', 'w') as f:
json.dump(users, f)
#client.event
async def on_message(message):
if message.author.bot == False:
with open('users.json', 'r') as f:
users = json.load(f)
await update_data(users, message.author)
await add_experience(users, message.author, 5)
await level_up(users, message.author, message)
with open('users.json', 'w') as f:
json.dump(users, f)
await client.process_commands(message)
async def update_data(users, user):
if not f'{user.id}' in users:
users[f'{user.id}'] = {}
users[f'{user.id}']['xp'] = 0
users[f'{user.id}']['level'] = 1
async def add_experience(users, user, exp):
users[f'{user.id}']['xp'] += exp
async def level_up(users, user, message):
with open('users.json', 'r') as g:
levels = json.load(g)
experience = users[f'{user.id}']['xp']
lvl_start = users[f'{user.id}']['level']
lvl_end = int(experience ** (1 / 4))
if lvl_start < lvl_end:
await message.channel.send(f'{user.mention} ist gerade auf Level {lvl_end} gestiegen!')
users[f'{user.id}']['level'] = lvl_end
#client.command()
async def r2(ctx, *, member:discord.Member=None):
await ctx.channel.purge(limit=1)
if member == None:
memberID = ctx.author.id
mentioned = ctx.author.name
else:
memberID = member.id
mentioned = member.name
with open('users.json', 'r') as f:
users = json.load(f)
xp = users[str(memberID)]['xp']
lvl = users[str(memberID)]['level']
embed = discord.Embed(title='')
embed.add_field(name="Spieler", value=mentioned, inline=True)
embed.add_field(name="Level:", value=lvl, inline=True)
embed.add_field(name="Experience:", value=xp, inline=True)
await ctx.send(embed=embed)
#client.command()
async def levels(ctx):
await ctx.channel.purge(limit=1)
with open('users.json', 'r') as f:
data = json.load(f)
top_spieler = {k: v for k, v in sorted(data.items(), key=lambda item: item[1]["xp"], reverse=True)}
names = ''
for position, user in enumerate(top_spieler):
names += f"{position+1} - <#!{user}> mit Level: {top_spieler[user]['level']} Exp: {top_spieler[user]['xp']}\n"
embed = discord.Embed(title='')
embed.add_field(name="Spieler", value=names, inline=False)
if position+1 > 19:
break
await ctx.send(embed=embed)
My JSON (only me on the server right now)
{"395805781863170050": {"xp": 15, "level": 1}}
What r2 does:
What levels does:
I hope there is someone who can help me.
One way is getting all the XP's on a list, append the new value and sort the list (in reverse), then getting the index of the new value, example:
>>> xp_list = [120, 90, 110, 150]
>>> new_xp = 100 # By logic, the "rank" would be 4
>>>
>>> xp_list.append(new_xp) # -> [120, 90, 110, 150, 100]
>>> xp_list.sort(reverse=True) # -> [150, 120, 110, 100, 90]
>>>
>>> rank = xp_list.index(new_xp) + 1
>>> print(rank)
4 # It's in fact 4
In a function:
def calculate_rank(user_xp: int, data: dict=None) -> int:
if data is None:
# Loading the data
with open("whatever.json", "r") as f: # Change the path accordingly
data = json.load(f)
# Getting ONLY the XP of the users
xp = [value["xp"] for value in data.values()] # -> [15, ...]
# Appending the new XP
xp.append(user_xp)
# Sorting the list
xp.sort(reverse=True)
# Returning the "rank"
return xp.index(xp) + 1
# To use it pass the user XP
# You can also pass the data directly as a kwarg
rank = calculate_rank(10)
You won't need to store the rank in the JSON this way, (tbh it's a bad option to store it, you'll have to re-calculate all the ranks everytime someone gets more XP)

message.channel.send doesn't send message [discord.py]

import discord
from discord.ext import commands, tasks
import datetime
import requests
import time
from bs4 import BeautifulSoup
client = discord.Client()
r = requests.get("https://www.worldometers.info/coronavirus/country/italy/")
s = BeautifulSoup(r.text, "html.parser")
data = s.find_all("div",class_ = "maincounter-number")
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#tasks.loop(seconds=50.0)
async def covid():
x = datetime.datetime.now()
d = x.strftime("%M")
if d == "21":
channel = bot.get_guild(guild).get_channel(channel)
await message.channel.send("casi di coronavirus in italia: \ncasi totali: " +
data[0].text.strip()
+ "\nmorti totali: " + data[1].text.strip()
+ "\nguariti totali: " + data[2].text.strip())
#covid.before_loop
async def before_printer(self):
print('waiting...')
await self.bot.wait_until_ready()
#covid.after_loop
async def post_loop(self):
if self.covid.failed():
import traceback
error = self.covid.get_task().exception()
traceback.print_exception(type(error), error, error.__traceback__)
client.run('token)
basically this code checks if it is a specified time and if it is it sends a message with the covid data of italy but it doesn't work and doesn't return anything i tried even adding an error handler (traceback) and doesn't do anything the only output i have is from async def on_ready()
so i tried this:
data = ''
#tasks.loop(seconds=50.0)
async def covid(ctx):
global data
x = datetime.datetime.now()
d = x.strftime("%M")
if d == "21":
data = "casi di coronavirus in italia: \ncasi totali: " +
data[0].text.strip() + "\nmorti totali: " + data[1].text.strip()
return data
#covid.before_loop
async def before_printer(self):
print('waiting...')
await self.bot.wait_until_ready()
#client.command()
async def get_covid(ctx):
global data
await ctx.send(data)
but i don't get any output and if i add #client.command() before async def covid
it gives me this error:
Traceback (most recent call last):
File "C:\Users\danie\OneDrive\Desktop\test.py", line 26, in
async def covid(ctx):
File "C:\Users\danie\AppData\Local\Programs\Python\Python38\lib\site- packages\discord\ext\commands\core.py", line 1162, in decorator
result = command(*args, **kwargs)(func)
File "C:\Users\danie\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\ext\commands\core.py", line 1317, in decorator
return cls(func, name=name, **attrs)
File "C:\Users\danie\AppData\Local\Programs\Python\Python38\lib\site- packages\discord\ext\commands\core.py", line 210, in init
raise TypeError('Callback must be a coroutine.')
TypeError: Callback must be a coroutine.
>>>
You need to add a context in the function and #bot.command() decorator followed by your instance.
Likewise:
#client.command()
async def test(ctx):
await ctx.send('PASSED')
a message is an event and you need to add a proper listener for it to work. You don't need to use this event unless you need the text data.
In your case, you are sending the data directly from your COVID-19 function which doesn't do anything since the message is not defined.
It would be as:
#STORE THE VALUE OF COVID INSIDE DATA VARIABLE.
data = ''
#tasks.loop(seconds=50.0)
async def covid():
global data
x = datetime.datetime.now()
d = x.strftime("%M")
if d == "21":
#Assign the value to DATA VARIABLE.
data = "casi di coronavirus in italia: \ncasi totali: " + data[0].text.strip() + "\nmorti totali: " + data[1].text.strip()
#Return the MODIFIED Data
return data
Now send the data with this function.
#client.command()
async def get_covid(ctx):
global data
await ctx.send(data)
Also, You defined the client wrongly. client = discord.Client()
It should be as:
# change '!' to any prefix you would like to use.
client = commands.Bot(command_prefix ='!')

Showing leader board stats from JSON with Discord.py via Embed

I'm trying to create a leaderboard to show the different stats the users collect when messaging the discord chatroom. I'm storing the data via JSON file and was wondering if I am on the right track or if there was a better way to display the stats with an Embed?
Edit: Edited the code to display what changes were made. New question is, how could I display 11-20 with a page forward? Tried the code below but when it goes to display 11-20, it sends #11 as an embed, then #11-12 as an embed, etc, etc and doesn't stop at 20, just keeps sending more embeds.
client = discord.Client()
try:
with open("cash.json") as fp:
cash = json.load(fp)
except Exception:
cash = {}
def save_cash():
with open("cash.json", "w+") as fp:
json.dump(cash, fp, sort_keys=True, indent=4)
def add_dollars(user: discord.User, dollars: int):
id = user.id
if id not in cash:
cash[id] = {}
cash[id]["dollars"] = cash[id].get("dollars", 0) + dollars
print("{} now has {} dollars".format(user.name, cash[id]["dollars"]))
save_cash()
def get_dollars(user: discord.User):
id = user.id
if id in cash:
return cash[id].get("dollars", 0)
return 0
client.event
async def on_message(message):
if message.content.startswith('!lb cash'):
cash_leaderboard = sorted(cash, key=lambda x : cash[x].get('dollars', 0), reverse=True)
msg = ''
for number, user in enumerate(cash_leaderboard):
msg += '{0}. <#!{1}> {2} Dollars\n\n'.format(number +1, user, cash[user].get('dollars', 0))
if number == 10:
break
else:
number += 1
embed = discord.Embed(
title="TOP BALLER LEADERBOARD\nBallers:",
color=0x24d7cf,
description=msg
)
embed.set_author(name="BOT", icon_url="")
embed.set_thumbnail(url="")
embed.set_footer(text="BOT", icon_url="")
lb_msg = await client.send_message(message.channel, embed=embed)
await client.add_reaction(lb_msg, "⏩")
lb_wait = await client.wait_for_reaction(emoji="⏩", user=message.author, message=lb_msg, timeout=1800)
if lb_wait:
await client.delete_message(lb_msg)
cash_leaderboard2 = sorted(cash, key=lambda x : cash[x].get('dollars', 0), reverse=True)
msg = ''
for number, user in enumerate(cash_leaderboard2):
msg += '{0}. <#!{1}> {2} Dollars\n\n'.format(number +11, user, cash[user].get('dollars', 0))
if number == 20:
break
else:
number += 1
embed = discord.Embed(
title="TOP BALLER LEADERBOARD 11-20\nBallers:",
color=0x24d7cf,
description=msg
)
embed.set_author(name="BOT", icon_url="")
embed.set_thumbnail(url="")
embed.set_footer(text="BOT", icon_url="")
await client.send_message(message.channel, embed=embed)

Categories

Resources