Skip to content

Instantly share code, notes, and snippets.

@miou-gh
Created May 1, 2017 22:58
Show Gist options
  • Save miou-gh/cc531b6ba6772a9eaec696652d336b26 to your computer and use it in GitHub Desktop.
Save miou-gh/cc531b6ba6772a9eaec696652d336b26 to your computer and use it in GitHub Desktop.
import os
import re
import time
import json
import hashlib
import calendar
import requests
import threading
import html2text
from datetime import datetime, date
from slackclient import SlackClient
from BeautifulSoup import BeautifulSoup as Soup
from BeautifulSoup import NavigableString
SLACK_BOT_TOKEN = 'CHANGE_THIS'
BOT_ID = 'CHANGE_THIS'
# constants
AT_BOT = "<@" + BOT_ID + ">"
COMMANDS = [ 'silence', 'listen', 'ping' ]
SILENCED = False
# instantiate Slack & Twilio clients
slack_client = SlackClient(SLACK_BOT_TOKEN)
def handle_command(command, channel):
response = "No such command found. For a list of commands, use 'commands'."
if command.startswith('commands') or command.startswith('help'):
response = "Available commands: " + ', '.join(COMMANDS)
elif command.startswith('silence'):
SILENCED = True
response = "Silence mode is now enabled."
elif command.startswith('listen'):
SILENCED = False
response = "Silence mode is now disabled."
elif command.startswith('ping'):
response = "Pong."
slack_client.api_call("chat.postMessage", channel=channel,
text=response, as_user=True)
def parse_slack_output(slack_rtm_output):
output_list = slack_rtm_output
if output_list and len(output_list) > 0:
for output in output_list:
if output and 'text' in output and AT_BOT in output['text']:
# return text after the @ mention, whitespace removed
return output['text'].split(AT_BOT)[1].strip().lower(), \
output['channel']
return None, None
def strip_html(html):
soup = Soup(html)
[div.extract() for div in soup.findAll('div')]
[span.extract() for span in soup.findAll('span')]
[br.extract() for br in soup.findAll('br')]
result = ''
try:
result = html2text.html2text(str(soup))
except:
result = str(soup)
re.sub(r'(\r\n){2,}','\r\n', result)
return result
def parse_forums():
READ_FORUM_FEED_DELAY = 10
PREVIOUS_POSTS = []
FULLY_PARSED = False
while True:
req = requests.request('GET', 'http://forums.everybodyedits.com/extern.php?action=feed&type=xml')
soup = Soup(req.content)
posts = []
for message in soup.findAll('topic'):
post_id = message.attrs[0][1]
title = message.find('title').text
author_name = message.find('author').find('name').text
author_profile = message.find('author').find('uri').text
timestamp = datetime.strptime(message.find('posted').text, "%a, %d %b %Y %H:%M:%S +0000")
content = strip_html(message.find('content').text)
digest = hashlib.sha1(str.format('{}{}{}', post_id, author_profile, timestamp)).hexdigest()
post = { 'post_id': post_id, 'title': title, 'author_name': author_name, 'author_profile': author_profile,
'timestamp': timestamp, 'content': content, 'digest': digest }
posts.append(post)
if FULLY_PARSED:
found_posts = []
for first in posts:
found = False
for second in PREVIOUS_POSTS:
if first['digest'] == second['digest']:
found = True
break
if not found:
found_posts.append(first)
for post in found_posts:
print(post)
channel_list = slack_client.api_call(
"channels.list",
exclude_archived=1
)
attachment = {
"fallback": str.format('[EEForums] {} replied to {}...', post['title'],
str.format("http://forums.everybodyedits.com/viewtopic.php?id={}&action=new", post['post_id'])),
"color": "#36a64f",
"author_name": post['author_name'],
"author_link": post['author_profile'],
"author_icon": str.format("http://forums.everybodyedits.com/img/avatars/{}.png", post['author_profile'].split("?id=",1)[1]),
"title": post['title'],
"title_link": str.format("http://forums.everybodyedits.com/viewtopic.php?id={}&action=new", post['post_id']),
"text": post['content'][:150] + (post['content'][150:] and '..'),
"footer": "Everybody Edits Forums",
"footer_icon": "https://forums.everybodyedits.com/favicon.png",
"ts": int(calendar.timegm(post['timestamp'].timetuple()))
}
for channel in channel_list['channels']:
if channel['is_member'] and not SILENCED:
slack_client.api_call("chat.postMessage", channel=channel['id'], attachments=json.dumps( [attachment] ), as_user=True)
PREVIOUS_POSTS = posts
else:
PREVIOUS_POSTS = posts
FULLY_PARSED = True
time.sleep(READ_FORUM_FEED_DELAY)
if __name__ == "__main__":
READ_WEBSOCKET_DELAY = 1
forum_parse_thread = threading.Thread(target=parse_forums, args=())
forum_parse_thread.daemon = True
forum_parse_thread.start()
if slack_client.rtm_connect():
print("BeefBot connected and running!")
while True:
command, channel = parse_slack_output(slack_client.rtm_read())
if command and channel:
handle_command(command, channel)
time.sleep(READ_WEBSOCKET_DELAY)
else:
print("Connection failed. Invalid Slack token or bot ID?")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment