From 50ec0f6ce29673ffa8435f4d5b6165a1240cd05d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 3 Mar 2021 19:06:18 +0000 Subject: [PATCH 1/7] Tidying --- inbox.py | 85 +++++------------------------------------------------- speaker.py | 81 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 83 deletions(-) diff --git a/inbox.py b/inbox.py index fa72339c5..b47ec94e3 100644 --- a/inbox.py +++ b/inbox.py @@ -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,9 +1405,9 @@ def _receiveAnnounce(recentPostsCache: {}, lookupActor = lookupActor.split('/statuses/')[0] if not os.path.isfile(postFilename + '.tts'): - _updateSpeaker(baseDir, nickname, domain, - postJsonObject, personCache, - translate, lookupActor) + updateSpeaker(baseDir, nickname, domain, + postJsonObject, personCache, + translate, lookupActor) ttsFile = open(postFilename + '.tts', "w+") if ttsFile: ttsFile.write('\n') @@ -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('

', '').replace('

', ' ') - 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,9 +2481,9 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, print('ERROR: unable to update ' + boxname + ' index') else: if boxname == 'inbox': - _updateSpeaker(baseDir, nickname, domain, - postJsonObject, personCache, - translate, None) + updateSpeaker(baseDir, nickname, domain, + postJsonObject, personCache, + translate, None) if not unitTest: if debug: print('Saving inbox post as html to cache') diff --git a/speaker.py b/speaker.py index 284938427..062c0b72f 100644 --- a/speaker.py +++ b/speaker.py @@ -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,7 +61,7 @@ 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: @@ -171,7 +180,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,9 +231,9 @@ def getSpeakerFromServer(baseDir: str, session, return speakerJson -def speakerEndpointJson(displayName: str, summary: str, - content: str, imageDescription: str, - links: [], gender: str) -> {}: +def _speakerEndpointJson(displayName: str, summary: str, + content: str, imageDescription: str, + links: [], gender: str) -> {}: """Returns a json endpoint for the TTS speaker """ speakerJson = { @@ -312,3 +321,65 @@ 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('

', '').replace('

', ' ') + 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) From 76314d55b60a93a97ac3b790e2ad636d0817ada7 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 3 Mar 2021 19:15:32 +0000 Subject: [PATCH 2/7] Fix unit tests --- speaker.py | 54 ++++++++++++++++++++++++++++++------------------------ utils.py | 5 ++++- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/speaker.py b/speaker.py index 062c0b72f..cf66c55a3 100644 --- a/speaker.py +++ b/speaker.py @@ -68,27 +68,29 @@ def _speakerPronounce(baseDir: str, sayText: str, translate: {}) -> str: Epicyon -> Epi-cyon """ pronounceFilename = baseDir + '/accounts/speaker_pronounce.txt' - convertDict = { - "Epicyon": "Epi-cyon", - "espeak": "e-speak", - "emoji": "emowji", - "clearnet": "clear-net", - "https": "H-T-T-P-S", - "HTTPS": "H-T-T-P-S", - "Tor": "Toor", - "🤔": ". " + translate["thinking emoji"], - "RT @": "Re-Tweet ", - "#": translate["hashtag"], - ":D": '. ' + translate["laughing"], - ":-D": '. ' + translate["laughing"], - ":)": '. ' + translate["smile"], - ";)": '. ' + translate["wink"], - ":(": '. ' + translate["sad face"], - ":-)": '. ' + translate["smile"], - ":-(": '. ' + translate["sad face"], - ";-)": '. ' + translate["wink"], - "*": "" - } + convertDict = {} + if translate: + convertDict = { + "Epicyon": "Epi-cyon", + "espeak": "e-speak", + "emoji": "emowji", + "clearnet": "clear-net", + "https": "H-T-T-P-S", + "HTTPS": "H-T-T-P-S", + "Tor": "Toor", + "🤔": ". " + translate["thinking emoji"], + "RT @": "Re-Tweet ", + "#": translate["hashtag"], + ":D": '. ' + translate["laughing"], + ":-D": '. ' + translate["laughing"], + ":)": '. ' + translate["smile"], + ";)": '. ' + translate["wink"], + ":(": '. ' + translate["sad face"], + ":-)": '. ' + translate["smile"], + ":-(": '. ' + translate["sad face"], + ";-)": '. ' + translate["wink"], + "*": "" + } if os.path.isfile(pronounceFilename): with open(pronounceFilename, 'r') as fp: pronounceList = fp.readlines() @@ -124,7 +126,10 @@ def speakerReplaceLinks(sayText: str, translate: {}, text = text.replace(ch, ' ') replacements = {} wordsList = text.split(' ') - linkedStr = translate['Linked'] + if translate.get('Linked'): + linkedStr = translate['Linked'] + else: + linkedStr = 'Linked' prevWord = '' for word in wordsList: if word.startswith(':'): @@ -133,8 +138,9 @@ def speakerReplaceLinks(sayText: str, translate: {}, continue # replace mentions, but not re-tweets if word.startswith('@') and not prevWord.endswith('RT'): - replacements[word] = \ - translate['mentioning'] + ' ' + word[1:] + ',' + if translate.get('mentioning'): + replacements[word] = \ + translate['mentioning'] + ' ' + word[1:] + ',' prevWord = word domain = None diff --git a/utils.py b/utils.py index 326f52c18..7460417dc 100644 --- a/utils.py +++ b/utils.py @@ -678,7 +678,10 @@ def getGenderFromBio(baseDir: str, actor: str, personCache: {}, if not personCache.get(actor): return None bioFound = None - pronounStr = translate['pronoun'].lower() + 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'): From 6b6304b59519b1571125900cb56534359634abba Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 3 Mar 2021 19:27:29 +0000 Subject: [PATCH 3/7] Extra speaker announce endpoint --- webapp_post.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/webapp_post.py b/webapp_post.py index f66d53a87..a0ba9a96a 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -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') From f963712ba854214d6695827af56ff6c9d062ce94 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 3 Mar 2021 19:31:23 +0000 Subject: [PATCH 4/7] Debug --- speaker.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/speaker.py b/speaker.py index cf66c55a3..aa6f1ba34 100644 --- a/speaker.py +++ b/speaker.py @@ -382,9 +382,12 @@ def updateSpeaker(baseDir: str, nickname: str, domain: str, if announcingActor: announcedNickname = getNicknameFromActor(announcingActor) announcedDomain = getDomainFromActor(announcingActor) - announcedHandle = announcedNickname + '@' + announcedDomain - content = \ - translate['announces'] + ' ' + announcedHandle + '. ' + content + if announcedNickname and announcedDomain: + announcedHandle = announcedNickname + '@' + announcedDomain + content = \ + translate['announces'] + ' ' + announcedHandle + '. ' + content + else: + print('WARN: announcingActor ' + str(announcingActor)) speakerJson = _speakerEndpointJson(speakerName, summary, content, imageDescription, detectedLinks, gender) From abd1afd024532057a7590258b5f89574ae2ae925 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 3 Mar 2021 19:32:49 +0000 Subject: [PATCH 5/7] Debug --- speaker.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/speaker.py b/speaker.py index aa6f1ba34..94eb8e02b 100644 --- a/speaker.py +++ b/speaker.py @@ -383,11 +383,12 @@ def updateSpeaker(baseDir: str, nickname: str, domain: str, announcedNickname = getNicknameFromActor(announcingActor) announcedDomain = getDomainFromActor(announcingActor) if announcedNickname and announcedDomain: + print('WARN: announcingActor ' + str(announcingActor)) announcedHandle = announcedNickname + '@' + announcedDomain content = \ translate['announces'] + ' ' + announcedHandle + '. ' + content else: - print('WARN: announcingActor ' + str(announcingActor)) + print('WARN: announcingActor2 ' + str(announcingActor)) speakerJson = _speakerEndpointJson(speakerName, summary, content, imageDescription, detectedLinks, gender) From c2e76178af37a355e582e9b9d313e6038c0fe19f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 3 Mar 2021 19:34:49 +0000 Subject: [PATCH 6/7] Debug --- speaker.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/speaker.py b/speaker.py index 94eb8e02b..a5d7fb009 100644 --- a/speaker.py +++ b/speaker.py @@ -383,7 +383,8 @@ def updateSpeaker(baseDir: str, nickname: str, domain: str, announcedNickname = getNicknameFromActor(announcingActor) announcedDomain = getDomainFromActor(announcingActor) if announcedNickname and announcedDomain: - print('WARN: announcingActor ' + str(announcingActor)) + print('WARN: announcingActor ' + str(announcingActor) + ' ' + + str(announcedNickname) + ' ' + str(announcedDomain)) announcedHandle = announcedNickname + '@' + announcedDomain content = \ translate['announces'] + ' ' + announcedHandle + '. ' + content From 19a9fe09702217b0a5dcbc9a4673fea6ca80b230 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 3 Mar 2021 19:36:13 +0000 Subject: [PATCH 7/7] Returned port --- speaker.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/speaker.py b/speaker.py index a5d7fb009..126a8a9f6 100644 --- a/speaker.py +++ b/speaker.py @@ -381,15 +381,11 @@ def updateSpeaker(baseDir: str, nickname: str, domain: str, personCache, translate) if announcingActor: announcedNickname = getNicknameFromActor(announcingActor) - announcedDomain = getDomainFromActor(announcingActor) + announcedDomain, announcedport = getDomainFromActor(announcingActor) if announcedNickname and announcedDomain: - print('WARN: announcingActor ' + str(announcingActor) + ' ' + - str(announcedNickname) + ' ' + str(announcedDomain)) announcedHandle = announcedNickname + '@' + announcedDomain content = \ translate['announces'] + ' ' + announcedHandle + '. ' + content - else: - print('WARN: announcingActor2 ' + str(announcingActor)) speakerJson = _speakerEndpointJson(speakerName, summary, content, imageDescription, detectedLinks, gender)