epicyon/notifications_client.py

250 lines
10 KiB
Python
Raw Normal View History

__filename__ = "notifications_client.py"
2021-03-04 13:57:30 +00:00
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.2.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
import os
import html
import time
2021-03-04 15:21:38 +00:00
import sys
import select
2021-03-04 13:57:30 +00:00
from session import createSession
from speaker import getSpeakerFromServer
from speaker import getSpeakerPitch
from speaker import getSpeakerRate
from speaker import getSpeakerRange
2021-03-04 14:36:24 +00:00
def _waitForKeypress(timeout: int, debug: bool) -> str:
"""Waits for a keypress with a timeout
Returns the key pressed, or None on timeout
"""
2021-03-04 15:21:38 +00:00
i, o, e = select.select([sys.stdin], [], [], timeout)
if (i):
2021-03-04 15:27:27 +00:00
text = sys.stdin.readline().strip()
2021-03-04 15:21:38 +00:00
if debug:
2021-03-04 15:27:27 +00:00
print("Text entered: " + text)
return text
2021-03-04 15:21:38 +00:00
else:
2021-03-04 14:36:24 +00:00
if debug:
2021-03-04 15:21:38 +00:00
print("Timeout")
2021-03-04 14:36:24 +00:00
return None
2021-03-04 13:57:30 +00:00
2021-03-04 14:54:30 +00:00
def _speakerEspeak(espeak, pitch: int, rate: int, srange: int,
sayText: str) -> None:
"""Speaks the given text with espeak
"""
espeak.set_parameter(espeak.Parameter.Pitch, pitch)
espeak.set_parameter(espeak.Parameter.Rate, rate)
espeak.set_parameter(espeak.Parameter.Range, srange)
espeak.synth(html.unescape(sayText))
def _speakerPicospeaker(pitch: int, rate: int, systemLanguage: str,
sayText: str) -> None:
speakerLang = 'en-GB'
if systemLanguage:
if systemLanguage.startswith('fr'):
speakerLang = 'fr-FR'
elif systemLanguage.startswith('es'):
speakerLang = 'es-ES'
elif systemLanguage.startswith('de'):
speakerLang = 'de-DE'
elif systemLanguage.startswith('it'):
speakerLang = 'it-IT'
speakerCmd = 'picospeaker ' + \
'-l ' + speakerLang + \
' -r ' + str(rate) + \
' -p ' + str(pitch) + ' "' + \
html.unescape(sayText) + '"'
# print(speakerCmd)
os.system(speakerCmd)
2021-03-09 19:52:10 +00:00
def _playNotificationSound(soundFilename: str, player='ffplay') -> None:
"""Plays a sound
"""
if not os.path.isfile(soundFilename):
return
if player == 'ffplay':
os.system('ffplay ' + soundFilename +
' -autoexit -hide_banner -nodisp')
2021-03-09 20:32:50 +00:00
def _desktopNotification(notificationType: str,
2021-03-09 21:23:32 +00:00
title: str, message: str) -> None:
2021-03-09 20:32:50 +00:00
"""Shows a desktop notification
"""
if not notificationType:
return
if notificationType == 'notify-send':
# Ubuntu
os.system('notify-send "' + title + '" "' + message + '"')
elif notificationType == 'osascript':
# Mac
os.system("osascript -e 'display notification \"" +
message + "\" with title \"" + title + "\"'")
elif notificationType == 'New-BurntToastNotification':
# Windows
os.system("New-BurntToastNotification -Text \"" +
title + "\", '" + message + "'")
def runNotificationsClient(baseDir: str, proxyType: str, httpPrefix: str,
nickname: str, domain: str, port: int,
password: str, screenreader: str,
systemLanguage: str, debug: bool) -> None:
"""Runs the notifications and screen reader client,
which announces new inbox items
2021-03-04 13:57:30 +00:00
"""
2021-03-09 19:52:10 +00:00
if screenreader:
if screenreader == 'espeak':
print('Setting up espeak')
from espeak import espeak
elif screenreader != 'picospeaker':
print(screenreader + ' is not a supported TTS system')
return
2021-03-04 13:57:30 +00:00
2021-03-09 19:52:10 +00:00
print('Running ' + screenreader + ' for ' + nickname + '@' + domain)
2021-03-04 13:57:30 +00:00
prevSay = ''
2021-03-09 19:52:10 +00:00
prevDM = False
prevReply = False
prevCalendar = False
prevFollow = False
prevLike = ''
prevShare = False
dmSoundFilename = 'dm.ogg'
replySoundFilename = 'reply.ogg'
calendarSoundFilename = 'calendar.ogg'
followSoundFilename = 'follow.ogg'
likeSoundFilename = 'like.ogg'
shareSoundFilename = 'share.ogg'
player = 'ffplay'
2021-03-09 20:32:50 +00:00
notificationType = 'notify-send'
instanceTitle = 'Epicyon'
2021-03-04 13:57:30 +00:00
while (1):
session = createSession(proxyType)
speakerJson = \
getSpeakerFromServer(baseDir, session, nickname, password,
domain, port, httpPrefix, True, __version__)
if speakerJson:
2021-03-09 19:52:10 +00:00
if speakerJson.get('notify'):
soundsDir = 'theme/default/sounds'
if speakerJson['notify'].get('theme'):
soundsDir = \
'theme/' + speakerJson['notify']['theme'] + '/sounds'
if not os.path.isdir(soundsDir):
soundsDir = 'theme/default/sounds'
if dmSoundFilename:
if speakerJson['notify']['dm'] != prevDM:
_playNotificationSound(soundsDir + '/' +
dmSoundFilename, player)
2021-03-09 20:32:50 +00:00
_desktopNotification(notificationType,
instanceTitle,
'New direct message')
2021-03-09 19:52:10 +00:00
elif replySoundFilename:
if speakerJson['notify']['reply'] != prevReply:
_playNotificationSound(soundsDir + '/' +
replySoundFilename, player)
2021-03-09 20:32:50 +00:00
_desktopNotification(notificationType,
instanceTitle,
'New reply')
2021-03-09 19:52:10 +00:00
elif calendarSoundFilename:
if speakerJson['notify']['calendar'] != prevCalendar:
_playNotificationSound(soundsDir + '/' +
calendarSoundFilename, player)
2021-03-09 20:32:50 +00:00
_desktopNotification(notificationType,
instanceTitle,
'New calendar event')
2021-03-09 19:52:10 +00:00
elif followSoundFilename:
if speakerJson['notify']['followRequests'] != prevFollow:
_playNotificationSound(soundsDir + '/' +
followSoundFilename, player)
2021-03-09 20:32:50 +00:00
_desktopNotification(notificationType,
instanceTitle,
'New follow request')
2021-03-09 19:52:10 +00:00
elif likeSoundFilename:
2021-03-09 19:59:10 +00:00
if speakerJson['notify']['likedBy'] != prevLike:
2021-03-09 19:52:10 +00:00
_playNotificationSound(soundsDir + '/' +
likeSoundFilename, player)
2021-03-09 20:32:50 +00:00
_desktopNotification(notificationType,
instanceTitle,
'New like')
2021-03-09 19:52:10 +00:00
elif shareSoundFilename:
if speakerJson['notify']['share'] != prevShare:
_playNotificationSound(soundsDir + '/' +
shareSoundFilename, player)
2021-03-09 20:32:50 +00:00
_desktopNotification(notificationType,
instanceTitle,
'New shared item')
2021-03-09 19:52:10 +00:00
prevDM = speakerJson['notify']['dm']
prevReply = speakerJson['notify']['reply']
prevCalendar = speakerJson['notify']['calendar']
prevFollow = speakerJson['notify']['followRequests']
2021-03-09 19:59:10 +00:00
prevLike = speakerJson['notify']['likedBy']
2021-03-09 19:52:10 +00:00
prevShare = speakerJson['notify']['share']
if speakerJson.get('say'):
if speakerJson['say'] != prevSay:
if speakerJson.get('name'):
nameStr = speakerJson['name']
gender = 'They/Them'
if speakerJson.get('gender'):
gender = speakerJson['gender']
# get the speech parameters
pitch = getSpeakerPitch(nameStr, screenreader, gender)
rate = getSpeakerRate(nameStr, screenreader)
srange = getSpeakerRange(nameStr)
# say the speaker's name
if screenreader == 'espeak':
_speakerEspeak(espeak, pitch, rate, srange,
nameStr)
elif screenreader == 'picospeaker':
_speakerPicospeaker(pitch, rate,
systemLanguage, nameStr)
time.sleep(2)
# append image description if needed
if not speakerJson.get('imageDescription'):
sayStr = speakerJson['say']
# echo spoken text to the screen
print(html.unescape(nameStr) + ': ' +
html.unescape(speakerJson['say']) + '\n')
else:
sayStr = speakerJson['say'] + '. ' + \
speakerJson['imageDescription']
# echo spoken text to the screen
imageDescription = \
html.unescape(speakerJson['imageDescription'])
print(html.unescape(nameStr) + ': ' +
html.unescape(speakerJson['say']) + '\n' +
imageDescription)
# speak the post content
if screenreader == 'espeak':
_speakerEspeak(espeak, pitch, rate, srange, sayStr)
elif screenreader == 'picospeaker':
_speakerPicospeaker(pitch, rate,
systemLanguage, sayStr)
prevSay = speakerJson['say']
2021-03-04 13:57:30 +00:00
# wait for a while, or until a key is pressed
2021-03-04 18:05:46 +00:00
keyPress = _waitForKeypress(30, debug)
if keyPress:
if keyPress.startswith('/'):
keyPress = keyPress[1:]
if keyPress == 'q' or keyPress == 'quit' or keyPress == 'exit':
break