Sending message to all user (dm off failure) - python

The issue im having here is when the bot is cycling through the members and its sending the message, when a user has the dms off it just stops going through them.
I would like it so it keeps going through the members after hitting a member with dms off.
CODE:
#client.command()
async def pd(ctx):
try:
for m in client.get_all_members():
await m.send(ad)
print(f"received the ad")
except:
print(f" has [DM] `off`")
This is what it looks like after hitting a member with dms off.
TERMINAL:
bot is now online
received the ad
received the ad
received the ad
received the ad
has [DM] `off`
Thank you!

The reason your code is not working is because whenever you get an error, the loop is broken, and execution continues from the except: block.
You can fix this simply by putting the try: and except: inside the loop.
#client.command()
async def pd(ctx):
# Iterates over each member
for m in client.get_all_members():
# Try sending the message to the member
try:
await m.send(ad)
print(f"received the ad")
# If an error is produced, log it.
# After this, the loop will continue onto
# the next member.
except:
print(f" has [DM] `off`")

OK! So I figured out the issue I had. I needed to move
try:
Down a line to make it inside the loop
EXAMPLE:
#client.command()
async def pd(ctx):
for m in client.get_all_members():
try:
await m.send(ad)
print(f"received the ad")
except:
print(f" has [DM] `off`")
print("finished sending ads")

Related

Discord.py || How to loop a part of Program infinite times without crashing it eventually?

I am Trying to Make a 24/7 Streaming Discord Bot using while(True): Infinite Loop,
But I think that the while(True): will get crashed by the OS (Using Heroku for Hosting) or Some kind of threads problem
#commands.command(name='play',aliases=["p"])
async def _play(self, ctx: commands.Context):
i = 0
while(True): #Infinite While Loop
search = URL[i] #URL is the List of Musics I What to Stream 24/7
if not ctx.voice_state.voice:
await ctx.invoke(self._join) #joins the voice channel if not in voice channel previously
async with ctx.typing():
try:
source = await YTDLSource.create_source(ctx, search, loop=self.bot.loop)
#Sets the Status of the Bot to What Music it is Playing Currently
await self.bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=f"{source.title}"))
except YTDLError as e:
await ctx.send('An error occurred while processing this request: {}'.format(str(e)))
else:
song = Song(source)
await ctx.voice_state.songs.put(song) #Enqueue the Song
i = (i + 1) % len(URL) # Updates the Index of URL
await asyncio.sleep(source.DURATION) #Gets the Lenght of the Music in int and Sleeps
I thought of using Asyncio Event Loops but Can't Figure it Out How to Use it Because my Function Has Parameters/Arguments like context (ctx)
I have Also thought of Cleaning the Memory stack after each songs play... But is it possible ??? If yes can we use it to fix my problem
So Is there anyway to Loop The above Mentioned Block or Code Infinitely without crashing it eventually
Thanks in advance !!!
I have a Out of Topic Query... Can we Use the ability of Context (ctx) without passing it as a Argument.
If we Can then I might be able to use asyncio_event_loop, I suppose

Discord.py Mass DM sometimes Bugs

i am Making a MassDM command but it dont works well, it sends a Message not to Everyone it stops automatically i think because they turn their DM's off thats why how can i Bypass it? or how can i Fix this error?
Code
#client.command()
async def massdm(self, ctx, *, message):
await ctx.message.delete()
embed = discord.Embed(description=f'**Sent everyone a DM with:** ``{message}``',color=embcolor)
await ctx.send(embed=embed, delete_after=delemb)
for user in list(ctx.guild.members):
try:
await asyncio.sleep(0.1)
await user.send(message)
except:
pass
To debug it properly, the first step would be to remove the try, except block and find out what exceptions are you actually getting. It's a bad habit to catch every exceptions at once. Without knowing what exception is it throwing, I'm unable to help more.
Another thing I would recommend is to benefit from the discord.py being an asynchronous package, and instead of iterating over the users synchronously, try something like that:
coros = [await user.send(message) for user in ctx.guild.members]
await asyncio.gather(*coros)
This way it will send the message to every user at the same time.
EDIT:
I also found another bug while using a loop like that. At some point the bot will try to send the DM to itself, and that is raising AttributeError. Make sure that you handle that, for example:
coros = [user.send(message) for user in ctx.guild.members if user != ctx.guild.me]
await asyncio.gather(*coros)
Maybe that was your issue all along.
Try this:) Hope it helps
#client.command(pass_context=True)
async def massdm(ctx):
await ctx.message.delete()
for member in list(client.get_all_members()):
try:
embed = discord.Embed(title="Test",
description="Test!",
color=discord.Colour.blurple())
embed.set_thumbnail(
url="test")
embed.set_footer(
text=
"test"
)
#delay. Set it to 10 to 20 seconds to avoid flagging
await asyncio.sleep(30)
await member.send(embed=embed)
except:
pass
#await ctx.send(f"Messaged: {member.name}")
print(f"Messaged: {member.name}")

How to stop telethon conversation on receiving a specific message

