2014-04-03 19:21:01 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
import json
|
|
|
|
import re
|
2014-04-07 21:58:23 +00:00
|
|
|
import urllib
|
2015-09-21 17:31:12 +00:00
|
|
|
import time
|
2014-04-03 19:21:01 +00:00
|
|
|
|
|
|
|
import weechat as w
|
|
|
|
|
2015-04-12 17:42:40 +00:00
|
|
|
# Constant used to check if configs are required
|
|
|
|
REQUIRED = '_required'
|
|
|
|
|
2015-09-21 17:31:12 +00:00
|
|
|
w.register('weebullet', 'Lefty', '0.4.0', 'BSD', 'weebullet pushes notifications from IRC to Pushbullet.', '', '')
|
2014-04-03 19:21:01 +00:00
|
|
|
|
|
|
|
w.hook_print("", "irc_privmsg", "", 1, "priv_msg_cb", "")
|
2014-04-03 20:51:11 +00:00
|
|
|
w.hook_command(
|
|
|
|
"send_push_note", #command
|
|
|
|
"send a push note", # description
|
2015-04-11 22:27:53 +00:00
|
|
|
"[message]" # arguments description,
|
2014-04-03 20:51:11 +00:00
|
|
|
"", #argument
|
|
|
|
"",
|
|
|
|
"",
|
2015-02-11 13:42:02 +00:00
|
|
|
"cmd_send_push_note", ""
|
|
|
|
)
|
2015-02-11 13:32:26 +00:00
|
|
|
w.hook_command(
|
2015-04-11 22:27:53 +00:00
|
|
|
"weebullet",
|
2015-02-11 13:32:26 +00:00
|
|
|
"pushes notifications from IRC to Pushbullet",
|
|
|
|
"[command]",
|
2015-04-11 22:27:53 +00:00
|
|
|
"Available commands are:\n" \
|
2015-04-11 22:30:20 +00:00
|
|
|
" help : prints config options and defaults\n" \
|
|
|
|
" listdevices : prints a list of all devices associated with your Pushbullet API key\n" \
|
|
|
|
" listignores : prints a list of channels that highlights won't be pushed for\n" \
|
|
|
|
" ignore : adds a channel to the blacklist\n" \
|
|
|
|
" unignore : removes a channel from the blacklist",
|
2015-02-11 13:32:26 +00:00
|
|
|
"",
|
2015-02-11 13:42:02 +00:00
|
|
|
"cmd_help", ""
|
|
|
|
)
|
2014-04-07 21:58:23 +00:00
|
|
|
configs = {
|
2015-04-12 17:42:40 +00:00
|
|
|
"api_key": REQUIRED,
|
2015-09-21 18:02:20 +00:00
|
|
|
"away_only": "1", # only send when away
|
|
|
|
"device_iden": "all", # send to all devices
|
|
|
|
"ignored_channels": "", # no ignored channels
|
|
|
|
"min_notify_interval": "0", # seconds, don't notify more often than this
|
|
|
|
"debug": "0", # enable debugging
|
2014-04-03 20:41:39 +00:00
|
|
|
}
|
|
|
|
|
2015-09-21 18:02:20 +00:00
|
|
|
last_notification = 0 # 0 seconds from the epoch
|
2015-09-21 17:31:12 +00:00
|
|
|
|
2014-04-07 21:58:23 +00:00
|
|
|
for option, default_value in configs.items():
|
2014-04-03 20:41:39 +00:00
|
|
|
if w.config_get_plugin(option) == "":
|
2015-04-12 17:42:40 +00:00
|
|
|
if configs[option] == REQUIRED:
|
2015-02-11 13:32:26 +00:00
|
|
|
w.prnt("", w.prefix("error") + "pushbullet: Please set option: %s" % option)
|
|
|
|
if type(default_value) == "str":
|
|
|
|
w.prnt("", "pushbullet: /set plugins.var.python.weebullet.%s STRING" % option)
|
|
|
|
elif type(default_value) == "int":
|
|
|
|
w.prnt("", "pushbullet: /set plugins.var.python.weebullet.%s INT" % option)
|
|
|
|
else:
|
|
|
|
w.prnt("", "pushbullet: /set plugins.var.python.weebullet.%s VALUE" % option)
|
2014-04-07 21:58:23 +00:00
|
|
|
else:
|
2015-02-11 13:32:26 +00:00
|
|
|
w.config_set_plugin(option, configs[option])
|
|
|
|
|
2015-09-21 17:31:12 +00:00
|
|
|
|
|
|
|
def debug(msg):
|
2015-09-21 18:02:20 +00:00
|
|
|
if str(w.config_get_plugin("debug")) is not "0":
|
2015-09-21 17:31:12 +00:00
|
|
|
w.prnt("", "[weebullet] DEBUG: %s" % str(msg))
|
|
|
|
|
2015-02-11 13:32:26 +00:00
|
|
|
def process_devicelist_cb(data, url, status, response, err):
|
|
|
|
try:
|
|
|
|
devices = json.loads(response)["devices"]
|
|
|
|
w.prnt("", "Device List:")
|
|
|
|
for device in devices:
|
|
|
|
if device["pushable"]:
|
|
|
|
if "nickname" in device:
|
|
|
|
w.prnt("", "---\n%s" % device["nickname"])
|
|
|
|
else:
|
|
|
|
w.prnt("", "---\nUnnamed")
|
|
|
|
w.prnt("", "%s" % device["iden"])
|
|
|
|
except KeyError:
|
|
|
|
w.prnt("", "[weebullet] Error accessing device list: %s" % response)
|
|
|
|
return w.WEECHAT_RC_ERROR
|
|
|
|
return w.WEECHAT_RC_OK
|
2014-04-03 19:21:01 +00:00
|
|
|
|
2015-04-12 17:43:25 +00:00
|
|
|
def get_ignored_channels():
|
|
|
|
ignored_channels = w.config_get_plugin("ignored_channels")
|
|
|
|
if ignored_channels == "":
|
|
|
|
return []
|
|
|
|
else:
|
|
|
|
return [channel.strip() for channel in ignored_channels.split(',')]
|
|
|
|
|
2015-02-11 13:32:26 +00:00
|
|
|
def cmd_help(data, buffer, args):
|
2015-04-11 22:27:53 +00:00
|
|
|
# Get current list of ignored channels in list form
|
2015-04-12 17:43:25 +00:00
|
|
|
ignored_channels = get_ignored_channels()
|
2015-04-11 22:27:53 +00:00
|
|
|
|
|
|
|
# Used for checking for ignore/unignore commands and getting the arguments
|
|
|
|
ignore_command = re.match("^ignore\s+(.+)", args)
|
|
|
|
unignore_command = re.match("^unignore\s+(.+)", args)
|
|
|
|
|
|
|
|
if(ignore_command is not None):
|
|
|
|
channels_to_ignore = ignore_command.group(1).split(' ')
|
|
|
|
|
|
|
|
for channel in channels_to_ignore:
|
|
|
|
if channel not in ignored_channels:
|
|
|
|
ignored_channels.append(channel)
|
|
|
|
|
|
|
|
w.config_set_plugin("ignored_channels", ','.join(ignored_channels))
|
|
|
|
w.prnt("", "Updated. Ignored channels: %s" % w.config_get_plugin("ignored_channels"))
|
|
|
|
elif(unignore_command is not None):
|
|
|
|
channels_to_unignore = unignore_command.group(1).split(' ')
|
|
|
|
|
|
|
|
for channel in channels_to_unignore:
|
|
|
|
if channel in ignored_channels:
|
|
|
|
ignored_channels.remove(channel)
|
|
|
|
|
|
|
|
w.config_set_plugin("ignored_channels", ','.join(ignored_channels))
|
|
|
|
w.prnt("", "Updated. Ignored channels: %s" % w.config_get_plugin("ignored_channels"))
|
|
|
|
elif(args == "listignores"):
|
|
|
|
w.prnt("", "Ignored channels: %s" % w.config_get_plugin("ignored_channels"))
|
|
|
|
elif(args == "listdevices"):
|
2015-02-11 13:32:26 +00:00
|
|
|
apikey = w.config_get_plugin("api_key")
|
|
|
|
apiurl = "https://%s@api.pushbullet.com/v2/devices" % (apikey)
|
|
|
|
w.hook_process("url:"+apiurl, 20000, "process_devicelist_cb", "")
|
|
|
|
else:
|
|
|
|
w.prnt("", """
|
|
|
|
Weebullet requires an API key from your Pushbullet account to work. Set your API key with:
|
|
|
|
/set plugins.var.python.weebullet.api_key <KEY>
|
|
|
|
|
|
|
|
Weebullet will by default only send notifications when you are marked away on IRC. You can change this with:
|
|
|
|
/set plugins.var.python.weebullet.away_only [0|1]
|
|
|
|
|
|
|
|
Weebullet will by default send to all devices associated with your Pushbullet account. You can change this with:
|
|
|
|
/set plugins.var.python.weebullet.device_iden <ID>
|
|
|
|
|
2015-09-21 17:31:12 +00:00
|
|
|
Weebullet can ignore repeated notifications if they arrive too often. You can set this with (0 or blank to disable):
|
|
|
|
/set plugins.var.python.weebullet.min_notify_interval <NUMBER>
|
|
|
|
|
2015-02-11 13:32:26 +00:00
|
|
|
You can get a list of your devices from the Pushbullet website, or by using
|
|
|
|
/weebullet listdevices
|
|
|
|
""")
|
|
|
|
return w.WEECHAT_RC_OK
|
2014-04-03 19:21:01 +00:00
|
|
|
|
2014-04-08 03:40:03 +00:00
|
|
|
def process_pushbullet_cb(data, url, status, response, err):
|
|
|
|
body = None
|
|
|
|
headers = {}
|
|
|
|
lines = response.rstrip().splitlines()
|
|
|
|
status_code = int(lines.pop(0).split()[1])
|
|
|
|
for line in lines:
|
|
|
|
if body == "":
|
|
|
|
body += line
|
|
|
|
continue
|
|
|
|
header_line = line.split(":", 2)
|
|
|
|
if len(header_line) != 2:
|
|
|
|
body = ""
|
|
|
|
continue
|
|
|
|
headers[header_line[0].strip()] = header_line[1].strip()
|
|
|
|
|
|
|
|
|
2014-04-07 21:58:23 +00:00
|
|
|
# response is the string of http body
|
2014-04-08 03:40:03 +00:00
|
|
|
if status == w.WEECHAT_HOOK_PROCESS_ERROR:
|
2014-04-07 21:58:23 +00:00
|
|
|
w.prnt("", "[weebullet] Error sending to pushbullet: %s - %s" % (status, url))
|
|
|
|
return w.WEECHAT_RC_ERROR
|
2014-04-03 19:21:01 +00:00
|
|
|
|
2014-04-08 03:42:40 +00:00
|
|
|
if status_code is 401 or status_code is 403:
|
|
|
|
w.prnt("", "[weebullet] Invalid API Token: %s" % (w.config_get_plugin("api_key")))
|
|
|
|
return w.WEECHAT_RC_ERROR
|
2014-04-08 03:40:03 +00:00
|
|
|
if status_code is not 200:
|
|
|
|
w.prnt("", "[weebullet] Error sending to pushbullet: %s - %s - %s" % (url, status_code, body))
|
|
|
|
return w.WEECHAT_RC_ERROR
|
|
|
|
|
2014-04-07 21:58:23 +00:00
|
|
|
return w.WEECHAT_RC_OK
|
2014-04-03 19:21:01 +00:00
|
|
|
|
2014-04-07 21:58:23 +00:00
|
|
|
def send_push(title, body):
|
2015-09-21 17:31:12 +00:00
|
|
|
global last_notification
|
|
|
|
|
|
|
|
interval = w.config_get_plugin("min_notify_interval")
|
|
|
|
if interval is not None and interval != "" and int(interval) != 0:
|
|
|
|
interval = int(interval)
|
|
|
|
|
|
|
|
earliest_notification = last_notification + int(interval)
|
|
|
|
|
|
|
|
if last_notification is not None and time.time() <= earliest_notification:
|
|
|
|
debug("Too soon since last notification, skipping")
|
|
|
|
return w.WEECHAT_RC_OK
|
|
|
|
|
|
|
|
last_notification = time.time()
|
|
|
|
|
|
|
|
debug("Sending push. Title: [%s], body: [%s]" % (title, body))
|
|
|
|
|
2014-04-07 21:58:23 +00:00
|
|
|
apikey = w.config_get_plugin("api_key")
|
2014-08-23 10:36:25 +00:00
|
|
|
apiurl = "https://%s@api.pushbullet.com/v2/pushes" % (apikey)
|
2014-04-07 21:58:23 +00:00
|
|
|
timeout = 20000 # FIXME - actually use config
|
2015-01-14 00:48:19 +00:00
|
|
|
if len(title) is not 0 or len(body) is not 0:
|
2015-02-11 13:32:26 +00:00
|
|
|
deviceiden = w.config_get_plugin("device_iden")
|
|
|
|
if deviceiden == "all":
|
2015-02-11 13:42:02 +00:00
|
|
|
payload = urllib.urlencode({'type': 'note', 'title': title, 'body': body.encode('utf-8')})
|
2015-02-11 13:32:26 +00:00
|
|
|
else:
|
2015-02-11 13:42:02 +00:00
|
|
|
payload = urllib.urlencode({'type': 'note', 'title': title, 'body': body.encode('utf-8'), 'device_iden':deviceiden})
|
2015-02-11 13:32:26 +00:00
|
|
|
w.hook_process_hashtable("url:" + apiurl, { "postfields": payload, "header":"1" }, timeout, "process_pushbullet_cb", "")
|
2014-04-03 19:21:01 +00:00
|
|
|
|
2014-04-03 20:51:11 +00:00
|
|
|
def cmd_send_push_note(data, buffer, args):
|
|
|
|
send_push(
|
|
|
|
title="Manual Notification from weechat",
|
2015-02-11 13:32:26 +00:00
|
|
|
body=args.decode('utf-8')
|
2014-04-03 20:51:11 +00:00
|
|
|
)
|
|
|
|
return w.WEECHAT_RC_OK
|
2014-04-03 19:21:01 +00:00
|
|
|
|
|
|
|
def priv_msg_cb(data, bufferp, uber_empty, tagsn, isdisplayed,
|
|
|
|
ishilight, prefix, message):
|
|
|
|
"""Sends highlighted message to be printed on notification"""
|
|
|
|
|
2015-02-11 13:32:26 +00:00
|
|
|
if w.config_get_plugin("away_only") == "1":
|
|
|
|
am_away = w.buffer_get_string(bufferp, 'localvar_away')
|
|
|
|
else:
|
|
|
|
am_away = True
|
2014-04-03 19:21:01 +00:00
|
|
|
|
|
|
|
if not am_away:
|
2015-02-11 13:42:02 +00:00
|
|
|
# TODO: make debug a configurable
|
2015-09-21 17:31:12 +00:00
|
|
|
debug("Not away, skipping notification")
|
2015-02-11 13:42:02 +00:00
|
|
|
return w.WEECHAT_RC_OK
|
2014-04-03 19:21:01 +00:00
|
|
|
|
|
|
|
notif_body = u"<%s> %s" % (
|
|
|
|
prefix.decode('utf-8'),
|
2015-02-11 13:42:02 +00:00
|
|
|
message.decode('utf-8')
|
2014-04-03 19:21:01 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
# Check that it's in a "/q" buffer and that I'm not the one writing the msg
|
|
|
|
is_pm = w.buffer_get_string(bufferp, "localvar_type") == "private"
|
|
|
|
is_notify_private = re.search(r'(^|,)notify_private(,|$)', tagsn) is not None
|
|
|
|
# PM (query)
|
|
|
|
if (is_pm and is_notify_private):
|
2015-02-11 13:42:02 +00:00
|
|
|
send_push(
|
|
|
|
title="Privmsg from %s" % prefix.decode('utf-8'),
|
|
|
|
body=notif_body
|
|
|
|
)
|
2014-04-03 19:21:01 +00:00
|
|
|
|
|
|
|
# Highlight (your nick is quoted)
|
2014-08-30 19:31:15 +00:00
|
|
|
elif (str(ishilight) == "1"):
|
2014-04-03 19:21:01 +00:00
|
|
|
bufname = (w.buffer_get_string(bufferp, "short_name") or
|
2015-02-11 13:42:02 +00:00
|
|
|
w.buffer_get_string(bufferp, "name"))
|
2015-04-11 22:27:53 +00:00
|
|
|
|
2015-04-12 17:43:25 +00:00
|
|
|
ignored_channels = get_ignored_channels()
|
2015-04-11 22:27:53 +00:00
|
|
|
|
|
|
|
if bufname not in ignored_channels:
|
|
|
|
send_push(
|
|
|
|
title="Highlight in %s" % bufname.decode('utf-8'),
|
|
|
|
body=notif_body
|
|
|
|
)
|
|
|
|
else:
|
2015-09-21 17:31:12 +00:00
|
|
|
debug("[weebullet] Ignored channel, skipping notification in %s" % bufname.decode('utf-8'))
|
2014-04-03 19:21:01 +00:00
|
|
|
|
|
|
|
return w.WEECHAT_RC_OK
|