When writing a bot, I used Inline - keyboard. I found that it was when EXIT (just in the background from the application) and LOGIN (into the application) in Telegram that the response to the button works again, as if it loops. Why is this happening? It seems like it didn't happen before.Is it possible to count on the incorrectness of the Internet or something like that?
It is interesting that anything can be in the body of the function, the code loops in any case...
import telebot
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
bot = telebot.TeleBot(config.TOKEN)
markup = InlineKeyboardMarkup()
markup.row_width = 1
markup.add(InlineKeyboardButton("My Links", callback_data="my_links"))
#bot.callback_query_handler(func=lambda call: call.data == 'my_links')
def myLinks(call):
# ...
# looping code
# ...
bot.polling()
It might be worth trying to replace the lambda function. To be honest, there are no thoughts
Related
So I am making a trading bot the user first have to type "/BUY" for the first command.
And every user have some settings saved up in files so I want them to choose to buy with old settings or new ones.
I tried to put a command instead of a text but that was impractical because anyone can use it without having to go the first one
This is my code for now:
from telebot import types
import telebot
from decouple import config
BOT_TOKEN = config('BOT_TOKEN')
bot = telebot.TeleBot(BOT_TOKEN)
#bot.message_handler(commands=['Start'])
def msg_hndl(message):
print(message)
markup =types.ReplyKeyboardMarkup(one_time_keyboard=True,selective=True)
markup.row_width = 2
button1 =types.InlineKeyboardButton(text="/BUY",callback_data="test",selective=True)
markup.add(button1)
bot.send_message(message.chat.id,"Choose #"+message.from_user.username, reply_markup=markup)
#bot.message_handler(commands=['BUY'])
def msg_hndl(message):
markup2 = types.ReplyKeyboardMarkup(one_time_keyboard=True,selective=True)
markup2.row_width = 2
button1 = types.InlineKeyboardButton(text="/New_settings", callback_data="test")
button2 = types.InlineKeyboardButton(text="/Old_settings", callback_data="test")
markup2.add(button1,button2)
bot.send_message(message.chat.id,"Choose #"+message.from_user.username, reply_markup=markup2)
#bot.message_handler(commands=['New_settings'])
def msg_hndl(message):
#do something
bot.polling()
So I did the research myself and saw the only solution is to save messages and have a message handler that saves the user id and compare it everytime.
first of all, im a beginner.
Want i want to accomplish is that music plays while the script is executing.
What it does right now it plays the music, waits until the music is over and then executes the rest of the code. That is not what i want. Here my Code:
import os
import subprocess
import multiprocessing
import threading
from playsound import playsound
CurrentPath = os.path.dirname(os.path.normpath(__file__))
os.chdir(CurrentPath)
def music():
Music = "Music.mp4"
#subprocess.run(["ffplay", "-nodisp", "-autoexit", "-hide_banner", Music])
playsound("Music.mp4")
def other_things():
print("Hello World")
#musicp = multiprocessing.Process(target=music())
#restp = multiprocessing.Process(target=other_things())
musicp = threading.Thread(target=music())
restp = threading.Thread(target=other_things())
restp.start()
musicp.start()
LIke you can see i even tried multithreading but it still waits until the music is over before it goes to the rest of the code.
Don't call the functions in the target parameter of the Thread function - delete the brackets to reference the function, not its return value
musicp = threading.Thread(target=music) # instead of music()
restp = threading.Thread(target=other_things) # instead of other_things()
I am writing a bot that will give out various media by certain tags. the user writes a request, it is processed and everything found in the database is converted into a list of links of these media, which will then be sent to the user. For example, the script found 100 media satisfying the search query.
how to issue messages in a loop of n messages (for example, n = 10), and to continue issuing, you need to press the inline button? I thought to use AsyncIOScheduler, but as far as I understand, it outputs a cycle over a time interval, but I need exactly the trigger of pressing the button
what do I need to use for this? any scheduler or other handlers?
I was asked to insert a bot initialization block, I don't understand why, if it's standard for any python telegram bot, but okay, here it is
#import block
import asyncio
import string
from asyncio.log import logger
import json
from aiogram.bot.api import TelegramAPIServer
from apscheduler.schedulers.asyncio import AsyncIOScheduler
import logging
import sqlite3
from aiogram.utils.callback_data import CallbackData
from aiogram import Bot, Dispatcher, executor, types
from aiogram.bot import bot
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.contrib.middlewares.logging import LoggingMiddleware
from aiogram.utils.markdown import hlink
import config
from utils import States
# Init block
logging.basicConfig(level=logging.INFO)
bot = Bot(token=config.API_TOKEN)
dp = Dispatcher(bot, storage=MemoryStorage())
dp.middleware.setup(LoggingMiddleware())
cb = CallbackData('id', 'action')
for example, my unfinished code
#dp.message_handler(state=States.S_SEND)
async def senn_media(link_list, message: types.Message):
chat_id = message.chat.id
for length in range(10):
caption1 = ("some text")
media1 = link_list[array]
await bot.send_video(chat_id, media1, caption=caption1, parse_mode="HTML")
I want this command to work in different places at the same time. When I run it on one channel, and my friend runs it on another channel, the command starts to be duplicated when one of us presses the button. I don't click anything, but if my friend clicks on the button in his channel, the message will be sent in both channels.
import random
import string
import discord
from discord_components import DiscordComponents, Button, ButtonStyle
#bot.command()
async def random_screenshot(ctx):
while True:
letters = string.ascii_lowercase + string.digits
rand_string = ''.join(random.choice(letters) for i in range(6))
link = "https://prnt.sc/" + str(rand_string)
await ctx.send(link,
components=[
Button(style=ButtonStyle.blue, label="Next", emoji="➡")])
await bot.wait_for('button_click')
This usually happens with all commands when i use the while loop
The while loop isn't the problem here (though it's a separate problem).
What's happening is that await bot.wait_for("button_click") doesn't care what button is pressed. This means that when the command is run twice, then a button is clicked, both messages respond.
You'll want to make sure that the wait_for only continues if the button is our message's button (instead of another message's button). To do that, you'll need to do two things.
First, we need to generate a random string and set our button's custom id to it. This is so that we can know which button was pressed depending on its custom id. But wait, the discord_components library already generates an ID for us when we create the Button object, so we can just remember its ID like so:
button = Button(style=ButtonStyle.blue, label="Next", emoji="➡")
button_id = button.custom_id
await ctx.send(link, components=[button])
Second, we'll need to pass a function to wait_for as the check keyword argument that only returns True if the button clicked was our button. Something like so:
def check_interaction(interaction):
return interaction.custom_id == button_id
await bot.wait_for("button_click", check=check_interaction)
Now your command should only respond to its own button presses :D
I've been trying to get this working for a long time now and i always get stuck at detecting button presses. I made a toast notification that looks like this:
Here's my code :
import winrt.windows.ui.notifications as notifications
import winrt.windows.data.xml.dom as dom
app = '{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\\WindowsPowerShell\\v1.0\\powershell.exe'
#create notifier
nManager = notifications.ToastNotificationManager
notifier = nManager.create_toast_notifier(app)
#define your notification as string
tString = """
<toast>
<visual>
<binding template='ToastGeneric'>
<text>New notifications</text>
<text>Text</text>
<text>Second text</text>
</binding>
</visual>
<actions>
<action
content="test1"
arguments="test1"
activationType="backround"/>
<action
content="test2"
arguments="test2"
activationType="backround"/>
</actions>
</toast>
"""
print(type(notifier.update))
#convert notification to an XmlDocument
xDoc = dom.XmlDocument()
xDoc.load_xml(tString)
#display notification
notifier.show(notifications.ToastNotification(xDoc))
I don't know how to detect button presses
the only thing i figured out is that if i change the argument of the buttons to a link like this:
arguments="https://google.com"
then it will open it
Is there any way i could implement this? or is there documentation for this XML format these toast notifications use. That explains how arguments work?
Alright so I know It's been a while, but I was trying to figure out the same thing and I couldn't find a good, conclusive answer anywhere. I've finally gotten something to work with WinRT in Python 3.9 so I wanted there to be an answer somewhere that people could find!
So to start, I'm not intimately familiar with how the 'arguments' attribute works, but it doesn't seem to be important for at least simple use cases. Most of what I know came from the Windows Toast docs. Here's some code that should produce a notification and open your Documents folder when you click the button. I got a headstart from an answer in this thread but it was missing some very important steps.
import os,sys,time
import subprocess
import threading
import winrt.windows.ui.notifications as notifications
import winrt.windows.data.xml.dom as dom
# this is not called on the main thread!
def handle_activated(sender, _):
path = os.path.expanduser("~\Documents")
subprocess.Popen('explorer "{}"'.format(path))
def test_notification():
#define your notification as
tString = """
<toast duration="short">
<visual>
<binding template='ToastGeneric'>
<text>New notifications</text>
<text>Text</text>
<text>Second text</text>
</binding>
</visual>
<actions>
<action
content="Test Button!"
arguments=""
activationType="foreground"/>
</actions>
</toast>
"""
#convert notification to an XmlDocument
xDoc = dom.XmlDocument()
xDoc.load_xml(tString)
notification = notifications.ToastNotification(xDoc)
# add the activation token.
notification.add_activated(handle_activated)
#create notifier
nManager = notifications.ToastNotificationManager
#link it to your Python executable (or whatever you want I guess?)
notifier = nManager.create_toast_notifier(sys.executable)
#display notification
notifier.show(notification)
duration = 7 # "short" duration for Toast notifications
# We have to wait for the results from the notification
# If we don't, the program will just continue and maybe even end before a button is clicked
thread = threading.Thread(target=lambda: time.sleep(duration))
thread.start()
print("We can still do things while the notification is displayed")
if __name__=="__main__":
test_notification()
The key thing to note here is that you need to find a way to wait for the response to the notification, since the notification is handled by a different thread than the program that produces it. This is why your "www.google.com" example worked while others didn't, because it didn't have anything to do with the Python program.
There's likely a more elegant solution, but a quick and easy way is to just create a Python thread and wait there for a duration. This way it doesn't interfere with the rest of your program in case you need to be doing something else. If you want your program to wait for a response, use time.sleep(duration) without all the threading code to pause the whole program.
I'm not sure how it works exactly, but it seems like the add_activated function just assigns a callback handler to the next available block in the XML. So if you wanted to add another button, my guess is that you can just do add_activated with another callback handler in the same order as you've listed your buttons.
Edit: I played around with it some and it turns out this lets you click anywhere, not just on the button. Not sure where to go from there but it's worth a heads up.