epicyon/desktop_client.py

1921 lines
80 KiB
Python
Raw Normal View History

2021-03-17 10:04:49 +00:00
__filename__ = "desktop_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
import webbrowser
import urllib.parse
from pathlib import Path
from random import randint
2021-03-21 18:37:06 +00:00
from utils import getFullDomain
2021-03-18 19:43:10 +00:00
from utils import isDM
2021-03-18 17:27:46 +00:00
from utils import loadTranslationsFromFile
from utils import removeHtml
from utils import getNicknameFromActor
from utils import getDomainFromActor
2021-03-12 12:04:34 +00:00
from utils import isPGPEncrypted
2021-03-04 13:57:30 +00:00
from session import createSession
2021-03-18 17:27:46 +00:00
from speaker import speakableText
2021-03-04 13:57:30 +00:00
from speaker import getSpeakerPitch
from speaker import getSpeakerRate
from speaker import getSpeakerRange
2021-03-10 13:04:22 +00:00
from like import sendLikeViaServer
2021-03-10 13:07:24 +00:00
from like import sendUndoLikeViaServer
from follow import sendFollowRequestViaServer
from follow import sendUnfollowRequestViaServer
2021-03-21 12:31:48 +00:00
from posts import sendMuteViaServer
from posts import sendUndoMuteViaServer
from posts import sendPostViaServer
from posts import c2sBoxJson
from posts import downloadAnnounce
from announce import sendAnnounceViaServer
2021-03-18 20:56:08 +00:00
from announce import sendUndoAnnounceViaServer
2021-03-11 17:15:32 +00:00
from pgp import pgpDecrypt
from pgp import hasLocalPGPkey
from pgp import pgpEncryptToActor
2021-03-17 20:18:00 +00:00
from pgp import pgpPublicKeyUpload
2021-03-18 20:04:49 +00:00
from like import noOfLikes
2021-03-19 22:04:57 +00:00
from bookmarks import sendBookmarkViaServer
2021-03-19 22:11:45 +00:00
from bookmarks import sendUndoBookmarkViaServer
2021-03-21 18:37:06 +00:00
from delete import sendDeleteViaServer
2021-03-22 18:27:48 +00:00
from person import getActorJson
2021-03-04 14:36:24 +00:00
2021-03-16 23:10:14 +00:00
def _desktopHelp() -> None:
"""Shows help
"""
2021-03-16 23:14:34 +00:00
indent = ' '
2021-03-16 23:10:14 +00:00
print('')
2021-03-16 23:14:34 +00:00
print(indent + 'Commands:')
2021-03-16 23:10:14 +00:00
print('')
2021-03-19 21:34:38 +00:00
print(indent + 'quit ' +
2021-03-17 10:04:49 +00:00
'Exit from the desktop client')
2021-03-19 21:34:38 +00:00
print(indent + 'show dm|sent|inbox|replies|bookmarks ' +
2021-03-16 23:14:34 +00:00
'Show a timeline')
2021-03-19 21:34:38 +00:00
print(indent + 'mute ' +
2021-03-16 23:14:34 +00:00
'Turn off the screen reader')
2021-03-19 21:34:38 +00:00
print(indent + 'speak ' +
2021-03-16 23:14:34 +00:00
'Turn on the screen reader')
2021-03-19 21:34:38 +00:00
print(indent + 'sounds on ' +
2021-03-16 23:14:34 +00:00
'Turn on notification sounds')
2021-03-19 21:34:38 +00:00
print(indent + 'sounds off ' +
2021-03-16 23:14:34 +00:00
'Turn off notification sounds')
2021-03-19 21:34:38 +00:00
print(indent + 'rp ' +
2021-03-16 23:14:34 +00:00
'Repeat the last post')
2021-03-19 21:34:38 +00:00
print(indent + 'like ' +
2021-03-16 23:14:34 +00:00
'Like the last post')
2021-03-19 21:34:38 +00:00
print(indent + 'unlike ' +
2021-03-16 23:14:34 +00:00
'Unlike the last post')
2021-03-20 09:49:43 +00:00
print(indent + 'bookmark ' +
2021-03-21 12:31:48 +00:00
'Bookmark the last post')
2021-03-20 09:49:43 +00:00
print(indent + 'unbookmark ' +
'Unbookmark the last post')
2021-03-21 12:31:48 +00:00
print(indent + 'mute ' +
'Mute the last post')
print(indent + 'unmute ' +
'Unmute the last post')
2021-03-19 21:34:38 +00:00
print(indent + 'reply ' +
2021-03-16 23:14:34 +00:00
'Reply to the last post')
2021-03-19 21:34:38 +00:00
print(indent + 'post ' +
2021-03-16 23:14:34 +00:00
'Create a new post')
2021-03-19 21:34:38 +00:00
print(indent + 'post to [handle] ' +
2021-03-16 23:14:34 +00:00
'Create a new direct message')
2021-03-19 21:34:38 +00:00
print(indent + 'announce/boost ' +
2021-03-16 23:14:34 +00:00
'Boost the last post')
2021-03-19 21:34:38 +00:00
print(indent + 'follow [handle] ' +
2021-03-16 23:14:34 +00:00
'Make a follow request')
2021-03-19 21:34:38 +00:00
print(indent + 'unfollow [handle] ' +
2021-03-16 23:14:34 +00:00
'Stop following the give handle')
2021-03-19 21:34:38 +00:00
print(indent + 'next ' +
2021-03-16 23:14:34 +00:00
'Next page in the timeline')
2021-03-19 21:34:38 +00:00
print(indent + 'prev ' +
2021-03-16 23:14:34 +00:00
'Previous page in the timeline')
2021-03-19 21:34:38 +00:00
print(indent + 'read [post number] ' +
2021-03-16 23:14:34 +00:00
'Read a post from a timeline')
2021-03-19 21:34:38 +00:00
print(indent + 'open [post number] ' +
2021-03-16 23:14:34 +00:00
'Open web links within a timeline post')
2021-03-22 18:27:48 +00:00
print(indent + 'profile [post number] ' +
'Show profile for the person who made the given post')
2021-03-16 23:10:14 +00:00
print('')
def _createDesktopConfig(actor: str) -> None:
"""Sets up directories for desktop client configuration
"""
homeDir = str(Path.home())
if not os.path.isdir(homeDir + '/.config'):
os.mkdir(homeDir + '/.config')
if not os.path.isdir(homeDir + '/.config/epicyon'):
os.mkdir(homeDir + '/.config/epicyon')
nickname = getNicknameFromActor(actor)
domain, port = getDomainFromActor(actor)
handle = nickname + '@' + domain
if port != 443 and port != 80:
handle += '_' + str(port)
readPostsDir = homeDir + '/.config/epicyon/' + handle
if not os.path.isdir(readPostsDir):
os.mkdir(readPostsDir)
def _markPostAsRead(actor: str, postId: str, postCategory: str) -> None:
"""Marks the given post as read by the given actor
"""
homeDir = str(Path.home())
_createDesktopConfig(actor)
nickname = getNicknameFromActor(actor)
domain, port = getDomainFromActor(actor)
handle = nickname + '@' + domain
if port != 443 and port != 80:
handle += '_' + str(port)
readPostsDir = homeDir + '/.config/epicyon/' + handle
readPostsFilename = readPostsDir + '/' + postCategory + '.txt'
if os.path.isfile(readPostsFilename):
if postId in open(readPostsFilename).read():
return
try:
# prepend to read posts file
postId += '\n'
with open(readPostsFilename, 'r+') as readFile:
content = readFile.read()
if postId not in content:
readFile.seek(0, 0)
readFile.write(postId + content)
except Exception as e:
print('WARN: Failed to mark post as read' + str(e))
else:
readFile = open(readPostsFilename, 'w+')
if readFile:
readFile.write(postId + '\n')
readFile.close()
def _hasReadPost(actor: str, postId: str, postCategory: str) -> bool:
"""Returns true if the given post has been read by the actor
"""
homeDir = str(Path.home())
_createDesktopConfig(actor)
nickname = getNicknameFromActor(actor)
domain, port = getDomainFromActor(actor)
handle = nickname + '@' + domain
if port != 443 and port != 80:
handle += '_' + str(port)
readPostsDir = homeDir + '/.config/epicyon/' + handle
readPostsFilename = readPostsDir + '/' + postCategory + '.txt'
if os.path.isfile(readPostsFilename):
if postId in open(readPostsFilename).read():
return True
return False
def _postIsToYou(actor: str, postJsonObject: {}) -> bool:
"""Returns true if the post is to the actor
"""
toYourActor = False
if postJsonObject.get('to'):
if actor in postJsonObject['to']:
toYourActor = True
if not toYourActor and postJsonObject.get('object'):
if isinstance(postJsonObject['object'], dict):
if postJsonObject['object'].get('to'):
if actor in postJsonObject['object']['to']:
toYourActor = True
return toYourActor
def _newDesktopNotifications(actor: str, inboxJson: {},
notifyJson: {}) -> None:
"""Looks for changes in the inbox and adds notifications
"""
if not inboxJson:
return
if not inboxJson.get('orderedItems'):
return
newDM = False
newReply = False
2021-03-22 13:50:49 +00:00
notifyJson['dmNotifyChanged'] = False
notifyJson['repliesNotifyChanged'] = False
for postJsonObject in inboxJson['orderedItems']:
if not postJsonObject.get('id'):
continue
if not _postIsToYou(actor, postJsonObject):
continue
if 'dmNotify' not in notifyJson:
notifyJson['dmNotify'] = False
if isDM(postJsonObject):
if not newDM:
if not _hasReadPost(actor, postJsonObject['id'], 'dm'):
if notifyJson.get('dmPostId'):
if notifyJson['dmPostId'] != postJsonObject['id']:
notifyJson['dmNotify'] = True
2021-03-22 13:43:20 +00:00
notifyJson['dmNotifyChanged'] = True
newDM = True
2021-03-22 13:43:20 +00:00
else:
notifyJson['dmNotifyChanged'] = False
notifyJson['dmPostId'] = postJsonObject['id']
2021-03-22 13:43:20 +00:00
if newDM:
break
else:
if not newReply:
if not _hasReadPost(actor, postJsonObject['id'], 'replies'):
if notifyJson.get('repliesPostId'):
if notifyJson['repliesPostId'] != postJsonObject['id']:
notifyJson['repliesNotify'] = True
2021-03-22 13:43:20 +00:00
notifyJson['repliesNotifyChanged'] = True
newReply = True
2021-03-22 13:43:20 +00:00
else:
notifyJson['repliesNotifyChanged'] = False
notifyJson['repliesPostId'] = postJsonObject['id']
2021-03-22 13:43:20 +00:00
if newReply:
break
2021-03-17 10:04:49 +00:00
def _desktopClearScreen() -> None:
2021-03-15 14:30:59 +00:00
"""Clears the screen
"""
2021-03-15 13:35:12 +00:00
os.system('cls' if os.name == 'nt' else 'clear')
2021-03-15 13:32:15 +00:00
2021-03-17 10:04:49 +00:00
def _desktopShowBanner() -> None:
2021-03-15 14:30:59 +00:00
"""Shows the banner at the top
"""
2021-03-15 14:36:03 +00:00
bannerFilename = 'banner.txt'
2021-03-15 14:31:33 +00:00
if not os.path.isfile(bannerFilename):
2021-03-15 14:36:03 +00:00
bannerTheme = 'starlight'
bannerFilename = 'theme/' + bannerTheme + '/banner.txt'
if not os.path.isfile(bannerFilename):
return
2021-03-15 14:31:33 +00:00
with open(bannerFilename, 'r') as bannerFile:
banner = bannerFile.read()
if banner:
print(banner + '\n')
2021-03-15 14:30:59 +00:00
2021-03-17 10:04:49 +00:00
def _desktopWaitForCmd(timeout: int, debug: bool) -> str:
"""Waits for a command to be entered with a timeout
Returns the command, or None on timeout
2021-03-04 14:36:24 +00:00
"""
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:
2021-03-16 10:37:51 +00:00
"""TTS using picospeaker
"""
2021-03-04 14:54:30 +00:00
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) + ' "' + \
2021-03-10 12:26:10 +00:00
html.unescape(sayText) + '" 2> /dev/null'
2021-03-04 14:54:30 +00:00
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 +
2021-03-10 15:43:21 +00:00
' -autoexit -hide_banner -nodisp 2> /dev/null')
2021-03-09 19:52:10 +00:00
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 + '"')
2021-03-11 10:01:05 +00:00
elif notificationType == 'zenity':
# Zenity
os.system('zenity --notification --title "' + title +
'" --text="' + message + '"')
2021-03-09 20:32:50 +00:00
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 + "'")
2021-03-10 12:11:42 +00:00
def _textToSpeech(sayStr: str, screenreader: str,
pitch: int, rate: int, srange: int,
systemLanguage: str, espeak=None) -> None:
"""Say something via TTS
"""
# speak the post content
if screenreader == 'espeak':
_speakerEspeak(espeak, pitch, rate, srange, sayStr)
elif screenreader == 'picospeaker':
_speakerPicospeaker(pitch, rate,
systemLanguage, sayStr)
def _sayCommand(content: str, sayStr: str, screenreader: str,
2021-03-10 12:11:42 +00:00
systemLanguage: str,
espeak=None,
speakerName='screen reader',
speakerGender='They/Them') -> None:
2021-03-10 10:25:41 +00:00
"""Speaks a command
"""
print(content)
2021-03-10 10:32:08 +00:00
if not screenreader:
return
2021-03-10 10:25:41 +00:00
2021-03-10 12:11:42 +00:00
pitch = getSpeakerPitch(speakerName,
screenreader, speakerGender)
rate = getSpeakerRate(speakerName, screenreader)
srange = getSpeakerRange(speakerName)
2021-03-10 10:25:41 +00:00
2021-03-10 12:11:42 +00:00
_textToSpeech(sayStr, screenreader,
pitch, rate, srange,
systemLanguage, espeak)
2021-03-10 10:25:41 +00:00
2021-03-17 10:04:49 +00:00
def _desktopReplyToPost(session, postId: str,
baseDir: str, nickname: str, password: str,
domain: str, port: int, httpPrefix: str,
cachedWebfingers: {}, personCache: {},
debug: bool, subject: str,
screenreader: str, systemLanguage: str,
espeak) -> None:
"""Use the desktop client to send a reply to the most recent post
2021-03-10 18:30:00 +00:00
"""
if '://' not in postId:
return
toNickname = getNicknameFromActor(postId)
toDomain, toPort = getDomainFromActor(postId)
sayStr = 'Replying to ' + toNickname + '@' + toDomain
_sayCommand(sayStr, sayStr,
2021-03-10 18:30:00 +00:00
screenreader, systemLanguage, espeak)
sayStr = 'Type your reply message, then press Enter.'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
2021-03-10 18:30:00 +00:00
replyMessage = input()
if not replyMessage:
sayStr = 'No reply was entered.'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
2021-03-10 18:30:00 +00:00
return
replyMessage = replyMessage.strip()
if not replyMessage:
sayStr = 'No reply was entered.'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
2021-03-10 18:30:00 +00:00
return
print('')
2021-03-10 18:30:00 +00:00
sayStr = 'You entered this reply:'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
_sayCommand(replyMessage, replyMessage, screenreader,
systemLanguage, espeak)
2021-03-10 18:30:00 +00:00
sayStr = 'Send this reply, yes or no?'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
2021-03-10 18:30:00 +00:00
yesno = input()
if 'y' not in yesno.lower():
sayStr = 'Abandoning reply'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
2021-03-10 18:30:00 +00:00
return
ccUrl = None
followersOnly = False
attach = None
mediaType = None
attachedImageDescription = None
isArticle = False
subject = None
commentsEnabled = True
sayStr = 'Sending reply'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
2021-03-10 19:31:33 +00:00
if sendPostViaServer(__version__,
baseDir, session, nickname, password,
domain, port,
toNickname, toDomain, toPort, ccUrl,
httpPrefix, replyMessage, followersOnly,
commentsEnabled, attach, mediaType,
attachedImageDescription,
cachedWebfingers, personCache, isArticle,
debug, postId, postId, subject) == 0:
sayStr = 'Reply sent'
else:
sayStr = 'Reply failed'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
2021-03-10 18:30:00 +00:00
2021-03-17 10:04:49 +00:00
def _desktopNewPost(session,
baseDir: str, nickname: str, password: str,
domain: str, port: int, httpPrefix: str,
cachedWebfingers: {}, personCache: {},
debug: bool,
screenreader: str, systemLanguage: str,
espeak) -> None:
"""Use the desktop client to create a new post
"""
sayStr = 'Create new post'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
sayStr = 'Type your post, then press Enter.'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
newMessage = input()
if not newMessage:
sayStr = 'No post was entered.'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
return
newMessage = newMessage.strip()
if not newMessage:
sayStr = 'No post was entered.'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
return
2021-03-21 13:43:04 +00:00
print('')
sayStr = 'You entered this public post:'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
_sayCommand(newMessage, newMessage, screenreader, systemLanguage, espeak)
sayStr = 'Send this post, yes or no?'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
yesno = input()
if 'y' not in yesno.lower():
sayStr = 'Abandoning new post'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
return
ccUrl = None
followersOnly = False
attach = None
mediaType = None
attachedImageDescription = None
isArticle = False
subject = None
commentsEnabled = True
subject = None
sayStr = 'Sending'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
if sendPostViaServer(__version__,
baseDir, session, nickname, password,
domain, port,
None, '#Public', port, ccUrl,
httpPrefix, newMessage, followersOnly,
commentsEnabled, attach, mediaType,
attachedImageDescription,
cachedWebfingers, personCache, isArticle,
debug, None, None, subject) == 0:
sayStr = 'Post sent'
else:
sayStr = 'Post failed'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
def _safeMessage(content: str) -> str:
"""Removes anything potentially unsafe from a string
"""
return content.replace('`', '').replace('$(', '$ (')
def _timelineIsEmpty(boxJson: {}) -> bool:
"""Returns true if the given timeline is empty
"""
empty = False
if not boxJson:
empty = True
else:
if not isinstance(boxJson, dict):
empty = True
elif not boxJson.get('orderedItems'):
empty = True
return empty
def _getFirstItemId(boxJson: {}) -> str:
"""Returns the id of the first item in the timeline
"""
if _timelineIsEmpty(boxJson):
return
if len(boxJson['orderedItems']) == 0:
return
return boxJson['orderedItems'][0]['id']
def _textOnlyContent(content: str) -> str:
"""Remove formatting from the given string
"""
content = urllib.parse.unquote_plus(content)
content = html.unescape(content)
return removeHtml(content)
2021-03-19 14:49:40 +00:00
def _getImageDescription(postJsonObject: {}) -> str:
"""Returns a image description/s on a post
"""
imageDescription = ''
if not postJsonObject['object'].get('attachment'):
return imageDescription
attachList = postJsonObject['object']['attachment']
if not isinstance(attachList, list):
return imageDescription
# for each attachment
for img in attachList:
if not isinstance(img, dict):
continue
if not img.get('name'):
continue
if not isinstance(img['name'], str):
continue
messageStr = img['name']
if messageStr:
messageStr = messageStr.strip()
if not messageStr.endswith('.'):
imageDescription += messageStr + '. '
else:
imageDescription += messageStr + ' '
return imageDescription
def _readLocalBoxPost(session, nickname: str, domain: str,
httpPrefix: str, baseDir: str, boxName: str,
pageNumber: int, index: int, boxJson: {},
2021-03-15 15:14:54 +00:00
systemLanguage: str,
2021-03-18 17:27:46 +00:00
screenreader: str, espeak,
translate: {}, yourActor: str) -> {}:
2021-03-15 15:14:54 +00:00
"""Reads a post from the given timeline
2021-03-22 18:27:48 +00:00
Returns the post json
2021-03-15 15:14:54 +00:00
"""
if _timelineIsEmpty(boxJson):
return {}
2021-03-12 19:55:16 +00:00
postJsonObject = _desktopGetBoxPostObject(boxJson, index)
if not postJsonObject:
return {}
2021-03-12 19:55:16 +00:00
gender = 'They/Them'
2021-03-19 17:23:30 +00:00
boxNameStr = boxName
if boxName.startswith('tl'):
boxNameStr = boxName[2:]
sayStr = 'Reading ' + boxNameStr + ' post ' + str(index) + \
' from page ' + str(pageNumber) + '.'
2021-03-16 18:08:18 +00:00
sayStr2 = sayStr.replace(' dm ', ' DM ')
_sayCommand(sayStr, sayStr2, screenreader, systemLanguage, espeak)
2021-03-12 20:51:04 +00:00
if postJsonObject['type'] == 'Announce':
actor = postJsonObject['actor']
nameStr = getNicknameFromActor(actor)
recentPostsCache = {}
allowLocalNetworkAccess = False
YTReplacementDomain = None
postJsonObject2 = \
downloadAnnounce(session, baseDir,
httpPrefix,
nickname, domain,
postJsonObject,
__version__, translate,
YTReplacementDomain,
allowLocalNetworkAccess,
recentPostsCache, False)
if postJsonObject2:
if postJsonObject2.get('object'):
if postJsonObject2['object'].get('attributedTo') and \
postJsonObject2['object'].get('content'):
actor = postJsonObject2['object']['attributedTo']
nameStr += ' ' + translate['announces'] + ' ' + \
getNicknameFromActor(actor)
sayStr = nameStr
_sayCommand(sayStr, sayStr, screenreader,
systemLanguage, espeak)
if screenreader:
time.sleep(2)
content = \
_textOnlyContent(postJsonObject2['object']['content'])
2021-03-19 14:49:40 +00:00
content += _getImageDescription(postJsonObject2)
messageStr, detectedLinks = \
speakableText(baseDir, content, translate)
sayStr = content
_sayCommand(sayStr, messageStr, screenreader,
systemLanguage, espeak)
return postJsonObject2
return {}
actor = postJsonObject['object']['attributedTo']
nameStr = getNicknameFromActor(actor)
content = _textOnlyContent(postJsonObject['object']['content'])
2021-03-19 14:49:40 +00:00
content += _getImageDescription(postJsonObject)
if isPGPEncrypted(content):
2021-03-16 11:56:24 +00:00
sayStr = 'Encrypted message. Please enter your passphrase.'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
content = pgpDecrypt(content, actor)
2021-03-16 11:56:24 +00:00
if isPGPEncrypted(content):
sayStr = 'Message could not be decrypted'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
return {}
2021-03-16 11:56:24 +00:00
content = _safeMessage(content)
2021-03-18 19:04:58 +00:00
messageStr, detectedLinks = speakableText(baseDir, content, translate)
if screenreader:
time.sleep(2)
2021-03-12 20:51:04 +00:00
2021-03-12 19:55:16 +00:00
# say the speaker's name
_sayCommand(nameStr, nameStr, screenreader,
2021-03-22 18:27:48 +00:00
systemLanguage, espeak, nameStr, gender)
2021-03-12 19:55:16 +00:00
2021-03-19 17:23:30 +00:00
if postJsonObject['object'].get('inReplyTo'):
print('Replying to ' + postJsonObject['object']['inReplyTo'] + '\n')
if screenreader:
time.sleep(2)
2021-03-12 19:55:16 +00:00
# speak the post content
_sayCommand(content, messageStr, screenreader,
2021-03-22 18:27:48 +00:00
systemLanguage, espeak, nameStr, gender)
# if the post is addressed to you then mark it as read
if _postIsToYou(yourActor, postJsonObject):
if isDM(postJsonObject['id']):
_markPostAsRead(yourActor, postJsonObject['id'], 'dm')
else:
_markPostAsRead(yourActor, postJsonObject['id'], 'replies')
return postJsonObject
2021-03-12 19:55:16 +00:00
2021-03-22 18:27:48 +00:00
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) -> {}:
"""Shows the profile of the actor for the given post
Returns the actor json
"""
if _timelineIsEmpty(boxJson):
return {}
postJsonObject = _desktopGetBoxPostObject(boxJson, index)
if not postJsonObject:
return {}
actor = None
if postJsonObject['type'] == 'Announce':
nickname = getNicknameFromActor(postJsonObject['object'])
if nickname:
nickStr = '/' + nickname + '/'
if nickStr in postJsonObject['object']:
actor = \
postJsonObject['object'].split(nickStr)[0] + \
'/' + nickname
else:
actor = postJsonObject['object']['attributedTo']
if not actor:
return {}
isHttp = False
if 'http://' in actor:
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)
return actorJson
def _desktopGetBoxPostObject(boxJson: {}, index: int) -> {}:
"""Gets the post with the given index from the timeline
"""
ctr = 0
for postJsonObject in boxJson['orderedItems']:
if not postJsonObject.get('type'):
continue
if not postJsonObject.get('object'):
continue
if postJsonObject['type'] == 'Announce':
if not isinstance(postJsonObject['object'], str):
continue
ctr += 1
if ctr == index:
return postJsonObject
continue
if not isinstance(postJsonObject['object'], dict):
continue
if not postJsonObject['object'].get('published'):
continue
if not postJsonObject['object'].get('content'):
continue
ctr += 1
if ctr == index:
return postJsonObject
return None
2021-03-18 22:16:01 +00:00
def _formatPublished(published: str) -> str:
"""Formats the published time for display on timeline
"""
dateStr = published.split('T')[0]
monthStr = dateStr.split('-')[1]
dayStr = dateStr.split('-')[2]
timeStr = published.split('T')[1]
hourStr = timeStr.split(':')[0]
minStr = timeStr.split(':')[1]
return monthStr + '-' + dayStr + ' ' + hourStr + ':' + minStr + 'Z'
def _padToWidth(content: str, width: int) -> str:
"""Pads the given string to the given width
"""
if len(content) > width:
content = content[:width]
else:
while len(content) < width:
content += ' '
return content
2021-03-19 11:59:14 +00:00
def _desktopShowBox(boxName: str, boxJson: {},
screenreader: str, systemLanguage: str, espeak,
pageNumber=1,
newReplies=False,
newDMs=False) -> bool:
"""Shows online timeline
"""
numberWidth = 2
nameWidth = 16
contentWidth = 50
indent = ' '
# title
_desktopClearScreen()
_desktopShowBanner()
notificationIcons = ''
2021-03-19 17:23:30 +00:00
if boxName.startswith('tl'):
2021-03-19 16:10:14 +00:00
boxNameStr = boxName[2:]
2021-03-19 15:39:16 +00:00
else:
2021-03-19 16:10:14 +00:00
boxNameStr = boxName
titleStr = '\33[7m' + boxNameStr.upper() + '\33[0m'
2021-03-22 16:56:13 +00:00
if newDMs:
notificationIcons += ' 📩'
if newReplies:
notificationIcons += ' 📨'
if notificationIcons:
while len(titleStr) < 95 - len(notificationIcons):
titleStr += ' '
titleStr += notificationIcons
print(indent + titleStr + '\n')
if _timelineIsEmpty(boxJson):
2021-03-19 16:10:14 +00:00
boxStr = boxNameStr
if boxName == 'dm':
boxStr = 'DM'
sayStr = indent + 'You have no ' + boxStr + ' posts yet.'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
print('')
return False
ctr = 1
for postJsonObject in boxJson['orderedItems']:
if not postJsonObject.get('type'):
continue
if postJsonObject['type'] == 'Announce':
if postJsonObject.get('actor') and \
postJsonObject.get('object'):
if isinstance(postJsonObject['object'], str):
authorActor = postJsonObject['actor']
name = getNicknameFromActor(authorActor) + ''
name = _padToWidth(name, nameWidth)
ctrStr = str(ctr)
posStr = _padToWidth(ctrStr, numberWidth)
published = _formatPublished(postJsonObject['published'])
announcedNickname = \
getNicknameFromActor(postJsonObject['object'])
announcedDomain, announcedPort = \
getDomainFromActor(postJsonObject['object'])
announcedHandle = announcedNickname + '@' + announcedDomain
print(indent + str(posStr) + ' | ' + name + ' | ' +
published + ' | ' +
_padToWidth(announcedHandle, contentWidth))
ctr += 1
continue
if not postJsonObject.get('object'):
continue
if not isinstance(postJsonObject['object'], dict):
continue
if not postJsonObject['object'].get('published'):
continue
if not postJsonObject['object'].get('content'):
continue
ctrStr = str(ctr)
posStr = _padToWidth(ctrStr, numberWidth)
authorActor = postJsonObject['object']['attributedTo']
contentWarning = None
if postJsonObject['object'].get('summary'):
contentWarning = '' + \
_padToWidth(postJsonObject['object']['summary'],
contentWidth)
name = getNicknameFromActor(authorActor)
# append icons to the end of the name
2021-03-18 20:11:28 +00:00
spaceAdded = False
2021-03-18 19:43:10 +00:00
if postJsonObject['object'].get('inReplyTo'):
2021-03-18 20:11:28 +00:00
if not spaceAdded:
spaceAdded = True
name += ' '
name += ''
2021-03-18 20:04:49 +00:00
likesCount = noOfLikes(postJsonObject)
if likesCount > 10:
likesCount = 10
for like in range(likesCount):
2021-03-18 20:11:28 +00:00
if not spaceAdded:
spaceAdded = True
name += ' '
2021-03-18 20:04:49 +00:00
name += ''
name = _padToWidth(name, nameWidth)
published = _formatPublished(postJsonObject['published'])
content = _textOnlyContent(postJsonObject['object']['content'])
if boxName != 'dm':
if isDM(postJsonObject):
content = '📧' + content
if not contentWarning:
if isPGPEncrypted(content):
content = '🔒' + content
elif '://' in content:
content = '🔗' + content
content = _padToWidth(content, contentWidth)
else:
# display content warning
if isPGPEncrypted(content):
content = '🔒' + contentWarning
else:
if '://' in content:
content = '🔗' + contentWarning
else:
content = contentWarning
2021-03-21 12:15:10 +00:00
if postJsonObject['object'].get('ignores'):
content = '🔇'
2021-03-21 13:20:07 +00:00
if postJsonObject['object'].get('bookmarks'):
2021-03-21 16:09:18 +00:00
content = '🔖' + content
print(indent + str(posStr) + ' | ' + name + ' | ' +
published + ' | ' + content)
ctr += 1
print('')
# say the post number range
2021-03-19 16:10:14 +00:00
sayStr = indent + boxNameStr + ' page ' + str(pageNumber) + \
' containing ' + str(ctr - 1) + ' posts. '
if newDMs and boxName != 'dm':
sayStr += \
'Use \33[3mshow dm\33[0m to view direct messages.'
2021-03-19 16:10:14 +00:00
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')
_sayCommand(sayStr, sayStr2, screenreader, systemLanguage, espeak)
print('')
return True
2021-03-17 10:04:49 +00:00
def _desktopNewDM(session, toHandle: str,
baseDir: str, nickname: str, password: str,
domain: str, port: int, httpPrefix: str,
cachedWebfingers: {}, personCache: {},
debug: bool,
screenreader: str, systemLanguage: str,
espeak) -> None:
"""Use the desktop client to create a new direct message
2021-03-14 10:28:48 +00:00
which can include multiple destination handles
"""
if ' ' in toHandle:
handlesList = toHandle.split(' ')
elif ',' in toHandle:
handlesList = toHandle.split(',')
elif ';' in toHandle:
handlesList = toHandle.split(';')
else:
handlesList = [toHandle]
for handle in handlesList:
handle = handle.strip()
2021-03-17 10:04:49 +00:00
_desktopNewDMbase(session, handle,
baseDir, nickname, password,
domain, port, httpPrefix,
cachedWebfingers, personCache,
debug,
screenreader, systemLanguage,
espeak)
2021-03-14 10:28:48 +00:00
2021-03-17 10:04:49 +00:00
def _desktopNewDMbase(session, toHandle: str,
baseDir: str, nickname: str, password: str,
domain: str, port: int, httpPrefix: str,
cachedWebfingers: {}, personCache: {},
debug: bool,
screenreader: str, systemLanguage: str,
espeak) -> None:
"""Use the desktop client to create a new direct message
2021-03-11 12:24:20 +00:00
"""
toPort = port
if '://' in toHandle:
toNickname = getNicknameFromActor(toHandle)
toDomain, toPort = getDomainFromActor(toHandle)
toHandle = toNickname + '@' + toDomain
else:
if toHandle.startswith('@'):
toHandle = toHandle[1:]
toNickname = toHandle.split('@')[0]
toDomain = toHandle.split('@')[1]
sayStr = 'Create new direct message to ' + toHandle
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
sayStr = 'Type your direct message, then press Enter.'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
newMessage = input()
if not newMessage:
sayStr = 'No direct message was entered.'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
return
newMessage = newMessage.strip()
if not newMessage:
sayStr = 'No direct message was entered.'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
return
sayStr = 'You entered this direct message to ' + toHandle + ':'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
_sayCommand(newMessage, newMessage, screenreader, systemLanguage, espeak)
ccUrl = None
followersOnly = False
attach = None
mediaType = None
attachedImageDescription = None
isArticle = False
subject = None
commentsEnabled = True
subject = None
# if there is a local PGP key then attempt to encrypt the DM
# using the PGP public key of the recipient
if hasLocalPGPkey():
sayStr = \
'Local PGP key detected...' + \
'Fetching PGP public key for ' + toHandle
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
paddedMessage = newMessage
if len(paddedMessage) < 32:
# add some padding before and after
# This is to guard against cribs based on small messages, like "Hi"
for before in range(randint(1, 16)):
paddedMessage = ' ' + paddedMessage
for after in range(randint(1, 16)):
paddedMessage += ' '
cipherText = \
pgpEncryptToActor(paddedMessage, toHandle)
if not cipherText:
sayStr = \
toHandle + ' has no PGP public key. ' + \
'Your message will be sent in clear text'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
else:
newMessage = cipherText
sayStr = 'Message encrypted'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
sayStr = 'Send this direct message, yes or no?'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
yesno = input()
if 'y' not in yesno.lower():
sayStr = 'Abandoning new direct message'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
return
2021-03-11 12:24:20 +00:00
sayStr = 'Sending'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
if sendPostViaServer(__version__,
baseDir, session, nickname, password,
domain, port,
toNickname, toDomain, toPort, ccUrl,
httpPrefix, newMessage, followersOnly,
commentsEnabled, attach, mediaType,
attachedImageDescription,
cachedWebfingers, personCache, isArticle,
debug, None, None, subject) == 0:
sayStr = 'Direct message sent'
else:
sayStr = 'Direct message failed'
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
2021-03-17 10:04:49 +00:00
def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
nickname: str, domain: str, port: int,
password: str, screenreader: str,
systemLanguage: str,
notificationSounds: bool,
notificationType: str,
noKeyPress: bool,
storeInboxPosts: bool,
showNewPosts: bool,
2021-03-18 17:27:46 +00:00
language: str,
2021-03-17 10:04:49 +00:00
debug: bool) -> None:
"""Runs the desktop and screen reader client,
which announces new inbox items
2021-03-04 13:57:30 +00:00
"""
2021-03-15 14:30:59 +00:00
indent = ' '
2021-03-15 13:51:21 +00:00
if showNewPosts:
indent = ''
2021-03-17 10:04:49 +00:00
_desktopClearScreen()
_desktopShowBanner()
2021-03-14 10:41:21 +00:00
2021-03-10 10:25:41 +00:00
espeak = None
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-15 13:51:21 +00:00
sayStr = indent + 'Running ' + screenreader + ' for ' + \
nickname + '@' + domain
_sayCommand(sayStr, sayStr, screenreader,
2021-03-10 10:49:45 +00:00
systemLanguage, espeak)
2021-03-09 21:30:23 +00:00
else:
2021-03-15 13:51:21 +00:00
print(indent + 'Running desktop notifications for ' +
nickname + '@' + domain)
if notificationSounds:
2021-03-15 13:51:21 +00:00
sayStr = indent + 'Notification sounds on'
else:
2021-03-15 13:51:21 +00:00
sayStr = indent + 'Notification sounds off'
_sayCommand(sayStr, sayStr, screenreader,
2021-03-10 10:49:45 +00:00
systemLanguage, espeak)
currTimeline = 'inbox'
pageNumber = 1
2021-03-10 10:51:06 +00:00
postJsonObject = {}
2021-03-10 10:25:41 +00:00
originalScreenReader = screenreader
2021-03-22 13:43:20 +00:00
soundsDir = 'theme/default/sounds/'
# prevSay = ''
# prevCalendar = False
# prevFollow = False
# prevLike = ''
# prevShare = False
2021-03-22 13:43:20 +00:00
dmSoundFilename = soundsDir + 'dm.ogg'
replySoundFilename = soundsDir + 'reply.ogg'
# calendarSoundFilename = soundsDir + 'calendar.ogg'
# followSoundFilename = soundsDir + 'follow.ogg'
# likeSoundFilename = soundsDir + 'like.ogg'
# shareSoundFilename = soundsDir + 'share.ogg'
player = 'ffplay'
2021-03-10 12:37:44 +00:00
nameStr = None
gender = None
messageStr = None
2021-03-11 10:52:06 +00:00
content = None
2021-03-10 13:04:22 +00:00
cachedWebfingers = {}
personCache = {}
newRepliesExist = False
newDMsExist = False
2021-03-17 20:18:00 +00:00
pgpKeyUpload = False
2021-03-18 17:30:47 +00:00
sayStr = indent + 'Loading translations file'
2021-03-18 17:27:46 +00:00
_sayCommand(sayStr, sayStr, screenreader,
systemLanguage, espeak)
translate, systemLanguage = \
loadTranslationsFromFile(baseDir, language)
sayStr = indent + 'Connecting...'
_sayCommand(sayStr, sayStr, screenreader,
systemLanguage, espeak)
session = createSession(proxyType)
2021-03-18 17:30:47 +00:00
sayStr = indent + '/q or /quit to exit'
_sayCommand(sayStr, sayStr, screenreader,
systemLanguage, espeak)
domainFull = getFullDomain(domain, port)
yourActor = httpPrefix + '://' + domainFull + '/users/' + nickname
2021-03-22 18:27:48 +00:00
actorJson = None
2021-03-22 13:43:20 +00:00
notifyJson = {
"dmPostId": "Initial",
"dmNotify": False,
"dmNotifyChanged": False,
"repliesPostId": "Initial",
"repliesNotify": False,
"repliesNotifyChanged": False
}
prevTimelineFirstId = ''
while (1):
2021-03-17 20:18:00 +00:00
if not pgpKeyUpload:
2021-03-18 17:37:14 +00:00
sayStr = indent + 'Uploading PGP public key'
_sayCommand(sayStr, sayStr, screenreader,
systemLanguage, espeak)
2021-03-18 17:42:24 +00:00
pgpPublicKeyUpload(baseDir, session,
nickname, password,
domain, port, httpPrefix,
cachedWebfingers, personCache,
debug, False)
2021-03-18 17:37:14 +00:00
sayStr = indent + 'PGP public key uploaded'
_sayCommand(sayStr, sayStr, screenreader,
systemLanguage, espeak)
2021-03-17 20:18:00 +00:00
pgpKeyUpload = True
boxJson = c2sBoxJson(baseDir, session,
nickname, password,
domain, port, httpPrefix,
currTimeline, pageNumber,
debug)
2021-03-22 13:44:14 +00:00
if not (currTimeline == 'inbox' and pageNumber == 1):
# monitor the inbox to generate notifications
inboxJson = c2sBoxJson(baseDir, session,
nickname, password,
domain, port, httpPrefix,
2021-03-22 13:51:54 +00:00
'inbox', 1, debug)
else:
inboxJson = boxJson
2021-03-22 16:56:13 +00:00
newDMsExist = False
newRepliesExist = False
if inboxJson:
_newDesktopNotifications(yourActor, inboxJson, notifyJson)
if notifyJson.get('dmNotify'):
2021-03-22 16:56:13 +00:00
newDMsExist = True
2021-03-22 13:43:20 +00:00
if notifyJson.get('dmNotifyChanged'):
_desktopNotification(notificationType,
"Epicyon",
"New DM " + yourActor + '/dm')
_playNotificationSound(dmSoundFilename, player)
if notifyJson.get('repliesNotify'):
2021-03-22 16:56:13 +00:00
newRepliesExist = True
2021-03-22 13:43:20 +00:00
if notifyJson.get('repliesNotifyChanged'):
_desktopNotification(notificationType,
"Epicyon",
"New reply " + yourActor + '/replies')
_playNotificationSound(replySoundFilename, player)
if boxJson:
timelineFirstId = _getFirstItemId(boxJson)
if timelineFirstId != prevTimelineFirstId:
_desktopClearScreen()
2021-03-19 11:59:14 +00:00
_desktopShowBox(currTimeline, boxJson,
None, systemLanguage, espeak,
pageNumber,
newRepliesExist,
newDMsExist)
prevTimelineFirstId = timelineFirstId
2021-03-19 15:31:16 +00:00
else:
session = createSession(proxyType)
2021-03-04 13:57:30 +00:00
# wait for a while, or until a key is pressed
if noKeyPress:
time.sleep(10)
else:
commandStr = _desktopWaitForCmd(30, debug)
2021-03-17 10:04:49 +00:00
if commandStr:
2021-03-21 13:29:56 +00:00
refreshTimeline = False
2021-03-17 10:04:49 +00:00
if commandStr.startswith('/'):
commandStr = commandStr[1:]
if commandStr == 'q' or \
commandStr == 'quit' or \
commandStr == 'exit':
2021-03-10 10:46:50 +00:00
sayStr = 'Quit'
_sayCommand(sayStr, sayStr, screenreader,
2021-03-10 10:46:50 +00:00
systemLanguage, espeak)
2021-03-10 18:31:45 +00:00
if screenreader:
2021-03-17 10:04:49 +00:00
commandStr = _desktopWaitForCmd(2, debug)
2021-03-04 18:05:46 +00:00
break
2021-03-17 10:04:49 +00:00
elif commandStr.startswith('show dm'):
pageNumber = 1
prevTimelineFirstId = ''
2021-03-12 19:13:01 +00:00
currTimeline = 'dm'
boxJson = c2sBoxJson(baseDir, session,
nickname, password,
domain, port, httpPrefix,
currTimeline, pageNumber,
debug)
if boxJson:
2021-03-19 11:59:14 +00:00
_desktopShowBox(currTimeline, boxJson,
screenreader, systemLanguage, espeak,
pageNumber,
newRepliesExist, newDMsExist)
newDMsExist = False
2021-03-17 10:04:49 +00:00
elif commandStr.startswith('show rep'):
pageNumber = 1
prevTimelineFirstId = ''
2021-03-19 15:39:16 +00:00
currTimeline = 'tlreplies'
boxJson = c2sBoxJson(baseDir, session,
nickname, password,
domain, port, httpPrefix,
currTimeline, pageNumber,
debug)
if boxJson:
2021-03-19 11:59:14 +00:00
_desktopShowBox(currTimeline, boxJson,
screenreader, systemLanguage, espeak,
pageNumber,
newRepliesExist, newDMsExist)
# Turn off the replies indicator
newRepliesExist = False
2021-03-19 21:34:38 +00:00
elif commandStr.startswith('show b'):
pageNumber = 1
prevTimelineFirstId = ''
currTimeline = 'tlbookmarks'
boxJson = c2sBoxJson(baseDir, session,
nickname, password,
domain, port, httpPrefix,
currTimeline, pageNumber,
debug)
if boxJson:
_desktopShowBox(currTimeline, boxJson,
screenreader, systemLanguage, espeak,
pageNumber,
newRepliesExist, newDMsExist)
# Turn off the replies indicator
newRepliesExist = False
2021-03-19 15:28:16 +00:00
elif (commandStr.startswith('show sen') or
commandStr.startswith('show out')):
pageNumber = 1
prevTimelineFirstId = ''
currTimeline = 'outbox'
boxJson = c2sBoxJson(baseDir, session,
nickname, password,
domain, port, httpPrefix,
currTimeline, pageNumber,
debug)
if boxJson:
2021-03-19 11:59:14 +00:00
_desktopShowBox(currTimeline, boxJson,
screenreader, systemLanguage, espeak,
pageNumber,
newRepliesExist, newDMsExist)
2021-03-17 10:04:49 +00:00
elif (commandStr == 'show' or commandStr.startswith('show in') or
commandStr == 'clear'):
pageNumber = 1
prevTimelineFirstId = ''
2021-03-12 19:13:01 +00:00
currTimeline = 'inbox'
2021-03-21 13:29:56 +00:00
refreshTimeline = True
2021-03-17 10:04:49 +00:00
elif commandStr.startswith('next'):
pageNumber += 1
prevTimelineFirstId = ''
2021-03-21 13:29:56 +00:00
refreshTimeline = True
2021-03-17 10:04:49 +00:00
elif commandStr.startswith('prev'):
pageNumber -= 1
if pageNumber < 1:
pageNumber = 1
prevTimelineFirstId = ''
boxJson = c2sBoxJson(baseDir, session,
nickname, password,
domain, port, httpPrefix,
currTimeline, pageNumber,
debug)
if boxJson:
2021-03-19 11:59:14 +00:00
_desktopShowBox(currTimeline, boxJson,
screenreader, systemLanguage, espeak,
pageNumber,
newRepliesExist, newDMsExist)
2021-03-17 10:04:49 +00:00
elif commandStr.startswith('read ') or commandStr == 'read':
if commandStr == 'read':
2021-03-16 14:06:05 +00:00
postIndexStr = '1'
else:
2021-03-17 10:04:49 +00:00
postIndexStr = commandStr.split('read ')[1]
if boxJson and postIndexStr.isdigit():
2021-03-21 20:17:56 +00:00
_desktopShowBox(currTimeline, boxJson,
screenreader, systemLanguage,
espeak, pageNumber,
newRepliesExist, newDMsExist)
2021-03-12 19:55:16 +00:00
postIndex = int(postIndexStr)
postJsonObject = \
_readLocalBoxPost(session, nickname, domain,
httpPrefix, baseDir, currTimeline,
pageNumber, postIndex, boxJson,
systemLanguage, screenreader,
espeak, translate, yourActor)
2021-03-12 19:55:16 +00:00
print('')
2021-03-22 18:27:48 +00:00
elif commandStr.startswith('profile ') or commandStr == 'profile':
if commandStr == 'profile':
postIndexStr = '1'
else:
postIndexStr = commandStr.split('profile ')[1]
if boxJson and postIndexStr.isdigit():
_desktopShowBox(currTimeline, boxJson,
screenreader, systemLanguage,
espeak, pageNumber,
newRepliesExist, newDMsExist)
postIndex = int(postIndexStr)
actorJson = \
_showProfile(session, nickname, domain,
httpPrefix, baseDir, currTimeline,
pageNumber, postIndex, boxJson,
systemLanguage, screenreader,
espeak, translate, yourActor)
print('')
2021-03-17 10:04:49 +00:00
elif commandStr == 'reply' or commandStr == 'r':
if postJsonObject:
if postJsonObject.get('id'):
postId = postJsonObject['id']
subject = None
if postJsonObject['object'].get('summary'):
subject = postJsonObject['object']['summary']
sessionReply = createSession(proxyType)
_desktopReplyToPost(sessionReply, postId,
baseDir, nickname, password,
domain, port, httpPrefix,
cachedWebfingers, personCache,
debug, subject,
screenreader, systemLanguage,
espeak)
2021-03-21 13:29:56 +00:00
refreshTimeline = True
print('')
2021-03-17 10:04:49 +00:00
elif (commandStr == 'post' or commandStr == 'p' or
commandStr == 'send' or
commandStr.startswith('dm ') or
commandStr.startswith('direct message ') or
commandStr.startswith('post ') or
commandStr.startswith('send ')):
sessionPost = createSession(proxyType)
2021-03-17 10:04:49 +00:00
if commandStr.startswith('dm ') or \
commandStr.startswith('direct message ') or \
commandStr.startswith('post ') or \
commandStr.startswith('send '):
commandStr = commandStr.replace(' to ', ' ')
commandStr = commandStr.replace(' dm ', ' ')
commandStr = commandStr.replace(' DM ', ' ')
2021-03-11 12:24:20 +00:00
# direct message
2021-03-11 12:30:29 +00:00
toHandle = None
2021-03-17 10:04:49 +00:00
if commandStr.startswith('post '):
toHandle = commandStr.split('post ', 1)[1]
elif commandStr.startswith('send '):
toHandle = commandStr.split('send ', 1)[1]
elif commandStr.startswith('dm '):
toHandle = commandStr.split('dm ', 1)[1]
elif commandStr.startswith('direct message '):
toHandle = commandStr.split('direct message ', 1)[1]
2021-03-11 12:30:29 +00:00
if toHandle:
2021-03-17 10:04:49 +00:00
_desktopNewDM(sessionPost, toHandle,
baseDir, nickname, password,
domain, port, httpPrefix,
cachedWebfingers, personCache,
debug,
screenreader, systemLanguage,
espeak)
2021-03-21 13:43:04 +00:00
refreshTimeline = True
2021-03-11 12:24:20 +00:00
else:
# public post
2021-03-17 10:04:49 +00:00
_desktopNewPost(sessionPost,
baseDir, nickname, password,
domain, port, httpPrefix,
cachedWebfingers, personCache,
debug,
screenreader, systemLanguage,
espeak)
2021-03-21 13:43:04 +00:00
refreshTimeline = True
2021-03-10 18:30:00 +00:00
print('')
2021-03-18 20:56:08 +00:00
elif commandStr == 'like' or commandStr.startswith('like '):
currIndex = 0
if ' ' in commandStr:
postIndex = commandStr.split(' ')[-1].strip()
if postIndex.isdigit():
currIndex = int(postIndex)
if currIndex > 0 and boxJson:
postJsonObject = \
_desktopGetBoxPostObject(boxJson, currIndex)
if postJsonObject:
if postJsonObject.get('id'):
likeActor = postJsonObject['object']['attributedTo']
sayStr = 'Liking post by ' + \
getNicknameFromActor(likeActor)
_sayCommand(sayStr, sayStr,
screenreader,
systemLanguage, espeak)
sessionLike = createSession(proxyType)
sendLikeViaServer(baseDir, sessionLike,
2021-03-10 13:07:24 +00:00
nickname, password,
domain, port, httpPrefix,
postJsonObject['id'],
2021-03-10 13:07:24 +00:00
cachedWebfingers, personCache,
False, __version__)
2021-03-21 13:29:56 +00:00
refreshTimeline = True
print('')
2021-03-21 12:31:48 +00:00
elif (commandStr == 'undo mute' or
commandStr == 'undo ignore' or
commandStr == 'remove mute' or
commandStr == 'rm mute' or
commandStr == 'unmute' or
commandStr == 'unignore' or
commandStr == 'mute undo' or
commandStr.startswith('undo mute ') or
commandStr.startswith('undo ignore ') or
commandStr.startswith('remove mute ') or
commandStr.startswith('remove ignore ') or
commandStr.startswith('unignore ') or
commandStr.startswith('unmute ')):
currIndex = 0
if ' ' in commandStr:
postIndex = commandStr.split(' ')[-1].strip()
if postIndex.isdigit():
currIndex = int(postIndex)
if currIndex > 0 and boxJson:
postJsonObject = \
_desktopGetBoxPostObject(boxJson, currIndex)
if postJsonObject:
if postJsonObject.get('id'):
muteActor = postJsonObject['object']['attributedTo']
sayStr = 'Unmuting post by ' + \
getNicknameFromActor(muteActor)
_sayCommand(sayStr, sayStr,
screenreader,
systemLanguage, espeak)
sessionMute = createSession(proxyType)
sendUndoMuteViaServer(baseDir, sessionMute,
nickname, password,
domain, port,
httpPrefix, postJsonObject['id'],
cachedWebfingers, personCache,
False, __version__)
2021-03-21 13:29:56 +00:00
refreshTimeline = True
2021-03-21 12:31:48 +00:00
print('')
elif (commandStr == 'mute' or
commandStr == 'ignore' or
commandStr.startswith('mute ') or
commandStr.startswith('ignore ')):
currIndex = 0
if ' ' in commandStr:
postIndex = commandStr.split(' ')[-1].strip()
if postIndex.isdigit():
currIndex = int(postIndex)
if currIndex > 0 and boxJson:
postJsonObject = \
_desktopGetBoxPostObject(boxJson, currIndex)
if postJsonObject:
if postJsonObject.get('id'):
muteActor = postJsonObject['object']['attributedTo']
sayStr = 'Muting post by ' + \
getNicknameFromActor(muteActor)
_sayCommand(sayStr, sayStr,
screenreader,
systemLanguage, espeak)
sessionMute = createSession(proxyType)
sendMuteViaServer(baseDir, sessionMute,
nickname, password,
domain, port,
httpPrefix, postJsonObject['id'],
cachedWebfingers, personCache,
False, __version__)
2021-03-21 13:29:56 +00:00
refreshTimeline = True
2021-03-21 12:31:48 +00:00
print('')
2021-03-20 14:46:24 +00:00
elif (commandStr == 'undo bookmark' or
commandStr == 'remove bookmark' or
commandStr == 'rm bookmark' or
commandStr == 'undo bm' or
commandStr == 'rm bm' or
commandStr == 'remove bm' or
commandStr == 'unbookmark' or
commandStr == 'bookmark undo' or
commandStr == 'bm undo ' or
commandStr.startswith('undo bm ') or
commandStr.startswith('remove bm ') or
commandStr.startswith('undo bookmark ') or
commandStr.startswith('remove bookmark ') or
commandStr.startswith('unbookmark ') or
commandStr.startswith('unbm ')):
2021-03-19 22:04:57 +00:00
currIndex = 0
if ' ' in commandStr:
postIndex = commandStr.split(' ')[-1].strip()
if postIndex.isdigit():
currIndex = int(postIndex)
if currIndex > 0 and boxJson:
postJsonObject = \
_desktopGetBoxPostObject(boxJson, currIndex)
if postJsonObject:
if postJsonObject.get('id'):
2021-03-21 12:31:48 +00:00
bmActor = postJsonObject['object']['attributedTo']
2021-03-20 14:46:24 +00:00
sayStr = 'Unbookmarking post by ' + \
2021-03-21 12:31:48 +00:00
getNicknameFromActor(bmActor)
2021-03-19 22:04:57 +00:00
_sayCommand(sayStr, sayStr,
screenreader,
systemLanguage, espeak)
2021-03-21 12:31:48 +00:00
sessionbm = createSession(proxyType)
sendUndoBookmarkViaServer(baseDir, sessionbm,
2021-03-20 14:46:24 +00:00
nickname, password,
domain, port, httpPrefix,
postJsonObject['id'],
cachedWebfingers,
personCache,
False, __version__)
2021-03-21 13:29:56 +00:00
refreshTimeline = True
2021-03-19 22:04:57 +00:00
print('')
2021-03-20 14:46:24 +00:00
elif (commandStr == 'bookmark' or
commandStr == 'bm' or
commandStr.startswith('bookmark ') or
commandStr.startswith('bm ')):
2021-03-19 22:11:45 +00:00
currIndex = 0
if ' ' in commandStr:
postIndex = commandStr.split(' ')[-1].strip()
if postIndex.isdigit():
currIndex = int(postIndex)
if currIndex > 0 and boxJson:
postJsonObject = \
_desktopGetBoxPostObject(boxJson, currIndex)
if postJsonObject:
if postJsonObject.get('id'):
2021-03-21 12:31:48 +00:00
bmActor = postJsonObject['object']['attributedTo']
2021-03-20 14:46:24 +00:00
sayStr = 'Bookmarking post by ' + \
2021-03-21 12:31:48 +00:00
getNicknameFromActor(bmActor)
2021-03-19 22:11:45 +00:00
_sayCommand(sayStr, sayStr,
screenreader,
systemLanguage, espeak)
2021-03-21 12:31:48 +00:00
sessionbm = createSession(proxyType)
sendBookmarkViaServer(baseDir, sessionbm,
2021-03-20 14:46:24 +00:00
nickname, password,
domain, port, httpPrefix,
postJsonObject['id'],
cachedWebfingers, personCache,
False, __version__)
2021-03-21 13:29:56 +00:00
refreshTimeline = True
2021-03-19 22:11:45 +00:00
print('')
elif commandStr == 'unlike' or commandStr == 'undo like':
2021-03-18 20:56:08 +00:00
currIndex = 0
if ' ' in commandStr:
postIndex = commandStr.split(' ')[-1].strip()
if postIndex.isdigit():
currIndex = int(postIndex)
if currIndex > 0 and boxJson:
postJsonObject = \
_desktopGetBoxPostObject(boxJson, currIndex)
if postJsonObject:
if postJsonObject.get('id'):
unlikeActor = postJsonObject['object']['attributedTo']
sayStr = \
'Undoing like of post by ' + \
getNicknameFromActor(unlikeActor)
_sayCommand(sayStr, sayStr,
screenreader,
systemLanguage, espeak)
sessionUnlike = createSession(proxyType)
sendUndoLikeViaServer(baseDir, sessionUnlike,
nickname, password,
domain, port, httpPrefix,
postJsonObject['id'],
cachedWebfingers, personCache,
False, __version__)
2021-03-21 13:29:56 +00:00
refreshTimeline = True
print('')
2021-03-18 20:56:08 +00:00
elif (commandStr.startswith('announce') or
commandStr.startswith('boost') or
commandStr.startswith('retweet')):
currIndex = 0
if ' ' in commandStr:
postIndex = commandStr.split(' ')[-1].strip()
if postIndex.isdigit():
currIndex = int(postIndex)
if currIndex > 0 and boxJson:
postJsonObject = \
_desktopGetBoxPostObject(boxJson, currIndex)
if postJsonObject:
if postJsonObject.get('id'):
postId = postJsonObject['id']
announceActor = \
postJsonObject['object']['attributedTo']
sayStr = 'Announcing post by ' + \
getNicknameFromActor(announceActor)
_sayCommand(sayStr, sayStr,
screenreader,
systemLanguage, espeak)
sessionAnnounce = createSession(proxyType)
sendAnnounceViaServer(baseDir, sessionAnnounce,
nickname, password,
domain, port,
httpPrefix, postId,
cachedWebfingers, personCache,
True, __version__)
2021-03-21 13:29:56 +00:00
refreshTimeline = True
print('')
2021-03-18 20:56:08 +00:00
elif (commandStr.startswith('unannounce') or
commandStr.startswith('undo announce') or
commandStr.startswith('unboost') or
commandStr.startswith('undo boost') or
commandStr.startswith('undo retweet')):
currIndex = 0
if ' ' in commandStr:
postIndex = commandStr.split(' ')[-1].strip()
if postIndex.isdigit():
currIndex = int(postIndex)
if currIndex > 0 and boxJson:
postJsonObject = \
_desktopGetBoxPostObject(boxJson, currIndex)
if postJsonObject:
if postJsonObject.get('id'):
postId = postJsonObject['id']
announceActor = \
postJsonObject['object']['attributedTo']
sayStr = 'Undoing announce post by ' + \
getNicknameFromActor(announceActor)
_sayCommand(sayStr, sayStr,
screenreader,
systemLanguage, espeak)
sessionAnnounce = createSession(proxyType)
sendUndoAnnounceViaServer(baseDir, sessionAnnounce,
postJsonObject,
nickname, password,
domain, port,
httpPrefix, postId,
cachedWebfingers,
personCache,
True, __version__)
2021-03-21 13:29:56 +00:00
refreshTimeline = True
2021-03-18 20:56:08 +00:00
print('')
2021-03-22 18:27:48 +00:00
elif (commandStr == 'follow' or
commandStr.startswith('follow ')):
if commandStr == 'follow':
if actorJson:
followHandle = actorJson['id']
else:
followHandle = ''
else:
followHandle = commandStr.replace('follow ', '').strip()
if followHandle.startswith('@'):
followHandle = followHandle[1:]
if '@' in followHandle or '://' in followHandle:
followNickname = getNicknameFromActor(followHandle)
followDomain, followPort = \
getDomainFromActor(followHandle)
if followNickname and followDomain:
sayStr = 'Sending follow request to ' + \
followNickname + '@' + followDomain
_sayCommand(sayStr, sayStr,
screenreader, systemLanguage, espeak)
2021-03-10 16:56:27 +00:00
sessionFollow = createSession(proxyType)
2021-03-22 18:27:48 +00:00
sendFollowRequestViaServer(baseDir,
sessionFollow,
nickname, password,
domain, port,
followNickname,
followDomain,
followPort,
httpPrefix,
cachedWebfingers,
personCache,
debug, __version__)
else:
2021-03-22 18:27:48 +00:00
if followHandle:
sayStr = followHandle + ' is not valid'
else:
sayStr = 'Specify a handle to follow'
_sayCommand(sayStr,
screenreader, systemLanguage, espeak)
print('')
2021-03-17 10:04:49 +00:00
elif (commandStr.startswith('unfollow ') or
commandStr.startswith('stop following ')):
followHandle = commandStr.replace('unfollow ', '').strip()
followHandle = followHandle.replace('stop following ', '')
if followHandle.startswith('@'):
followHandle = followHandle[1:]
if '@' in followHandle or '://' in followHandle:
followNickname = getNicknameFromActor(followHandle)
followDomain, followPort = \
getDomainFromActor(followHandle)
if followNickname and followDomain:
sayStr = 'Stop following ' + \
followNickname + '@' + followDomain
_sayCommand(sayStr, sayStr,
screenreader, systemLanguage, espeak)
2021-03-10 16:56:27 +00:00
sessionUnfollow = createSession(proxyType)
sendUnfollowRequestViaServer(baseDir, sessionUnfollow,
nickname, password,
domain, port,
followNickname,
followDomain,
followPort,
httpPrefix,
cachedWebfingers,
personCache,
debug, __version__)
else:
sayStr = followHandle + ' is not valid'
_sayCommand(sayStr, sayStr,
screenreader, systemLanguage, espeak)
print('')
2021-03-17 10:04:49 +00:00
elif (commandStr == 'repeat' or commandStr == 'replay' or
commandStr == 'rp' or commandStr == 'again' or
commandStr == 'say again'):
2021-03-11 11:09:33 +00:00
if screenreader and nameStr and \
gender and messageStr and content:
sayStr = 'Repeating ' + nameStr
2021-03-11 11:12:01 +00:00
_sayCommand(sayStr, sayStr, screenreader,
2021-03-10 12:37:44 +00:00
systemLanguage, espeak,
nameStr, gender)
time.sleep(2)
_sayCommand(content, messageStr, screenreader,
2021-03-10 12:40:17 +00:00
systemLanguage, espeak,
nameStr, gender)
print('')
2021-03-17 10:04:49 +00:00
elif (commandStr == 'sounds on' or
commandStr == 'sound on' or
commandStr == 'sound'):
2021-03-10 10:34:06 +00:00
sayStr = 'Notification sounds on'
_sayCommand(sayStr, sayStr, screenreader,
2021-03-10 10:32:08 +00:00
systemLanguage, espeak)
notificationSounds = True
2021-03-17 10:04:49 +00:00
elif (commandStr == 'sounds off' or
commandStr == 'sound off' or
commandStr == 'nosound'):
2021-03-10 10:34:06 +00:00
sayStr = 'Notification sounds off'
_sayCommand(sayStr, sayStr, screenreader,
2021-03-10 10:32:08 +00:00
systemLanguage, espeak)
notificationSounds = False
2021-03-17 10:04:49 +00:00
elif (commandStr == 'speak' or
commandStr == 'screen reader on' or
commandStr == 'speaker on' or
commandStr == 'talker on' or
commandStr == 'reader on'):
2021-03-10 10:25:41 +00:00
if originalScreenReader:
screenreader = originalScreenReader
2021-03-10 10:34:06 +00:00
sayStr = 'Screen reader on'
_sayCommand(sayStr, sayStr, screenreader,
2021-03-10 10:25:41 +00:00
systemLanguage, espeak)
else:
print('No --screenreader option was specified')
2021-03-17 10:04:49 +00:00
elif (commandStr == 'mute' or
commandStr == 'screen reader off' or
commandStr == 'speaker off' or
commandStr == 'talker off' or
commandStr == 'reader off'):
2021-03-10 10:25:41 +00:00
if originalScreenReader:
screenreader = None
2021-03-10 10:34:06 +00:00
sayStr = 'Screen reader off'
_sayCommand(sayStr, sayStr, originalScreenReader,
2021-03-10 10:25:41 +00:00
systemLanguage, espeak)
else:
print('No --screenreader option was specified')
2021-03-17 10:04:49 +00:00
elif commandStr.startswith('open'):
2021-03-15 17:00:23 +00:00
currIndex = 0
2021-03-17 10:04:49 +00:00
if ' ' in commandStr:
postIndex = commandStr.split(' ')[-1].strip()
2021-03-15 17:00:23 +00:00
if postIndex.isdigit():
currIndex = int(postIndex)
2021-03-18 19:04:58 +00:00
if currIndex > 0 and boxJson:
postJsonObject = \
_desktopGetBoxPostObject(boxJson, currIndex)
if postJsonObject:
if postJsonObject['type'] == 'Announce':
recentPostsCache = {}
allowLocalNetworkAccess = False
YTReplacementDomain = None
postJsonObject2 = \
downloadAnnounce(session, baseDir,
httpPrefix,
nickname, domain,
postJsonObject,
__version__, translate,
YTReplacementDomain,
allowLocalNetworkAccess,
recentPostsCache, False)
if postJsonObject2:
postJsonObject = postJsonObject2
2021-03-18 19:04:58 +00:00
if postJsonObject:
content = postJsonObject['object']['content']
messageStr, detectedLinks = \
speakableText(baseDir, content, translate)
linkOpened = False
for url in detectedLinks:
if '://' in url:
webbrowser.open(url)
linkOpened = True
if linkOpened:
sayStr = 'Opened web links'
_sayCommand(sayStr, sayStr, originalScreenReader,
systemLanguage, espeak)
else:
sayStr = 'There are no web links to open.'
_sayCommand(sayStr, sayStr, originalScreenReader,
systemLanguage, espeak)
print('')
2021-03-17 10:04:49 +00:00
elif commandStr.startswith('h'):
2021-03-16 23:10:14 +00:00
_desktopHelp()
2021-03-21 18:37:06 +00:00
elif (commandStr == 'delete' or
commandStr == 'rm' or
commandStr.startswith('delete ') or
commandStr.startswith('rm ')):
currIndex = 0
if ' ' in commandStr:
postIndex = commandStr.split(' ')[-1].strip()
if postIndex.isdigit():
currIndex = int(postIndex)
if currIndex > 0 and boxJson:
postJsonObject = \
_desktopGetBoxPostObject(boxJson, currIndex)
if postJsonObject:
if postJsonObject.get('id'):
rmActor = postJsonObject['object']['attributedTo']
if rmActor != yourActor:
2021-03-21 18:37:06 +00:00
sayStr = 'You can only delete your own posts'
_sayCommand(sayStr, sayStr,
screenreader,
systemLanguage, espeak)
else:
2021-03-21 20:05:06 +00:00
print('')
if postJsonObject['object'].get('summary'):
print(postJsonObject['object']['summary'])
print(postJsonObject['object']['content'])
print('')
sayStr = 'Confirm delete, yes or no?'
_sayCommand(sayStr, sayStr, screenreader,
2021-03-21 18:37:06 +00:00
systemLanguage, espeak)
2021-03-21 20:05:06 +00:00
yesno = input()
if 'y' not in yesno.lower():
sayStr = 'Deleting post'
_sayCommand(sayStr, sayStr,
screenreader,
systemLanguage, espeak)
sessionrm = createSession(proxyType)
sendDeleteViaServer(baseDir, sessionrm,
nickname, password,
domain, port,
httpPrefix,
postJsonObject['id'],
cachedWebfingers,
personCache,
False, __version__)
refreshTimeline = True
2021-03-21 18:37:06 +00:00
print('')
2021-03-21 13:29:56 +00:00
if refreshTimeline:
if boxJson:
_desktopShowBox(currTimeline, boxJson,
screenreader, systemLanguage,
espeak, pageNumber,
newRepliesExist, newDMsExist)