__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 utils import getConfigParam from follow import followerApprovalActive from person import isPersonSnoozed from webapp_utils import htmlPostSeparator from webapp_utils import getBannerFile from webapp_utils import htmlHeaderWithExternalStyle, htmlHeaderWithExternalStyles 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, headerNewsTabs 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) cssFiles = [] # TODO: Clean up - default load only one base css file # default css cssFiles.append(baseDir + '/epicyon-profile.css') if os.path.isfile(baseDir + '/epicyon.css'): cssFiles[0] = baseDir + '/epicyon.css' # TODO: Clean up and remove this override cssFiles[0] = 'base.css' # Get theme-specific css if exists - must be named '.css' themeName = getConfigParam(baseDir, 'theme') themePath = f'{baseDir}/theme/{themeName}.css' if os.path.isfile(themePath): cssFiles.append('theme/' + themeName + '.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)) # NOTE: This uses a variant function for multiple CSS files # TODO: Figure out a better approach tlStr = htmlHeaderWithExternalStyles(cssFiles) # benchmark 4 timeDiff = int((time.time() - timelineStartTime) * 1000) if timeDiff > 100: print('TIMELINE TIMING ' + boxName + ' 4 = ' + str(timeDiff)) _logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '4') # if this is a 'News' instance and we are viewing the features timeline newsHeader = False if defaultTimeline == 'tlfeatures':# and boxName == 'tlfeatures': newsHeader = True # Banner and "profile toggle" link tlStr += '
\n' # 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) if not newsHeader: tlStr += (f"\t" f"{translate['Switch to profile view']}\n") else: # TODO: News instances should ignore personalised banners # Currently uses the 'news' actor banner - as it remains unchanged tlStr += (f"\t" f"{translate['Features']}\n" f"\t
\n" f"\t\t#IndymediaBack\n" f"\t
\n") # Certain Epciyon pages should only be accessible via the 'User' page for News instances # TODO: The 'new...' pages appear to require handling elsewhere userPages = ['inbox', 'outbox', 'dm', 'tlreplies', 'tlblogs', 'tlmedia', 'tlshares', \ 'tlsaves', 'tlevents', 'tlbookmarks', 'moderation', 'search', \ 'followers', 'newfollowers', 'newdm', 'newpost', 'newblog', 'newevent', 'editprofile'] # Full row "navbar" if defaultTimeline == 'tlfeatures': # Show "tab" links instead of standard "buttons" tlStr += headerNewsTabs(boxName, translate, usersPath, baseDir, authorized, userPages) # Close banner div tlStr += '
\n' elif fullWidthTimelineButtonHeader: # Close banner div tlStr += '\n' tlStr += \ headerButtonsTimeline(defaultTimeline, boxName, pageNumber, translate, usersPath, minimal, moderator, manuallyApproveFollowers, baseDir, nickname, domain, timelineStartTime, iconsAsButtons, userPages) else: # Close banner div tlStr += '\n' # TODO: Should probably use a more generic class, easier to re-use and help simplify CSS # NOTE: Related also to class "page" added to 'webapp_create_post.py' # start the timeline tlStr += '
\n' domainFull = getFullDomain(domain, port) # For 'News' instances, only show standard "buttons" on "user" pages if defaultTimeline == 'tlfeatures' and boxName in userPages: tlStr += \ headerButtonsTimeline(defaultTimeline, boxName, pageNumber, translate, usersPath, minimal, moderator, manuallyApproveFollowers, baseDir, nickname, domain, timelineStartTime, iconsAsButtons, userPages) else: # left column leftColumnStr = \ getLeftColumnContent(baseDir, nickname, domainFull, httpPrefix, translate, iconsPath, editor, False, None, rssIconAtTop, True, False) tlStr += ' \n' # center column containing posts tlStr += '
\n' if not defaultTimeline == 'tlfeatures' and not fullWidthTimelineButtonHeader: tlStr += \ headerButtonsTimeline(defaultTimeline, boxName, pageNumber, translate, usersPath, minimal, moderator, manuallyApproveFollowers, baseDir, nickname, domain, timelineStartTime, iconsAsButtons, userPages) # 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' if defaultTimeline == 'tlfeatures' and boxName not in userPages: # right column rightColumnStr = getRightColumnContent(baseDir, nickname, domainFull, httpPrefix, translate, iconsPath, 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 += '\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: 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' # TODO: [rename] 'timelineicon' should maybe be more generic, e.g 'icon-button' # Generate HTML list for name, config in actionButtonList: if iconsAsButtons: classStr = 'button-test' else: # Currently 'timelineicon' denotes an icon instead of text button classStr = 'timelineicon' # NOTE: If iconClass is missing, expect some kind of failed output # CSS alone is responsible for what image will be displayed, etc if 'iconClass' in config: classStr += ' ' + config['iconClass'] if 'class' in config: classStr += ' ' + config['class'] if 'highlightLabel' in config: textStr = htmlHighlightLabel(translate[config['translateText']], config['highlightLabel']) else: textStr = translate[config['translateText']] actionButtonStr += (f"\t\t\t\t\n" f'\t\t\t\t\t
  • {textStr}
  • \n' f'\t\t\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 headerNewsTabs(boxName: str, translate: {}, usersPath: str, moderator: bool, baseDir: str) -> str: navTabList = [] navTabList.append(('tlnews', {'pageRef': '/tlnews', 'translateText': 'Features'} )) navTabList.append(('newswiremobile', {'pageRef': '/newswiremobile', 'translateText': 'News'} )) navTabList.append(('calendar', {'pageRef': '/calendar', 'translateText': 'Calendar'} )) navTabList.append(('linksmobile', {'pageRef': '/linksmobile', 'translateText': 'Links'} )) navTabList.append(('inbox', {'pageRef': '/inbox', 'translateText': 'User'} )) navStr = '\t\t\n' return navStr 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)