In the article My semi automated workflow for blogging, I have outlined what my blogging process is like and how I've started to automate it. Ofcourse, at the time of that article, the process was still in early stages and I hadn't automated everything I do. And, that's where this article comes in. This is the second attempt at automating my entire Blogging workflow.

Medium blogger python logo

Just to give you some context, here are the things that I do when I'm blogging.

  1. Open a markdown file in Vim with the title of the article as the name along with some template text
  2. Open a browser with the html of the newly created markdown file
  3. Convert markdown to html with pandoc several times during the writing process
  4. Once the article is done and html is produced, edit the html to make some changes specific based on whether I'm publishing on Medium or if I'm publishing on Blogger
  5. Read the tags/labels and other attributes from the file and Publish the code as draft on Medium or Blogger.
  6. Once it looks good, Schedule or Publish it (This is a manual process. There's no denying it.)
  7. Finally tweet about the post with the link to the article

I have the individual pieces of this process ready. I have already written about them in the following articles.

Semi Automated Blogging Workflow

Publish Articles To Blogger In One Second

Publish Articles To Medium In One Second

Tweeting With Python & Tweepy

Now, since the individual pieces are ready, it might seem that everything is done. But, as it turns out (unsurprisingly), the integration is of-course a big deal and took a lot more effort than I was expecting. And I am documenting that in this article along with the complete flow.

It starts with the script blog-it which opens vim for me, opens chrome and also sets up a process for converting markdown to html, continuously.

That script calls which is what opens the vim along with the default text template. I would like to put the complete gist here, but it is just too long and so instead I'm showing the meat of the script.

article_title = title.replace("_", " ").title()

# Create the markdown file and add the title
f = open(md_file, "w+")
f.write(article_title)  # Replace underscores and title case it
f.write("-" * len(title))

# Now, create the html file
html_file = title + ".html"
open(html_file, "w").close()

# Start vim with the markdown file open on line #10['C:/Program Files (x86)/Vim/vim80/gvim.exe', '+10', md_file])

Then comes m2h which continuously converts markdown to html.

This ends one flow. Next comes, publishing. I have broken this down because publishing is a manual process for me unless I can complete the entire article in one sitting, which is never going to be possible. So, Once I'm doing with writing it, I'll start the publishing.

I'll run which depending on the comments in the html publishes it to either Blogger or Medium. Again, I'm only showing a part of it. The full gist is available here.

with open(html_file) as file:
    html_file_contents =

re_comments = re.compile('\s*<!--(.*)-->', re.DOTALL)
comments_text =
comments_parser = CommentParser.parse_comments(comments_text)

if comments_parser.destination.lower() == 'blogger':
    blogger_publish.publish(html_file, comments_parser.title, comments_parser.labels, comments_parser.post_id)
elif comments_parser.destination.lower() == 'medium':
    medium_publish.publish(html_file, comments_parser.title, comments_parser.labels)
        'Unknown destination: ' + comments_parser.destination + '. Supported destinations are Blogger and Medium.')

Then comes the individual publishing scripts that publish to blogger and medium.

For (Gist here), I do any required modifications with (Gist here) which converts some tags as expected my blogger page.

Then for (Gist here), I take the parameters and publish to blogger as html. No, modifications needed to be done here.

access_token_file = '~/.medium-access-token'
expanded_path = os.path.expanduser(access_token_file)
with open(expanded_path) as file:
  access_token =

headers = get_headers(access_token)
user_url = get_user_url(headers)

# Publish new post
posts_url = user_url + 'posts/'
payload = generate_payload(title, labels, html_file)
response = requests.request('POST', posts_url, data=payload, headers=headers)

Actually this publishing does send it to the site as a draft instead of actually publishing it. This is a step that I don't know how to automate as I have to manually take a look at how the article looks in preview. May be I should try doing this with selenium or something like that.

Once, I've verified that the post looks good, I will publish it and take the URL of the published article and call the (Gist here) which then opens a Vim file with some default text for title, and URL already filled in along with some hashtags. I'll complete the tweet and once, I close it, It gets published on Twitter.

And that completes the process. Obviously there are still a couple of manual steps. Although I can't eliminate all of them, I might be able to minimize them as well. But, so far it looks pretty good especially with just the little effort I've put into this in just one week. Of course, I'll keep on tuning it as needed to make it even better and may be I'll publish one final article for that.

That is all for this article.

For more programming articles, checkout Freblogg, Freblogg/Python

Some articles on automation:

Web Scraping For Beginners with Python My semi automated workflow for blogging Publish articles to Blogger automatically Publish articles to Medium automatically

This is the 9th article as part of my twitter challenge #30DaysOfBlogging. Twenty one more articles on various topics, including but not limited to, Java, Git, Vim, Software Development, Python, to come.

If you are interested in this, make sure to follow me on Twitter @durgaswaroop.

If you are interested in contributing to any open source projects and haven't found the right project or if you were unsure on how to begin, I would like to suggest my own project, Delorean which is a Distributed Version control system, built from scratch in scala. You can contribute not only in the form of code, but also with usage documentation and also by identifying any bugs in its functionality.

Thanks for reading. See you again in the next article.