__filename__ = "webapp_timeline.py" __author__ = "Bob Mottram" __license__ = "AGPL3+" __version__ = "1.1.0" __maintainer__ = "Bob Mottram" __email__ = "bob@freedombone.net" __status__ = "Production" import os import time from utils import getFullDomain from utils import isEditor from utils import removeIdEnding from follow import followerApprovalActive from person import isPersonSnoozed from webapp_utils import htmlPostSeparator from webapp_utils import getBannerFile from webapp_utils import htmlHeaderWithExternalStyle from webapp_utils import htmlFooter from webapp_utils import sharesTimelineJson from webapp_utils import htmlHighlightLabel from webapp_post import preparePostFromHtmlCache from webapp_post import individualPostAsHtml from webapp_column_left import getLeftColumnContent from webapp_column_right import getRightColumnContent from webapp_headerbuttons import headerButtonsTimeline from posts import isModerator def _logTimelineTiming(enableTimingLog: bool, timelineStartTime, boxName: str, debugId: str) -> None: """Create a log of timings for performance tuning """ if not enableTimingLog: return timeDiff = int((time.time() - timelineStartTime) * 1000) if timeDiff > 100: print('TIMELINE TIMING ' + boxName + ' ' + debugId + ' = ' + str(timeDiff)) def htmlTimeline(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, timelineJson: {}, boxName: str, allowDeletion: bool, httpPrefix: str, projectVersion: str, manuallyApproveFollowers: bool, minimal: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, moderator: bool, editor: bool, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, moderationActionStr: str, theme: str, peertubeInstances: []) -> str: """Show the timeline as html """ enableTimingLog = False timelineStartTime = time.time() # directory where icons are found # This changes depending upon theme iconsDir = getIconsDir(baseDir) separatorStr = '' if boxName != 'tlmedia': separatorStr = htmlPostSeparator(baseDir, None) # the css filename cssFilename = baseDir + '/epicyon-profile.css' if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' # filename of the banner shown at the top bannerFile, bannerFilename = \ getBannerFile(baseDir, nickname, domain, theme) _logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '1') # is the user a moderator? if not moderator: moderator = isModerator(baseDir, nickname) # is the user a site editor? if not editor: editor = isEditor(baseDir, nickname) _logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '2') # get the full domain, including any port number fullDomain = getFullDomain(domain, port) usersPath = '/users/' + nickname actor = httpPrefix + '://' + fullDomain + usersPath showIndividualPostIcons = True # benchmark 3 timeDiff = int((time.time() - timelineStartTime) * 1000) if timeDiff > 100: print('TIMELINE TIMING ' + boxName + ' 3 = ' + str(timeDiff)) tlStr = htmlHeaderWithExternalStyle(cssFilename, profileStyle) _logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '4') # if this is a news instance and we are viewing the news timeline newsHeader = False if defaultTimeline == 'tlfeatures' and boxName == 'tlfeatures': newsHeader = True # Banner and "profile toggle" link # TODO: This CSS should be moved out of the code # Items like this that can be different per user should be kept # in the user's folder and loaded as final CSS, to allow overwrite(s) tlStr += (f"\t" f"{translate['Switch to profile view']}\n") # Full Row of Buttons if fullWidthTimelineButtonHeader: tlStr += \ headerButtonsTimeline(defaultTimeline, boxName, pageNumber, translate, usersPath, minimal, moderator, manuallyApproveFollowers, baseDir, nickname, domain, timelineStartTime, iconsAsButtons) # start the timeline tlStr += '
\n' domainFull = getFullDomain(domain, port) # left column leftColumnStr = \ getLeftColumnContent(baseDir, nickname, domainFull, httpPrefix, translate, editor, False, None, rssIconAtTop, True, False) tlStr += '
\n' + \ leftColumnStr + '
\n' # center column containing posts tlStr += '
\n' if not fullWidthTimelineButtonHeader: tlStr += \ headerButtonsTimeline(defaultTimeline, boxName, pageNumber, translate, usersPath, minimal, moderator, manuallyApproveFollowers, baseDir, nickname, domain, timelineStartTime, iconsAsButtons) # second row of buttons for moderator actions if moderator and boxName == 'moderation': tlStr += \ '
' tlStr += '
\n' idx = 'Nickname or URL. Block using *@domain or nickname@domain' tlStr += \ ' ' + translate[idx] + '
\n' if moderationActionStr: tlStr += '
\n' else: tlStr += '
\n' tlStr += \ ' \n' tlStr += \ ' \n' tlStr += \ ' \n' tlStr += \ ' \n' tlStr += \ ' \n' tlStr += \ ' \n' tlStr += \ ' \n' tlStr += \ ' \n' tlStr += '
\n
\n' _logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '6') if boxName == 'tlshares': maxSharesPerAccount = itemsPerPage return (tlStr + _htmlSharesTimeline(translate, pageNumber, itemsPerPage, baseDir, actor, nickname, domain, port, maxSharesPerAccount, httpPrefix) + htmlFooter()) _logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '7') # page up arrow if pageNumber > 1: tlStr += \ '
\n' + \ ' ' + \
            translate['Page up'] + '\n' + \ '
