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

main
Bob Mottram 2020-08-29 17:56:23 +01:00
commit 14cff36a70
30 changed files with 1022 additions and 201 deletions

View File

@ -121,7 +121,7 @@ def storeBasicCredentials(baseDir: str, nickname: str, password: str) -> bool:
if os.path.isfile(passwordFile): if os.path.isfile(passwordFile):
if nickname + ':' in open(passwordFile).read(): if nickname + ':' in open(passwordFile).read():
with open(passwordFile, "r") as fin: with open(passwordFile, "r") as fin:
with open(passwordFile + '.new', "w") as fout: with open(passwordFile + '.new', 'w+') as fout:
for line in fin: for line in fin:
if not line.startswith(nickname + ':'): if not line.startswith(nickname + ':'):
fout.write(line) fout.write(line)
@ -133,7 +133,7 @@ def storeBasicCredentials(baseDir: str, nickname: str, password: str) -> bool:
with open(passwordFile, 'a+') as passfile: with open(passwordFile, 'a+') as passfile:
passfile.write(storeStr + '\n') passfile.write(storeStr + '\n')
else: else:
with open(passwordFile, "w") as passfile: with open(passwordFile, 'w+') as passfile:
passfile.write(storeStr + '\n') passfile.write(storeStr + '\n')
return True return True
@ -145,7 +145,7 @@ def removePassword(baseDir: str, nickname: str) -> None:
passwordFile = baseDir + '/accounts/passwords' passwordFile = baseDir + '/accounts/passwords'
if os.path.isfile(passwordFile): if os.path.isfile(passwordFile):
with open(passwordFile, "r") as fin: with open(passwordFile, "r") as fin:
with open(passwordFile + '.new', "w") as fout: with open(passwordFile + '.new', 'w+') as fout:
for line in fin: for line in fin:
if not line.startswith(nickname + ':'): if not line.startswith(nickname + ':'):
fout.write(line) fout.write(line)

View File

