Giter VIP home page Giter VIP logo

azmdpub's Introduction

azmdpub

Writing and editing on the Medium website is not only painful and also wasting of time on style wrangling. I am wondering if there is a way to write in the Markdown file and then publish to Medium directly using Python.

After some searches, no open source and free solution exist, not to mention image uploading capability. So I decided to build one and open source it. This article is a summary of my solution.

To publish a Markdown file to the Medium site, I have to solve the following four problems:

  1. Translate Markdown to HTML string.
  2. Extract meta info like title and tags from Markdown file.
  3. The hardest part, upload images/GIFs to Medium server and update HTML image links.
  4. Post the HTML string to Medium site.

Before moving on, Go to your medium home page to get the access token:

Click your avatar -> Settings -> Security and apps -> Integration tokens

The token will be used for Post uploading.

My solution - azmdpub

Check out the code I post in github azmdpub. Pull the code, compile it, and start publishing your markdown files to Medium with images.

The code works in Windows, Linux and MacOS.

Here are steps to use it:

Step 1. Pull the code to your local machine

Step 2. Navigate to the git folder, and install dependant packages

pip install -r requirments.txt

Step 3. Use pyinstaller to compile the code

Install pyinstaller:

pip install pyinstaller

Compile python code:

cd src/azmdpub
pyinstaller -F 'azmdpub.py' -n 'azmdpub' -c

Step 4. Now you shall see the executable file under dist folder, you can execute it like this:

./dist/azmdpub 'markdown_file.md'

The program will ask for access token in the first time use, then cache the token in file ~/medium.conf.

The content in the markdown_file.md is like this:

---
title: Test markdown file
tags: ["tag1","tag2","tag3"]
---

# Test markdown file

This is a test markdown file

## Title2 

content content 
...

Note that the title and tags in the yaml meta section will be used during the uploading session.

If you still want to know how it works, please read on.

Problem #1. Translate Markdown to HTML string

With some researching and comparisons, I found package markdown-it-py is the best. The only problem is its confusing installation instruction from its readme file.

Here is the working way to install the package with pip.

Install markdown-it-py:

pip install markdown-it-py

Enable plugins:

pip install mdit_py_plugins

Translate Markdown file to HTML string using the following code:

from markdown_it import MarkdownIt
from mdit_py_plugins.front_matter import front_matter_plugin
from mdit_py_plugins.footnote import footnote_plugin
md = (
    MarkdownIt()
    .use(front_matter_plugin)
    .use(footnote_plugin)
    .enable('image')
    .enable('table')
)
with open(md_path,'r') as f:
    md_text = f.read()

Problem #2. Extract meta info like title and tags from Markdown file

I can use Regex to extract the title and tags, but there is another module can do the extraction job. Module markdown can extract the meta information such as title and tags defined in the yaml header.

---
title: Test markdown file
tags: ["tag1","tag2","tag3"]
---

# Test markdown file

Here is the code do the meta extraction work:

import markdown 
with open(md_path,'r') as f:
    md_text = f.read()

md      = markdown.Markdown(extensions = ['meta'], output_format='html5')
html    = md.convert(md_text)
meta    = md.Meta
return {
    'title':meta['title'][0]
    ,'tags':meta['tags'][0]
}

Problem #3. Upload images/GIFs to Medium server

I spent most of my time on implementing this feature, the post boundary settings is confusing. With the help from this solution about MultipartEncoder, I managed to implement the image uploading function. The code support four image types:

  1. image/jpeg
  2. image/png
  3. image/gif
  4. image/tiff

Yes, Animated gifs are also supported.

Use your power for good

Here is the full function code, to run it, please check out the whole code file using the below link.

def upload_img(self,img_path):
    '''
    Upload one image to medium server
    '''
    post_image_url = "https://api.medium.com/v1/images"
    img_type = img_path.split('.')[-1]

    files = {
        'image': (
            img_path
            ,open(img_path,'rb')
            ,f'image/{img_type}'
        )
    }

    m = MultipartEncoder(files, boundary='FormBoundaryXYZ')

    image_up_headers = {
        'Authorization':    "Bearer " + self.access_token
        ,'Content-Type':    m.content_type
        ,'Accept':          'application/json'
        ,'Accept-Charset':  'utf-8'
    }

    r = requests.post(
        post_image_url
        ,data = m.to_string()
        ,headers = image_up_headers
    )
    r_obj = json.loads(r.text)
    return r_obj['data']['url']

See full code file here.

Problem #4. Post the HTML string to Medium site

From the Medium's official API document on Posting. You will see an authorId with double parentheses.

POST https://api.medium.com/v1/users/{{authorId}}/posts

The authorId here is the user id or client id, you can fetch it with this code:

self.base_url       = "https://api.medium.com/v1/"
self.headers = {
    'Authorization': "Bearer " + self.access_token
    ,'Content-Type': 'application/json'
    ,'Accept': 'application/json'
    ,'Accept-Charset': 'utf-8'
}
try:
    r = requests.get(self.base_url+'me',headers=self.headers)
    self.client_obj = json.loads(r.text)
    self.client_id = self.client_obj['data']['id']
...

See full code here. The {{}} is unnecessary, you should remove it in the request call.

Here is my implementation of blog Posting:

def pub_post(self,md_path,status='draft'):
    
    post_url = f"{self.base_url}/users/{self.client_id}/posts"

    post_obj = self.md_to_html_meta(md_path)
    html_content = self.md_to_html(md_path)

    post_json = {
        "title": post_obj['title'],
        "contentFormat": "html",
        "content": html_content,
        "tags": json.loads(post_obj['tags']),
        "publishStatus": status
    }

    r = requests.post(post_url,json=post_json,headers=self.headers)
    print(r.text)

See full code here.

Last words

There are some other trivial processes I did not covered above, for example, the image URLs needed to be updated with the uploaded image links. These should be easy by using Python's string replacing functions.

This doc is written and edited with Markdown in VSCode. And post with azmdpub without any editing in Medium editor. Let me know if you are stuck or have any questions. Hope this tool enrich your writing experience.

azmdpub's People

Contributors

xhinker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

frostbite1536

azmdpub's Issues

Uploading Failing (File not Found)

The executable is failing with error saying cannot find test.md even though I do not have any file called test.md referenced in the code

.\azmdpub.exe '.\My Articles\Medium\Automated Post Testing\Article.md'
Traceback (most recent call last):
  File "azmdpub.py", line 201, in <module>
  File "azmdpub.py", line 141, in pub_post
  File "azmdpub.py", line 61, in md_to_html_meta
FileNotFoundError: [Errno 2] No such file or directory: 'test.md'
[9544] Failed to execute script 'azmdpub' due to unhandled exception!

I am using Windows 11 but I guess this is not an OS issue

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.