From 19a64c7f93374313bfce1c6986258bf1b616f0b5 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 23 May 2020 09:41:50 +0000 Subject: [PATCH] Support rss version 3.0 blog feeds --- blog.py | 84 ++++++++++++++++++++++++++++++++++++++++++--- daemon.py | 34 ++++++++++++++++++ img/icons/rss3.png | Bin 0 -> 5439 bytes 3 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 img/icons/rss3.png diff --git a/blog.py b/blog.py index a4e4ed50..067487a8 100644 --- a/blog.py +++ b/blog.py @@ -295,6 +295,29 @@ def htmlBlogPostRSS2(authorized: bool, return rssStr +def htmlBlogPostRSS3(authorized: bool, + baseDir: str, httpPrefix: str, translate: {}, + nickname: str, domain: str, domainFull: str, + postJsonObject: {}, + handle: str, restrictToDomain: bool) -> str: + """Returns the RSS version 3 feed for a single blog post + """ + messageLink = '' + if postJsonObject['object'].get('id'): + messageLink = postJsonObject['object']['id'].replace('/statuses/', '/') + if not restrictToDomain or \ + (restrictToDomain and '/' + domain in messageLink): + if postJsonObject['object'].get('summary'): + published = postJsonObject['object']['published'] + pubDate = datetime.strptime(published, "%Y-%m-%dT%H:%M:%SZ") + titleStr = postJsonObject['object']['summary'] + rssDateStr = pubDate.strftime("%a, %d %b %Y %H:%M:%S UT") + rssStr = 'title: ' + titleStr + '\n' + rssStr += 'link: ' + messageLink + '\n' + rssStr += 'created: ' + rssDateStr + '\n\n' + return rssStr + + def htmlBlogPost(authorized: bool, baseDir: str, httpPrefix: str, translate: {}, nickname: str, domain: str, domainFull: str, @@ -317,14 +340,21 @@ def htmlBlogPost(authorized: bool, domainFull, postJsonObject, None, False) - # show rss link + # show rss links iconsDir = getIconsDir(baseDir) blogStr += '

' + blogStr += '' - blogStr += 'RSS' - blogStr += '

' + blogStr += 'RSS 2.0' + + blogStr += '' + blogStr += 'RSS 3.0' + + blogStr += '

' return blogStr + htmlFooter() return None @@ -479,6 +509,52 @@ def htmlBlogPageRSS2(authorized: bool, session, return blogRSS2 + rss2Footer() +def htmlBlogPageRSS3(authorized: bool, session, + baseDir: str, httpPrefix: str, translate: {}, + nickname: str, domain: str, port: int, + noOfItems: int, pageNumber: int) -> str: + """Returns an RSS version 3 feed containing posts + """ + if ' ' in nickname or '@' in nickname or \ + '\n' in nickname or '\r' in nickname: + return None + + domainFull = domain + if port: + if port != 80 and port != 443: + domainFull = domain + ':' + str(port) + + blogRSS3 = '' + + blogsIndex = baseDir + '/accounts/' + \ + nickname + '@' + domain + '/tlblogs.index' + if not os.path.isfile(blogsIndex): + return blogRSS3 + + timelineJson = createBlogsTimeline(session, baseDir, + nickname, domain, port, + httpPrefix, + noOfItems, False, False, + pageNumber) + + if not timelineJson: + return blogRSS3 + + if pageNumber is not None: + for item in timelineJson['orderedItems']: + if item['type'] != 'Create': + continue + + blogRSS3 += \ + htmlBlogPostRSS3(authorized, baseDir, + httpPrefix, translate, + nickname, domain, + domainFull, item, + None, True) + + return blogRSS3 + + def getBlogIndexesForAccounts(baseDir: str) -> {}: """ Get the index files for blogs for each account and add them to a dict diff --git a/daemon.py b/daemon.py index 4b6afc1f..4cc452c2 100644 --- a/daemon.py +++ b/daemon.py @@ -95,6 +95,7 @@ from config import getConfigParam from roles import setRole from roles import clearModeratorStatus from blog import htmlBlogPageRSS2 +from blog import htmlBlogPageRSS3 from blog import htmlBlogView from blog import htmlBlogPage from blog import htmlBlogPost @@ -1128,6 +1129,7 @@ class PubServer(BaseHTTPRequestHandler): self._benchmarkGETtimings(GETstartTime, GETtimings, 8) + # RSS 2.0 if self.path.startswith('/blog/') and \ self.path.endswith('/rss.xml'): nickname = self.path.split('/blog/')[1] @@ -1159,6 +1161,38 @@ class PubServer(BaseHTTPRequestHandler): self._404() return + # RSS 3.0 + if self.path.startswith('/blog/') and \ + self.path.endswith('/rss.txt'): + nickname = self.path.split('/blog/')[1] + if '/' in nickname: + nickname = nickname.split('/')[0] + if not nickname.startswith('rss.'): + if os.path.isdir(self.server.baseDir + + '/accounts/' + nickname + + '@' + self.server.domain): + if not self.server.session: + self.server.session = \ + createSession(self.server.useTor) + msg = \ + htmlBlogPageRSS3(authorized, + self.server.session, + self.server.baseDir, + self.server.httpPrefix, + self.server.translate, + nickname, + self.server.domain, + self.server.port, + maxPostsInRSSFeed, 1) + if msg is not None: + msg = msg.encode() + self._set_headers('text/plain; charset=utf-8', + len(msg), cookie, callingDomain) + self._write(msg) + return + self._404() + return + # show the main blog page if htmlGET and (self.path == '/blog' or self.path == '/blog/' or diff --git a/img/icons/rss3.png b/img/icons/rss3.png new file mode 100644 index 0000000000000000000000000000000000000000..83521cd1b479624e85a4eca787b8c757e03b7854 GIT binary patch literal 5439 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 literal 0 HcmV?d00001