--- a/weechat/python/autoload/growl.py Tue Oct 11 09:09:18 2011 -0400
+++ b/weechat/python/autoload/growl.py Wed Oct 19 14:35:48 2011 -0400
@@ -1,136 +1,146 @@
# -*- coding: utf-8 -*-
#
-# growl.py
+# growl.py
# Copyright (c) 2011 Sorin Ionescu <sorin.ionescu@gmail.com>
#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
-SCRIPT_NAME = 'growl'
-SCRIPT_AUTHOR = 'Sorin Ionescu <sorin.ionescu@gmail.com>'
-SCRIPT_VERSION = '1.0.0'
-SCRIPT_LICENSE = 'GPL3'
-SCRIPT_DESC = 'Sends Growl notifications upon events.'
+SCRIPT_NAME = 'growl'
+SCRIPT_AUTHOR = 'Sorin Ionescu <sorin.ionescu@gmail.com>'
+SCRIPT_VERSION = '1.0.4'
+SCRIPT_LICENSE = 'MIT'
+SCRIPT_DESC = 'Sends Growl notifications upon events.'
+
# Changelog
-#
+# 2011-10-11: v1.0.4 Handle import errors better.
+# 2011-10-10: v1.0.3 Handle Growl exceptions.
+# 2011-10-04: v1.0.2 Growl 1.3 requires GNTP.
+# 2011-09-25: v1.0.1 Always show highlighted messages if set on.
# 2011-03-27: v1.0.0 Initial release.
-# ------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
# Settings
-# ------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
SETTINGS = {
- 'show_public_message' : 'off',
- 'show_private_message' : 'on',
- 'show_public_action_message' : 'off',
- 'show_private_action_message' : 'on',
- 'show_notice_message' : 'off',
- 'show_invite_message' : 'on',
- 'show_highlighted_message' : 'on',
- 'show_server' : 'on',
- 'show_channel_topic' : 'on',
- 'show_dcc' : 'on',
- 'show_upgrade_ended' : 'on',
- 'sticky' : 'off',
- 'sticky_away' : 'on',
- 'hostname' : '',
- 'password' : '',
- 'icon' : 'icon.png',
+ 'show_public_message': 'off',
+ 'show_private_message': 'on',
+ 'show_public_action_message': 'off',
+ 'show_private_action_message': 'on',
+ 'show_notice_message': 'off',
+ 'show_invite_message': 'on',
+ 'show_highlighted_message': 'on',
+ 'show_server': 'on',
+ 'show_channel_topic': 'on',
+ 'show_dcc': 'on',
+ 'show_upgrade_ended': 'on',
+ 'sticky': 'off',
+ 'sticky_away': 'on',
+ 'hostname': '',
+ 'password': '',
+ 'icon': 'icon.png',
}
-# ------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
# Imports
-# ------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
try:
import re
import os
import weechat
- import Growl
+ from gntp.notifier import GrowlNotifier
IMPORT_OK = True
except ImportError as error:
IMPORT_OK = False
- if str(error) == 'No module named weechat':
+ if str(error).find('weechat') != -1:
print('This script must be run under WeeChat.')
print('Get WeeChat at http://www.weechat.org.')
- if str(error) == 'No module named Growl':
- weechat.prnt('', 'Growl: Python bindings are not installed.')
-
+ elif str(error).find('notifier') != -1:
+ weechat.prnt('', 'growl: GNTP bindings are not installed')
+ else:
+ weechat.prnt('', 'growl: {0}'.format(error))
-# ------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
# Globals
-# ------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
TAGGED_MESSAGES = {
- 'public message or action' : set(['irc_privmsg', 'notify_message']),
- 'private message or action' : set(['irc_privmsg', 'notify_private']),
- 'notice message' : set(['irc_notice', 'notify_private']),
- 'invite message' : set(['irc_invite', 'notify_highlight']),
- 'channel topic' : set(['irc_topic',]),
- 'away status' : set(['away_info',]),
+ 'public message or action': set(['irc_privmsg', 'notify_message']),
+ 'private message or action': set(['irc_privmsg', 'notify_private']),
+ 'notice message': set(['irc_notice', 'notify_private']),
+ 'invite message': set(['irc_invite', 'notify_highlight']),
+ 'channel topic': set(['irc_topic', ]),
+ 'away status': set(['away_info', ]),
}
+
UNTAGGED_MESSAGES = {
- 'dcc chat request' : re.compile(
- r'^xfer: incoming chat request from (\w+)',
- re.UNICODE),
- 'dcc chat closed' : re.compile(
- r'^xfer: chat closed with (\w+)',
- re.UNICODE),
- 'dcc get request' : re.compile(
- r'^xfer: incoming file from (\w+) [^:]+: ' +
- '((?:,\w|[^,])+),',
- re.UNICODE),
- 'dcc get completed' : re.compile(
- r'^xfer: file ([^\s]+) received from \w+: OK',
- re.UNICODE),
- 'dcc get failed' : re.compile(
- r'^xfer: file ([^\s]+) received from \w+: ' +
- 'FAILED',
- re.UNICODE),
- 'dcc send completed' : re.compile(
- r'^xfer: file ([^\s]+) sent to \w+: OK',
- re.UNICODE),
- 'dcc send failed' : re.compile(
- r'^xfer: file ([^\s]+) sent to \w+: FAILED',
- re.UNICODE),
+ 'dcc chat request':
+ re.compile(r'^xfer: incoming chat request from (\w+)', re.UNICODE),
+ 'dcc chat closed':
+ re.compile(r'^xfer: chat closed with (\w+)', re.UNICODE),
+ 'dcc get request':
+ re.compile(
+ r'^xfer: incoming file from (\w+) [^:]+: ((?:,\w|[^,])+),',
+ re.UNICODE),
+ 'dcc get completed':
+ re.compile(r'^xfer: file ([^\s]+) received from \w+: OK', re.UNICODE),
+ 'dcc get failed':
+ re.compile(
+ r'^xfer: file ([^\s]+) received from \w+: FAILED',
+ re.UNICODE),
+ 'dcc send completed':
+ re.compile(r'^xfer: file ([^\s]+) sent to \w+: OK', re.UNICODE),
+ 'dcc send failed':
+ re.compile(r'^xfer: file ([^\s]+) sent to \w+: FAILED', re.UNICODE),
}
+
DISPATCH_TABLE = {
- 'away status' : 'set_away_status',
- 'public message or action' : 'notify_public_message_or_action',
- 'private message or action' : 'notify_private_message_or_action',
- 'notice message' : 'notify_notice_message',
- 'invite message' : 'notify_invite_message',
- 'channel topic' : 'notify_channel_topic',
- 'dcc chat request' : 'notify_dcc_chat_request',
- 'dcc chat closed' : 'notify_dcc_chat_closed',
- 'dcc get request' : 'notify_dcc_get_request',
- 'dcc get completed' : 'notify_dcc_get_completed',
- 'dcc get failed' : 'notify_dcc_get_failed',
- 'dcc send completed' : 'notify_dcc_send_completed',
- 'dcc send failed' : 'notify_dcc_send_failed',
+ 'away status': 'set_away_status',
+ 'public message or action': 'notify_public_message_or_action',
+ 'private message or action': 'notify_private_message_or_action',
+ 'notice message': 'notify_notice_message',
+ 'invite message': 'notify_invite_message',
+ 'channel topic': 'notify_channel_topic',
+ 'dcc chat request': 'notify_dcc_chat_request',
+ 'dcc chat closed': 'notify_dcc_chat_closed',
+ 'dcc get request': 'notify_dcc_get_request',
+ 'dcc get completed': 'notify_dcc_get_completed',
+ 'dcc get failed': 'notify_dcc_get_failed',
+ 'dcc send completed': 'notify_dcc_send_completed',
+ 'dcc send failed': 'notify_dcc_send_failed',
}
+
STATE = {
- 'growl' : None,
- 'is_away' : False
+ 'growl': None,
+ 'icon': None,
+ 'is_away': False
}
-# ------------------------------------------------------------------------------
-# Notifiers
-# ------------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# Notifiers
+# -----------------------------------------------------------------------------
def cb_irc_server_connected(data, signal, signal_data):
'''Notify when connected to IRC server.'''
if weechat.config_get_plugin('show_server') == 'on':
@@ -140,6 +150,7 @@
'Connected to network {0}.'.format(signal_data))
return weechat.WEECHAT_RC_OK
+
def cb_irc_server_disconnected(data, signal, signal_data):
'''Notify when disconnected to IRC server.'''
if weechat.config_get_plugin('show_server') == 'on':
@@ -149,6 +160,7 @@
'Disconnected from network {0}.'.format(signal_data))
return weechat.WEECHAT_RC_OK
+
def cb_notify_upgrade_ended(data, signal, signal_data):
'''Notify on end of WeeChat upgrade.'''
if weechat.config_get_plugin('show_upgrade_ended') == 'on':
@@ -158,6 +170,7 @@
'WeeChat has been upgraded.')
return weechat.WEECHAT_RC_OK
+
def notify_highlighted_message(prefix, message):
'''Notify on highlighted message.'''
if weechat.config_get_plugin("show_highlighted_message") == "on":
@@ -167,6 +180,7 @@
"{0}: {1}".format(prefix, message),
priority=2)
+
def notify_public_message_or_action(prefix, message, highlighted):
'''Notify on public message or action.'''
if prefix == ' *':
@@ -179,12 +193,12 @@
else:
if highlighted:
notify_highlighted_message(prefix, message)
- else:
- if weechat.config_get_plugin("show_public_message") == "on":
- growl_notify(
- 'Public',
- 'Public Message',
- '{0}: {1}'.format(prefix, message))
+ elif weechat.config_get_plugin("show_public_message") == "on":
+ growl_notify(
+ 'Public',
+ 'Public Message',
+ '{0}: {1}'.format(prefix, message))
+
def notify_private_message_or_action(prefix, message, highlighted):
'''Notify on private message or action.'''
@@ -203,52 +217,52 @@
else:
if highlighted:
notify_highlighted_message(prefix, message)
- else:
- if weechat.config_get_plugin("show_private_message") == "on":
- growl_notify(
- 'Private',
- 'Private Message',
- '{0}: {1}'.format(prefix, message))
+ elif weechat.config_get_plugin("show_private_message") == "on":
+ growl_notify(
+ 'Private',
+ 'Private Message',
+ '{0}: {1}'.format(prefix, message))
+
def notify_public_action_message(prefix, message, highlighted):
'''Notify on public action message.'''
- if weechat.config_get_plugin("show_public_action_message") == "on":
- if highlighted:
- notify_highlighted_message(prefix, message)
- else:
- growl_notify(
- 'Action',
- 'Public Action Message',
- '{0}: {1}'.format(prefix, message),
- priority=1)
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_public_action_message") == "on":
+ growl_notify(
+ 'Action',
+ 'Public Action Message',
+ '{0}: {1}'.format(prefix, message),
+ priority=1)
+
def notify_private_action_message(prefix, message, highlighted):
'''Notify on private action message.'''
- if weechat.config_get_plugin("show_private_action_message") == "on":
- if highlighted:
- notify_highlighted_message(prefix, message)
- else:
- growl_notify(
- 'Action',
- 'Private Action Message',
- '{0}: {1}'.format(prefix, message),
- priority=1)
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_private_action_message") == "on":
+ growl_notify(
+ 'Action',
+ 'Private Action Message',
+ '{0}: {1}'.format(prefix, message),
+ priority=1)
+
def notify_notice_message(prefix, message, highlighted):
'''Notify on notice message.'''
- if weechat.config_get_plugin("show_notice_message") == "on":
- regex = re.compile(r'^([^\s]*) [^:]*: (.+)$', re.UNICODE)
- match = regex.match(message)
- if match:
- prefix = match.group(1)
- message = match.group(2)
- if highlighted:
- notify_highlighted_message(prefix, message)
- else:
- growl_notify(
- 'Notice',
- 'Notice Message',
- '{0}: {1}'.format(prefix, message))
+ regex = re.compile(r'^([^\s]*) [^:]*: (.+)$', re.UNICODE)
+ match = regex.match(message)
+ if match:
+ prefix = match.group(1)
+ message = match.group(2)
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_notice_message") == "on":
+ growl_notify(
+ 'Notice',
+ 'Notice Message',
+ '{0}: {1}'.format(prefix, message))
+
def notify_invite_message(prefix, message, highlighted):
'''Notify on channel invitation message.'''
@@ -264,11 +278,12 @@
'Channel Invitation',
'{0} has invited you to join {1}.'.format(nick, channel))
+
def notify_channel_topic(prefix, message, highlighted):
'''Notify on channel topic change.'''
if weechat.config_get_plugin("show_channel_topic") == "on":
regex = re.compile(
- r'^\w+ has (?:changed|unset) topic for ([^\s]+)'+
+ r'^\w+ has (?:changed|unset) topic for ([^\s]+)' +
'(?:(?: from "(?:(?:"\w|[^"])+)")? to "((?:"\w|[^"])+)")?',
re.UNICODE)
match = regex.match(message)
@@ -280,6 +295,7 @@
'Channel Topic',
"{0}: {1}".format(channel, topic))
+
def notify_dcc_chat_request(match):
'''Notify on DCC chat request.'''
if weechat.config_get_plugin("show_dcc") == "on":
@@ -289,6 +305,7 @@
'Direct Chat Request',
'{0} wants to chat directly.'.format(nick))
+
def notify_dcc_chat_closed(match):
'''Notify on DCC chat termination.'''
if weechat.config_get_plugin("show_dcc") == "on":
@@ -298,6 +315,7 @@
'Direct Chat Ended',
'Direct chat with {0} has ended.'.format(nick))
+
def notify_dcc_get_request(match):
'Notify on DCC get request.'
if weechat.config_get_plugin("show_dcc") == "on":
@@ -308,24 +326,28 @@
'File Transfer Request',
'{0} wants to send you {1}.'.format(nick, file_name))
+
def notify_dcc_get_completed(match):
'Notify on DCC get completion.'
if weechat.config_get_plugin("show_dcc") == "on":
file_name = match.group(1)
growl_notify('DCC', 'Download Complete', file_name)
+
def notify_dcc_get_failed(match):
'Notify on DCC get failure.'
if weechat.config_get_plugin("show_dcc") == "on":
file_name = match.group(1)
growl_notify('DCC', 'Download Failed', file_name)
+
def notify_dcc_send_completed(match):
'Notify on DCC send completion.'
if weechat.config_get_plugin("show_dcc") == "on":
file_name = match.group(1)
growl_notify('DCC', 'Upload Complete', file_name)
+
def notify_dcc_send_failed(match):
'Notify on DCC send failure.'
if weechat.config_get_plugin("show_dcc") == "on":
@@ -333,9 +355,9 @@
growl_notify('DCC', 'Upload Failed', file_name)
-# ------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
# Utility
-# ------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
def set_away_status(prefix, message, highlighted):
'''Sets away status for use by sticky notifications.'''
regex = re.compile(r'^\[\w+ \b(away|back)\b:', re.UNICODE)
@@ -347,6 +369,7 @@
if status == 'back':
STATE['is_away'] = False
+
def cb_process_message(
data,
wbuffer,
@@ -385,21 +408,32 @@
return weechat.WEECHAT_RC_OK
return weechat.WEECHAT_RC_OK
+
def growl_notify(notification, title, description, priority=None):
'''Returns whether Growl notifications should be sticky.'''
growl = STATE['growl']
is_away = STATE['is_away']
+ icon = STATE['icon']
is_sticky = False
if weechat.config_get_plugin('sticky') == 'on':
is_sticky = True
if weechat.config_get_plugin('sticky_away') == 'on' and is_away:
is_sticky = True
- growl.notify(notification, title, description, '', is_sticky, priority)
+ try:
+ growl.notify(
+ noteType=notification,
+ title=title,
+ description=description,
+ icon=icon,
+ sticky=is_sticky,
+ priority=priority)
+ except Exception as error:
+ weechat.prnt('', 'growl: {0}'.format(error))
-# ------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
# Main
-# ------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
def main():
'''Sets up WeeChat Growl notifications.'''
# Initialize options.
@@ -410,7 +444,7 @@
name = "WeeChat"
hostname = weechat.config_get_plugin('hostname')
password = weechat.config_get_plugin('password')
- icon = Growl.Image.imageFromPath(
+ icon = 'file://{0}'.format(
os.path.join(
weechat.info_get("weechat_dir", ""),
weechat.config_get_plugin('icon')))
@@ -430,14 +464,18 @@
hostname = None
if len(password) == 0:
password = None
- growl = Growl.GrowlNotifier(
+ growl = GrowlNotifier(
applicationName=name,
hostname=hostname,
password=password,
notifications=notifications,
applicationIcon=icon)
- growl.register()
+ try:
+ growl.register()
+ except Exception as error:
+ weechat.prnt('', 'growl: {0}'.format(error))
STATE['growl'] = growl
+ STATE['icon'] = icon
# Register hooks.
weechat.hook_signal(
'irc_server_connected',
@@ -450,6 +488,7 @@
weechat.hook_signal('upgrade_ended', 'cb_upgrade_ended', '')
weechat.hook_print('', '', '', 1, 'cb_process_message', '')
+
if __name__ == '__main__' and IMPORT_OK and weechat.register(
SCRIPT_NAME,
SCRIPT_AUTHOR,
@@ -460,4 +499,3 @@
''
):
main()
-