\n' # show the posts itemCtr = 0 if timelineJson: # if this is the media timeline then add an extra gallery container if boxName == 'tlmedia': if pageNumber > 1: tlStr += '
' tlStr += '
\n' # show each post in the timeline for item in timelineJson['orderedItems']: if item['type'] == 'Create' or \ item['type'] == 'Announce' or \ item['type'] == 'Update': # is the actor who sent this post snoozed? if isPersonSnoozed(baseDir, nickname, domain, item['actor']): continue # is the post in the memory cache of recent ones? currTlStr = None if boxName != 'tlmedia' and \ recentPostsCache.get('index'): postId = \ removeIdEnding(item['id']).replace('/', '#') if postId in recentPostsCache['index']: if not item.get('muted'): if recentPostsCache['html'].get(postId): currTlStr = recentPostsCache['html'][postId] currTlStr = \ preparePostFromHtmlCache(currTlStr, boxName, pageNumber) _logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '10') if not currTlStr: _logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '11') # read the post from disk currTlStr = \ individualPostAsHtml(False, recentPostsCache, maxRecentPosts, translate, pageNumber, baseDir, session, cachedWebfingers, personCache, nickname, domain, port, item, None, True, allowDeletion, httpPrefix, projectVersion, boxName, YTReplacementDomain, showPublishedDateOnly, peertubeInstances, boxName != 'dm', showIndividualPostIcons, manuallyApproveFollowers, False, True) _logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '12') if currTlStr: itemCtr += 1 tlStr += currTlStr if separatorStr: tlStr += separatorStr if boxName == 'tlmedia': tlStr += '
\n' # page down arrow if itemCtr > 2: tlStr += \ '
\n' + \ ' ' + \
            translate['Page down'] + '\n' + \ '
\n' # end of timeline-posts tlStr += '
\n' # end of column-center tlStr += '
\n' # right column rightColumnStr = getRightColumnContent(baseDir, nickname, domainFull, httpPrefix, translate, moderator, editor, newswire, positiveVoting, False, None, True, showPublishAsIcon, rssIconAtTop, publishButtonAtTop, authorized, True) tlStr += '
' + \ rightColumnStr + '
\n' _logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '9') tlStr += '\n' tlStr += htmlFooter() return tlStr def htmlIndividualShare(actor: str, item: {}, translate: {}, showContact: bool, removeButton: bool) -> str: """Returns an individual shared item as html """ profileStr = '
\n' profileStr += '

' + item['displayName'] + '

\n' if item.get('imageUrl'): profileStr += '\n' profileStr += \ '' + translate['Item image'] + '\n\n' profileStr += '

' + item['summary'] + '

\n' profileStr += \ '

' + translate['Type'] + ': ' + item['itemType'] + ' ' profileStr += \ '' + translate['Category'] + ': ' + item['category'] + ' ' profileStr += \ '' + translate['Location'] + ': ' + item['location'] + '

\n' sharedesc = item['displayName'] if '<' not in sharedesc and '?' not in sharedesc: if showContact: contactActor = item['actor'] profileStr += \ '

