So I wrote a Discord bot in Python and it worked. But, when I close my Python shell (where I run my code) the bot stops working. Is there anything I can do so my bot keeps working no matter if the shell is closed or not? Just in case if you need the code, here it is
import os
import random
import datetime
import discord
bot = discord.Client()
#bot.event
async def on_member_join(member):
if member.id == bot.id:
return
channel = discord.utils.get(bot.guilds[0].channels,name="genral")
member_id = member.id
response = f"Welcome to For Testing,<#{member_id}> !"
await channel.send(response)
#bot.event
async def on_message(message):
if message.author == bot.user:
return
Keywords = ["sup","lol","yeet"]
channel = message.channel
for keyword in Keywords:
if keyword.lower() in message.content.lower():
user_id = message.author.id
response = f"Did someone say {keyword.lower()}? I guess it was <#{user_id}>"
await channel.send(response)
#bot.event
async def reminder():
while(True):
await bot.wait_until_ready()
online_members = []
for member in bot.get_all_members():
online_members.append(member.id)
if len(online_members) > 0:
user = random.choice(online_members)
channel = discord.utils.get(bot.guilds[0].channels,name="genral")
response = f"So what are u up to <#{user.id}>"
await channel.send(response)
await asyncio.sleep(3600)
bot.loop.create_task(reminder())
real_token = "THE TOKEN"
bot.run("THE TOKEN")
You can save your script as a file with the file extension .py and then run it through your file manager (e.g. double-click the file in Windows). That should run your script without needing the shell open.
https://realpython.com/run-python-scripts/#how-to-run-python-scripts-from-a-file-manager
On Windows, you can use pythonw.exe in order to run a python script as a background process:
Python scripts (files with the extension .py) will be executed by python.exe by default. This executable opens a terminal, which stays open even if the program uses a GUI. If you do not want this to happen, use the extension .pyw which will cause the script to be executed by pythonw.exe by default (both executables are located in the top-level of your Python installation directory). This suppresses the terminal window on startup.
For example,
C:\ThanosDodd\Python3.6\pythonw.exe C:\\Python\Scripts\moveDLs.py
or
pythonw.exe pythonFile.py
You can export code onto repl.it and make one more file called keep_alive.py
from flask import Flask
from threading import Thread
app = Flask('')
#app.route('/')
def main():
return "Your bot is alive!"
def run():
app.run(host="0.0.0.0", port=<any Port>)
def keep_alive():
server = Thread(target=run)
server.start()
then do
from keep_alive import keep_alive
then call the keep_alive function before bot.run
this makes a flask server then u can take the server link and make a monitor in http://uptimerobot.com/
For more info check the link
https://repl.it/talk/learn/Hosting-discordpy-bots-with-replit/11008
Related
Purpose:
To add more commands without interrupting other commands
I have been looking around to find a way to roll out updates without interrupting the flow of my bot, since it has some asyncio functions that execute a while after the function has been called
I have tried:
await client.logout()
Above will logout the bot, but also closes the command line. I found this on the discord.py docs.
I am running Windows 10, with Python version 3.9
Any help would be appreciated. Thanks in advance.
If you don't want to kill the current process and instead just want hot-reloading of different functionality, you might want to look into discord.py's extensions feature. Using extensions and cogs will allow you to enable/disable/reload certain features in your bot without stopping it (which should keep tasks running). It's also the built-in method for hot-reloading.
Extensions and cogs are typically used together (though they don't have to be). You can create files for each group of similar commands you want to reload together.
The following code samples should be integrated into your setup. You'll probably also want to add error handling and input checks, but it should give you an idea of what's going on. For a detailed explanation or method options, check out the docs.
# info.py
# ...
# this is just an example
class Info(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.command()
async def about(self, ctx):
await ctx.send("something here")
# ...
# extensions need a setup function
def setup(bot):
bot.add_cog(Info(bot))
# main.py
# ...
bot = commands.Bot(
# ...
)
bot.load_extension("info")
bot.run(token)
# reload command
#bot.command()
async def reload(ctx, extension):
# probably want to add a check to make sure
# only you can reload things.
# also handle the input
bot.reload_extension(extension)
to use, you might do something like `prefix!reload info`
Create a new python file in the same directory with the name startup.py for example. Inside this file do the following:
import os
import time
time.sleep(5)
os.system('python YOUR_BOTS_FILE_NAME.py')
Then in the file where your bot's code is add a new command that we are going to call restart for example:
import discord
from discord.ext import commands
import os
#client.command()
#commands.is_owner()
async def restart(ctx):
os.system('python startup.py')
exit()
In the startup.py file, os waits 5 seconds for your bot's file to turn off and then turns it on. The restart command in your bot's file starts the startup file then shuts itself down.
#commands.is_owner()
Makes sure the author of the message is you so people don't restart your bot.
I am developing a bot myself and I have made a shutdown command myself which shuts down the bot without using terminal.
First I would add the code and then explain it.
Code:
myid = <my discord account ID>
#MyBot.command()
async def shutdown(ctx):
if ctx.author.id == myid:
shutdown_embed = discord.Embed(title='Bot Update', description='I am now shutting down. See you later. BYE! :slight_smile:', color=0x8ee6dd)
await ctx.channel.send(embed=shutdown_embed)
await MyBot.logout()
if ctx.author.id != myid:
errorperm_embed = discord.Embed(title='Access Denied!', description='This command is `OWNER` only. You are not allowed to use this. Try not to execute it another time.', color=0xFF0000)
errorperm_embed.set_footer(text=ctx.author)
await ctx.channel.send(embed=errorperm_embed, delete_after=10.0)
I have not added any has_permissions as I don't need it when I using my discord ID to restrict its usage.
Explanation:
I have defined a variable, myid which is equal to my discord account ID.
Check here on how to get user ID:
https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-
I have added a condition that if the ID of the user who used this command is equal to myid or if it is not. If it is equal to my account' ID then it would shutdown the bot otherwise it would show an error to the user.
I have simply used await MyBot.logout() which logs you out and disconnect.
You can place your code in a while True loop.
while True:
client = commands.Bot(command_prefix='!')
async def restart(ctx):
await client.logout()
client.run('token')
You could just replace the current process with the same process, starting anew. You have to flush buffers and close file-pointers beforehand, but that's easy to do:
import os
import sys
from typing import List
def restart(filepointers: List):
# this cleanup part is optional, don't need it if your bot is ephemeral
# flush output buffers
sys.stdout.flush()
sys.stderr.flush()
# flush and close filepointers
for fp in filepointers:
os.fsync(fp)
fp.close()
# replace current process
os.execl(*sys.argv)
Then just call this function with your bot as you would(from the same file).
If you want to update your code you must restart the program.
import os
path = "your .py file path"
#client.command(name="restart")
async def restart_command(ctx):
await client.close()
os.system("python " + path)
I am currently trying to make a discord bot where when you type the command !purge in the desired channel, it will constantly delete all the messages sent, and when you type it again, it will stop deleting all the messages.
From learning online I know I have to use a Cog listener, but I don't exactly know how to "trigger" it with a command. I would need the #commands.Cog.listener() paragraph to use the on_message listener, but I also can't figure out how I would get it to delete messages in the channel where the command !purge was executed.
I tried already using a boolean value to toggle on and off when the command was typed and it would use a while loop to constantly delete messages, but then the while loop would stop. It might have been because the session of the command expired, not sure about that though.
Any thoughts on how I can use get this working? More specifically, how I can somehow link the Cog to the command? Thanks!
(Edits of my code I tried to use to be here but I have deleted them because of irrelevancy)
Cog Thread I found: https://stackoverflow.com/a/53528504/11805086
You'd have to create a trigger command, which enables or disables the purge mode and then, in your on_message function, you'd have to check if the purge mode is enabled or not.
Here's how to do it (within a cog):
Edited by poster
In cogs.py
from discord.ext import commands
class Purge_Cog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.channels = {}
#commands.command()
async def purge(self, ctx):
try:
if self.channels[ctx.channel]:
self.channels[ctx.channel] = False
await ctx.channel.send("Purge mode disabled!")
else:
self.channels[ctx.channel] = True
await ctx.channel.send("Purge mode enabled!")
except:
self.channels[ctx.channel] = True
await ctx.channel.send("Purge mode enabled!")
#commands.Cog.listener()
async def on_message(self, message):
try:
if self.channels[message.channel]:
await message.channel.purge(limit=999)
except:
pass
def setup(bot):
bot.add_cog(Purge_Cog(bot))
In your main file add this (bot.py or main.py)
import discord
from discord.ext import commands
initial_extensions = ['cogs.cogs']
if __name__ == '__main__':
for extension in initial_extensions:
bot.load_extension(extension)
bot.run('Your token')
I'm wondering how would I run my 2 discord bots at once from main, app.py, file.
And after I kill that process (main file process), they both would stop.
Tried os.system, didn't work. Tried multiple subprocess.Popen, didn't work.
Am I doing something wrong?
How would I do that?
You can use subprocess in python. Link for docs Example:
bot1.py
import discord
from discord.ext import commands
client = commands.Bot(command_prefix='!')
#client.event
async def on_ready():
print("Ready bot1")
#client.command()
async def command1(ctx):
await ctx.send("Bot1")
client.run('TOKEN')
bot2.py
import discord
from discord.ext import commands
client = commands.Bot(command_prefix='!')
#client.event
async def on_ready():
print("Ready bot2")
#client.command()
async def command2(ctx):
await ctx.send("Bot2")
client.run('TOKEN')
main.py
import subprocess
subprocess.Popen('python bot1.py')
subprocess.Popen('python bot2.py')
In command line: python main.py and wait when 2 bots will be ready.
Result:
P.S. You will have one problem: one bot will issue errors if it doesn't see the commands you run for another bot. It's big problem for debugging. Sorry for my bad English :)
I think the good design is to have one bot per .py file. If they both need code that is in app.py then they should 'import' the common code. Doing that you can just run both bot1.py and bot2.py.
I want to make a bot that runs bash commands through the discord api with a checker against a file called admin.json that would run through discord's API running bash commands on my vps server so I don't have to logon each time through ssh. I want to do this over discord specifically.
I tried researching LIKE EVERYWHERE..
https://discordpy.readthedocs.io/en/latest/api.html#discord.MessageType
This was the closet I have gotten to about what I need: To return the message.content identifier. I want to be able to access my vps server over discord so I don't have to login each time through ssh.
import discord
import sys
import os
import json
import subprocess
import asyncio
from discord.ext import commands
t = "<token here>"
with open("admin.json", "r") as admin:
admin = json.load(admin)
client = commands.Bot(command_prefix='-')
#client.event
async def on_ready():
print('Bash bot is online')
#client.command()
async def on_message(ctx, arg1):
if str(ctx.author.id) in(admin):
command = ctx.message.content #this for some reason fails
cmd = subprocess.getoutput(command)
await ctx.send(command)
print(str(ctx.message.content)) #even this one fails :(
else:
pass
await ctx.send("You don't have permission to use this command!" + "\n" + "<" + "#" + str(ctx.author.id) + ">")
client.run(t, bot=True)```
Should be able to run with any args so if there is a space between a bash command it shouldn't break the bot like:
```wget https://google.com``` <- Should not break the discord bot
My most common error message:
```File "bot.py", line 23, in run
print(message.content)
AttributeError: 'str' object has no attribute 'content'
You can make a check to handle checking the ids. I'm not sure where your problem with ctx.message is coming from, I suspect you had some code that is assigning to it.
with open("admin.json", "r") as admin:
admin = [int(x) for x in json.load(admin)]
def is_any_user(ids):
def predicate(ctx):
return ctx.message.author.id in ids
return commands.check(predicate)
#is_any_user(admin)
#client.command(name="run")
async def run_command(ctx, *, command_string):
output = subprocess.getoutput(command_string)
await ctx.send(output)
#run_command.error
async def run_error(ctx, error):
if isinstance(error, commands.CheckFailure):
await ctx.send(f"You don't have permission, {ctx.author.mention}")
else:
raise error
I have a python script that contains code for the discord bot. When I run it, it activates the discord bot and shows the status for the bot as online. But, when I end the python script, it disables the bot. How could I keep the bot active without using a server even when I'm offline?
I used a keep_alive script on mine.
Add to start of main.py code:
from keep_alive import keep_alive
Add to bottom of main.py code:
keep_alive()
Then create a file called keep_alive.py, and add the code:
from flask import Flask
from threading import Thread
app = Flask('')
#app.route('/')
def home():
return "Server Host Connected and Synced to Main Code."
def run():
app.run(host='0.0.0.0',port=8080)
def keep_alive():
t = Thread(target=run)
t.start()
If you make a file called requirements.txt, or use it if you already have one.
Add:
flask
If the bot is Python this should work. It works for me on repl.it
Maybe try using if/else statements, so something like:
User = (your userID)
Bot = (Bot userID)
If User online keep Bot online
Else keep Bot online