Now that content is written pretty nicely, the whole blog is represented by a json object internally, thus it's very easy to pass the templating engine a json list and it construct an index page. There needs to be FEEDS.
My first thought was that, since the blog's structure is represented as a json tree why not just write that to a file directly simply:
writeFile(fg.jsonPath, $ blog)
The $
operator I learnt was the 'toString' of nim, with it being pretty
general to a good few types. I decided that instead of opening a config file for
each module I would instead make an object that holds all of the information
about what is to be generated like this:
type feedGenerator* = ref object of RootObj
rssEnabled: bool
rssPath: string
atomEnabled: bool
atomPath: string
jsonEnabled: bool
jsonPath: string
Then create a newFeedGenerator
proc that would return this object, this allows
me to set things up a little nicer in terms of default values and handling
undefined config variables etc. I changed this similarly in the html generation
module, and did some more error handling there.
I defined all the feed generation as async since they just write to a file and don't return anything, this seemed to speed up the program on the admittedly small test site I'd started.
RSS
I love RSS, it's only of my favourite things about the internet, I use Youtube
through RSS (with some macros for newsboat
) but had never really learnt about
the structure of the data; w3c's specification for RSS is actually really well
written and simple to understand with a validator tool being provided. Since the
blog was represented as a json object I just had to create the xml nodes
correctly.
RSS is composed of an <rss>
tag with a <channel>
and <item>
s in the
channel. The channel has information like 'what blog is this' (<title>
),
<link>
etc. Each item is then an entry in the blog similarly with <title>
,
<link>
, <pubDate>
and so on. The date must be in
RFC822 format which is a funny document to
read since only 10 time zones are named, 8 of them being North American; UTC is
also called 'UT' here ('GMT' is equivalent).
Nim xmltree macros for constructing xml nodes is nice with an example being:
<>title(newText(item["metadata"]["title"].getStr))
However this falls down when trying to create a namespace'd tag like the
suggested <atom:link>
as :
is a special character. Usually you can use
back ticks `` to escape something from the keywords (e.g. `template`) but
here the :
breaks it, making the node creation more like:
let atomLink = newElement("atom:link")
atomLink.attrs = {"href": blog["blog_url"].getStr & fg.atomPath,
"rel": "self",
"type":"application/rss+xml"}.toXmlAttributes
When writing rss to a file, I found some frustration as the $
operator (notice
how I introduced that earlier ;) ) printed xml 'pretty' where it hadn't with the
json. Looking at what $
was doing I managed to figure out how to print with no
whitespace or indentation.
var xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
xmlString.add(feed, addNewLines=false, indWidth=0)
writeFile(fg.rssPath, xmlString)
Template Blog Entries
A small problem I have now is writing blog entries in pelican I always forget
how the header line is supposed to look like and format etc. I decided to
instead add a subcommand that makes a template to the correct specification,
this is as simple as building and then pretty-printing a json object and writing
to a file. I think this tool is worth it because it makes writing blog posts
much nicer when you don't have to keep a template file around to copy and start
writing just simply mmb template -t "title"
. It could also be useful in
scripting, for example making automated blog posts with contents from a text
file, as all you would have to do is something like.
mmb template -t "title"
cat "mytext.txt" >> content/title.md
mmb publish
Up next
The biggest thing to get this usable at the moment is being able to in-line
static content in the content, I think I might be able to achieve this with the
templating engine having escaped the html I pass it but perhaps there will need
to be a pre-processing stage (slowing down the building :( ) to find something
along the lines of {static}
and replacing it with the directory.
I'd also be interested in some sort of implicit category system that uses the directory structure of the content directory to group posts into categories. Or simply defining the category in the header and creating category directories with their own indexes.
The code is now hosted here.