Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Configuring Typora to Automatically Upload Local Images to Cnblogs

Tech May 17 3

1. Obtaining Your Cnblogs Authentication Cookie

After logging into your Cnblogs account, retrieve the cookie value from your browser's developer tools. The required cookie key is .Cnblogs.AspNetCore.Cookies. This single cookie entry is sufficient for authentication.

2. Creating the Upload Script

Create a Python script to handle image uploads. The following implementation supports both local image files and remote URLs:

# cnblogs_uploader.py
# Handles local images and remote image URLs
import re
import requests
import sys
from pathlib import Path
from uuid import uuid4


# Pattern components for URL validation
IP_MIDDLE = r"(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5]))"
IP_LAST = r"(?:\.(?:0|[1-9]\d?|1\d\d|2[0-4]\d|25[0-5]))"

url_pattern = re.compile(
    r"^"
    r"(?:(?:https?|ftp)://)"
    r"(?:[-a-z\u00a1-\uffff0-9._~%!$&'()*+,;=:]+"
    r"(?::[-a-z0-9._~%!$&'()*+,;=:]*)?@)?"
    r"(?:"
    r"(?P<private_ip>"
    r"(?:(?:10|127)" + IP_MIDDLE + r"{2}" + IP_LAST + r")|"
    r"(?:(?:169\.254|192\.168)" + IP_MIDDLE + IP_LAST + r")|"
    r"(?:172\.(?:1[6-9]|2\d|3[0-1])" + IP_MIDDLE + IP_LAST + r"))"
    r"|"
    r"(?P<private_host>(?:localhost))"
    r"|"
    r"(?P<public_ip>"
    r"(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])"
    r"" + IP_MIDDLE + r"{2}"
    r"" + IP_LAST + r")"
    r"|"
    r"\[("
    r"([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|"
    r"([0-9a-fA-F]{1,4}:){1,7}:|"
    r"([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|"
    r"([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|"
    r"([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|"
    r"([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|"
    r"([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|"
    r"[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|"
    r":((:[0-9a-fA-F]{1,4}){1,7}|:)|"
    r"fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|"
    r"::(ffff(:0{1,4}){0,1}:){0,1}"
    r"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}"
    r"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|"
    r"([0-9a-fA-F]{1,4}:){1,4}:"
    r"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}"
    r"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"
    r")\]|"
    r"(?:(?:(?:xn--)|[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]-?)*"
    r"[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]+)"
    r"(?:\.(?:(?:xn--)|[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]-?)*"
    r"[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]+)*"
    r"(?:\.(?:(?:xn--[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]{2,})|"
    r"[a-z\u00a1-\uffff\U00010000-\U0010ffff]{2,}))"
    r")"
    r"(?::\d{2,5})?"
    r"(?:/[-a-z\u00a1-\uffff\U00010000-\U0010ffff0-9._~%!$&'()*+,;=:@/]*)?"
    r"(?:\?\S*)?"
    r"(?:#\S*)?"
    r"$",
    re.UNICODE | re.IGNORECASE
)


def validate_url(target_string, restrict_public=False):
    match_result = url_pattern.match(target_string)
    if not restrict_public:
        return match_result
    return match_result and not any(
        match_result.groupdict().get(key) for key in ('private_ip', 'private_host')
    )


def main():
    args = sys.argv
    if len(args) <= 1:
        return

    image_arg = sys.argv[1]

    if not validate_url(image_arg):
        file_path = Path(image_arg)
        if not file_path.exists() or file_path.is_dir():
            return
        file_name = file_path.name
        file_handle = file_path.open('rb')
        mime_type = f'image/{file_path.suffix[1:]}'
    else:
        response = requests.get(image_arg)
        mime_type = response.headers['Content-Type']
        if 'image' in mime_type:
            path_segments = image_arg.split('/')
            file_name = path_segments[-1] if path_segments else uuid4().hex
            file_handle = response.content
        else:
            return

    request_headers = {
        'x-mime-type': mime_type,
    }

    auth_cookies = {
        '.Cnblogs.AspNetCore.Cookies': 'YOUR_COOKIE_VALUE_HERE',
    }

    upload_endpoint = f"http://upload.cnblogs.com/imageuploader/processupload?host=www.cnblogs.com&qqfile={file_name}"

    payload = {"qqfile": (file_name, file_handle, mime_type)}

    response = requests.post(upload_endpoint, files=payload, cookies=auth_cookies, headers=request_headers)

    if response.status_code == 200:
        response_data = response.json()
        is_success = response_data['success']
        result_url = response_data['message']
        if is_success:
            print('Upload Success:')
            print(result_url)


if __name__ == '__main__':
    main()
</public_ip></private_host></private_ip>

3. Configuring Typora's Image Upload Settings

To enable automatic uploads in Typora, follow these configuration steps:

  • Navigate to PreferencesImage
  • Select Custom Command as the upload service
  • Enter the comand in the following format: python /path/to/cnblogs_uploader.py (adjust the path according to your Python interpreter lcoation)

Typora will pass the absolute path of the selected image to the script as an argument. The number of arguments varies depending on how many images are being uploaded.

After the upload completes, the script must output results in the following format for Typora to parse:

Upload Success:
https://example.cdn.com/uploaded/image.png

The first line must be exactly Upload Success:, followed by image URLs on subsequent lines (one URL per line).

Configure the When Inserting Images option according to your preference:

  • Upload Image: Automatically uploads local images to Cnblogs when inserted
  • No Special Action: Prompts you to choose alternative actions like manual upload

If you encounter errors during upload, verify the error message carefully. Common issues include expired or invalid cookies.

4. Notes

This script is designed specifically for Cnblogs image hosting and uses their current upload API. The implementation serves as a foundation that can be adapted to work with other object storage services or image hosting platforms by modifying the upload endpoint and authentication mechanism.

Tags: Typora

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.