Python Discord Bot problems - python

this is a long one.
so basically im trying to code a Python bot based on Harry Potter, and on my pc im using repl.it
and on my laptop im using PyCharm CE.
my laptop doesnt detect any type of discord (as in import discord) and my pc comes up with the error "AttributeError: 'NoneType' object has no attribute 'strip'". plus repl.it wont allow me to create a .env file and i cant figure out how to use Secrets (Environment Variables). my laptop also will not let me reinstall/uninstall discord and comes up with a LOT of errors (OSErro when i try to force reinstall, permission denied etc. i dont know how to change permissions)
The following is the troublesome code. Note they are the exact same on both platforms
import os
client = discord.Client()
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('$hello'):
await message.channel.send('Hello!')
client.run(os.getenv('TOKEN'))'''

Short answer:
In the last line, simply change client.run(os.getenv('TOKEN')) to client.run('<bot-token>') where '<bot-token>' is supposed to be your actual bot token in string format. (In case you aren't sure where to find the bot token of your bot, this link may help)
Long answer:
The client.run() function needs your bot token as the argument in string format. From the error message that you mentioned, it seems that os.getenv('TOKEN') is returning None value, and it seems internally it is trying to strip the given token and failing to strip it because None value doesn't have strip attribute unlike string values. Have you stored your bot token in the key 'TOKEN' of os.environ in string format? Unless you are doing that, I don't think you should use os.getenv('TOKEN') at all. Just enter the bot token as a string, directly as the argument in client.run(). (In case you aren't sure where to find the bot token of your bot, this link may help)
Btw, I am assuming that the ''' in the end is a typo and if not then please remove it!
So, the new code would look like:
import os
import discord
client = discord.Client()
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('$hello'):
await message.channel.send('Hello!')
client.run('<your bot token>')

Related

Why is this not working for my Discord bot?

I'm currently working on a Discord bot for a server I moderate (and hope to eventually get onto the dev team for the project we run). It was working just fine when my code looked like this:
import discord
import os
client = discord.Client()
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('!hello'):
await message.channel.send('Hello!')
I had an issue with this however, and that is that the command was case sensitive and allowed anything to follow the command. I tried following something I found on another post here and came up with this:
import discord
import os
client = discord.Client()
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.lower == "!hello":
await message.channel.send("Hello!")
Now that I do that, the command doesn't work. Is the issue the exclamation point in the string? That's my best guess, but what do I know? If there's a way to do this that makes implementing more commands easier, I'm willing to start the code over because I don't have many commands implemented yet, but I need to add more in the future. If this is a relatively easy way to do it, while doing what I want it to (respond to commands that have an exclamation point at the beginning, the letters in the right order with no extra letters, and not pay attention to case, with a simple message) then simply fixing the issue with this method not functioning would be acceptable.
lower is a method. So if you want to use it, you should use lower(). So your code should look like this:
import discord
import os
client = discord.Client()
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.lower() == "!hello":
await message.channel.send("Hello!")
Hope this helps:))
As mentioned by CrazyChucky, its lower() that you want. And the comment regarding commands is probably one that might help you out a bit. If you want to achieve the same thing using a command it would look like this:
import discord
import os
from discord.ext import commands
client = commands.Bot(command_prefix='!')
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#client.command()
async def hello(ctx):
await ctx.send("Hello!")
This way you predefine that all commands starts with ! and you can set up more commands easily. Instead of the message you have something called context or ctx as it's always referred to. ctx.send is the same as writing ctx.channel.send so you can see the similarity between it and message that you previously used.
You mentioned that you didnt want to allow anyone to write anything after the command. And this also achieves that, however, if you at any point want someone to follow up on the command with some additional information it is very easy to add this. Simply by adding a second parameter to the function that can later be accessed:
#client.command()
async def hello(ctx, args):
await ctx.send(args)
If a user then calls the command using !hello world the bot would send world back to the channel.

Sending messages in discord.py #tasks.loop()

