Hi I'm having an issue checking through a list codes that are stored in a temp dictionary and matching ones that exist and if one doesn't exist then print/await a different result. I'm doing this by comparing the uses for each invite before the user joined and after they joined.
It seems as if the if statement if invite.uses < find_invite_by_code(invites_after_join, invite.code).uses: is being ignored and the else statement is being printed/awaited instead for both expired and none expired code. I'm not too sure why this is happening. Help would be appreciated.
I have commented parts of the code for a better understanding.
Here is my code:
invites = {} #temporary dict to store the codes
# A function to find an invite in a guilds.invites() list
def find_invite_by_code(invite_list, code):
# Simply looping through each invite in an
# invite list which we will get using guild.invites()
for inv in invite_list:
# Check if the invite code in this element
# of the list is the one we're looking for
if inv.code == code:
# If it is, we return it.
return inv
#commands.Cog.listener()
async def on_member_join(self, member):
time = datetime.utcnow()
users = len([e.name for e in member.guild.members])
name = member
name = " ~ ".join((name.name, name.nick)) if name.nick else name.name
# Getting the invites before the user joining
# from our cache for this specific guild
invites_before_join = invites[member.guild.id]
# Getting the invites after the user joining
# so we can compare it with the first one, and
# see which invite uses number increased
invites_after_join = await member.guild.invites()
# Loops for each invite we have for the guild
# the user joined.
for invite in invites_before_join:
# Now, we're using the function we created just
# before to check which invite count is bigger
# than it was before the user joined.
if invite.uses < find_invite_by_code(invites_after_join, invite.code).uses:
# Now that we found which link was used we'll start the embed
joinmsg = discord.Embed(title=f'{member.name}#{member.discriminator} has joined', timestamp=time, colour=discord.Color(random.randint(0x000000, 0xFFFFFF)))
joinmsg.add_field(name="**Account Created:**", value=member.created_at.strftime("%#d %b %Y, at %I:%M%p"), inline=True)
joinmsg.add_field(name="**Invite:**", value=f"||{invite.code}||", inline=True)
joinmsg.add_field(name="**Inviter:**", value=f"{invite.inviter}", inline=False)
joinmsg.set_footer(text=f"Member {users} • User ID: {member.id}")
joinmsg.set_thumbnail(url=member.avatar_url)
await self.bot.send_log_message(member.guild, embed=joinmsg)
#We use an else statement if a NoneType is returned this would happen if the invite link has expired.
else:
# Create the embed to be sent
joinmsg = discord.Embed(title=f'{member.name}#{member.discriminator} has joined', timestamp=time, colour=discord.Color(random.randint(0x000000, 0xFFFFFF)))
joinmsg.add_field(name="**Account Created:**", value=member.created_at.strftime("%#d %b %Y, at %I:%M%p"), inline=True)
joinmsg.add_field(name="**Invite:**", value=f"Expired", inline=True)
joinmsg.set_footer(text=f"Member {users} • User ID: {member.id}")
joinmsg.set_thumbnail(url=member.avatar_url)
await self.bot.send_log_message(member.guild, embed=joinmsg)
# We will now update our cache so it's ready
# for the next user that joins the guild
invites[member.guild.id] = invites_after_join
# return to prevent looping when we already got what we want
return
It looks like something isn't happening quite the way you want it to, I would add a print function before it and print the values of invite.uses and find_invite_by_code(invites_after_join, invite.code).uses and then print the type of them too, if you still can't spot the error, then we'll have a problem
print(invite.uses, find_invite_by_code(invites_after_join, invite.code).uses)
print(type(invite.uses), type(find_invite_by_code(invites_after_join, invite.code).uses))
Related
Hi so im having a problem where when I try to use this command its bringing the USERID instead of what im trying to get heres the error
File "goonie.py", line 421, in spam
spammers = users[str(ctx.author.id)]['text_max']
KeyError: '932428536176848938'
The numbers are the "ctx.author.id" and im trying to get the "text_max"
async def spam(ctx, message,amount):
users = await get_paid_data()
spammers = users[str(ctx.author.id)]['text_max']
if amount > spammers:
if str(ctx.author.id) in users:
if users[str(ctx.author.id)]['vip'] == 'Y':
timeleft = datetime.strptime(users[str(ctx.author.id)]['expDate'],'%Y-%m-%d') - datetime.now()
if timeleft.days <= 0:
em = discord.Embed(color=0x000000, description="Sorry your plan on this tool has expired")
await ctx.send(embed=em) ```
users is a dictionary.
You first access the str(ctx.author.id) key in the dictionary.
The error is telling you the dictionary does not contain a key corresponding to the value of string value of ctx.author.id. Therefore, you cannot access text_max because the first part of your dict navigation is incorrect.
You should print users and see what it contains:
print(users)
My initial guess is that you're converting the id to a string when it in-fact doesn't need to be converted, but it's impossible to say without seeing the contents of the dictionary.
I'm trying to make it so my bot when it comes online it will check for every server the bot is on and create a folder for them in a directory but i keep getting the error list2 is not defined even though iv defined it here's the code:
import discord
from discord.ext import commands
import os
PREFIX = "$"
bot = commands.Bot(command_prefix=PREFIX, description="Hi")
list1 = os.listdir('C:/Users/User/Desktop/BOT_FOLDER')
for guild in bot.guilds:
print(guild.name)
list2 = guild.name
print(os.listdir('C:/Users/User/Desktop/BOT_FOLDER'))
set1 = set(list1)
set2 = set(list2)
missing = list(sorted(set1 - set2))
added = list(sorted(set2 - set1))
print('missing:', missing)
print('added:', added)
newpath = r'C:\Users\User\Desktop\BOT_FOLDER\{}'.format(added)
if not os.path.exists(newpath):
os.makedirs(newpath)
if os.path.exists("demofile.txt"):
os.remove('C:/Users/User/Desktop/BOT_FOLDER/{}').format(missing)
else:
print("The file does not exist")
bot.run('BOT_TOKEN_HERE')
Actually the interpreter is right! Even if it doesn't seem like it, list2 isn't defined, when you run set2 = set(list2).
Why this is the case
You're bascially calling for guild in bot.guilds right after the initialization of your bot object. However, it hasn't connnected to the API yet, which means it hasn't loaded things like bot.guilds. This attribute will be None, therefore your loop doesn't run and list2 won't get defined.
How to fix this
Wait until your bot is successfully connected to the API, and then iterate over your guilds. This can be done by using the on_ready() event. Also, you need to .append() items to a list, you can't just assign new items with the equal sign.
#bot.event
async def on_ready():
list1 = os.listdir('C:/Users/User/Desktop/BOT_FOLDER')
list2 = []
for guild in bot.guilds:
print(guild.name)
list2.append(guild.name)
print(os.listdir('C:/Users/User/Desktop/BOT_FOLDER'))
set1 = set(list1)
set2 = set(list2)
missing = list(sorted(set1 - set2))
added = list(sorted(set2 - set1))
print('missing:', missing)
print('added:', added)
newpath = r'C:\Users\User\Desktop\BOT_FOLDER\{}'.format(added)
if not os.path.exists(newpath):
os.makedirs(newpath)
if os.path.exists("demofile.txt"):
os.remove('C:/Users/User/Desktop/BOT_FOLDER/{}').format(missing)
else:
print("The file does not exist")
I am creating a discord bot that will help managing tasks.
Currently, I want to remove the date from the task string. But I am kinda stuck.
I tried some stuff with the .split method. But apparently, there is a two arguments cap.
I didn't find a helpful post on here so I hope someone can help me...
if message.content.startswith(PREFIX + COMMAND_TASK):
subject = message.content.split(' ')[1]
task = message.content.split(' ', 2)[2:]
date = message.content.split(' ')[-1]
task = task[:task.find(date)-1]
embed = discord.Embed(colour=discord.Colour(0xbd10e0))
embed.set_thumbnail(url=thumbnailurl)
embed.add_field(name="subject",
value=subject,
inline=False)
embed.add_field(name="task",
value=str(task)[2:-2],
inline=False)
embed.add_field(name="date",
value=date,
inline=False)
await message.channel.send(embed=embed)
It looks like this:
You can find the index of the date in the string via find()
The task description will become
subject = message.content.split(' ')[1]
task = message.content.split(' ', 2)[2:]
date = message.content.split(' ')[-1]
task = task[:task[0].find(date)-1] # -1 so that we don't have the last space that is before 03
Now, your task should be exactly "A description of the task"
Maybe the title is a bit confusing but my brain is stuck on this for like days now. So here is my "problem". I am redoing my Discord Bot and I have a small task that will check 2 JSON files (same format, different data) and there is a difference between them it will send a message.
This code needs to load 2 JSON files ("VATSIM_DATA_old.json & VATSIM_Data_new.json") and compare them and find differences. Now for simplicity, I reduced code so I just get if someone came online and if they are no longer online.
So my flow for this is something like this:
-When bots start, fetch JSON data and save it to file so we can compare updated data with this file,
-Now it is time to check if someone came online by fetching new data from the same link and saving it to the new file,
-Load both files as JSON so we can find all items inside of them and compare if some items are present in both or only in one of them,
-After comparing them and doing actions such as sending messages to the channel let's save that new data to our Old_Data.json file and go to sleep for X min (I set it to 5),
The problem I have is that it will send the same message every time a task is started. So my logic here was ok let's check if files are changing and they are but the code still somehow ignores part of the code that tells him if data is not changed here simply pass.
So here is my code:
atc = ["ADR_CTR", "ADR_W_CTR", "ADR_U_CTR", "ADR_E_CTR"] #this is short version of array which needs to be checked. This will most likely be moved to the config file so code is cleaner
#tasks.loop(minutes=5)
async def atcAnnoucements(self):
#Load old and new VATSIM Data for comparing!
with open("VATSIM_Data_old.json", encoding="utf-8") as f:
data = json.load(f)
file = open("VATSIM_Data_new.json", "w", encoding="utf-8")
file.write(requests.get('https://data.vatsim.net/vatsim-data.json').text)
file.close()
with open("VATSIM_Data_new.json", encoding="utf-8") as s:
data1 = json.load(s)
#Check if new VATSIM data contains some changes in online atc
#If callsign from atc array is present in VATSIM_Data_old it will check is same controller active or not
#If the controller is not changed it will skip, if new controller comes online it will send a message that the ATC station came online
for item in data1['clients']:
if item['callsign'] in data['clients']:
pass
else:
if item['callsign'] in atc:
time_start = item['time_logon']
time_logg = time_start[:19]
logon_start = datetime.strptime(time_logg, '%Y-%m-%dT%H:%M:%S')
time_logon = logon_start.strftime('%H:%M')
channel = self.bot.get_channel(781834455765483562)
embed = Embed(title="ATC Annoucement", description="`New controller just logged in!`", color=0x00ff4c)
embed.add_field(name='Position', value=f"`{item['callsign']}`", inline=False)
embed.add_field(name='Frequency', value=f"`{item['frequency']}`", inline=False)
embed.add_field(name='Controller', value=f"`{item['realname']}`", inline=False)
embed.set_footer(text=f"Logged on at: {time_logon}")
await channel.send(embed=embed)
if item['callsign'] in data['clients'] and atc and not data1['clients']:
channel = self.bot.get_channel(781834455765483562)
embed2 = Embed(title="ATC Logged off!", description=f"{item['callsign']} just logged off!", color=0xff8800)
await channel.send(embed=embed2)
file = open("VATSIM_Data_old.json", "w", encoding="utf-8")
file.write(requests.get('https://data.vatsim.net/vatsim-data.json').text)
file.close()
print("Saved new VATSIM Data!")
EDIT:
In my first attempt to just get 1 message, I did something like the code below and it worked. But as soon as I changed to the code above it simply sends the same message all over again
json1 = open("VATSIM_Data_old.json", "r", encoding="utf-8").read()
xy = json.dumps(json1)
s1 = json.loads(xy)
t = requests.get('https://data.vatsim.net/vatsim-data.json').json()
xx = json.dumps(t)
s = json.loads(xx)
for item in s['clients']:
if item['callsign'] in atc:
if item['callsign'] in s1:
pass
else:
if item['callsign'] in atc:
time_start = item['time_logon']
time_logg = time_start[:19]
logon_start = datetime.strptime(time_logg, '%Y-%m-%dT%H:%M:%S')
time_logon = logon_start.strftime('%H:%M')
channel = self.bot.get_channel(781834455765483562)
embed = Embed(title="ATC Annoucement", description="`New controller just logged in!`", color=0x00ff4c)
embed.add_field(name='Position', value=f"`{item['callsign']}`", inline=False)
embed.add_field(name='Frequency', value=f"`{item['frequency']}`", inline=False)
embed.add_field(name='Controller', value=f"`{item['realname']}`", inline=False)
embed.set_footer(text=f"Logged on at: {time_logon}")
await channel.send(embed=embed)```
I try to get name of channel by channel id:
result = self._client(GetHistoryRequest(
entity,
limit=100,
offset_date=None,
offset_id=0,
max_id=0,
min_id=last_read_message_id,
add_offset=0
))
for message in result.messages:
if isinstance(message.fwd_from, MessageFwdHeader):
fwd_channel_id = message.fwd_from.channel_id
if fwd_channel_id:
fwd_result = self._client(GetFullChannelRequest( # problem!!!
InputPeerChannel(message.fwd_from.channel_id, 0)
))
message.fwd_from looks like:
fwd_from=MessageFwdHeader(
channel_id=1053596007,
date=datetime.fromtimestamp(1507891987.0),
post_author=None, # None!!!
from_id=None,
channel_post=3030
),
So, I cant take channel name from message.fwd_from. And I dont join into this channel.
When I try to call GetFullChannelRequest, I have next error:
ChannelInvalidError(...), 'Invalid channel object. Make sure to pass
the right types, for instance making sure that the request is designed
for channels or otherwise look for a different one more suited.'
How to get name of channel properly?
Answer here
Example:
result = self._client(GetHistoryRequest(
entity,
limit=100,
offset_date=None,
offset_id=0,
max_id=0,
min_id=last_read_message_id,
add_offset=0
))
for message in result.messages:
if isinstance(message.fwd_from, MessageFwdHeader):
entity = self._client.get_input_entity(
PeerChannel(message.fwd_from.channel_id)
)
if message.fwd_from.channel_id:
fwd_result = self._client(GetFullChannelRequest(entity))
if hasattr(fwd_result, 'chats') and len(fwd_result.chats) > 0:
fwd_title = fwd_result.chats[0].title
In last version telethon you can search it in message object, example from channel name it's
message.forward.chat.title
For user
message.forward.sender.first_name