So, I found this question I want to make a multi-page help command using discord.py
But the answer make me a doubt. I tried a similar code to just try this thing, but while the loop is going on I literally can't use any of the other commands. What should I do in order to permit all the commands work while the loop is going on?
import discord
import datetime
from datetime import timedelta
import pytz
from discord.ext import commands
client = discord.Client()
client = commands.Bot(command_prefix = "!")
prefix = "!"
id = client.get_guild(766402039495262218)
#client.event
async def on_ready():
print("Bot is ready")
game = discord.Game("Could I Destroy a Server...?")
await client.change_presence(status=discord.Status.idle, activity=game)
#client.event
async def on_message(message):
await client.process_commands(message)
#client.event
async def on_reaction_add(reaction, user):
channel = reaction.message.channel
if reaction.emoji == '➡':
if reaction.message.embeds == discord.embeds.Embed(title='Corsi Informatica I Anno'):
await channel.send("ok")
print("ok")
else:
print(reaction.message.embeds)
print("not ok")
else:
await channel.send("YOLO")
#client.command(pass_context = True)
async def test(ctx):
await ctx.message.channel.send("this is a testing test")
#client.command(pass_context=True)
async def corsi(ctx):
page = 1
left_arrow = '⬅'
right_arrow = '➡'
first_year = discord.Embed(
title = 'Corsi Informatica I Anno',
description = 'Lista dei corsi:',
colour = discord.Colour.dark_blue()
)
second_year = discord.Embed(
title = 'Corsi Informatica II Anno',
description = 'Lista dei corsi:',
colour = discord.Colour.dark_green()
)
third_year = discord.Embed(
title = 'Corsi Informatica III Anno',
description = 'Lista dei corsi:',
colour = discord.Colour.dark_red()
)
first_year.set_footer(text = datetime.datetime.now().strftime('%d/%m/%Y %H:%M') + "\t\t\t\t\t\t\t\t\t\t\t\t\t" + "pag." + " " + str(page)+"/3")
first_year.set_author(name = ctx.message.author)
first_year.add_field(name = 'Calcolo I', value = 'I Semestre', inline = True)
first_year.add_field(name = 'Algebra Lineare', value='I Semestre', inline = True)
first_year.add_field(name ='Programmazione I', value='I Semestre', inline=True)
first_year.add_field(name='--------------------------------------------------------------------------',value="**--------------------------------------------------------------------------**"
,inline=False)
first_year.add_field(name ='Elaboratori I', value='I Semestre', inline = True)
first_year.add_field(name ='Matematica Discreta', value='I Semestre', inline = True)
first_year.add_field(name ='Programmazione II', value='II Semestre', inline = True)
first_year.add_field(name='--------------------------------------------------------------------------',value="**--------------------------------------------------------------------------**",
inline=False)
first_year.add_field(name ='Elaboratori II', value='II Semestre', inline = True)
first_year.add_field(name ='Calcolo II', value='II Semestre', inline = True)
first_year.add_field(name ='Inglese', value='II Semestre', inline = True)
second_year.set_footer(text = datetime.datetime.now().strftime('%d/%m/%Y %H:%M') + "\t\t\t\t\t\t\t\t\t\t\t\t\t" + "pag." + " " + str(page)+"/3")
second_year.set_author(name = ctx.message.author)
third_year.set_footer(text = datetime.datetime.now().strftime('%d/%m/%Y %H:%M') + "\t\t\t\t\t\t\t\t\t\t\t\t\t" + "pag." + " " + str(page)+"/3")
third_year.set_author(name = ctx.message.author)
while True:
if page == 1:
sent = await ctx.message.channel.send(client.get_channel("795387716967333889"), embed=first_year)
await sent.add_reaction(right_arrow)
page = 4
# Do not do nothing until user use a reaction
elif page == 2:
sent = await ctx.message.channel.send(client.get_channel("795387716967333889"), embed=second_year)
await sent.add_reaction(left_arrow)
await sent.add_reaction(right_arrow)
elif page == 3:
sent = await ctx.message.channel.send(client.get_channel("795387716967333889"), embed=third_year)
await sent.add_reaction(left_arrow)
Instead of using a while True loop that blocks your processing, you should make use of the on_reaction_add event to watch for added reactions. You can identify the embed by checking the embed title & embed poster (your bot).
Documentation can be found here here
Related
I want to track the time spent in vc by users but after a while of checking, we see that their time has reduced which makes no sense. I want to check 3 channels every minute for which members are inside those channels and in the member_info list, increase the time stored in member_info[member_index][1] if they are in one of the 3 channels. I can't understand why the total time is reducing if I only add values to the list and if the file is only read to initialise the list.
member_info = []
intents = discord.Intents.default()
intents.members = True
bot = commands.Bot(command_prefix='$', intents = intents)
#bot.event
async def on_ready():
print("We have logged in as {0.user}".format(bot))
global member_info
f = open("times.txt")
content = f.readlines()
for i in range (0, len(content)):
content[i] = content[i].split(", ")
content[i][0] = int(content[i][0])
content[i][1] = int(content[i][1].strip())
member_info.append(content[i])
print(member_info)
track_user_time.start()
update_file.start()
#bot.command()
async def myTime(ctx):
author = ctx.author.id
global member_info
for b in range (0, len(member_info)):
if (member_info[b][0] == author):
time_spent = member_info[b][1]
user_days = time_spent // 3600
user_hours = (time_spent - (user_days*3600)) // 60
user_minutes = time_spent - (user_days*3600) - (user_hours *60)
time_msg = f"""
Time Spent by: {ctx.author.name}
Days Spent Studying: {user_days} day(s)
Hours Spent Studying: {user_hours} hour(s)
Minutes Spent Studying: {user_minutes} minutes
"""
await ctx.send(time_msg)
#tasks.loop(seconds=60)
async def track_user_time():
global member_info
active_members = []
await bot.wait_until_ready()
channel = bot.get_channel(868830478705233993)
members = channel.members
for k in range (0, len(members)):
if (members[k].id not in active_members):
active_members.append(members[k].id)
#find their id for each work channel
#look for corresponding id in member_info
#add 1 minute to their time spent studying
channel = bot.get_channel(868835241958182984)
members = channel.members
for p in range (0, len(members)):
if (members[p].id not in active_members):
active_members.append(members[p].id)
channel = bot.get_channel(868835476147146752)
members = channel.members
for o in range (0, len(members)):
if (members[o].id not in active_members):
active_members.append(members[o].id)
print(active_members)
for f in range (0, len(member_info)):
for y in range(0, len(active_members)):
if (member_info[f][0] == active_members[y]):
member_info[f][1] = member_info[f][1] + 1
print("working")
#tasks.loop(seconds = 90)
async def update_file():
await bot.wait_until_ready()
f = open('times.txt', 'w')
for q in range(0, len(member_info)):
file_info = str(member_info[q][0]) + ", " + str(member_info[q][1]) + "\n"
f.write(file_info)
print("updated")
thats my cog file levelsys.py
import discord
from discord.ext import commands
from pymongo import MongoClient
general = [825768173730660404]
bot_channel = 825871367575830548
level = ["Level 1", "Level 2", "Level 3"]
levelnum = [5, 10, 15]
cluster = MongoClient(
"mongodb+srv://my username:<my password>#bot.orejh.mongodb.net/myFirstDatabase?retryWrites=true&w=majority")
levelling = cluster["discord"], ["levelling"]
class levelsys(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_message(self, message):
if message.channel.id in general:
stats = levelling.find_one({"id": message.author.id})
if not message.author.bot:
if stats is None:
newuser = {"id": message.author.id, "xp": 100}
levelling.insert_one(newuser)
else:
xp = stats["xp"] + 5
levelling.update_one({"id": message.author.id}, {"$set": {"xp": xp}})
lvl = 0
while True:
if xp < ((50 * (lvl ** 2)) + (50 * lvl)):
break
lvl += 1
xp -= ((50 * ((lvl - 1) ** 2)) + (50 * (lvl - 1)))
if xp == 0:
await message.channel.send(
f"well done {message.author.mention}! You leveled up to **level: {lvl}**!")
for i in range(len(level)):
if lvl == levelnum[i]:
await message.author.add_roles(
discord.utils.get(message.author.guild.roles, name=level[i]))
embed = discord.Embed(
description=f"{message.author.mention} you have gotten role **{level[i]}**!!!")
embed.set_thumbnail(url=message.author.avatar_url)
await message.channel.send(embed=embed)
#commands.command()
async def rank(self, ctx):
if ctx.channel.id == bot_channel:
stats = levelling.find_one({"id": ctx.author.id})
if stats is None:
embed = discord.Embed(description="You haven't sent any messages, no rank!!!")
await ctx.channel.send(embed=embed)
else:
xp = stats["xp"]
lvl = 0
rank = 0
while True:
if xp < ((50 * (lvl ** 2)) + (50 * lvl)):
break
lvl += 1
xp -= ((50 * ((lvl - 1) ** 2)) + (50 * (lvl - 1)))
boxes = int((xp / (200 * ((1 / 2) * lvl))) * 20)
rankings = levelling.find().sort("xp", -1)
for x in rankings:
rank += 1
if stats["id"] == x["id"]:
break
embed = discord.Embed(title="{}'s level stats".format(ctx.author.name))
embed.add_field(name="Name", value=ctx.author.mention, inline=True)
embed.add_field(name="XP", value=f"{xp}/{int(200 * ((1 / 2) * lvl))}", inline=True)
embed.add_field(name="Rank", value=f"{rank}/{ctx.guild.member_count}", inline=True)
embed.set_thumbnail(url=ctx.author.avatar_url)
await ctx.channel.send(embed=embed)
#commands.command()
async def leaderboard(self, ctx):
if (ctx.channel.id == bot_channel):
rankings = levelling.find().sort("xp", -1)
i = 1
embed = discord.Embed(title="Rankings:")
for x in rankings:
try:
temp = ctx.guild.get_member(x["id"])
tempxp = x["xp"]
embed.add_field(name=f"{i}: {temp.name}", value=f"Total XP: {tempxp}", inline=False)
i += 1
except:
pass
if i == 11:
break
await ctx.channel.send(embed=embed)
def setup(client):
client.add_cog(levelsys(client))
error message:
Ignoring exception in on_message
Traceback (most recent call last):
File "C:\Users\Kacper\.virtualenvs\Nocne_Farfocle\lib\site-packages\discord\client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "D:\Programming\Python\Nocne_Farfocle\levelsys.py", line 25, in on_message
stats = levelling.find_one({"id": message.author.id})
AttributeError: 'tuple' object has no attribute 'find_one'
I'm using python 3.9.1, discord 1.0.1, discord.py 1.6.0, dnspython 2.1.0 and pymongo 3.11.3
I'm trying to make a custom discord bot, and that's one of modules for this bot, i'm stuck wit this error for like 3 days now, soo i would really like to get any tips from you guys :D
I think the answer is that leveling is one variable to which you assigned 2 values. This makes it into a tuple. therefore, when you try to run find_one on the tuple, it can't because it isn't the object you wanted it to be.
sidenote: a similar thing happens if you make a method return value1, value2. In python, that is considered a tuple.
I can't use !giveaway command when I use host.
When I'm running this command using cmd, it works great but when I'm trying to run this command using Heroku host, it doesn't work and heroku logs command doesn't returnes me any errors. I don't know what to do.
How to fix that? Help me, please.
Here is the command code:
#bot.command(aliases=["giveaway-start", "розыгрыш-начать"])
async def __giveaway_start(ctx, duration: int, sign: str, channel: discord.TextChannel, *, prize: str):
with open('C:\\bot1\\giveaways.json', 'r') as f:
givs = json.load(f)
async def new_id(givs,g_id):
if g_id in givs:
new_g_id += random.choice(giveaway_id)
giveaway_id = '1234567890'
for n in range(1):
g_id = ''
for i in range(16):
g_id += random.choice(giveaway_id)
if g_id in givs:
await ctx.send("Попробуйте позже")
if sign == "с":
wait = 1 * duration
elif sign == "м":
wait = 60 * duration
elif sign == "ч":
wait = 3600 * duration
elif sign == "д":
wait = 86400 * duration
emoji = "🎉"
if duration == 0:
return
embed = discord.Embed(title=prize, description=f"Автор - {ctx.author.mention}\n"f"**Нажмите на :tada: чтобы принять участие!**\n"f"Времени осталось: {wait} секунд",color=discord.Color.blue(),timestamp=datetime.utcnow())
message = await channel.send(embed=embed)
async def update_data(givs,g_away):
if not g_away in givs:
givs[g_away] = {}
givs[g_away]["msg_id"] = message.id
await ctx.send(f"Розыгрыш в канале {channel.mention} успешно создан! ID розыгрыша: `{g_id}`. Я напишу Вам в ЛС когда розыгрыш закончится.\nТак же можете присоединиться к нашему серверу тех. поддержки! https://discord.gg/YUzE6rB")
await message.add_reaction(emoji)
await update_data(givs,str(g_id))
with open('C:\\bot1\\giveaways.json', 'w') as f:
json.dump(givs,f)
while wait:
await asyncio.sleep(1)
if wait == 0:
await ctx.send("Giveaway is over!")
else:
wait -= 1
if wait > 86400:
cld = wait / 86400
time = "дней"
cooldown = round(cld, 1)
elif wait > 3600:
cld = wait / 3600
time = "часов"
cooldown = round(cld, 1)
elif wait > 60:
cld = wait / 60
time = "минут"
cooldown = round(cld, 1)
else:
cld = wait / 1
time = "секунд"
cooldown = round(cld, 1)
embed.description = f"Автор - {ctx.author.mention}\n"f"**Нажмите на :tada: чтобы принять участие!**\n"f"Времени осталось: {cooldown} {time}"
await message.edit(embed=embed)
await asyncio.sleep(duration)
message = await message.channel.fetch_message(message.id)
reaction = get(message.reactions, emoji=emoji)
users = [user async for user in reaction.users() if user.id != bot.user.id]
if len(users) == 0:
embed.description = f"Автор - {ctx.author.mention}\n"f"Нет победителей"
await message.edit(embed=embed)
return
else:
winner = random.choice(users)
embed.description = f"**Автор - {ctx.author.mention}**\n"f"**Победитель - {winner.mention}**"
await message.edit(embed=embed)
embed_end=discord.Embed(color=discord.Color.gold())
embed_end.add_field(name=f"Розыгрыш окончен!", value=f"[Ссылка на розыгрыш]({message.jump_url})", inline=False)
await ctx.author.send(embed=embed_end)
await channel.send(winner.mention, embed=embed)
win_embed=discord.Embed(title="Вы победили в розыгрыше!", color=discord.Color.gold())
win_embed.add_field(name=f"Вы выйграли: {prize}", value=f"[Ссылка на розыгрыш]({message.jump_url})",inline=False)
await winner.send(embed=win_embed)
Free Heroku does not support JSON writing, so your command would not be executed as it contains json.dump.
So, I made some code that takes events from a google calendar and organizes them then posts them on discord. The main problem is this: client.send_message(client.get_channel('483988804370169857'),"None")
When using this code in a #client.event it works fine, the problem begins when i put it in a normal function. I need it in a normal function so that it runs once every 24 hours. No errors, no nothing. The code just goes through the function and doesn't send the message. How can I fix this?
from __future__ import print_function
import json
import datetime
import discord
from discord.ext import commands
from datetime import timedelta
import gspread
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
from discord.ext import commands
import threading
SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'
client = discord.Client()
def Hw():
print("HW")
now = datetime.datetime.now()
run_at = now + timedelta(hours=3)
delay = (run_at - now).total_seconds()
#Begin Google Calander API
store = file.Storage('token.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
creds = tools.run_flow(flow, store)
service = build('calendar', 'v3', http=creds.authorize(Http()))
now = datetime.datetime.utcnow().isoformat() + 'Z'
#Retrieve all Events
events_result = service.events().list(calendarId='CENSORED', timeMin=now,maxResults=250, singleEvents=True,orderBy='startTime').execute()
events = events_result.get('items', [])
#Currentmode stores if searching for tommorow, the week, or other (1,2,3)
Currentmode = 0
UMode=1
none = True
#Gets end of week
dt = datetime.datetime.now()
startweek = dt - timedelta(days=dt.weekday())
endweek = startweek + timedelta(days=6)
dtstring = str(dt.date())
TheMessages = "**" + dtstring + " Report**"
client.send_message(client.get_channel('483988804370169857'),TheMessages)
if not events:
client.send_message(client.get_channel('483988804370169857'), 'No upcoming events found.')
for event in events:
if Currentmode == 0:
client.send_message(client.get_channel('483988804370169857'),"*Due Tommorow*")
Currentmode = 1
thestr = event['start'].get('dateTime')
count = 0
count2 = 0
for x in thestr:
count += 1
if x == "-":
count2 +=1
if count2 == 3:
break
count = count - 1
thestr = thestr[0:count]
start = datetime.datetime.strptime(thestr, "%Y-%m-%dT%H:%M:%S")
if (start - dt).days <= 7 and Currentmode == 1:
if UMode == 1:
client.send_message(client.get_channel('483988804370169857'),"None")
client.send_message(client.get_channel('483988804370169857'),"*Due in the Next 7 Days*")
UMode = 2
Currentmode = 2
elif (start - dt).days >= 7 and (Currentmode == 1 or Currentmode == 2):
if UMode == 1:
client.send_message(client.get_channel('483988804370169857'),"None")
client.send_message(client.get_channel('483988804370169857'),"*Due in the Next 7 Days*")
client.send_message(client.get_channel('483988804370169857'),"None")
client.send_message(client.get_channel('483988804370169857'),"*Longterm*")
Currentmode = 3
UMode = 3
FirstMessage = str(start.date())
SecondMessage = event['summary']
ThirdMessage= FirstMessage + " " + SecondMessage
client.send_message(client.get_channel('483988804370169857'),ThirdMessage)
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('!hello'):
msg = 'Hello {0.author.mention}'.format(message)
await client.send_message(message.channel, msg)
#client.event
async def on_ready():
print('Logged in as')
print(client.user.name)
print(client.user.id)
print('------')
now = datetime.datetime.now()
run_at = now + timedelta(seconds=1)
delay = (run_at - now).total_seconds()
threading.Timer(delay, Hw).start()
#Run client and start daily timer
client.run('CENSORED')
I am using pyTelegramBotAPI. I make some chain of functions using register_next_step_handler(msg, process_name_step)
It works fine, as I want.
But if I send to this bot two messages or more from user without waitining answer, hi start answering with two or more replys.
I using webhooks and CherryPy
Here is a part of my code:
# Handle '/start'
#bot.message_handler(commands=['start'])
def handle_start(message):
# get user id
user_id = message.from_user.id
# get User
user = commands.get_user(message)
# if lng not selected
if user[6] == 0:
# set user markup
user_markup = telebot.types.ReplyKeyboardMarkup(True, False)
user_markup.row('Русский язык', 'Українська мова')
msg = bot.send_message(user_id, 'Добрый день, выберите пожалуйста язык бота.\n'
'Добрий день, оберіть будь ласка мову бота.', reply_markup=user_markup)
bot.register_next_step_handler(msg, lng_select)
# if lng ru
elif user[6] == 1:
message.text = 'ru'
menu_ru(message)
# if lng ua
elif user[6] == 2:
message.text = 'ua'
menu_ua(message)
def lng_select(message):
lng = message.text
if lng == 'Русский язык':
commands.set_user_lng(message, 1)
handle_start(message)
elif lng == 'Українська мова':
commands.set_user_lng(message, 2)
handle_start(message)
else:
handle_start(message)
# ru version
def menu_ru(message):
admin = [(1, 1111111, 1)]
#get user id
user_id = message.from_user.id
# get User
user = commands.get_user(message)
user_full_name = ''
if user[2]:
user_full_name = ' ' + user[2]
# get Basket
basket = commands.make_basket(message)
if not basket:
basket = ''
user_markup = telebot.types.ReplyKeyboardMarkup(True, False)
user_markup.row('Купить журнал')
user_markup.row('Подтвердить оплату')
user_markup.row('Поменять язык')
if basket:
user_markup.row('Перейти к заказу')
user_markup.row('Очистить корзину')
if message.from_user.id == admin[0][1]:
user_markup.row('/admin')
msg = bot.send_message(user_id, 'Добро пожаловать' + user_full_name + '!\n'
+ basket +
'Что бы вы хотели сделать?', reply_markup=user_markup)
bot.register_next_step_handler(msg, process_menu_ru_step)