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

main
Bob Mottram 2021-03-09 19:57:36 +00:00
commit bb3ea15e34
19 changed files with 323 additions and 156 deletions

View File

@ -2719,7 +2719,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain,
self.server.showPublishedDateOnly,
self.server.peertubeInstances,
self.server.allowLocalNetworkAccess)
self.server.allowLocalNetworkAccess,
self.server.themeName)
if hashtagStr:
msg = hashtagStr.encode('utf-8')
msglen = len(msg)
@ -2772,7 +2773,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain,
self.server.showPublishedDateOnly,
self.server.peertubeInstances,
self.server.allowLocalNetworkAccess)
self.server.allowLocalNetworkAccess,
self.server.themeName)
if historyStr:
msg = historyStr.encode('utf-8')
msglen = len(msg)
@ -2862,7 +2864,8 @@ class PubServer(BaseHTTPRequestHandler):
showPublishedDateOnly,
self.server.defaultTimeline,
self.server.peertubeInstances,
allowLocalNetworkAccess)
allowLocalNetworkAccess,
self.server.themeName)
if profileStr:
msg = profileStr.encode('utf-8')
msglen = len(msg)
@ -4853,8 +4856,7 @@ class PubServer(BaseHTTPRequestHandler):
# only receive DMs from accounts you follow
followDMsFilename = \
baseDir + '/accounts/' + \
nickname + '@' + domain + \
'/.followDMs'
nickname + '@' + domain + '/.followDMs'
if onFinalWelcomeScreen:
# initial default setting created via
# the welcome screen
@ -5988,7 +5990,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain,
self.server.showPublishedDateOnly,
self.server.peertubeInstances,
self.server.allowLocalNetworkAccess)
self.server.allowLocalNetworkAccess,
self.server.themeName)
if hashtagStr:
msg = hashtagStr.encode('utf-8')
msglen = len(msg)
@ -6951,7 +6954,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain,
self.server.showPublishedDateOnly,
self.server.peertubeInstances,
self.server.allowLocalNetworkAccess)
self.server.allowLocalNetworkAccess,
self.server.themeName)
if deleteStr:
deleteStrLen = len(deleteStr)
self._set_headers('text/html', deleteStrLen,
@ -7156,7 +7160,8 @@ class PubServer(BaseHTTPRequestHandler):
ytDomain,
self.server.showPublishedDateOnly,
peertubeInstances,
self.server.allowLocalNetworkAccess)
self.server.allowLocalNetworkAccess,
self.server.themeName)
msg = msg.encode('utf-8')
msglen = len(msg)
self._set_headers('text/html', msglen,
@ -7243,7 +7248,8 @@ class PubServer(BaseHTTPRequestHandler):
ytDomain,
self.server.showPublishedDateOnly,
peertubeInstances,
self.server.allowLocalNetworkAccess)
self.server.allowLocalNetworkAccess,
self.server.themeName)
msg = msg.encode('utf-8')
msglen = len(msg)
self._set_headers('text/html', msglen,
@ -7533,6 +7539,8 @@ class PubServer(BaseHTTPRequestHandler):
cssCache = self.server.cssCache
allowLocalNetworkAccess = \
self.server.allowLocalNetworkAccess
themeName = \
self.server.themeName
msg = \
htmlIndividualPost(cssCache,
recentPostsCache,
@ -7553,7 +7561,8 @@ class PubServer(BaseHTTPRequestHandler):
ytDomain,
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess)
allowLocalNetworkAccess,
themeName)
msg = msg.encode('utf-8')
msglen = len(msg)
self._set_headers('text/html', msglen,
@ -7657,6 +7666,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.peertubeInstances
allowLocalNetworkAccess = \
self.server.allowLocalNetworkAccess
themeName = \
self.server.themeName
msg = \
htmlIndividualPost(self.server.cssCache,
recentPostsCache,
@ -7677,7 +7688,8 @@ class PubServer(BaseHTTPRequestHandler):
ytDomain,
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess)
allowLocalNetworkAccess,
themeName)
msg = msg.encode('utf-8')
msglen = len(msg)
self._set_headers('text/html', msglen,
@ -14668,7 +14680,8 @@ def runDaemon(brochMode: bool,
httpd.maxFollowers,
httpd.allowLocalNetworkAccess,
httpd.peertubeInstances,
verifyAllSignatures), daemon=True)
verifyAllSignatures,
httpd.themeName), daemon=True)
print('Creating scheduled post thread')
httpd.thrPostSchedule = \