I have made a telegram bot using telethon library which takes reponses from user using button.inline and button.text methods. But I want to stop the conversation as soon as a specific message(like bye) is entered by the user.
#bot.on(events.NewMessage(incoming=True, pattern='Hi'))
async def main(event):
global SENDER
MSG = event.raw_text
SENDER=event.chat_id
async with bot.conversation(SENDER) as conv:
await conv.send_message('choose', buttons=[[Button.inline('Yes'), Button.inline('No')] ])
await conv.send_message('<b> Want More ? </b>', parse_mode='html', buttons=[ [Button.text('Yes', resize=True,single_use=True), Button.text('No', resize=True,single_use=True)], [Button.text('More', resize=True,single_use=True)] ] )
...
...
Whenever the user sends 'Hi', the bot starts querying using buttons.
In the telethon docs , cancel() and cancel_all() methods are provided. But how can I implement them such that on getting message bye, it ends the conversation ?
According to the docs, conv.cancel_all() cancels all conversations of that chat. I noticed I wasn't able to open more than one conversation, because default value exclusive=True was set.
So, what I did was:
#client.on(events.NewMessage(func=lambda e: e.is_private))
async def handler(event):
try:
rawmsg = event.message.message
if rawmsg == "/cancel":
# set exclusive=False so we can still create a conversation, even when there's an existing (exclusive) one.
async with client.conversation(await event.get_chat(), exclusive=False) as conv:
await conv.cancel_all()
await event.respond("Operation is cancelled.")
return
async with client.conversation(await event.get_chat(), exclusive=True) as conv:
await conv.send_message("Hey, I'll send you back whatever you write! To cancel, do /cancel")
while True:
resp = (await conv.get_response()).raw_text
await conv.send_message(resp)
# except telethon.errors.common.AlreadyInConversationError:
# pass
except:
traceback.print_exc()
When there's a new message with text "/cancel", it will open a conversation, and call .cancel_all() to cancel the old conversation.

DM commands to discord bot

I recently had the idea of DMing my bot commands. For example, a command which would unban me from every server that the bot is on.
Unfortunately I don't have any starting point for the command because I'm not even sure DMing commands is possible.
Keywords like discord.py, command or DM are so common in google that finding any good info on the topic is very hard.
I'm looking for a way for the bot to receive DMs as commands and only accept them from me (my ID is stored in the variable ownerID if anyone wants to share any code).
While I'm mostly looking for the above, some code for the DM unban command would also be very helpful.
EDIT: I was asked to show some example code from my bot. Here is the code for the command number which generates a random number and sends it in a message. I hope this gives you an idea of how my bot is made:
#BSL.command(pass_context = True)
async def number(ctx, minInt, maxInt):
if ctx.message.author.server_permissions.send_messages or ctx.message.author.id == ownerID:
maxInt = int(maxInt)
minInt = int(minInt)
randomInt = random.randint(minInt, maxInt)
randomInt = str(randomInt)
await BSL.send_message(ctx.message.channel, 'Your random number is: ' + randomInt)
else:
await BSL.send_message(ctx.message.channel, 'Sorry, you do not have the permissions to do that #{}!'.format(ctx.message.author))
You can send commands in private messages. Something like
#BSL.command(pass_context=True)
async def unban(ctx):
if ctx.message.channel.is_private and ctx.message.author.id == ownerID:
owner = await BSL.get_user_info(ownerID)
await BSL.say('Ok {}, unbanning you.'.format(owner.name))
for server in BSL.servers:
try:
await BSL.unban(server, owner) # I think having the same name should be fine. If you see weird errors this may be why.
await BSL.say('Unbanned from {}'.format(server.name))
except discord.HTTPException as e:
await BSL.say('Unbanning failed in {} because\n{}'.format(server.name, e.text))
except discord.Forbidden:
await BSL.say('Forbidden to unban in {}'.format(server.name))
else:
if ctx.message.author.id != ownerID:
await BSL.say('You are not my owner')
if not ctx.message.channel.is_private:
await BSL.say('This is a public channel')
should work. I'm not sure what happens if you try to unban a user who is not banned, that may be what raises HTTPException

Why is my discord bot only executing my command one time and one time only?

I'm in the process of finishing a simple sound clip Discord bot I made by recycling a basic music bot example in python. All I want the bot to do is enter the voice channel of the user who called the command (!womble), play a random sound clip from a folder of sound clips, then leave the voice channel.
"Simple, right?" Of course it isn't, not with this API apparently.
After a BUNCH of trial and error, looking to at least 3 API revisions I got the bot to actually perform the command.....one time. Any further prompts of the command are met with crickets. I can do a !summon and it bring the bot into the channel, but the !womble command no longer works.
def bot_leave(self, ctx):
state = self.get_voice_state(ctx.message.server)
coro = state.voice.disconnect()
fut = asyncio.run_coroutine_threadsafe(coro, state.voice.loop)
try:
fut.result()
except:
# an error happened sending the message
pass
#commands.command(pass_context=True, no_pm=True)
async def womble(self, ctx):
state = self.get_voice_state(ctx.message.server)
opts = {
'default_search': 'auto',
'quiet': True,
}
if state.voice is None:
success = await ctx.invoke(self.summon)
if not success:
return
try:
random_clip = clip_dir + "\\" + random.choice(os.listdir(clip_dir))
player = state.voice.create_ffmpeg_player(random_clip, after=lambda: self.bot_leave(ctx))
player.start()
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.send_message(ctx.message.channel, fmt.format(type(e).__name__, e))
I have tried going into the python chat is the Discord API server, but much like my bot, I'm met with crickets. (Guess that's what I get trying to seek support from a chat that already has 4 conversations going.)
I'm guessing you might not need help anymore but just in case you should try removing the coroutine.result() and run it directly. I.e change:
def bot_leave(self, ctx):
state = self.get_voice_state(ctx.message.server)
coro = state.voice.disconnect()
fut = asyncio.run_coroutine_threadsafe(coro, state.voice.loop)
try:
fut.result()
except:
# an error happened sending the message
pass
to:
def bot_leave(self, ctx):
state = self.get_voice_state(ctx.message.server)
coro = state.voice.disconnect()
try:
asyncio.run_coroutine_threadsafe(coro, state.voice.loop)
except:
# an error happened sending the message
pass
That's the only thing I could think of seeing your code snippet, but the problem may lie elsewhere in the code.

Categories