/plugins/growl.py

https://github.com/ozamosi/river · Python · 150 lines · 101 code · 25 blank · 24 comment · 7 complexity · a394d084a2b61ef4c1050ae4b32590fd MD5 · raw file

  1. #!/usr/bin/env python
  2. ###
  3. ### netgrowl
  4. ###
  5. """Growl 0.6 Network Protocol Client for Python"""
  6. __version__ = "0.6.1" # will always match Growl version
  7. __author__ = "Rui Carmo (http://the.taoofmac.com)"
  8. __copyright__ = "(C) 2004 Rui Carmo. Code under BSD License."
  9. __contributors__ = "Ingmar J Stein (Growl Team)"
  10. import struct
  11. import md5
  12. from socket import AF_INET, SOCK_DGRAM, socket
  13. GROWL_UDP_PORT=9887
  14. GROWL_PROTOCOL_VERSION=1
  15. GROWL_TYPE_REGISTRATION=0
  16. GROWL_TYPE_NOTIFICATION=1
  17. class GrowlRegistrationPacket:
  18. """Builds a Growl Network Registration packet.
  19. Defaults to emulating the command-line growlnotify utility."""
  20. def __init__(self, application="growlnotify", password = None ):
  21. self.notifications = []
  22. self.defaults = [] # array of indexes into notifications
  23. self.application = application.encode("utf-8")
  24. self.password = password
  25. # end def
  26. def addNotification(self, notification="Command-Line Growl Notification", enabled=True):
  27. """Adds a notification type and sets whether it is enabled on the GUI"""
  28. self.notifications.append(notification)
  29. if enabled:
  30. self.defaults.append(len(self.notifications)-1)
  31. # end def
  32. def payload(self):
  33. """Returns the packet payload."""
  34. self.data = struct.pack( "!BBH",
  35. GROWL_PROTOCOL_VERSION,
  36. GROWL_TYPE_REGISTRATION,
  37. len(self.application) )
  38. self.data += struct.pack( "BB",
  39. len(self.notifications),
  40. len(self.defaults) )
  41. self.data += self.application
  42. for notification in self.notifications:
  43. encoded = notification.encode("utf-8")
  44. self.data += struct.pack("!H", len(encoded))
  45. self.data += encoded
  46. for default in self.defaults:
  47. self.data += struct.pack("B", default)
  48. self.checksum = md5.new()
  49. self.checksum.update(self.data)
  50. if self.password:
  51. self.checksum.update(self.password)
  52. self.data += self.checksum.digest()
  53. return self.data
  54. # end def
  55. # end class
  56. class GrowlNotificationPacket:
  57. """Builds a Growl Network Notification packet.
  58. Defaults to emulating the command-line growlnotify utility."""
  59. def __init__(self, application="growlnotify",
  60. notification="Command-Line Growl Notification", title="Title",
  61. description="Description", priority = 0, sticky = False, password = None ):
  62. self.application = application.encode("utf-8")
  63. self.notification = notification.encode("utf-8")
  64. self.title = title.encode("utf-8")
  65. self.description = description.encode("utf-8")
  66. flags = (priority & 0x07) * 2
  67. if priority < 0:
  68. flags |= 0x08
  69. if sticky:
  70. flags = flags | 0x0100
  71. self.data = struct.pack( "!BBHHHHH",
  72. GROWL_PROTOCOL_VERSION,
  73. GROWL_TYPE_NOTIFICATION,
  74. flags,
  75. len(self.notification),
  76. len(self.title),
  77. len(self.description),
  78. len(self.application) )
  79. self.data += self.notification
  80. self.data += self.title
  81. self.data += self.description
  82. self.data += self.application
  83. self.checksum = md5.new()
  84. self.checksum.update(self.data)
  85. if password:
  86. self.checksum.update(password)
  87. self.data += self.checksum.digest()
  88. # end def
  89. def payload(self):
  90. """Returns the packet payload."""
  91. return self.data
  92. # end def
  93. # end class
  94. ###
  95. ### End netgrowl
  96. ###
  97. # Actual plugin
  98. # config: str: ip; str: password;
  99. def notify(pdata, notif_type, title, message):
  100. p = GrowlNotificationPacket (application=pdata['app'], notification=notif_type,
  101. title=title, description=message, priority=1,
  102. sticky=True, password=pdata['config']['password'])
  103. pdata['socket'].sendto (p.payload (), pdata['addr'])
  104. def new_entry (pdata, dl, item): # not of interest for this plugin, but needs to be implemented
  105. pass
  106. def download_complete (pdata, dl, item):
  107. notify (pdata, "Download Complete", 'Download Complete', item['title'])
  108. def download_started (pdata, dl, item):
  109. notify (pdata, "Download Started", 'Download Started', item['title'])
  110. def download_update (pdata, dl, downloaded, length, item):
  111. pass
  112. def download_error (pdata, dl, error, item):
  113. pass
  114. def init (pdata):
  115. pdata['app'] = 'river'
  116. pdata['addr'] = (pdata['config']['ip'], GROWL_UDP_PORT)
  117. pdata['socket'] = socket (AF_INET, SOCK_DGRAM)
  118. p = GrowlRegistrationPacket (application=pdata['app'], password=pdata['config']['password'])
  119. p.addNotification ("Download Started", enabled=True)
  120. p.addNotification ("Download Complete", enabled=True)
  121. pdata['socket'].sendto (p.payload (), pdata['addr'])
  122. print 'Loaded growl plugin'
  123. def shutdown (pdata):
  124. pdata['socket'].close ()
  125. print 'Unloaded growl plugin'