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

main
Bob Mottram 2021-03-25 15:17:24 +00:00
commit e78e368df6
4 changed files with 285 additions and 169 deletions

View File

@ -473,9 +473,11 @@ next Next page in the timeline
prev Previous page in the timeline prev Previous page in the timeline
read [post number] Read a post from a timeline read [post number] Read a post from a timeline
open [post number] Open web links within a timeline post open [post number] Open web links within a timeline post
profile [post number] Show profile for the person who made the given post profile [post number or handle] Show profile for the person who made the given post
following [page number] Show accounts that you are following following [page number] Show accounts that you are following
followers [page number] Show accounts that are following you followers [page number] Show accounts that are following you
approve [handle] Approve a follow request
deny [handle] Deny a follow request
``` ```
If you have a GPG key configured on your local system and are sending a direct message to someone who has a PGP key (the exported key, not just the key ID) set as a tag on their profile then it will try to encrypt the message automatically. So under some conditions end-to-end encryption is possible, such that the instance server only sees ciphertext. Conversely, for arriving direct messages if they are PGP encrypted then the desktop client will try to obtain the relevant public key and decrypt. If you have a GPG key configured on your local system and are sending a direct message to someone who has a PGP key (the exported key, not just the key ID) set as a tag on their profile then it will try to encrypt the message automatically. So under some conditions end-to-end encryption is possible, such that the instance server only sees ciphertext. Conversely, for arriving direct messages if they are PGP encrypted then the desktop client will try to obtain the relevant public key and decrypt.

View File

