So, I'm kinda new creating bots with Python. I'm using PyPI(PY Telegram Bot). I've been learning a lot during these days and it even started working. While using MessageHandler I could pretty much send a message and the bot would return me a text or a picture.
But now I want something different. I want to start creating a game for Telegram, still to learn more on how to use the library.
The thing is: eveytime I want the bot to answer me, it doesn't work. Basically when entering the rockpaperscissors function, I want it to show a text asking for an option, then, whatever this answer is leads me to an answer by the bot. But whenever I answer, the bot never answers back.
Just an example of what happens:
And here is the source code. I excluded the superfluous sections so it wouldn't be that messy. Any help is appreciated :)
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, ConversationHandler, CallbackContext
import random
def rockpaperscissors(update, context):
update.message.reply_text('Rock, paper, scissors. Return an option')
msgUsr = str(update.message.text)
if msgUser == "rock":
update.message.reply_text("You chose 'rock'")
def main():
token ='(token)'
updater = Updater(token=token, use_context=True)
dispatcher.add_handler(CommandHandler('rps',rockpaperscissors))
updater.start_polling()
updater.idle()
if __name__ == "__main__":
main()
Your bot is expecting a command /rps, and responding correctly. However, when you send a plain message (rather than a command), the bot just doesn't know what to do. Note that the function rockpaperscissors is only called when the user sends a message starting with /rps or /rps#yourbot , but it never equals to "rock". So your if will never be executed.
You must add a MessageHandler and associate another function to, well, handle the message.
Related
I want to get the user that was mentioned in a message and send him a private message. That's working without problems, but now I want to add a message for the case, that the mentioned member is not on the same server.
I searched a lot and try now for over 3 hours to find a solution.
Showcase of the problem: https://youtu.be/PYZMVXYtxpE
Heres my code:
#bot.event
async def on_message(message):
if len(message.mentions) == 1:
membe1 = message.mentions[0].id
membe2 = bot.get_user(membe1)
guild = bot.get_guild(message.author.guild.id)
if guild.get_member(membe1) is not None:
await membe2.send(content=f"you was mentioned in the server chat")
else:
embed2 = discord.Embed(title=f"ยป :warning: | PING not possible", description=f"not possible")
await message.channel.send(content=f"{message.author.mention}", embed=embed)
await message.delete()
return
The first part is working without problems, but at the "else" part, does the bot nothing. He still posts the message with the "invalid" ping in the chat and just ignores it. What can I do to fix that?
There is an error of design in what you are trying to do.
In Discord, you are not able to mention a user if he is not on that same server, so what you are checking will never work at all, currently your code is pretty much checking if the mentioned user exists, which will always happen unless he leaves the guild at the same time the command is executed.
Say for example, to make your command work you want to mention the user user123, who is in your server, you do the following:
#user123 blablabla
And that works because Discord internal cache can find user123 in your server and it is mentioned, which means that clicking on "#user123" will show us a target with his avatar, his roles or whatsoever.
But if you try to do the same for an invalid user, let's say notuser321:
#notuser321 blablabla
This is not a mention, take for example that you know who notuser321 is but he is in the same server as the bot is. Discord cannot retrieve this user from the cache and it is not considered a mention, just a single string, so not a single part of your code will be triggered, because len(message.mentions) will be 0.
Something that you could try would be using regular expressions to find an attempt to tag within message.content. An example would be something like this:
import re
message = "I love #user1 and #user2"
mention_attempt = re.findall(r'[#]\S*', message) # ['#user1', '#user2']
Is there a Python Client-Side API for Discord?
I don't need much, just to listen to events like getting a call or a message.
Is it possible?
Note that selfbots are against TOS, and you could be banned without warning.
Sounds like you want a selfbot.
What you might be looking for is Discord.py, many selfbots are written in that, such as:
https://github.com/appu1232/Discord-Selfbot
If you would rather not get banned, discord.py is still good for scripting bots for servers.
Ok late answer but maybe someone can benefit from it so here goes.
Never use discord.py for selfbots. Discord.py was created to work on bot accounts not user accounts. That being said, a lot of things in discord.py will flag your account.
If you want, you can use what I'm currently developing with Merubokkusu: discum: discord selfbot api wrapper
Here's the classic ping-pong example:
import discum
bot=discum.Client(token=yourtoken)
#bot.gateway.command
def pingpong(resp):
if resp.event.message:
m = resp.parsed.auto()
if m['content'] == 'ping':
bot.sendMessage(m['channel_id'], 'pong')
bot.gateway.run()
Here's a ping-pong example where you don't reply to yourself:
import discum
bot=discum.Client(token=yourtoken)
#bot.gateway.command
def pingpong(resp):
if resp.event.message:
m = resp.parsed.auto()
if m['author']['id'] != bot.gateway.session.user['id']
if m['content'] == 'ping':
bot.sendMessage(m['channel_id'], 'pong')
bot.gateway.run()
here's another example, this one appends live messages to a list:
import discum
bot=discum.Client(token=yourtoken)
messagelist = []
#bot.gateway.command
def pingpong(resp):
if resp.event.message:
messagelist.append(resp.raw)
bot.gateway.run()
Also, if you're just doing this in the terminal and don't want to reinitialize your gateway every time, you can just clear the commands you've set
bot.gateway.clearCommands()
and clear the current (gateway) session variables
bot.gateway.resetSession()
Discum is intended to be a raw wrapper in order to give the developer maximum freedom. It's also written to be relatively-simple, easy to build-on, and easy-to-use. Hope this helps someone! Happy coding!
I'm using python-telegram-bot and I need to process the output of a reply keyboard to use this in further steps (e.g., to return to the user an output based on her choice).
This is my code
def start(update, context):
reply_keyboard = [['Boy', 'Girl', 'Other']]
update.message.reply_text(
'Hi! My name is Professor Bot. I will hold a conversation with you. '
'Send /cancel to stop talking to me.\n\n'
'Are you a boy or a girl?',
reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
How can I use user's choice to return data based on it? The code above just print the choice to the chat.
I can see that you're referring to the example conversationbot.py from python-telegram-bot's GitHub.
When user selects a choice from ReplyKeyboard, it'll be sent as a message to bot. So you've to pickup that message. For this you've to use ConversationHandler where you can define stages/states for a conversation.
Look at the same example you're referring to. The entry point to ConversationHandler here is /start command. Then the bot replies with the keyboard. The next stage here is GENDER (you can see return GENDER in start function). Here MessageHandler is used with regex and the callback function is gender(). When user selects from the choice, the bot matches the reply with ^(Boy|Girl|Other)$ and this calls gender() function if it's true. Similarly the further states in ConversationHandler will proceed.
Finally, ConversationHandler will end when it reaches the last state or when /cancel (fallback) is sent.
I am not familiar with Discord bots or much of Python so here's a simple question I can't figure out the answer to.
I have two files; discord_bot.py and test.py
How do I forward a message from test.py to send it to a channel in Discord?
test.py
import discord_bot
discord_bot.signal(msg = "Hi")
discord_bot.py
import discord
from discord.ext import commands
TOKEN = '1234567890'
bot = commands.Bot(command_prefix='!')
#bot.command()
async def signal(ctx, *, msg):
await ctx.send(msg)
The Discord bot works fine but calling the signal function from test is not the correct way to do it. Any help here please?
This is a lot to unpack.
0. Never post your discord token online. Discord may automatically invalidate your token if it's posted online.
1. You are not running your bot at the moment, add bot.run(TOKEN) at the end
2. How the commands of the discord bot extension work
#bot.command() is a decorator, if you do not know how they work, read up on it. Overly simplified, they take your function and register in the bot.
The inner workings of the commands extension are basically:
Register all commands by loading the decorators
Whenever a message arrives, check if it contains a prefix and if so, check if it fits a command.
If both checks from 2 passed, construct a Context object, then pass that object to the function. Something like the following:
signal(ctx, *args)
This is why the ctx object can't be positional, because the way the function is called in the inner workings of the bot as a normal argument.
4. Do not try to mess with creating your own context object, unless you know what you're doing. You only need to create context objects if you're overriding the default message parser.
5. Don't use commands for this.
What you want to do, as far as I can tell:
Call a command yourself. This is easy enough:
file 1:
#bot.command()
async def signal(ctx, *, msg):
print(msg)
file 2:
from file1 import signal
import asyncio # if you don't know asyncio, read up on it
asyncio.run(signal(None, 'This is an argument'))
This works easily, it prints your stuff. But you don't want it to be printed, right? You want it to be sent in a channel. This is what you need the context object for, which I said before, to not construct yourself. So how do we actually do this?
The answer is: Don't use commands. They are used for reacting to messages, not to be called by themselves.
6. The solution you (probably) want
So the major changes here are:
signal is now a normal async function with no decorator
We actually specify a channel where we want the stuff to be sent in as an argument of the function
file 1:
import discord
from discord.ext import commands
TOKEN = 'do not share your token online'
bot = commands.Bot(command_prefix='!')
# as the channel_id, pass the channel_id you want the message to be sent in
async def signal(msg, channel_id):
global bot # getting our bot variable from the global context
channel = bot.get_channel(channel_id)
await channel.send(msg)
bot.run(TOKEN)
Major changes here are:
We use asyncio.run to call the function. Async functions cannot be called with regular syntax.
You'll probably need to run file2.py to start the program. Running file1 will not load file2.
file 2
from file1 import signal
from time import sleep
import asyncio
sleep(5) # We need to give our bot time to log in, or it won't work
asyncio.run(signal('hi!', 123))
I am new to Telegram Bot API (python telegram.ext), here is my question: I am trying to send formatted message in reply to received message. For simplicity I removed everything from the code below
mtxt = "<ul><li>line 1</li></ul>"
res = bot.send_message(chat_id=update.message.chat_id, text=mtxt, parse_mode='HTML')
print(res)
Nothing is returned to telegram (no answer from bot) and print() never happens. If I remove 'parse_mode...' clause from the call it works.
I must be fundamentally wrong somewhere... This is very basic staff, what is missing?
There only have limited tags :(
You can use emoji to format, or make a suggestion to Telegram.