diff --git a/blog.py b/blog.py
index 2f0d4e70a..9963ae0ea 100644
--- a/blog.py
+++ b/blog.py
@@ -11,10 +11,10 @@ from datetime import datetime
from content import replaceEmojiFromTags
from webapp import getIconsDir
-from webapp import getPostAttachmentsAsHtml
from webapp import htmlHeader
from webapp import htmlFooter
-from webapp import addEmbeddedElements
+from webapp_media import addEmbeddedElements
+from webapp_utils import getPostAttachmentsAsHtml
from utils import getNicknameFromActor
from utils import getDomainFromActor
from utils import locatePost
diff --git a/daemon.py b/daemon.py
index 967aac905..f9c85e10d 100644
--- a/daemon.py
+++ b/daemon.py
@@ -143,11 +143,8 @@ from webapp import htmlGetLoginCredentials
from webapp import htmlNewPost
from webapp import htmlFollowConfirm
from webapp import htmlCalendar
-from webapp import htmlSearch
from webapp import htmlNewswireMobile
from webapp import htmlLinksMobile
-from webapp import htmlSearchEmoji
-from webapp import htmlSearchEmojiTextEntry
from webapp import htmlUnfollowConfirm
from webapp import htmlProfileAfterSearch
from webapp import htmlEditProfile
@@ -155,13 +152,16 @@ from webapp import htmlEditLinks
from webapp import htmlEditNewswire
from webapp import htmlEditNewsPost
from webapp import htmlTermsOfService
-from webapp import htmlSkillsSearch
-from webapp import htmlHistorySearch
-from webapp import htmlHashtagSearch
-from webapp import rssHashtagSearch
from webapp import htmlModerationInfo
-from webapp import htmlSearchSharedItems
from webapp import htmlHashtagBlocked
+from webapp_search import htmlSkillsSearch
+from webapp_search import htmlHistorySearch
+from webapp_search import htmlHashtagSearch
+from webapp_search import rssHashtagSearch
+from webapp_search import htmlSearchEmoji
+from webapp_search import htmlSearchSharedItems
+from webapp_search import htmlSearchEmojiTextEntry
+from webapp_search import htmlSearch
from shares import getSharesFeedForPerson
from shares import addShare
from shares import removeShare
diff --git a/delete.py b/delete.py
index 751b95aa0..3b195db7e 100644
--- a/delete.py
+++ b/delete.py
@@ -6,6 +6,8 @@ __maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
+import os
+from datetime import datetime
from utils import removeIdEnding
from utils import getStatusNumber
from utils import urlPermitted
@@ -295,3 +297,33 @@ def outboxDelete(baseDir: str, httpPrefix: str,
postFilename, debug, recentPostsCache)
if debug:
print('DEBUG: post deleted via c2s - ' + postFilename)
+
+
+def removeOldHashtags(baseDir: str, maxMonths: int) -> str:
+ """Remove old hashtags
+ """
+ if maxMonths > 11:
+ maxMonths = 11
+ maxDaysSinceEpoch = \
+ (datetime.utcnow() - datetime(1970, 1 + maxMonths, 1)).days
+ removeHashtags = []
+
+ for subdir, dirs, files in os.walk(baseDir + '/tags'):
+ for f in files:
+ tagsFilename = os.path.join(baseDir + '/tags', f)
+ if not os.path.isfile(tagsFilename):
+ continue
+ # get last modified datetime
+ modTimesinceEpoc = os.path.getmtime(tagsFilename)
+ lastModifiedDate = datetime.fromtimestamp(modTimesinceEpoc)
+ fileDaysSinceEpoch = (lastModifiedDate - datetime(1970, 1, 1)).days
+
+ # check of the file is too old
+ if fileDaysSinceEpoch < maxDaysSinceEpoch:
+ removeHashtags.append(tagsFilename)
+
+ for removeFilename in removeHashtags:
+ try:
+ os.remove(removeFilename)
+ except BaseException:
+ pass
diff --git a/inbox.py b/inbox.py
index 4916af2fa..5deb64b2a 100644
--- a/inbox.py
+++ b/inbox.py
@@ -58,7 +58,6 @@ from posts import sendSignedJson
from posts import sendToFollowersThread
from webapp import individualPostAsHtml
from webapp import getIconsDir
-from webapp import removeOldHashtags
from question import questionUpdateVotes
from media import replaceYouTube
from git import isGitPatch
@@ -66,6 +65,7 @@ from git import receiveGitPatch
from followingCalendar import receivingCalendarEvents
from content import dangerousMarkup
from happening import saveEventPost
+from delete import removeOldHashtags
def storeHashTags(baseDir: str, nickname: str, postJsonObject: {}) -> None:
diff --git a/posts.py b/posts.py
index ec59bc6db..5e16b369b 100644
--- a/posts.py
+++ b/posts.py
@@ -3977,3 +3977,27 @@ def sendUndoBlockViaServer(baseDir: str, session,
print('DEBUG: c2s POST block success')
return newBlockJson
+
+
+def postIsMuted(baseDir: str, nickname: str, domain: str,
+ postJsonObject: {}, messageId: str) -> bool:
+ """ Returns true if the given post is muted
+ """
+ isMuted = postJsonObject.get('muted')
+ if isMuted is True or isMuted is False:
+ return isMuted
+ postDir = baseDir + '/accounts/' + nickname + '@' + domain
+ muteFilename = \
+ postDir + '/inbox/' + messageId.replace('/', '#') + '.json.muted'
+ if os.path.isfile(muteFilename):
+ return True
+ muteFilename = \
+ postDir + '/outbox/' + messageId.replace('/', '#') + '.json.muted'
+ if os.path.isfile(muteFilename):
+ return True
+ muteFilename = \
+ baseDir + '/accounts/cache/announce/' + nickname + \
+ '/' + messageId.replace('/', '#') + '.json.muted'
+ if os.path.isfile(muteFilename):
+ return True
+ return False
diff --git a/utils.py b/utils.py
index b653d280c..23de5d1cf 100644
--- a/utils.py
+++ b/utils.py
@@ -1494,3 +1494,11 @@ def siteIsActive(url: str) -> bool:
if e.errno == errno.ECONNRESET:
print('WARN: connection was reset during siteIsActive')
return False
+
+
+def weekDayOfMonthStart(monthNumber: int, year: int) -> int:
+ """Gets the day number of the first day of the month
+ 1=sun, 7=sat
+ """
+ firstDayOfMonth = datetime(year, monthNumber, 1, 0, 0)
+ return int(firstDayOfMonth.strftime("%w")) + 1
diff --git a/webapp.py b/webapp.py
index dbfff8c99..b810d8fe9 100644
--- a/webapp.py
+++ b/webapp.py
@@ -8,10 +8,8 @@ __status__ = "Production"
import time
import os
-import urllib.parse
from datetime import datetime
from datetime import date
-from dateutil.parser import parse
from shutil import copyfile
from pprint import pprint
from person import personBoxJson
@@ -24,26 +22,15 @@ from ssb import getSSBAddress
from tox import getToxAddress
from matrix import getMatrixAddress
from donate import getDonationUrl
-from question import isQuestion
-from utils import firstParagraphFromString
+from utils import weekDayOfMonthStart
from utils import getCSS
from utils import isSystemAccount
from utils import removeIdEnding
-from utils import getProtocolPrefixes
-from utils import searchBoxPosts
-from utils import isEventPost
-from utils import isBlogPost
-from utils import isNewsPost
-from utils import updateRecentPostsCache
from utils import getNicknameFromActor
from utils import getDomainFromActor
from utils import locatePost
from utils import noOfAccounts
-from utils import isPublicPost
from utils import isPublicPostFromUrl
-from utils import getDisplayName
-from utils import getCachedPostDirectory
-from utils import getCachedPostFilename
from utils import loadJson
from utils import getConfigParam
from utils import votesOnNewswireItem
@@ -51,58 +38,40 @@ from utils import removeHtml
from follow import isFollowingActor
from follow import followerApprovalActive
from webfinger import webfingerHandle
-from posts import isDM
from posts import getPersonBox
from posts import getUserUrl
from posts import parseUserFeed
from posts import populateRepliesJson
from posts import isModerator
from posts import isEditor
-from posts import downloadAnnounce
from session import getJson
-from auth import createPassword
-from like import likedByPerson
-from like import noOfLikes
-from bookmarks import bookmarkedByPerson
-from announce import announcedByPerson
from blocking import isBlocked
-from blocking import isBlockedHashtag
-from content import htmlReplaceEmailQuote
-from content import htmlReplaceQuoteMarks
-from content import removeTextFormatting
-from content import switchWords
-from content import getMentionsFromHtml
-from content import addHtmlTags
-from content import replaceEmojiFromTags
from content import removeLongWords
from skills import getSkills
-from cache import getPersonFromCache
from shares import getValidSharedItemID
from happening import todaysEventsCheck
from happening import thisWeeksEventsCheck
from happening import getCalendarEvents
from happening import getTodaysEvents
-from git import isGitPatch
from theme import getThemesList
from petnames import getPetName
from followingCalendar import receivingCalendarEvents
-from devices import E2EEdecryptMessageFromDevice
-from feeds import rss2TagHeader
-from feeds import rss2TagFooter
from webapp_utils import getAltPath
-from webapp_utils import getContentWarningButton
from webapp_utils import getBlogAddress
from webapp_utils import getPersonAvatarUrl
-from webapp_utils import updateAvatarImageCache
from webapp_utils import getIconsDir
from webapp_utils import scheduledPostsExist
from webapp_utils import sharesTimelineJson
-from webapp_utils import postContainsPublic
from webapp_utils import getImageFile
from webapp_utils import getBannerFile
-from webapp_utils import getSearchBannerFile
from webapp_utils import getLeftImageFile
from webapp_utils import getRightImageFile
+from webapp_utils import htmlHeader
+from webapp_utils import htmlFooter
+from webapp_utils import addEmojiToDisplayName
+from webapp_utils import htmlPostSeparator
+from webapp_post import individualPostAsHtml
+from webapp_post import preparePostFromHtmlCache
def htmlFollowingList(cssCache: {}, baseDir: str,
@@ -171,246 +140,6 @@ def htmlFollowingDataList(baseDir: str, nickname: str,
return listStr
-def htmlSearchEmoji(cssCache: {}, translate: {},
- baseDir: str, httpPrefix: str,
- searchStr: str) -> str:
- """Search results for emoji
- """
- # emoji.json is generated so that it can be customized and the changes
- # will be retained even if default_emoji.json is subsequently updated
- if not os.path.isfile(baseDir + '/emoji/emoji.json'):
- copyfile(baseDir + '/emoji/default_emoji.json',
- baseDir + '/emoji/emoji.json')
-
- searchStr = searchStr.lower().replace(':', '').strip('\n').strip('\r')
- cssFilename = baseDir + '/epicyon-profile.css'
- if os.path.isfile(baseDir + '/epicyon.css'):
- cssFilename = baseDir + '/epicyon.css'
-
- emojiCSS = getCSS(baseDir, cssFilename, cssCache)
- if emojiCSS:
- if httpPrefix != 'https':
- emojiCSS = emojiCSS.replace('https://',
- httpPrefix + '://')
- emojiLookupFilename = baseDir + '/emoji/emoji.json'
-
- # create header
- emojiForm = htmlHeader(cssFilename, emojiCSS)
- emojiForm += '
' + \
- translate['Emoji Search'] + \
- '
'
-
- # does the lookup file exist?
- if not os.path.isfile(emojiLookupFilename):
- emojiForm += '' + \
- translate['No results'] + '
'
- emojiForm += htmlFooter()
- return emojiForm
-
- emojiJson = loadJson(emojiLookupFilename)
- if emojiJson:
- results = {}
- for emojiName, filename in emojiJson.items():
- if searchStr in emojiName:
- results[emojiName] = filename + '.png'
- for emojiName, filename in emojiJson.items():
- if emojiName in searchStr:
- results[emojiName] = filename + '.png'
- headingShown = False
- emojiForm += ''
- msgStr1 = translate['Copy the text then paste it into your post']
- msgStr2 = ':'
- emojiForm += ''
-
- emojiForm += htmlFooter()
- return emojiForm
-
-
-def htmlSearchSharedItems(cssCache: {}, translate: {},
- baseDir: str, searchStr: str,
- pageNumber: int,
- resultsPerPage: int,
- httpPrefix: str,
- domainFull: str, actor: str,
- callingDomain: str) -> str:
- """Search results for shared items
- """
- iconsDir = getIconsDir(baseDir)
- currPage = 1
- ctr = 0
- sharedItemsForm = ''
- searchStrLower = urllib.parse.unquote(searchStr)
- searchStrLower = searchStrLower.lower().strip('\n').strip('\r')
- searchStrLowerList = searchStrLower.split('+')
- cssFilename = baseDir + '/epicyon-profile.css'
- if os.path.isfile(baseDir + '/epicyon.css'):
- cssFilename = baseDir + '/epicyon.css'
-
- sharedItemsCSS = getCSS(baseDir, cssFilename, cssCache)
- if sharedItemsCSS:
- if httpPrefix != 'https':
- sharedItemsCSS = \
- sharedItemsCSS.replace('https://',
- httpPrefix + '://')
- sharedItemsForm = htmlHeader(cssFilename, sharedItemsCSS)
- sharedItemsForm += \
- '' + translate['Shared Items Search'] + \
- '
'
- resultsExist = False
- for subdir, dirs, files in os.walk(baseDir + '/accounts'):
- for handle in dirs:
- if '@' not in handle:
- continue
- contactNickname = handle.split('@')[0]
- sharesFilename = baseDir + '/accounts/' + handle + \
- '/shares.json'
- if not os.path.isfile(sharesFilename):
- continue
-
- sharesJson = loadJson(sharesFilename)
- if not sharesJson:
- continue
-
- for name, sharedItem in sharesJson.items():
- matched = True
- for searchSubstr in searchStrLowerList:
- subStrMatched = False
- searchSubstr = searchSubstr.strip()
- if searchSubstr in sharedItem['location'].lower():
- subStrMatched = True
- elif searchSubstr in sharedItem['summary'].lower():
- subStrMatched = True
- elif searchSubstr in sharedItem['displayName'].lower():
- subStrMatched = True
- elif searchSubstr in sharedItem['category'].lower():
- subStrMatched = True
- if not subStrMatched:
- matched = False
- break
- if matched:
- if currPage == pageNumber:
- sharedItemsForm += '\n'
- sharedItemsForm += \
- '
' + \
- sharedItem['displayName'] + '
\n'
- if sharedItem.get('imageUrl'):
- sharedItemsForm += \
- '
\n'
- sharedItemsForm += \
- '\n'
- sharedItemsForm += \
- '
' + sharedItem['summary'] + '
\n'
- sharedItemsForm += \
- '
' + translate['Type'] + \
- ': ' + sharedItem['itemType'] + ' '
- sharedItemsForm += \
- '' + translate['Category'] + \
- ': ' + sharedItem['category'] + ' '
- sharedItemsForm += \
- '' + translate['Location'] + \
- ': ' + sharedItem['location'] + '
\n'
- contactActor = \
- httpPrefix + '://' + domainFull + \
- '/users/' + contactNickname
- sharedItemsForm += \
- '
\n'
- if actor.endswith('/users/' + contactNickname):
- sharedItemsForm += \
- ' \n'
- sharedItemsForm += '
\n'
- if not resultsExist and currPage > 1:
- postActor = \
- getAltPath(actor, domainFull,
- callingDomain)
- # previous page link, needs to be a POST
- sharedItemsForm += \
- '\n'
- resultsExist = True
- ctr += 1
- if ctr >= resultsPerPage:
- currPage += 1
- if currPage > pageNumber:
- postActor = \
- getAltPath(actor, domainFull,
- callingDomain)
- # next page link, needs to be a POST
- sharedItemsForm += \
- '\n'
- break
- ctr = 0
- if not resultsExist:
- sharedItemsForm += \
- '' + translate['No results'] + '
\n'
- sharedItemsForm += htmlFooter()
- return sharedItemsForm
-
-
def htmlModerationInfo(cssCache: {}, translate: {},
baseDir: str, httpPrefix: str) -> str:
msgStr1 = \
@@ -477,494 +206,6 @@ def htmlModerationInfo(cssCache: {}, translate: {},
return infoForm
-def htmlHashtagSearch(cssCache: {},
- nickname: str, domain: str, port: int,
- recentPostsCache: {}, maxRecentPosts: int,
- translate: {},
- baseDir: str, hashtag: str, pageNumber: int,
- postsPerPage: int,
- session, wfRequest: {}, personCache: {},
- httpPrefix: str, projectVersion: str,
- YTReplacementDomain: str,
- showPublishedDateOnly: bool) -> str:
- """Show a page containing search results for a hashtag
- """
- if hashtag.startswith('#'):
- hashtag = hashtag[1:]
- hashtag = urllib.parse.unquote(hashtag)
- hashtagIndexFile = baseDir + '/tags/' + hashtag + '.txt'
- if not os.path.isfile(hashtagIndexFile):
- if hashtag != hashtag.lower():
- hashtag = hashtag.lower()
- hashtagIndexFile = baseDir + '/tags/' + hashtag + '.txt'
- if not os.path.isfile(hashtagIndexFile):
- print('WARN: hashtag file not found ' + hashtagIndexFile)
- return None
-
- iconsDir = getIconsDir(baseDir)
- separatorStr = htmlPostSeparator(baseDir, None)
-
- # check that the directory for the nickname exists
- if nickname:
- if not os.path.isdir(baseDir + '/accounts/' +
- nickname + '@' + domain):
- nickname = None
-
- # read the index
- with open(hashtagIndexFile, "r") as f:
- lines = f.readlines()
-
- # read the css
- cssFilename = baseDir + '/epicyon-profile.css'
- if os.path.isfile(baseDir + '/epicyon.css'):
- cssFilename = baseDir + '/epicyon.css'
-
- hashtagSearchCSS = getCSS(baseDir, cssFilename, cssCache)
- if hashtagSearchCSS:
- if httpPrefix != 'https':
- hashtagSearchCSS = \
- hashtagSearchCSS.replace('https://',
- httpPrefix + '://')
-
- # ensure that the page number is in bounds
- if not pageNumber:
- pageNumber = 1
- elif pageNumber < 1:
- pageNumber = 1
-
- # get the start end end within the index file
- startIndex = int((pageNumber - 1) * postsPerPage)
- endIndex = startIndex + postsPerPage
- noOfLines = len(lines)
- if endIndex >= noOfLines and noOfLines > 0:
- endIndex = noOfLines - 1
-
- # add the page title
- hashtagSearchForm = htmlHeader(cssFilename, hashtagSearchCSS)
- if nickname:
- hashtagSearchForm += '\n' + \
- '\n' + '\n'
- else:
- hashtagSearchForm += '\n' + \
- '#' + hashtag + '
\n' + '\n'
-
- # RSS link for hashtag feed
- hashtagSearchForm += ''
- hashtagSearchForm += \
- ''
-
- if startIndex > 0:
- # previous page link
- hashtagSearchForm += \
- ' \n' + \
- ' \n \n'
- index = startIndex
- while index <= endIndex:
- postId = lines[index].strip('\n').strip('\r')
- if ' ' not in postId:
- nickname = getNicknameFromActor(postId)
- if not nickname:
- index += 1
- continue
- else:
- postFields = postId.split(' ')
- if len(postFields) != 3:
- index += 1
- continue
- nickname = postFields[1]
- postId = postFields[2]
- postFilename = locatePost(baseDir, nickname, domain, postId)
- if not postFilename:
- index += 1
- continue
- postJsonObject = loadJson(postFilename)
- if postJsonObject:
- if not isPublicPost(postJsonObject):
- index += 1
- continue
- showIndividualPostIcons = False
- if nickname:
- showIndividualPostIcons = True
- allowDeletion = False
- hashtagSearchForm += separatorStr + \
- individualPostAsHtml(True, recentPostsCache,
- maxRecentPosts,
- iconsDir, translate, None,
- baseDir, session, wfRequest,
- personCache,
- nickname, domain, port,
- postJsonObject,
- None, True, allowDeletion,
- httpPrefix, projectVersion,
- 'search',
- YTReplacementDomain,
- showPublishedDateOnly,
- showIndividualPostIcons,
- showIndividualPostIcons,
- False, False, False)
- index += 1
-
- if endIndex < noOfLines - 1:
- # next page link
- hashtagSearchForm += \
- ' \n' + \
- ' ' + \
- ' '
- hashtagSearchForm += htmlFooter()
- return hashtagSearchForm
-
-
-def rssHashtagSearch(nickname: str, domain: str, port: int,
- recentPostsCache: {}, maxRecentPosts: int,
- translate: {},
- baseDir: str, hashtag: str,
- postsPerPage: int,
- session, wfRequest: {}, personCache: {},
- httpPrefix: str, projectVersion: str,
- YTReplacementDomain: str) -> str:
- """Show an rss feed for a hashtag
- """
- if hashtag.startswith('#'):
- hashtag = hashtag[1:]
- hashtag = urllib.parse.unquote(hashtag)
- hashtagIndexFile = baseDir + '/tags/' + hashtag + '.txt'
- if not os.path.isfile(hashtagIndexFile):
- if hashtag != hashtag.lower():
- hashtag = hashtag.lower()
- hashtagIndexFile = baseDir + '/tags/' + hashtag + '.txt'
- if not os.path.isfile(hashtagIndexFile):
- print('WARN: hashtag file not found ' + hashtagIndexFile)
- return None
-
- # check that the directory for the nickname exists
- if nickname:
- if not os.path.isdir(baseDir + '/accounts/' +
- nickname + '@' + domain):
- nickname = None
-
- # read the index
- lines = []
- with open(hashtagIndexFile, "r") as f:
- lines = f.readlines()
- if not lines:
- return None
-
- domainFull = domain
- if port:
- if port != 80 and port != 443:
- domainFull = domain + ':' + str(port)
-
- maxFeedLength = 10
- hashtagFeed = \
- rss2TagHeader(hashtag, httpPrefix, domainFull)
- for index in range(len(lines)):
- postId = lines[index].strip('\n').strip('\r')
- if ' ' not in postId:
- nickname = getNicknameFromActor(postId)
- if not nickname:
- index += 1
- if index >= maxFeedLength:
- break
- continue
- else:
- postFields = postId.split(' ')
- if len(postFields) != 3:
- index += 1
- if index >= maxFeedLength:
- break
- continue
- nickname = postFields[1]
- postId = postFields[2]
- postFilename = locatePost(baseDir, nickname, domain, postId)
- if not postFilename:
- index += 1
- if index >= maxFeedLength:
- break
- continue
- postJsonObject = loadJson(postFilename)
- if postJsonObject:
- if not isPublicPost(postJsonObject):
- index += 1
- if index >= maxFeedLength:
- break
- continue
- # add to feed
- if postJsonObject['object'].get('content') and \
- postJsonObject['object'].get('attributedTo') and \
- postJsonObject['object'].get('published'):
- published = postJsonObject['object']['published']
- pubDate = datetime.strptime(published, "%Y-%m-%dT%H:%M:%SZ")
- rssDateStr = pubDate.strftime("%a, %d %b %Y %H:%M:%S UT")
- hashtagFeed += ' - '
- hashtagFeed += \
- ' ' + \
- postJsonObject['object']['attributedTo'] + \
- ''
- if postJsonObject['object'].get('summary'):
- hashtagFeed += \
- ' ' + \
- postJsonObject['object']['summary'] + \
- ''
- description = postJsonObject['object']['content']
- description = firstParagraphFromString(description)
- hashtagFeed += \
- ' ' + description + ''
- hashtagFeed += \
- ' ' + rssDateStr + ''
- if postJsonObject['object'].get('attachment'):
- for attach in postJsonObject['object']['attachment']:
- if not attach.get('url'):
- continue
- hashtagFeed += \
- ' ' + attach['url'] + ''
- hashtagFeed += '
'
- index += 1
- if index >= maxFeedLength:
- break
-
- return hashtagFeed + rss2TagFooter()
-
-
-def htmlSkillsSearch(cssCache: {}, translate: {}, baseDir: str,
- httpPrefix: str,
- skillsearch: str, instanceOnly: bool,
- postsPerPage: int) -> str:
- """Show a page containing search results for a skill
- """
- if skillsearch.startswith('*'):
- skillsearch = skillsearch[1:].strip()
-
- skillsearch = skillsearch.lower().strip('\n').strip('\r')
-
- results = []
- # search instance accounts
- for subdir, dirs, files in os.walk(baseDir + '/accounts/'):
- for f in files:
- if not f.endswith('.json'):
- continue
- if '@' not in f:
- continue
- if f.startswith('inbox@'):
- continue
- actorFilename = os.path.join(subdir, f)
- actorJson = loadJson(actorFilename)
- if actorJson:
- if actorJson.get('id') and \
- actorJson.get('skills') and \
- actorJson.get('name') and \
- actorJson.get('icon'):
- actor = actorJson['id']
- for skillName, skillLevel in actorJson['skills'].items():
- skillName = skillName.lower()
- if not (skillName in skillsearch or
- skillsearch in skillName):
- continue
- skillLevelStr = str(skillLevel)
- if skillLevel < 100:
- skillLevelStr = '0' + skillLevelStr
- if skillLevel < 10:
- skillLevelStr = '0' + skillLevelStr
- indexStr = \
- skillLevelStr + ';' + actor + ';' + \
- actorJson['name'] + \
- ';' + actorJson['icon']['url']
- if indexStr not in results:
- results.append(indexStr)
- if not instanceOnly:
- # search actor cache
- for subdir, dirs, files in os.walk(baseDir + '/cache/actors/'):
- for f in files:
- if not f.endswith('.json'):
- continue
- if '@' not in f:
- continue
- if f.startswith('inbox@'):
- continue
- actorFilename = os.path.join(subdir, f)
- cachedActorJson = loadJson(actorFilename)
- if cachedActorJson:
- if cachedActorJson.get('actor'):
- actorJson = cachedActorJson['actor']
- if actorJson.get('id') and \
- actorJson.get('skills') and \
- actorJson.get('name') and \
- actorJson.get('icon'):
- actor = actorJson['id']
- for skillName, skillLevel in \
- actorJson['skills'].items():
- skillName = skillName.lower()
- if not (skillName in skillsearch or
- skillsearch in skillName):
- continue
- skillLevelStr = str(skillLevel)
- if skillLevel < 100:
- skillLevelStr = '0' + skillLevelStr
- if skillLevel < 10:
- skillLevelStr = '0' + skillLevelStr
- indexStr = \
- skillLevelStr + ';' + actor + ';' + \
- actorJson['name'] + \
- ';' + actorJson['icon']['url']
- if indexStr not in results:
- results.append(indexStr)
-
- results.sort(reverse=True)
-
- cssFilename = baseDir + '/epicyon-profile.css'
- if os.path.isfile(baseDir + '/epicyon.css'):
- cssFilename = baseDir + '/epicyon.css'
-
- skillSearchCSS = getCSS(baseDir, cssFilename, cssCache)
- if skillSearchCSS:
- if httpPrefix != 'https':
- skillSearchCSS = \
- skillSearchCSS.replace('https://',
- httpPrefix + '://')
- skillSearchForm = htmlHeader(cssFilename, skillSearchCSS)
- skillSearchForm += \
- '' + translate['Skills search'] + ': ' + \
- skillsearch + '
'
-
- if len(results) == 0:
- skillSearchForm += \
- '' + translate['No results'] + \
- '
'
- else:
- skillSearchForm += ''
- ctr = 0
- for skillMatch in results:
- skillMatchFields = skillMatch.split(';')
- if len(skillMatchFields) != 4:
- continue
- actor = skillMatchFields[1]
- actorName = skillMatchFields[2]
- avatarUrl = skillMatchFields[3]
- skillSearchForm += \
- ''
- ctr += 1
- if ctr >= postsPerPage:
- break
- skillSearchForm += ''
- skillSearchForm += htmlFooter()
- return skillSearchForm
-
-
-def htmlHistorySearch(cssCache: {}, translate: {}, baseDir: str,
- httpPrefix: str,
- nickname: str, domain: str,
- historysearch: str,
- postsPerPage: int, pageNumber: int,
- projectVersion: str,
- recentPostsCache: {},
- maxRecentPosts: int,
- session,
- wfRequest,
- personCache: {},
- port: int,
- YTReplacementDomain: str,
- showPublishedDateOnly: bool) -> str:
- """Show a page containing search results for your post history
- """
- if historysearch.startswith('!'):
- historysearch = historysearch[1:].strip()
-
- historysearch = historysearch.lower().strip('\n').strip('\r')
-
- boxFilenames = \
- searchBoxPosts(baseDir, nickname, domain,
- historysearch, postsPerPage)
-
- cssFilename = baseDir + '/epicyon-profile.css'
- if os.path.isfile(baseDir + '/epicyon.css'):
- cssFilename = baseDir + '/epicyon.css'
-
- historySearchCSS = getCSS(baseDir, cssFilename, cssCache)
- if historySearchCSS:
- if httpPrefix != 'https':
- historySearchCSS = \
- historySearchCSS.replace('https://',
- httpPrefix + '://')
- historySearchForm = htmlHeader(cssFilename, historySearchCSS)
-
- # add the page title
- historySearchForm += \
- '' + translate['Your Posts'] + '
'
-
- if len(boxFilenames) == 0:
- historySearchForm += \
- '' + translate['No results'] + \
- '
'
- return historySearchForm
-
- iconsDir = getIconsDir(baseDir)
- separatorStr = htmlPostSeparator(baseDir, None)
-
- # ensure that the page number is in bounds
- if not pageNumber:
- pageNumber = 1
- elif pageNumber < 1:
- pageNumber = 1
-
- # get the start end end within the index file
- startIndex = int((pageNumber - 1) * postsPerPage)
- endIndex = startIndex + postsPerPage
- noOfBoxFilenames = len(boxFilenames)
- if endIndex >= noOfBoxFilenames and noOfBoxFilenames > 0:
- endIndex = noOfBoxFilenames - 1
-
- index = startIndex
- while index <= endIndex:
- postFilename = boxFilenames[index]
- if not postFilename:
- index += 1
- continue
- postJsonObject = loadJson(postFilename)
- if not postJsonObject:
- index += 1
- continue
- showIndividualPostIcons = True
- allowDeletion = False
- historySearchForm += separatorStr + \
- individualPostAsHtml(True, recentPostsCache,
- maxRecentPosts,
- iconsDir, translate, None,
- baseDir, session, wfRequest,
- personCache,
- nickname, domain, port,
- postJsonObject,
- None, True, allowDeletion,
- httpPrefix, projectVersion,
- 'search',
- YTReplacementDomain,
- showPublishedDateOnly,
- showIndividualPostIcons,
- showIndividualPostIcons,
- False, False, False)
- index += 1
-
- historySearchForm += htmlFooter()
- return historySearchForm
-
-
def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
domain: str, port: int, httpPrefix: str,
defaultTimeline: str) -> str:
@@ -2831,40 +2072,6 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
return newPostForm
-def getFontFromCss(css: str) -> (str, str):
- """Returns the font name and format
- """
- if ' url(' not in css:
- return None, None
- fontName = css.split(" url(")[1].split(")")[0].replace("'", '')
- fontFormat = css.split(" format('")[1].split("')")[0]
- return fontName, fontFormat
-
-
-def htmlHeader(cssFilename: str, css: str, lang='en') -> str:
- htmlStr = '\n'
- htmlStr += '\n'
- htmlStr += ' \n'
- htmlStr += ' \n'
- fontName, fontFormat = getFontFromCss(css)
- if fontName:
- htmlStr += ' \n'
- htmlStr += ' \n'
- htmlStr += ' \n'
- htmlStr += ' \n'
- htmlStr += ' Epicyon\n'
- htmlStr += ' \n'
- htmlStr += ' \n'
- return htmlStr
-
-
-def htmlFooter() -> str:
- htmlStr = ' \n'
- htmlStr += '\n'
- return htmlStr
-
-
def htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
translate: {},
baseDir: str, httpPrefix: str,
@@ -3530,1775 +2737,6 @@ def individualFollowAsHtml(translate: {},
return resultStr
-def addEmbeddedAudio(translate: {}, content: str) -> str:
- """Adds embedded audio for mp3/ogg
- """
- if not ('.mp3' in content or '.ogg' in content):
- return content
-
- if '