Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

476 lines
16 KiB

4 years ago
4 years ago
4 years ago
4 years ago
  1. # -*- coding: utf-8 -*-
  2. #
  3. # anotify.py
  4. # Copyright (c) 2012 magnific0 <jacco.geul@gmail.com>
  5. #
  6. # based on:
  7. # growl.py
  8. # Copyright (c) 2011 Sorin Ionescu <sorin.ionescu@gmail.com>
  9. #
  10. # Permission is hereby granted, free of charge, to any person obtaining a copy
  11. # of this software and associated documentation files (the "Software"), to deal
  12. # in the Software without restriction, including without limitation the rights
  13. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14. # copies of the Software, and to permit persons to whom the Software is
  15. # furnished to do so, subject to the following conditions:
  16. #
  17. # The above copyright notice and this permission notice shall be included in
  18. # all copies or substantial portions of the Software.
  19. #
  20. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  26. # SOFTWARE.
  27. SCRIPT_NAME = 'anotify'
  28. SCRIPT_AUTHOR = 'magnific0'
  29. SCRIPT_VERSION = '1.0.2'
  30. SCRIPT_LICENSE = 'MIT'
  31. SCRIPT_DESC = 'Sends libnotify notifications upon events.'
  32. # Changelog
  33. # 2014-05-10: v1.0.1 Change hook_print callback argument type of
  34. # displayed/highlight (WeeChat >= 1.0)
  35. # 2012-09-20: v1.0.0 Forked from original and adapted for libnotify.
  36. # -----------------------------------------------------------------------------
  37. # Settings
  38. # -----------------------------------------------------------------------------
  39. SETTINGS = {
  40. 'show_public_message': 'off',
  41. 'show_private_message': 'on',
  42. 'show_public_action_message': 'off',
  43. 'show_private_action_message': 'on',
  44. 'show_notice_message': 'off',
  45. 'show_invite_message': 'on',
  46. 'show_highlighted_message': 'on',
  47. 'show_server': 'on',
  48. 'show_channel_topic': 'on',
  49. 'show_dcc': 'on',
  50. 'show_upgrade_ended': 'on',
  51. 'sticky': 'off',
  52. 'sticky_away': 'on',
  53. 'icon': '/usr/share/pixmaps/weechat.xpm',
  54. }
  55. # -----------------------------------------------------------------------------
  56. # Imports
  57. # -----------------------------------------------------------------------------
  58. try:
  59. import re
  60. import weechat
  61. import gi
  62. import notify2
  63. import subprocess
  64. IMPORT_OK = True
  65. except ImportError as error:
  66. IMPORT_OK = False
  67. if str(error).find('weechat') != -1:
  68. print('This script must be run under WeeChat.')
  69. print('Get WeeChat at http://www.weechat.org.')
  70. else:
  71. weechat.prnt('', 'anotify: {0}'.format(error))
  72. # -----------------------------------------------------------------------------
  73. # Globals
  74. # -----------------------------------------------------------------------------
  75. TAGGED_MESSAGES = {
  76. 'public message or action': set(['irc_privmsg', 'notify_message']),
  77. 'private message or action': set(['irc_privmsg', 'notify_private']),
  78. 'notice message': set(['irc_notice', 'notify_private']),
  79. 'invite message': set(['irc_invite', 'notify_highlight']),
  80. 'channel topic': set(['irc_topic', ]),
  81. #'away status': set(['away_info', ]),
  82. }
  83. UNTAGGED_MESSAGES = {
  84. 'away status':
  85. re.compile(r'^You ((\w+).){2,3}marked as being away', re.UNICODE),
  86. 'dcc chat request':
  87. re.compile(r'^xfer: incoming chat request from (\w+)', re.UNICODE),
  88. 'dcc chat closed':
  89. re.compile(r'^xfer: chat closed with (\w+)', re.UNICODE),
  90. 'dcc get request':
  91. re.compile(
  92. r'^xfer: incoming file from (\w+) [^:]+: ((?:,\w|[^,])+),',
  93. re.UNICODE),
  94. 'dcc get completed':
  95. re.compile(r'^xfer: file ([^\s]+) received from \w+: OK', re.UNICODE),
  96. 'dcc get failed':
  97. re.compile(
  98. r'^xfer: file ([^\s]+) received from \w+: FAILED',
  99. re.UNICODE),
  100. 'dcc send completed':
  101. re.compile(r'^xfer: file ([^\s]+) sent to \w+: OK', re.UNICODE),
  102. 'dcc send failed':
  103. re.compile(r'^xfer: file ([^\s]+) sent to \w+: FAILED', re.UNICODE),
  104. }
  105. DISPATCH_TABLE = {
  106. 'away status': 'set_away_status',
  107. 'public message or action': 'notify_public_message_or_action',
  108. 'private message or action': 'notify_private_message_or_action',
  109. 'notice message': 'notify_notice_message',
  110. 'invite message': 'notify_invite_message',
  111. 'channel topic': 'notify_channel_topic',
  112. 'dcc chat request': 'notify_dcc_chat_request',
  113. 'dcc chat closed': 'notify_dcc_chat_closed',
  114. 'dcc get request': 'notify_dcc_get_request',
  115. 'dcc get completed': 'notify_dcc_get_completed',
  116. 'dcc get failed': 'notify_dcc_get_failed',
  117. 'dcc send completed': 'notify_dcc_send_completed',
  118. 'dcc send failed': 'notify_dcc_send_failed',
  119. }
  120. STATE = {
  121. 'icon': None,
  122. 'is_away': False
  123. }
  124. # -----------------------------------------------------------------------------
  125. # Notifiers
  126. # -----------------------------------------------------------------------------
  127. def cb_irc_server_connected(data, signal, signal_data):
  128. '''Notify when connected to IRC server.'''
  129. if weechat.config_get_plugin('show_server') == 'on':
  130. a_notify(
  131. 'Server',
  132. 'Server Connected',
  133. 'Connected to network {0}.'.format(signal_data))
  134. return weechat.WEECHAT_RC_OK
  135. def cb_irc_server_disconnected(data, signal, signal_data):
  136. '''Notify when disconnected to IRC server.'''
  137. if weechat.config_get_plugin('show_server') == 'on':
  138. a_notify(
  139. 'Server',
  140. 'Server Disconnected',
  141. 'Disconnected from network {0}.'.format(signal_data))
  142. return weechat.WEECHAT_RC_OK
  143. def cb_notify_upgrade_ended(data, signal, signal_data):
  144. '''Notify on end of WeeChat upgrade.'''
  145. if weechat.config_get_plugin('show_upgrade_ended') == 'on':
  146. a_notify(
  147. 'WeeChat',
  148. 'WeeChat Upgraded',
  149. 'WeeChat has been upgraded.')
  150. return weechat.WEECHAT_RC_OK
  151. def notify_highlighted_message(prefix, message):
  152. '''Notify on highlighted message.'''
  153. if weechat.config_get_plugin("show_highlighted_message") == "on":
  154. a_notify(
  155. 'Highlight',
  156. 'Highlighted Message',
  157. "{0}: {1}".format(prefix, message),
  158. priority=notify2.URGENCY_CRITICAL)
  159. def notify_public_message_or_action(prefix, message, highlighted):
  160. '''Notify on public message or action.'''
  161. if prefix == ' *':
  162. regex = re.compile(r'^(\w+) (.+)$', re.UNICODE)
  163. match = regex.match(message)
  164. if match:
  165. prefix = match.group(1)
  166. message = match.group(2)
  167. notify_public_action_message(prefix, message, highlighted)
  168. else:
  169. if highlighted:
  170. notify_highlighted_message(prefix, message)
  171. elif weechat.config_get_plugin("show_public_message") == "on":
  172. a_notify(
  173. 'Public',
  174. 'Public Message',
  175. '{0}: {1}'.format(prefix, message))
  176. def notify_private_message_or_action(prefix, message, highlighted):
  177. '''Notify on private message or action.'''
  178. regex = re.compile(r'^CTCP_MESSAGE.+?ACTION (.+)$', re.UNICODE)
  179. match = regex.match(message)
  180. if match:
  181. notify_private_action_message(prefix, match.group(1), highlighted)
  182. else:
  183. if prefix == ' *':
  184. regex = re.compile(r'^(\w+) (.+)$', re.UNICODE)
  185. match = regex.match(message)
  186. if match:
  187. prefix = match.group(1)
  188. message = match.group(2)
  189. notify_private_action_message(prefix, message, highlighted)
  190. else:
  191. if highlighted:
  192. notify_highlighted_message(prefix, message)
  193. elif weechat.config_get_plugin("show_private_message") == "on":
  194. a_notify(
  195. 'Private',
  196. 'Private Message',
  197. '{0}: {1}'.format(prefix, message))
  198. def notify_public_action_message(prefix, message, highlighted):
  199. '''Notify on public action message.'''
  200. if highlighted:
  201. notify_highlighted_message(prefix, message)
  202. elif weechat.config_get_plugin("show_public_action_message") == "on":
  203. a_notify(
  204. 'Action',
  205. 'Public Action Message',
  206. '{0}: {1}'.format(prefix, message),
  207. priority=notify2.URGENCY_NORMAL)
  208. def notify_private_action_message(prefix, message, highlighted):
  209. '''Notify on private action message.'''
  210. if highlighted:
  211. notify_highlighted_message(prefix, message)
  212. elif weechat.config_get_plugin("show_private_action_message") == "on":
  213. a_notify(
  214. 'Action',
  215. 'Private Action Message',
  216. '{0}: {1}'.format(prefix, message),
  217. priority=notify2.URGENCY_NORMAL)
  218. def notify_notice_message(prefix, message, highlighted):
  219. '''Notify on notice message.'''
  220. regex = re.compile(r'^([^\s]*) [^:]*: (.+)$', re.UNICODE)
  221. match = regex.match(message)
  222. if match:
  223. prefix = match.group(1)
  224. message = match.group(2)
  225. if highlighted:
  226. notify_highlighted_message(prefix, message)
  227. elif weechat.config_get_plugin("show_notice_message") == "on":
  228. a_notify(
  229. 'Notice',
  230. 'Notice Message',
  231. '{0}: {1}'.format(prefix, message))
  232. def notify_invite_message(prefix, message, highlighted):
  233. '''Notify on channel invitation message.'''
  234. if weechat.config_get_plugin("show_invite_message") == "on":
  235. regex = re.compile(
  236. r'^You have been invited to ([^\s]+) by ([^\s]+)$', re.UNICODE)
  237. match = regex.match(message)
  238. if match:
  239. channel = match.group(1)
  240. nick = match.group(2)
  241. a_notify(
  242. 'Invite',
  243. 'Channel Invitation',
  244. '{0} has invited you to join {1}.'.format(nick, channel))
  245. def notify_channel_topic(prefix, message, highlighted):
  246. '''Notify on channel topic change.'''
  247. if weechat.config_get_plugin("show_channel_topic") == "on":
  248. regex = re.compile(
  249. r'^\w+ has (?:changed|unset) topic for ([^\s]+)' +
  250. '(?:(?: from "(?:(?:"\w|[^"])+)")? to "((?:"\w|[^"])+)")?',
  251. re.UNICODE)
  252. match = regex.match(message)
  253. if match:
  254. channel = match.group(1)
  255. topic = match.group(2) or ''
  256. a_notify(
  257. 'Channel',
  258. 'Channel Topic',
  259. "{0}: {1}".format(channel, topic))
  260. def notify_dcc_chat_request(match):
  261. '''Notify on DCC chat request.'''
  262. if weechat.config_get_plugin("show_dcc") == "on":
  263. nick = match.group(1)
  264. a_notify(
  265. 'DCC',
  266. 'Direct Chat Request',
  267. '{0} wants to chat directly.'.format(nick))
  268. def notify_dcc_chat_closed(match):
  269. '''Notify on DCC chat termination.'''
  270. if weechat.config_get_plugin("show_dcc") == "on":
  271. nick = match.group(1)
  272. a_notify(
  273. 'DCC',
  274. 'Direct Chat Ended',
  275. 'Direct chat with {0} has ended.'.format(nick))
  276. def notify_dcc_get_request(match):
  277. 'Notify on DCC get request.'
  278. if weechat.config_get_plugin("show_dcc") == "on":
  279. nick = match.group(1)
  280. file_name = match.group(2)
  281. a_notify(
  282. 'DCC',
  283. 'File Transfer Request',
  284. '{0} wants to send you {1}.'.format(nick, file_name))
  285. def notify_dcc_get_completed(match):
  286. 'Notify on DCC get completion.'
  287. if weechat.config_get_plugin("show_dcc") == "on":
  288. file_name = match.group(1)
  289. a_notify('DCC', 'Download Complete', file_name)
  290. def notify_dcc_get_failed(match):
  291. 'Notify on DCC get failure.'
  292. if weechat.config_get_plugin("show_dcc") == "on":
  293. file_name = match.group(1)
  294. a_notify('DCC', 'Download Failed', file_name)
  295. def notify_dcc_send_completed(match):
  296. 'Notify on DCC send completion.'
  297. if weechat.config_get_plugin("show_dcc") == "on":
  298. file_name = match.group(1)
  299. a_notify('DCC', 'Upload Complete', file_name)
  300. def notify_dcc_send_failed(match):
  301. 'Notify on DCC send failure.'
  302. if weechat.config_get_plugin("show_dcc") == "on":
  303. file_name = match.group(1)
  304. a_notify('DCC', 'Upload Failed', file_name)
  305. # -----------------------------------------------------------------------------
  306. # Utility
  307. # -----------------------------------------------------------------------------
  308. def set_away_status(match):
  309. status = match.group(1)
  310. if status == 'been ':
  311. STATE['is_away'] = True
  312. if status == 'longer ':
  313. STATE['is_away'] = False
  314. def cb_process_message(
  315. data,
  316. wbuffer,
  317. date,
  318. tags,
  319. displayed,
  320. highlight,
  321. prefix,
  322. message
  323. ):
  324. '''Delegates incoming messages to appropriate handlers.'''
  325. tags = set(tags.split(','))
  326. functions = globals()
  327. is_public_message = tags.issuperset(
  328. TAGGED_MESSAGES['public message or action'])
  329. buffer_name = weechat.buffer_get_string(wbuffer, 'name')
  330. dcc_buffer_regex = re.compile(r'^irc_dcc\.', re.UNICODE)
  331. dcc_buffer_match = dcc_buffer_regex.match(buffer_name)
  332. highlighted = False
  333. if int(highlight):
  334. highlighted = True
  335. # Private DCC message identifies itself as public.
  336. if is_public_message and dcc_buffer_match:
  337. notify_private_message_or_action(prefix, message, highlighted)
  338. return weechat.WEECHAT_RC_OK
  339. # Pass identified, untagged message to its designated function.
  340. for key, value in UNTAGGED_MESSAGES.items():
  341. match = value.match(message)
  342. if match:
  343. functions[DISPATCH_TABLE[key]](match)
  344. return weechat.WEECHAT_RC_OK
  345. # Pass identified, tagged message to its designated function.
  346. for key, value in TAGGED_MESSAGES.items():
  347. if tags.issuperset(value):
  348. functions[DISPATCH_TABLE[key]](prefix, message, highlighted)
  349. return weechat.WEECHAT_RC_OK
  350. return weechat.WEECHAT_RC_OK
  351. def a_notify(notification, title, description, priority=notify2.URGENCY_LOW):
  352. '''Returns whether notifications should be sticky.'''
  353. is_away = STATE['is_away']
  354. icon = STATE['icon']
  355. time_out = 5000
  356. if weechat.config_get_plugin('sticky') == 'on':
  357. time_out = 0
  358. if weechat.config_get_plugin('sticky_away') == 'on' and is_away:
  359. time_out = 0
  360. try:
  361. # notify2.init("wee-notifier")
  362. # wn = notify2.Notification(title, description, icon)
  363. # wn.set_urgency(priority)
  364. # wn.set_timeout(time_out)
  365. # wn.show()
  366. subprocess.Popen(["notify-send", "-a", " WeeChat", title, description])
  367. if title != "Server Connected" and title != "Server Disconnected":
  368. subprocess.Popen(["canberra-gtk-play", "-i", "message-new-instant", "-V", "15"])
  369. except Exception as error:
  370. weechat.prnt('', 'anotify: {0}'.format(error))
  371. # -----------------------------------------------------------------------------
  372. # Main
  373. # -----------------------------------------------------------------------------
  374. def main():
  375. '''Sets up WeeChat notifications.'''
  376. # Initialize options.
  377. for option, value in SETTINGS.items():
  378. if not weechat.config_is_set_plugin(option):
  379. weechat.config_set_plugin(option, value)
  380. # Initialize.
  381. name = "WeeChat"
  382. icon = "/usr/share/pixmaps/weechat.xpm"
  383. notifications = [
  384. 'Public',
  385. 'Private',
  386. 'Action',
  387. 'Notice',
  388. 'Invite',
  389. 'Highlight',
  390. 'Server',
  391. 'Channel',
  392. 'DCC',
  393. 'WeeChat'
  394. ]
  395. STATE['icon'] = icon
  396. # Register hooks.
  397. weechat.hook_signal(
  398. 'irc_server_connected',
  399. 'cb_irc_server_connected',
  400. '')
  401. weechat.hook_signal(
  402. 'irc_server_disconnected',
  403. 'cb_irc_server_disconnected',
  404. '')
  405. weechat.hook_signal('upgrade_ended', 'cb_upgrade_ended', '')
  406. weechat.hook_print('', '', '', 1, 'cb_process_message', '')
  407. if __name__ == '__main__' and IMPORT_OK and weechat.register(
  408. SCRIPT_NAME,
  409. SCRIPT_AUTHOR,
  410. SCRIPT_VERSION,
  411. SCRIPT_LICENSE,
  412. SCRIPT_DESC,
  413. '',
  414. ''
  415. ):
  416. main()