@ -73,7 +73,7 @@ def noOfBlogReplies(baseDir: str, httpPrefix: str, translate: {},
if lines and removals: if lines and removals:
print('Rewriting ' + postFilename + ' to remove ' + print('Rewriting ' + postFilename + ' to remove ' +
str(len(removals)) + ' entries') str(len(removals)) + ' entries')
with open(postFilename, "w") as f: with open(postFilename, 'w+') as f:
for replyPostId in lines: for replyPostId in lines:
replyPostId = replyPostId.replace('\n', '').replace('\r', '') replyPostId = replyPostId.replace('\n', '').replace('\r', '')
if replyPostId not in removals: if replyPostId not in removals:

View File

@ -14,7 +14,8 @@ from utils import getFileCaseInsensitive
def storePersonInCache(baseDir: str, personUrl: str, def storePersonInCache(baseDir: str, personUrl: str,
personJson: {}, personCache: {}) -> None: personJson: {}, personCache: {},
allowWriteToFile: bool) -> None:
"""Store an actor in the cache """Store an actor in the cache
""" """
currTime = datetime.datetime.utcnow() currTime = datetime.datetime.utcnow()
@ -26,6 +27,7 @@ def storePersonInCache(baseDir: str, personUrl: str,
return return
# store to file # store to file
if allowWriteToFile:
if os.path.isdir(baseDir+'/cache/actors'): if os.path.isdir(baseDir+'/cache/actors'):
cacheFilename = baseDir + '/cache/actors/' + \ cacheFilename = baseDir + '/cache/actors/' + \
personUrl.replace('/', '#')+'.json' personUrl.replace('/', '#')+'.json'
@ -33,18 +35,21 @@ def storePersonInCache(baseDir: str, personUrl: str,
saveJson(personJson, cacheFilename) saveJson(personJson, cacheFilename)
def getPersonFromCache(baseDir: str, personUrl: str, personCache: {}) -> {}: def getPersonFromCache(baseDir: str, personUrl: str, personCache: {},
allowWriteToFile: bool) -> {}:
"""Get an actor from the cache """Get an actor from the cache
""" """
# if the actor is not in memory then try to load it from file # if the actor is not in memory then try to load it from file
loadedFromFile = False loadedFromFile = False
if not personCache.get(personUrl): if not personCache.get(personUrl):
# does the person exist as a cached file?
cacheFilename = baseDir + '/cache/actors/' + \ cacheFilename = baseDir + '/cache/actors/' + \
personUrl.replace('/', '#')+'.json' personUrl.replace('/', '#')+'.json'
if os.path.isfile(getFileCaseInsensitive(cacheFilename)): if os.path.isfile(getFileCaseInsensitive(cacheFilename)):
personJson = loadJson(getFileCaseInsensitive(cacheFilename)) personJson = loadJson(getFileCaseInsensitive(cacheFilename))
if personJson: if personJson:
storePersonInCache(baseDir, personUrl, personJson, personCache) storePersonInCache(baseDir, personUrl, personJson,
personCache, False)
loadedFromFile = True loadedFromFile = True
if personCache.get(personUrl): if personCache.get(personUrl):

582
daemon.py

File diff suppressed because it is too large Load Diff

View File

@ -210,7 +210,7 @@ def unfollowPerson(baseDir: str, nickname: str, domain: str,
return return
with open(filename, "r") as f: with open(filename, "r") as f:
lines = f.readlines() lines = f.readlines()
with open(filename, "w") as f: with open(filename, 'w+') as f:
for line in lines: for line in lines:
if line.strip("\n").strip("\r").lower() != handleToUnfollowLower: if line.strip("\n").strip("\r").lower() != handleToUnfollowLower:
f.write(line) f.write(line)

4
git.py
View File

@ -210,12 +210,12 @@ def receiveGitPatch(baseDir: str, nickname: str, domain: str,
return False return False
patchStr = \ patchStr = \
gitAddFromHandle(patchStr, '@' + fromNickname + '@' + fromDomain) gitAddFromHandle(patchStr, '@' + fromNickname + '@' + fromDomain)
with open(patchFilename, "w") as patchFile: with open(patchFilename, 'w+') as patchFile:
patchFile.write(patchStr) patchFile.write(patchStr)
patchNotifyFilename = \ patchNotifyFilename = \
baseDir + '/accounts/' + \ baseDir + '/accounts/' + \
nickname + '@' + domain + '/.newPatchContent' nickname + '@' + domain + '/.newPatchContent'
with open(patchNotifyFilename, "w") as patchFile: with open(patchNotifyFilename, 'w+') as patchFile:
patchFile.write(patchStr) patchFile.write(patchStr)
return True return True
return False return False

View File

@ -244,7 +244,7 @@ def getTodaysEvents(baseDir: str, nickname: str, domain: str,
# if some posts have been deleted then regenerate the calendar file # if some posts have been deleted then regenerate the calendar file
if recreateEventsFile: if recreateEventsFile:
calendarFile = open(calendarFilename, "w") calendarFile = open(calendarFilename, 'w+')
for postId in calendarPostIds: for postId in calendarPostIds:
calendarFile.write(postId + '\n') calendarFile.write(postId + '\n')
calendarFile.close() calendarFile.close()
@ -412,7 +412,7 @@ def getThisWeeksEvents(baseDir: str, nickname: str, domain: str) -> {}:
# if some posts have been deleted then regenerate the calendar file # if some posts have been deleted then regenerate the calendar file
if recreateEventsFile: if recreateEventsFile:
calendarFile = open(calendarFilename, "w") calendarFile = open(calendarFilename, 'w+')
for postId in calendarPostIds: for postId in calendarPostIds:
calendarFile.write(postId + '\n') calendarFile.write(postId + '\n')
calendarFile.close() calendarFile.close()
@ -494,7 +494,7 @@ def getCalendarEvents(baseDir: str, nickname: str, domain: str,
# if some posts have been deleted then regenerate the calendar file # if some posts have been deleted then regenerate the calendar file
if recreateEventsFile: if recreateEventsFile:
calendarFile = open(calendarFilename, "w") calendarFile = open(calendarFilename, 'w+')
for postId in calendarPostIds: for postId in calendarPostIds:
calendarFile.write(postId + '\n') calendarFile.write(postId + '\n')
calendarFile.close() calendarFile.close()

View File

@ -199,7 +199,8 @@ def getPersonPubKey(baseDir: str, session, personUrl: str,
if debug: if debug:
print('DEBUG: Obtaining public key for shared inbox') print('DEBUG: Obtaining public key for shared inbox')
personUrl = personUrl.replace('/users/inbox', '/inbox') personUrl = personUrl.replace('/users/inbox', '/inbox')
personJson = getPersonFromCache(baseDir, personUrl, personCache) personJson = \
getPersonFromCache(baseDir, personUrl, personCache, True)
if not personJson: if not personJson:
if debug: if debug:
print('DEBUG: Obtaining public key for ' + personUrl) print('DEBUG: Obtaining public key for ' + personUrl)
@ -228,7 +229,7 @@ def getPersonPubKey(baseDir: str, session, personUrl: str,
if debug: if debug:
print('DEBUG: Public key not found for ' + personUrl) print('DEBUG: Public key not found for ' + personUrl)
storePersonInCache(baseDir, personUrl, personJson, personCache) storePersonInCache(baseDir, personUrl, personJson, personCache, True)
return pubKey return pubKey
@ -272,6 +273,8 @@ def inboxPermittedMessage(domain: str, messageJson: {},
return False return False
if messageJson['object'].get('inReplyTo'): if messageJson['object'].get('inReplyTo'):
inReplyTo = messageJson['object']['inReplyTo'] inReplyTo = messageJson['object']['inReplyTo']
if not isinstance(inReplyTo, str):
return False
if not urlPermitted(inReplyTo, federationList, "inbox:write"): if not urlPermitted(inReplyTo, federationList, "inbox:write"):
return False return False
@ -863,7 +866,8 @@ def personReceiveUpdate(baseDir: str,
'cached actor when updating') 'cached actor when updating')
return False return False
# save to cache in memory # save to cache in memory
storePersonInCache(baseDir, personJson['id'], personJson, personCache) storePersonInCache(baseDir, personJson['id'], personJson,
personCache, True)
# save to cache on file # save to cache on file
if saveJson(personJson, actorFilename): if saveJson(personJson, actorFilename):
print('actor updated for ' + personJson['id']) print('actor updated for ' + personJson['id'])
@ -1596,6 +1600,8 @@ def populateReplies(baseDir: str, httpPrefix: str, domain: str,
if not messageJson['object'].get('to'): if not messageJson['object'].get('to'):
return False return False
replyTo = messageJson['object']['inReplyTo'] replyTo = messageJson['object']['inReplyTo']
if not isinstance(replyTo, str):
return False
if debug: if debug:
print('DEBUG: post contains a reply') print('DEBUG: post contains a reply')
# is this a reply to a post on this domain? # is this a reply to a post on this domain?
@ -1636,7 +1642,7 @@ def populateReplies(baseDir: str, httpPrefix: str, domain: str,
repliesFile.write(messageId + '\n') repliesFile.write(messageId + '\n')
repliesFile.close() repliesFile.close()
else: else:
repliesFile = open(postRepliesFilename, "w") repliesFile = open(postRepliesFilename, 'w+')
repliesFile.write(messageId + '\n') repliesFile.write(messageId + '\n')
repliesFile.close() repliesFile.close()
return True return True
@ -1760,6 +1766,9 @@ def obtainAvatarForReplyPost(session, baseDir: str, httpPrefix: str,
if not lookupActor: if not lookupActor:
return return
if not isinstance(lookupActor, str):
return
if not ('/users/' in lookupActor or if not ('/users/' in lookupActor or
'/accounts/' in lookupActor or '/accounts/' in lookupActor or
'/channel/' in lookupActor or '/channel/' in lookupActor or
@ -2355,11 +2364,15 @@ def inboxAfterCapabilities(recentPostsCache: {}, maxRecentPosts: int,
if nickname != 'inbox': if nickname != 'inbox':
# replies index will be updated # replies index will be updated
updateIndexList.append('tlreplies') updateIndexList.append('tlreplies')
inReplyTo = postJsonObject['object']['inReplyTo']
if inReplyTo:
if isinstance(inReplyTo, str):
if not isMuted(baseDir, nickname, domain, if not isMuted(baseDir, nickname, domain,
postJsonObject['object']['inReplyTo']): inReplyTo):
replyNotify(baseDir, handle, replyNotify(baseDir, handle,
httpPrefix + '://' + domain + httpPrefix + '://' + domain +
'/users/' + nickname + '/tlreplies') '/users/' + nickname +
'/tlreplies')
else: else:
isReplyToMutedPost = True isReplyToMutedPost = True
@ -2386,7 +2399,7 @@ def inboxAfterCapabilities(recentPostsCache: {}, maxRecentPosts: int,
# This enables you to ignore a threat that's getting boring # This enables you to ignore a threat that's getting boring
if isReplyToMutedPost: if isReplyToMutedPost:
print('MUTE REPLY: ' + destinationFilename) print('MUTE REPLY: ' + destinationFilename)
muteFile = open(destinationFilename + '.muted', "w") muteFile = open(destinationFilename + '.muted', 'w+')
if muteFile: if muteFile:
muteFile.write('\n') muteFile.write('\n')
muteFile.close() muteFile.close()

View File

@ -350,7 +350,7 @@ def createPersonBase(baseDir: str, nickname: str, domain: str, port: int,
if not os.path.isdir(baseDir + privateKeysSubdir): if not os.path.isdir(baseDir + privateKeysSubdir):
os.mkdir(baseDir + privateKeysSubdir) os.mkdir(baseDir + privateKeysSubdir)
filename = baseDir + privateKeysSubdir + '/' + handle + '.key' filename = baseDir + privateKeysSubdir + '/' + handle + '.key'
with open(filename, "w") as text_file: with open(filename, 'w+') as text_file:
print(privateKeyPem, file=text_file) print(privateKeyPem, file=text_file)
# save the public key # save the public key
@ -358,7 +358,7 @@ def createPersonBase(baseDir: str, nickname: str, domain: str, port: int,
if not os.path.isdir(baseDir + publicKeysSubdir): if not os.path.isdir(baseDir + publicKeysSubdir):
os.mkdir(baseDir + publicKeysSubdir) os.mkdir(baseDir + publicKeysSubdir)
filename = baseDir + publicKeysSubdir + '/' + handle + '.pem' filename = baseDir + publicKeysSubdir + '/' + handle + '.pem'
with open(filename, "w") as text_file: with open(filename, 'w+') as text_file:
print(publicKeyPem, file=text_file) print(publicKeyPem, file=text_file)
if password: if password:
@ -454,22 +454,22 @@ def createPerson(baseDir: str, nickname: str, domain: str, port: int,
setRole(baseDir, nickname, domain, 'instance', 'delegator') setRole(baseDir, nickname, domain, 'instance', 'delegator')
setConfigParam(baseDir, 'admin', nickname) setConfigParam(baseDir, 'admin', nickname)
if not os.path.isdir(baseDir + '/accounts'):
os.mkdir(baseDir + '/accounts')
if not os.path.isdir(baseDir + '/accounts/' + nickname + '@' + domain):
os.mkdir(baseDir + '/accounts/' + nickname + '@' + domain)
if manualFollowerApproval: if manualFollowerApproval:
followDMsFilename = baseDir + '/accounts/' + \ followDMsFilename = baseDir + '/accounts/' + \
nickname + '@' + domain + '/.followDMs' nickname + '@' + domain + '/.followDMs'
with open(followDMsFilename, "w") as fFile: with open(followDMsFilename, 'w+') as fFile:
fFile.write('\n') fFile.write('\n')
# notify when posts are liked # notify when posts are liked
notifyLikesFilename = baseDir + '/accounts/' + \ notifyLikesFilename = baseDir + '/accounts/' + \
nickname + '@' + domain + '/.notifyLikes' nickname + '@' + domain + '/.notifyLikes'
with open(notifyLikesFilename, "w") as fFile: with open(notifyLikesFilename, 'w+') as nFile:
fFile.write('\n') nFile.write('\n')
if not os.path.isdir(baseDir + '/accounts'):
os.mkdir(baseDir + '/accounts')
if not os.path.isdir(baseDir + '/accounts/' + nickname + '@' + domain):
os.mkdir(baseDir + '/accounts/' + nickname + '@' + domain)
if os.path.isfile(baseDir + '/img/default-avatar.png'): if os.path.isfile(baseDir + '/img/default-avatar.png'):
copyfile(baseDir + '/img/default-avatar.png', copyfile(baseDir + '/img/default-avatar.png',

View File

@ -209,7 +209,8 @@ def getPersonBox(baseDir: str, session, wfRequest: {},
personUrl = httpPrefix + '://' + domain + '/users/' + nickname personUrl = httpPrefix + '://' + domain + '/users/' + nickname
if not personUrl: if not personUrl:
return None, None, None, None, None, None, None, None return None, None, None, None, None, None, None, None
personJson = getPersonFromCache(baseDir, personUrl, personCache) personJson = \
getPersonFromCache(baseDir, personUrl, personCache, True)
if not personJson: if not personJson:
if '/channel/' in personUrl or '/accounts/' in personUrl: if '/channel/' in personUrl or '/accounts/' in personUrl:
asHeader = { asHeader = {
@ -265,7 +266,7 @@ def getPersonBox(baseDir: str, session, wfRequest: {},
if personJson.get('name'): if personJson.get('name'):
displayName = personJson['name'] displayName = personJson['name']
storePersonInCache(baseDir, personUrl, personJson, personCache) storePersonInCache(baseDir, personUrl, personJson, personCache, True)
return boxJson, pubKeyId, pubKey, personId, sharedInbox, \ return boxJson, pubKeyId, pubKey, personId, sharedInbox, \
capabilityAcquisition, avatarUrl, displayName capabilityAcquisition, avatarUrl, displayName
@ -388,6 +389,7 @@ def getPosts(session, outboxUrl: str, maxPosts: int,
inReplyTo = '' inReplyTo = ''
if item['object'].get('inReplyTo'): if item['object'].get('inReplyTo'):
if item['object']['inReplyTo']: if item['object']['inReplyTo']:
if isinstance(item['object']['inReplyTo'], str):
# No replies to non-permitted domains # No replies to non-permitted domains
if not urlPermitted(item['object']['inReplyTo'], if not urlPermitted(item['object']['inReplyTo'],
federationList, federationList,
@ -483,6 +485,7 @@ def getPostDomains(session, outboxUrl: str, maxPosts: int,
if not isinstance(item['object'], dict): if not isinstance(item['object'], dict):
continue continue
if item['object'].get('inReplyTo'): if item['object'].get('inReplyTo'):
if isinstance(item['object']['inReplyTo'], str):
postDomain, postPort = \ postDomain, postPort = \
getDomainFromActor(item['object']['inReplyTo']) getDomainFromActor(item['object']['inReplyTo'])
if postDomain not in postDomains: if postDomain not in postDomains:
@ -2675,6 +2678,7 @@ def isReply(postJsonObject: {}, actor: str) -> bool:
postJsonObject['object']['type'] != 'Article': postJsonObject['object']['type'] != 'Article':
return False return False
if postJsonObject['object'].get('inReplyTo'): if postJsonObject['object'].get('inReplyTo'):
if isinstance(postJsonObject['object']['inReplyTo'], str):
if postJsonObject['object']['inReplyTo'].startswith(actor): if postJsonObject['object']['inReplyTo'].startswith(actor):
return True return True
if not postJsonObject['object'].get('tag'): if not postJsonObject['object'].get('tag'):
@ -3532,7 +3536,7 @@ def mutePost(baseDir: str, nickname: str, domain: str, postId: str,
return return
print('MUTE: ' + postFilename) print('MUTE: ' + postFilename)
muteFile = open(postFilename + '.muted', "w") muteFile = open(postFilename + '.muted', 'w+')
if muteFile: if muteFile:
muteFile.write('\n') muteFile.write('\n')
muteFile.close() muteFile.close()

View File

@ -25,6 +25,8 @@ def questionUpdateVotes(baseDir: str, nickname: str, domain: str,
return None return None
if not replyJson['object']['inReplyTo']: if not replyJson['object']['inReplyTo']:
return None return None
if not isinstance(replyJson['object']['inReplyTo'], str):
return None
if not replyJson['object'].get('name'): if not replyJson['object'].get('name'):
return None return None
inReplyTo = replyJson['object']['inReplyTo'] inReplyTo = replyJson['object']['inReplyTo']
@ -64,7 +66,7 @@ def questionUpdateVotes(baseDir: str, nickname: str, domain: str,
votersFilename = questionPostFilename.replace('.json', '.voters') votersFilename = questionPostFilename.replace('.json', '.voters')
if not os.path.isfile(votersFilename): if not os.path.isfile(votersFilename):
# create a new voters file # create a new voters file
votersFile = open(votersFilename, "w") votersFile = open(votersFilename, 'w+')
if votersFile: if votersFile:
votersFile.write(replyJson['actor'] + votersFile.write(replyJson['actor'] +
votersFileSeparator + votersFileSeparator +
@ -97,7 +99,7 @@ def questionUpdateVotes(baseDir: str, nickname: str, domain: str,
else: else:
newlines.append(voteLine) newlines.append(voteLine)
if saveVotersFile: if saveVotersFile:
with open(votersFilename, "w") as votersFile: with open(votersFilename, 'w+') as votersFile:
for voteLine in newlines: for voteLine in newlines:
votersFile.write(voteLine) votersFile.write(voteLine)
else: else:

View File

@ -52,7 +52,7 @@ def addModerator(baseDir: str, nickname: str, domain: str) -> None:
if moderator == nickname: if moderator == nickname:
return return
lines.append(nickname) lines.append(nickname)
with open(moderatorsFile, "w") as f: with open(moderatorsFile, 'w+') as f:
for moderator in lines: for moderator in lines:
moderator = moderator.strip('\n').strip('\r') moderator = moderator.strip('\n').strip('\r')
if len(moderator) > 1: if len(moderator) > 1:
@ -74,7 +74,7 @@ def removeModerator(baseDir: str, nickname: str):
return return
with open(moderatorsFile, "r") as f: with open(moderatorsFile, "r") as f:
lines = f.readlines() lines = f.readlines()
with open(moderatorsFile, "w") as f: with open(moderatorsFile, 'w+') as f:
for moderator in lines: for moderator in lines:
moderator = moderator.strip('\n').strip('\r') moderator = moderator.strip('\n').strip('\r')
if len(moderator) > 1 and moderator != nickname: if len(moderator) > 1 and moderator != nickname:

View File

@ -209,8 +209,8 @@ def testCache():
"test": "This is a test" "test": "This is a test"
} }
personCache = {} personCache = {}
storePersonInCache(None, personUrl, personJson, personCache) storePersonInCache(None, personUrl, personJson, personCache, True)
result = getPersonFromCache(None, personUrl, personCache) result = getPersonFromCache(None, personUrl, personCache, True)
assert result['id'] == 123456 assert result['id'] == 123456
assert result['test'] == 'This is a test' assert result['test'] == 'This is a test'
@ -2064,6 +2064,9 @@ def testTranslations():
langDict = {} langDict = {}
for lang in languagesStr: for lang in languagesStr:
langJson = loadJson('translations/' + lang + '.json') langJson = loadJson('translations/' + lang + '.json')
if not langJson:
print('Missing language file ' +
'translations/' + lang + '.json')
assert langJson assert langJson
langDict[lang] = langJson langDict[lang] = langJson

View File

@ -282,5 +282,6 @@
"Create a new event": "أنشئ حدثًا جديدًا", "Create a new event": "أنشئ حدثًا جديدًا",
"Moderation policy or code of conduct": "سياسة الوسطية أو قواعد السلوك", "Moderation policy or code of conduct": "سياسة الوسطية أو قواعد السلوك",
"Edit event": "تحرير الحدث", "Edit event": "تحرير الحدث",
"Notify when posts are liked": "يخطر عندما يتم اعجاب المشاركات" "Notify when posts are liked": "يخطر عندما يتم اعجاب المشاركات",
"Don't show the Like button": "لا تظهر زر أعجبني"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "Creeu un esdeveniment nou", "Create a new event": "Creeu un esdeveniment nou",
"Moderation policy or code of conduct": "Política de moderació o codi de conducta", "Moderation policy or code of conduct": "Política de moderació o codi de conducta",
"Edit event": "Edita lesdeveniment", "Edit event": "Edita lesdeveniment",
"Notify when posts are liked": "Notifiqueu-ho quan us agradin les publicacions" "Notify when posts are liked": "Notifiqueu-ho quan us agradin les publicacions",
"Don't show the Like button": "No mostreu el botó M'agrada"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "Creu digwyddiad newydd", "Create a new event": "Creu digwyddiad newydd",
"Moderation policy or code of conduct": "Polisi cymedroli neu god ymddygiad", "Moderation policy or code of conduct": "Polisi cymedroli neu god ymddygiad",
"Edit event": "Golygu digwyddiad", "Edit event": "Golygu digwyddiad",
"Notify when posts are liked": "Hysbysu pryd mae swyddi'n cael eu hoffi" "Notify when posts are liked": "Hysbysu pryd mae swyddi'n cael eu hoffi",
"Don't show the Like button": "Peidiwch â dangos y botwm Hoffi"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "Erstellen Sie ein neues Ereignis", "Create a new event": "Erstellen Sie ein neues Ereignis",
"Moderation policy or code of conduct": "Moderationsrichtlinie oder Verhaltenskodex", "Moderation policy or code of conduct": "Moderationsrichtlinie oder Verhaltenskodex",
"Edit event": "Ereignis bearbeiten", "Edit event": "Ereignis bearbeiten",
"Notify when posts are liked": "Benachrichtigen, wenn Beiträge gefallen" "Notify when posts are liked": "Benachrichtigen, wenn Beiträge gefallen",
"Don't show the Like button": "Zeigen Sie nicht die Schaltfläche \"Gefällt mir\" an"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "Create a new event", "Create a new event": "Create a new event",
"Moderation policy or code of conduct": "Moderation policy or code of conduct", "Moderation policy or code of conduct": "Moderation policy or code of conduct",
"Edit event": "Edit event", "Edit event": "Edit event",
"Notify when posts are liked": "Notify when posts are liked" "Notify when posts are liked": "Notify when posts are liked",
"Don't show the Like button": "Don't show the Like button"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "Crea un nuevo evento", "Create a new event": "Crea un nuevo evento",
"Moderation policy or code of conduct": "Política de moderación o código de conducta", "Moderation policy or code of conduct": "Política de moderación o código de conducta",
"Edit event": "Editar evento", "Edit event": "Editar evento",
"Notify when posts are liked": "Notificar cuando les gusten las publicaciones" "Notify when posts are liked": "Notificar cuando les gusten las publicaciones",
"Don't show the Like button": "No mostrar el botón Me gusta"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "Créer un nouvel événement", "Create a new event": "Créer un nouvel événement",
"Moderation policy or code of conduct": "Politique de modération ou code de conduite", "Moderation policy or code of conduct": "Politique de modération ou code de conduite",
"Edit event": "Modifier l'événement", "Edit event": "Modifier l'événement",
"Notify when posts are liked": "Notifier lorsque les messages sont aimés" "Notify when posts are liked": "Notifier lorsque les messages sont aimés",
"Don't show the Like button": "Ne pas afficher le bouton J'aime"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "Cruthaigh imeacht nua", "Create a new event": "Cruthaigh imeacht nua",
"Moderation policy or code of conduct": "Beartas modhnóireachta nó cód iompair", "Moderation policy or code of conduct": "Beartas modhnóireachta nó cód iompair",
"Edit event": "Cuir imeacht in eagar", "Edit event": "Cuir imeacht in eagar",
"Notify when posts are liked": "Cuir in iúl cathain is maith poist" "Notify when posts are liked": "Cuir in iúl cathain is maith poist",
"Don't show the Like button": "Ná taispeáin an cnaipe Cosúil"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "एक नई घटना बनाएँ", "Create a new event": "एक नई घटना बनाएँ",
"Moderation policy or code of conduct": "मॉडरेशन पॉलिसी या आचार संहिता", "Moderation policy or code of conduct": "मॉडरेशन पॉलिसी या आचार संहिता",
"Edit event": "घटना संपादित करें", "Edit event": "घटना संपादित करें",
"Notify when posts are liked": "पोस्ट पसंद आने पर सूचित करें" "Notify when posts are liked": "पोस्ट पसंद आने पर सूचित करें",
"Don't show the Like button": "लाइक बटन न दिखाएं"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "Crea un nuovo evento", "Create a new event": "Crea un nuovo evento",
"Moderation policy or code of conduct": "Politica di moderazione o codice di condotta", "Moderation policy or code of conduct": "Politica di moderazione o codice di condotta",
"Edit event": "Modifica evento", "Edit event": "Modifica evento",
"Notify when posts are liked": "Avvisa quando i post sono piaciuti" "Notify when posts are liked": "Avvisa quando i post sono piaciuti",
"Don't show the Like button": "Non mostrare il pulsante Mi piace"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "新しいイベントを作成する", "Create a new event": "新しいイベントを作成する",
"Moderation policy or code of conduct": "モデレートポリシーまたは行動規範", "Moderation policy or code of conduct": "モデレートポリシーまたは行動規範",
"Edit event": "イベントを編集", "Edit event": "イベントを編集",
"Notify when posts are liked": "投稿が高く評価されたときに通知する" "Notify when posts are liked": "投稿が高く評価されたときに通知する",
"Don't show the Like button": "「いいね!」ボタンを表示しない"
} }

View File

@ -278,5 +278,6 @@
"Create a new event": "Create a new event", "Create a new event": "Create a new event",
"Moderation policy or code of conduct": "Moderation policy or code of conduct", "Moderation policy or code of conduct": "Moderation policy or code of conduct",
"Edit event": "Edit event", "Edit event": "Edit event",
"Notify when posts are liked": "Notify when posts are liked" "Notify when posts are liked": "Notify when posts are liked",
"Don't show the Like button": "Don't show the Like button"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "Crie um novo evento", "Create a new event": "Crie um novo evento",
"Moderation policy or code of conduct": "Política de moderação ou código de conduta", "Moderation policy or code of conduct": "Política de moderação ou código de conduta",
"Edit event": "Editar evento", "Edit event": "Editar evento",
"Notify when posts are liked": "Notificar quando as postagens forem curtidas" "Notify when posts are liked": "Notificar quando as postagens forem curtidas",
"Don't show the Like button": "Não mostrar o botão Curtir"
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "Создать новое мероприятие", "Create a new event": "Создать новое мероприятие",
"Moderation policy or code of conduct": "Политика модерации или кодекс поведения", "Moderation policy or code of conduct": "Политика модерации или кодекс поведения",
"Edit event": "Изменить мероприятие", "Edit event": "Изменить мероприятие",
"Notify when posts are liked": "Уведомлять, когда публикации нравятся" "Notify when posts are liked": "Уведомлять, когда публикации нравятся",
"Don't show the Like button": "Не показывать кнопку \"Нравится\""
} }

View File

@ -282,5 +282,6 @@
"Create a new event": "建立新活动", "Create a new event": "建立新活动",
"Moderation policy or code of conduct": "审核政策或行为准则", "Moderation policy or code of conduct": "审核政策或行为准则",
"Edit event": "编辑活动", "Edit event": "编辑活动",
"Notify when posts are liked": "通知喜欢的帖子" "Notify when posts are liked": "通知喜欢的帖子",
"Don't show the Like button": "不显示“赞”按钮"
} }

View File

@ -75,12 +75,12 @@ def saveJson(jsonObject: {}, filename: str) -> bool:
return False return False
def loadJson(filename: str, delaySec=2) -> {}: def loadJson(filename: str, delaySec=2, maxTries=5) -> {}:
"""Makes a few attempts to load a json formatted file """Makes a few attempts to load a json formatted file
""" """
jsonObject = None jsonObject = None
tries = 0 tries = 0
while tries < 5: while tries < maxTries:
try: try:
with open(filename, 'r') as fp: with open(filename, 'r') as fp:
data = fp.read() data = fp.read()
@ -351,7 +351,7 @@ def followPerson(baseDir: str, nickname: str, domain: str,
for line in lines: for line in lines:
if handleToFollow not in line: if handleToFollow not in line:
newLines += line newLines += line
with open(unfollowedFilename, "w") as f: with open(unfollowedFilename, 'w+') as f:
f.write(newLines) f.write(newLines)
if not os.path.isdir(baseDir + '/accounts'): if not os.path.isdir(baseDir + '/accounts'):
@ -383,7 +383,7 @@ def followPerson(baseDir: str, nickname: str, domain: str,
followNickname, followDomain) followNickname, followDomain)
if debug: if debug:
print('DEBUG: creating new following file to follow ' + handleToFollow) print('DEBUG: creating new following file to follow ' + handleToFollow)
with open(filename, "w") as followfile: with open(filename, 'w+') as followfile:
followfile.write(handleToFollow + '\n') followfile.write(handleToFollow + '\n')
return True return True
@ -473,6 +473,8 @@ def isReplyToBlogPost(baseDir: str, nickname: str, domain: str,
return False return False
if not postJsonObject['object'].get('inReplyTo'): if not postJsonObject['object'].get('inReplyTo'):
return False return False
if not isinstance(postJsonObject['object']['inReplyTo'], str):
return False
blogsIndexFilename = baseDir + '/accounts/' + \ blogsIndexFilename = baseDir + '/accounts/' + \
nickname + '@' + domain + '/tlblogs.index' nickname + '@' + domain + '/tlblogs.index'
if not os.path.isfile(blogsIndexFilename): if not os.path.isfile(blogsIndexFilename):
@ -905,11 +907,19 @@ def searchBoxPosts(baseDir: str, nickname: str, domain: str,
def getFileCaseInsensitive(path: str) -> str: def getFileCaseInsensitive(path: str) -> str:
"""Returns a case specific filename given a case insensitive version of it """Returns a case specific filename given a case insensitive version of it
""" """
# does the given file exist? If so then we don't need
# to do a directory search
if os.path.isfile(path):
return path
if path != path.lower():
if os.path.isfile(path.lower()):
return path.lower()
directory, filename = os.path.split(path) directory, filename = os.path.split(path)
directory, filename = (directory or '.'), filename.lower() directory, filename = (directory or '.'), filename.lower()
for f in os.listdir(directory): for f in os.listdir(directory):
if f.lower() == filename:
newpath = os.path.join(directory, f) newpath = os.path.join(directory, f)
if os.path.isfile(newpath) and f.lower() == filename: if os.path.isfile(newpath):
return newpath return newpath
return path return path

View File

@ -199,7 +199,8 @@ def setBlogAddress(actorJson: {}, blogAddress: str) -> None:
def updateAvatarImageCache(session, baseDir: str, httpPrefix: str, def updateAvatarImageCache(session, baseDir: str, httpPrefix: str,
actor: str, avatarUrl: str, actor: str, avatarUrl: str,
personCache: {}, force=False) -> str: personCache: {}, allowDownloads: bool,
force=False) -> str:
"""Updates the cached avatar for the given actor """Updates the cached avatar for the given actor
""" """
if not avatarUrl: if not avatarUrl:
@ -232,7 +233,8 @@ def updateAvatarImageCache(session, baseDir: str, httpPrefix: str,
avatarImageFilename = avatarImagePath + '.webp' avatarImageFilename = avatarImagePath + '.webp'
else: else:
return None return None
if not os.path.isfile(avatarImageFilename) or force:
if (not os.path.isfile(avatarImageFilename) or force) and allowDownloads:
try: try:
print('avatar image url: ' + avatarUrl) print('avatar image url: ' + avatarUrl)
result = session.get(avatarUrl, result = session.get(avatarUrl,
@ -282,18 +284,23 @@ def updateAvatarImageCache(session, baseDir: str, httpPrefix: str,
"public keys don't match when downloading actor for " + "public keys don't match when downloading actor for " +
actor) actor)
return None return None
storePersonInCache(baseDir, actor, personJson, personCache) storePersonInCache(baseDir, actor, personJson, personCache,
return getPersonAvatarUrl(baseDir, actor, personCache) allowDownloads)
return getPersonAvatarUrl(baseDir, actor, personCache,
allowDownloads)
return None return None
return avatarImageFilename.replace(baseDir + '/cache', '') return avatarImageFilename.replace(baseDir + '/cache', '')
def getPersonAvatarUrl(baseDir: str, personUrl: str, personCache: {}) -> str: def getPersonAvatarUrl(baseDir: str, personUrl: str, personCache: {},
allowDownloads: bool) -> str:
"""Returns the avatar url for the person """Returns the avatar url for the person
""" """
personJson = getPersonFromCache(baseDir, personUrl, personCache) personJson = \
getPersonFromCache(baseDir, personUrl, personCache, allowDownloads)
if not personJson: if not personJson:
return None return None
# get from locally stored image # get from locally stored image
actorStr = personJson['id'].replace('/', '-') actorStr = personJson['id'].replace('/', '-')
avatarImagePath = baseDir + '/cache/avatars/' + actorStr avatarImagePath = baseDir + '/cache/avatars/' + actorStr
@ -796,7 +803,7 @@ def htmlHashtagSearch(nickname: str, domain: str, port: int,
showIndividualPostIcons = True showIndividualPostIcons = True
allowDeletion = False allowDeletion = False
hashtagSearchForm += \ hashtagSearchForm += \
individualPostAsHtml(recentPostsCache, individualPostAsHtml(True, recentPostsCache,
maxRecentPosts, maxRecentPosts,
iconsDir, translate, None, iconsDir, translate, None,
baseDir, session, wfRequest, baseDir, session, wfRequest,
@ -1025,7 +1032,7 @@ def htmlHistorySearch(translate: {}, baseDir: str,
showIndividualPostIcons = True showIndividualPostIcons = True
allowDeletion = False allowDeletion = False
historySearchForm += \ historySearchForm += \
individualPostAsHtml(recentPostsCache, individualPostAsHtml(True, recentPostsCache,
maxRecentPosts, maxRecentPosts,
iconsDir, translate, None, iconsDir, translate, None,
baseDir, session, wfRequest, baseDir, session, wfRequest,
@ -1084,6 +1091,7 @@ def htmlEditProfile(translate: {}, baseDir: str, path: str,
followDMs = '' followDMs = ''
removeTwitter = '' removeTwitter = ''
notifyLikes = '' notifyLikes = ''
hideLikeButton = ''
mediaInstanceStr = '' mediaInstanceStr = ''
displayNickname = nickname displayNickname = nickname
bioStr = '' bioStr = ''
@ -1134,6 +1142,9 @@ def htmlEditProfile(translate: {}, baseDir: str, path: str,
if os.path.isfile(baseDir + '/accounts/' + if os.path.isfile(baseDir + '/accounts/' +
nickname + '@' + domain + '/.notifyLikes'): nickname + '@' + domain + '/.notifyLikes'):
notifyLikes = 'checked' notifyLikes = 'checked'
if os.path.isfile(baseDir + '/accounts/' +
nickname + '@' + domain + '/.hideLikeButton'):
hideLikeButton = 'checked'
mediaInstance = getConfigParam(baseDir, "mediaInstance") mediaInstance = getConfigParam(baseDir, "mediaInstance")
if mediaInstance: if mediaInstance:
@ -1473,6 +1484,10 @@ def htmlEditProfile(translate: {}, baseDir: str, path: str,
' <input type="checkbox" class="profilecheckbox" ' + \ ' <input type="checkbox" class="profilecheckbox" ' + \
'name="notifyLikes" ' + notifyLikes + '> ' + \ 'name="notifyLikes" ' + notifyLikes + '> ' + \
translate['Notify when posts are liked'] + '<br>\n' translate['Notify when posts are liked'] + '<br>\n'
editProfileForm += \
' <input type="checkbox" class="profilecheckbox" ' + \
'name="hideLikeButton" ' + hideLikeButton + '> ' + \
translate["Don't show the Like button"] + '<br>\n'
editProfileForm += \ editProfileForm += \
' <br><b><label class="labels">' + \ ' <br><b><label class="labels">' + \
@ -2493,7 +2508,8 @@ def htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
for item in outboxFeed['orderedItems']: for item in outboxFeed['orderedItems']:
if item['type'] == 'Create': if item['type'] == 'Create':
postStr = \ postStr = \
individualPostAsHtml(recentPostsCache, maxRecentPosts, individualPostAsHtml(True, recentPostsCache,
maxRecentPosts,
iconsDir, translate, None, iconsDir, translate, None,
baseDir, session, wfRequest, baseDir, session, wfRequest,
personCache, personCache,
@ -3053,7 +3069,7 @@ def individualFollowAsHtml(translate: {},
nickname = getNicknameFromActor(followUrl) nickname = getNicknameFromActor(followUrl)
domain, port = getDomainFromActor(followUrl) domain, port = getDomainFromActor(followUrl)
titleStr = '@' + nickname + '@' + domain titleStr = '@' + nickname + '@' + domain
avatarUrl = getPersonAvatarUrl(baseDir, followUrl, personCache) avatarUrl = getPersonAvatarUrl(baseDir, followUrl, personCache, True)
if not avatarUrl: if not avatarUrl:
avatarUrl = followUrl + '/avatar.png' avatarUrl = followUrl + '/avatar.png'
if domain not in followUrl: if domain not in followUrl:
@ -3778,7 +3794,8 @@ def getPostAttachmentsAsHtml(postJsonObject: {}, boxName: str, translate: {},
return attachmentStr, galleryStr return attachmentStr, galleryStr
def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int, def individualPostAsHtml(allowDownloads: bool,
recentPostsCache: {}, maxRecentPosts: int,
iconsDir: str, translate: {}, iconsDir: str, translate: {},
pageNumber: int, baseDir: str, pageNumber: int, baseDir: str,
session, wfRequest: {}, personCache: {}, session, wfRequest: {}, personCache: {},
@ -3795,17 +3812,30 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
storeToCache=True) -> str: storeToCache=True) -> str:
""" Shows a single post as html """ Shows a single post as html
""" """
# benchmark
postStartTime = time.time()
postActor = postJsonObject['actor'] postActor = postJsonObject['actor']
# ZZZzzz # ZZZzzz
if isPersonSnoozed(baseDir, nickname, domain, postActor): if isPersonSnoozed(baseDir, nickname, domain, postActor):
return '' return ''
# benchmark 1
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 1 = ' + str(timeDiff))
avatarPosition = '' avatarPosition = ''
messageId = '' messageId = ''
if postJsonObject.get('id'): if postJsonObject.get('id'):
messageId = removeIdEnding(postJsonObject['id']) messageId = removeIdEnding(postJsonObject['id'])
# benchmark 2
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 2 = ' + str(timeDiff))
messageIdStr = '' messageIdStr = ''
if messageId: if messageId:
messageIdStr = ';' + messageId messageIdStr = ';' + messageId
@ -3827,9 +3857,26 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
# update avatar if needed # update avatar if needed
if not avatarUrl: if not avatarUrl:
avatarUrl = \ avatarUrl = \
getPersonAvatarUrl(baseDir, postActor, personCache) getPersonAvatarUrl(baseDir, postActor, personCache,
allowDownloads)
# benchmark 2.1
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName +
' 2.1 = ' + str(timeDiff))
updateAvatarImageCache(session, baseDir, httpPrefix, updateAvatarImageCache(session, baseDir, httpPrefix,
postActor, avatarUrl, personCache) postActor, avatarUrl, personCache,
allowDownloads)
# benchmark 2.2
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName +
' 2.2 = ' + str(timeDiff))
postHtml = \ postHtml = \
loadIndividualPostAsHtmlFromCache(baseDir, nickname, domain, loadIndividualPostAsHtmlFromCache(baseDir, nickname, domain,
@ -3838,17 +3885,38 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
postHtml = preparePostFromHtmlCache(postHtml, boxName, pageNumber) postHtml = preparePostFromHtmlCache(postHtml, boxName, pageNumber)
updateRecentPostsCache(recentPostsCache, maxRecentPosts, updateRecentPostsCache(recentPostsCache, maxRecentPosts,
postJsonObject, postHtml) postJsonObject, postHtml)
# benchmark 3
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName +
' 3 = ' + str(timeDiff))
return postHtml return postHtml
# benchmark 4
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 4 = ' + str(timeDiff))
if not avatarUrl: if not avatarUrl:
avatarUrl = \ avatarUrl = \
getPersonAvatarUrl(baseDir, postActor, personCache) getPersonAvatarUrl(baseDir, postActor, personCache,
allowDownloads)
avatarUrl = \ avatarUrl = \
updateAvatarImageCache(session, baseDir, httpPrefix, updateAvatarImageCache(session, baseDir, httpPrefix,
postActor, avatarUrl, personCache) postActor, avatarUrl, personCache,
allowDownloads)
else: else:
updateAvatarImageCache(session, baseDir, httpPrefix, updateAvatarImageCache(session, baseDir, httpPrefix,
postActor, avatarUrl, personCache) postActor, avatarUrl, personCache,
allowDownloads)
# benchmark 5
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 5 = ' + str(timeDiff))
if not avatarUrl: if not avatarUrl:
avatarUrl = postActor + '/avatar.png' avatarUrl = postActor + '/avatar.png'
@ -3861,6 +3929,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
personCache, personCache,
projectVersion, httpPrefix, projectVersion, httpPrefix,
nickname, domain, 'outbox') nickname, domain, 'outbox')
# benchmark 6
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 6 = ' + str(timeDiff))
if avatarUrl2: if avatarUrl2:
avatarUrl = avatarUrl2 avatarUrl = avatarUrl2
if displayName: if displayName:
@ -3870,6 +3944,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
nickname, domain, nickname, domain,
displayName, False) displayName, False)
# benchmark 7
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 7 = ' + str(timeDiff))
avatarLink = ' <a class="imageAnchor" href="' + postActor + '">' avatarLink = ' <a class="imageAnchor" href="' + postActor + '">'
avatarLink += \ avatarLink += \
' <img loading="lazy" src="' + avatarUrl + '" title="' + \ ' <img loading="lazy" src="' + avatarUrl + '" title="' + \
@ -3923,6 +4003,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
postJsonObject = postJsonAnnounce postJsonObject = postJsonAnnounce
isAnnounced = True isAnnounced = True
# benchmark 8
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 8 = ' + str(timeDiff))
if not isinstance(postJsonObject['object'], dict): if not isinstance(postJsonObject['object'], dict):
return '' return ''
@ -3971,6 +4057,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
';' + str(pageNumber) + ';' + avatarUrl + messageIdStr + \ ';' + str(pageNumber) + ';' + avatarUrl + messageIdStr + \
'">@' + actorNickname + '@' + actorDomain + '</a>\n' '">@' + actorNickname + '@' + actorDomain + '</a>\n'
# benchmark 9
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 9 = ' + str(timeDiff))
# Show a DM icon for DMs in the inbox timeline # Show a DM icon for DMs in the inbox timeline
if showDMicon: if showDMicon:
titleStr = \ titleStr = \
@ -4028,8 +4120,20 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
translate['Reply to this post'] + \ translate['Reply to this post'] + \
' |" src="/' + iconsDir + '/reply.png"/></a>\n' ' |" src="/' + iconsDir + '/reply.png"/></a>\n'
# benchmark 10
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 10 = ' + str(timeDiff))
isEvent = isEventPost(postJsonObject) isEvent = isEventPost(postJsonObject)
# benchmark 11
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 11 = ' + str(timeDiff))
editStr = '' editStr = ''
if fullDomain + '/users/' + nickname in postJsonObject['actor']: if fullDomain + '/users/' + nickname in postJsonObject['actor']:
if '/statuses/' in postJsonObject['object']['id']: if '/statuses/' in postJsonObject['object']['id']:
@ -4083,12 +4187,32 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
'" alt="' + translate['Repeat this post'] + \ '" alt="' + translate['Repeat this post'] + \
' |" src="/' + iconsDir + '/' + announceIcon + '"/></a>\n' ' |" src="/' + iconsDir + '/' + announceIcon + '"/></a>\n'
# benchmark 12
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 12 = ' + str(timeDiff))
# whether to show a like button
hideLikeButtonFile = \
baseDir + '/accounts/' + nickname + '@' + domain + '/.hideLikeButton'
showLikeButton = True
if os.path.isfile(hideLikeButtonFile):
showLikeButton = False
likeStr = '' likeStr = ''
if not isModerationPost: if not isModerationPost and showLikeButton:
likeIcon = 'like_inactive.png' likeIcon = 'like_inactive.png'
likeLink = 'like' likeLink = 'like'
likeTitle = translate['Like this post'] likeTitle = translate['Like this post']
likeCount = noOfLikes(postJsonObject) likeCount = noOfLikes(postJsonObject)
# benchmark 12.1
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 12.1 = ' + str(timeDiff))
likeCountStr = '' likeCountStr = ''
if likeCount > 0: if likeCount > 0:
if likeCount > 1: if likeCount > 1:
@ -4100,6 +4224,13 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
if likedByPerson(postJsonObject, nickname, fullDomain): if likedByPerson(postJsonObject, nickname, fullDomain):
likeLink = 'unlike' likeLink = 'unlike'
likeTitle = translate['Undo the like'] likeTitle = translate['Undo the like']
# benchmark 12.2
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 12.2 = ' + str(timeDiff))
likeStr = \ likeStr = \
'<a class="imageAnchor" href="/users/' + nickname + '?' + \ '<a class="imageAnchor" href="/users/' + nickname + '?' + \
likeLink + '=' + postJsonObject['object']['id'] + \ likeLink + '=' + postJsonObject['object']['id'] + \
@ -4113,6 +4244,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
'" alt="' + likeTitle + \ '" alt="' + likeTitle + \
' |" src="/' + iconsDir + '/' + likeIcon + '"/></a>\n' ' |" src="/' + iconsDir + '/' + likeIcon + '"/></a>\n'
# benchmark 12.5
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 12.5 = ' + str(timeDiff))
bookmarkStr = '' bookmarkStr = ''
if not isModerationPost: if not isModerationPost:
bookmarkIcon = 'bookmark_inactive.png' bookmarkIcon = 'bookmark_inactive.png'
@ -4122,6 +4259,11 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
bookmarkIcon = 'bookmark.png' bookmarkIcon = 'bookmark.png'
bookmarkLink = 'unbookmark' bookmarkLink = 'unbookmark'
bookmarkTitle = translate['Undo the bookmark'] bookmarkTitle = translate['Undo the bookmark']
# benchmark 12.6
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 12.6 = ' + str(timeDiff))
bookmarkStr = \ bookmarkStr = \
'<a class="imageAnchor" href="/users/' + nickname + '?' + \ '<a class="imageAnchor" href="/users/' + nickname + '?' + \
bookmarkLink + '=' + postJsonObject['object']['id'] + \ bookmarkLink + '=' + postJsonObject['object']['id'] + \
@ -4134,8 +4276,20 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
bookmarkTitle + ' |" src="/' + iconsDir + \ bookmarkTitle + ' |" src="/' + iconsDir + \
'/' + bookmarkIcon + '"/></a>\n' '/' + bookmarkIcon + '"/></a>\n'
# benchmark 12.9
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 12.9 = ' + str(timeDiff))
isMuted = postIsMuted(baseDir, nickname, domain, postJsonObject, messageId) isMuted = postIsMuted(baseDir, nickname, domain, postJsonObject, messageId)
# benchmark 13
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 13 = ' + str(timeDiff))
deleteStr = '' deleteStr = ''
muteStr = '' muteStr = ''
if (allowDeletion or if (allowDeletion or
@ -4174,6 +4328,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
' |" title="' + translate['Undo mute'] + \ ' |" title="' + translate['Undo mute'] + \
'" src="/' + iconsDir+'/unmute.png"/></a>\n' '" src="/' + iconsDir+'/unmute.png"/></a>\n'
# benchmark 13.1
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 13.1 = ' + str(timeDiff))
replyAvatarImageInPost = '' replyAvatarImageInPost = ''
if showRepeatIcon: if showRepeatIcon:
if isAnnounced: if isAnnounced:
@ -4189,22 +4349,45 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
'" src="/' + iconsDir + \ '" src="/' + iconsDir + \
'/repeat_inactive.png" class="announceOrReply"/>\n' '/repeat_inactive.png" class="announceOrReply"/>\n'
else: else:
# benchmark 13.2
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName +
' 13.2 = ' + str(timeDiff))
announceNickname = None announceNickname = None
if attributedTo: if attributedTo:
announceNickname = getNicknameFromActor(attributedTo) announceNickname = getNicknameFromActor(attributedTo)
if announceNickname: if announceNickname:
announceDomain, announcePort = \ announceDomain, announcePort = \
getDomainFromActor(attributedTo) getDomainFromActor(attributedTo)
getPersonFromCache(baseDir, attributedTo, personCache) getPersonFromCache(baseDir, attributedTo,
personCache, allowDownloads)
announceDisplayName = \ announceDisplayName = \
getDisplayName(baseDir, attributedTo, personCache) getDisplayName(baseDir, attributedTo, personCache)
if announceDisplayName: if announceDisplayName:
# benchmark 13.3
if not allowDownloads:
timeDiff = \
int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName +
' 13.3 = ' + str(timeDiff))
if ':' in announceDisplayName: if ':' in announceDisplayName:
announceDisplayName = \ announceDisplayName = \
addEmojiToDisplayName(baseDir, httpPrefix, addEmojiToDisplayName(baseDir, httpPrefix,
nickname, domain, nickname, domain,
announceDisplayName, announceDisplayName,
False) False)
# benchmark 13.3.1
if not allowDownloads:
timeDiff = \
int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName +
' 13.3.1 = ' + str(timeDiff))
titleStr += \ titleStr += \
' <img loading="lazy" title="' + \ ' <img loading="lazy" title="' + \
translate['announces'] + '" alt="' + \ translate['announces'] + '" alt="' + \
@ -4218,7 +4401,16 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
postJsonObject['object']['attributedTo'] postJsonObject['object']['attributedTo']
announceAvatarUrl = \ announceAvatarUrl = \
getPersonAvatarUrl(baseDir, announceActor, getPersonAvatarUrl(baseDir, announceActor,
personCache) personCache, allowDownloads)
# benchmark 13.4
if not allowDownloads:
timeDiff = \
int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName +
' 13.4 = ' + str(timeDiff))
if announceAvatarUrl: if announceAvatarUrl:
idx = 'Show options for this person' idx = 'Show options for this person'
replyAvatarImageInPost = \ replyAvatarImageInPost = \
@ -4283,12 +4475,22 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
getDomainFromActor(replyActor) getDomainFromActor(replyActor)
if replyNickname and replyDomain: if replyNickname and replyDomain:
getPersonFromCache(baseDir, replyActor, getPersonFromCache(baseDir, replyActor,
personCache) personCache,
allowDownloads)
replyDisplayName = \ replyDisplayName = \
getDisplayName(baseDir, replyActor, getDisplayName(baseDir, replyActor,
personCache) personCache)
if replyDisplayName: if replyDisplayName:
if ':' in replyDisplayName: if ':' in replyDisplayName:
# benchmark 13.5
if not allowDownloads:
timeDiff = \
int((time.time() -
postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' +
boxName + ' 13.5 = ' +
str(timeDiff))
repDisp = replyDisplayName repDisp = replyDisplayName
replyDisplayName = \ replyDisplayName = \
addEmojiToDisplayName(baseDir, addEmojiToDisplayName(baseDir,
@ -4297,6 +4499,15 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
domain, domain,
repDisp, repDisp,
False) False)
# benchmark 13.6
if not allowDownloads:
timeDiff = \
int((time.time() -
postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' +
boxName + ' 13.6 = ' +
str(timeDiff))
titleStr += \ titleStr += \
' <img loading="lazy" title="' + \ ' <img loading="lazy" title="' + \
translate['replying to'] + \ translate['replying to'] + \
@ -4308,11 +4519,29 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
'<a href="' + inReplyTo + \ '<a href="' + inReplyTo + \
'">' + replyDisplayName + '</a>\n' '">' + replyDisplayName + '</a>\n'
# benchmark 13.7
if not allowDownloads:
timeDiff = int((time.time() -
postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName +
' 13.7 = ' + str(timeDiff))
# show avatar of person replied to # show avatar of person replied to
replyAvatarUrl = \ replyAvatarUrl = \
getPersonAvatarUrl(baseDir, getPersonAvatarUrl(baseDir,
replyActor, replyActor,
personCache) personCache,
allowDownloads)
# benchmark 13.8
if not allowDownloads:
timeDiff = int((time.time() -
postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName +
' 13.8 = ' + str(timeDiff))
if replyAvatarUrl: if replyAvatarUrl:
replyAvatarImageInPost = \ replyAvatarImageInPost = \
'<div class=' + \ '<div class=' + \
@ -4379,6 +4608,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
postJsonObject['object']['inReplyTo'] + \ postJsonObject['object']['inReplyTo'] + \
'">' + postDomain + '</a>\n' '">' + postDomain + '</a>\n'
# benchmark 14
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 14 = ' + str(timeDiff))
attachmentStr, galleryStr = \ attachmentStr, galleryStr = \
getPostAttachmentsAsHtml(postJsonObject, boxName, translate, getPostAttachmentsAsHtml(postJsonObject, boxName, translate,
isMuted, avatarLink.strip(), isMuted, avatarLink.strip(),
@ -4402,6 +4637,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
datetimeObject = parse(publishedStr) datetimeObject = parse(publishedStr)
publishedStr = datetimeObject.strftime("%a %b %d, %H:%M") publishedStr = datetimeObject.strftime("%a %b %d, %H:%M")
# benchmark 15
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 15 = ' + str(timeDiff))
publishedLink = messageId publishedLink = messageId
# blog posts should have no /statuses/ in their link # blog posts should have no /statuses/ in their link
if isBlogPost(postJsonObject): if isBlogPost(postJsonObject):
@ -4459,6 +4700,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
postJsonObject['object']['summary'], postJsonObject['object']['summary'],
postJsonObject['object']['content']) postJsonObject['object']['content'])
# benchmark 16
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 16 = ' + str(timeDiff))
if not isPatch: if not isPatch:
objectContent = \ objectContent = \
removeLongWords(postJsonObject['object']['content'], 40, []) removeLongWords(postJsonObject['object']['content'], 40, [])
@ -4499,6 +4746,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
else: else:
contentStr += cwContentStr contentStr += cwContentStr
# benchmark 17
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 17 = ' + str(timeDiff))
if postJsonObject['object'].get('tag') and not isPatch: if postJsonObject['object'].get('tag') and not isPatch:
contentStr = \ contentStr = \
replaceEmojiFromTags(contentStr, replaceEmojiFromTags(contentStr,
@ -4527,6 +4780,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
else: else:
postHtml = galleryStr postHtml = galleryStr
# benchmark 18
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 18 = ' + str(timeDiff))
if not showPublicOnly and storeToCache and \ if not showPublicOnly and storeToCache and \
boxName != 'tlmedia' and boxName != 'tlbookmarks' and \ boxName != 'tlmedia' and boxName != 'tlbookmarks' and \
boxName != 'bookmarks': boxName != 'bookmarks':
@ -4535,6 +4794,12 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
updateRecentPostsCache(recentPostsCache, maxRecentPosts, updateRecentPostsCache(recentPostsCache, maxRecentPosts,
postJsonObject, postHtml) postJsonObject, postHtml)
# benchmark 19
if not allowDownloads:
timeDiff = int((time.time() - postStartTime) * 1000)
if timeDiff > 100:
print('TIMING INDIV ' + boxName + ' 19 = ' + str(timeDiff))
return postHtml return postHtml
@ -4581,6 +4846,8 @@ def htmlTimeline(defaultTimeline: str,
YTReplacementDomain: str) -> str: YTReplacementDomain: str) -> str:
"""Show the timeline as html """Show the timeline as html
""" """
timelineStartTime = time.time()
accountDir = baseDir + '/accounts/' + nickname + '@' + domain accountDir = baseDir + '/accounts/' + nickname + '@' + domain
# should the calendar icon be highlighted? # should the calendar icon be highlighted?
@ -4651,6 +4918,11 @@ def htmlTimeline(defaultTimeline: str,
if not os.path.isfile(bannerFilename): if not os.path.isfile(bannerFilename):
bannerFile = 'banner.webp' bannerFile = 'banner.webp'
# benchmark 1
timeDiff = int((time.time() - timelineStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE TIMING ' + boxName + ' 1 = ' + str(timeDiff))
with open(cssFilename, 'r') as cssFile: with open(cssFilename, 'r') as cssFile:
# load css # load css
profileStyle = \ profileStyle = \
@ -4665,6 +4937,11 @@ def htmlTimeline(defaultTimeline: str,
# is the user a moderator? # is the user a moderator?
moderator = isModerator(baseDir, nickname) moderator = isModerator(baseDir, nickname)
# benchmark 2
timeDiff = int((time.time() - timelineStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE TIMING ' + boxName + ' 2 = ' + str(timeDiff))
# the appearance of buttons - highlighted or not # the appearance of buttons - highlighted or not
inboxButton = 'button' inboxButton = 'button'
blogsButton = 'button' blogsButton = 'button'
@ -4744,6 +5021,11 @@ def htmlTimeline(defaultTimeline: str,
'" src="/' + iconsDir + '/person.png"/></a>\n' '" src="/' + iconsDir + '/person.png"/></a>\n'
break break
# benchmark 3
timeDiff = int((time.time() - timelineStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE TIMING ' + boxName + ' 3 = ' + str(timeDiff))
# moderation / reports button # moderation / reports button
moderationButtonStr = '' moderationButtonStr = ''
if moderator and not minimal: if moderator and not minimal:
@ -4777,6 +5059,11 @@ def htmlTimeline(defaultTimeline: str,
tlStr = htmlHeader(cssFilename, profileStyle) tlStr = htmlHeader(cssFilename, profileStyle)
# benchmark 4
timeDiff = int((time.time() - timelineStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE TIMING ' + boxName + ' 4 = ' + str(timeDiff))
# what screen to go to when a new post is created # what screen to go to when a new post is created
if boxName == 'dm': if boxName == 'dm':
newPostButtonStr = \ newPostButtonStr = \
@ -4919,6 +5206,11 @@ def htmlTimeline(defaultTimeline: str,
translate['Search and follow'] + '" alt="| ' + \ translate['Search and follow'] + '" alt="| ' + \
translate['Search and follow'] + '" class="timelineicon"/></a>\n' translate['Search and follow'] + '" class="timelineicon"/></a>\n'
# benchmark 5
timeDiff = int((time.time() - timelineStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE TIMING ' + boxName + ' 5 = ' + str(timeDiff))
# the calendar button # the calendar button
calendarAltText = translate['Calendar'] calendarAltText = translate['Calendar']
if newCalendarEvent: if newCalendarEvent:
@ -4979,6 +5271,11 @@ def htmlTimeline(defaultTimeline: str,
'" name="submitInfo" value="' + translate['Info'] + '">\n' '" name="submitInfo" value="' + translate['Info'] + '">\n'
tlStr += '</div>\n</form>\n' tlStr += '</div>\n</form>\n'
# benchmark 6
timeDiff = int((time.time() - timelineStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE TIMING ' + boxName + ' 6 = ' + str(timeDiff))
if boxName == 'tlshares': if boxName == 'tlshares':
maxSharesPerAccount = itemsPerPage maxSharesPerAccount = itemsPerPage
return (tlStr + return (tlStr +
@ -4987,6 +5284,11 @@ def htmlTimeline(defaultTimeline: str,
maxSharesPerAccount, httpPrefix) + maxSharesPerAccount, httpPrefix) +
htmlFooter()) htmlFooter())
# benchmark 7
timeDiff = int((time.time() - timelineStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE TIMING ' + boxName + ' 7 = ' + str(timeDiff))
# show todays events buttons on the first inbox page # show todays events buttons on the first inbox page
if boxName == 'inbox' and pageNumber == 1: if boxName == 'inbox' and pageNumber == 1:
if todaysEventsCheck(baseDir, nickname, domain): if todaysEventsCheck(baseDir, nickname, domain):
@ -5015,6 +5317,11 @@ def htmlTimeline(defaultTimeline: str,
translate['Happening This Week'] + '</button></a>\n' + \ translate['Happening This Week'] + '</button></a>\n' + \
'</center>\n' '</center>\n'
# benchmark 8
timeDiff = int((time.time() - timelineStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE TIMING ' + boxName + ' 8 = ' + str(timeDiff))
# page up arrow # page up arrow
if pageNumber > 1: if pageNumber > 1:
tlStr += \ tlStr += \
@ -5036,6 +5343,8 @@ def htmlTimeline(defaultTimeline: str,
# show each post in the timeline # show each post in the timeline
for item in timelineJson['orderedItems']: for item in timelineJson['orderedItems']:
timelinePostStartTime = time.time()
if item['type'] == 'Create' or \ if item['type'] == 'Create' or \
item['type'] == 'Announce' or \ item['type'] == 'Announce' or \
item['type'] == 'Update': item['type'] == 'Update':
@ -5057,10 +5366,27 @@ def htmlTimeline(defaultTimeline: str,
preparePostFromHtmlCache(currTlStr, preparePostFromHtmlCache(currTlStr,
boxName, boxName,
pageNumber) pageNumber)
# benchmark cache post
timeDiff = \
int((time.time() -
timelinePostStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE POST CACHE TIMING ' +
boxName + ' = ' + str(timeDiff))
if not currTlStr: if not currTlStr:
# benchmark cache post
timeDiff = \
int((time.time() -
timelinePostStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE POST DISK TIMING START ' +
boxName + ' = ' + str(timeDiff))
# read the post from disk # read the post from disk
currTlStr = \ currTlStr = \
individualPostAsHtml(recentPostsCache, maxRecentPosts, individualPostAsHtml(False, recentPostsCache,
maxRecentPosts,
iconsDir, translate, pageNumber, iconsDir, translate, pageNumber,
baseDir, session, wfRequest, baseDir, session, wfRequest,
personCache, personCache,
@ -5074,6 +5400,13 @@ def htmlTimeline(defaultTimeline: str,
showIndividualPostIcons, showIndividualPostIcons,
manuallyApproveFollowers, manuallyApproveFollowers,
False, True) False, True)
# benchmark cache post
timeDiff = \
int((time.time() -
timelinePostStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE POST DISK TIMING ' +
boxName + ' = ' + str(timeDiff))
if currTlStr: if currTlStr:
itemCtr += 1 itemCtr += 1
@ -5081,6 +5414,11 @@ def htmlTimeline(defaultTimeline: str,
if boxName == 'tlmedia': if boxName == 'tlmedia':
tlStr += '</div>\n' tlStr += '</div>\n'
# benchmark 9
timeDiff = int((time.time() - timelineStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE TIMING ' + boxName + ' 9 = ' + str(timeDiff))
# page down arrow # page down arrow
if itemCtr > 2: if itemCtr > 2:
tlStr += \ tlStr += \
@ -5337,7 +5675,7 @@ def htmlIndividualPost(recentPostsCache: {}, maxRecentPosts: int,
postStr += followStr + '</p>\n' postStr += followStr + '</p>\n'
postStr += \ postStr += \
individualPostAsHtml(recentPostsCache, maxRecentPosts, individualPostAsHtml(True, recentPostsCache, maxRecentPosts,
iconsDir, translate, None, iconsDir, translate, None,
baseDir, session, wfRequest, personCache, baseDir, session, wfRequest, personCache,
nickname, domain, port, postJsonObject, nickname, domain, port, postJsonObject,
@ -5358,7 +5696,8 @@ def htmlIndividualPost(recentPostsCache: {}, maxRecentPosts: int,
postJsonObject = loadJson(postFilename) postJsonObject = loadJson(postFilename)
if postJsonObject: if postJsonObject:
postStr = \ postStr = \
individualPostAsHtml(recentPostsCache, maxRecentPosts, individualPostAsHtml(True, recentPostsCache,
maxRecentPosts,
iconsDir, translate, None, iconsDir, translate, None,
baseDir, session, wfRequest, baseDir, session, wfRequest,
personCache, personCache,
@ -5385,7 +5724,8 @@ def htmlIndividualPost(recentPostsCache: {}, maxRecentPosts: int,
# add items to the html output # add items to the html output
for item in repliesJson['orderedItems']: for item in repliesJson['orderedItems']:
postStr += \ postStr += \
individualPostAsHtml(recentPostsCache, maxRecentPosts, individualPostAsHtml(True, recentPostsCache,
maxRecentPosts,
iconsDir, translate, None, iconsDir, translate, None,
baseDir, session, wfRequest, baseDir, session, wfRequest,
personCache, personCache,
@ -5419,7 +5759,8 @@ def htmlPostReplies(recentPostsCache: {}, maxRecentPosts: int,
if repliesJson.get('orderedItems'): if repliesJson.get('orderedItems'):
for item in repliesJson['orderedItems']: for item in repliesJson['orderedItems']:
repliesStr += \ repliesStr += \
individualPostAsHtml(recentPostsCache, maxRecentPosts, individualPostAsHtml(True, recentPostsCache,
maxRecentPosts,
iconsDir, translate, None, iconsDir, translate, None,
baseDir, session, wfRequest, personCache, baseDir, session, wfRequest, personCache,
nickname, domain, port, item, nickname, domain, port, item,
@ -5552,7 +5893,7 @@ def htmlDeletePost(recentPostsCache: {}, maxRecentPosts: int,
httpPrefix + '://') httpPrefix + '://')
deletePostStr = htmlHeader(cssFilename, profileStyle) deletePostStr = htmlHeader(cssFilename, profileStyle)
deletePostStr += \ deletePostStr += \
individualPostAsHtml(recentPostsCache, maxRecentPosts, individualPostAsHtml(True, recentPostsCache, maxRecentPosts,
iconsDir, translate, pageNumber, iconsDir, translate, pageNumber,
baseDir, session, wfRequest, personCache, baseDir, session, wfRequest, personCache,
nickname, domain, port, postJsonObject, nickname, domain, port, postJsonObject,
@ -6251,6 +6592,7 @@ def htmlCalendar(translate: {},
else: else:
daysInMonth = \ daysInMonth = \
(date(year + 1, 1, 1) - date(year, monthNumber, 1)).days (date(year + 1, 1, 1) - date(year, monthNumber, 1)).days
# print('daysInMonth ' + str(monthNumber) + ': ' + str(daysInMonth))
cssFilename = baseDir + '/epicyon-calendar.css' cssFilename = baseDir + '/epicyon-calendar.css'
if os.path.isfile(baseDir + '/calendar.css'): if os.path.isfile(baseDir + '/calendar.css'):
@ -6304,7 +6646,9 @@ def htmlCalendar(translate: {},
dayOfMonth = 0 dayOfMonth = 0
dow = weekDayOfMonthStart(monthNumber, year) dow = weekDayOfMonthStart(monthNumber, year)
for weekOfMonth in range(1, 6): for weekOfMonth in range(1, 7):
if dayOfMonth == daysInMonth:
continue
calendarStr += ' <tr>\n' calendarStr += ' <tr>\n'
for dayNumber in range(1, 8): for dayNumber in range(1, 8):
if (weekOfMonth > 1 and dayOfMonth < daysInMonth) or \ if (weekOfMonth > 1 and dayOfMonth < daysInMonth) or \
@ -6636,7 +6980,8 @@ def htmlProfileAfterSearch(recentPostsCache: {}, maxRecentPosts: int,
if profileJson['icon'].get('url'): if profileJson['icon'].get('url'):
avatarUrl = profileJson['icon']['url'] avatarUrl = profileJson['icon']['url']
if not avatarUrl: if not avatarUrl:
avatarUrl = getPersonAvatarUrl(baseDir, personUrl, personCache) avatarUrl = getPersonAvatarUrl(baseDir, personUrl,
personCache, True)
displayName = searchNickname displayName = searchNickname
if profileJson.get('name'): if profileJson.get('name'):
displayName = profileJson['name'] displayName = profileJson['name']
@ -6730,7 +7075,7 @@ def htmlProfileAfterSearch(recentPostsCache: {}, maxRecentPosts: int,
if not item.get('object'): if not item.get('object'):
continue continue
profileStr += \ profileStr += \
individualPostAsHtml(recentPostsCache, maxRecentPosts, individualPostAsHtml(True, recentPostsCache, maxRecentPosts,
iconsDir, translate, None, baseDir, iconsDir, translate, None, baseDir,
session, cachedWebfingers, personCache, session, cachedWebfingers, personCache,
nickname, domain, port, nickname, domain, port,