Why doesn't FSM(state) work with channel_post_handler? - python

When you click on the button, the bot sends a message asking you to specify the name(I'm sending the name in response) by writing message_data (for example), then the post handler in the channel should be called via state, but this does not happen (the code does not send the last print "test handler"). If you use it without state, everything works, just as if you use it in the bot itself via message_handler, everything works too. Why doesn't it work and how can I use FSM for messages in the channel, because I need to save several consecutive messages from there when I press the button.
#dp.callback_query_handler(text='test_video')
async def test_video(call: types.CallbackQuery, state: FSMContext):
message_data = await bot.send_message(chat_id=call.message.chat.id, text='OK now send me the title', reply_markup= ikb_back)
async with state.proxy() as data:
data['message_data'] = message_data
print("test set") # sends
await astate.Admin_State.test_video.name.set()
#dp.channel_post_handler(state=astate.Admin_State.test_video.name)
async def print_test_video(message: types.Message, state: FSMContext):
print("test handler") # does not send

Related

For a discord.py slash command that iterates the bot asnwer, how can I make it not show that "Tap to see attachment" above the messages?

I have a discord.py command that makes feeds of memes, but when I use the command, all the images sent by the bot with exception of the first one have a "tap to see attachment" as if they were a response to the first image, is it possible to make it not appear? If so, how?
#bot.hybrid_command(name = "command", with_app_command = True, description = "description")
async def test1(ctx, number: int):
i = 0
while i < number:
await ctx.send("Message")
i = i+1
await asyncio.sleep(5)
ctx.send will either try to respond to the interaction, followups to the response if a response has been given, or just send if the interaction has expired. I believe the behaviour you're seeing is expected.
If you change your ctx.send to ctx.channel.send then that should act like a more regular send.
We can also add a defer to prevent discord saying we didn't respond whilst we sent lots of messages, and then use ctx.send at the end to finally respond and tell the user we're done. Using ephemeral=True means that we only send the message to the user that initiated the command.
async def test1(ctx, number: int):
# defer the interaction to prevent "bot didn't respond" messages
await ctx.defer(ephemeral=True)
# do the rest of your code here
# once you're done sending lots of messages
await ctx.send("Finished meme feed", ephemeral=True)

How do I make my discord bot send this message to a specific channel?

Here is my code, I need it to send the response to a specific channel. Can't seem to find how to do it anywhere in the API.
#bot.tree.command(name='training', description='Set up a training date & announce it to everyone in the server')
#app_commands.describe(date = "Date")
#app_commands.describe(time = "Time")
#app_commands.describe(location = "Location")
async def say(interaction: discord.Interaction, date: str, time: str, location: str):
await interaction.response.send_message(f"{interaction.user.mention} is training at {location} on {date} at {time}")
I've tried changing the "interaction.response.send_message" into "channel.send" but that gave back an error with the atr: send
You need to have the channel ID somewhere - and then fetch that channel object when the interaction is invoked and then send the message.
The docs:
Interaction object
Guild object
Channel object
interaction response object
MY_CHANNEL_ID = 123455678
#bot.tree.command(name='training', description='Set up a training date & announce it to everyone in the server')
#app_commands.describe(date = "Date")
#app_commands.describe(time = "Time")
#app_commands.describe(location = "Location")
async def say(interaction: discord.Interaction, date: str, time: str, location: str):
my_channel = await interaction.guild.fetch_channel(MY_CHANNEL_ID)
# could also do it this way if the command can be used outside a guild context
# my_channel = await bot.fetch_channel(MY_CHANNEL_ID)
await my_channel.send(f"{interaction.user.mention} is training at {location} on {date} at {time}")```
# make sure we notify the user that we did what they wanted to do and respond
await interaction.response.send_message("Done the thing", ephemeral=True)
To get the Channel ID follow this guide and right-click on the channel you want to send the message to.

Disnake/discord.py indefinitely await reponse

When I create a button and handle the callback or send a message and await a reaction in discord with my python bot, this seems to be limited in time. Sometimes after ~ 1hour, the bot doesn't register reactions anymore. For sure once I restart the bot, the connection is lost and it won't register the interaction anymore.
However, I have seen bots in discord that always react to a button, no matter how long ago that button was created. Is there a way to achieve this? Do I have to periodically "reconnect" the bot to the buttons it created?
Simple example:
class ButtonView(disnake.ui.View):
def __init__(self):
super().__init__(timeout=None)
#disnake.ui.button(label="Hi", style=ButtonStyle.red)
async def first_button(
self, button: disnake.ui.Button, interaction: disnake.MessageInteraction
):
await interaction.response.send_message("Button clicked.")
class Test(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
#commands.slash_command()
async def test(self, inter):
await inter.send("Button!", view=ButtonView())
-> In this example the bot won't react to the button click anymore after some time has passed or I restarted the bot.
You can do like this :
import disnake
from disnake.ext import commands
# Define a simple View that persists between bot restarts
# In order a view to persist between restarts it needs to meet the following conditions:
# 1) The timeout of the View has to be set to None
# 2) Every item in the View has to have a custom_id set
# It is recommended that the custom_id be sufficiently unique to
# prevent conflicts with other buttons the bot sends.
# For this example the custom_id is prefixed with the name of the bot.
# Note that custom_ids can only be up to 100 characters long.
class PersistentView(disnake.ui.View):
def __init__(self):
super().__init__(timeout=None)
#disnake.ui.button(
label="Green", style=disnake.ButtonStyle.green, custom_id="persistent_view:green"
)
async def green(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
await interaction.response.send_message("This is green.", ephemeral=True)
#disnake.ui.button(label="Red", style=disnake.ButtonStyle.red, custom_id="persistent_view:red")
async def red(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
await interaction.response.send_message("This is red.", ephemeral=True)
#disnake.ui.button(
label="Grey", style=disnake.ButtonStyle.grey, custom_id="persistent_view:grey"
)
async def grey(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
await interaction.response.send_message("This is grey.", ephemeral=True)
class PersistentViewBot(commands.Bot):
def __init__(self):
super().__init__(command_prefix=commands.when_mentioned)
self.persistent_views_added = False
async def on_ready(self):
if not self.persistent_views_added:
# Register the persistent view for listening here.
# Note that this does not send the view to any message.
# In order to do this you need to first send a message with the View, which is shown below.
# If you have the message_id you can also pass it as a keyword argument, but for this example
# we don't have one.
self.add_view(PersistentView())
self.persistent_views_added = True
print(f"Logged in as {self.user} (ID: {self.user.id})")
print("------")
bot = PersistentViewBot()
#bot.command()
#commands.is_owner()
async def prepare(ctx: commands.Context):
"""Starts a persistent view."""
# In order for a persistent view to be listened to, it needs to be sent to an actual message.
# Call this method once just to store it somewhere.
# In a more complicated program you might fetch the message_id from a database for use later.
# However this is outside of the scope of this simple example.
await ctx.send("What's your favourite colour?", view=PersistentView())
bot.run("token")
This code comes from disnake repository
I think it's most likely that your internet has a connection issue, and that you're disconnecting without noticing.
That was happening to me, so I added on_disconnect and on_resumed bot events that were just simple print statements so that I would be able to check on if that was the source of the issue.
bot: commands.Bot = commands.Bot(command_prefix='.', intents=intents)
bot.time = time.time()
#bot.event
async def on_ready():
print(f"Logged in as {bot.user} (ID: {bot.user.id})")
print('TesterBot is ready starting at ' + time.ctime(bot.time))
#bot.event
async def on_disconnect():
uptimedelta = time.time() - bot.time
print('TesterBot is disconnected at ' + time.ctime(bot.time) + '. Testerbot has been up for ' + str(datetime.timedelta(seconds=uptimedelta)))
#bot.event
async def on_resumed():
uptimedelta = time.time() - bot.time
print("TesterBot reconnected " + time.ctime(bot.time) + '. Testerbot has been up for ' + str(datetime.timedelta(seconds=uptimedelta)))
#bot.event
async def on_connect():
print('TesterBot is connected starting at ' + time.ctime(time.time()))
Just basic stuff like that helped reveal that the problem was that my machine was dropping the connection. It was a physical issue with my internet, not a coding error or misunderstanding of the api or library.
await inter.response.defer(enter image description here)

how to send albums as new messages in telethon

I want to send every new message from one channel to another.
But when there are albums in the message, they are sent separately to the destination channel.
How can I send them as an album (as one message)?
#client.on(events.NewMessage('your_channel'))
async def my_event_handler(event):
await client.send_message('my_channel', event.message)
And I used events.album instead of events.NewMessage, but it didn't work!
I find a simple way, maybe someone will use it
#client.on(events.Album(chats="your_channel"))
async def handler(event):
await client.send_message(
"my_channel", #output channel
file=event.messages, #list of messages
message=event.original_update.message.message, #caption
)

sending notification to one user using Channels 2

I want to send notification to specific authenticated user using Channels 2.
In below code i am sending notification as a broadcast instead of that i want to send notification to a specific user.
from channels.generic.websocket import AsyncJsonWebsocketConsumer
class NotifyConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
await self.accept()
await self.channel_layer.group_add("gossip", self.channel_name)
print(f"Added {self.channel_name} channel to gossip")
async def disconnect(self, close_code):
await self.channel_layer.group_discard("gossip", self.channel_name)
print(f"Removed {self.channel_name} channel to gossip")
async def user_gossip(self, event):
await self.send_json(event)
print(f"Got message {event} at {self.channel_name}")
Most users new to Django-channels 2.x face this problem. let me explain.
self.channel_layer.group_add("gossip", self.channel_name) takes two arguments: room_name and channel_name
When you connect from your browser via socket to this consumer, you are creating a new socket connection called as channel. So, when you open multiple pages in your browser, multiple channels are created. Each channel has a unique Id/name : channel_name
room is a group of channels. If anyone sends a message to the room, all channels in that room will receive that message.
So, if you need to send a notification/message to a single user, then you must create a room only for that particular user.
Assuming that current user is passed in the consumer's scope.
self.user = self.scope["user"]
self.user_room_name = "notif_room_for_user_"+str(self.user.id) ##Notification room name
await self.channel_layer.group_add(
self.user_room_name,
self.channel_name
)
Whenever you send/broadcast a message to user_room_name, It will only be received by that user.

Categories

Resources