Merge branch 'main' of ssh://code.freedombone.net:2222/bashrc/epicyon into main

main
Bob Mottram 2021-03-03 19:37:06 +00:00
commit 3d8a91e9c8
4 changed files with 132 additions and 108 deletions

View File

@ -10,12 +10,7 @@ import json
import os
import datetime
import time
import html
import urllib.parse
from linked_data_sig import verifyJsonSignature
from utils import getDisplayName
from utils import getGenderFromBio
from utils import removeHtml
from utils import getConfigParam
from utils import hasUsersPath
from utils import validPostDate
@ -82,11 +77,7 @@ from happening import saveEventPost
from delete import removeOldHashtags
from categories import guessHashtagCategory
from context import hasValidContext
from content import htmlReplaceQuoteMarks
from speaker import speakerReplaceLinks
from speaker import speakerPronounce
from speaker import speakerEndpointJson
from speaker import removeEmojiFromText
from speaker import updateSpeaker
def storeHashTags(baseDir: str, nickname: str, postJsonObject: {}) -> None:
@ -1414,7 +1405,7 @@ def _receiveAnnounce(recentPostsCache: {},
lookupActor = lookupActor.split('/statuses/')[0]
if not os.path.isfile(postFilename + '.tts'):
_updateSpeaker(baseDir, nickname, domain,
updateSpeaker(baseDir, nickname, domain,
postJsonObject, personCache,
translate, lookupActor)
ttsFile = open(postFilename + '.tts', "w+")
@ -2155,68 +2146,6 @@ def _bounceDM(senderPostId: str, session, httpPrefix: str,
return True
def _updateSpeaker(baseDir: str, nickname: str, domain: str,
postJsonObject: {}, personCache: {},
translate: {}, announcingActor: str) -> None:
""" Generates a json file which can be used for TTS announcement
of incoming inbox posts
"""
if not postJsonObject.get('object'):
return
if not isinstance(postJsonObject['object'], dict):
return
if not postJsonObject['object'].get('content'):
return
if not isinstance(postJsonObject['object']['content'], str):
return
speakerFilename = \
baseDir + '/accounts/' + nickname + '@' + domain + '/speaker.json'
detectedLinks = []
content = urllib.parse.unquote_plus(postJsonObject['object']['content'])
content = html.unescape(content)
content = content.replace('<p>', '').replace('</p>', ' ')
content = removeHtml(htmlReplaceQuoteMarks(content))
content = speakerReplaceLinks(content, translate, detectedLinks)
content = speakerPronounce(baseDir, content, translate)
imageDescription = ''
if postJsonObject['object'].get('attachment'):
attachList = postJsonObject['object']['attachment']
if isinstance(attachList, list):
for img in attachList:
if not isinstance(img, dict):
continue
if img.get('name'):
if isinstance(img['name'], str):
imageDescription += \
img['name'] + '. '
summary = ''
if postJsonObject['object'].get('summary'):
if isinstance(postJsonObject['object']['summary'], str):
summary = \
urllib.parse.unquote_plus(postJsonObject['object']['summary'])
summary = html.unescape(summary)
speakerName = \
getDisplayName(baseDir, postJsonObject['actor'], personCache)
if not speakerName:
return
speakerName = removeEmojiFromText(speakerName)
gender = getGenderFromBio(baseDir, postJsonObject['actor'],
personCache, translate)
if announcingActor:
announcedNickname = getNicknameFromActor(announcingActor)
announcedDomain = getDomainFromActor(announcingActor)
announcedHandle = announcedNickname + '@' + announcedDomain
content = \
translate['announces'] + ' ' + announcedHandle + '. ' + content
speakerJson = speakerEndpointJson(speakerName, summary,
content, imageDescription,
detectedLinks, gender)
saveJson(speakerJson, speakerFilename)
def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
session, keyId: str, handle: str, messageJson: {},
baseDir: str, httpPrefix: str, sendThreads: [],
@ -2552,7 +2481,7 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
print('ERROR: unable to update ' + boxname + ' index')
else:
if boxname == 'inbox':
_updateSpeaker(baseDir, nickname, domain,
updateSpeaker(baseDir, nickname, domain,
postJsonObject, personCache,
translate, None)
if not unitTest:

View File

@ -7,11 +7,20 @@ __email__ = "bob@freedombone.net"
__status__ = "Production"
import os
import html
import random
import urllib.parse
from auth import createBasicAuthHeader
from session import getJson
from utils import getDomainFromActor
from utils import getNicknameFromActor
from utils import getGenderFromBio
from utils import getDisplayName
from utils import removeHtml
from utils import loadJson
from utils import saveJson
from utils import getFullDomain
from content import htmlReplaceQuoteMarks
speakerRemoveChars = ('.\n', '. ', ',', ';', '?', '!')
@ -52,13 +61,15 @@ def getSpeakerRange(displayName: str) -> int:
return random.randint(300, 800)
def speakerPronounce(baseDir: str, sayText: str, translate: {}) -> str:
def _speakerPronounce(baseDir: str, sayText: str, translate: {}) -> str:
"""Screen readers may not always pronounce correctly, so you
can have a file which specifies conversions. File should contain
line items such as:
Epicyon -> Epi-cyon
"""
pronounceFilename = baseDir + '/accounts/speaker_pronounce.txt'
convertDict = {}
if translate:
convertDict = {
"Epicyon": "Epi-cyon",
"espeak": "e-speak",
@ -115,7 +126,10 @@ def speakerReplaceLinks(sayText: str, translate: {},
text = text.replace(ch, ' ')
replacements = {}
wordsList = text.split(' ')
if translate.get('Linked'):
linkedStr = translate['Linked']
else:
linkedStr = 'Linked'
prevWord = ''
for word in wordsList:
if word.startswith(':'):
@ -124,6 +138,7 @@ def speakerReplaceLinks(sayText: str, translate: {},
continue
# replace mentions, but not re-tweets
if word.startswith('@') and not prevWord.endswith('RT'):
if translate.get('mentioning'):
replacements[word] = \
translate['mentioning'] + ' ' + word[1:] + ','
prevWord = word
@ -171,7 +186,7 @@ def _addSSMLemphasis(sayText: str) -> str:
return sayText
def removeEmojiFromText(sayText: str) -> str:
def _removeEmojiFromText(sayText: str) -> str:
"""Removes :emoji: from the given text
"""
if '*' not in sayText:
@ -222,7 +237,7 @@ def getSpeakerFromServer(baseDir: str, session,
return speakerJson
def speakerEndpointJson(displayName: str, summary: str,
def _speakerEndpointJson(displayName: str, summary: str,
content: str, imageDescription: str,
links: [], gender: str) -> {}:
"""Returns a json endpoint for the TTS speaker
@ -312,3 +327,66 @@ def getSSMLbox(baseDir: str, path: str,
speakerJson['detectedLinks'],
systemLanguage,
instanceTitle, gender)
def updateSpeaker(baseDir: str, nickname: str, domain: str,
postJsonObject: {}, personCache: {},
translate: {}, announcingActor: str) -> None:
""" Generates a json file which can be used for TTS announcement
of incoming inbox posts
"""
if not postJsonObject.get('object'):
return
if not isinstance(postJsonObject['object'], dict):
return
if not postJsonObject['object'].get('content'):
return
if not isinstance(postJsonObject['object']['content'], str):
return
speakerFilename = \
baseDir + '/accounts/' + nickname + '@' + domain + '/speaker.json'
detectedLinks = []
content = urllib.parse.unquote_plus(postJsonObject['object']['content'])
content = html.unescape(content)
content = content.replace('<p>', '').replace('</p>', ' ')
content = removeHtml(htmlReplaceQuoteMarks(content))
content = speakerReplaceLinks(content, translate, detectedLinks)
content = _speakerPronounce(baseDir, content, translate)
imageDescription = ''
if postJsonObject['object'].get('attachment'):
attachList = postJsonObject['object']['attachment']
if isinstance(attachList, list):
for img in attachList:
if not isinstance(img, dict):
continue
if img.get('name'):
if isinstance(img['name'], str):
imageDescription += \
img['name'] + '. '
summary = ''
if postJsonObject['object'].get('summary'):
if isinstance(postJsonObject['object']['summary'], str):
summary = \
urllib.parse.unquote_plus(postJsonObject['object']['summary'])
summary = html.unescape(summary)
speakerName = \
getDisplayName(baseDir, postJsonObject['actor'], personCache)
if not speakerName:
return
speakerName = _removeEmojiFromText(speakerName)
gender = getGenderFromBio(baseDir, postJsonObject['actor'],
personCache, translate)
if announcingActor:
announcedNickname = getNicknameFromActor(announcingActor)
announcedDomain, announcedport = getDomainFromActor(announcingActor)
if announcedNickname and announcedDomain:
announcedHandle = announcedNickname + '@' + announcedDomain
content = \
translate['announces'] + ' ' + announcedHandle + '. ' + content
speakerJson = _speakerEndpointJson(speakerName, summary,
content, imageDescription,
detectedLinks, gender)
saveJson(speakerJson, speakerFilename)

View File

@ -678,7 +678,10 @@ def getGenderFromBio(baseDir: str, actor: str, personCache: {},
if not personCache.get(actor):
return None
bioFound = None
if translate:
pronounStr = translate['pronoun'].lower()
else:
pronounStr = 'pronoun'
if personCache[actor].get('actor'):
# is gender defined as a profile tag?
if personCache[actor]['actor'].get('attachment'):

View File

@ -63,6 +63,7 @@ from webapp_media import addEmbeddedElements
from webapp_question import insertQuestion
from devices import E2EEdecryptMessageFromDevice
from webfinger import webfingerHandle
from speaker import updateSpeaker
def _logPostTiming(enableTimingLog: bool, postStartTime, debugId: str) -> None:
@ -1290,6 +1291,19 @@ def individualPostAsHtml(allowDownloads: bool,
if not postJsonAnnounce:
return ''
postJsonObject = postJsonAnnounce
announceFilename = \
locatePost(baseDir, nickname, domain, postJsonObject['id'])
if announceFilename and postJsonObject.get('actor'):
if not os.path.isfile(announceFilename + '.tts'):
updateSpeaker(baseDir, nickname, domain,
postJsonObject, personCache,
translate, postJsonObject['actor'])
ttsFile = open(announceFilename + '.tts', "w+")
if ttsFile:
ttsFile.write('\n')
ttsFile.close()
isAnnounced = True
_logPostTiming(enableTimingLog, postStartTime, '8')