From ecbd574cf62ece6eca41b1001244cc524213f577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaume=20Delcl=C3=B2s=20Coll?= Date: Thu, 29 Oct 2020 16:05:57 +0100 Subject: [PATCH 1/5] atom feed support --- README.md | 2 ++ setup.py | 3 +- ttbp/atom.py | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ttbp/core.py | 24 +++++++++++--- ttbp/ttbp.py | 26 ++++++++------- 5 files changed, 126 insertions(+), 18 deletions(-) create mode 100644 ttbp/atom.py diff --git a/README.md b/README.md index 538d30e..61c6113 100644 --- a/README.md +++ b/README.md @@ -236,6 +236,8 @@ instance of this yourself) * [mistune](https://pypi.python.org/pypi/mistune) * [inflect](https://pypi.python.org/pypi/inflect) * [six](https://pypi.python.org/pypi/six) +* [colorama](https://pypi.python.org/pypi/colorama) +* [feedgen](https://pypi.python.org/pypi/feedgen) ### contributing diff --git a/setup.py b/setup.py index ee2c1d3..a02f2e6 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,8 @@ setup( 'inflect', 'mistune', 'colorama', - 'six' + 'six', + 'feedgen', ], include_package_data = True, entry_points = { diff --git a/ttbp/atom.py b/ttbp/atom.py new file mode 100644 index 0000000..218ce76 --- /dev/null +++ b/ttbp/atom.py @@ -0,0 +1,89 @@ +#!/usr/bin/python + +''' +ttbp: tilde town blogging platform +(also known as the feels engine) +a console-based blogging program developed for tilde.town +copyright (c) 2016 ~endorphant (endorphant@tilde.town) + +atom.py: +Atom feed generation + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +the complete codebase is available at: +https://github.com/modgethanc/ttbp +''' +from . import config +from . import util +from feedgen.feed import FeedGenerator +import os +import mistune +import datetime + +def publish_atom(entry_filenames, settings): + fg = FeedGenerator() + url = (config.LIVE + config.USER + '/' + + str(settings.get("publish dir"))).rstrip('/') + fg.id(url) + fg.title("{}'s feels".format(config.USER)) + fg.author(name=config.USER) + fg.link(href=url+'/', rel='alternate') + fg.link(href=url+'/atom.xml', rel='self') + fg.language('en') # TODO: feels language should be configurable + + for filename in entry_filenames: + date = util.parse_date(filename) + title = "-".join(date) + name = "".join(date) + + path = os.path.join(config.MAIN_FEELS, filename) + with open(path) as f: + raw = f.read() + html = mistune.markdown(raw) + + fe = fg.add_entry() + fe.id(url+'/'+name) + fe.link(href=url+'/'+name+'.html', rel="alternate") + fe.title(title) + fe.author(name=config.USER) + fe.content(html, type="html") + try: # crashing because of an invalid date would be sad + year, month, day = [int(x) for x in date] + dt = datetime.datetime(year, month, day) + fe.updated(dt) + except ValueError: + pass + outfile = os.path.join(config.WWW, 'atom.xml') + fg.atom_file(outfile) + +def select_atom(): + publish = util.input_yn(""" +SETTING UP ATOM + +Atom is a syndication format similar to RSS. +it is used so that people can subscribe to blogs and other news sources. + +do you want to generate an atom feed for your feels along the HTML? +this setting only has effect if publishing is enabled. + +you can change this option any time. +""") + return publish diff --git a/ttbp/core.py b/ttbp/core.py index 157017a..470c2e1 100644 --- a/ttbp/core.py +++ b/ttbp/core.py @@ -43,6 +43,7 @@ from . import chatter from . import config from . import gopher from . import util +from . import atom FEED = os.path.join("/home", "endorphant", "public_html", "ttbp", "index.html") SETTINGS = {} @@ -95,6 +96,23 @@ def get_files(feelsdir=config.MAIN_FEELS): return files +def render(files): + out = "" + if publishing(): + write_html("index.html") + out += "posted to {url}/index.html\n\n> ".format( + url="/".join( + [config.LIVE+config.USER, + str(SETTINGS.get("publish dir"))])) + if SETTINGS.get('gopher'): + gopher.publish_gopher('feels', files) + out += "also posted to your ~/public_gopher!\n\n> " + if SETTINGS.get('atom'): + atom.publish_atom(files, SETTINGS) + out += "also posted to your atom feed {url}/atom.xml!\n\n> " + return out + + def load_files(feelsdir=config.MAIN_FEELS): ''' file loader @@ -108,11 +126,7 @@ def load_files(feelsdir=config.MAIN_FEELS): load_nopubs() FILES = get_files(feelsdir) - - if publishing(): - write_html("index.html") - if SETTINGS.get('gopher'): - gopher.publish_gopher('feels', FILES) + render(FILES) def load_nopubs(): """Load a list of the user's nopub entries. diff --git a/ttbp/ttbp.py b/ttbp/ttbp.py index d103c37..8ae8c28 100644 --- a/ttbp/ttbp.py +++ b/ttbp/ttbp.py @@ -50,6 +50,7 @@ from . import core from . import chatter from . import gopher from . import util +from . import atom __version__ = "0.12.2" __author__ = "endorphant to continue.\n\n".format(friend=chatter.say("friend"))) redraw() @@ -1202,16 +1213,7 @@ def write_entry(entry=os.path.join(config.MAIN_FEELS, "test.txt")): if SETTINGS.get("post as nopub"): core.toggle_nopub(os.path.basename(entry)) else: - if core.publishing(): - core.write_html("index.html") - left = "posted to {url}/index.html\n\n> ".format( - url="/".join( - [config.LIVE+config.USER, - str(SETTINGS.get("publish dir"))])) - - if SETTINGS.get('gopher'): - gopher.publish_gopher('feels', core.FILES) - left += "also posted to your ~/public_gopher!\n\n> " + left = core.render(core.FILES) #core.load_files() redraw(left + "thanks for sharing your feels!") From d337e65f97e926a12ce30c31e12d27c9383e39bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaume=20Delcl=C3=B2s=20Coll?= Date: Thu, 29 Oct 2020 16:32:41 +0100 Subject: [PATCH 2/5] make sure order is reverse chronological --- ttbp/atom.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ttbp/atom.py b/ttbp/atom.py index 218ce76..94d5cfe 100644 --- a/ttbp/atom.py +++ b/ttbp/atom.py @@ -49,7 +49,7 @@ def publish_atom(entry_filenames, settings): fg.link(href=url+'/atom.xml', rel='self') fg.language('en') # TODO: feels language should be configurable - for filename in entry_filenames: + for filename in sorted(entry_filenames): date = util.parse_date(filename) title = "-".join(date) name = "".join(date) @@ -59,7 +59,7 @@ def publish_atom(entry_filenames, settings): raw = f.read() html = mistune.markdown(raw) - fe = fg.add_entry() + fe = fg.add_entry(order='prepend') fe.id(url+'/'+name) fe.link(href=url+'/'+name+'.html', rel="alternate") fe.title(title) From 19a3eb02972553166dab82cf67138d835b80812e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaume=20Delcl=C3=B2s=20Coll?= Date: Thu, 29 Oct 2020 16:47:15 +0100 Subject: [PATCH 3/5] fix atom update datetime --- ttbp/atom.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ttbp/atom.py b/ttbp/atom.py index 94d5cfe..879a132 100644 --- a/ttbp/atom.py +++ b/ttbp/atom.py @@ -66,9 +66,7 @@ def publish_atom(entry_filenames, settings): fe.author(name=config.USER) fe.content(html, type="html") try: # crashing because of an invalid date would be sad - year, month, day = [int(x) for x in date] - dt = datetime.datetime(year, month, day) - fe.updated(dt) + fe.updated("-".join(date)+"T00:00:00Z") except ValueError: pass outfile = os.path.join(config.WWW, 'atom.xml') From 3a8630f2a79813c9afa3517c64f89ad96e3cba9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaume=20Delcl=C3=B2s=20Coll?= Date: Thu, 29 Oct 2020 17:00:54 +0100 Subject: [PATCH 4/5] actually good dates --- ttbp/atom.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ttbp/atom.py b/ttbp/atom.py index 879a132..46cc255 100644 --- a/ttbp/atom.py +++ b/ttbp/atom.py @@ -37,6 +37,8 @@ from feedgen.feed import FeedGenerator import os import mistune import datetime +import stat +import time def publish_atom(entry_filenames, settings): fg = FeedGenerator() @@ -66,7 +68,11 @@ def publish_atom(entry_filenames, settings): fe.author(name=config.USER) fe.content(html, type="html") try: # crashing because of an invalid date would be sad - fe.updated("-".join(date)+"T00:00:00Z") + fe.published("-".join(date)+"T00:00:00Z") + stats = os.stat(path) + updated = datetime.datetime.fromtimestamp(stats[stat.ST_MTIME], + datetime.timezone.utc) + fe.updated(updated.strftime('%Y-%m-%dT%H:%M:%SZ')) except ValueError: pass outfile = os.path.join(config.WWW, 'atom.xml') From 3e16943f326460cb6a7a909ed00f1dd7a57697f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaume=20Delcl=C3=B2s=20Coll?= Date: Thu, 29 Oct 2020 17:10:54 +0100 Subject: [PATCH 5/5] timezone info --- README.md | 1 + setup.py | 1 + ttbp/atom.py | 11 +++++++---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 61c6113..f10cb38 100644 --- a/README.md +++ b/README.md @@ -238,6 +238,7 @@ instance of this yourself) * [six](https://pypi.python.org/pypi/six) * [colorama](https://pypi.python.org/pypi/colorama) * [feedgen](https://pypi.python.org/pypi/feedgen) +* [dateutil](https://pypi.python.org/pypi/python-dateutil) ### contributing diff --git a/setup.py b/setup.py index a02f2e6..8e2ec14 100644 --- a/setup.py +++ b/setup.py @@ -22,6 +22,7 @@ setup( 'colorama', 'six', 'feedgen', + 'python-dateutil', ], include_package_data = True, entry_points = { diff --git a/ttbp/atom.py b/ttbp/atom.py index 46cc255..0d542b5 100644 --- a/ttbp/atom.py +++ b/ttbp/atom.py @@ -38,7 +38,7 @@ import os import mistune import datetime import stat -import time +from dateutil import tz def publish_atom(entry_filenames, settings): fg = FeedGenerator() @@ -50,6 +50,7 @@ def publish_atom(entry_filenames, settings): fg.link(href=url+'/', rel='alternate') fg.link(href=url+'/atom.xml', rel='self') fg.language('en') # TODO: feels language should be configurable + fg.updated(datetime.datetime.now(tz.tzlocal())) for filename in sorted(entry_filenames): date = util.parse_date(filename) @@ -68,11 +69,13 @@ def publish_atom(entry_filenames, settings): fe.author(name=config.USER) fe.content(html, type="html") try: # crashing because of an invalid date would be sad - fe.published("-".join(date)+"T00:00:00Z") + year, month, day = [int(x) for x in date] + fe.published(datetime.datetime(year, month, day, + tzinfo=tz.tzlocal())) stats = os.stat(path) updated = datetime.datetime.fromtimestamp(stats[stat.ST_MTIME], - datetime.timezone.utc) - fe.updated(updated.strftime('%Y-%m-%dT%H:%M:%SZ')) + tz.tzlocal()) + fe.updated(updated) except ValueError: pass outfile = os.path.join(config.WWW, 'atom.xml')