View File

@ -58,12 +58,12 @@ from filters import isFiltered
from utils import updateAnnounceCollection
from utils import undoAnnounceCollectionEntry
from utils import dangerousMarkup
from utils import isDM
from utils import isReply
from httpsig import messageContentDigest
from posts import createDirectMessagePost
from posts import validContentWarning
from posts import downloadAnnounce
from posts import isDM
from posts import isReply
from posts import isMuted
from posts import isImageMedia
from posts import sendSignedJson
@ -158,7 +158,8 @@ def _inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int,
allowDeletion: bool, boxname: str,
showPublishedDateOnly: bool,
peertubeInstances: [],
allowLocalNetworkAccess: bool) -> None:
allowLocalNetworkAccess: bool,
themeName: str) -> None:
"""Converts the json post into html and stores it in a cache
This enables the post to be quickly displayed later
"""
@ -176,6 +177,7 @@ def _inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int,
httpPrefix, __version__, boxname, None,
showPublishedDateOnly,
peertubeInstances, allowLocalNetworkAccess,
themeName,
not isDM(postJsonObject),
True, True, False, True)
@ -1290,7 +1292,8 @@ def _receiveAnnounce(recentPostsCache: {},
personCache: {}, messageJson: {}, federationList: [],
debug: bool, translate: {},
YTReplacementDomain: str,
allowLocalNetworkAccess: bool) -> bool:
allowLocalNetworkAccess: bool,
themeName: str) -> bool:
"""Receives an announce activity within the POST section of HTTPServer
"""
if messageJson['type'] != 'Announce':
@ -1408,9 +1411,12 @@ def _receiveAnnounce(recentPostsCache: {},
if isRecentPost(postJsonObject):
if not os.path.isfile(postFilename + '.tts'):
updateSpeaker(baseDir, nickname, domain,
domainFull = getFullDomain(domain, port)
updateSpeaker(baseDir, httpPrefix,
nickname, domain, domainFull,
postJsonObject, personCache,
translate, lookupActor)
translate, lookupActor,
themeName)
ttsFile = open(postFilename + '.tts', "w+")
if ttsFile:
ttsFile.write('\n')
@ -2164,7 +2170,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
showPublishedDateOnly: bool,
allowLocalNetworkAccess: bool,
peertubeInstances: [],
lastBounceMessage: []) -> bool:
lastBounceMessage: [],
themeName: str) -> bool:
""" Anything which needs to be done after initial checks have passed
"""
actor = keyId
@ -2243,7 +2250,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
federationList,
debug, translate,
YTReplacementDomain,
allowLocalNetworkAccess):
allowLocalNetworkAccess,
themeName):
if debug:
print('DEBUG: Announce accepted from ' + actor)
@ -2491,9 +2499,11 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
else:
if boxname == 'inbox':
if isRecentPost(postJsonObject):
updateSpeaker(baseDir, nickname, domain,
domainFull = getFullDomain(domain, port)
updateSpeaker(baseDir, httpPrefix,
nickname, domain, domainFull,
postJsonObject, personCache,
translate, None)
translate, None, themeName)
if not unitTest:
if debug:
print('Saving inbox post as html to cache')
@ -2513,7 +2523,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
boxname,
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess)
allowLocalNetworkAccess,
themeName)
if debug:
timeDiff = \
str(int((time.time() - htmlCacheStartTime) *
@ -2614,7 +2625,8 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
showPublishedDateOnly: bool,
maxFollowers: int, allowLocalNetworkAccess: bool,
peertubeInstances: [],
verifyAllSignatures: bool) -> None:
verifyAllSignatures: bool,
themeName: str) -> None:
"""Processes received items and moves them to the appropriate
directories
"""
@ -3107,7 +3119,8 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
showPublishedDateOnly,
allowLocalNetworkAccess,
peertubeInstances,
lastBounceMessage)
lastBounceMessage,
themeName)
if debug:
pprint(queueJson['post'])

