Moved notifications to plugins (including sound)
This commit is contained in:
parent
24a9dc3b37
commit
ef8f40ccc4
11
setup.py
11
setup.py
|
@ -254,7 +254,9 @@ if __name__ == "__main__":
|
|||
install_requires=installRequires,
|
||||
extras_require={
|
||||
'qrcode': ['qrcode'],
|
||||
'pyopencl': ['pyopencl']
|
||||
'pyopencl': ['pyopencl'],
|
||||
'notify2': ['pygobject', 'notify2'],
|
||||
'sound:platform_system=="Windows"': ['winsound']
|
||||
},
|
||||
classifiers=[
|
||||
"License :: OSI Approved :: MIT License"
|
||||
|
@ -278,6 +280,13 @@ if __name__ == "__main__":
|
|||
'popMenuYourIdentities.qrcode = '
|
||||
'pybitmessage.plugins.qrcodeui [qrcode]'
|
||||
],
|
||||
'notification.message': [
|
||||
'notify2 = pybitmessage.plugins.notification_notify2'
|
||||
'[notify2]'
|
||||
],
|
||||
'notification.sound': [
|
||||
'fallback = pybitmessage.plugins.sound_playfile [sound]'
|
||||
],
|
||||
# 'console_scripts': [
|
||||
# 'pybitmessage = pybitmessage.bitmessagemain:main'
|
||||
# ]
|
||||
|
|
|
@ -4,8 +4,6 @@ try:
|
|||
import gi
|
||||
gi.require_version('MessagingMenu', '1.0')
|
||||
from gi.repository import MessagingMenu
|
||||
gi.require_version('Notify', '0.7')
|
||||
from gi.repository import Notify
|
||||
withMessagingMenu = True
|
||||
except (ImportError, ValueError):
|
||||
MessagingMenu = None
|
||||
|
@ -62,9 +60,8 @@ import platform
|
|||
import textwrap
|
||||
import debug
|
||||
import random
|
||||
import subprocess
|
||||
import string
|
||||
import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from helper_sql import *
|
||||
import helper_search
|
||||
import l10n
|
||||
|
@ -153,7 +150,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
SOUND_CONNECTION_GREEN = 5
|
||||
|
||||
# the last time that a message arrival sound was played
|
||||
lastSoundTime = datetime.datetime.now() - datetime.timedelta(days=1)
|
||||
lastSoundTime = datetime.now() - timedelta(days=1)
|
||||
|
||||
# the maximum frequency of message sounds in seconds
|
||||
maxSoundFrequencySec = 60
|
||||
|
@ -1368,39 +1365,41 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# returns true if the given sound category is a connection sound
|
||||
# rather than a received message sound
|
||||
def isConnectionSound(self, category):
|
||||
if (category is self.SOUND_CONNECTED or
|
||||
category is self.SOUND_DISCONNECTED or
|
||||
category is self.SOUND_CONNECTION_GREEN):
|
||||
return True
|
||||
return False
|
||||
return category in (
|
||||
self.SOUND_CONNECTED,
|
||||
self.SOUND_DISCONNECTED,
|
||||
self.SOUND_CONNECTION_GREEN
|
||||
)
|
||||
|
||||
# play a sound
|
||||
def playSound(self, category, label):
|
||||
# filename of the sound to be played
|
||||
soundFilename = None
|
||||
|
||||
# whether to play a sound or not
|
||||
play = True
|
||||
def _choose_ext(basename):
|
||||
for ext in ('.wav', '.mp3', '.oga'):
|
||||
if os.path.isfile(basename + ext):
|
||||
return ext
|
||||
|
||||
# if the address had a known label in the address book
|
||||
if label is not None:
|
||||
if label:
|
||||
# Does a sound file exist for this particular contact?
|
||||
if (os.path.isfile(state.appdata + 'sounds/' + label + '.wav') or
|
||||
os.path.isfile(state.appdata + 'sounds/' + label + '.mp3')):
|
||||
soundFilename = state.appdata + 'sounds/' + label
|
||||
ext = _choose_ext(soundFilename)
|
||||
if not ext:
|
||||
soundFilename = None
|
||||
|
||||
if soundFilename is None:
|
||||
# Avoid making sounds more frequently than the threshold.
|
||||
# This suppresses playing sounds repeatedly when there
|
||||
# are many new messages
|
||||
if (soundFilename is None and
|
||||
not self.isConnectionSound(category)):
|
||||
if not self.isConnectionSound(category):
|
||||
# elapsed time since the last sound was played
|
||||
dt = datetime.datetime.now() - self.lastSoundTime
|
||||
dt = datetime.now() - self.lastSoundTime
|
||||
# suppress sounds which are more frequent than the threshold
|
||||
if dt.total_seconds() < self.maxSoundFrequencySec:
|
||||
play = False
|
||||
return
|
||||
|
||||
if soundFilename is None:
|
||||
# the sound is for an address which exists in the address book
|
||||
if category is self.SOUND_KNOWN:
|
||||
soundFilename = state.appdata + 'sounds/known'
|
||||
|
@ -1417,73 +1416,53 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
elif category is self.SOUND_CONNECTION_GREEN:
|
||||
soundFilename = state.appdata + 'sounds/green'
|
||||
|
||||
if soundFilename is not None and play is True:
|
||||
if soundFilename is None:
|
||||
return
|
||||
|
||||
if not self.isConnectionSound(category):
|
||||
# record the last time that a received message sound was played
|
||||
self.lastSoundTime = datetime.datetime.now()
|
||||
self.lastSoundTime = datetime.now()
|
||||
|
||||
# if not wav then try mp3 format
|
||||
if not os.path.isfile(soundFilename + '.wav'):
|
||||
soundFilename = soundFilename + '.mp3'
|
||||
else:
|
||||
soundFilename = soundFilename + '.wav'
|
||||
try: # try already known format
|
||||
soundFilename += ext
|
||||
except (TypeError, NameError):
|
||||
ext = _choose_ext(soundFilename)
|
||||
if not ext:
|
||||
return
|
||||
|
||||
if os.path.isfile(soundFilename):
|
||||
if 'linux' in sys.platform:
|
||||
# Note: QSound was a nice idea but it didn't work
|
||||
if '.mp3' in soundFilename:
|
||||
gst_available=False
|
||||
try:
|
||||
subprocess.call(["gst123", soundFilename],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE)
|
||||
gst_available=True
|
||||
except:
|
||||
logger.warning("WARNING: gst123 must be installed in order to play mp3 sounds")
|
||||
if not gst_available:
|
||||
try:
|
||||
subprocess.call(["mpg123", soundFilename],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE)
|
||||
gst_available=True
|
||||
except:
|
||||
logger.warning("WARNING: mpg123 must be installed in order to play mp3 sounds")
|
||||
else:
|
||||
try:
|
||||
subprocess.call(["aplay", soundFilename],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE)
|
||||
except:
|
||||
logger.warning("WARNING: aplay must be installed in order to play WAV sounds")
|
||||
elif sys.platform[0:3] == 'win':
|
||||
# use winsound on Windows
|
||||
import winsound
|
||||
winsound.PlaySound(soundFilename, winsound.SND_FILENAME)
|
||||
soundFilename += ext
|
||||
|
||||
self._player(soundFilename)
|
||||
|
||||
# initialise the message notifier
|
||||
def notifierInit(self):
|
||||
if withMessagingMenu:
|
||||
Notify.init('pybitmessage')
|
||||
|
||||
# shows a notification
|
||||
def notifierShow(self, title, subtitle, fromCategory, label):
|
||||
self.playSound(fromCategory, label)
|
||||
|
||||
if withMessagingMenu:
|
||||
n = Notify.Notification.new(
|
||||
title, subtitle, 'notification-message-email')
|
||||
try:
|
||||
n.show()
|
||||
except:
|
||||
# n.show() has been known to throw this exception:
|
||||
# gi._glib.GError: GDBus.Error:org.freedesktop.Notifications.
|
||||
# MaxNotificationsExceeded: Exceeded maximum number of
|
||||
# notifications
|
||||
pass
|
||||
return
|
||||
else:
|
||||
def _simple_notify(
|
||||
title, subtitle, category, label=None, icon=None):
|
||||
self.tray.showMessage(title, subtitle, 1, 2000)
|
||||
|
||||
self._notifier = _simple_notify
|
||||
self._player = QtGui.QSound.play
|
||||
|
||||
if not get_plugins:
|
||||
return
|
||||
|
||||
for plugin in get_plugins('notification.message'):
|
||||
self._notifier = plugin
|
||||
break
|
||||
|
||||
if not QtGui.QSound.isAvailable():
|
||||
for plugin in get_plugins('notification.sound'):
|
||||
self._player = plugin
|
||||
break
|
||||
else:
|
||||
logger.warning("No sound player plugin found!")
|
||||
|
||||
def notifierShow(
|
||||
self, title, subtitle, category, label=None, icon=None):
|
||||
self.playSound(category, label)
|
||||
self._notifier(
|
||||
unicode(title), unicode(subtitle), category, label, icon)
|
||||
|
||||
# tree
|
||||
def treeWidgetKeyPressEvent(self, event):
|
||||
return self.handleKeyPress(event, self.getCurrentTreeWidget())
|
||||
|
@ -1663,15 +1642,18 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
def setStatusIcon(self, color):
|
||||
# print 'setting status icon color'
|
||||
_notifications_enabled = not BMConfigParser().getboolean(
|
||||
'bitmessagesettings', 'hidetrayconnectionnotifications')
|
||||
if color == 'red':
|
||||
self.pushButtonStatusIcon.setIcon(
|
||||
QIcon(":/newPrefix/images/redicon.png"))
|
||||
shared.statusIconColor = 'red'
|
||||
# if the connection is lost then show a notification
|
||||
if self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'):
|
||||
self.notifierShow('Bitmessage', unicode(_translate(
|
||||
"MainWindow", "Connection lost").toUtf8(),'utf-8'),
|
||||
self.SOUND_DISCONNECTED, None)
|
||||
if self.connected and _notifications_enabled:
|
||||
self.notifierShow(
|
||||
'Bitmessage',
|
||||
_translate("MainWindow", "Connection lost"),
|
||||
self.SOUND_DISCONNECTED)
|
||||
if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and \
|
||||
BMConfigParser().get('bitmessagesettings', 'socksproxytype') == "none":
|
||||
self.statusBar().showMessage(_translate(
|
||||
|
@ -1689,10 +1671,11 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
":/newPrefix/images/yellowicon.png"))
|
||||
shared.statusIconColor = 'yellow'
|
||||
# if a new connection has been established then show a notification
|
||||
if not self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'):
|
||||
self.notifierShow('Bitmessage', unicode(_translate(
|
||||
"MainWindow", "Connected").toUtf8(),'utf-8'),
|
||||
self.SOUND_CONNECTED, None)
|
||||
if not self.connected and _notifications_enabled:
|
||||
self.notifierShow(
|
||||
'Bitmessage',
|
||||
_translate("MainWindow", "Connected"),
|
||||
self.SOUND_CONNECTED)
|
||||
self.connected = True
|
||||
|
||||
if self.actionStatus is not None:
|
||||
|
@ -1705,10 +1688,11 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.pushButtonStatusIcon.setIcon(
|
||||
QIcon(":/newPrefix/images/greenicon.png"))
|
||||
shared.statusIconColor = 'green'
|
||||
if not self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'):
|
||||
self.notifierShow('Bitmessage', unicode(_translate(
|
||||
"MainWindow", "Connected").toUtf8(),'utf-8'),
|
||||
self.SOUND_CONNECTION_GREEN, None)
|
||||
if not self.connected and _notifications_enabled:
|
||||
self.notifierShow(
|
||||
'Bitmessage',
|
||||
_translate("MainWindow", "Connected"),
|
||||
self.SOUND_CONNECTION_GREEN)
|
||||
self.connected = True
|
||||
|
||||
if self.actionStatus is not None:
|
||||
|
@ -2253,8 +2237,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
else:
|
||||
acct = ret
|
||||
self.propagateUnreadCount(acct.address)
|
||||
if BMConfigParser().getboolean('bitmessagesettings', 'showtraynotifications'):
|
||||
self.notifierShow(unicode(_translate("MainWindow",'New Message').toUtf8(),'utf-8'), unicode(_translate("MainWindow",'From ').toUtf8(),'utf-8') + unicode(acct.fromLabel, 'utf-8'), self.SOUND_UNKNOWN, None)
|
||||
if BMConfigParser().getboolean(
|
||||
'bitmessagesettings', 'showtraynotifications'):
|
||||
self.notifierShow(
|
||||
_translate("MainWindow", "New Message"),
|
||||
_translate("MainWindow", "From %1").arg(
|
||||
unicode(acct.fromLabel, 'utf-8')),
|
||||
self.SOUND_UNKNOWN
|
||||
)
|
||||
if self.getCurrentAccount() is not None and ((self.getCurrentFolder(treeWidget) != "inbox" and self.getCurrentFolder(treeWidget) is not None) or self.getCurrentAccount(treeWidget) != acct.address):
|
||||
# Ubuntu should notify of new message irespective of whether it's in current message list or not
|
||||
self.ubuntuMessagingMenuUpdate(True, None, acct.toLabel)
|
||||
|
|
13
src/plugins/notification_notify2.py
Normal file
13
src/plugins/notification_notify2.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import gi
|
||||
gi.require_version('Notify', '0.7')
|
||||
from gi.repository import Notify
|
||||
|
||||
Notify.init('pybitmessage')
|
||||
|
||||
|
||||
def connect_plugin(title, subtitle, category, label, icon):
|
||||
if not icon:
|
||||
icon = 'mail-message-new' if category == 2 else 'pybitmessage'
|
||||
Notify.Notification.new(title, subtitle, icon).show()
|
|
@ -3,10 +3,12 @@
|
|||
import pkg_resources
|
||||
|
||||
|
||||
def get_plugins(group, point, name=None):
|
||||
def get_plugins(group, point='', name=None):
|
||||
for plugin in pkg_resources.iter_entry_points(group):
|
||||
if plugin.name.startswith(point):
|
||||
if plugin.name == name or plugin.name.startswith(point):
|
||||
try:
|
||||
yield plugin.load().connect_plugin
|
||||
except (AttributeError, pkg_resources.DistributionNotFound):
|
||||
except (AttributeError,
|
||||
pkg_resources.DistributionNotFound,
|
||||
pkg_resources.UnknownExtra):
|
||||
continue
|
||||
|
|
37
src/plugins/sound_playfile.py
Normal file
37
src/plugins/sound_playfile.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
try:
|
||||
import winsound
|
||||
|
||||
def connect_plugin(sound_file):
|
||||
winsound.PlaySound(sound_file, winsound.SND_FILENAME)
|
||||
except ImportError:
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
play_cmd = {}
|
||||
|
||||
def connect_plugin(sound_file):
|
||||
global play_cmd
|
||||
|
||||
ext = os.path.splitext(sound_file)[-1]
|
||||
try:
|
||||
subprocess.call([play_cmd[ext], sound_file])
|
||||
return
|
||||
except (KeyError, AttributeError):
|
||||
pass
|
||||
|
||||
programs = ['gst123']
|
||||
if ext == '.wav':
|
||||
programs.append('aplay')
|
||||
elif ext == '.mp3':
|
||||
programs += ['mpg123', 'mpg321', 'mpg321-mpg123']
|
||||
for cmd in programs:
|
||||
try:
|
||||
subprocess.call([cmd, sound_file])
|
||||
except OSError:
|
||||
pass # log here!
|
||||
else:
|
||||
play_cmd[ext] = cmd
|
||||
break
|
Loading…
Reference in New Issue
Block a user