Goal:
I am simply trying to send a message to a discord channel from a #tasks.loop() without the need for a discord message variable from #client.event async def on_message. The discord bot is kept running in repl.it using uptime robot.
Method / Background:
A simple while True loop in will not work for the larger project I will be applying this principle to, as detailed by Karen's answer here. I am now using #tasks.loop() which Lovesh has quickly detailed here: (see Lovesh's work).
Problem:
I still get an error for using the most common method to send a message in discord using discord.py. The error has to have something to do with the await channel.send( ) method. Neither of the messages get sent in discord. Here is the error message.
Code:
from discord.ext import tasks, commands
import os
from keep_alive import keep_alive
import time
token = os.environ['goofyToken']
# Set Up Discord Client & Ready Function
client = discord.Client()
channel = client.get_channel(CHANNEL-ID)
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#tasks.loop(count=1)
async def myloop(word):
await channel.send(word)
#client.event
async def on_message(message):
msg = message.content
if msg.startswith('!'):
message_to_send = 'Hello World!'
await channel.send(message_to_send)
myloop.start(message_to_send)
keep_alive()
client.run(token)
Attempted Solutions:
A message can be sent from the on_message event using the syntax await message.channel.send('Hello World!). However, I just can't use this. The code is kept running online by uptimerobot, a free website which pings the repository on repl.it. When the robot pings the repository, the message variable is lost, so the loop would stop scanning my data in the larger project I am working on which is giving me this issue.
When using any client.get_* method the bot will try to grab the object from the cache, the channel global variable is defined before the bot actually runs (so the cache is empty). You should get the channel inside the loop function:
#tasks.loop(count=1)
async def myloop(word):
channel = client.get_channel(CHANNEL_ID)
await channel.send(word)

How do i get a discord bot to make and assign roles using Discord.py?

I want to make a bot that makes and assigns a role to the person who requested it. How do I do that? I have tried many things but they all don't work. Here is a copy of the non-functioning code.
import discord
import os
from discord.utils import get
client = discord.Client()
#client.event
async def on_ready():
print ('we have logged in as {0.user}'.format(client))
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('~hello?'):
await message.channel.send('YOU WILL NOW WISH YOU NEVER SUMMONED ME...')
client.run(os.environ['TOKEN'])
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content == ('~begin?'):
role = get(message.server.roles, name=('Admin'))
await client.add_roles(message.author, role)
client.run(os.environ['TOKEN'])
The first part works (~hello?) but the second part (~begin?) doesn't work. Can one of you gracious souls save me from this endless tussle of debugging and coding?
You can add a command using the #client.command function, but first you need to add a prefix to `client by doing
client = commands.AutoShardedBot(commands.when_mentioned_or(*prefix*))
remember to import commands using from discord.ext import commands
then your life would be easy now, if you want to add a command just do
#client.command
async def add_role(ctx, member:discord.Member):
role = get(ctx.guild.roles, name='*the role*')
await member.add_roles(role)
so to call the command just say *prefix* add_role #*the user*
I see a few mistakes in your code.
To get back to your question:
If you want to get the role in a server you have to request the guild, server is kind of outdated. In code this means the following:
role = message.guild.roles.
Reference: Message.guild
After getting the role we have to assign it to a member, this does not work with client.add_roles, try message.author.add_roles() instead. It'll be await message.author.add_roles(role) in the long version then.
If you want to assign a role to a member through your bot you also need to enable Intents. There are tons of Contributions on this site but also in the docs, for example:
Docs
How to get intents to work?

How can a discord bot use one of the functions that are in the same code?

I copied the discord tutorial code from
freecodecamp and I am making a discord.py bot that receives a link, but then replaces one of the words from the link. The code to replace one of the words is:
def b_link():
user_input=input("Enter a website")
link=user_input.replace("com","ca")
return (link)
This code is a part of the code that activates the discord bot, but whenever i type the link into discord for the bot to replace a word, the bot does not reply to it but I get the input command on my python shell and I have to type the link in the shell instead of on discord for the bot to reply.
Can anyone tell me what I am doing wrong? How do I get to code so that I can type the link into discord and the bot picks it up from there only.
My entire code is as follows:
``import discord
import os
client = discord.Client()
Token="<redacted>"
def b_link():
user_input=input("Enter a website")
link=user_input.replace("com","ca")
return (link)
#client.event
async def on_ready():
print('Logged in successfully {0.user}'.format(client))
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('!br https'):
link=br_link()
await message.channel.send(link)
client.run(Token)
The input() function will work on the "backend" of things, so it will not directly work with your Discord channel messages. I recommend first changing your function b_link to something like:
def b_link(original):
link = original.replace("com", "ca")
return (link)
where it takes in a parameter instead of using input. Then, in your on_message function, you can instead do something like:
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('!br https'):
original_link = str(message.content)
original_link = original_link.split(" ")[1]
link = br_link(original_link)
await message.channel.send(link)
Using message.content gets the full message string, and we can get the original link by using the str.split method. Then, we passed the original link to the b_link function, and sends the new link on the Discord channel.
While this will work, stylistically, it is better to put helper functions in a separate Python script and import them in. Additionally, you should look into using bot commands instead of client events for more convenience.

Why is my discord bot spamming?

I have previously posted on this same bot and got it working thanks to the people who responded. But, while it finally came to life and turned on, it started spamming messages for no apparent reason. I've looked over the code for typos and can't find any.
Here's the code:
import discord
from discord.ext.commands import bot
from discord.ext import commands
import asyncio
import time
Client = discord.Client()
client = commands.Bot (command_prefix = discord)
#client.event
async def on_ready() :
print("Bepis machine fixed")
#client.event
async def on_message(message) :
if message.content == "bepis" :
await client.send_message (message.channel, "bepis")
client.run("Censored Bot Token")
after #client.event is where i need help. also the bottom line if fine this time! turns out i had hit the space bar before the parenthesis and it didn't like that. Help is very appreciated so i can continue adding on to this awesome bot.
It looks like you are sending a message "bepis" in response to the first, then every, message "bepis" - presumably your first response will appear as an entry on the incoming feed which will trigger a second, etc.
Turns out I was not using proper formatting for my bot.
Whenever you say "bepis" in the discord server, the bot will see it and then say "bepis" back, as its intended to do, but, because of my improper formatting, the bot saw itself say "bepis" and responded as if someone else was saying "bepis".
Old lines:
if message.content == "bepis" :
await client.send_message(message.channel, "bepis")
New lines:
if message.content.startswith('bepis'):
await client.send_message(message.channel, "bepis")
So make sure you're using the right format if you're making a bot!
You seemed to already know what the problem is, from this answer you posted. But your solution is far from being able to solve the problem.
on_message is called whenever a new message is sent to anywhere accessible by the bot; therefore, when you type in "bepis" in discord, the bot replies with "bepis", then the message sent by the bot goes into on_message, which the bot re-replies "bepis", and so on...
The simple solution is to check if the message's author is any bot account, or if you want, if the message's author is your bot.
from discord.ext import commands
client = commands.Bot(command_prefix=None)
#client.event
async def on_ready():
print("Bepis machine fixed")
#client.event
async def on_message(message):
# or `if message.author.bot:` # which checks for any bot account
if message.author == client.user:
return
if message.content == "bepis":
await client.send_message(message.channel, "bepis")
client.run("Token")
Note: I also fixed many of your other problems, such as multiple unused imports, another Client, and indentation.
And FYI, command_prefix is only used when command is being processed by a functional command. When you use on_message it has no use, which means you can set it to None.

Categories