Configuring Typora to Automatically Upload Local Images to Cnblogs
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 Preferences → Image
- 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.