Skip to content

Instantly share code, notes, and snippets.

@andystanton
Last active July 30, 2017 16:15
Show Gist options
  • Save andystanton/5d1a6a7aa3b01b97c647 to your computer and use it in GitHub Desktop.
Save andystanton/5d1a6a7aa3b01b97c647 to your computer and use it in GitHub Desktop.
Ghost2Jekyll: Converts ghost 0.4.2 sqlite db posts to jekyll 2.3.0 markdown posts.

Ghost to Jekyll

A utility that takes a Ghost 0.4.2 blog sqlite db file, extracts the posts and converts them to Jekyll 2.3.0 markdown format.

Requirements

  • Python 3

Quick Start

  • Download ghost2jekyll.py and post-template.md to a new folder.
  • Execute python3 ghost2jekyll.py --dbfile=/path/to/ghost.db

The posts are created in a subfolder called posts.

Disclaimer

This script is provided to show how I migrated from Ghost 0.4.2 to Jekyll 2.3.0 and is used at your own risk. Back up your blog before trying it out.

#!/usr/bin/env python3
# This script is provided to show how I migrated from Ghost 0.4.2
# to Jekyll 2.3.0 and is used at your own risk. Back up your blog
# before trying it out.
def getPostTemplate():
with open('post-template.md', 'r') as f:
posttemplate = f.read()
f.closed
return posttemplate
def getDBPosts(dbPath):
import sqlite3
conn = sqlite3.connect(dbPath)
c = conn.cursor()
query = """SELECT
p.title,
p.created_at,
t.name,
p.markdown,
p.slug
FROM
posts p
LEFT JOIN
posts_tags pt ON pt.post_id=p.id
LEFT JOIN
tags t ON pt.tag_id=t.id"""
c.execute(query)
batchsize = 10
results = c.fetchmany(batchsize)
postDict = {}
while results:
from datetime import datetime
for post in results:
title = post[0]
created_at_str = str(post[1])
created_at_timestamp = int(created_at_str[0:len(created_at_str)-3])
created_at = datetime.fromtimestamp(created_at_timestamp)
tag_name = []
if post[2]:
tag_name = [post[2].replace(' ', '-')]
content = post[3]
slug = post[4]
t = title, created_at, tag_name, content, slug
if title not in postDict:
postDict[title] = t
else:
postDict[title][2].extend(tag_name)
results = c.fetchmany(batchsize)
conn.close()
return postDict
def writePosts(postDict):
import os
from shutil import rmtree
if os.path.isdir("posts"):
rmtree("posts")
os.mkdir("posts")
posttemplate = getPostTemplate()
for title, post in postDict.items():
print("Creating post:", title, "(" + str(post[1]) + ")")
postcontent = posttemplate
postcontent = postcontent.replace("{{post.title}}", post[0])
postcontent = postcontent.replace("{{post.date}}", post[1].isoformat(' '))
postcontent = postcontent.replace("{{post.tags}}", ' '.join(post[2]))
postcontent = postcontent.replace("{{post.content}}", post[3])
filename = post[1].date().isoformat() + "-" + post[4] + '.md'
postfile = open('posts/' + filename, 'w')
postfile.write(postcontent)
postfile.close()
def main():
import argparse
parser = argparse.ArgumentParser(
description='Ghost2Jekyll: Converts ghost 0.4.2 sqlite db posts to jekyll 2.3.0 markdown posts.'
)
parser.add_argument(
'--dbfile',
dest='filename',
metavar='FILE',
help='full path and filename of Ghost sqlite db file',
required=True
)
args = parser.parse_args()
posts = getDBPosts(args.filename)
writePosts(posts)
if __name__ == "__main__":
main()
layout title date tags
post
{{post.title}}
{"post.date"=>nil}
{"post.tags"=>nil}

{{post.content}}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment