I am currently working on implementing a game report webhook into my discord bot, so I can send the message with buttons etc., to have a claim system (so using discords webhooks isn't a solution).
How can I run my discord bot and have flask (or every other suitable library) run simultaneously?
If I manage to get that to work, how do I transfer the data to my discord bot?
Here is what I tried:
from flask import Flask, request, Response
from json import loads
app = Flask(import_name='scp:flask')
#app.route('/webhook', methods=['POST'])
async def listener():
data = request.form
x = (loads(data.get("payload_json")))["embeds"][0]["fields"][2:9]
print(f'Data: {x}')
return Response(status=200)
app.run()
Related
I am trying to have a server that will be able to give us the status on discord.
I did achieve this by having an extra socketio client that run discord.py aswell.
I would like discord to run on the server instead of on a client. I am unable to make this work at the same time, any insight or help would be appreciated.
I tried launching discord before socketio, also tried launching discord in a different thread.
--Update--
The orginal post had a emit onConenct. this is apparently a known issue and will cause a namespace error. . please find trhe edited code below
as a minimal reproductable example here is the code:
server:
import asyncio
from time import sleep
from flask import Flask
from aiohttp import web
import socketio
from discord.ext import commands
sio = socketio.AsyncServer(async_mode='aiohttp',logger=True)
app = web.Application()
sio.attach(app)
bot = commands.Bot(command_prefix='+')
#bot.command(help="testing")
async def test(ctx):
await ctx.send("Hello world!")
await sio.emit('marco')
#sio.on('polo')
async def message(sid):
print("a wild client responded")
async def start_discord():
print('starting discord')
await bot.start('token')
if __name__ == '__main__':
asyncio.run(asyncio.gather(web.run_app(app),start_discord()))
client :
import asyncio
from click import prompt
import socketio
from discord.ext import commands
sio = socketio.Client(logger=True)
#sio.on("marco")
def polo():
sio.emit('polo')
print("wow i found a server")
if __name__ == "__main__":
sio.connect("http://localhost:8080")
sio.wait()
Ther server and client are connecting but not discord.
Your issue is that the socket server only starts when the discord bot exists. This will never happen.
If you want to run 2 functions concurrently use asyncio.gather in combination with client.start
Like this:
if __name__ == '__main__':
asyncio.run(
asyncio.gather(
bot.start('SuperSecret Token')
sio.start(app, host="localhost", port=8080)
)
)
This will ensure they start the the same time.
Note your code to create a custom event loop is probably unnecessary.
Having multiple calls to asyncio.run in your code is a mistake 99% of the time. You normally need only one async context.
I am designing an app where I can send notification to my discord channel when something happen with my python code (e.g new user signup on my website). It will be a one way communication as only python app will send message to discord channel.
Here is what I have tried.
import os
import discord
import asyncio
TOKEN = ""
GUILD = ""
def sendMessage(message):
client = discord.Client()
#client.event
async def on_ready():
channel = client.get_channel(706554288985473048)
await channel.send(message)
print("done")
return ""
client.run(TOKEN)
print("can you see me?")
if __name__ == '__main__':
sendMessage("abc")
sendMessage("def")
The issue is only first message is being sent (i-e abc) and then aysn function is blocking the second call (def).
I don't need to listen to discord events and I don't need to keep the network communication open. Is there any way where I can just post the text (post method of api like we use normally) to discord server without listening to events?
Thanks.
You can send the message to a Discord webhook.
First, make a webhook in the Discord channel you'd like to send messages to.
Then, use the discord.Webhook.from_url method to fetch a Webhook object from the URL Discord gave you.
Finally, use the discord.Webhook.send method to send a message using the webhook.
If you're using version 2 of discord.py, you can use this snippet:
from discord import SyncWebhook
webhook = SyncWebhook.from_url("url-here")
webhook.send("Hello World")
Otherwise, you can make use of the requests module:
import requests
from discord import Webhook, RequestsWebhookAdapter
webhook = Webhook.from_url("url-here", adapter=RequestsWebhookAdapter())
webhook.send("Hello World")
I have found it. "Webhook" is the answer. Instead of using discord.py, just create a webhook for your channle and then just post the data to that endpoint.
import requests
#Webhook of my channel. Click on edit channel --> Webhooks --> Creates webhook
mUrl = "https://discord.com/api/webhooks/729017161942******/-CC0BNUXXyrSLF1UxjHMwuHA141wG-FjyOSDq2Lgt*******************"
data = {"content": 'abc'}
response = requests.post(mUrl, json=data)
print(response.status_code)
print(response.content)
This might be one of the best approaches as it saves the addition of more python packages(one mentioned by #john), but I believe there is a more robust and easy solution for this scenario, as you can add images, make tables and make those notifications look more expressive.
A python library designed for the explicit purpose of sending a message to the discord server. A simple example from the PyPI page would be:
from discord_webhook import DiscordWebhook
webhook = DiscordWebhook(url='your webhook url', content='Webhook Message')
response = webhook.execute()
more examples follow on the page.
This is how the sent notification/message would look like
Discord notification with table
I was wondering if I can automatically download files from other telegram bots. I've searched online how to make a Python bot (or a Telegram bot written in Python) which do this, but I didn't find anything. Can someone help me?
Interaction between bots in telegram directly isn't possible since the Bot API doesn't support that.
But you can use MTProto libraries to automate almost all interactions with bots (including file downloading). since these libs simply automate regular user accounts, they don't have the limitations of the bot api.
Here is an example to download a file using telethon lib :
from telethon import TelegramClient, events
api_id = <API_ID>
api_hash = '<API_HASH>'
client = TelegramClient('session', api_id, api_hash)
BOT_USER_NAME="#filesending_sample_bot" # the username of the bot that sends files (images, docs, ...)
#client.on(events.NewMessage(func=lambda e: e.is_private))
async def message_handler(event):
if event.message.media is not None: # if there's something to download (media)
await client.download_media(message=event.message, )
async def main():
await client.send_message(BOT_USER_NAME, 'some text or command to trigger file sending') # trigger the bot here by sending something so that the bot sends the media
client.start()
client.loop.run_until_complete(main())
client.run_until_disconnected()
and in my example I created a minimal telegram bot in javascript that sends a photo (as Document) as it receives any message to test the above script out (but you configure the above script to match with your case):
const bot = new (require("telegraf"))(<MY_BOT_TOKEN>);
bot.on("message", (ctx) => ctx.replyWithDocument("https://picsum.photos/200/300"));
bot.launch();
Note that you must connect using a regular telegram account (not using a bot token but rather a phone number) for this to work. If using a telegram bot is a must, you can use the script in the background (by running it as a new process or as a REST api, etc...) and return a result to the telegram bot.
I am currently working on a desktop application and I want to get messages sent from Discord to this application. How should I do this?
I have used POST requests and webhooks to send messages TO Discord, but I have never taken messages from a channel and sent them somewhere else.
I know I can do something using on_message like this:
#bot.event
async def on_message(message):
message_content = message.content
## send message_content to external application
I just am confused on what to use/how to send the messages to the application itself. Keep in mind that this I'm making in Python 3.6.6
I am building a Discord bot in Python and would like to receive HTTP requests from Twitch.tv's API (See Webhooks Guide & Webhooks Reference) (To subscribe to events like; X streamer has gone live) and based on the content of the HTTP (POST or GET) request received from Twitch, do something on the Discord bot, e.g: Output a message on a text channel.
I am using the discord.py Python Discord API/Library.
I've looked into the matter and found that Flask seemed like a good minimalist choice for a webserver to receive these requests on.
I should preface this by saying I'm very new to Python and I've never used Flask before.
Now. The problem is I can't seem to figure out a way to run the Flask server inside of my discord bot.
I've tried adding this simple code into my discord.py script:
from flask import Flask, request
app = Flask(__name__)
#app.route('/posts', methods=['POST'])
def result():
print(request.form['sched'])
# Send a message to a discord text channel etc...
return 'Received !'
When I run my discord.py script which looks something like this:
(Stripped away some commands and features for the sake of keeping this shorter)
import discord
import asyncio
from flask import Flask, request
app = Flask(__name__)
#app.route('/posts', methods=['POST'])
def result():
print(request.form['sched'])
# Send a message to a discord text channel etc...
return 'Received !'
client = discord.Client()
#client.event
async def on_ready():
print('Logged in as')
print(client.user.name)
print(client.user.id)
print('------')
#client.event
async def on_message(message):
if message.author == client.user:
return
content = message.content
fullUser = message.author.name+'#'+message.author.discriminator
print(str(message.timestamp)+" #"+message.channel.name+" "+fullUser+": "+str(content.encode('ascii', 'ignore').decode('ascii')))
if content.startswith('!'):
content = content[1:]
if content.startswith('test'):
counter = 0
tmp = await client.send_message(message.channel, 'Calculating messages...')
async for log in client.logs_from(message.channel, limit=100):
if log.author == message.author:
counter += 1
await client.edit_message(tmp, 'You have {} messages.'.format(counter))
client.run('MyTokenHere')
It seems like if I point flask to discord.py (the above) and run it, it'll start the code, get to the "client.run('MyTokenHere')" part for discord, and just stop at that and run the discord bot. It's not until I exit out of the bot by doing Ctrl+C that the actual Flask server starts, but now the discord bot is disconnected and no longer does any processing.
The same problem persists if I were to for example add "app.run()" somewhere in my code (before calling "client.run()" which starts the Discord bot part) to launch the Flask server; It'll just run the flask, get stuck on that until I Ctrl+C out of the Flask server, then it'll proceed to start the Discord bot.
Ultimately, I need to use the Discord API and I need to be connected to the Discord API gateway and all that good jazz to actually send messages to a channel with the bot, so I don't really know what to do here.
So. I think I've tried my best to explain what I'm ultimately trying to achieve here, and hopefully someone can help me find a way to either make this work with Flask, or if there's a better and easier way, provide a different solution.
This is cog example in discord.py
I made this thing for dbl (Discord Bot Lists) you can implement, the thing you need.
Note: run your heroku app with webprocess
example :
web: python main.py
Then go on https://uptimerobot.com/
and setup to ping your web app after every 5 minutes
from aiohttp import web
from discord.ext import commands, tasks
import discord
import os
import aiohttp
app = web.Application()
routes = web.RouteTableDef()
def setup(bot):
bot.add_cog(Webserver(bot))
class Webserver(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.web_server.start()
#routes.get('/')
async def welcome(request):
return web.Response(text="Hello, world")
#routes.post('/dbl')
async def dblwebhook(request):
if request.headers.get('authorization') == '3mErTJMYFt':
data = await request.json()
user = self.bot.get_user(data['user']) or await self.bot.fetch_user(data['user'])
if user is None:
return
_type = f'Tested!' if data['type'] == 'test' else f'Voted!'
upvoted_bot = f'<#{data["bot"]}>'
embed = discord.Embed(title=_type, colour=discord.Color.blurple())
embed.description = f'**Upvoter :** {user.mention} Just {_type}' + f'\n**Upvoted Bot :** {upvoted_bot}'
embed.set_thumbnail(url=user.avatar_url)
channel = self.bot.get_channel(5645646545142312312)
await channel.send(embed=embed)
return 200
self.webserver_port = os.environ.get('PORT', 5000)
app.add_routes(routes)
#tasks.loop()
async def web_server(self):
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, host='0.0.0.0', port=self.webserver_port)
await site.start()
#web_server.before_loop
async def web_server_before_loop(self):
await self.bot.wait_until_ready()
As the kind commenters informed me; threading seems like the way to go.
Thanks guys!
Another cool way if you aren't going to use flask extensions, use quart instead of flask, then it will super easy for you.
Note: Run your heroku app with webprocess
example :
web: python main.py
Then go on https://uptimerobot.com/ and setup to ping your web app after every 5 minutes
# Code Example
from discord.ext import commands
from quart import Quart
import os
app = Quart(__name__)
bot = commands.Bot('!')
#bot.command()
async def something(ctx):
...
"""
Note: On Heroku you cant bind your webserver with 5000 port as they aren't static.
To fix above problem you will have to get dynamic port from the environment variable and you are good to go.
"""
PORT = os.environ.get('PORT')
bot.loop.create_task(app.run_task('0.0.0.0', PORT))
bot.run('Token')
Or you can use the Terminal Multiplexer, tmux to run them independently!.
If you are running on a Linux platform, tmux python3 flaskapp.py would run the flask app, while you can independently run the discord bot.
You can use asyncio with flask to perform this
import discord
import asyncio
class PrintDiscordChannelsClient(discord.Client):
def __init__(self, *args, **kwargs):
self.guild_id = kwargs.pop('guild_id')
super().__init__(*args, **kwargs)
async def on_ready(self):
try:
await self.wait_until_ready()
guild = self.get_guild(int(self.guild_id))
print(f'{guild.name} is ready!')
channels = guild.text_channels
print(f'{(channels)} channels found')
await self.close()
except Exception as e:
print(e)
await self.close()
async def print_discord_channels(guild_id):
client = PrintDiscordChannelsClient(guild_id=guild_id)
await client.start('DISCORD_BOT_TOKEN')
#application.route("/discord-api", methods=["GET"])
def discord_api():
guild_id = request.args.get('guild_id')
asyncio.run(print_discord_channels(guild_id=guild_id))
return make_response("Success", 200)