Telegram Bot Python Inlinekeyboardmarkup does not work for all users in a group - telegram

I want to respond when someone sends the /start comand and display a text with a like/dislike button in a group.
Here is my sample code:
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
Updater,
CommandHandler,
CallbackQueryHandler,
ConversationHandler)
import logging
FIRST, SECOND = range(2)
keyboard = [[InlineKeyboardButton('👍', callback_data='0'),
InlineKeyboardButton('👎', callback_data='2')]]
def start(update, context):
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text(
'Test Message\n',
reply_markup=reply_markup
)
return FIRST
def main():
updater = Updater(
'TOKEN', use_context=True)
dp = updater.dispatcher
conv_handler = ConversationHandler(
entry_points=[CommandHandler('start', start)],
states={
FIRST: [CallbackQueryHandler(a, pattern='^'+str(0)+'$'),
CallbackQueryHandler(b, pattern='^'+str(2)+'$')]
},
fallbacks=[CommandHandler('start', start)]
)
dp.add_handler(conv_handler)
updater.start_polling()
updater.idle()
if __name__ == "__main__":
main()
The callbacks only work for the user who sent the /start command. Other users cannot click the button or there is no callback. if another user sends a /start command, both like/dislike buttons of both posts of the bot work for the two users.
Where is the mistake?
I want every user to be able to press the buttons and it triggers a callback. regardless of whether the user has ever sent the /start command
I am thankful for every help.

The issue here is that by default conversations are per user - please also see this faq entry for details.
For your use case, I doubt that a ConversationHandler gives you any benefit. I would just register the CommandHandler and the CallbackQueryHandler independently.
Disclaimer: I'm currently the maintainer of python-telegram-bot.

Related

How to check if user is already logged-in in pyrogram?

while trying to run a pyrogram script, how to check user is already logged-in in pyrogram or that session is valid ?
So we no need to login again and we can go on next step without login ?
You can use this method to check if your connection to Telegram has not expired or if it was done successfully.
from pyrogram import errors
from pyrogram import Client
app = Client(
...
)
app.connect()
try:
app.get_me()
except (
errors.ActiveUserRequired,
errors.AuthKeyInvalid,
errors.AuthKeyPermEmpty,
errors.AuthKeyUnregistered,
errors.AuthKeyDuplicated,
errors.SessionExpired,
errors.SessionPasswordNeeded,
errors.SessionRevoked,
errors.UserDeactivated,
errors.UserDeactivatedBan,
):
print("Session invalid / Login failed")
else:
print('Login successfully')
app.disconnect()
Chers

Telegram Bot: job_queue.run_repeating cannot properly callback

I have been wrestling with this for a while. I can't seem to get the job_queue.run_repeating to call back a function properly.
My goal is for the user to issue command in the form of /alert to begin running the send_alert function on a fixed interval. I am not sure where I am going wrong despite having looked at at several examples. I can get regular commands to execute just fine, but not JobQueue callbacks.
Currently my code below throws an error on the start_alerts callback, saying NameError: name 'job_queue' is not defined. When I add job_queue accordingly to the function call, such as start_alerts(update, context, job_queue) it no longer updates the "alerts started!" message to my Telegram chat, but it also doesn't throw an error.
from telegram.ext import Updater, CommandHandler, JobQueue
def start_alerts(update, context):
context.bot.send_message(chat_id=update.effective_chat.id, text="alerts started!")
job_queue.run_repeating(send_alert, interval=5.0, first=1.0)
def send_alert(update, context):
message="this is an alert to send"
context.bot.send_message(chat_id=update.effective_chat.id, text=message)
updater = Updater(token=token, use_context=True)
dispatcher = updater.dispatcher
job_queue = updater.job_queue
job_queue.set_dispatcher(dispatcher)
dispatcher.add_handler(CommandHandler('alert', start_alerts))
updater.start_polling()
job_queue.start()
Within the start_alerts function, the variable job_queue is not defined. Use context.job_queue instead as explained in the JobQueue tutorial, the timerbot.py example and the documentation of CallbackContext.

Python-Telegram-Bot ConversationHandler unable to receive Message

I am using the Python-Telegram-Bot Package. My telegram bot is unable to receive a message at state FIRST. After sending my bot /start , I am prompted the text message as shown in start_command. However, after sending a url to the bot, the bot is unable to receive the message as seen in the 'single tick' at the bottom right of my message.
# Stages
FIRST, SECOND = range(2)
def start_command(update: Update, context: CallbackContext):
update.message.reply_text("""
To use:
1. Send the google sheets URL and sheet name to this telegram bot in the following format:
your_google_sheets_url (your_sheet_name)
""")
global user_id
user_id = update.message.from_user['id']
return FIRST
def select(update: Update, context: CallbackContext):
if update.message.text:
user_input = update.message.text
update.message.reply_text('I have received your Google Sheets!')
reply_markup = InlineKeyboardMarkup(build_menu(button_list, n_cols=1))
update.message.reply_text('Please choose the headers:', reply_markup=reply_markup)
return SECOND
dp = updater.dispatcher
dp.add_handler(CommandHandler("start", start_command))
conv_handler = ConversationHandler(
entry_points=[CommandHandler('start', start_command)],
states={
FIRST: [MessageHandler(Filters.text, select)],
SECOND: [CallbackQueryHandler(display)],
},
fallbacks=[CommandHandler('cancel', cancel)],
)
dp.add_handler(conv_handler)
the CommandHandler for start should not be added. This is because when the user inputs /start, the CommandHandler is called to handle the command instead of the ConversationHandler.

