Discord Poll Bot - python-3.x

Hi i am trying to make a poll bot but ive encountered a problem here is the code ignore the other commands other than + poll
import discord
import os
import requests
import json
import random
pollid = 0
emoji1 = '\N{THUMBS UP SIGN}'
emoji2 = '\N{THUMBS DOWN SIGN}'
client = discord.Client()
sad_words=["sad","depressed", "unhappy","angry","miserable","depressing"]
starter_encouragements = ["Cheer up", "hang in there.", "You are a great person / bot!"]
def get_quote():
response = requests.get("https://zenquotes.io/api/random")
json_data = json.loads(response.text)
quote = json_data[0]['q'] + " -" + json_data[0]['a']
return[quote]
from discord.utils import get
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#client.event
async def on_message(message):
global pollid
#if message.author == client.user:
# return
msg = message.content
if message.content.startswith('+encourage'):
quote=get_quote()
await message.channel.send(quote)
if any(word in msg for word in sad_words):
await message.channel.send(random.choice(starter_encouragements))
if message.content.startswith("+joke"):
from dadjokes import Dadjoke
dadjoke = Dadjoke()
await message.channel.send(dadjoke.joke)
if message.content.startswith("+poll"):
pollid = pollid+1
await message.channel.send(content = msg.split(' ', 1)[1] + ' (number of polls made ' + str(pollid) + ')')
if message.author == client.user:
await message.add_reaction(emoji1)
await message.add_reaction(emoji2)
reaction = get(message.reactions, emoji=emoji1)
#reaction2 = get(message.reactions, emoji=emoji2)
#if (reaction != None and reaction2 != None):
# totalcount = reaction.count + reaction2.count
#if totalcount>=2:
if (reaction != None and reaction.count != 1):
await message.channel.send('The outcome of the poll is yes'+ str(reaction.count))
# await message.channel.send('The outcome of the poll is no')
client.run(os.getenv('TOKEN'))
i am very new to python and the discord api for it ive been trying to set up a poll system where it has a timer on each poll that lasts 24 hrs and after 24 hrs it compares the amount of reactions on the message to see which side wins. Can someone help me with this. Thanks

I would not use on_message events for that but instead use a command.
You can do something like this:
import discord
from discord.ext import commands
#client.command()
async def poll(ctx, *, text: str):
poll = await ctx.send(f"{text}")
await poll.add_reaction("✅")
await poll.add_reaction("❌")
Here we have text as a str so you can add as many text as you want.
If you want to compare it after 24 hours you would also have to build in a cooldown saver if the bot restarts, otherwise we could go with await asyncio.sleep(TimeAmount)
If you want to check the result with a command we could go for this:
from discord.utils import get
import discord
from discord.ext import commands
#client.command()
async def results(ctx, channel: discord.TextChannel, msgID: int):
msg = await channel.fetch_message(msgID)
reaction = get(msg.reactions, emoji='✅')
count1 = reaction.count # Count the one reaction
reaction2 = get(msg.reactions, emoji="❌")
count2 = reaction2.count # Count the second reaction
await ctx.send(f"✅**: {count1 - 1}** and ❌**: {count2 - 1}**") # -1 is used to exclude the bot
The usage of the command would be: results #channel MSGID.
Be aware that fetch is an API call and could cause a ratelimit.

Related

How to make discord bot timed mute automatic for 5 mins?