View File

@ -66,6 +66,17 @@ def _speakerPicospeaker(pitch: int, rate: int, systemLanguage: str,
os.system(speakerCmd)
def _playNotificationSound(soundFilename: str, player='ffplay') -> None:
"""Plays a sound
"""
if not os.path.isfile(soundFilename):
return
if player == 'ffplay':
os.system('ffplay ' + soundFilename +
' -autoexit -hide_banner -nodisp')
def runNotificationsClient(baseDir: str, proxyType: str, httpPrefix: str,
nickname: str, domain: str, port: int,
password: str, screenreader: str,
@ -73,64 +84,121 @@ def runNotificationsClient(baseDir: str, proxyType: str, httpPrefix: str,
"""Runs the notifications and screen reader client,
which announces new inbox items
"""
if screenreader == 'espeak':
print('Setting up espeak')
from espeak import espeak
elif screenreader != 'picospeaker':
print(screenreader + ' is not a supported TTS system')
return
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
print('Running ' + screenreader + ' for ' + nickname + '@' + domain)
print('Running ' + screenreader + ' for ' + nickname + '@' + domain)
prevSay = ''
prevDM = False
prevReply = False
prevCalendar = False
prevFollow = False
prevLike = ''
prevShare = False
dmSoundFilename = 'dm.ogg'
replySoundFilename = 'reply.ogg'
calendarSoundFilename = 'calendar.ogg'
followSoundFilename = 'follow.ogg'
likeSoundFilename = 'like.ogg'
shareSoundFilename = 'share.ogg'
player = 'ffplay'
while (1):
session = createSession(proxyType)
speakerJson = \
getSpeakerFromServer(baseDir, session, nickname, password,
domain, port, httpPrefix, True, __version__)
if speakerJson:
if speakerJson['say'] != prevSay:
if speakerJson.get('name'):
nameStr = speakerJson['name']
gender = 'They/Them'
if speakerJson.get('gender'):
gender = speakerJson['gender']
if speakerJson.get('notify'):
soundsDir = 'theme/default/sounds'
if speakerJson['notify'].get('theme'):
soundsDir = \
'theme/' + speakerJson['notify']['theme'] + '/sounds'
if not os.path.isdir(soundsDir):
soundsDir = 'theme/default/sounds'
if dmSoundFilename:
if speakerJson['notify']['dm'] != prevDM:
_playNotificationSound(soundsDir + '/' +
dmSoundFilename, player)
elif replySoundFilename:
if speakerJson['notify']['reply'] != prevReply:
_playNotificationSound(soundsDir + '/' +
replySoundFilename, player)
elif calendarSoundFilename:
if speakerJson['notify']['calendar'] != prevCalendar:
_playNotificationSound(soundsDir + '/' +
calendarSoundFilename, player)
elif followSoundFilename:
if speakerJson['notify']['followRequests'] != prevFollow:
_playNotificationSound(soundsDir + '/' +
followSoundFilename, player)
elif likeSoundFilename:
if speakerJson['notify']['like'] != prevLike:
_playNotificationSound(soundsDir + '/' +
likeSoundFilename, player)
elif shareSoundFilename:
if speakerJson['notify']['share'] != prevShare:
_playNotificationSound(soundsDir + '/' +
shareSoundFilename, player)
# get the speech parameters
pitch = getSpeakerPitch(nameStr, screenreader, gender)
rate = getSpeakerRate(nameStr, screenreader)
srange = getSpeakerRange(nameStr)
prevDM = speakerJson['notify']['dm']
prevReply = speakerJson['notify']['reply']
prevCalendar = speakerJson['notify']['calendar']
prevFollow = speakerJson['notify']['followRequests']
prevLike = speakerJson['notify']['like']
prevShare = speakerJson['notify']['share']
# say the speaker's name
if screenreader == 'espeak':
_speakerEspeak(espeak, pitch, rate, srange, nameStr)
elif screenreader == 'picospeaker':
_speakerPicospeaker(pitch, rate,
systemLanguage, nameStr)
time.sleep(2)
if speakerJson.get('say'):
if speakerJson['say'] != prevSay:
if speakerJson.get('name'):
nameStr = speakerJson['name']
gender = 'They/Them'
if speakerJson.get('gender'):
gender = speakerJson['gender']
# append image description if needed
if not speakerJson.get('imageDescription'):
sayStr = speakerJson['say']
# echo spoken text to the screen
print(html.unescape(nameStr) + ': ' +
html.unescape(speakerJson['say']) + '\n')
else:
sayStr = speakerJson['say'] + '. ' + \
speakerJson['imageDescription']
# echo spoken text to the screen
print(html.unescape(nameStr) + ': ' +
html.unescape(speakerJson['say']) + '\n' +
html.unescape(speakerJson['imageDescription']))
# get the speech parameters
pitch = getSpeakerPitch(nameStr, screenreader, gender)
rate = getSpeakerRate(nameStr, screenreader)
srange = getSpeakerRange(nameStr)
# speak the post content
if screenreader == 'espeak':
_speakerEspeak(espeak, pitch, rate, srange, sayStr)
elif screenreader == 'picospeaker':
_speakerPicospeaker(pitch, rate,
systemLanguage, sayStr)
# say the speaker's name
if screenreader == 'espeak':
_speakerEspeak(espeak, pitch, rate, srange,
nameStr)
elif screenreader == 'picospeaker':
_speakerPicospeaker(pitch, rate,
systemLanguage, nameStr)
time.sleep(2)
prevSay = speakerJson['say']
# append image description if needed
if not speakerJson.get('imageDescription'):
sayStr = speakerJson['say']
# echo spoken text to the screen
print(html.unescape(nameStr) + ': ' +
html.unescape(speakerJson['say']) + '\n')
else:
sayStr = speakerJson['say'] + '. ' + \
speakerJson['imageDescription']
# echo spoken text to the screen
imageDescription = \
html.unescape(speakerJson['imageDescription'])
print(html.unescape(nameStr) + ': ' +
html.unescape(speakerJson['say']) + '\n' +
imageDescription)
# speak the post content
if screenreader == 'espeak':
_speakerEspeak(espeak, pitch, rate, srange, sayStr)
elif screenreader == 'picospeaker':
_speakerPicospeaker(pitch, rate,
systemLanguage, sayStr)
prevSay = speakerJson['say']
# wait for a while, or until a key is pressed
keyPress = _waitForKeypress(30, debug)

View File

@ -2921,34 +2921,6 @@ def createModeration(baseDir: str, nickname: str, domain: str, port: int,
return boxItems
def isDM(postJsonObject: {}) -> bool:
"""Returns true if the given post is a DM
"""
if postJsonObject['type'] != 'Create':
return False
if not postJsonObject.get('object'):
return False
if not isinstance(postJsonObject['object'], dict):
return False
if postJsonObject['object']['type'] != 'Note' and \
postJsonObject['object']['type'] != 'Patch' and \
postJsonObject['object']['type'] != 'EncryptedMessage' and \
postJsonObject['object']['type'] != 'Article':
return False
if postJsonObject['object'].get('moderationStatus'):
return False
fields = ('to', 'cc')
for f in fields:
if not postJsonObject['object'].get(f):
continue
for toAddress in postJsonObject['object'][f]:
if toAddress.endswith('#Public'):
return False
if toAddress.endswith('followers'):
return False
return True
def isImageMedia(session, baseDir: str, httpPrefix: str,
nickname: str, domain: str,
postJsonObject: {}, translate: {},
@ -2992,40 +2964,6 @@ def isImageMedia(session, baseDir: str, httpPrefix: str,
return False
def isReply(postJsonObject: {}, actor: str) -> bool:
"""Returns true if the given post is a reply to the given actor
"""
if postJsonObject['type'] != 'Create':
return False
if not postJsonObject.get('object'):
return False
if not isinstance(postJsonObject['object'], dict):
return False
if postJsonObject['object'].get('moderationStatus'):
return False
if postJsonObject['object']['type'] != 'Note' and \
postJsonObject['object']['type'] != 'EncryptedMessage' and \
postJsonObject['object']['type'] != 'Article':
return False
if postJsonObject['object'].get('inReplyTo'):
if isinstance(postJsonObject['object']['inReplyTo'], str):
if postJsonObject['object']['inReplyTo'].startswith(actor):
return True
if not postJsonObject['object'].get('tag'):
return False
if not isinstance(postJsonObject['object']['tag'], list):
return False
for tag in postJsonObject['object']['tag']:
if not tag.get('type'):
continue
if tag['type'] == 'Mention':
if not tag.get('href'):
continue
if actor in tag['href']:
return True
return False
def _addPostStringToTimeline(postStr: str, boxname: str,
postsInBox: [], boxActor: str) -> bool:
""" is this a valid timeline post?

View File

@ -209,9 +209,9 @@ function notifications {
if [[ "$epicyonLikeFileContent" == *':'* ]]; then
epicyonLikeMessage="Epicyon: $epicyonLikeFileContent"
fi
"${PROJECT_NAME}-notification" -u "$USERNAME" -s "Epicyon" -m "$epicyonLikeMessage" --sensitive yes
sendNotification "$USERNAME" "Epicyon" "$epicyonLikeMessage"
echo "##sent##" > "$epicyonLikeFile"
chown ${PROJECT_NAME}:${PROJECT_NAME} "$epicyonLkeFile"
chown ${PROJECT_NAME}:${PROJECT_NAME} "$epicyonLikeFile"
fi
fi

View File

@ -12,6 +12,8 @@ import random
import urllib.parse
from auth import createBasicAuthHeader
from session import getJson
from utils import isDM
from utils import isReply
from utils import camelCaseSplit
from utils import getDomainFromActor
from utils import getNicknameFromActor
@ -263,7 +265,11 @@ def getSpeakerFromServer(baseDir: str, session,
def _speakerEndpointJson(displayName: str, summary: str,
content: str, imageDescription: str,
links: [], gender: str, postId: str) -> {}:
links: [], gender: str, postId: str,
postDM: bool, postReply: bool,
followRequestsExist: bool,
likedBy: str, postCal: bool,
postShare: bool, themeName: str) -> {}:
"""Returns a json endpoint for the TTS speaker
"""
speakerJson = {
@ -272,7 +278,16 @@ def _speakerEndpointJson(displayName: str, summary: str,
"say": content,
"imageDescription": imageDescription,
"detectedLinks": links,
"id": postId
"id": postId,
"notify": {
"theme": themeName,
"dm": postDM,
"reply": postReply,
"followRequests": followRequestsExist,
"likedBy": likedBy,
"calendar": postCal,
"share": postShare
}
}
if gender:
speakerJson['gender'] = gender
@ -360,9 +375,11 @@ def getSSMLbox(baseDir: str, path: str,
instanceTitle, gender)
def _postToSpeakerJson(baseDir: str, nickname: str, domain: str,
def _postToSpeakerJson(baseDir: str, httpPrefix: str,
nickname: str, domain: str, domainFull: str,
postJsonObject: {}, personCache: {},
translate: {}, announcingActor: str) -> {}:
translate: {}, announcingActor: str,
themeName: str) -> {}:
"""Converts an ActivityPub post into some Json containing
speech synthesis parameters.
NOTE: There currently appears to be no standardized json
@ -429,21 +446,54 @@ def _postToSpeakerJson(baseDir: str, nickname: str, domain: str,
postId = None
if postJsonObject['object'].get('id'):
postId = postJsonObject['object']['id']
actor = httpPrefix + '://' + domainFull + '/users/' + nickname
postDM = isDM(postJsonObject)
postReply = isReply(postJsonObject, actor)
followRequestsExist = False
accountsDir = baseDir + '/accounts/' + nickname + '@' + domainFull
approveFollowsFilename = accountsDir + '/followrequests.txt'
if os.path.isfile(approveFollowsFilename):
with open(approveFollowsFilename, 'r') as fp:
follows = fp.readlines()
if len(follows) > 0:
followRequestsExist = True
likedBy = ''
likeFilename = accountsDir + '/.newLike'
if os.path.isfile(likeFilename):
with open(likeFilename, 'r') as fp:
likedBy = fp.read()
if '##sent##' in likedBy:
likedBy = ''
calendarFilename = accountsDir + '/.newCalendar'
postCal = os.path.isfile(calendarFilename)
shareFilename = accountsDir + '/.newShare'
postShare = os.path.isfile(shareFilename)
return _speakerEndpointJson(speakerName, summary,
content, imageDescription,
detectedLinks, gender, postId)
detectedLinks, gender, postId,
postDM, postReply,
followRequestsExist,
likedBy,
postCal, postShare, themeName)
def updateSpeaker(baseDir: str, nickname: str, domain: str,
def updateSpeaker(baseDir: str, httpPrefix: str,
nickname: str, domain: str, domainFull: str,
postJsonObject: {}, personCache: {},
translate: {}, announcingActor: str) -> None:
translate: {}, announcingActor: str,
themeName: str) -> None:
""" Generates a json file which can be used for TTS announcement
of incoming inbox posts
"""
speakerJson = \
_postToSpeakerJson(baseDir, nickname, domain,
_postToSpeakerJson(baseDir, httpPrefix,
nickname, domain, domainFull,
postJsonObject, personCache,
translate, announcingActor)
translate, announcingActor,
themeName)
speakerFilename = \
baseDir + '/accounts/' + nickname + '@' + domain + '/speaker.json'
saveJson(speakerJson, speakerFilename)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -2068,3 +2068,65 @@ def rejectPostId(baseDir: str, nickname: str, domain: str,
if rejectFile:
rejectFile.write('\n')
rejectFile.close()
def isDM(postJsonObject: {}) -> bool:
"""Returns true if the given post is a DM
"""
if postJsonObject['type'] != 'Create':
return False
if not postJsonObject.get('object'):
return False
if not isinstance(postJsonObject['object'], dict):
return False
if postJsonObject['object']['type'] != 'Note' and \
postJsonObject['object']['type'] != 'Patch' and \
postJsonObject['object']['type'] != 'EncryptedMessage' and \
postJsonObject['object']['type'] != 'Article':
return False
if postJsonObject['object'].get('moderationStatus'):
return False
fields = ('to', 'cc')
for f in fields:
if not postJsonObject['object'].get(f):
continue
for toAddress in postJsonObject['object'][f]:
if toAddress.endswith('#Public'):
return False
if toAddress.endswith('followers'):
return False
return True
def isReply(postJsonObject: {}, actor: str) -> bool:
"""Returns true if the given post is a reply to the given actor
"""
if postJsonObject['type'] != 'Create':
return False
if not postJsonObject.get('object'):
return False
if not isinstance(postJsonObject['object'], dict):
return False
if postJsonObject['object'].get('moderationStatus'):
return False
if postJsonObject['object']['type'] != 'Note' and \
postJsonObject['object']['type'] != 'EncryptedMessage' and \
postJsonObject['object']['type'] != 'Article':
return False
if postJsonObject['object'].get('inReplyTo'):
if isinstance(postJsonObject['object']['inReplyTo'], str):
if postJsonObject['object']['inReplyTo'].startswith(actor):
return True
if not postJsonObject['object'].get('tag'):
return False
if not isinstance(postJsonObject['object']['tag'], list):
return False
for tag in postJsonObject['object']['tag']:
if not tag.get('type'):
continue
if tag['type'] == 'Mention':
if not tag.get('href'):
continue
if actor in tag['href']:
return True
return False

View File

@ -31,7 +31,8 @@ def htmlConfirmDelete(cssCache: {},
YTReplacementDomain: str,
showPublishedDateOnly: bool,
peertubeInstances: [],
allowLocalNetworkAccess: bool) -> str:
allowLocalNetworkAccess: bool,
themeName: str) -> str:
"""Shows a screen asking to confirm the deletion of a post
"""
if '/statuses/' not in messageId:
@ -72,6 +73,7 @@ def htmlConfirmDelete(cssCache: {},
YTReplacementDomain,
showPublishedDateOnly,
peertubeInstances, allowLocalNetworkAccess,
themeName,
False, False, False, False, False)
deletePostStr += '<center>'
deletePostStr += \

View File

@ -30,7 +30,8 @@ def _htmlFrontScreenPosts(recentPostsCache: {}, maxRecentPosts: int,
YTReplacementDomain: str,
showPublishedDateOnly: bool,
peertubeInstances: [],
allowLocalNetworkAccess: bool) -> str:
allowLocalNetworkAccess: bool,
themeName: str) -> str:
"""Shows posts on the front screen of a news instance
These should only be public blog posts from the features timeline
which is the blog timeline of the news actor
@ -71,6 +72,7 @@ def _htmlFrontScreenPosts(recentPostsCache: {}, maxRecentPosts: int,
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess,
themeName,
False, False, False, True, False)
if postStr:
profileStr += postStr + separatorStr
@ -159,7 +161,8 @@ def htmlFrontScreen(rssIconAtTop: bool,
YTReplacementDomain,
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess) + licenseStr
allowLocalNetworkAccess,
theme) + licenseStr
# Footer which is only used for system accounts
profileFooterStr = ' </td>\n'

View File

@ -19,9 +19,9 @@ from like import noOfLikes
from follow import isFollowingActor
from posts import postIsMuted
from posts import getPersonBox
from posts import isDM
from posts import downloadAnnounce
from posts import populateRepliesJson
from utils import isDM
from utils import rejectPostId
from utils import isRecentPost
from utils import getConfigParam
@ -1139,6 +1139,7 @@ def individualPostAsHtml(allowDownloads: bool,
showPublishedDateOnly: bool,
peertubeInstances: [],
allowLocalNetworkAccess: bool,
themeName: str,
showRepeats=True,
showIcons=False,
manuallyApprovesFollowers=False,
@ -1304,9 +1305,11 @@ def individualPostAsHtml(allowDownloads: bool,
postJsonObject['id'])
if announceFilename and postJsonObject.get('actor'):
if not os.path.isfile(announceFilename + '.tts'):
updateSpeaker(baseDir, nickname, domain,
updateSpeaker(baseDir, httpPrefix,
nickname, domain, domainFull,
postJsonObject, personCache,
translate, postJsonObject['actor'])
translate, postJsonObject['actor'],
themeName)
ttsFile = open(announceFilename + '.tts', "w+")
if ttsFile:
ttsFile.write('\n')
@ -1683,7 +1686,8 @@ def htmlIndividualPost(cssCache: {},
YTReplacementDomain: str,
showPublishedDateOnly: bool,
peertubeInstances: [],
allowLocalNetworkAccess: bool) -> str:
allowLocalNetworkAccess: bool,
themeName: str) -> str:
"""Show an individual post as html
"""
postStr = ''
@ -1724,7 +1728,7 @@ def htmlIndividualPost(cssCache: {},
YTReplacementDomain,
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess,
allowLocalNetworkAccess, themeName,
False, authorized, False, False, False)
messageId = removeIdEnding(postJsonObject['id'])
@ -1752,6 +1756,7 @@ def htmlIndividualPost(cssCache: {},
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess,
themeName,
False, authorized,
False, False, False) + postStr
@ -1782,6 +1787,7 @@ def htmlIndividualPost(cssCache: {},
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess,
themeName,
False, authorized,
False, False, False)
cssFilename = baseDir + '/epicyon-profile.css'
@ -1803,7 +1809,8 @@ def htmlPostReplies(cssCache: {},
YTReplacementDomain: str,
showPublishedDateOnly: bool,
peertubeInstances: [],
allowLocalNetworkAccess: bool) -> str:
allowLocalNetworkAccess: bool,
themeName: str) -> str:
"""Show the replies to an individual post as html
"""
repliesStr = ''
@ -1822,6 +1829,7 @@ def htmlPostReplies(cssCache: {},
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess,
themeName,
False, False, False, False, False)
cssFilename = baseDir + '/epicyon-profile.css'

View File

@ -66,7 +66,8 @@ def htmlProfileAfterSearch(cssCache: {},
showPublishedDateOnly: bool,
defaultTimeline: str,
peertubeInstances: [],
allowLocalNetworkAccess: bool) -> str:
allowLocalNetworkAccess: bool,
themeName: str) -> str:
"""Show a profile page after a search for a fediverse address
"""
if hasUsersPath(profileHandle) or '/@' in profileHandle:
@ -300,6 +301,7 @@ def htmlProfileAfterSearch(cssCache: {},
YTReplacementDomain,
showPublishedDateOnly,
peertubeInstances, allowLocalNetworkAccess,
themeName,
False, False, False, False, False)
i += 1
if i >= 20:
@ -804,7 +806,8 @@ def htmlProfile(rssIconAtTop: bool,
YTReplacementDomain,
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess) + licenseStr
allowLocalNetworkAccess,
theme) + licenseStr
elif selected == 'following':
profileStr += \
_htmlProfileFollowing(translate, baseDir, httpPrefix,
@ -856,7 +859,8 @@ def _htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
YTReplacementDomain: str,
showPublishedDateOnly: bool,
peertubeInstances: [],
allowLocalNetworkAccess: bool) -> str:
allowLocalNetworkAccess: bool,
themeName: str) -> str:
"""Shows posts on the profile screen
These should only be public posts
"""
@ -896,6 +900,7 @@ def _htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess,
themeName,
False, False, False, True, False)
if postStr:
profileStr += postStr + separatorStr

View File

@ -527,7 +527,8 @@ def htmlHistorySearch(cssCache: {}, translate: {}, baseDir: str,
YTReplacementDomain: str,
showPublishedDateOnly: bool,
peertubeInstances: [],
allowLocalNetworkAccess: bool) -> str:
allowLocalNetworkAccess: bool,
themeName: str) -> str:
"""Show a page containing search results for your post history
"""
if historysearch.startswith('!'):
@ -604,6 +605,7 @@ def htmlHistorySearch(cssCache: {}, translate: {}, baseDir: str,
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess,
themeName,
showIndividualPostIcons,
showIndividualPostIcons,
False, False, False)
@ -626,7 +628,8 @@ def htmlHashtagSearch(cssCache: {},
YTReplacementDomain: str,
showPublishedDateOnly: bool,
peertubeInstances: [],
allowLocalNetworkAccess: bool) -> str:
allowLocalNetworkAccess: bool,
themeName: str) -> str:
"""Show a page containing search results for a hashtag
"""
if hashtag.startswith('#'):
@ -778,6 +781,7 @@ def htmlHashtagSearch(cssCache: {},
allowLocalNetworkAccess,
showRepeats, showIcons,
manuallyApprovesFollowers,
themeName,
showPublicOnly,
storeToCache)
if postStr:

View File

@ -723,6 +723,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
boxName != 'dm',
showIndividualPostIcons,
manuallyApproveFollowers,
theme,
False, True)
_logTimelineTiming(enableTimingLog,
timelineStartTime, boxName, '12')