Redirect messages to another handler in Telegram bot(telethon library)

I'm trying to make menu with navigation buttons in my telethon bot, so when 'Back' message is sent I want to be able to invoke message handler responsible for previous menu, for example main menu with command '/start'. Is there any funcion like bot.redirect from the code below that would call main_menu(event)?
bot = TelegramClient('bot', BOT_API_ID, BOT_API_HASH).start(
bot_token=BOT_TOKEN)
#bot.on(events.NewMessage(pattern='/start'))
async def main_menu(event):
buttons = [
Button.text("Music"),
...
]
message = 'You are in main menu'
await event.respond(message=message, buttons=buttons)
raise events.StopPropagation
#bot.on(events.NewMessage(pattern='Music'))
async def music(event):
buttons = [
Button.text("Rap"),
Button.text("Hip Hop"),
...
Button.text("Back")
]
message = 'Choose what kind of music you want to find'
await event.respond(message=message, buttons=buttons)
raise events.StopPropagation
#bot.on(events.NewMessage(pattern='Back'))
async def back(event):
prev_menu = get_prev_menu(event.input_chat.user_id) # Teturns '/start' when in 'Music' menu
event.text = prev_menu
bot.redirect(event) # <==========================================
Telethon is a library to interact with Telegram and not much else. Business logic like this should live inside your code, but nothing is stopping you from having a "stack" of functions (here, USER_LOC):
from collections import defaultdict
bot = TelegramClient('bot', BOT_API_ID, BOT_API_HASH).start(
bot_token=BOT_TOKEN)
# Store user locations {user_id: [menu callback]}
USER_LOC = defaultdict(list)
#bot.on(events.NewMessage(pattern='/start'))
async def main_menu(event):
buttons = [
Button.text("Music"),
...
]
message = 'You are in main menu'
await event.respond(message=message, buttons=buttons)
USER_LOC[event.sender_id].append(main_menu) # <- push to stack
raise events.StopPropagation
#bot.on(events.NewMessage(pattern='Music'))
async def music(event):
buttons = [
Button.text("Rap"),
Button.text("Hip Hop"),
...
Button.text("Back")
]
message = 'Choose what kind of music you want to find'
await event.respond(message=message, buttons=buttons)
USER_LOC[event.sender_id].append(music) # <- push to stack
raise events.StopPropagation
#bot.on(events.NewMessage(pattern='Back'))
async def back(event):
stack = USER_LOC[event.sender_id]
if not stack:
return # empty
stack.pop() # ignore second-to-last
if stack:
await stack.pop()(event) # <- pop last pushed callback and call it
You can also write decorators to make it nicer if you want to.

How to get a Telegram Channel Id without sending a message to it

Is there any way to find a telegram channel id without sending a message to it ?
Right now I go this way and find the channel id by calling this URL in my code and get the JSON as result:
https://api.telegram.org/bot???????/sendMessage?chat_id=#?????&text=123
However, this cause sending the message "123" to the channel which is not good.
Check this link for help.
It is using web telegram url param info.
Adding details from the referred link:
log in web telegram
Click on the target channel then you will find the url displayed on your browser.
If it's a public channel, the ID is #name of the channel.
If it's a private channel then the url must be similar to:
https://web.telegram.org/#/im?p=c1018013852_555990343349619165
For this case, the channel ID would be 1018013852.
It's important to know that channel's IDs are always negative and 13 characters long!
So add -100 to it, making the correct ID -1001018013852.
You Can use Web Telegram to see each channel id in link of that page in your explorer
or
Just Simply Forward a message from your channel to This Bot: (https://telegram.me/getidsbot)
Yes, just forward a message of the channel to your bot and get the message.forward_from_chat.id.
Get your channel link
install python library telethon
get your api_id and api_hash here.
write the following code and run:
from telethon import TelegramClient
api_id=
api_hash=
channel_link = 'your_channel_link'
client = TelegramClient(session_name, api_id, api_hash,
update_workers=4, spawn_read_thread=False)
client.start()
entity = client.get_input_entity(**channel_link**)
print(entity.channel_id)
By the way, if you use it for telegram bot, just add -100 before the printed id, this should be work!
You Don't Need to get Channels ID .
simple send Message with Channel User Like : #channel
Fixing #scruel's answer:
In [1]: api_id = ...
In [2]: api_hash = '...'
In [3]: channelLink = 'https://t.me/BTCST_Community_EN'
In [4]: from telethon import TelegramClient, events
In [5]: client = TelegramClient('test', api_id, api_hash)
In [6]: client.start()
Out[6]: <telethon.client.telegramclient.TelegramClient at 0x7fc90c352290>
In [7]: entity = await client.get_entity(channelLink)
In [8]: channelId = '-100' + str(entity.id)
In [9]: channelId
Out[9]: '-1001236496320'
Here's a CLI util to do it:
#!env/bin/python
import sys
import asyncio
from telethon import TelegramClient
import config
async def channel_id_from_link(client, channel_link):
return "-100" + str((await client.get_entity(channel_link)).id)
async def main(channel_link):
async with TelegramClient(
"test", config.api_id, config.api_hash
) as client:
channel_id = await channel_id_from_link(client, channel_link)
return channel_id
if __name__ == "__main__":
channel_link = sys.argv[1]
channel_id = asyncio.run(main(channel_link))
print(channel_id)
Test:
> ./TelegramChannelId.py https://t.me/binance_api_english
-1001134190352
Put your bot into your channel and go to https://api.telegram.org/bot/getUpdates.
If someone send message to that channel, you will get the channel ID there.

Resources