How to handle a Telegram_bot conversation in Python? - python

I'm writing a simple telegram bot to accept a word as input and return a message inlcuding a Youtube link based on that word.
The bot should look for the word after the '/search' command is invoked but here it's using every word sent to the chat.
Please can you help me to fix it?
import logging
from telegram import Update
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters
import random
import re
import urllib.request
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO
)
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id, text="I'm a bot, please talk to me!")
async def search(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Search a single word"""
await update.message.reply_text("Type a single word")
return short_reply
async def short_reply(update: Update, context: ContextTypes.DEFAULT_TYPE):
word = update.message.text
html = urllib.request.urlopen("https://www.youtube.com/results?search_query=" + word)
video_ids = re.findall(r"watch\?v=(\S{11})", html.read().decode())
await context.bot.send_message(chat_id=update.effective_chat.id, text=f"https://www.youtube.com/watch?v=" + video_ids[random.randrange(1,20)])
return start
if __name__ == '__main__':
application = ApplicationBuilder().token('TOKEN').build()
start_handler = CommandHandler('start', start)
application.add_handler(start_handler)
search_handler = CommandHandler('search', search)
application.add_handler(search_handler)
short_reply_handler = MessageHandler(filters.TEXT, short_reply)
application.add_handler(short_reply_handler)
application.run_polling()
I even tried to add other functions as a sort of 'keywords menu' but i encountered the same problem: the bot will immediately reply with "I didn't undestand your command" because it's always reading the message sent right before the function invocation (the function/command invocation itself).
async def edit_tags(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id, text="ADD/REMOVE?")
msg = update.message.text
if msg == 'ADD':
await context.bot.send_message(chat_id=update.effective_chat.id, text="Write a keyword")
keyword = update.message.text
print(keyword)
elif msg == 'REMOVE':
await context.bot.send_message(chat_id=update.effective_chat.id, text="Remove")
pass
else:
await context.bot.send_message(chat_id=update.effective_chat.id, text="I didn't undestand your command")
tags_handler = MessageHandler(filters.TEXT, edit_tags)
application.add_handler(tags_handler)

Related

How to make "back" button in aiogram? - python

I need to make working "back" button in aiogram that returns to /start menu.
I know what's my mistake is, but I have no idea how to fix it. Can someone help?
back_button = InlineKeyboardButton(text = "back", callback_data="bk")
keyboard_back = InlineKeyboardMarkup().add(back_button)
#dp.message_handler(commands=['start', 'help'])
async def send_welcome(message: types.Message):
return await bot.send_message(message.from_user.id, text="Hello!\nI'm WriteEssayBot!\nI will write any essay for you!", reply_markup = keyboard_inline)
#dp.callback_query_handler()
async def generate_text(call: types.CallbackQuery):
await bot.answer_callback_query(call.id)
if call.data == "bk":
await send_welcome() ```

How do i keep my class variable exclusive for every user?

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.

telegram bot reply message for 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)

Wait_for and buttons not working for discord bot

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,

getting a discord bot to ignore all incoming inputs after detecting spam

im working on a discord bot that responds to keywords with some text and an image, as you can imagine this would create a lot of opportunities to use the bot to spam and I would like to create a system in the code that allows the program to stop accepting all inputs once spamming is detected, I managed to create a system to detect the spam using time stamps but so far it does nothing, as I cannot figure out the code for what I need to do.
this is my code so far:
import os
import discord
import datetime
import time
from keep_on import keep_on
bot_token = os.environ['TOKEN']
client = discord.Client()
#client.event
async def on_ready():
print('{0.user} is online'.format(client))
print('###########################################')
enabled = True
time_storage = int(datetime.datetime.utcnow().timestamp())
#client.event
async def on_message(message):
global enabled
global time_storage
sentWord = message.content
CSentWord = sentWord.upper()
if message.content == "!start":
enabled = True
await message.channel.send("Having Trouble?")
await message.channel.send(file=discord.File('Having trouble.png'))
elif message.content == "!stop":
enabled = False
await message.channel.send("Ok Ill Stop.")
await message.channel.send(file=discord.File('Joey will stop.png'))
elif enabled == True:
if message.author == client.user:
return
if "SORRY" in CSentWord:
time.sleep(0.5)
time_delay = int(datetime.datetime.utcnow().timestamp())
time_difference = time_delay - time_storage
print('time since last stored:',time_storage)
print('time now:',time_delay)
print('time difference:',time_difference)
print('###########################################')
if time_difference < 5:
await message.channel.send("You are moving too fast")
await message.channel.send(file=discord.File('Bruh what.png'))
time.sleep(2)
return
await message.channel.send("'We're Very Sorry' - Joey Tribbiani")
await message.channel.send(file=discord.File('Joey Is Sorry.png'))
time_storage = int(datetime.datetime.utcnow().timestamp())
keep_on()
client.run(os.getenv('TOKEN'))
You can add cooldowns to commands using
#commands.cooldown(1, 10, commands.BucketType.user)
For example here the user can use a command once every 10 seconds

Categories