import discord
from discord.ext import commands
class AntiCog(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_message(self, message):
if message.author.id == 1234567891234567:
mention = f'<#!1234567891234567>'
if message.content == mention:
await message.channel.send("grow up")
user = message.author
print(str(user))
print(str(message.content))
muted_role = discord.utils.get(message.guild.roles, name="Muted")
await user.add_roles(muted_role)
else:
return
await self.client.process_commands(message)
def setup(client):
client.add_cog(AntiCog(client))
This's a working code for muting a person if they ping another person, however, I would like to make it a timed mute for 5 min. All of the resources I found were on_command timed mute, however, this's an auto one, how can I do so. thank you!
All you would have to do is add asyncio.sleep, and then remove the role, so:
import discord
from discord.ext import commands
import asyncio
class AntiCog(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_message(self, message):
if message.author.id == 1234567891234567:
mention = f'<#!1234567891234567>'
if message.content == mention:
await message.channel.send("grow up")
user = message.author
print(str(user))
print(str(message.content))
muted_role = discord.utils.get(message.guild.roles, name="Muted")
await user.add_roles(muted_role)
await asyncio.sleep(300) # you can change the time here
await user.remove_roles(muted_role)
else:
return
await self.client.process_commands(message)
def setup(client):
client.add_cog(AntiCog(client))
Be sure to import asyncio!

Bot discord with python

How can I make it so that when someone who is not an administrator and runs the 'cls' command gives him a message like for example you are not an administrator, sorry
Python code
#bot.command()
#commands.has_permissions(manage_messages=True)
async def cls(ctx, Quantity= 10000):
if manage_messages == False:
await ctx.send('You are not an administrator, you cannot run this command.')
await ctx.channel.purge(limit = Quantity)
Help I don't know how to do it.
import discord
import asyncio
from discord.ext.commands import Bot
client = Bot(description="My Cool Bot", command_prefix="!", pm_help = False, )
#client.event
async def on_ready():
print("Bot is ready!")
return await client.change_presence(game=discord.Game(name='My bot'))
#client.command(pass_context = True)
async def whoami(ctx):
if ctx.message.author.server_permissions.administrator:
msg = "You're an admin {0.author.mention}".format(ctx.message)
await client.send_message(ctx.message.channel, msg)
else:
msg = "You're an average joe {0.author.mention}".format(ctx.message)
await client.send_message(ctx.message.channel, msg)
client.run('Your_Bot_Token')
This is how I would do it to check if the author of the message has admin permissions in your case.
if ctx.message.author.guild_permissions.administrator:
await ctx.channel.purge(limit=Quantity)
await ctx.send('Deletion success! Deleted ' + Quantity + ' messages.')
else:
await ctx.send('You are not an administrator, you cannot run this command.')

Python Discord Bot - Keep real time message parser from blocking async

I am writing a Discord Bot to take messages from a live chat and relay them to Discord channel, but want it to have other responsive features. Currently the script relays messages by entering a while loop which runs until the right message is recieved.
def chat_parser():
resp = sock.recv(4096).decode('utf-8')
#print(' - ', end='')
filtered_response = filter_fighter_announce(resp)
if resp.startswith('PING'):
# sock.send("PONG :tmi.twitch.tv\n".encode('utf-8'))
print("Ponging iirc server")
sock.send("PONG\n".encode('utf-8'))
return ''
elif (len(filtered_response) > 0):
if (filtered_response.count('ets are OPEN for') > 0):
filtered_response = get_fighters(filtered_response)
return filtered_response
return ''
fight = fight_tracker('') #initialize first fight object
def message_loop():
global first_loop_global
while True:
chat_reception = chat_parser()
if (chat_reception == ''):
continue
fight.set_variables(chat_reception)
return fight.announcement
return ''
The issue with this is that responsive functions for Discord are stuck waiting for this loop to finish. Here is the other code for reference.
#client.event
async def on_ready():
print('Finding channel...')
for guild in client.guilds:
if guild.name == GUILD:
break
channel = guild.get_channel(salty_bet_chat_id)
print('Connected to Channel.')
try:
print('Beginning main loop.')
while True:
message_out = await message_loop()
if (message_out != None and message_out != None):
print('Sending to Discord: ', message_out)
msg = await channel.send(message_out)
await msg.add_reaction(fight.fighter_1[1])
await msg.add_reaction(fight.fighter_2[1])
print('message sent...')
except KeyboardInterrupt:
print('KeyboardInterrupt')
sock.close()
exit()
#client.event
async def on_raw_reaction_add(reaction):
print(reaction)
#client.event
async def on_message(message):
print(message.author)
print(client.user)
client.run(TOKEN)
I have tried making async functions out of chat_parser() and message_loo() and awaiting their return where they are called, but the code is still blocking for the loop. I am new to both async and coding with Discord's library, so I am not sure how to make an async loop function when the only way to start the Discord client is by client.run(TOKEN), which I could not figure out how to incorporate into another event loop.

How to loop a task in discord.py

I am experimenting with making my own little discord bot that can get information from Twitch, but I'm stumped on how to make the bot loop and check for a condition.
I want the bot to loop a section of code every few seconds that checks if the specified twitch channel is live.
Code
import discord
from discord.ext import commands, tasks
from twitch import TwitchClient
from pprint import pformat
client = TwitchClient(client_id='<twitch token>')
bot = commands.Bot(command_prefix='$')
#bot.event
async def on_ready():
print('We have logged in as {0.user}'.format(bot))
#bot.command()
async def info(ctx, username):
response = await ctx.send("Querying twitch database...")
try:
users = client.users.translate_usernames_to_ids(username)
for user in users:
print(user.id)
userid = user.id
twitchinfo = client.users.get_by_id(userid)
status = client.streams.get_stream_by_user(userid)
if status == None:
print("Not live")
livestat = twitchinfo.display_name + "is not live"
else:
livestat = twitchinfo.display_name + " is " + status.stream_type
responsemsg = pformat(twitchinfo) + "\n" + livestat
await response.edit(content=responsemsg)
except:
await response.edit(content="Invalid username")
bot.run("<discord token>")
I want the bot to run the following code every 10 seconds, for example:
status = client.streams.get_stream_by_user(<channel id>)
if status == None:
print("Not live")
livestat = twitchinfo.display_name + "is not live"
else:
livestat = twitchinfo.display_name + " is " + status.stream_type
I've tried using #tasks.loop(seconds=10) to try and make a custom async def repeat every 10 seconds but it didn't seem to work.
Any ideas?
The newer version of discord.py doesn't support client.command()
To achieve the same I used the following snippet
import discord
from discord.ext import tasks
client = discord.Client()
#tasks.loop(seconds = 10) # repeat after every 10 seconds
async def myLoop():
# work
myLoop.start()
client.run('<your token>')
This can be done like so:
async def my_task(ctx, username):
while True:
# do something
await asyncio.sleep(10)
#client.command()
async def info(ctx, username):
client.loop.create_task(my_task(ctx, username))
References:
asyncio.create_task()
asyncio.sleep()
This is the most proper way to implement background tasks.
from discord.ext import commands, tasks
bot = commands.Bot(...)
#bot.listen()
async def on_ready():
task_loop.start() # important to start the loop
#tasks.loop(seconds=10)
async def task_loop():
... # this code will be executed every 10 seconds after the bot is ready
Check this for more info
I struggled with this as well. The problem I ran into is that none of the examples online were complete. Here is one I came up with that uses #tasks.loop(seconds=10).
import discord
import os
from discord.ext import tasks
from dotenv import load_dotenv
intents = discord.Intents.all()
client = discord.Client(command_prefix="!", intents=intents)
load_dotenv()
token = os.getenv("DISCORD_TOKEN")
CHANNEL_ID = 1234
#client.event
async def on_ready():
print(f"We have logged in as {client.user}")
myloop.start()
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith("hi"):
await message.channel.send("Hello!")
#tasks.loop(seconds=10)
async def myloop():
channel = client.get_channel(CHANNEL_ID)
await channel.send("Message")
client.run(token)

Why has is_closed stopped working in the rewrite version?

I am new to the Discord python API. I am trying to run a method forever as long as the client is still open. I scheduled the method through Client.loop.create_task(), and am running while not client.is_closed. I added a debugging print statement, but the print statement is called 0 times.
I based the code on this post: Discord.py Schedule
import discord
from datetime import datetime
from datetime import timedelta
token = "TOKEN"
s_users = {}
timezon_offset = 5
inac_days = 0
inac_hours = 0
inac_minutes = 1
active_role = "Active"
inac_role = "Inactive"
client = discord.Client()
async def monitor():
for guild in client.guilds:
for user in guild.members:
s_users[user] = datetime(1,1,1)
#client.event
async def on_ready():
print('logged on as {0}'.format(client.user))
#client.event
async def on_message(message):
print('message logged from {0.author}: {0.content} at {0.created_at}'.format(message))
s_users[message.author] = message.created_at - timedelta(hours=timezon_offset)
async def task():
await client.wait_until_ready()
active = None
inactive = None
for guild in client.guilds:
for role in guild.roles:
if (role.name == active_role):
active = role
elif (role.name == inac_role):
inactive = role
while not client.is_closed:
print("here")
for user in s_users:
if datetime.now() - s_users[user] > timedelta(days=inac_days, hours=inac_hours, minutes=inac_minutes):
if not(inac_role in [role.name for role in user.roles]):
await user.remove_roles(active)
await user.add_roles(inactive)
print("gave user: " + user.name + " " + inac_role + " role")
if datetime.now() - s_users[user] <= timedelta(days=inac_days, hours=inac_hours, minutes=inac_minutes):
if not(active_role in [role.name for role in user.roles]):
await user.remove_roles(inactive)
await user.add_roles(active)
print("gave user: " + user.name + " " + active_role + " role")
client.loop.create_task(task())
client.run(token)
It should execute task(), which should run as long as the client is not closed. However, the print statement is executed 0 times.
In version 1.0.0, Client.is_closed was changed from a property to a method. See Property Changes in the Migration guide.
You'll need to add parentheses to call the method:
while not client.is_closed():
...

Resources