Blogger posts from markdown and CLI
There are plans to migrate Silly Bytes to Hakyll
and GitHub pages, but till then I’m still stuck with Blogger and wanted to make
the posting process as painless and automatic as possible.
Every post I write is currently a separate git repo hosted on the Silly Bytes
GitHub organization. The post is written and
maintained in Markdown using Pandoc and a convenient Makefile generated by the
made script.
Writing posts in Markdown is nice but is not that advantageous if you still have to
mess around with Blogger’s web interface, so here is the plan:
- Write posts in Markdown
- Use made to generate a Makefile
- Generate HTML with
$ make
- Push the HTML post to Blogger using Google’s APIs
The first 3 steps are already covered so lets dig into the Blogger negotiation
part.
API script
Google’s
APIs
come in handy here, the best language option was Python (I refuse tu use
Java). So starting from
an
example
I came up with this helper script:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
from googleapiclient import discovery
from oauth2client import client
from oauth2client import file
from oauth2client import tools
import sys
import os
import httplib2
import argparse
="1318550761233559867"
SILLYBYTESID
def main(argv):
if (len(argv) < 3):
print("Post title must be provided as the first argument and html file as the second")
1)
exit(
= argv[1]
post_title = argv[2]
input_file
= 'https://www.googleapis.com/auth/blogger'
scope
= [tools.argparser]
parent_parsers
parent_parsers.extend([])= argparse.ArgumentParser(
parser =__doc__,
description=argparse.RawDescriptionHelpFormatter,
formatter_class=parent_parsers)
parents= parser.parse_args("")
flags
try:
= os.path.join(os.path.expanduser("~") + '/.sillybytes/',
client_secrets 'secrets.json')
except:
print("Can't find secrets.json file maybe?")
1)
exit(
= client.flow_from_clientsecrets(client_secrets,
flow =scope,
scope=tools.message_if_missing(client_secrets))
message
= file.Storage('auth_data' + '.dat')
storage = storage.get()
credentials if credentials is None or credentials.invalid:
= tools.run_flow(flow, storage, flags)
credentials
= credentials.authorize(http = httplib2.Http())
http = discovery.build('blogger', 'v3', http=http)
service
try:
= open(input_file, 'r').read()
content except FileNotFoundError:
print("Input file not found")
1)
exit(
= {
body "kind": "blogger#post",
"title": post_title,
"content": content
}
try:
= service.posts()
posts = posts.insert(blogId=SILLYBYTESID, body=body, isDraft=False)
request = request.execute()
result print("Live: " + result['url'])
except:
print("Can't execute request")
1)
exit(
if __name__ == '__main__':
main(sys.argv)
The script will initiate an OAuth negotiation when needed and store the
authentication tokens in the auth_data.dat
file.
API project
Before we’re able to use this we need to create a new API project, configure
it and get the client_secrets.json
that the script will use to start the OAuth
negotiation.
First, enable the Blogger API at:
https://console.developers.google.com/apis/library
Then create a new project, a new set of credentials and download the JSON file
from it. From the script above you’ll gather my client_secrets.json
file will
be located at ~/.sillybytes
.
Now, running:
$ python deploy.py "post title" "post HTML"
Will push the post to Blogger!
CLI tool
This is good enough already, we could just invoke deploy.py
from the Makefile,
but we can still do better:
$ silly help
Now I can create all the post boilerplate by doing silly new
and deploying the
current post with silly deploy
. Much better.
There are plans to migrate Silly Bytes to Hakyll and GitHub pages, but till then I’m still stuck with Blogger and wanted to make the posting process as painless and automatic as possible.
Every post I write is currently a separate git repo hosted on the Silly Bytes GitHub organization. The post is written and maintained in Markdown using Pandoc and a convenient Makefile generated by the made script.
Writing posts in Markdown is nice but is not that advantageous if you still have to mess around with Blogger’s web interface, so here is the plan:
- Write posts in Markdown
- Use made to generate a Makefile
- Generate HTML with
$ make
- Push the HTML post to Blogger using Google’s APIs
The first 3 steps are already covered so lets dig into the Blogger negotiation part.
API script
Google’s APIs come in handy here, the best language option was Python (I refuse tu use Java). So starting from an example I came up with this helper script:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
from googleapiclient import discovery
from oauth2client import client
from oauth2client import file
from oauth2client import tools
import sys
import os
import httplib2
import argparse
="1318550761233559867"
SILLYBYTESID
def main(argv):
if (len(argv) < 3):
print("Post title must be provided as the first argument and html file as the second")
1)
exit(
= argv[1]
post_title = argv[2]
input_file
= 'https://www.googleapis.com/auth/blogger'
scope
= [tools.argparser]
parent_parsers
parent_parsers.extend([])= argparse.ArgumentParser(
parser =__doc__,
description=argparse.RawDescriptionHelpFormatter,
formatter_class=parent_parsers)
parents= parser.parse_args("")
flags
try:
= os.path.join(os.path.expanduser("~") + '/.sillybytes/',
client_secrets 'secrets.json')
except:
print("Can't find secrets.json file maybe?")
1)
exit(
= client.flow_from_clientsecrets(client_secrets,
flow =scope,
scope=tools.message_if_missing(client_secrets))
message
= file.Storage('auth_data' + '.dat')
storage = storage.get()
credentials if credentials is None or credentials.invalid:
= tools.run_flow(flow, storage, flags)
credentials
= credentials.authorize(http = httplib2.Http())
http = discovery.build('blogger', 'v3', http=http)
service
try:
= open(input_file, 'r').read()
content except FileNotFoundError:
print("Input file not found")
1)
exit(
= {
body "kind": "blogger#post",
"title": post_title,
"content": content
}
try:
= service.posts()
posts = posts.insert(blogId=SILLYBYTESID, body=body, isDraft=False)
request = request.execute()
result print("Live: " + result['url'])
except:
print("Can't execute request")
1)
exit(
if __name__ == '__main__':
main(sys.argv)
The script will initiate an OAuth negotiation when needed and store the
authentication tokens in the auth_data.dat
file.
API project
Before we’re able to use this we need to create a new API project, configure
it and get the client_secrets.json
that the script will use to start the OAuth
negotiation.
First, enable the Blogger API at: https://console.developers.google.com/apis/library
Then create a new project, a new set of credentials and download the JSON file
from it. From the script above you’ll gather my client_secrets.json
file will
be located at ~/.sillybytes
.
Now, running:
$ python deploy.py "post title" "post HTML"
Will push the post to Blogger!
CLI tool
This is good enough already, we could just invoke deploy.py
from the Makefile,
but we can still do better:
$ silly help
Now I can create all the post boilerplate by doing silly new
and deploying the
current post with silly deploy
. Much better.