I'd like to send on a Discord bot a message embed but text is from another file.
I did this way and it doesn't work:
#bot.command()
async def gdc(ctx):
"""Wins GDC"""
message = '/home/plo/rkr/res_wins2'
title = "GDC"
embed = discord.Embed()
embed.description = message
embed.title = title
embed.colour = 0xF1C40F
await ctx.send(embed=embed)
I have the embed message displaying the directory (/home/plo/rkr/res_wins2).
I modified it to read it before send it to Embed:
bot.command()
async def gdc(ctx):
"""Wins GDC"""
index1 = 0
file = open("/home/plo/rkr/res_wins2", "r")
for line in file.readlines():
line = line.strip()
index1 += 1
if index1 == 4: break
message = line
embed = discord.Embed()
embed.description = message
embed.title = title
embed.colour = 0xF1C40F
await ctx.send(embed=embed)
However, it seems only one result goes out... Here is my txt file:
Roi mouton: 9
tomate: 8
The_Portos: 8
Are the message in a .txt file? If this is true what you should do is read the file and pass it to a text string so you can match it to message. Here you can find the documentation to Handling Files.
You can check the Documentation Here.
It will help.
However using Java will be easier with like this:
channel.sendMessage("message").addFile(new File("path/to/file")).queue();
#bot.command()
async def gdc(ctx):
"""Wins GDC"""
with open("/home/plo/rkr/res_wins2", "r") as f:
scores = f.read().splitlines()
final = '\n'.join(scores[0:3])
embed=discord.Embed(title="Leader Board", description=final,color = 0xF1C40F)
await ctx.send(embed=embed)
Try putting it in a for-loop:
#bot.command()
async def logs(ctx):
embed: discord.Embed = discord.Embed(
title="title", description="description",
color=discord.Color.red()
)
file = open("file.txt", "r")
for line in file.readlines():
l = line.strip()
loglist.append(l)
embed.add_field(name="⠀", value=" `{0}`".format(l), inline=False)
embed.set_author(name="name")
await ctx.send(embed=embed)
Related
I'm trying to make a bot that would autoreact, check the amount of reactions on the messages in a channel, make a link to the message and send it on a moderation channel if it got 2 or more reactions, then log it's jump url in bot's directory. I cant find a way to fetch all the messages with jump_url and reactions attributes. im feeling super lost so i'll put the code here
async def on_message(message):
if message.channel.id == 828579458167996420:
channel = client.get_channel(828579458167996420)
if message.attachments or "http" in message.content:
await message.add_reaction("<:MashaUpset:828589397074116709>")
x = int
messages = await channel.history(limit=21).flatten()
f = open("message log.txt","r")
readfile = f.read()
f.close()
if str(messages.jump_url) not in readfile:
if messages.reactions[0].count >= 2:
x = messages.reactions[0].count - 1
link = messages.jump_url
channel = client.get_channel(892065611876823100)
await channel.send("this post was liked "+ str(x) + " times! "+ str(link))
f = open("message log.txt", "a")
f.write("\n" + str(messages.jump_url))
f.close()
im a beginner, so sorry for the mess i've made
Edit: can't fetch jump_url, so instead fetching for message.id
Ok I found it. thx to Dominik for help
Changes I've done
I've separated the script into 2 parts, an on_message and a #tasks.loop
Added a for x loop
Added an await channel.fetch_message(x.id) in the loop
Fetched for message.id rather than jump_url
Added if statement to check if the message has reactions
#client.event
async def on_message(message):
if message.channel.id == 828579458167996420:
if message.attachments or "http" in message.content:
await message.add_reaction("<:MashaUpset:828589397074116709>")
#tasks.loop(minutes=2)
async def check():
channel = client.get_channel(828579458167996420)
messages = await channel.history(limit=30).flatten()
await asyncio.sleep(3)
f = open("message log.txt","r")
readfile = f.read()
f.close()
for message in messages:
channel = client.get_channel(828579458167996420)
message = await channel.fetch_message(message.id)
if str(message.id) not in readfile:
if message.reactions:
if message.reactions[0].count >= 2:
x = message.reactions[0].count - 1
link = message.jump_url
channel = client.get_channel(892065611876823100)
await channel.send("this post was liked "+ str(x) + " times! "+ str(link))
f = open("message log.txt", "a")
f.write("\n" + str(message.id))
f.close()
#check.before_loop
async def before():
await client.wait_until_ready()
check.start()
I want to update an embed message that my bot has already written in a specific channel, how can I do that? If i try to use message.edit it givesthis error: discord.errors.Forbidden: 403 Forbidden (error code: 50005): Cannot edit a message authored by another user
import discord
import json
from discord.ext import commands
def write_json(data,filename="handle.json"):
with open (filename, "w") as f:
json.dump(data,f,indent=4)
class Handle(commands.Cog):
def __init__(self, client):
self.client=client
#commands.Cog.listener()
async def on_ready(self):
print("Modulo_Handle: ON")
#commands.command()
async def Handlers(self,ctx):
with open('handle.json','r') as file:
data = json.load(file)
embed = discord.Embed.from_dict(data)
await ctx.channel.send(embed=embed)
file.close()
#commands.Cog.listener()
async def on_message(self, message):
if str(message.channel) == "solaris™-handle":
author = message.author
content = message.content
user = str(author)
with open ("handle.json") as file:
data = json.load(file)
temp = data['fields']
y={"name":user[:-5],"value":content}
temp.append(y)
write_json(data)
updated_embed = discord.Embed.from_dict(data)
await message.edit(embed=updated_embed)
file.close()
def setup(client):
client.add_cog(Handle(client))
msg_id = 875774528062640149
channel = self.client.get_channel(875764672639422555)
msg = await channel.fetch_message(msg_id)
with open('handle.json','r') as file:
data = json.load(file)
embed = discord.Embed.from_dict(data)
await msg.edit(embed=embed)
Fixed adding this code below write_json(data) and remove
updated_embed = discord.Embed.from_dict(data) await message.edit(embed=updated_embed)
def get_channel_id(client, message):
with open('./json/welcome.json', 'r') as f:
channel_id = json.load(f)
return channel_id[str(message.guild.id)]
#client.event
async def on_member_join(member):
embed = discord.Embed(colour=0x767429, description=f"Welcome to my server! You are the {len(list(member.guild.members))}th member ")
embed.set_thumbnail(url=f" {member.avatar_url} ")
embed.set_author(name=f" {member.name} ", icon_url=f" {member.avatar_url} ")
embed.set_footer(text=f"{ member.guild }", icon_url=f" {member.guild.icon_url} ")
embed.timestamp = datetime.datetime.utcnow()
channel = client.get_channel(id=get_channel_id)
await channel.send(embed=embed)
#client.command()
async def welcomechannel(ctx, channel_id):
with open('./json/welcome.json', 'r') as f:
id = json.load(f)
id[str(ctx.guild.id)] = channel_id
with open('./json/welcome.json', 'w') as f:
json.dump(id, f, indent=4)
await ctx.send(f'Welcome channel changed to {channel_id}')
I'd like to have the get_channel_idfunction be the ID of the channel = client.get_channel(id=get_channel_id) but everytime I run it i get the error AttributeError: 'NoneType' object has no attribute 'send'. Can someone please help me
You can simplify the code quite a bit. As mentioned in my comment, you also need to open the JSON when a new user enters the server.
Your own function above is completely redundant and not needed.
I also once changed your welcomechannel command a bit because you don't get far with channel_id, you can use channel: discord.TextChannel instead and it comes out the same.
Here is the command for now:
#client.command()
async def welcomechannel(ctx, channel: discord.TextChannel): # We use discord.TextChannel
with open('./json/welcome.json', 'r') as f:
id = json.load(f)
id[str(ctx.guild.id)] = channel.id # Saving JUST the ID, you also had <#ID> in it
with open('./json/welcome.json', 'w') as f:
json.dump(id, f, indent=4)
await ctx.send(f'Welcome channel changed to `{channel}`')
And now to check the channel. For that we open the JSON in the same way as we did with the command:
#client.event
async def on_member_join(member):
with open('./json/welcome.json', 'r') as f:
wchannel = json.load(f) # Define our channel
try:
if wchannel: # If a channel is set for the server
wchannelsend = member.guild.get_channel(wchannel[str(member.guild.id)]) # Get the channel from the JSON
embed = discord.Embed(color=0x767429,
description=f"Welcome to my server! You are the {len(list(member.guild.members))}th member ")
embed.set_thumbnail(url=f"{member.avatar_url} ")
embed.set_author(name=f"{member.name} ", icon_url=f"{member.avatar_url} ")
embed.set_footer(text=f"{member.guild}", icon_url=f"{member.guild.icon_url} ")
embed.timestamp = datetime.datetime.utcnow()
await wchannelsend.send(embed=embed) # Send the embed to the channel
else:
return # If no channel was set, nothing will happen
except:
return
I'm creating a discord bot and tryying to save stats about every user and their messages sent but it's not working. This is what I have:
async def update_stats():
await client.wait_until_ready()
global messages, author
data = []
if author != 0:
try:
with open("stats.txt", "r") as f:
data = f.readlines()
for item in data:
author2, messages2 = item.split(":")
print(author2, messages2)
index = data.index(item)
if author == author2:
with open("stats.txt", "w") as f1:
data.pop(index)
novi_stat = f"""{author}:{int(messages) + int(messages2)}\n"""
data.insert(index, novi_stat)
str = ''.join(data)
f1.write(str)
else:
with open("stats.txt", "w") as f2:
data.append(f"""{author}:{messages}\n""")
str = ''.join(data)
f2.write(str)
await asyncio.sleep(5)
except Exception as e:
print(e)
await asyncio.sleep(5)
And this is the content of the text file it loads and is supposed to change when number of messages changes:
DrDEagle#4984:100
kreten:123
This is what I get when running the code:
DrDEagle#4984:100
kreten:123
:0
It is supposed to change the number from 100 to 101 if I send one message, but instead it writes a new line which doesn't even contain the right data, what am I doing wrong?
EDIT: After an hour of editing and rewriting the code, I did this and it works.
import discord
import random
import aiohttp
import asyncio
import json
import datetime
client = discord.Client()
sentdex_guild = client.get_guild(No, No!) # I didn't post the code...
author = ''
messages = 0
#client.event
async def on_message(message):
global author, messages
author = message.author.name
messages += 1
authorsInFile = []
f = open("stats.txt", 'r')
data = f.readlines()
for item in data:
author2, messages2 = item.split(":")
authorsInFile.append(author2)
print(author2, messages2)
if author in authorsInFile:
index = authorsInFile.index(author)
else:
pass
if author2 == author:
f1 = open("stats.txt", "w")
print(author)
data.pop(index)
novi_stat = f"""{author}:{int(messages2) + 1}\n"""
data.insert(index, novi_stat)
str = ''.join(data)
f1.write(str)
f1.close()
f.close()
else:
f2 = open("stats.txt", "w")
data.append(f"""{author}:{messages}\n""")
str = ''.join(data)
f2.write(str)
f2.close()
f.close()
await asyncio.sleep(5)
with open('log.txt', 'a') as f:
f.write(f"""{datetime.datetime.now()} | {message.author} je rekao: {message.content}\n""")
if message.content == "!bok":
await message.channel.send("Pozdrav!")
elif message.content == "!korisnici":
online = 0
idle = 0
offline = 0
for m in sentdex_guild.members:
if str(m.status) == "online":
online += 1
if str(m.status) == "offline":
offline += 1
else:
idle += 1
await message.channel.send(f"""Broj korisnika: {online+offline - 1}\nˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇ\nOnline korisnika: {online - 1}\nOffline korisnika: {offline}\n^^^^^^^^^^^^^^^^^^^^^^^^""") # printa broj korisnika, ali ne broji sebe
elif message.content == "!ping":
latency = client.latency
await message.channel.send(f"""Moj ping iznosi {round(latency, 6)}ms""")
elif message.content == "!yacketty":
await message.channel.send("Dostupne komande su: !ping, !bok, !korisnici, !bitcoin...")
elif message.content == "!bitcoin":
url = 'https://api.coindesk.com/v1/bpi/currentprice/BTC.json'
async with aiohttp.ClientSession() as session: # Async HTTP request
raw_response = await session.get(url)
response = await raw_response.text()
response = json.loads(response)
await message.channel.send("Cijena bitcoina: $" + response['bpi']['USD']['rate'])
elif "!8ball" in message.content:
moguci_odgovori = [
'Nema jebene šanse',
'Možda, ali samo možda',
'Ahhh, 50-50',
'Vrlo moguće',
'Apsolutno da'
]
await message.channel.send(random.choice(moguci_odgovori) + ", " + message.author.mention)
#client.event
async def welcome(member):
for channel in member.server.channels:
if str(channel) == "general":
await client.send_message(f"""{member.mention}, dobrodošao na server!""")
client.run("I'm not showing you this hehe")
I don't see anywhere that you set either author or messages. You have them set as globals, so I assume you're setting them before calling this function. If author is an empty string, and messages is 0, then the output you are getting is just what I would expect from your code.
Since there is not yet an author named "", it appends an entry for that author to the file that is the empty author name, a colon, and the 0 that is the value of message.
Note that your first if test would succeed and the if block entered in this proposed case, as "" != 0 is True.
Another observation...you're reading in multiple existing authors, but you seem to be only comparing the passed in author against the last author read in from the file. I'm assuming that's not what you want...you probably want to be comparing each author you read in against the passed in author in the loop that is processing each line of the file.
On Discord, you can only have messages of character length 2000 or under. I am trying to append the server name, member amount and server ID for each server that the bot is in to a list, and then sending the list to a channel.
However, as the list length exceeds 2000 I have tried to split it up, however the method requires it to be updated every time manually as the list gets larger. How can I make the script automatically split up the list based on how many 'splits' are required and then send those 'splits'?
What I have so far, which works, but is not automatic:
#commands.command()
async def getallservers(self, ctx):
serverslist = []
def split_list(alist, wanted_parts=1):
length = len(alist)
return [ alist[i*length // wanted_parts: (i+1)*length // wanted_parts]
for i in range(wanted_parts) ]
if ctx.author.id == 204616460797083648:
for x in self.bot.guilds:
serverslist.append(f'{x.name}: **{len(x.members)}** - {x.id}\n')
q1,q2,q3,q4,q5,q6 = split_list(serverslist, wanted_parts=6)
embed = discord.Embed(title='Server List')
embed.description = ''.join(q1)
await ctx.send(embed=embed)
embed.description = ''.join(q2)
await ctx.send(embed=embed)
embed.description = ''.join(q3)
await ctx.send(embed=embed)
embed.description = ''.join(q4)
await ctx.send(embed=embed)
embed.description = ''.join(q5)
await ctx.send(embed=embed)
embed.description = ''.join(q6)
await ctx.send(embed=embed)
else:
pass
One you have the serverslist, you can pass it to a function that builds < 2000 character pages
def paginate(lines, chars=2000):
size = 0
message = []
for line in lines:
if len(line) + size > chars:
yield message
message = []
size = 0
message.append(line)
size += len(line)
yield message
then in your command
for message in paginate(serverlist):
embed.description = ''.join(message)
await ctx.send(embed=embed)