\n' if removeButton: profileStr += \ ' \n' profileStr += '

\n' return profileStr def _htmlSharesTimeline(translate: {}, pageNumber: int, itemsPerPage: int, baseDir: str, actor: str, nickname: str, domain: str, port: int, maxSharesPerAccount: int, httpPrefix: str) -> str: """Show shared items timeline as html """ sharesJson, lastPage = \ sharesTimelineJson(actor, pageNumber, itemsPerPage, baseDir, maxSharesPerAccount) domainFull = getFullDomain(domain, port) actor = httpPrefix + '://' + domainFull + '/users/' + nickname timelineStr = '' if pageNumber > 1: timelineStr += \ '
\n' + \ ' ' + translate['Page up'] + '\n' + \ '
\n' separatorStr = htmlPostSeparator(baseDir, None) for published, item in sharesJson.items(): showContactButton = False if item['actor'] != actor: showContactButton = True showRemoveButton = False if item['actor'] == actor: showRemoveButton = True timelineStr += \ htmlIndividualShare(actor, item, translate, showContactButton, showRemoveButton) timelineStr += separatorStr if not lastPage: timelineStr += \ '
\n' + \ ' ' + translate['Page down'] + '\n' + \ '
\n' return timelineStr # TODO: Can this be re-implemented as injecting an additional CSS class ? # Would allow for much more opportunity to style def htmlHighlightLabel(label: str, highlight: bool) -> str: """If the give text should be highlighted then return the appropriate markup. This is so that in shell browsers, like lynx, it's possible to see if the replies or DM button are highlighted. """ if not highlight: return label return '*' + str(label) + '*' def headerButtonsTimeline(defaultTimeline: str, boxName: str, pageNumber: int, translate: {}, usersPath: str, minimal: bool, moderator: bool, manuallyApproveFollowers: bool, baseDir: str, nickname: str, domain: str, timelineStartTime, iconsAsButtons: bool) -> str: """Returns the header at the top of the timeline, containing buttons for inbox, outbox, search, calendar, etc """ accountDir = baseDir + '/accounts/' + nickname + '@' + domain # should the calendar icon be highlighted? newCalendarEvent = False calendarImage = 'calendar.png' calendarPath = '/calendar' calendarFile = accountDir + '/.newCalendar' if os.path.isfile(calendarFile): newCalendarEvent = True calendarImage = 'calendar_notify.png' with open(calendarFile, 'r') as calfile: calendarPath = calfile.read().replace('##sent##', '') calendarPath = calendarPath.replace('\n', '').replace('\r', '') # should the DM button be highlighted? newDM = False dmFile = accountDir + '/.newDM' if os.path.isfile(dmFile): newDM = True if boxName == 'dm': os.remove(dmFile) # should the Replies button be highlighted? newReply = False replyFile = accountDir + '/.newReply' if os.path.isfile(replyFile): newReply = True if boxName == 'tlreplies': os.remove(replyFile) # should the Shares button be highlighted? newShare = False newShareFile = accountDir + '/.newShare' if os.path.isfile(newShareFile): newShare = True if boxName == 'tlshares': os.remove(newShareFile) # should the Moderation/reports button be highlighted? newReport = False newReportFile = accountDir + '/.newReport' if os.path.isfile(newReportFile): newReport = True if boxName == 'moderation': os.remove(newReportFile) # start of the button header with inbox, outbox, etc # TODO: [rename] containerHeader -> menu (or similar) tlStr = '\t
\n' # TODO: Fix that the following two bools are equivalent # - Pick one and move on # if this is a news instance and we are viewing the news timeline newsHeader = False if defaultTimeline == 'tlnews' and boxName == 'tlnews': newsHeader = True isFeaturesTimeline = \ defaultTimeline == 'tlnews' and boxName == 'tlnews' # TODO: Easiest solution for News instance tab links # - Simply hide the button row # - Draw a separate
just for News tabs # if newsHeader: # tlStr += \ # '' + \ # '' # tlStr += \ # '' + \ # '' # TODO: Group _all_ items that are hidden in 'minimal' mode ? # - Are there others elsewhere in the code ? # All menu items default to text buttons # Add class "icon-button" to overwrite default behaviour # NOTE: Currently handled further down in loops over navButtonList and actionButtonList # Menu buttons are split into two sections # - Navigation buttons : Informational pages, e.g. Inbox # - Action buttons : More clear action, e.g. Search, Create Post # default appearance text; use CSS class(es) to re-style # A list of buttons to be rendered as html, # each item being a tuple containing # - ref name # - dictionary of unique config # Each dict has: # - pageRef : the url snippet # - translationText : text to be displayed # - highlightLabel : boolean to determine highlight # - isIcon : boolean to trigger specific CSS class addition(s) for icon buttons # - class : string of class(es) to append # - iconClass : string of class(es) to append, only regarding icons # Buttons should be added in the order you wish them to appear in the menu navButtonList = [] actionButtonList = [] # Too many buttons - some visibility can be toggled # TODO: Show/Hide menu buttons should not require page reload! # Implement checkbox method # Requires grouping the buttons that are shown/hidden ? # TODO: The 'minimal' attribute could be done using CSS class ? # Minimal View only shows: # - Inbox # - Outbox # - DM # - Replies # - News # TODO: Should this be in minimal view? 'Media' and 'Blogs' are not ... # NOTE: "Action" buttons (icons in default Epicyon) are always visible navButtonList.append(('inbox', {'pageRef': '/inbox', 'translateText': 'Inbox'} )) navButtonList.append(('outbox', {'pageRef': '/outbox', 'translateText': 'Outbox'} )) navButtonList.append(('dm', {'pageRef': '/dm', 'translateText': 'DM', 'highlightLabel': newDM} )) navButtonList.append(('tlreplies', {'pageRef': '/tlreplies', 'translateText': 'Replies', 'highlightLabel': newReply} )) if not minimal: navButtonList.append(('tlnews', {'pageRef': '/tlnews', 'translateText': 'News'} )) # The following translationText should be 'Article' for News instances navButtonList.append(('tlblogs', {'pageRef': '/tlblogs', 'translateText': 'Blogs'} )) navButtonList.append(('tlmedia', {'pageRef': '/tlmedia', 'translateText': 'Media'} )) navButtonList.append(('tlshares', {'pageRef': '/tlshares', 'translateText': 'Shares', 'highlightLabel': newShare} )) navButtonList.append(('tlbookmarks', {'pageRef': '/tlbookmarks', 'translateText': 'Bookmarks'} )) navButtonList.append(('tlevents', {'pageRef': '/tlevents', 'translateText': 'Events'} )) if moderator: navButtonList.append(('moderation', {'pageRef': '/moderation', 'translateText': 'Mod', 'highlightLabel': newReport} )) # Single out the "instance-type" button, and move to front of list # NOTE: Current instance types are: 'tlblogs', 'tlmedia', 'tlnews' for i, (name, config) in enumerate(navButtonList): if name == defaultTimeline: tmp = navButtonList.pop(i) navButtonList.insert(0, tmp) break # Generate HTML list navButtonStr = '\t\t\n' # start of headericons list # show an icon for new follow approvals followApprovals = False followRequestsFilename = \ baseDir + '/accounts/' + \ nickname + '@' + domain + '/followrequests.txt' if os.path.isfile(followRequestsFilename): with open(followRequestsFilename, 'r') as f: for line in f: if len(line) > 0: # show follow approvals icon followApprovals = True break # NOTE: Certain buttons only appear when relevant # TODO: Determine if approvals (currently appended at end of actionButtonList) # and events should be in a separate list; # e.g. notificationButtonList # Having its' own
for instance would allow more versatile styling if followApprovals: actionButtonList.append(('followers', {'pageRef': '/followers', 'translateText': 'Approve follow requests', 'iconClass': 'icon-newfollow'} )) # Only show todays events buttons on the first inbox page if boxName == 'inbox' and pageNumber == 1: if todaysEventsCheck(baseDir, nickname, domain): now = datetime.now() todayRef = '/calendar?year=' + str(now.year) + \ '?month=' + str(now.month) + \ '?day=' + str(now.day) actionButtonList.append(('today-event', {'pageRef': todayRef, 'translateText': 'Happening Today', 'class': 'button-event'} )) if thisWeeksEventsCheck(baseDir, nickname, domain): actionButtonList.append(('week-event', {'pageRef': '/calendar', 'translateText': 'Happening Today', 'class': 'button-event'} )) # NOTE: CSS used to show or hide these based on screen size actionButtonList.append(('newswire', {'pageRef': '/newswiremobile', 'translateText': 'Newswire', 'class': 'mobile-only', 'iconClass': 'icon-newswire'} )) actionButtonList.append(('links', {'pageRef': '/linksmobile', 'translateText': 'Edit Links', 'class': 'mobile-only', 'iconClass': 'icon-links'} )) # what screen to go to when a new post is created # The following produces one button/icon for "new post" dependent on current viewed page if boxName == 'dm': actionButtonList.append(('newdm', {'pageRef': '/newdm', 'translateText': 'Create a new DM'} )) elif boxName == 'tlblogs' or boxName == 'tlnews': actionButtonList.append(('newblog', {'pageRef': '/newblog', 'translateText': 'Create a new post'} )) elif boxName == 'tlevents': actionButtonList.append(('newevent', {'pageRef': '/newevent', 'translateText': 'Create a new event'} )) else: if not manuallyApproveFollowers: actionButtonList.append(('newpost', {'pageRef': '/newpost', 'translateText': 'Create a new post'} )) else: actionButtonList.append(('newfollowers', {'pageRef': '/newfollowers', 'translateText': 'Create a new post'} )) # 'icon-' is solely used for the CSS to load appropriate icon actionButtonList[-1][1]['iconClass'] = 'icon-newpost' actionButtonList.append(('calendar', {'pageRef': calendarPath, 'translateText': 'Calendar', 'iconClass': 'icon-calendar'} )) actionButtonList.append(('search', {'pageRef': '/search', 'translateText': 'Search', 'iconClass': 'icon-search'} )) actionButtonList.append(('minimal', {'pageRef': '/minimal', 'translateText': 'Show/Hide Buttons', 'iconClass': 'icon-showhide'} )) actionButtonStr = '\t\t
\n' actionButtonStr += '\t\t\t\n\t\t
\n' # benchmark 5 timeDiff = int((time.time() - timelineStartTime) * 1000) if timeDiff > 100: print('TIMELINE TIMING ' + boxName + ' 5 = ' + str(timeDiff)) # Compile HTML parts tlStr += navButtonStr + actionButtonStr # End header button section tlStr += '\t
\n' return tlStr def htmlShares(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, allowDeletion: bool, httpPrefix: str, projectVersion: str, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, theme: str, peertubeInstances: []) -> str: """Show the shares timeline as html """ manuallyApproveFollowers = \ followerApprovalActive(baseDir, nickname, domain) return htmlTimeline(cssCache, defaultTimeline, recentPostsCache, maxRecentPosts, translate, pageNumber, itemsPerPage, session, baseDir, cachedWebfingers, personCache, nickname, domain, port, None, 'tlshares', allowDeletion, httpPrefix, projectVersion, manuallyApproveFollowers, False, YTReplacementDomain, showPublishedDateOnly, newswire, False, False, positiveVoting, showPublishAsIcon, fullWidthTimelineButtonHeader, iconsAsButtons, rssIconAtTop, publishButtonAtTop, authorized, None, theme, peertubeInstances) def htmlInbox(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, inboxJson: {}, allowDeletion: bool, httpPrefix: str, projectVersion: str, minimal: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, theme: str, peertubeInstances: []) -> str: """Show the inbox as html """ manuallyApproveFollowers = \ followerApprovalActive(baseDir, nickname, domain) return htmlTimeline(cssCache, defaultTimeline, recentPostsCache, maxRecentPosts, translate, pageNumber, itemsPerPage, session, baseDir, cachedWebfingers, personCache, nickname, domain, port, inboxJson, 'inbox', allowDeletion, httpPrefix, projectVersion, manuallyApproveFollowers, minimal, YTReplacementDomain, showPublishedDateOnly, newswire, False, False, positiveVoting, showPublishAsIcon, fullWidthTimelineButtonHeader, iconsAsButtons, rssIconAtTop, publishButtonAtTop, authorized, None, theme, peertubeInstances) def htmlBookmarks(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, bookmarksJson: {}, allowDeletion: bool, httpPrefix: str, projectVersion: str, minimal: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, theme: str, peertubeInstances: []) -> str: """Show the bookmarks as html """ manuallyApproveFollowers = \ followerApprovalActive(baseDir, nickname, domain) return htmlTimeline(cssCache, defaultTimeline, recentPostsCache, maxRecentPosts, translate, pageNumber, itemsPerPage, session, baseDir, cachedWebfingers, personCache, nickname, domain, port, bookmarksJson, 'tlbookmarks', allowDeletion, httpPrefix, projectVersion, manuallyApproveFollowers, minimal, YTReplacementDomain, showPublishedDateOnly, newswire, False, False, positiveVoting, showPublishAsIcon, fullWidthTimelineButtonHeader, iconsAsButtons, rssIconAtTop, publishButtonAtTop, authorized, None, theme, peertubeInstances) def htmlEvents(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, bookmarksJson: {}, allowDeletion: bool, httpPrefix: str, projectVersion: str, minimal: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, theme: str, peertubeInstances: []) -> str: """Show the events as html """ manuallyApproveFollowers = \ followerApprovalActive(baseDir, nickname, domain) return htmlTimeline(cssCache, defaultTimeline, recentPostsCache, maxRecentPosts, translate, pageNumber, itemsPerPage, session, baseDir, cachedWebfingers, personCache, nickname, domain, port, bookmarksJson, 'tlevents', allowDeletion, httpPrefix, projectVersion, manuallyApproveFollowers, minimal, YTReplacementDomain, showPublishedDateOnly, newswire, False, False, positiveVoting, showPublishAsIcon, fullWidthTimelineButtonHeader, iconsAsButtons, rssIconAtTop, publishButtonAtTop, authorized, None, theme, peertubeInstances) def htmlInboxDMs(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, inboxJson: {}, allowDeletion: bool, httpPrefix: str, projectVersion: str, minimal: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, theme: str, peertubeInstances: []) -> str: """Show the DM timeline as html """ return htmlTimeline(cssCache, defaultTimeline, recentPostsCache, maxRecentPosts, translate, pageNumber, itemsPerPage, session, baseDir, cachedWebfingers, personCache, nickname, domain, port, inboxJson, 'dm', allowDeletion, httpPrefix, projectVersion, False, minimal, YTReplacementDomain, showPublishedDateOnly, newswire, False, False, positiveVoting, showPublishAsIcon, fullWidthTimelineButtonHeader, iconsAsButtons, rssIconAtTop, publishButtonAtTop, authorized, None, theme, peertubeInstances) def htmlInboxReplies(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, inboxJson: {}, allowDeletion: bool, httpPrefix: str, projectVersion: str, minimal: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, theme: str, peertubeInstances: []) -> str: """Show the replies timeline as html """ return htmlTimeline(cssCache, defaultTimeline, recentPostsCache, maxRecentPosts, translate, pageNumber, itemsPerPage, session, baseDir, cachedWebfingers, personCache, nickname, domain, port, inboxJson, 'tlreplies', allowDeletion, httpPrefix, projectVersion, False, minimal, YTReplacementDomain, showPublishedDateOnly, newswire, False, False, positiveVoting, showPublishAsIcon, fullWidthTimelineButtonHeader, iconsAsButtons, rssIconAtTop, publishButtonAtTop, authorized, None, theme, peertubeInstances) def htmlInboxMedia(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, inboxJson: {}, allowDeletion: bool, httpPrefix: str, projectVersion: str, minimal: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, theme: str, peertubeInstances: []) -> str: """Show the media timeline as html """ return htmlTimeline(cssCache, defaultTimeline, recentPostsCache, maxRecentPosts, translate, pageNumber, itemsPerPage, session, baseDir, cachedWebfingers, personCache, nickname, domain, port, inboxJson, 'tlmedia', allowDeletion, httpPrefix, projectVersion, False, minimal, YTReplacementDomain, showPublishedDateOnly, newswire, False, False, positiveVoting, showPublishAsIcon, fullWidthTimelineButtonHeader, iconsAsButtons, rssIconAtTop, publishButtonAtTop, authorized, None, theme, peertubeInstances) def htmlInboxBlogs(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, inboxJson: {}, allowDeletion: bool, httpPrefix: str, projectVersion: str, minimal: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, theme: str, peertubeInstances: []) -> str: """Show the blogs timeline as html """ return htmlTimeline(cssCache, defaultTimeline, recentPostsCache, maxRecentPosts, translate, pageNumber, itemsPerPage, session, baseDir, cachedWebfingers, personCache, nickname, domain, port, inboxJson, 'tlblogs', allowDeletion, httpPrefix, projectVersion, False, minimal, YTReplacementDomain, showPublishedDateOnly, newswire, False, False, positiveVoting, showPublishAsIcon, fullWidthTimelineButtonHeader, iconsAsButtons, rssIconAtTop, publishButtonAtTop, authorized, None, theme, peertubeInstances) def htmlInboxFeatures(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, inboxJson: {}, allowDeletion: bool, httpPrefix: str, projectVersion: str, minimal: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, theme: str, peertubeInstances: []) -> str: """Show the features timeline as html """ return htmlTimeline(cssCache, defaultTimeline, recentPostsCache, maxRecentPosts, translate, pageNumber, itemsPerPage, session, baseDir, cachedWebfingers, personCache, nickname, domain, port, inboxJson, 'tlfeatures', allowDeletion, httpPrefix, projectVersion, False, minimal, YTReplacementDomain, showPublishedDateOnly, newswire, False, False, positiveVoting, showPublishAsIcon, fullWidthTimelineButtonHeader, iconsAsButtons, rssIconAtTop, publishButtonAtTop, authorized, None, theme, peertubeInstances) def htmlInboxNews(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, inboxJson: {}, allowDeletion: bool, httpPrefix: str, projectVersion: str, minimal: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, moderator: bool, editor: bool, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, theme: str, peertubeInstances: []) -> str: """Show the news timeline as html """ return htmlTimeline(cssCache, defaultTimeline, recentPostsCache, maxRecentPosts, translate, pageNumber, itemsPerPage, session, baseDir, cachedWebfingers, personCache, nickname, domain, port, inboxJson, 'tlnews', allowDeletion, httpPrefix, projectVersion, False, minimal, YTReplacementDomain, showPublishedDateOnly, newswire, moderator, editor, positiveVoting, showPublishAsIcon, fullWidthTimelineButtonHeader, iconsAsButtons, rssIconAtTop, publishButtonAtTop, authorized, None, theme, peertubeInstances) def htmlOutbox(cssCache: {}, defaultTimeline: str, recentPostsCache: {}, maxRecentPosts: int, translate: {}, pageNumber: int, itemsPerPage: int, session, baseDir: str, cachedWebfingers: {}, personCache: {}, nickname: str, domain: str, port: int, outboxJson: {}, allowDeletion: bool, httpPrefix: str, projectVersion: str, minimal: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, positiveVoting: bool, showPublishAsIcon: bool, fullWidthTimelineButtonHeader: bool, iconsAsButtons: bool, rssIconAtTop: bool, publishButtonAtTop: bool, authorized: bool, theme: str, peertubeInstances: []) -> str: """Show the Outbox as html """ manuallyApproveFollowers = \ followerApprovalActive(baseDir, nickname, domain) return htmlTimeline(cssCache, defaultTimeline, recentPostsCache, maxRecentPosts, translate, pageNumber, itemsPerPage, session, baseDir, cachedWebfingers, personCache, nickname, domain, port, outboxJson, 'outbox', allowDeletion, httpPrefix, projectVersion, manuallyApproveFollowers, minimal, YTReplacementDomain, showPublishedDateOnly, newswire, False, False, positiveVoting, showPublishAsIcon, fullWidthTimelineButtonHeader, iconsAsButtons, rssIconAtTop, publishButtonAtTop, authorized, None, theme, peertubeInstances)