How to call any other event in the Slack API besides [message]? - python-3.x

I'm playing around with trying to make a bot in the slack channel so that I can understand how the whole process works. I have 2 questions. [1st question solved]First, I know how to send a message if someone said anything but I can't figure out how to check what was specifically said. Here's my code:
import os
import time
from slackclient import SlackClient
BOT_TOKEN = os.getenv('SLACK_BOT_USER_TOKEN')
print(BOT_TOKEN)
CH_NM = "bot_testing"
def main():
sc = SlackClient(BOT_TOKEN)
SM = sc.rtm_send_message
if sc.rtm_connect():
print("Bot running")
SM(CH_NM, "Started")
while True:
for slack_message in sc.rtm_read():
message = slack_message.get("text")
user = slack_message.get("user")
if 'hello' in message:
SM(CH_NM, "Hey, <#{}>!".format(user))
if not message or not user:
continue
SM(CH_NM, """<#{}> wrote something...""".format(user))
time.sleep(.5)
if __name__ == '__main__':
main()
The main line I'm having trouble with is
if 'hello' in message:
SM(CH_NM, "Hey, <#{}>!".format(user))
because I can't iterate through 'message' since it is 'NoneType'. How then would I go about checking if it contained a specific string?
Second question, I see that there are all sorts of event types, but mine only seems to work for the "message" type of events. If I wanted to return something every time a specific user started typing for example what would I add to make that work? I already tried adding typing = slack_message.get("user_typing") but understandably it doesn't work since 'user_typing' is an event type, not part of the message event type I'm pulling 'text' and 'user' out of.
So you know, I'm using python 3.6, Windows 10, powershell.

The issue was that I had my if not message or not user: continue line below the if 'hello' in message: line, so it would error out due to any other event that is happening that isn't a message. 1st Issue solved.

Related

Get Discord username and discriminator through a mention

I have tried reading the docs, but I don't understand what is going on here and how to fix it. I am trying to map a mention to its proper Name#NNNN form, but alas, it is proving to be a fruitless endeavor for me.
import discord
from discord.ext import commands
from collections import defaultdict
client = commands.Bot(command_prefix=">")
#client.event
async def on_ready():
print('Ready!')
jobz = {}
'''PART 1 v v v'''
#client.event
if message.content.startswith('>jobsched'):
author = message.author
jobz[author].append(...)
await channel.send(jobz[author])
'''PART 2 v v v'''
if message.content.startswith('>when '):
channel = message.channel
worker = list(filter(None, message.content[6:].split(' ')))[0]
uname = message.mentions[0].mention
await channel.send(jobz[uname])
PART 1:
I run this first, the send works as expected as seen below:
>jobsched 'a'
>jobsched 'b'
As seen in the last line, this spits out ['1a', '2b']
PART 2:
Here is where I have my issue.
>when #Name
I expected this to spit out ['1a', '2b'] because I expected it to look up or translate the mentioned name, find its respective name and discriminator. I thought this should happen since, in the above piece, that is how the name gets written into the dictionary is i.e. Name#1234: ['1a','2b']
Printing out .keys() shows that the key has the name and discriminator i.e. Name#1234 in the 'jobz' dictionary.
However, I can't seem to get the mention to give me the Name and Discriminator. I have tried doing mentions[0].mention from what I have seen here on stackoverflow, but it doesn't result in a Member class for me, just a string, presumably just '#Name'. If I leave it alone, as shown in my 'worker' variable, it passes an empty list. It should pull the list because when I override it to jobz['Name#1234'] it gives me the list I expect.
Can anyone please help?
just cast the member object to string to get the name and discriminator as it says in the discord.py docs. To mention someone, put the internal representation like this: f'<#{member.id}>'. To stop problems like this, use client.command() it's way easier to put in parameters, and easier to access info. So, here would be the code:
#client.command()
async def when(ctx, member: discord.Member):
await ctx.send(jobz[str(member)])
Also, if your worker variable is returning None, you're not passing a parameter at all
mentions is a list of Member objects, so when you do mentions[0] you are referencing a Member. Thus, mentions[0].mention is the formatted mention string for the first-mentioned (element 0) Member.
You probably want mentions[0].name and mentions[0].discriminator
See: https://discordpy.readthedocs.io/en/latest/api.html#discord.Message.mentions

