I am reworking my discord bot with cogs and I'm stuck on the snipe function:
import discord
from discord.ext import commands
class Snipe(commands.Cog):
def __init__(self, client):
self.Client = client
#commands.Cog.listener()
async def on_ready(self):
print ("Snipe is now enabled")
async def on_message_delete(self, message):
messageauthor = {}
messagecontent = {}
messageauthor[message.channel.id] = message.author
messagecontent[message.channel.id] = message.content
#commands.command()
async def snipe(self, ctx):
channel = ctx.channel
try:
em = discord.Embed(description = f"said:\n{ctx.messagecontent[channel.id]}", color = 0x00c230)
em.set_author(name = f"Last deleted message in #{ctx.channel.name}")
em.set_thumbnail(url="https://cdn.discordapp.com/avatars/352793093105254402/8a2018de21ad29973696bfbf92fc31cd.png?size=4096")
em.set_footer(text = f"Snipe requested by {ctx.message.author}")
await ctx.channel.send(embed = em)
except:
embed = discord.Embed(colour = 0x00c230)
embed.set_author(name=f"There are no deleted messages in #{ctx.channel.name}!")
embed.set_thumbnail(url="https://cdn.discordapp.com/avatars/352793093105254402/8a2018de21ad29973696bfbf92fc31cd.png?size=4096")
embed.set_footer(text=f"Snipe requested by {ctx.message.author}")
await ctx.channel.send(embed=embed)
def setup(client):
client.add_cog(Snipe(client))
This is my code so far, this is the part that doesn't seem to work:
#commands.command()
async def snipe(self, ctx):
channel = ctx.channel
try:
em = discord.Embed(description = f"said:\n{ctx.messagecontent[channel.id]}", color = 0x00c230)
em.set_author(name = f"Last deleted message in #{ctx.channel.name}")
em.set_thumbnail(url="https://cdn.discordapp.com/avatars/352793093105254402/8a2018de21ad29973696bfbf92fc31cd.png?size=4096")
em.set_footer(text = f"Snipe requested by {ctx.message.author}")
await ctx.channel.send(embed = em)
When I try to snipe a deleted message it just shows the text for the "no messages to snipe" option.
If anyone can help with this/has their own code, edit it as much as you want ill work around that,
Thanks!
Well, in python, if you assign a variable in a function, it will be considered as a local variable. To make it global, you will need to use the global keyword. but since you are coding in a class, you can assign the variable to the class, like:
# to assign
self.messageauthor = {}
# to use
print(self.messageauthor)
So your new code will be:
#commands.command()
async def snipe(self, ctx):
channel = ctx.channel
try:
em = discord.Embed(title="Put something here", description = f"said:\n{ctx.messagecontent[channel.id]}", color = '0x00c230') #color code should be a str
em.set_author(name = f"Last deleted message in #{ctx.channel.name}")
em.set_thumbnail(url="https://cdn.discordapp.com/avatars/352793093105254402/8a2018de21ad29973696bfbf92fc31cd.png?size=4096")
em.set_footer(text = f"Snipe requested by {ctx.message.author}")
await ctx.channel.send(embed = em)
except:
embed = discord.Embed(title="", description="", colour = '0x00c230') # should be str
embed.set_author(name=f"There are no deleted messages in #{ctx.channel.name}!")
embed.set_thumbnail(url="https://cdn.discordapp.com/avatars/352793093105254402/8a2018de21ad29973696bfbf92fc31cd.png?size=4096")
embed.set_footer(text=f"Snipe requested by {ctx.message.author}")
await ctx.channel.send(embed=embed)
Also, title and description are required arguments to make an embed. and, the html color code should be a str. (Use ''). I hope this much helps you.
Related
I’m trying to code a simple music bot for discord in python. I tried coding a queue command so that I can queue a certain song (searching for songs and playing them etc. all work). This is my code for the queue command:
#commands.command()
async def checkqueue(self, ctx):
if len(self.song_queue[ctx.guild.id]) == 0:
return await ctx.send("Queue is empty")
else:
embed = discord.Embed(title="Song Queue", description="", colour=discord.colour.dark_gold())
i = 1
for url in self.song_queue[ctx.guild.id]:
embed.description += f"{i}) {url}\n"
i += 1
await ctx.send(embed=embed)
When the queue is empty, the bot sends a message in discord saying "Queue is empty”. When I use the play command, it adds a song to the queue. However, when I try to use the checkqueue command when there’s at least one song in the queue, the bot doesn’t send the embed. Not sure if this is a problem with the code in the queue command or outside the queue command, so here’s the cut-down version of the rest of my code in my commands Cog.
import discord
from discord.ext import commands
import youtube_dl
import pafy
import asyncio
class Commands(commands.Cog):
def __init__(self, client):
self.client = client
self.song_queue = {}
#commands.Cog.listener()
async def on_ready(self):
for guild in self.client.guilds:
self.song_queue[guild.id] = []
async def check_queue(self, ctx):
if len(self.song_queue[ctx.guild.id]) > 0:
ctx.voice_client.stop()
await self.play_song(ctx, self.song_queue[ctx.guild.id][0])
self.song_queue[ctx.guild.id].pop(0)
async def search_song(self, amount, song, get_url=False):
info = await self.client.loop.run_in_executor(None, lambda: youtube_dl.YoutubeDL({"format": "bestaudio", "quiet" : True}).extract_info(f"ytsearch{amount}:{song}", download=False, ie_key="YoutubeSearch"))
if len(info["entries"]) == 0:
return None
return [entry["webpage_url"] for entry in info["entries"]] if get_url else info
async def play_song(self, ctx, song):
url = pafy.new(song).getbestaudio().url
ctx.voice_client.play(discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(url)), after=lambda error: self.client.loop.create_task(self.check_queue(ctx)))
ctx.voice_client.source.volume = 0.5
#commands.command()
async def stop(self, ctx):
if ctx.voice_client is not None:
return await ctx.voice_client.disconnect()
return await ctx.send("Disconnected")
else:
return await ctx.send("I am not connected to a voice channel")
#commands.command()
async def join(self, ctx):
if ctx.author.voice is None:
return await ctx.send("You are not connected to a voice channel")
else:
channel = ctx.author.voice.channel
await channel.connect()
await ctx.send(f"Connected to voice channel: '{channel}'")
#commands.command()
async def play(self, ctx, *, song=None):
if song is None:
return await ctx.send("You must include a song to play.")
if ctx.voice_client is None:
return await ctx.send("I must be in a voice channel to play a song.")
if not ("youtube.com/watch?" in song or "https://youtu.be/" in song):
await ctx.send("Searching for a song, this may take a few seconds...")
result = await self.search_song(1, song, get_url=True)
if result is None:
return await ctx.send("Sorry, I couldn't find the song you asked for. Try using my search command to find the song you want.")
song = result[0]
if ctx.voice_client.source is not None:
queue_len = len(self.song_queue[ctx.guild.id])
if queue_len < 10:
self.song_queue[ctx.guild.id].append(song)
return await ctx.send(f"Song added to the queue at position {queue_len+1}")
else:
return await ctx.send("Maximum queue limit has been reached, please wait for the current song to end to add more songs to the queue")
await self.play_song(ctx, song)
await ctx.send(f"Now playing: {song}")
#commands.command()
async def search(self, ctx, *, song=None):
if song is None:
return await ctx.send("Please include a song to search for")
await ctx.send("Searching for song, this may take a few seconds...")
info = await self.search_song(5, song)
embed = discord.Embed(title=f"Results for '{song}':", description="You can use these URL's to play the song\n", colour=discord.Colour.blue())
amount = 0
for entry in info["entries"]:
embed.description += f"[{entry['title']}]({entry['webpage_url']})\n"
amount += 1
embed.set_footer(text=f"Displaying the first {amount} results.")
await ctx.send(embed=embed)
#commands.command()
async def checkqueue(self, ctx):
if len(self.song_queue[ctx.guild.id]) == 0:
return await ctx.send("Queue is empty")
else:
embed = discord.Embed(title="Song Queue", description="", colour=discord.colour.blue())
i = 1
for url in self.song_queue[ctx.guild.id]:
embed.description += f"{i}) {url}\n"
i += 1
await ctx.send(embed=embed)
#commands.command()
async def queue(self, ctx, *, song=None):
if song is None:
return await ctx.send("You must include a song to queue.")
if not ("youtube.com/watch?" in song or "https://youtu.be/" in song):
await ctx.send("Searching for a song, this may take a few seconds...")
result = await self.search_song(1, song, get_url=True)
if result is None:
return await ctx.send("Sorry, I couldn't find the song you asked for. Try using my search command to find the song you want.")
song = result[0]
if ctx.voice_client.source is not None:
queue_len = len(self.song_queue[ctx.guild.id])
if queue_len < 10:
self.song_queue[ctx.guild.id].append(song)
return await ctx.send(f"Song added to the queue at position {queue_len+1}")
else:
return await ctx.send("Maximum queue limit has been reached, please wait for the current song to end to add more songs to the queue")
The issue that I was having with your code was the color of the Embed. Everything else went smoothly when I ran your code. When you referenced the Colour, you didn't properly access the function.
What you did:
embed = discord.Embed(title="Song Queue",
description="",
colour=discord.colour.dark_gold())
What you should do:
embed = discord.Embed(title="Song Queue",
description="",
colour=discord.Colour.dark_gold())
I keep trying, it was a tutorial. I did exactly what it said. I doubt the next episode will say what's wrong. why do i need so many words ,,,
#client.command()
async def balance(ctx):
await open_account(ctx.author)
user = ctx.author
users = get_bank_data()
wallet_amt = users[str(user.id)]["wallet"]
bank_amt = users[str(user.id)]["bank"]
em = discord.Embed(title = f"{ctx.author.name}'s balance",color=discord.color.dark_green)
em.add_field(name = "Wallet Balance", value = wallet_amt)
em.add_field(name = "Bank Balance", value = bank_amt)
await ctx.send(embed=em)
#client.command()
async def beg(ctx):
await open_account(ctx.author)
users = get_bank_data()
user = ctx.author
earnings = random.randrange(51)
await ctx.send(f"Someone gave you {earnings} coins!!")
users[str(user.id)]["wallet"] += earnings
with open("bank.json", "w") as f:
json.dump(users, f)
def open_account(user):
users = await get_bank_data()
with open("bank.json", "r") as f:
users = json.load(f)
if str(user.id) in users:
return False
else:
users[str(user.id)] = {}
users[str(user.id)]["wallet"] = 0
users[str(user.id)]["bank"] = 0
with open("bank.json", "w") as f:
json.dump(users, f)
return True
def get_bank_data():
with open("bank.json", "r") as f:
users = json.load(f)
return users
but with this error
z:\DBot\bot(1.2).py:108: RuntimeWarning: coroutine 'Command.__call__' was never awaited
with open("bank.json", "r") as f:
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
i don't know what to do. Sorry my questions are bad because i just want someone to answer them, dont have time to make them good
open_account() and get_bank_data() are not required be asynchronous functions,
You can use def open_account(user) and def get_back_data().
If you do that, you should remove await while calling those two functions.
I need help fixing my code
#client.command
#commands.cooldown(5, 20, commands.BucketType.user)
async def search(ctx):
await open_account(ctx.author)
user = ctx.author
users = await get_bank_data()
peen = users[str(user.id)]["wallet"]
tu = random.randint(19, 157)
rand = random.choice(hs)
embed54=discord.Embed(title='Search in...', description=f'{rand}, {rand}, {rand}')
embed54.add_footer('Do !beg for money as well!')
await ctx.send(embed=embed54)
await client.wait_for(rand)
def check(m):
return m.author == ctx.author and m.channnel == ctx.channel
embed53=discord.Embed(title='You Found...', description=f'${tu} From {ctx.message}')
await ctx.send(embed=embed53)
fa = tu
peen += fa
why does it not work
SyntaxError: 'await' outside async function
i need help
pls it gives error every time so help me
also yeah boi
Since I don't know what hs means or how you defined it I omitted the whole thing once and replaced it with a simple number just for my test.
To clarify beforehand: You had errors in creating an embed, in your check function and in your way of rendering with await functions and some typos.
This method works fine for me:
#client.command()
#commands.cooldown(5, 20, commands.BucketType.user)
async def search(ctx):
def check(m):
return m.author == ctx.author and m.channel == ctx.message.channel # New check
await open_account(ctx.author)
user = ctx.author
users = await get_bank_data()
hs = # DEFINE WHAT IT IS! <<<
peen = users[str(user.id)]["wallet"]
tu = random.randint(19, 157)
rand = random.choice(hs)
embed54 = discord.Embed(title='Search in...', description=f'{rand}, {rand}, {rand}')
embed54.set_footer(text='Do !beg for money as well!') # SET footer
await ctx.send(embed=embed54)
response = await client.wait_for('message', check=check) # Wait for MESSAGE, add check
if response.content == rand: # I assume you want to get the author say one of the numbers
embed53 = discord.Embed(title='You Found...', description=f'${tu} From {ctx.message.content}')
await ctx.send(embed=embed53)
fa = tu
peen += fa
else: # If the number is not in the embed
await ctx.send("You did not respond correctly.")
What did we do?
Re-built your check as it is m.channel and NOT m.channnel, just a little typo here
Added a "real" footer, as embed54.add_footer does not exist, it is embed54.set_footer(text='', icon_url='')
wait_for a 'message' from the author of the message and if rand, which you have to define as I do not know what hs is, is not in his answer he will not get whatever you defined. (if/else statements)
Replaced ctx.message with ctx.message.content as otherwise it will give out a longer "text" than just search
! Since there were many mistakes in your code I would recommend to have a closer look at the docs again !
i actually did this and it worked:
#commands.cooldown(5, 20, commands.BucketType.user)
async def search(ctx):
def check(m):
return m.author == ctx.author and m.channel == ctx.message.channel # New check
await open_account(ctx.author)
user = ctx.author
users = await get_bank_data()
peen = users[str(user.id)]["wallet"]
tu = random.randint(19, 157)
rand = random.choice(hs)
rand1 = random.choice(hs)
rand2 = random.choice(hs)
embed54 = discord.Embed(title='Search in...', description=f'{rand}, {rand1}, {rand2}')
embed54.set_footer(text='Do !beg for money as well!') # SET footer
await ctx.send(embed=embed54)
response = await client.wait_for('message', check=check) # Wait for MESSAGE, import check
if response.content == rand: # I assume you want to get the author say one of the numbers
embed53 = discord.Embed(title='You Found...', description=f'${tu} From {ctx.message.content}')
await ctx.send(embed=embed53)
earnings = tu
users[str(user.id)]["wallet"] += earnings
with open("mainbank.json","w") as f:
json.dump(users,f)
return True
else:
response = await client.wait_for('message', check=check)
if response.content == rand1: # I assume you want to get the author say one of the numbers
embed53 = discord.Embed(title='You Found...', description=f'${tu} From {ctx.message.content}')
await ctx.send(embed=embed53)
earnings = tu
users[str(user.id)]["wallet"] += earnings
with open("mainbank.json","w") as f:
json.dump(users,f)
return True
else:
response = await client.wait_for('message', check=check) # Wait for MESSAGE, import check
if response.content == rand1: # I assume you want to get the author say one of the numbers
embed53 = discord.Embed(title='You Found...', description=f'${tu} From {ctx.message.content}')
await ctx.send(embed=embed53)
earnings = tu
users[str(user.id)]["wallet"] += earnings
with open("mainbank.json","w") as f:
json.dump(users,f)
return True
I was trying to make my code a little cleaner by using cogs but it doesn't seem to work. When I do +balance this error comes up: Ignoring exception in command None: discord.ext.commands.errors.CommandNotFound: Command "balance" is not found: Here's the code part in main.py:
for file in os.listdir("./cogs"): # lists all the cog files inside the cog folder.
if file.endswith(".py"): # It gets all the cogs that ends with a ".py".
name = file[:-3] # It gets the name of the file removing the ".py"
bot.load_extension(f"cogs.{name}") # This loads the cog.
And from the balance file:
bot = commands.Bot(command_prefix='+')
class Balance(commands.Cog):
def __init__(self, client):
self.bot = bot
#commands.command(aliases = ["bal"])
async def balance(self, ctx):
await open_account(ctx.author)
user = ctx.author
users = await get_bank_data()
wallet_amt = users[str(user.id)]["wallet"]
#bank_amt = users[str(user.id)]["bank"]
em = discord.Embed(title = f"{ctx.author.name}'s balance",color = (0x95a5a6), description = f"{wallet_amt} dogecoins")
#em.add_field(name = "Bank balance",value = bank_amt)
await ctx.send(embed = em)
async def open_account(user):
users = await get_bank_data()
if str(user.id) in users:
return False
else:
users[str(user.id)] = {}
users[str(user.id)]["wallet"] = 250
users[str(user.id)]["bank"] = 0
with open("mainbank.json","w") as f:
json.dump(users,f)
return True
async def get_bank_data():
with open("mainbank.json","r") as f:
users = json.load(f)
return users
async def update_bank(user,change = 0,mode = "wallet"):
users = await get_bank_data()
users[str(user.id)][mode] += change
with open("mainbank.json","w") as f:
json.dump(users,f)
return True
def setup(bot):
bot.add_cog(Balance(bot))
I'm new to coding and cogs especially so if anyone knows how to fix this, please help me.
I can't tell if the commands and functions you're showing are inside the class or not. Also, why are you creating a new Bot instance, and why does your init function take an argument called client and then set self.bot to bot?
Try replacing client in your init function with bot, or vice versa.
Do you get any errors when you try to run your main file?
I would like to, as an admin, add points to a specific member's balance
Know how to create a JSON file with all the "points" someone has.
import discord
from discord.ext import commands
import random
import os
import json
# this line of code gives the bot a comand prefix
bot = commands.Bot(command_prefix="/")
# This line of code tells the bot to start up
#bot.event
async def on_ready():
print("The bot is now online!")
#bot.command(pass_context=True)
async def leaderboard(ctx):
await ctx.send("This is a work in progress, this will dieplay the leaderboard")
amounts = {}
#bot.command(pass_context=True)
async def balance(ctx):
id = str(ctx.message.author.id)
if id in amounts:
await ctx.send("You have {} ben points".format(amounts[id]))
else:
await ctx.send("You do not have an account")
#bot.command(pass_context=True)
async def register(ctx):
id = str(ctx.message.author.id)
if id not in amounts.keys:
amounts[id] = 100
await ctx.send("You are now registered")
_save()
else:
await ctx.send("You already have an account")
#bot.command(pass_context=True)
async def transfer(ctx, amount: int, other: discord.Member):
primary_id = str(ctx.message.author.id)
other_id = str(other.id)
if primary_id not in amounts:
await ctx.send("You do not have an account")
elif other_id not in amounts:
await ctx.send("The other party does not have an account")
elif amounts[primary_id] < amount:
await ctx.send("You cannot afford this transaction")
else:
amounts[primary_id] -= amount
amounts[other_id] += amount
await ctx.send("Transaction complete")
_save()
def _save():
with open('amounts.json', 'w+') as f:
json.dump(amounts, f)
#bot.command()
async def save():
_save()
#This line of code tells the bot to run
bot.run("Token")
I am not sure on what I am meant to do from here.
I might be over complicating the code if anyone can make it more efficient I will be incredibly grateful.
Here's the essential usage and everything you'll need to know for the basics of JSON:
# Creating a dictionary with some values
>>> data = {"foo": "bar", "key": "value"}
# Opening a file and writing to it
>>> with open("db.json", "w+") as fp:
... json.dump(data, fp, sort_keys=True, indent=4) # Kwargs for beautification
# Loading in data from a file
>>> with open("db.json", "r") as fp:
... data = json.load(fp)
# Accessing the values
>>> data["foo"]
'bar'
>>> data["key"]
'value'
This can be adapted to suit your needs, perhaps something like:
# Let's say the JSON has the following structure:
# {"users": {112233445566778899: {"points": 0}, 224466881133557799: {"points": 0}}}
# The "users" key is a bit redundant if you're only gonna store users in the file.
# It's down to what you'll be storing in the file and readability etc.
import json
import random
import typing
def add_points(member_id: str, amount: int):
# Open the file first as to load in all the users' data
# Making a new dict would just overwrite the current file's contents
with open("file.json", "r") as fp:
data = json.load(fp)
data["users"][member_id]["points"] += amount
# Write the updated data to the file
with open("file.json", "w+") as fp:
json.dump(data, fp, sort_keys=True, indent=4)
return data["users"][user_id]["points"]
#bot.command()
async def give(ctx, member: typing.Optional[discord.Member]=None, points:typing.Optional[int]=None):
if not member:
member = ctx.author
if not points:
points = random.randint(10, 50)
# Have a separate getter for the points - this was just for the sake of concise code
total_points = add_points(member.id, points)
await ctx.send(f"Successfully gave {member.mention} {points} points! Total: {total_points}")
I'll be happy to clarify anything if need be.
References:
Dictionary exercises - Might be worth taking a look into so then you're comfortable with how they work.
f-Strings - Python 3.6.0+
json.load()
json.dump()
typing.Optional
User.id
commands.Context
Context.author