How to forward message from a specific chat in Telethon? - python

This is a continuation of this short forum (How forward message to other contact with telethon).
Problem
I replaced entity with the group id for GC A and it works since I type something in GC B the bot forwards it to GC A however, when I message GC A the bot still forwards the messages to GC A which I don't want, I just want it to not react.
await client.forward_messages(entity, event.message)
The bot forwards every new message because the event type is new messages so I was thinking, is there a way to filter it so that it only triggers when there are new messages on a specific group?
#client.on(events.NewMessage)
async def main(event):
Solutions Ive tried
Looking at the documentation (https://docs.telethon.dev/en/latest/modules/client.html#telethon.client.messages.MessageMethods.forward_messages) there is an example with the argument "from_chat". So I placed the group id of GC B but it doesn't work.
await client.forward_messages(chat, message_id, from_chat)
I also tried making the argument look like this to copy the examples better but It does not work
await client.forward_messages(entity("group ID"), event.message, from_chat("group_id"))

For me worked this code:
#client.on(events.NewMessage(chats = FROM_CHANNEL_ID))
async def main(event):
await event.forward_to(TO_CHAT_ID)
Try it, may it will work for you to.

Related

How to delete a private chat (pyrogram)

i tried pyrogram.raw.functions.messages.DeleteChat but get following trackback
pyrogram.errors.exceptions.bad_request_400.PeerIdInvalid: Telegram says: [400 PEER_ID_INVALID] - The peer id being used is invalid or not known yet. Make sure you meet the peer before interacting with it (caused by "messages.DeleteChat")
account.UpdateNotifySettings has the same problem too.
await client.invoke(UpdateNotifySettings(peer=await client.resolve_peer(cid),settings=InputPeerNotifySettings(silent=True)))
i have read this doc and i am sure that the id is correct for client.archive_chats works well with the same id.
the id is like this 5126101582 is there any another kinds of id or my code is wrong
note:
what i need is like this:
UPDATE
Ok, I THINK I've found a solution for personal chats too!
I was messing around with something else and reading this part of the documentation, I have come up with a way of listing every conversation and their respective id:
from pyrogram import Client
app = Client("my_client")
async def main():
async with app:
async for dialog in app.get_dialogs():
print(str(dialog.chat.id) + " - " + str(dialog.chat.first_name or str(dialog.chat.title)) )
app.run(main())
Basically what it does is loop through all your chats and output their id and "title" in case of a group/channel and a name in case of a chat with a person. You will notice that some ids will be output with a hyphen (-) in front of them, and some won't.
You will need to copy that exact string with or without the hyphen and then you can do this to delete all messages from a chat:
from pyrogram import Client
app = Client("Telecom")
async def main():
await app.start()
async for message in app.get_chat_history("1212345678"):
await app.delete_messages("1212345678", message.id)
app.run(main())
--------------------------- END OF UPDATE ------------------------
I could not understand clearly if you want to delete only the messages of a specific chat or if you want to delete the chat per se.
Anyways, here's what the documentation says:
chat_id (int | str) – Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use “me” or “self”. For a contact that exists in your Telegram address book you can use his phone number (str).
Reference:
Pyrogram Documentation - Delete Messages
Therefore, you cannot delete messages from a chat with the ID, unless it's a channel/bot/group - and since you're receiving this error, I'm assuming you want to delete a chat with a person.
Now, if you are trying to delete, let's say, messages with a channel, there are several ways to retrieve the right ID.
The one I use the most is going to web.telegram and changing it to the "legacy" version.
Once there, click on the chat id you want to delete messages with. You should see something like this:
Telegram URL
you will need the numbers after the "c", and before the underscore.
So let's say my number is c1503123456789_1111111111111
You will use 1503123456789.
You also need to add -100 to it. So the final number will be:
-1001503123456789.
I hope that helps somehow.
Good luck!
you can delete a dialog with leave_chat method.
Leave chat or channel
await app.leave_chat(chat_id)
Leave basic chat and also delete the dialog
await app.leave_chat(chat_id, delete=True)
Bound method leave of Chat.
Use as a shortcut for:
await client.leave_chat(123456789)
Example
await chat.leave()
fine
await client.invoke(DeleteHistory(max_id=0, peer=await client.resolve_peer(cid))
works

Discord Selfbot cant get all members, just part of it

Hey i am trying to get all the users in a specific guide, and i am getting part of the users and not all of them, why?, And i dont care about discord terms, i am not gonna spam servers or something like this so please help instead telling me the discord rules because i am know it well, This is the code i did,
import discord
import asyncio
intents = discord.Intents(messages=True, guilds=True, members=True)
client = discord.Client(intents=intents)
token = ""
#client.event
async def on_ready():
print("Bot Is Ready!")
guild = client.get_guild(328154277111398403)
for member in guild.members:
print(member)
await asyncio.sleep(0.1)
client.run(token, bot=False)
in the context of selfbots/userbots, discord.py doesn't actually have the ability to get the member list (or, at least, a significant portion of it), and therefore is not suited for this task. Instead, you'll either have to use a different library or code your own solution. Keep on reading for some code :)
Code:
A python lib with this support is discum.
Here's the least amount of code required to get the member list with discum:
import discum
bot = discum.Client(token='blah blah blah')
#bot.gateway.command
def helloworld(resp):
if resp.event.ready_supplemental:
bot.gateway.fetchMembers("GUILD_ID_HERE", "CHANNEL_ID_HERE")
bot.gateway.run()
And here's another example that creates a function called get_members that returns the member list: https://github.com/Merubokkusu/Discord-S.C.U.M/blob/master/examples/gettingGuildMembers.py
And here are more examples:
https://github.com/Merubokkusu/Discord-S.C.U.M/blob/master/docs/fetchingGuildMembers.md
How does it work?
Since we can't request for the member list the same way bot accounts can, we instead need to exploit the member list (yea, that members sidebar on the right that you see when going to a guild). We need to read that entire thing, piece by piece.
Essentially how it's done is the client first subscribes to member events in a channel in a guild (Luna somewhat went over this in her unofficial discord docs, but left out a lot). Then, as the user scrolls through the member list, more lazy requests are sent to get each chunk of the member list. And this is what happens in discum: lazy requests are sent until the entire member list is fetched. Here's some more info.

How does discord.py detect that a message is sent using just a coroutine which is being defined in the code itself?

I am a intermediate python programmer and just started coding discord bots using the discord.py module. One question that always revolves around my head is, how does the module detect that a message is sent using on_message() coroutine which is declared in our code and no such detection construct is there?
async def on_message(mssg):
#our conditions and responses
Consider the above code. Is there an equivalent predefined coroutine in the module that calls when we declare the on_message() in our code or is there something else that makes it to detect messages and pass it to the function argument, or detect any other event? On youtube or elsewhere, they just make you learn the syntax for some reason that you have to use async...await from the documentation.
so if memory serves me correct, the on_message() is what calls the bot to listen to each message that is sent, every time a message is sent. So with your code there:
async def on_message(mssg):
#our conditions and responses
we can actually dress that up a bit with some inter-workings, like so:
#bot.listen('on_message')
it's a bot event, so every-time a message is sent, this function is called.
async def stuff(message):
pass message so that the bot knows what to scan.
if message.content.startswith("buttlerprefix"):
start it off with an if statement so that the bot has something to check the user's message against
If I typed buttlerprefix and hit enter, it would respond with this message:
msg = await message.channel.send("my prefix is `>`")
if you want to go an extra step, and keep the channels declutterd, you can set the response equal to a variable msg in the event that you want to manipulate it later, thus in this scenario, it's set to auto delete with
await asyncio.sleep(10)
await msg.delete()
So if we put all of that together:
#bot.listen('on_message')
async def stuff(message):
if message.content.startswith("buttlerprefix"):
msg = await message.channel.send("my prefix is `>`")
await asyncio.sleep(10)
await msg.delete()
we get a function that is now scanning every message that comes through the guild that this bot functions in, no matter the channel, due to the on_message() function being called every-time a message is sent which is triggered by the #bot.listen

How do I make a bot write a certain message when it first joins a server?

I want my Discord bot to send a certain message, For example: "Hello" when he joins a new server. The bot should search for the top channel to write to and then send the message there.
i saw this, but this isn't helpful to me
async def on_guild_join(guild):
general = find(lambda x: x.name == 'general', guild.text_channels)
if general and general.permissions_for(guild.me).send_messages:
await general.send('Hello {}!'.format(guild.name))```
The code you used is actually very helpful, as it contains all of the building blocks you need:
The on_guild_join event
The list of all channels in order from top to bottom (according to the official reference). If you want to get the "top channel" you can therefore just use guild.text_channels[0]
checking the permissions of said channel
async def on_guild_join(guild):
general = guild.text_channels[0]
if general and general.permissions_for(guild.me).send_messages:
await general.send('Hello {}!'.format(guild.name))
else:
# raise an error
Now one problem you might encounter is the fact that if the top channel is something like an announcement channel, you might not have permissions to message in it. So logically you would want to try the next channel and if that doesn't work, the next etc. You can do this in a normal for loop:
async def on_guild_join(guild):
for general in guild.text_channels:
if general and general.permissions_for(guild.me).send_messages:
await general.send('Hello {}!'.format(guild.name))
return
print('I could not send a message in any channel!')
So in actuality, the piece of code you said was "not useful" was actually the key to doing the thing you want. Next time please be concise and say what of it is not useful instead of just saying "This whole thing is not useful because it does not do the thing I want".

on_reaction_add not being run

I'm new to discord.py and trying to make a translator bot. When the user reacts with a certain flag, the bot translates it, but the event is never getting called hence I have no code to translate any messages yet. I know it's not getting called because the program isn't printing an 'x' to the console.
#client.event
async def on_reaction_add(reaction, user):
channel = reaction.message.channel
print('x')
await client.send_message(channel, '{} has added {} to the the message {}'.format(user.name, reaction.emoji, reaction.message.content))
await client.process_commands(reaction.message)
Probably a bit late to this thread but, the answer above is a valid answer. But you can also use on_raw_reaction_add which gets called even if the messages aren't in the Bot's cache.
Called when a message has a reaction added. Unlike on_reaction_add(), this is called regardless of the state of the internal message cache.
Documentation Link
Example:
#commands.Cog.listener()
async def on_raw_reaction_add(self, payload):
channel = await self.bot.fetch_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
user = await self.bot.fetch_user(payload.user_id)
emoji = payload.emoji
await channel.send("Hello")
There isn't much valid reason for why the event isn't registered/called.
One of which is stated in the docs: http://discordpy.readthedocs.io/en/async/api.html#discord.on_reaction_add. Try adding a reaction immediately to a message that is sent after the bot is online. Since messages sent before the bot is online will not be recognized by the bot (not in Client.messages).
if the message is not found in the Client.messages cache, then this
event will not be called.
Another possible reason is that this function was never defined before the client loop commenced. Verify your indentation. And/Or try placing the function directly under client = Bot(...), to check if this is the problem.
If neither of the aforementioned solves your problem, please post a minimal, complete, verifiable example (a short runnable code from top to bottom that indicates your problem).

Categories