I've got this code that I use for discord channel logging. It basically gets the last 10,000 messages in a channel, and makes a .txt file with those messages in it, with the !log command. However, how would I make it so optionally users can type a number after !log, and it will log that number of previous messages? EG: "!log" on it's own logs the last 10,000 messages, but "!log 100" would log the last 100 messages. But I have no clue how to do that.
Here's my code:
#commands.has_any_role('Logger', 'logger')
#bot.command()
async def log(ctx):
try:
channel = ctx.message.channel
await ctx.message.delete()
await channel.send(ctx.message.author.mention+" Creating a log now. This may take up to 5 minutes, please be patient.")
messages = await ctx.channel.history(limit=10000).flatten()
numbers = "\n".join([f"{message.author}: {message.clean_content}" for message in messages])
f = BytesIO(bytes(numbers, encoding="utf-8"))
file = discord.File(fp=f, filename='Log.txt')
await channel.send(ctx.message.author.mention+" Message logging has completed.")
await channel.send(file=file)
except:
embed = discord.Embed(title="Error creating normal log:", description="The bot doesn't have necessary permissions to make this log type. Please confirm the bot has these permissions for this channel: View Channel, Read and Send Messages, Attatch Files (used for sending the log file), Manage Messages (used for deleting the command the user sends when making a log).", color=0xf44336)
await channel.send(embed=embed)
Any help about how to make it so they can optionally provide a number, which would then log that amount, would help a lot. Thanks!
Take the number of messages to be logged as a parameter
...
#bot.command()
async def log(ctx, limit: int=1000):
...
then use the value of the parameter
...
messages = await ctx.channel.history(limit=limit).flatten()
...
docs: https://discordpy.readthedocs.io/en/latest/ext/commands/commands.html#parameters
Related
Well im creating a discord bot right now and i wanted to add a feature that it deletes messages.
Basically the bot waits for a message to pop up, if this message contains a given command,
in this case "sudo clean (number)", it deletes (number) messages (so if the number is 5 it deletes 5 messages). Well i mean its supposed to do that but yea its not doing what its supposed to do.
I get discord.errors.NotFound: 404 Not Found (error code: 10008): Unknown Message
Thats my code:
elif message.content.lower().startswith("sudo clean"):
userMessage = message.content
message.delete()
for word in userMessage.split():
if word.isdigit():
textToClean = int(word)
for i in range(0, textToClean):
await message.delete()
Whats the Problem?
here is what I use that's a lot easier if you don't want anything fancy
#client.command(name="clear",
brief="Deletes a certain amount of messages ex. .clear 10")
async def clear(ctx, amount=5):
amount += 1
await ctx.channel.purge(limit=amount)
Here is a pretty simple implementation using slash commands, which i currently use.
#commands.slash_command(description='Delete messages from a channel.')
#commands.has_permissions(manage_messages=True)
async def purge(
self,
inter,
amount: int
):
"""Delete a certain amount of messages in the chat
Parameters
----------
amount: The amount of messages you want to delete, can't be greater than 100
"""
if amount > 100:
await inter.send("Wow, take it easy, no more than 100 messages at a time", ephemeral=True)
return
await inter.channel.purge(limit=amount, check=lambda msg: not msg.pinned)
await inter.send('Messages deleted.', ephemeral=True)
Of course, if you don't use slash commands can be easily turned into a regular prefix command
#commands.command()
#commands.has_permissions(manage_messages=True)
async def purge(
self,
ctx,
amount: int
):
"""Delete a certain amount of messages in the chat
Parameters
----------
amount: The amount of messages you want to delete, can't be greater than 100
"""
if amount > 100:
await ctx.send("Wow, take it easy, no more than 100 messages at a time")
return
await ctx.channel.purge(limit=amount, check=lambda msg: not msg.pinned)
await ctx.send('Messages deleted.')
The check is for avoiding Pinned messages
I am trying to understand how to automatically update a specific voice channels name in Discord. Looking through the API and around the site, I have found this:
#client.command()
async def emoivb(ctx, channel: discord.VoiceChannel, new_name):
await channel.edit(name=new_name)
However, I need it not as a command.
Example: Each time a person sends a specific message, the channel will increment its integer name by +1
Create a json file to store the number of messages with name message and use the following code
#client.listen()
async def on_message(message):
channel_id="channel which is to be edited"
channel=await client.fetch_channel(channel_id)
with open('message.json',"r") as f:
messages=json.load(f)
try:
x=messages[str(message.guild.id)]
x=x+1
messages[str(message.guild.id)]=x
with open('message.json',"w") as f:
json.dump(messages,f,indent=4)
await channel.edit(name=str(x))
except:
messages[str(message.guild.id)]=1
with open('message.json',"w") as f:
json.dump(messages,f,indent=4)
await channel.edit(name=str(1))
I have a program that changes what channel members can see at certain times of the day. To do this, I can either change the roles that every member has, or change the permissions of each channel. However, I have looked all over the web and all of the ways for either method require a message to be sent so that the data from that message can be read and put into the function, such as:
#client.command()
async def perm(ctx):
await ctx.channel.set_permissions(ctx.guild.default_role, send_messages=False
Change the permissions of a discord text channel with discord.py
or
async def addrole(ctx):
member = ctx.message.author
role = get(member.server.roles, name="Test")
await bot.add_roles(member, role)
Discord.py | add role to someone
My current program looks like this:
import discord
client = discord.Client()
import datetime
async def live_day(schedule):
current_place = "the void"
while True:
current_time = str((datetime.datetime.now() -datetime.timedelta(hours=7)).time())
int_time = int(current_time[:2] + current_time[3:5])
for x in range(len(schedule)):
try:
start_time = schedule[x][1]
end_time = schedule[x + 1][1]
except IndexError:
end_time = 2400
if current_place != schedule[x][0] and int_time >= start_time and int_time < end_time:
current_place = schedule[x][0]
#Change the channel permissions of the current place to allow viewing
#Change the channel permissions of the last channel to disallow viewing
#client.event
async def on_ready():
print("{0.user} has arrived for duty".format(client))
client.loop.create_task(live_day([
("Home", 0),
("Work", 900),
("Home", 1700),
("Nightclub", 2000),
("Home", 2200),
]))
client.run(my_secret)
Never mind the badly written code, how would I do this or where should I go to figure this out? Any help is appreciated. Thanks!
Edit: I could get the channels individually by using this,
channel1=client.get_channel(channelid)
discord.py, send message by channel id without on_message() event?
but then I can't use this for more than one server. How can I get channels by name?
Note on on_ready():
This function is not guaranteed to be the first event called. Likewise, this function is not guaranteed to only be called once. This library implements reconnection logic and thus will end up calling this event whenever a RESUME request fails.
Using this function may crash the bot.
Instead create background tasks and use wait_until_ready().
You can find examples in https://github.com/Rapptz/discord.py/blob/v1.7.3/examples/background_task.py
If you want to change only one channel's permissions (per guild) this might fit your needs:
#changing "Home" channel visibility, every day at 5 pm.
#client.event
async def on_ready():
while True:
await asyncio.sleep(1)
current_time = datetime.datetime.now()
five_pm = current_time.replace(hour=17, minute=0, second=0)
if current_time == five_pm:
for guild in client.guilds: #looping through all the guilds your bot is in
channel = discord.utils.get(client.get_all_channels(), name="Home") #getting channel by name by using "discord.utils"
await channel.set_permissions(guild.default_role, view_channel=True) #changing permissions
By using the on_ready() event you can loop through the time check without sending any message.
Remember to import discord.utils.
If we have a message with ⬇️ and ⬆️ Reaction.
How can we get all users reacted in particular emojis and how to use as button.
Like,
If a user reacts his name will be added in message along with the emoji which he reached.
Here is a simple example this is not the best method since this will be active on all bot messages when someone reacts with ⬆️. The best is save the message id that you want then do a check here to make sure it is the wanted message.
If message.id is not an option then make a dedicated channel for this and hard code the id of that channel, this is not the best practice but it will work.
#bot.event
async def on_raw_reaction_add(payload):
channel = bot.get_channel(payload.channel_id)
message = channel.get_message(payload.message_id)
# guild = bot.get_guild(payload.guild_id)
emoji = payload.emoji.name
# skip DM messages
if isinstance(channel, discord.DMChannel):
return
# only work if in bot is the author
# skip messages not by bot
# skip reactions by the bot
if message.author.id != bot.user.id or payload.member.id == bot.user.id:
return
if emoji == '⬆️':
up_users = f"{message.content} \n {user.name}"
await message.edit(up_users)
# remove user reaction
reaction = discord.utils.get(message.reactions, emoji=emoji)
await reaction.remove(payload.member)
I've got this code, which when I type !snapshot should log the last 100 messages in the channel, and make them into a text file:
snapshot_channel = (my snapshot channel ID)
#commands.has_permissions(administrator=True)
#bot.command()
async def snapshot(ctx):
channel = bot.get_channel(snapshot_channel)
await ctx.message.delete()
messages = message in ctx.history(limit=100)
numbers = "\n".join(
f"{message.author}: {message.clean_content}" for message in messages
)
f = BytesIO(bytes(numbers, encoding="utf-8"))
file = discord.File(fp=f, filename="snapshot.txt")
await channel.send("Snapshot requested has completed.")
await channel.send(file=file)
I've got BytesIO imported, and it works fine for a different command which purges messages and logs them, but this code which should just make a log and then send it in the channel doesn't work. Please can you send me what it should look like for it to work. Thanks!
TextChannel.history is an async generator, you're not using it properly
messages = await ctx.channel.history(limit=100).flatten()
numbers = "\n".join([f"{message.author}: {message.clean_content}" for message in messages])
Another option would be
numbers = ""
async for message in ctx.channel.history(limit=100):
numbers += f"{message.author}: {message.clean_content}"