Python Facebookchat AttributeError 'str' object has no attribute '_to_send_data'

I was trying send message to my friend using python.
But I am getting this error.
sent = client.send(friend.uid, msg)
File "/home/can/anaconda3/lib/python3.7/site-packages/fbchat/_client.py", line 1059, in send
data.update(message._to_send_data())
AttributeError: 'str' object has no attribute '_to_send_data'
I can login in to my account and ı can enter value of friends also ı can enter my friend name.
Then when ı write my message for example "hello" then press enter, it gives me error.
Codes of program;
import fbchat
from getpass import getpass
username = str(input("Username: "))
client = fbchat.Client(username, getpass())
no_of_friends = int(input("Number of friends: "))
for i in range(no_of_friends):
name = str(input("Name: "))
friends = client.searchForUsers(name) # return a list of names
friend = friends[0]
msg = str(input("Message: "))
sent = client.send(friend.uid, msg)
if sent:
print("Message sent successfully!")
can I see "Message sent successfully!" this message? also modules are successfully installed.
I am working on Ubuntu 19.10
I fix my issue by myself. ı put the answer here maybe someone will have same error and can find the answer here.
My mistake is here;
sent = client.send(friend.uid, msg)
I changed like this one;
sent = client.sendMessage(msg, thread_id=friend.uid)
and it's worked!

Python while True preventing previous code execution

