I'm trying to write a telegram bot, that selects a group of photos in 3 steps, using Inline Keyboards. During each of steps I call an Inline Keyboard with 2 buttons. First button selects a criteria, changes variable "selected_criteria" and calls next Inline Keyboard, 2nd button sends photos based on the variable "selected_criteria".
from aiogram import Bot, Dispatcher, executor, types
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
import os
button1 = InlineKeyboardButton(text="Criteria1", callback_data="Never")
button2 = InlineKeyboardButton(text="Criteria2", callback_data="Gonna")
button3 = InlineKeyboardButton(text="Criteria3", callback_data="Give")
button4 = InlineKeyboardButton(text="Selected Criteria", callback_data="You")
keyboard_inline = InlineKeyboardMarkup().add(button1, button4)
keyboard_inline2 = InlineKeyboardMarkup().add(button2, button4)
keyboard_inline3 = InlineKeyboardMarkup().add(button3, button4)
keyboard_inline4 = InlineKeyboardMarkup().add(button4)
class Handler:
def __init__(self, dp: Dispatcher, chat_id):
self.selected_criteria = ""
self.chat_id = chat_id
self.source_dir = ""
dp.callback_query_handler(
text=["Never", "Gonna", "Give", "You"]
)(self.criteria_selection)
async def criteria_selection(self, call: types.CallbackQuery):
if call.data == "Never":
self.selected_criteria = "1"
await call.message.reply("Choose 2nd Criteria", reply_markup=keyboard_inline2)
if call.data == "Gonna":
self.selected_criteria = self.selected_criteria + "2"
await call.message.reply("Choose 3rd Criteria", reply_markup=keyboard_inline3)
if call.data == "Give":
self.selected_criteria = self.selected_criteria + "3"
await call.message.reply("End Selection", reply_markup=keyboard_inline4)
if call.data == "You":
await call.message.reply(self.selected_criteria)
with os.scandir(self.source_dir) as entries:
for entry in entries:
if entry.name.startswith(self.selected_criteria):
await call.message.answer_photo(photo=open(entry, "rb"))
await call.answer()
bot = Bot(token="")
dp = Dispatcher(bot)
#dp.message_handler(commands=['start', 'help'])
async def welcome(message: types.Message):
handler = Handler(dp, message.chat.id)
await message.reply("Welcome chat_id= " + str(handler.chat_id), reply_markup=keyboard_inline)
await handler.criteria_selection()
executor.start_polling(dp)
Variable source_dir is the folder where I keep all of the photos that I will be sending
The problem is that once there is more than 1 user of the bot, it stops working as intended, because the variable "selected_criteria" is shared between all users.
So if User1 chose all 3 criteria, but before he pushed the button to send photos, someone else chose 1st criteria, User1 is going to receive incorrect photos.
It's my first time doing a telegram bot, so i'm probably doing something wrong, if so please tell me how I can do better.
Related
button = Button(style = discord.ButtonStyle.green, emoji = ":arrow_backward:", custom_id = "button1")
button2 = Button(style = discord.ButtonStyle.green, emoji = ":arrow_up_small:", custom_id = "button2")
button3 = Button(style = discord.ButtonStyle.green, emoji = ":arrow_forward:", custom_id = "button3")
view = View()
view.add_item(button)
view.add_item(button2)
view.add_item(button3)
async def button_callback(interaction):
if number != ("⠀⠀1"):
await message.edit(content="**response 1**")
else:
await message.edit(content="**response 2**")
async def button_callback2(interaction):
if number != ("⠀⠀⠀⠀⠀⠀⠀⠀⠀2"):
await message.edit(content="**response 1**")
else:
await message.edit(content="**response 2**")
async def button_callback3(interaction):
if number != ("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀3"):
await message.edit(content="**response 1**")
else:
await message.edit(content= "**response 2**")
button.callback = button_callback
button2.callback = button_callback2
button3.callback = button_callback3
await message.edit(content= f"⠀⠀:watermelon:⠀⠀⠀⠀⠀:watermelon:⠀⠀⠀⠀⠀:watermelon:\n{number}", view=view)
In the code it creates and sends a message with buttons on it, once you press the button itll either edit the message to say "response1" or "response2" depending if the button had the 1, 2 ,3 over it (if it didnt have the number over it, it prints "response1" if it did have the number over it, it prints "response2") i would like it so when it edits it to either of the responses it also removes the buttons, as it currently doesnt.
Set view=None in your message.edit function call to remove all of the buttons.
recently i created a telegram bot using python and i added keyboard button features to the bot. However, i am having difficulties in getting replies from bot to the buttons users choose.
button7 = KeyboardButton('About Us',request_contact= False)
keyboard2 = ReplyKeyboardMarkup(resize_keyboard = True, one_time_keyboard = True).row(button7)
#dp.message_handler(commands=['info'])
async def mood(message: types.Message):
await message.reply('Do you wish to know about us??', reply_markup=keyboard2)
In this case, i created a button named "About Us" and i want the bot to open a url using webbrowser.open if the user click on that button. Can anyone help me solving this problem?
Try it:
markup = types.InlineKeyboardMarkup()
button1 = types.InlineKeyboardButton(text='Ukraine', url="https://en.wikipedia.org/wiki/Ukraine", callback_data='1')
markup.add(button1)
bot.send_message(message.from_user.id, 'Do you know?, parse_mode='Markdown', reply_markup=markup)
Text (inline button)
from aiogram import Bot, Dispatcher, executor, types
bot = Bot(token='token')
dp = Dispatcher(bot)
#dp.message_handler(commands=['start'])
async def welcome(message: types.Message):
markup = types.InlineKeyboardMarkup()
button1 = types.InlineKeyboardButton(text='Ukraine', url="https://en.wikipedia.org/wiki/Ukraine", callback_data='1')
button2 = types.InlineKeyboardButton(text='Hi bot!', callback_data="1")
markup.add(button1, button2)
await bot.send_message(message.from_user.id, "Do you know?", parse_mode="Markdown", reply_markup=markup)
#dp.callback_query_handler(lambda call: True)
async def sendText(call: types.CallbackQuery):
msg = ""
if call.data == "1":
msg = "Hi, programmer!"
await call.message.edit_text(msg)
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)
I am making a telegram bot on aiogram. Can't pass variables from message.handler to callback.handler. I use FSM, in message.handler state = "waiting_for_address".
The algorithm is => in message.handler, the bot sends inline_keyboard with the "Take" button to the GROUP. When the button is clicked, a callback is sent and the bot visits callback.handler. The state (state = "waiting_for_address") is saved, but only for the user who used the bot. But when we click the button, another user appears and has no state set. If I manually set the state in callback.handler, then the bot stops working.
Tell me, please, how to do it right?
#dp.message_handler(state=Form.waiting_for_address)
async def address_enter(message: types.Message, state: FSMContext):
inline_button = InlineKeyboardButton(text = 'Take order', callback_data='take')
inline_keyboard = types.InlineKeyboardMarkup(resize_keyboard = True, one_time_keyboard=True).add(inline_button)
address = message.text
await state.update_data(myTelephone=await getPhone(mydb,message))
await state.update_data(myAddress=address)
await state.update_data(myId=message.from_user.id)
user_data = await state.get_data()
chatId = '-###'
await bot.send_message(chatId, text=emoji.emojize(f"❗️ <b>New order</b> ❗️\nAddress : <b>{user_data['myAddress']}</b>\nCustomers telephone number : <b>{user_data['myTelephone']}</b>"),parse_mode='html',reply_markup = inline_keyboard)
await message.answer('Your order is sent',parse_mode='html')
#dp.callback_query_handler(lambda call: call.data == 'take' )
async def agree_ref_start(query: types.CallbackQuery, state: FSMContext):
if query.data == 'take':
await query.answer("I am callback!")
await bot.edit_message_text(chat_id=query.message.chat.id, message_id=query.message.message_id, text=emoji.emojize(f"✅ <b>Order is accepted</b> ✅\nАдрес : <b>{user_data['myAddress']}</b>\nCustomer telephone : <b>{user_data['myTelephone']}</b>\nOrder is accepted by #{query.from_user.username}"),parse_mode='html', reply_markup=None)
await bot.send_message(user_data['myId'],f"✅Your order is accepted\nYour telephone number <b>{user_data['myTelephone']}</b>\ndriver id - {query.from_user.id} ",parse_mode='html')
await state.finish()
I am trying to make something that is whenever someone clicks on a button, the bot will send another message.
I searched online and found lots of libraries but every time I try it says interaction failed.
It seems the bot never gets to the wait_for part in halloween.py, and I am wondering if I did anything wrong.
Here is the code for main.py:
import json
import random
import discord
from discord.ext import commands
INITIAL_EXTENSIONS = [
"cogs.default",
"cogs.halloween"
]
bot = commands.Bot(command_prefix="can ")
client = discord.Client()
bot.remove_command("help")
def percentage(percentage):
raw = []
for x in range(percentage):
raw.append(1)
for y in range(100 - percentage):
raw.append(0)
selected = random.choice(raw)
if selected == 1:
return True
else:
return False
def read_JSON(filename):
with open(filename, "r") as f:
return json.load(f)
for extension in INITIAL_EXTENSIONS:
try:
bot.load_extension(extension)
except Exception as e:
print('Failed to load extension {}\n{}: {}'.format(extension, type(e).__name__, e))
if __name__ == '__main__':
bot.run(read_JSON("data.json")["TOKEN"])
And here is halloween.py:
import random
import time
import discord
from discord.ext import commands
from discord_components import *
import main
class Halloween(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.command()
async def checkdoor(self, ctx):
someonethere = main.percentage(100)
await ctx.channel.send("Seeing if anyone is at the door...")
time.sleep(random.randint(1, 2))
if someonethere:
give = Button(style=ButtonStyle.blue, label="Give", id="result")
result = discord.Embed(title=f"You gave!", description="Description", colour=discord.Colour.blue())
await ctx.reply(
embed=there_embed,
components=[
[give]
]
)
buttons = {
"result": result
}
def check(m):
return m.channel == ctx.channel
while True:
event = await main.client.wait_for("button_click", check=check)
if event.channel is not ctx.channel:
return
if event.channel == ctx.channel:
response = buttons.get(event.component.id)
if response is None:
await event.channel.send("Something went wrong. Please try it again")
if event.channel == ctx.channel:
await event.respond(
type=4,
embed=response
)
else:
embed = discord.Embed(
title="Nope",
description="No one's there at your door. Try again later..."
)
return await ctx.reply(embed=embed)
def setup(bot):
bot.add_cog(Halloween(bot))
Thanks,
Edit: I probably should have added that I did all of the following code on repl.it, though I doubt it makes any difference.
Edit 2: I don't know what I did, but now absolutely nothing works. The 'ready' message won't show in the console. It might have to do with the 'keep_alive' file I added in.
So I was going about my day, trying to figure out what the problem is with this snippet of code, until I realized 'Hey, I could try to ask Stack Overflow'!
For context, whenever I run the bot and type in a command (i.e. '!rank'), the bot doesn't seem to recognize the command. The console is just empty of red words, unless I use a nonexisting command. This is the console after I used three commands: '!rank', '!leaderboard', and '!yeet', which purposefully doesn't exist.
In case you're too lazy to open the image, the console goes:
Ignoring exception in command None:
discord.ext.commands.errors.CommandNotFound: Command "yeet" is not found
Here's the code:
from keep_alive import keep_alive
from discord.ext import commands
import discord
import os
import levelsys
cogs = [levelsys]
client = commands.Bot(command_prefix="!", intents = discord.Intents.all())
token = os.environ.get("DISCORD_BOT_SECRET")
client.run(token)
keep_alive()
token = os.environ.get("DISCORD_BOT_SECRET")
client.run(token)
for i in range(len(cogs)):
cogs[i].setup(client)
import discord
from discord.ext import commands
from pymongo import MongoClient
general = [806613968684318720]
level = ["Sperm Whale", "Artillery General", "Commander", "Supreme General",]
levelnum = [1,5,10,15]
cluster = MongoClient("mongodb+srv://[Username]:[Password]#kingdom-kun.lffd9.mongodb.net/Kingdom-kun?retryWrites=true&w=majority")
client = discord.Client
leveling = cluster["discord"]["levelling"]
class levelsys(commands.Cog):
def _init_(self, client):
self.client = client
#commands.Cog.listener()
async def on_ready(self):
print("Kingdom-kun is ready to come!")
#commands.Cog.listener()
async def on_message(self, message):
if message.channel == general:
stats = leveling.find_one({"id" : message.author.id})
if not message.author.bot:
if stats is None:
newuser = {"id": message.author.id, "xp": 100}
leveling.insert_one(newuser)
else:
xp = stats["xp"] +5
leveling.update_one({"id": message.author.id}, {"$set": {"xp"}})
lvl = 0
while True:
if xp < {(50*(lvl**2))+(50*(lvl-1))}:
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 were promoted 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)
#This is rank command
#commands.command()
async def rank(self, ctx):
if ctx.channel.id == general:
stats = leveling.find_one({"id": ctx.author.id})
if stats is None:
embed = discord.Embed(description = "You haven't sent any messages, no rank!!!")
await ctx.channelsned(embed=embed)
else:
xp = stats["xp"]
lvl = 0
rank = 0
while True:
if xp < {(50*(lvl**2))+(50*(lvl-1))}:
break
lvl += 1
xp -= {(50*(lvl-1)**2)+(50*(lvl-1))}
boxes = [(xp/(200*((1/2) * lvl)))*20]
rankings = leveling.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/(200*((1/2)* lvl)))*20}", inline=True)
embed.add_field(name="Rank", value = f"{rank}/{ctx.guild.member_count}", inline=True)
embed.add_field(name="Progress Bar[lvl]", value = boxes * ":blue_square:" * (20-boxes) * ":white_large_square:", inline=False)
embed.set_thumbnail(url=ctx.author.avatar_url)
await ctx.channel.send(embed=embed)
#This is leaderboard command
#commands.command()
async def leaderboard(self, ctx):
if (ctx.channel.id == general):
rankings = leveling.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))
(This is the keep_alive file I added on that somehow screwed everything up)
from flask import Flask
from threading import Thread
app = Flask('')
#app.route('/')
def home():
return "OwO mode pog?"
def run():
app.run(host='0.0.0.0',port=8080)
def keep_alive():
t = Thread(target=run)
t.start()
I've tried a lot of things - changing brackets to parentheses then back again, retyping the entire thing... again, and more, yet nothing changes. If anyone could answer this conundrum, I'd be very thankful.
Anyway, have a nice day!