Motor-Blog
Blog platform based on Tornado, MongoDB, and Motor. To be used with MarsEdit.
Prequisites
Features
-
Frontend: Motor-Blog runs in Tornado. It is very fast.
-
Editing: Motor-Blog has no admin panel, but supports MarsEdit.
-
Comments: Motor-Blog does not support comments natively, I recommend a third-party Javascript comments API like Disqus.
-
Customization: Appearance is completely customizable.
Installation
-
Install MongoDB and run it on the default port on the same machine as Motor-Blog
-
pip install -r requirements.txt
-
To migrate from a prior WordPress blog with migrate_from_wordpress.py you'll need Pandoc
Deployment
Development Deployment
Start MongoDB
mkdir data
mongod --dbpath data --logpath data/mongod.log --fork --setParameter textSearchEnabled=true
Copy motor_blog.conf.example to motor_blog.conf, edit it as desired. Start the application:
python server.py --debug --config=motor_blog.conf --ensure-indexes
Visit http://localhost:8888/blog
Production Deployment
I run Motor-Blog on http://emptysquare.net/blog with Nginx at the front and four server.py
processes.
Those processes and MongoDB are managed by Supervisor.
I've provided example config files in this repository in etc/
.
If you have an Nginx version with WebSocket support (1.3.13 or later)
then draft posts will autoreload when you update them from MarsEdit.
Run python server.py --ensure-indexes
at once when first installing Motor-Blog on a production MongoDB server.
(If you see an error when using the search box, "Can't canonicalize query: IndexNotFound text index required for $text query", it means you haven't done this step. In any case, running Motor-Blog without indexes built will risk performance problems.)
MarsEdit setup
In MarsEdit, do "File -> New Blog." Give it a name and the URL of your Motor-Blog's home page. MarsEdit auto-detects the rest. You'll need to enter the username and password you put in motor_blog.conf. In the "General" tab of your blog's settings, I suggest setting "Download the 1000 most recent posts on refresh," since Motor-Blog can handle it. Under "Editing," set Preview Text Filter to "Markdown", and Image Size "Defaults To Full Size".
When you're editing a post, do "View -> Excerpt" to edit the post's meta-description. This text appears in Google results as a snippet, or when sharing a link to the post on Facebook. Motor-Blog refuses the post if the meta-description field is over 155 characters. Do "View -> Slug Field" to set a custom slug as the final part of the post's URL. If you leave the slug empty, Motor-Blog slugifies the title.
Finally, you'll want to customize how MarsEdit inserts images.
This customization serves two purposes: first, we'll remove the width and height
from img
tags so Motor-Blog's responsive layout can fit them to the visitor's screen.
Second, we'll set images' title text is set to the same value as their alt-text,
since browsers display image titles as tooltips.
Open the MarsEdit Media Manager and select an image.
In the Media Manager's lower-right corner is a "Style" chooser,
with the option "Customize...":
Choose this and create a new image style with "opening markup" like this:
<img
style="display:block; margin-left:auto; margin-right:auto;"
src="#fileurl#"
alt="#alttext#"
title="#alttext#" />
Blogging
Motor-Blog renders Markdown with Python-Markdown. Plain inline code is surrounded by single backticks (``). Code blocks can be fenced in a number of styles, such as GitHub's:
```python
print "foo"
```
The list of languages
is whatever Pygments supports. The following are of
interest to Python coders like me: py
, py3
, pytb
and py3tb
for tracebacks, and pycon
for
console sessions.
Using a feature in the latest Python-Markdown, you can highlight specific lines in a code block:
```python hl_lines="2"
# Line 1.
# Line 2. This will have a yellow background
```
Customization
- Set your theme directory in
motor_blog.conf
. - The theme directory should contain a
templates
subdir with the same set of filenames as the example theme. Tornado templates or Jade templates are both supported. - Follow the example theme for inspiration.
- The
setting()
function is available to all templates, and gives access to values inmotor_blog.conf
.
A Tour of the Code
- server.py: Web application server
- motor_blog/: Package code
- web/
- handlers.py: RequestHandlers for the blog's website
- admin-templates/: Templates for login/out and viewing drafts
- theme/: Default theme for emptysquare.net, overridable with your theme
- api/: The XML-RPC API that MarsEdit uses
- models.py: schema definitions
- text/
- markup.py: convert from Markdown into HTML for display, including some custom syntax
- wordpress_to_markdown.py: convert from the WordPress's particular HTML to markdown, for migrate_from_wordpress.py
- abbrev.py: convert from HTML to truncated plain text for all-posts page
- tools/:
- migrate_from_wordpress.py: Tool for migrating from my old Wordpress blog to Motor-Blog. I wrote this tool when Motor didn't support GridFS, so it puts all media from Wordpress into single documents in the "media" collection, which brings us to...
- migrate_media_to_gridfs.py: Tool to migrate media from a single document per image in the "media" collection to GridFS.
- cache.py: Cache results from MongoDB, invalidate when events are emitted
- indexes.py: Index definitions for
server.py --ensure_indexes
- options.py: Configuration parsing
- web/