diff options
-rw-r--r-- | README.md | 17 | ||||
-rw-r--r-- | wee_slack.py | 70 |
2 files changed, 64 insertions, 23 deletions
@@ -3,11 +3,6 @@ wee-slack ========= -**Important:** - Just updated with some **huge** performance improvements! Seriously, **upgrade now**. Weechat 1.1 or newer is now required. There was code to work around issues that no longer exist in newer versions. You should upgrade to if you wish to use continue using wee-slack. - ------------ - A WeeChat native client for Slack.com. Provides supplemental features only available in the web/mobile clients such as: synchronizing read markers, typing notification, search, (and more)! Connects via the Slack API, and maintains a persistent websocket for notification of events. ![animated screenshot](https://dl.dropboxusercontent.com/u/566560/slack.gif) @@ -46,6 +41,7 @@ Dependencies ------------ * WeeChat 1.1+ http://weechat.org/ * websocket-client https://pypi.python.org/pypi/websocket-client/ + * curl http://curl.haxx.se/ Setup ------ @@ -63,11 +59,20 @@ wee-slack doesn't use the Slack IRC gateway. If you currently connect via the ga /python reload ``` -####1. Install websocket-client lib +####1. Install dependencies + +##### OSX +``` +pip install websocket-client +``` + +##### Linux (ubuntu) ``` +sudo apt-get install curl pip install websocket-client ``` + ####2. copy wee_slack.py to ~/.weechat/python/autoload ``` wget https://raw.githubusercontent.com/rawdigits/wee-slack/master/wee_slack.py diff --git a/wee_slack.py b/wee_slack.py index b444aa3..467a29c 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # + from functools import wraps import time import json @@ -9,6 +10,7 @@ import re import urllib import urlparse import HTMLParser +import sys from websocket import create_connection # hack to make tests possible.. better way? @@ -19,7 +21,7 @@ except: SCRIPT_NAME = "slack_extension" SCRIPT_AUTHOR = "Ryan Huber <rhuber@gmail.com>" -SCRIPT_VERSION = "0.97.21" +SCRIPT_VERSION = "0.97.25" SCRIPT_LICENSE = "MIT" SCRIPT_DESC = "Extends weechat for typing notification/search/etc on slack.com" @@ -211,14 +213,16 @@ class SlackServer(object): self.communication_counter += 1 return self.communication_counter - def send_to_websocket(self, data): + def send_to_websocket(self, data, expect_reply=True): + data["id"] = self.get_communication_id() + message = json.dumps(data) try: - data["id"] = self.get_communication_id() - message = json.dumps(data) - self.message_buffer[data["id"]] = data + if expect_reply: + self.message_buffer[data["id"]] = data self.ws.send(message) dbg("Sent {}...".format(message[:100])) except: + dbg("Unexpected error: {}\nSent: {}".format(sys.exc_info()[0], data)) self.connected = False def ping(self): @@ -251,6 +255,16 @@ class SlackServer(object): self.connecting = False self.print_connection_info(login_data) + if len(self.message_buffer) > 0: + for message_id in self.message_buffer.keys(): + if self.message_buffer[message_id]["type"] != 'ping': + resend = self.message_buffer.pop(message_id) + dbg("Resent failed message.") + self.send_to_websocket(resend) + #sleep to prevent being disconnected by websocket server + time.sleep(1) + else: + self.message_buffer.pop(message_id) return True else: w.prnt("", "\n!! slack.com login error: " + login_data["error"] + "\n Please check your API token with\n \"/set plugins.var.python.slack_extension.slack_api_token (token)\"\n\n ") @@ -293,11 +307,13 @@ class SlackServer(object): if "topic" not in item: item["topic"] = {} item["topic"]["value"] = "" - self.channels.append(Channel(self, item["name"], item["id"], item["is_member"], item["last_read"], "#", item["members"], item["topic"]["value"])) + if not item["is_archived"]: + self.channels.append(Channel(self, item["name"], item["id"], item["is_member"], item["last_read"], "#", item["members"], item["topic"]["value"])) for item in data["groups"]: if "last_read" not in item: item["last_read"] = 0 - self.channels.append(GroupChannel(self, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"]["value"])) + if not item["is_archived"]: + self.channels.append(GroupChannel(self, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"]["value"])) for item in data["ims"]: if "last_read" not in item: item["last_read"] = 0 @@ -390,6 +406,7 @@ class Channel(SlackThing): channel_buffer = w.buffer_search("", "{}.{}".format(self.server.domain, self.name)) if channel_buffer != main_weechat_buffer: self.channel_buffer = channel_buffer + w.buffer_set(self.channel_buffer, "localvar_set_nick", self.server.nick) # w.buffer_set(self.channel_buffer, "highlight_words", self.server.nick) else: self.channel_buffer = None @@ -454,8 +471,10 @@ class Channel(SlackThing): def linkify_text(self, message): message = message.split(' ') for item in enumerate(message): - if item[1].startswith('@'): + if item[1].startswith('@') and len(item[1]) > 1: named = re.match('.*[@#](\w+)(\W*)', item[1]).groups() + if named[0] in ["group", "channel"]: + message[item[0]] = "<!{}>".format(named[0]) if self.server.users.find(named[0]): message[item[0]] = "<@{}>{}".format(self.server.users.find(named[0]).identifier, named[1]) if item[1].startswith('#') and self.server.channels.find(item[1]): @@ -491,7 +510,10 @@ class Channel(SlackThing): async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["leave"], {"channel": self.identifier}) def closed(self): - message_cache.pop(self.identifier) + try: + message_cache.pop(self.identifier) + except KeyError: + pass self.channel_buffer = None self.last_received = None self.close() @@ -1029,14 +1051,18 @@ def process_team_join(message_json): server.users.append(User(server, item["name"], item["id"], item["presence"])) server.buffer_prnt(server.buffer, "New user joined: {}".format(item["name"])) +def process_manual_presence_change(message_json): + process_presence_change(message_json) def process_presence_change(message_json): - buffer_name = "{}.{}".format(domain, message_json["user"]) + server = servers.find(message_json["myserver"]) + nick = message_json.get("user", server.nick) + buffer_name = "{}.{}".format(domain, nick) buf_ptr = w.buffer_search("", buffer_name) if message_json["presence"] == 'active': - users.find(message_json["user"]).set_active() + users.find(nick).set_active() else: - users.find(message_json["user"]).set_inactive() + users.find(nick).set_inactive() def process_channel_marked(message_json): @@ -1060,7 +1086,7 @@ def process_channel_created(message_json): server.channels.find(message_json["channel"]["name"]).open(False) else: item = message_json["channel"] - server.channels.append(Channel(server, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"])) + server.channels.append(Channel(server, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"]["value"])) server.buffer_prnt("New channel created: {}".format(item["name"])) @@ -1087,7 +1113,7 @@ def process_channel_joined(message_json): server.channels.find(message_json["channel"]["name"]).open(False) else: item = message_json["channel"] - server.channels.append(Channel(server, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"])) + server.channels.append(Channel(server, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"]["value"])) def process_channel_leave(message_json): @@ -1096,6 +1122,11 @@ def process_channel_leave(message_json): channel.user_leave(message_json["user"]) +def process_channel_archive(message_json): + channel = server.channels.find(message_json["channel"]) + channel.detach_buffer() + + def process_group_left(message_json): server = servers.find(message_json["myserver"]) server.channels.find(message_json["channel"]).close(False) @@ -1107,7 +1138,12 @@ def process_group_joined(message_json): server.channels.find(message_json["channel"]["name"]).open(False) else: item = message_json["channel"] - server.channels.append(GroupChannel(server, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"])) + server.channels.append(GroupChannel(server, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"]["value"])) + + +def process_group_archive(message_json): + channel = server.channels.find(message_json["channel"]) + channel.detach_buffer() def process_im_close(message_json): @@ -1405,7 +1441,7 @@ def typing_notification_cb(signal, sig_type, data): if channel: identifier = channel.identifier request = {"type": "typing", "channel": identifier} - channel.server.send_to_websocket(request) + channel.server.send_to_websocket(request, expect_reply=False) typing_timer = now return w.WEECHAT_RC_OK @@ -1434,7 +1470,7 @@ def slack_never_away_cb(data, remaining): identifier = server.channels.find("slackbot").identifier request = {"type": "typing", "channel": identifier} #request = {"type":"typing","channel":"slackbot"} - server.send_to_websocket(request) + server.send_to_websocket(request, expect_reply=False) return w.WEECHAT_RC_OK # Slack specific requests |