@ -29,6 +29,8 @@ from speaker import getSpeakerRate
from speaker import getSpeakerRange from speaker import getSpeakerRange
from like import sendLikeViaServer from like import sendLikeViaServer
from like import sendUndoLikeViaServer from like import sendUndoLikeViaServer
from follow import approveFollowRequestViaServer
from follow import denyFollowRequestViaServer
from follow import getFollowRequestsViaServer from follow import getFollowRequestsViaServer
from follow import getFollowingViaServer from follow import getFollowingViaServer
from follow import getFollowersViaServer from follow import getFollowersViaServer
@ -57,9 +59,10 @@ from person import getActorJson
def _desktopHelp() -> None: def _desktopHelp() -> None:
"""Shows help """Shows help
""" """
_desktopClearScreen()
indent = ' ' indent = ' '
print('') print('')
print(indent + 'Commands:') print(indent + _highlightText('Help Commands:'))
print('') print('')
print(indent + 'quit ' + print(indent + 'quit ' +
'Exit from the desktop client') 'Exit from the desktop client')
@ -111,12 +114,16 @@ def _desktopHelp() -> None:
'Read a post from a timeline') 'Read a post from a timeline')
print(indent + 'open [post number] ' + print(indent + 'open [post number] ' +
'Open web links within a timeline post') 'Open web links within a timeline post')
print(indent + 'profile [post number] ' + print(indent + 'profile [post number or handle] ' +
'Show profile for the person who made the given post') 'Show profile for the person who made the given post')
print(indent + 'following [page number] ' + print(indent + 'following [page number] ' +
'Show accounts that you are following') 'Show accounts that you are following')
print(indent + 'followers [page number] ' + print(indent + 'followers [page number] ' +
'Show accounts that are following you') 'Show accounts that are following you')
print(indent + 'approve [handle] ' +
'Approve a follow request')
print(indent + 'deny [handle] ' +
'Deny a follow request')
print('') print('')
@ -322,11 +329,12 @@ def _speakerPicospeaker(pitch: int, rate: int, systemLanguage: str,
speakerLang = 'de-DE' speakerLang = 'de-DE'
elif systemLanguage.startswith('it'): elif systemLanguage.startswith('it'):
speakerLang = 'it-IT' speakerLang = 'it-IT'
sayText = str(sayText).replace('"', "'")
speakerCmd = 'picospeaker ' + \ speakerCmd = 'picospeaker ' + \
'-l ' + speakerLang + \ '-l ' + speakerLang + \
' -r ' + str(rate) + \ ' -r ' + str(rate) + \
' -p ' + str(pitch) + ' "' + \ ' -p ' + str(pitch) + ' "' + \
html.unescape(sayText) + '" 2> /dev/null' html.unescape(str(sayText)) + '" 2> /dev/null'
os.system(speakerCmd) os.system(speakerCmd)
@ -752,13 +760,48 @@ def _readLocalBoxPost(session, nickname: str, domain: str,
return postJsonObject return postJsonObject
def _showProfile(session, nickname: str, domain: str, def _desktopShowActor(baseDir: str, actorJson: {}, translate: {},
httpPrefix: str, baseDir: str, boxName: str, systemLanguage: str, screenreader: str,
pageNumber: int, index: int, boxJson: {}, espeak) -> None:
systemLanguage: str, """Shows information for the given actor
screenreader: str, espeak, """
translate: {}, yourActor: str, actor = actorJson['id']
postJsonObject: {}) -> {}: actorNickname = getNicknameFromActor(actor)
actorDomain, actorPort = getDomainFromActor(actor)
actorDomainFull = getFullDomain(actorDomain, actorPort)
handle = '@' + actorNickname + '@' + actorDomainFull
sayStr = 'Profile for ' + html.unescape(handle)
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
print(actor)
if actorJson.get('movedTo'):
sayStr = 'Moved to ' + html.unescape(actorJson['movedTo'])
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
if actorJson.get('alsoKnownAs'):
alsoKnownAsStr = ''
ctr = 0
for altActor in actorJson['alsoKnownAs']:
if ctr > 0:
alsoKnownAsStr += ', '
ctr += 1
alsoKnownAsStr += altActor
sayStr = 'Also known as ' + html.unescape(alsoKnownAsStr)
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
if actorJson.get('summary'):
sayStr = html.unescape(removeHtml(actorJson['summary']))
sayStr = sayStr.replace('"', "'")
sayStr2 = speakableText(baseDir, sayStr, translate)[0]
_sayCommand(sayStr, sayStr2, screenreader, systemLanguage, espeak)
def _desktopShowProfile(session, nickname: str, domain: str,
httpPrefix: str, baseDir: str, boxName: str,
pageNumber: int, index: int, boxJson: {},
systemLanguage: str,
screenreader: str, espeak,
translate: {}, yourActor: str,
postJsonObject: {}) -> {}:
"""Shows the profile of the actor for the given post """Shows the profile of the actor for the given post
Returns the actor json Returns the actor json
""" """
@ -790,33 +833,26 @@ def _showProfile(session, nickname: str, domain: str,
isHttp = True isHttp = True
actorJson = getActorJson(actor, isHttp, False, False, True) actorJson = getActorJson(actor, isHttp, False, False, True)
actor = actorJson['id'] _desktopShowActor(baseDir, actorJson, translate,
actorNickname = getNicknameFromActor(actor) systemLanguage, screenreader, espeak)
actorDomain, actorPort = getDomainFromActor(actor)
actorDomainFull = getFullDomain(actorDomain, actorPort)
handle = '@' + actorNickname + '@' + actorDomainFull
sayStr = handle return actorJson
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
print(actor)
if actorJson.get('movedTo'):
sayStr = 'Moved to ' + actorJson['movedTo']
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
if actorJson.get('alsoKnownAs'):
alsoKnownAsStr = ''
ctr = 0
for altActor in actorJson['alsoKnownAs']:
if ctr > 0:
alsoKnownAsStr += ', '
ctr += 1
alsoKnownAsStr += altActor
sayStr = 'Also known as ' + alsoKnownAsStr
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak) def _desktopShowProfileFromHandle(session, nickname: str, domain: str,
if actorJson.get('summary'): httpPrefix: str, baseDir: str, boxName: str,
sayStr = removeHtml(actorJson['summary']) handle: str,
sayStr2 = speakableText(baseDir, sayStr, translate) systemLanguage: str,
_sayCommand(sayStr, sayStr2, screenreader, systemLanguage, espeak) screenreader: str, espeak,
translate: {}, yourActor: str,
postJsonObject: {}) -> {}:
"""Shows the profile for a handle
Returns the actor json
"""
actorJson = getActorJson(handle, False, False, False, True)
_desktopShowActor(baseDir, actorJson, translate,
systemLanguage, screenreader, espeak)
return actorJson return actorJson
@ -1045,10 +1081,6 @@ def _desktopShowBox(indent: str,
elif newReplies and boxName != 'tlreplies': elif newReplies and boxName != 'tlreplies':
sayStr += \ sayStr += \
'Use \33[3mshow replies\33[0m to view reply posts.' 'Use \33[3mshow replies\33[0m to view reply posts.'
else:
sayStr += \
'Use the \33[3mnext\33[0m and ' + \
'\33[3mprev\33[0m commands to navigate.'
sayStr2 = sayStr.replace('\33[3m', '').replace('\33[0m', '') sayStr2 = sayStr.replace('\33[3m', '').replace('\33[0m', '')
sayStr2 = sayStr2.replace('show dm', 'show DM') sayStr2 = sayStr2.replace('show dm', 'show DM')
sayStr2 = sayStr2.replace('dm post', 'Direct message post') sayStr2 = sayStr2.replace('dm post', 'Direct message post')
@ -1189,6 +1221,10 @@ def _desktopNewDMbase(session, toHandle: str,
def _desktopShowFollowRequests(followRequestsJson: {}, translate: {}) -> None: def _desktopShowFollowRequests(followRequestsJson: {}, translate: {}) -> None:
"""Shows any follow requests """Shows any follow requests
""" """
if not isinstance(followRequestsJson, dict):
return
if not followRequestsJson.get('orderedItems'):
return
if not followRequestsJson['orderedItems']: if not followRequestsJson['orderedItems']:
return return
indent = ' ' indent = ' '
@ -1209,6 +1245,10 @@ def _desktopShowFollowing(followingJson: {}, translate: {},
followType='following') -> None: followType='following') -> None:
"""Shows a page of accounts followed """Shows a page of accounts followed
""" """
if not isinstance(followingJson, dict):
return
if not followingJson.get('orderedItems'):
return
if not followingJson['orderedItems']: if not followingJson['orderedItems']:
return return
print('') print('')
@ -1521,12 +1561,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
else: else:
postIndexStr = commandStr.split('read ')[1] postIndexStr = commandStr.split('read ')[1]
if boxJson and postIndexStr.isdigit(): if boxJson and postIndexStr.isdigit():
_desktopShowBox(indent, followRequestsJson, _desktopClearScreen()
yourActor, currTimeline, boxJson, _desktopShowBanner()
translate,
screenreader, systemLanguage,
espeak, pageNumber,
newRepliesExist, newDMsExist)
postIndex = int(postIndexStr) postIndex = int(postIndexStr)
postJsonObject = \ postJsonObject = \
_readLocalBoxPost(session, nickname, domain, _readLocalBoxPost(session, nickname, domain,
@ -1534,38 +1570,68 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
pageNumber, postIndex, boxJson, pageNumber, postIndex, boxJson,
systemLanguage, screenreader, systemLanguage, screenreader,
espeak, translate, yourActor) espeak, translate, yourActor)
print('')
sayStr = 'Press Enter to continue...'
sayStr2 = _highlightText(sayStr)
_sayCommand(sayStr2, sayStr,
screenreader, systemLanguage, espeak)
input()
prevTimelineFirstId = ''
refreshTimeline = True
print('') print('')
elif commandStr.startswith('profile ') or commandStr == 'profile': elif commandStr.startswith('profile ') or commandStr == 'profile':
actorJson = None actorJson = None
if commandStr == 'profile': if commandStr == 'profile':
if postJsonObject: if postJsonObject:
actorJson = \ actorJson = \
_showProfile(session, nickname, domain, _desktopShowProfile(session, nickname, domain,
httpPrefix, baseDir, currTimeline, httpPrefix, baseDir,
pageNumber, postIndex, boxJson, currTimeline,
systemLanguage, screenreader, pageNumber, postIndex,
espeak, translate, yourActor, boxJson,
postJsonObject) systemLanguage, screenreader,
espeak, translate, yourActor,
postJsonObject)
else: else:
postIndexStr = '1' postIndexStr = '1'
else: else:
postIndexStr = commandStr.split('profile ')[1] postIndexStr = commandStr.split('profile ')[1]
if not actorJson and boxJson and postIndexStr.isdigit(): if not postIndexStr.isdigit():
_desktopShowBox(indent, followRequestsJson, profileHandle = postIndexStr
yourActor, currTimeline, boxJson, _desktopClearScreen()
translate, _desktopShowBanner()
screenreader, systemLanguage, _desktopShowProfileFromHandle(session, nickname, domain,
espeak, pageNumber, httpPrefix, baseDir,
newRepliesExist, newDMsExist) currTimeline, profileHandle,
systemLanguage, screenreader,
espeak, translate, yourActor,
None)
sayStr = 'Press Enter to continue...'
sayStr2 = _highlightText(sayStr)
_sayCommand(sayStr2, sayStr,
screenreader, systemLanguage, espeak)
input()
prevTimelineFirstId = ''
refreshTimeline = True
elif not actorJson and boxJson:
_desktopClearScreen()
_desktopShowBanner()
postIndex = int(postIndexStr) postIndex = int(postIndexStr)
actorJson = \ actorJson = \
_showProfile(session, nickname, domain, _desktopShowProfile(session, nickname, domain,
httpPrefix, baseDir, currTimeline, httpPrefix, baseDir, currTimeline,
pageNumber, postIndex, boxJson, pageNumber, postIndex, boxJson,
systemLanguage, screenreader, systemLanguage, screenreader,
espeak, translate, yourActor, espeak, translate, yourActor,
None) None)
sayStr = 'Press Enter to continue...'
sayStr2 = _highlightText(sayStr)
_sayCommand(sayStr2, sayStr,
screenreader, systemLanguage, espeak)
input()
prevTimelineFirstId = ''
refreshTimeline = True
print('') print('')
elif commandStr == 'reply' or commandStr == 'r': elif commandStr == 'reply' or commandStr == 'r':
if postJsonObject: if postJsonObject:
@ -2093,6 +2159,70 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
_sayCommand(sayStr, sayStr, _sayCommand(sayStr, sayStr,
screenreader, systemLanguage, espeak) screenreader, systemLanguage, espeak)
print('') print('')
elif commandStr.startswith('approve '):
approveHandle = commandStr.replace('approve ', '').strip()
if approveHandle.startswith('@'):
approveHandle = approveHandle[1:]
if '@' in approveHandle or '://' in approveHandle:
approveNickname = getNicknameFromActor(approveHandle)
approveDomain, approvePort = \
getDomainFromActor(approveHandle)
if approveNickname and approveDomain:
sayStr = 'Sending approve follow request for ' + \
approveNickname + '@' + approveDomain
_sayCommand(sayStr, sayStr,
screenreader, systemLanguage, espeak)
sessionApprove = createSession(proxyType)
approveFollowRequestViaServer(baseDir, sessionApprove,
nickname, password,
domain, port,
httpPrefix,
approveHandle,
cachedWebfingers,
personCache,
debug,
__version__)
else:
if approveHandle:
sayStr = approveHandle + ' is not valid'
else:
sayStr = 'Specify a handle to approve'
_sayCommand(sayStr,
screenreader, systemLanguage, espeak)
print('')
elif commandStr.startswith('deny '):
denyHandle = commandStr.replace('deny ', '').strip()
if denyHandle.startswith('@'):
denyHandle = denyHandle[1:]
if '@' in denyHandle or '://' in denyHandle:
denyNickname = getNicknameFromActor(denyHandle)
denyDomain, denyPort = \
getDomainFromActor(denyHandle)
if denyNickname and denyDomain:
sayStr = 'Sending deny follow request for ' + \
denyNickname + '@' + denyDomain
_sayCommand(sayStr, sayStr,
screenreader, systemLanguage, espeak)
sessionDeny = createSession(proxyType)
denyFollowRequestViaServer(baseDir, sessionDeny,
nickname, password,
domain, port,
httpPrefix,
denyHandle,
cachedWebfingers,
personCache,
debug,
__version__)
else:
if denyHandle:
sayStr = denyHandle + ' is not valid'
else:
sayStr = 'Specify a handle to deny'
_sayCommand(sayStr,
screenreader, systemLanguage, espeak)
print('')
elif (commandStr == 'repeat' or commandStr == 'replay' or elif (commandStr == 'repeat' or commandStr == 'replay' or
commandStr == 'rp' or commandStr == 'again' or commandStr == 'rp' or commandStr == 'again' or
commandStr == 'say again'): commandStr == 'say again'):
@ -2190,6 +2320,13 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
print('') print('')
elif commandStr.startswith('h'): elif commandStr.startswith('h'):
_desktopHelp() _desktopHelp()
sayStr = 'Press Enter to continue...'
sayStr2 = _highlightText(sayStr)
_sayCommand(sayStr2, sayStr,
screenreader, systemLanguage, espeak)
input()
prevTimelineFirstId = ''
refreshTimeline = True
elif (commandStr == 'delete' or elif (commandStr == 'delete' or
commandStr == 'rm' or commandStr == 'rm' or
commandStr.startswith('delete ') or commandStr.startswith('delete ') or

184
follow.py
View File

@ -1145,41 +1145,7 @@ def getFollowingViaServer(baseDir: str, session,
return 6 return 6
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)
followActor = httpPrefix + '://' + domainFull + '/users/' + nickname followActor = httpPrefix + '://' + domainFull + '/users/' + nickname
handle = httpPrefix + '://' + domainFull + '/@' + nickname
# lookup the inbox for the To handle
wfRequest = \
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
domain, projectVersion, debug)
if not wfRequest:
if debug:
print('DEBUG: following list webfinger failed for ' + handle)
return 1
if not isinstance(wfRequest, dict):
print('WARN: following list Webfinger for ' + handle +
' did not return a dict. ' + str(wfRequest))
return 1
postToBox = 'outbox'
# get the actor inbox for the To handle
(inboxUrl, pubKeyId, pubKey,
fromPersonId, sharedInbox, avatarUrl,
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
projectVersion, httpPrefix, nickname,
domain, postToBox, 52025)
if not inboxUrl:
if debug:
print('DEBUG: following list no ' + postToBox +
' was found for ' + handle)
return 3
if not fromPersonId:
if debug:
print('DEBUG: following list no actor was found for ' + handle)
return 4
authHeader = createBasicAuthHeader(nickname, password) authHeader = createBasicAuthHeader(nickname, password)
@ -1220,41 +1186,7 @@ def getFollowersViaServer(baseDir: str, session,
return 6 return 6
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)
followActor = httpPrefix + '://' + domainFull + '/users/' + nickname followActor = httpPrefix + '://' + domainFull + '/users/' + nickname
handle = httpPrefix + '://' + domainFull + '/@' + nickname
# lookup the inbox for the To handle
wfRequest = \
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
domain, projectVersion, debug)
if not wfRequest:
if debug:
print('DEBUG: followers list webfinger failed for ' + handle)
return 1
if not isinstance(wfRequest, dict):
print('WARN: followers list Webfinger for ' + handle +
' did not return a dict. ' + str(wfRequest))
return 1
postToBox = 'outbox'
# get the actor inbox for the To handle
(inboxUrl, pubKeyId, pubKey,
fromPersonId, sharedInbox, avatarUrl,
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
projectVersion, httpPrefix, nickname,
domain, postToBox, 52025)
if not inboxUrl:
if debug:
print('DEBUG: followers list no ' + postToBox +
' was found for ' + handle)
return 3
if not fromPersonId:
if debug:
print('DEBUG: followers list no actor was found for ' + handle)
return 4
authHeader = createBasicAuthHeader(nickname, password) authHeader = createBasicAuthHeader(nickname, password)
@ -1296,42 +1228,6 @@ def getFollowRequestsViaServer(baseDir: str, session,
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)
followActor = httpPrefix + '://' + domainFull + '/users/' + nickname followActor = httpPrefix + '://' + domainFull + '/users/' + nickname
handle = httpPrefix + '://' + domainFull + '/@' + nickname
# lookup the inbox for the To handle
wfRequest = \
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
domain, projectVersion, debug)
if not wfRequest:
if debug:
print('DEBUG: follow requests list webfinger failed for ' +
handle)
return 1
if not isinstance(wfRequest, dict):
print('WARN: follow requests list Webfinger for ' + handle +
' did not return a dict. ' + str(wfRequest))
return 1
postToBox = 'outbox'
# get the actor inbox for the To handle
(inboxUrl, pubKeyId, pubKey,
fromPersonId, sharedInbox, avatarUrl,
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
projectVersion, httpPrefix, nickname,
domain, postToBox, 42759)
if not inboxUrl:
if debug:
print('DEBUG: follow requests list no ' + postToBox +
' was found for ' + handle)
return 3
if not fromPersonId:
if debug:
print('DEBUG: follow requests list no actor was found for ' +
handle)
return 4
authHeader = createBasicAuthHeader(nickname, password) authHeader = createBasicAuthHeader(nickname, password)
headers = { headers = {
@ -1357,6 +1253,86 @@ def getFollowRequestsViaServer(baseDir: str, session,
return followersJson return followersJson
def approveFollowRequestViaServer(baseDir: str, session,
nickname: str, password: str,
domain: str, port: int,
httpPrefix: str, approveHandle: int,
cachedWebfingers: {}, personCache: {},
debug: bool, projectVersion: str) -> str:
"""Approves a follow request
This is not exactly via c2s though. It simulates pressing the Approve
button on the web interface
"""
if not session:
print('WARN: No session for approveFollowRequestViaServer')
return 6
domainFull = getFullDomain(domain, port)
actor = httpPrefix + '://' + domainFull + '/users/' + nickname
authHeader = createBasicAuthHeader(nickname, password)
headers = {
'host': domain,
'Content-type': 'text/html; charset=utf-8',
'Authorization': authHeader
}
url = actor + '/followapprove=' + approveHandle
approveHtml = \
getJson(session, url, headers, {}, debug,
__version__, httpPrefix, domain, 10, True)
if not approveHtml:
if debug:
print('DEBUG: GET approve follow request failed for c2s to ' + url)
return 5
if debug:
print('DEBUG: c2s GET approve follow request request success')
return approveHtml
def denyFollowRequestViaServer(baseDir: str, session,
nickname: str, password: str,
domain: str, port: int,
httpPrefix: str, denyHandle: int,
cachedWebfingers: {}, personCache: {},
debug: bool, projectVersion: str) -> str:
"""Denies a follow request
This is not exactly via c2s though. It simulates pressing the Deny
button on the web interface
"""
if not session:
print('WARN: No session for denyFollowRequestViaServer')
return 6
domainFull = getFullDomain(domain, port)
actor = httpPrefix + '://' + domainFull + '/users/' + nickname
authHeader = createBasicAuthHeader(nickname, password)
headers = {
'host': domain,
'Content-type': 'text/html; charset=utf-8',
'Authorization': authHeader
}
url = actor + '/followdeny=' + denyHandle
denyHtml = \
getJson(session, url, headers, {}, debug,
__version__, httpPrefix, domain, 10, True)
if not denyHtml:
if debug:
print('DEBUG: GET deny follow request failed for c2s to ' + url)
return 5
if debug:
print('DEBUG: c2s GET deny follow request request success')
return denyHtml
def getFollowersOfActor(baseDir: str, actor: str, debug: bool) -> {}: def getFollowersOfActor(baseDir: str, actor: str, debug: bool) -> {}:
"""In a shared inbox if we receive a post we know who it's from """In a shared inbox if we receive a post we know who it's from
and if it's addressed to followers then we need to get a list of those. and if it's addressed to followers then we need to get a list of those.

View File

@ -376,6 +376,7 @@ def speakableText(baseDir: str, content: str, translate: {}) -> (str, []):
"""Convert the given text to a speakable version """Convert the given text to a speakable version
which includes changes for prononciation which includes changes for prononciation
""" """
content = str(content)
if isPGPEncrypted(content): if isPGPEncrypted(content):
return content, [] return content, []