From 7aea1105e6c9295de9cd5716550a2d8689bd80a2 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 10:56:41 +0000 Subject: [PATCH 01/14] Check follow requests returned value --- desktop_client.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/desktop_client.py b/desktop_client.py index 70c1c847f..a085ab00f 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -1189,6 +1189,10 @@ def _desktopNewDMbase(session, toHandle: str, def _desktopShowFollowRequests(followRequestsJson: {}, translate: {}) -> None: """Shows any follow requests """ + if not isinstance(followRequestsJson, dict): + return + if not followRequestsJson.get('orderedItems'): + return if not followRequestsJson['orderedItems']: return indent = ' ' @@ -1534,6 +1538,11 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, pageNumber, postIndex, boxJson, systemLanguage, screenreader, espeak, translate, yourActor) + print('') + print(_highlightText('Press Enter to continue...')) + enterKey = input() + prevTimelineFirstId = '' + refreshTimeline = True print('') elif commandStr.startswith('profile ') or commandStr == 'profile': actorJson = None From 26d25c5067075368cdf8e3b92816185975fc39ab Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 10:58:53 +0000 Subject: [PATCH 02/14] Check following is a dict --- desktop_client.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/desktop_client.py b/desktop_client.py index a085ab00f..90d16a242 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -1213,6 +1213,10 @@ def _desktopShowFollowing(followingJson: {}, translate: {}, followType='following') -> None: """Shows a page of accounts followed """ + if not isinstance(followingJson, dict): + return + if not followingJson.get('orderedItems'): + return if not followingJson['orderedItems']: return print('') From ffb47522c13094e496f94c92219b3b051980048d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 12:07:44 +0000 Subject: [PATCH 03/14] Accept or deny follow commands for desktop client --- README_commandline.md | 2 ++ desktop_client.py | 72 +++++++++++++++++++++++++++++++++++++- follow.py | 80 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 1 deletion(-) diff --git a/README_commandline.md b/README_commandline.md index 28206529a..72a058ab0 100644 --- a/README_commandline.md +++ b/README_commandline.md @@ -476,6 +476,8 @@ open [post number] Open web links within a timeline post profile [post number] Show profile for the person who made the given post following [page number] Show accounts that you are following 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. diff --git a/desktop_client.py b/desktop_client.py index 90d16a242..065039904 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -29,6 +29,8 @@ from speaker import getSpeakerRate from speaker import getSpeakerRange from like import sendLikeViaServer from like import sendUndoLikeViaServer +from follow import approveFollowRequestViaServer +from follow import denyFollowRequestViaServer from follow import getFollowRequestsViaServer from follow import getFollowingViaServer from follow import getFollowersViaServer @@ -117,6 +119,10 @@ def _desktopHelp() -> None: 'Show accounts that you are following') print(indent + 'followers [page number] ' + 'Show accounts that are following you') + print(indent + 'approve [handle] ' + + 'Approve a follow request') + print(indent + 'deny [handle] ' + + 'Deny a follow request') print('') @@ -1544,7 +1550,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, espeak, translate, yourActor) print('') print(_highlightText('Press Enter to continue...')) - enterKey = input() + input() prevTimelineFirstId = '' refreshTimeline = True print('') @@ -2106,6 +2112,70 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, _sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak) 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 commandStr == 'rp' or commandStr == 'again' or commandStr == 'say again'): diff --git a/follow.py b/follow.py index 87cccca78..aa8d19881 100644 --- a/follow.py +++ b/follow.py @@ -1357,6 +1357,86 @@ def getFollowRequestsViaServer(baseDir: str, session, 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) -> {}: """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. From 97390c9114985daa4436257247fe54fe41b319df Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 12:15:25 +0000 Subject: [PATCH 04/14] Tidying --- follow.py | 104 ------------------------------------------------------ 1 file changed, 104 deletions(-) diff --git a/follow.py b/follow.py index aa8d19881..107986d44 100644 --- a/follow.py +++ b/follow.py @@ -1145,41 +1145,7 @@ def getFollowingViaServer(baseDir: str, session, return 6 domainFull = getFullDomain(domain, port) - 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) @@ -1220,41 +1186,7 @@ def getFollowersViaServer(baseDir: str, session, return 6 domainFull = getFullDomain(domain, port) - 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) @@ -1296,42 +1228,6 @@ def getFollowRequestsViaServer(baseDir: str, session, domainFull = getFullDomain(domain, port) 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) headers = { From 2a25c6909e312d5245241e6a86b2b06bdbc476bb Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 12:21:04 +0000 Subject: [PATCH 05/14] Enter key after help --- desktop_client.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/desktop_client.py b/desktop_client.py index 065039904..8f3f0ce40 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -2273,6 +2273,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, print('') elif commandStr.startswith('h'): _desktopHelp() + print(_highlightText('Press Enter to continue...')) + input() elif (commandStr == 'delete' or commandStr == 'rm' or commandStr.startswith('delete ') or From 264747d7f808d839840c6a6b8d3f98e69c6e6dea Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 12:39:10 +0000 Subject: [PATCH 06/14] Split profile function --- desktop_client.py | 62 ++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/desktop_client.py b/desktop_client.py index 8f3f0ce40..293bf5a0c 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -758,6 +758,39 @@ def _readLocalBoxPost(session, nickname: str, domain: str, return postJsonObject +def _showActor(baseDir: str, actorJson: {}, translate: {}, + systemLanguage: str, screenreader: str, espeak) -> None: + """ + """ + actor = actorJson['id'] + actorNickname = getNicknameFromActor(actor) + actorDomain, actorPort = getDomainFromActor(actor) + actorDomainFull = getFullDomain(actorDomain, actorPort) + handle = '@' + actorNickname + '@' + actorDomainFull + + sayStr = handle + _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) + if actorJson.get('summary'): + sayStr = removeHtml(actorJson['summary']) + sayStr2 = speakableText(baseDir, sayStr, translate) + _sayCommand(sayStr, sayStr2, screenreader, systemLanguage, espeak) + + def _showProfile(session, nickname: str, domain: str, httpPrefix: str, baseDir: str, boxName: str, pageNumber: int, index: int, boxJson: {}, @@ -796,33 +829,8 @@ def _showProfile(session, nickname: str, domain: str, isHttp = True actorJson = getActorJson(actor, isHttp, False, False, True) - actor = actorJson['id'] - actorNickname = getNicknameFromActor(actor) - actorDomain, actorPort = getDomainFromActor(actor) - actorDomainFull = getFullDomain(actorDomain, actorPort) - handle = '@' + actorNickname + '@' + actorDomainFull - - sayStr = handle - _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) - if actorJson.get('summary'): - sayStr = removeHtml(actorJson['summary']) - sayStr2 = speakableText(baseDir, sayStr, translate) - _sayCommand(sayStr, sayStr2, screenreader, systemLanguage, espeak) + _showActor(baseDir, actorJson, translate, + systemLanguage, screenreader, espeak) return actorJson From 6f7bc847809a64606d1590d56471e3a8bfa333c7 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 12:43:11 +0000 Subject: [PATCH 07/14] Change function names --- desktop_client.py | 51 +++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/desktop_client.py b/desktop_client.py index 293bf5a0c..d225243ab 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -758,9 +758,10 @@ def _readLocalBoxPost(session, nickname: str, domain: str, return postJsonObject -def _showActor(baseDir: str, actorJson: {}, translate: {}, - systemLanguage: str, screenreader: str, espeak) -> None: - """ +def _desktopShowActor(baseDir: str, actorJson: {}, translate: {}, + systemLanguage: str, screenreader: str, + espeak) -> None: + """Shows information for the given actor """ actor = actorJson['id'] actorNickname = getNicknameFromActor(actor) @@ -791,13 +792,13 @@ def _showActor(baseDir: str, actorJson: {}, translate: {}, _sayCommand(sayStr, sayStr2, screenreader, systemLanguage, espeak) -def _showProfile(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: {}) -> {}: +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 Returns the actor json """ @@ -829,8 +830,8 @@ def _showProfile(session, nickname: str, domain: str, isHttp = True actorJson = getActorJson(actor, isHttp, False, False, True) - _showActor(baseDir, actorJson, translate, - systemLanguage, screenreader, espeak) + _desktopShowActor(baseDir, actorJson, translate, + systemLanguage, screenreader, espeak) return actorJson @@ -1567,12 +1568,14 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, if commandStr == 'profile': if postJsonObject: actorJson = \ - _showProfile(session, nickname, domain, - httpPrefix, baseDir, currTimeline, - pageNumber, postIndex, boxJson, - systemLanguage, screenreader, - espeak, translate, yourActor, - postJsonObject) + _desktopShowProfile(session, nickname, domain, + httpPrefix, baseDir, + currTimeline, + pageNumber, postIndex, + boxJson, + systemLanguage, screenreader, + espeak, translate, yourActor, + postJsonObject) else: postIndexStr = '1' else: @@ -1587,12 +1590,12 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, newRepliesExist, newDMsExist) postIndex = int(postIndexStr) actorJson = \ - _showProfile(session, nickname, domain, - httpPrefix, baseDir, currTimeline, - pageNumber, postIndex, boxJson, - systemLanguage, screenreader, - espeak, translate, yourActor, - None) + _desktopShowProfile(session, nickname, domain, + httpPrefix, baseDir, currTimeline, + pageNumber, postIndex, boxJson, + systemLanguage, screenreader, + espeak, translate, yourActor, + None) print('') elif commandStr == 'reply' or commandStr == 'r': if postJsonObject: From 96b36e81a990c50dfea0e21d562fbb22d1deea7b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 12:57:01 +0000 Subject: [PATCH 08/14] Profile command can use handle --- README_commandline.md | 2 +- desktop_client.py | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/README_commandline.md b/README_commandline.md index 72a058ab0..a01428ca0 100644 --- a/README_commandline.md +++ b/README_commandline.md @@ -473,7 +473,7 @@ next Next page in the timeline prev Previous page in the timeline read [post number] Read a post from a timeline 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 followers [page number] Show accounts that are following you approve [handle] Approve a follow request diff --git a/desktop_client.py b/desktop_client.py index d225243ab..766c6b9db 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -113,7 +113,7 @@ def _desktopHelp() -> None: 'Read a post from a timeline') print(indent + 'open [post number] ' + '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') print(indent + 'following [page number] ' + 'Show accounts that you are following') @@ -836,6 +836,24 @@ def _desktopShowProfile(session, nickname: str, domain: str, return actorJson +def _desktopShowProfileFromHandle(session, nickname: str, domain: str, + httpPrefix: str, baseDir: str, boxName: str, + handle: str, + systemLanguage: str, + 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 + + def _desktopGetBoxPostObject(boxJson: {}, index: int) -> {}: """Gets the post with the given index from the timeline """ @@ -1581,7 +1599,21 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, else: postIndexStr = commandStr.split('profile ')[1] - if not actorJson and boxJson and postIndexStr.isdigit(): + if not postIndexStr.isdigit(): + profileHandle = postIndexStr + _desktopShowBox(indent, followRequestsJson, + yourActor, currTimeline, boxJson, + translate, + screenreader, systemLanguage, + espeak, pageNumber, + newRepliesExist, newDMsExist) + _desktopShowProfileFromHandle(session, nickname, domain, + httpPrefix, baseDir, + currTimeline, profileHandle, + systemLanguage, screenreader, + espeak, translate, yourActor, + None) + elif not actorJson and boxJson: _desktopShowBox(indent, followRequestsJson, yourActor, currTimeline, boxJson, translate, From 8b6ba41533c4db30449427f305eaed420c68e2de Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 13:57:47 +0000 Subject: [PATCH 09/14] Unescape profile summary --- desktop_client.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/desktop_client.py b/desktop_client.py index 766c6b9db..dced99ee4 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -332,7 +332,7 @@ def _speakerPicospeaker(pitch: int, rate: int, systemLanguage: str, '-l ' + speakerLang + \ ' -r ' + str(rate) + \ ' -p ' + str(pitch) + ' "' + \ - html.unescape(sayText) + '" 2> /dev/null' + html.unescape(str(sayText)) + '" 2> /dev/null' os.system(speakerCmd) @@ -769,11 +769,11 @@ def _desktopShowActor(baseDir: str, actorJson: {}, translate: {}, actorDomainFull = getFullDomain(actorDomain, actorPort) handle = '@' + actorNickname + '@' + actorDomainFull - sayStr = handle + sayStr = html.unescape(handle) _sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak) print(actor) if actorJson.get('movedTo'): - sayStr = 'Moved to ' + actorJson['movedTo'] + sayStr = 'Moved to ' + html.unescape(actorJson['movedTo']) _sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak) if actorJson.get('alsoKnownAs'): alsoKnownAsStr = '' @@ -784,10 +784,11 @@ def _desktopShowActor(baseDir: str, actorJson: {}, translate: {}, ctr += 1 alsoKnownAsStr += altActor - sayStr = 'Also known as ' + alsoKnownAsStr + sayStr = 'Also known as ' + html.unescape(alsoKnownAsStr) _sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak) if actorJson.get('summary'): - sayStr = removeHtml(actorJson['summary']) + sayStr = html.unescape(removeHtml(actorJson['summary'])) + sayStr = sayStr.replace('"', "'") sayStr2 = speakableText(baseDir, sayStr, translate) _sayCommand(sayStr, sayStr2, screenreader, systemLanguage, espeak) From 2c4e09ab84fdbec2c950611b829aeca11d6a2218 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 14:15:36 +0000 Subject: [PATCH 10/14] Clear screen when reading post --- desktop_client.py | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/desktop_client.py b/desktop_client.py index dced99ee4..818c0d9a8 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -328,6 +328,7 @@ def _speakerPicospeaker(pitch: int, rate: int, systemLanguage: str, speakerLang = 'de-DE' elif systemLanguage.startswith('it'): speakerLang = 'it-IT' + sayText = str(sayText).replace('"', "'") speakerCmd = 'picospeaker ' + \ '-l ' + speakerLang + \ ' -r ' + str(rate) + \ @@ -1563,12 +1564,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, else: postIndexStr = commandStr.split('read ')[1] if boxJson and postIndexStr.isdigit(): - _desktopShowBox(indent, followRequestsJson, - yourActor, currTimeline, boxJson, - translate, - screenreader, systemLanguage, - espeak, pageNumber, - newRepliesExist, newDMsExist) + _desktopClearScreen() + _desktopShowBanner() postIndex = int(postIndexStr) postJsonObject = \ _readLocalBoxPost(session, nickname, domain, @@ -1577,7 +1574,9 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, systemLanguage, screenreader, espeak, translate, yourActor) print('') - print(_highlightText('Press Enter to continue...')) + sayStr = 'Press Enter to continue...' + _sayCommand(_highlightText(sayStr), sayStr, + screenreader, systemLanguage, espeak) input() prevTimelineFirstId = '' refreshTimeline = True @@ -1602,25 +1601,21 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, if not postIndexStr.isdigit(): profileHandle = postIndexStr - _desktopShowBox(indent, followRequestsJson, - yourActor, currTimeline, boxJson, - translate, - screenreader, systemLanguage, - espeak, pageNumber, - newRepliesExist, newDMsExist) + _desktopClearScreen() + _desktopShowBanner() _desktopShowProfileFromHandle(session, nickname, domain, httpPrefix, baseDir, currTimeline, profileHandle, systemLanguage, screenreader, espeak, translate, yourActor, None) + sayStr = 'Press Enter to continue...' + _sayCommand(_highlightText(sayStr), sayStr, + screenreader, systemLanguage, espeak) + input() elif not actorJson and boxJson: - _desktopShowBox(indent, followRequestsJson, - yourActor, currTimeline, boxJson, - translate, - screenreader, systemLanguage, - espeak, pageNumber, - newRepliesExist, newDMsExist) + _desktopClearScreen() + _desktopShowBanner() postIndex = int(postIndexStr) actorJson = \ _desktopShowProfile(session, nickname, domain, @@ -1629,6 +1624,10 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, systemLanguage, screenreader, espeak, translate, yourActor, None) + sayStr = 'Press Enter to continue...' + _sayCommand(_highlightText(sayStr), sayStr, + screenreader, systemLanguage, espeak) + input() print('') elif commandStr == 'reply' or commandStr == 'r': if postJsonObject: @@ -2317,7 +2316,9 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, print('') elif commandStr.startswith('h'): _desktopHelp() - print(_highlightText('Press Enter to continue...')) + sayStr = 'Press Enter to continue...' + _sayCommand(_highlightText(sayStr), sayStr, + screenreader, systemLanguage, espeak) input() elif (commandStr == 'delete' or commandStr == 'rm' or From 6492264990c31d9d12b6f9b79aed6be378de2e7d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 14:18:19 +0000 Subject: [PATCH 11/14] Refresh timeline after showing profile --- desktop_client.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/desktop_client.py b/desktop_client.py index 818c0d9a8..a65bad27e 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -1613,6 +1613,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, _sayCommand(_highlightText(sayStr), sayStr, screenreader, systemLanguage, espeak) input() + prevTimelineFirstId = '' + refreshTimeline = True elif not actorJson and boxJson: _desktopClearScreen() _desktopShowBanner() @@ -1628,6 +1630,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, _sayCommand(_highlightText(sayStr), sayStr, screenreader, systemLanguage, espeak) input() + prevTimelineFirstId = '' + refreshTimeline = True print('') elif commandStr == 'reply' or commandStr == 'r': if postJsonObject: From 20476173cc2b7337e847a0fefe051c1a4b5bec73 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 14:31:34 +0000 Subject: [PATCH 12/14] Use first value from speakable text --- desktop_client.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/desktop_client.py b/desktop_client.py index a65bad27e..e06b3df3c 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -704,7 +704,7 @@ def _readLocalBoxPost(session, nickname: str, domain: str, _textOnlyContent(postJsonObject2['object']['content']) content += _getImageDescription(postJsonObject2) messageStr, detectedLinks = \ - speakableText(baseDir, content, translate) + speakableText(baseDir, content, translate)[0] sayStr = content _sayCommand(sayStr, messageStr, screenreader, systemLanguage, espeak) @@ -726,7 +726,7 @@ def _readLocalBoxPost(session, nickname: str, domain: str, return {} content = _safeMessage(content) - messageStr, detectedLinks = speakableText(baseDir, content, translate) + messageStr, detectedLinks = speakableText(baseDir, content, translate)[0] if screenreader: time.sleep(2) @@ -790,7 +790,7 @@ def _desktopShowActor(baseDir: str, actorJson: {}, translate: {}, if actorJson.get('summary'): sayStr = html.unescape(removeHtml(actorJson['summary'])) sayStr = sayStr.replace('"', "'") - sayStr2 = speakableText(baseDir, sayStr, translate) + sayStr2 = speakableText(baseDir, sayStr, translate)[0] _sayCommand(sayStr, sayStr2, screenreader, systemLanguage, espeak) @@ -2303,7 +2303,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, if postJsonObject: content = postJsonObject['object']['content'] messageStr, detectedLinks = \ - speakableText(baseDir, content, translate) + speakableText(baseDir, content, translate)[0] linkOpened = False for url in detectedLinks: if '://' in url: From 40655f8b19b9bcc5794f2e8b40b68e109ecb61a1 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 14:51:41 +0000 Subject: [PATCH 13/14] Fix speakable return values --- desktop_client.py | 12 ++++-------- speaker.py | 1 + 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/desktop_client.py b/desktop_client.py index e06b3df3c..b54c087a1 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -704,7 +704,7 @@ def _readLocalBoxPost(session, nickname: str, domain: str, _textOnlyContent(postJsonObject2['object']['content']) content += _getImageDescription(postJsonObject2) messageStr, detectedLinks = \ - speakableText(baseDir, content, translate)[0] + speakableText(baseDir, content, translate) sayStr = content _sayCommand(sayStr, messageStr, screenreader, systemLanguage, espeak) @@ -726,7 +726,7 @@ def _readLocalBoxPost(session, nickname: str, domain: str, return {} content = _safeMessage(content) - messageStr, detectedLinks = speakableText(baseDir, content, translate)[0] + messageStr, detectedLinks = speakableText(baseDir, content, translate) if screenreader: time.sleep(2) @@ -770,7 +770,7 @@ def _desktopShowActor(baseDir: str, actorJson: {}, translate: {}, actorDomainFull = getFullDomain(actorDomain, actorPort) handle = '@' + actorNickname + '@' + actorDomainFull - sayStr = html.unescape(handle) + sayStr = 'Profile for ' + html.unescape(handle) _sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak) print(actor) if actorJson.get('movedTo'): @@ -1080,10 +1080,6 @@ def _desktopShowBox(indent: str, elif newReplies and boxName != 'tlreplies': sayStr += \ '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 = sayStr2.replace('show dm', 'show DM') sayStr2 = sayStr2.replace('dm post', 'Direct message post') @@ -2303,7 +2299,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, if postJsonObject: content = postJsonObject['object']['content'] messageStr, detectedLinks = \ - speakableText(baseDir, content, translate)[0] + speakableText(baseDir, content, translate) linkOpened = False for url in detectedLinks: if '://' in url: diff --git a/speaker.py b/speaker.py index d6d66fbca..a04ef3709 100644 --- a/speaker.py +++ b/speaker.py @@ -376,6 +376,7 @@ def speakableText(baseDir: str, content: str, translate: {}) -> (str, []): """Convert the given text to a speakable version which includes changes for prononciation """ + content = str(content) if isPGPEncrypted(content): return content, [] From c3f435f30fb1052e4e658590fbe4f3daa55104c7 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 25 Mar 2021 15:11:52 +0000 Subject: [PATCH 14/14] Fix tests --- desktop_client.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/desktop_client.py b/desktop_client.py index b54c087a1..192d23033 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -59,9 +59,10 @@ from person import getActorJson def _desktopHelp() -> None: """Shows help """ + _desktopClearScreen() indent = ' ' print('') - print(indent + 'Commands:') + print(indent + _highlightText('Help Commands:')) print('') print(indent + 'quit ' + 'Exit from the desktop client') @@ -1571,7 +1572,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, espeak, translate, yourActor) print('') sayStr = 'Press Enter to continue...' - _sayCommand(_highlightText(sayStr), sayStr, + sayStr2 = _highlightText(sayStr) + _sayCommand(sayStr2, sayStr, screenreader, systemLanguage, espeak) input() prevTimelineFirstId = '' @@ -1606,7 +1608,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, espeak, translate, yourActor, None) sayStr = 'Press Enter to continue...' - _sayCommand(_highlightText(sayStr), sayStr, + sayStr2 = _highlightText(sayStr) + _sayCommand(sayStr2, sayStr, screenreader, systemLanguage, espeak) input() prevTimelineFirstId = '' @@ -1623,7 +1626,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, espeak, translate, yourActor, None) sayStr = 'Press Enter to continue...' - _sayCommand(_highlightText(sayStr), sayStr, + sayStr2 = _highlightText(sayStr) + _sayCommand(sayStr2, sayStr, screenreader, systemLanguage, espeak) input() prevTimelineFirstId = '' @@ -2317,9 +2321,12 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str, elif commandStr.startswith('h'): _desktopHelp() sayStr = 'Press Enter to continue...' - _sayCommand(_highlightText(sayStr), sayStr, + sayStr2 = _highlightText(sayStr) + _sayCommand(sayStr2, sayStr, screenreader, systemLanguage, espeak) input() + prevTimelineFirstId = '' + refreshTimeline = True elif (commandStr == 'delete' or commandStr == 'rm' or commandStr.startswith('delete ') or