I'm building a telegram bot using telepot(python) and a weird thing happened:
since the bot is supposed to keep running, I've set a
while 1:
time.sleep(.3)
at the end of my bot, right after I define how to handle the MessageLoop.
The bot has some print() to assert that the bot is setting up (or better, that it's setting up the message handler) and that it is reading the chat, waiting for any input.
The problem is that if I run the code without the
while 1:
time.sleep(.3)
it prints the messages and stops the execution (not having a loop to wait for new input), but if I add the while 1: (...) the code stops before being able to print anything.
Here's the code:
"""Launch the bot."""
import json
import telepot
from telepot.loop import MessageLoop
import time
from base import splitter
from base import handler
messageHandler = handler.Handler()
with open('triggers.json') as f:
triggers = json.load(f)
with open('config.json') as f:
config = json.load(f)
botKey = config['BOT_KEY']
# define the bot and the botname
bot = telepot.Bot(botKey)
botName = bot.getMe()['username']
# split commands in arrays ordered by priority
configSplitter = splitter.Splitter()
triggers = configSplitter.splitByPriority(triggers)
# define the handler
messageHandler.setBotname(botName)
messageHandler.setMessages(triggers)
# handle the messageLoop
print("setting up the bot...")
MessageLoop(bot, messageHandler.handle).run_as_thread()
print("Multibot is listening!")
# loop to catch all the messages
while 1:
time.sleep(.3)
Python version: 3.6 32-bit
The solution was to add sys.stdout.flush() after the various print()to restore the functionality of print(), while in order to make the code work again i had to change the telepot function
MessageLoop(bot, messageHandler.handle).run_as_thread()
which wasn't working properly to:
bot.message_loop(messageHandler.handle)

Discord.py mass dm bot

I've been trying to find out a way to make a discord bot dm everybody inside of my server. I have already found a question similar to mine and tried the answer but it didn't work. My current code looks like this
if message.content.upper().startswith('.MSG'):
if "345897570268086277" in [role.id for role in message.author.roles]:
member = discord.Member
args = message.content.split(" ")
if member == "#everyone":
for server_member in server.members:
await client.send_message(server_member, "%s" % (" ".join(args[1:])))
I would use the commands extension for this, not on_message
# import stuff we'll be using
from discord.ext import commands
from discord.utils import get
# Bot objects listen for commands on the channels they can "see" and react to them by
# calling the function with the same name
bot = commands.Bot(command_prefix='.')
# Here we register the below function with the bot Bot
# We also specify that we want to pass information about the message containing the command
# This is how we identify the author
#bot.command(pass_context=True)
# The command is named MSG
# The `, *, payload` means take everything after the command and put it in one big string
async def MSG(ctx, *, payload):
# get will return the role if the author has it. Otherwise, it will return None
if get(ctx.message.author.roles, id="345897570268086277"):
for member in ctx.message.server.members:
await bot.send_message(member, payload)
bot.run('token')
How sure are you that "345897570268086277" is the role id? It might make more sense to search for it by name.

Why can I not send a message via Discord.py from a function?

I have created a script which takes in a message formatted as !notice [MM/DD/YY HH:mm], message, target which then calls a function using threading.Timer to call it at the time given in the message in UTC.
Where I am having trouble is sending a message from this function, I can't seem to get a message to send from the function regardless of the input of the message.
See below:
import discord
import asyncio
from datetime import *
import threading
client = discord.Client()
#client.event
async def on_message(message):
if message.content[:7].lower() == "!notice".lower():
try:
notice = [datetime.strptime(message.content[message.content.find("[")+1:message.content.find("]")], "%m/%d/%y %H:%M"), message.content.split(", ")[1], message.content.split(", ")[2]]
await client.send_message(message.channel, 'Created notice "'+notice[1]+'" to be sent to '+notice[2]+' at '+str(notice[0])+' UTC.')
threading.Timer((notice[0] - datetime.utcnow()).total_seconds(), lambda a=notice[1], b=notice[2]: func(a, b)).start()
print(str((notice[0] - datetime.utcnow()).total_seconds())+" seconds until message is sent")
except (ValueError, IndexError):
await client.send_message(message.channel, 'Incorrect Notice Format.\nMust be "!notice [MM/DD/YY HH:mm], Notice contents, Target".\nEG: "!notice [01/01/2017 12:00], This is a notice, Siren Raid Team".')
def func(message, target):
print("Func called")
for i in client.servers:
for c in i.channels:
client.send_message(c, target+message)
client.run(MY_SESSION_KEY)
This returns "Func called" so I know the function is being called, but no exceptions are raised and no message is posted in my chat.
I also tried substituting func with:
async def func(message, target):
print("Func called")
for i in client.servers:
for c in i.channels:
await client.send_message(c, target+message)
However this throws up an exception:
RuntimeWarning: coroutine 'func' was never awaited
Frankly, I'm out of my depth here. Is there any reason why this won't work?
I saw online that asyncio is not thread-safe. But, unless I'm misunderstanding, my first example didn't use that library in the function. Could is still be causing problems?
discord.py's discord.Client.send_message is a coroutine and must be awaited, like you did in your second code snippet. However, threading.Timer does not support coroutines.
What you're looking for is create_task, which enables you to run a coroutine on the event loop. Since most of what your coroutine does is sleeping (mimicking threading.Timer), your on_message will proceed to run, given that you use asyncio.sleep and not time.sleep - the latter blocks the event loop. Here's an example, including passing arguments to functions:
import asyncio
loop = asyncio.get_event_loop()
async def sleep_and_add(a, b):
await asyncio.sleep(3)
print(a, '+', b, 'is', a + b)
async def on_message():
# prepare arguments to your function
loop.create_task(sleep_and_add(2, 3))
# continue doing other things
In case anyone needs help with just sending messages to a server from inside of a flask function. I spent hours with this problem myself after going down the rabbit hole of asyncio and threading. Turned out to be way easier than I thought. Webhooks, unlike a regular Discord bot, are entirely synchronous, which means they can run in a flask function no problem.
If your goal is to just simply send a message to a channel from a flask endpoint and not use any other functionality, try webhooks.
from discord import Webhook, RequestsWebhookAdapter
webhook = Webhook.partial(WEB_HOOK_ID, 'WEB_HOOK_TOKEN', adapter=RequestsWebhookAdapter())
and then post the message
webhook.send('MESSAGE', username='WEBHOOK_BOT')
Creating Webhook tutorial
Discord.py Webhook Info

Resources