aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xpyblog86
-rw-r--r--source/blog/2015-05-05-new-blog-new-start.md42
-rw-r--r--source/css/theme.css8
-rw-r--r--source/img/README.rst2
-rw-r--r--source/img/icon.pngbin0 -> 6920 bytes
-rw-r--r--source/img/icon.svg134
-rw-r--r--templates/template.html2
7 files changed, 124 insertions, 150 deletions
diff --git a/pyblog b/pyblog
index 271a4684..687d8400 100755
--- a/pyblog
+++ b/pyblog
@@ -2,6 +2,8 @@
"""A simple blog generator with Pandoc as backend."""
+# TODO: Feed icon next to the CC icon.
+
import argparse
import datetime
import io
@@ -12,6 +14,7 @@ import subprocess
import sys
import tempfile
import time
+import urllib.parse
import xml.etree.ElementTree as ET
import bs4
@@ -133,11 +136,6 @@ class AtomEntry(object):
return ET.tostring(self.entry).decode('utf-8')
-# TODO:
-def new_post():
- pass
-
-
def generate_index(feed):
"""Generate index.html from index.md and a TOC."""
@@ -252,7 +250,7 @@ def generate_index_and_feed():
sys.stderr.write("wrote atom.xml\n")
-def generate(fresh=False):
+def generate_blog(fresh=False):
"""Generate the blog in BUILDDIR.
Parameters
@@ -344,6 +342,55 @@ def generate(fresh=False):
return failed_builds
+def generate(args):
+ """Wrapper for generate_blog(fresh=False)."""
+ exit(generate_blog(fresh=False))
+
+
+def regenerate(args):
+ """Wrapper for generate_blog(fresh=True)."""
+ exit(generate_blog(fresh=True))
+
+
+def sanitize(string):
+ """Sanitize string (title) for URI consumption."""
+ if isinstance(string, bytes):
+ string = string.decode('utf-8')
+ # to lowercase
+ string = string.lower()
+ # strip all non-word, non-hyphen and non-whitespace characters
+ string = re.sub(r"[^\w\s-]", "", string)
+ # replace consecutive whitespaces with a single hyphen
+ string = re.sub(r"\s+", "-", string)
+ # percent encode the result
+ return urllib.parse.quote(string)
+
+
+def new_post(args):
+ title = args.title
+ date = datetime.datetime.fromtimestamp(round(time.time()),
+ dateutil.tz.tzlocal())
+ filename_date = date.strftime("%Y-%m-%d")
+ iso_date = date.isoformat()
+ display_date = "%s %d, %d" % (date.strftime("%B"), date.day, date.year)
+ title_sanitized = sanitize(title)
+ filename = "%s-%s.md" % (filename_date, title_sanitized)
+ postdir = os.path.join(SOURCEDIR, "blog")
+ fullpath = os.path.join(postdir, filename)
+ if not os.path.isdir(postdir):
+ if os.path.exists(postdir):
+ os.remove(postdir)
+ os.mkdir(postdir, mode=0o755)
+ with open(fullpath, 'w', encoding='utf-8') as fd:
+ fd.write("---\n")
+ fd.write('title: "%s"\n' % title)
+ fd.write("date: %s\n" % iso_date)
+ fd.write("date-display: %s\n" % display_date)
+ fd.write("---\n")
+ sys.stderr.write("New post created in:\n")
+ print(fullpath)
+
+
# TODO:
def deploy():
pass
@@ -363,15 +410,26 @@ def main():
"""CLI interface."""
description = "Simple blog generator in Python with Pandoc as backend."
parser = argparse.ArgumentParser(description=description)
- parser.add_argument('action', choices=[
- 'generate', 'regenerate',
- ])
- args = parser.parse_args()
+ subparsers = parser.add_subparsers()
+
+ parser_generate = subparsers.add_parser(
+ "generate", aliases=["g", "gen"],
+ description="Generate new or changed objects.")
+ parser_generate.set_defaults(func=generate)
- if args.action == 'generate':
- exit(generate(fresh=False))
- elif args.action == 'regenerate':
- exit(generate(fresh=True))
+ parser_regenerate = subparsers.add_parser(
+ "regenerate", aliases=["r", "regen"],
+ description="Regenerate the entire blog afresh.")
+ parser_regenerate.set_defaults(func=regenerate)
+
+ parser_new_post = subparsers.add_parser(
+ "new_post", aliases=["n", "new"],
+ description="Create a new post with metadata pre-filled.")
+ parser_new_post.add_argument("title", help="title of the new post")
+ parser_new_post.set_defaults(func=new_post)
+
+ args = parser.parse_args()
+ exit(args.func(args))
if __name__ == '__main__':
diff --git a/source/blog/2015-05-05-new-blog-new-start.md b/source/blog/2015-05-05-new-blog-new-start.md
new file mode 100644
index 00000000..4fcdf0cb
--- /dev/null
+++ b/source/blog/2015-05-05-new-blog-new-start.md
@@ -0,0 +1,42 @@
+---
+title: "New blog, new start"
+date: 2015-05-05T02:42:44-07:00
+date-display: May 5, 2015
+---
+Octopress has been serving me for the past six months, during which even Octopress itself underwent major changes — in fact, [Octopress 3.0.0](https://github.com/octopress/octopress/releases/tag/v3.0.0) was only released 3 days ago, which I never got to try. Anyway, Octopress's heavily colored interface grew old on me fairly quickly. I'm especially unhappy with the inline `<code>` tag, which is always wrapped in a white box and stands out too much (worse still, there's no visual difference when such a `<code>` tag is placed inside an `<a>` tag). Since I use inline code/verbatim a lot, many of my articles were littered with arbitrary boxes everywhere.
+
+![Farewell, Octopress.](http://i.imgur.com/hxfSnOk.png)
+
+Apparently I need something simpler. Because
+
+> Simplicity is the ultimate sophistication.
+
+But how? Simiplicity 101: get rid of the "platform". There's no reason why I need a blogging platform like Jekyll (let alone the WordPress monster). When I initially switched to Octopress, I thought code highlighting was something fancy that I need heavy machinery to achieve, but it turned out that Pandoc is battery-included when it comes to syntax highting,[^pandoc] so all I need is to specify a highlight style, e.g., Pygments:
+
+[^pandoc]: Well, Pandoc is heavy-machinery, but it's both generic and self-contained, unlike a specialized blogging platform.
+
+```
+pandoc input.md --highlight-style=pygments --template template.html --output output.html
+```
+
+That's it. Write the Markdown, compile with Pandoc, instantly awesome. So the HTML posts are there (assuming the HTML template is written, which is not hard to kick off).
+
+The rest of the job is to design the stylesheets and compile the posts into a coherent blog — basically, generate an index. I was able to realize both in several hours. For the former task, I borrowed a lot from [mort.ninja](http://mort.ninja/) by [Mort Yao](https://github.com/soimort). Interestingly, we were born in the same city (Nanjing, China), and I benefit from at least two of his open source projects: [you-get](https://github.com/soimort/you-get) and [translate-shell](https://github.com/soimort/translate-shell). The latter task is more interesting but also not hard. I'm rolling my own toolchain in Python, which you can find in [`pyblog`](https://github.com/zmwangx/zmwangx.github.io/blob/source/pyblog). In fact, the complete source of this blog (down to how image assets are generated) are in the [`source` branch](https://github.com/zmwangx/zmwangx.github.io/tree/source) of my GitHub Pages repo, so you may take a look if you're interested. `pyblog` is highly specialized[^pyblog] and is still a work in progress at the time of writing, but it's already well capable of generating the blog — currently missing are auto gen-deploy and preview (with auto-update), which will also come soon.
+
+[^pyblog]: Which is fine since I don't expect anyone else to use it, anyway.
+
+By the way, the most annoying thing in the development process was working with XML and generating [the Atom feed](/atom.xml). Standard library `xml.etree.ElementTree` doesn't support the `![CDATA[` tag, and in the end I had to hack [library internals](https://github.com/zmwangx/zmwangx.github.io/blob/source/pyblog#L34-L54), which is likely to break in future versions. Remember the quotes?
+
+> XML is a classic political compromise: it balances the needs of man and machine by being equally unreadable to both.
+
+> XML combines the efficiency of text files with the readability of binary files.
+
+Sigh.
+
+Anyway, here is my new shiny blog.
+
+![Welcome to the completely revamped dl? cmplnts?](http://i.imgur.com/VS5f9eJ.png)
+
+It looks ten times better than Octopress, and ever builds much faster than Octopress[^speed]. As a bonus, the codebase is so small that it's super trivial to hack (no, not *that* hack).
+
+[^speed]: I have the impression that a complete build of all posts (about fifty of them) with `pyblog` is faster than regenerating for a single modified post in Octopress. That's in the context of absolutely no categories; when you have a dozen or more categories, Octopress slows down to a halt.
diff --git a/source/css/theme.css b/source/css/theme.css
index f125cc03..4fe7a1ff 100644
--- a/source/css/theme.css
+++ b/source/css/theme.css
@@ -64,6 +64,14 @@ blockquote {
font-style: italic;
}
+div.footnotes {
+ font-size: 10pt;
+}
+
+div.footnotes code {
+ font-size: 9.5pt;
+}
+
img {
display: block;
max-width: 100%;
diff --git a/source/img/README.rst b/source/img/README.rst
index cb7a633c..be3eabf7 100644
--- a/source/img/README.rst
+++ b/source/img/README.rst
@@ -2,7 +2,7 @@ The icon and favicon files are generated via the following commands: ::
cd source/img
xelatex icon.tex
- convert icon.pdf icon.svg
+ convert icon.pdf -quality 400 -resize 100x100 icon.png
for size in 16 32 48 144 152; do convert icon.pdf -density 400 -resize ${size}x${size} favicon-${size}.png; done
optipng favicon-16.png favicon-32.png favicon-48.png favicon-144.png favicon-152.png
convert favicon-16.png favicon-32.png favicon-48.png ../favicon.ico
diff --git a/source/img/icon.png b/source/img/icon.png
new file mode 100644
index 00000000..5f1f894b
--- /dev/null
+++ b/source/img/icon.png
Binary files differ
diff --git a/source/img/icon.svg b/source/img/icon.svg
deleted file mode 100644
index e74fd042..00000000
--- a/source/img/icon.svg
+++ /dev/null
@@ -1,134 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="567px" height="567px" viewBox="0 0 567 567" enable-background="new 0 0 567 567" xml:space="preserve"> <image id="image0" width="567" height="567" x="0" y="0"
- xlink:href="data:image/png;base64,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" />
-</svg>
diff --git a/templates/template.html b/templates/template.html
index ba826be1..de507642 100644
--- a/templates/template.html
+++ b/templates/template.html
@@ -36,7 +36,7 @@ $endfor$
<body>
<nav>
<div style="height:150px; width:100px; text-align:center;">
-<a href="/"><embed src="/img/icon.svg" type="image/svg+xml" height="100" width="100" style="padding: 2px 0;"></a>
+<a href="/"><img src="/img/icon.png" height="100" width="100" style="padding: 2px 0;"></a>
<div style="padding: 1px 0;"><a href="/"><strong>dl? cmplnts?</strong></a></div>
<div style="font-size: 9pt;">by <a href="https://github.com/zmwangx" target="_blank">Zhiming Wang</a></div>
</div>