cnblog_upload/cnblog_upload.command
#! /bin/bash
# source /Users/song/Code/script_python/pycnblog-master/venv/bin/activate
echo -n '请拖入一个md文件或者文件夹:'
read file_path
/Users/song/Code/script_python/cnblog_upload/venv/bin/python3 /Users/song/Code/script_python/cnblog_upload/src/main.py $file_path
cnblog_upload/src/history2anki.py
import os
from server.cnblog_server import server
from conf.conf import ST
from file.csv import write2csv
if __name__ == "__main__":
recent_posts = server.metaWeblog.getRecentPosts(ST.blog_id,ST.username ,ST.password, 19)
# 输出到桌面
out_md_path = os.path.join("/Users/song/Desktop" ,'anki.csv')
for post in recent_posts:
link = post['link']
content = post['description'].split('\n')[0]
write2csv(out_md_path,f'{content}\t<a href={link}>{content}</a>\n')
cnblog_upload/src/main.py
import asyncio
import time
import os
import sys
from img.unload_img import find_md_img,replace_md_img,upload_md_img
from server.cnblog_server import server
from conf.conf import ST
from file.csv import write2csv,generate_file_name
from file.md import read_md,get_md_files
net_images = [] # 图片上传后url
image_count = 1 # 图片计数
def get_image_url(t):
"""回调,获取url"""
global image_count
global net_images
url = t.result()['url']
print(f'第{image_count}张图片上传成功,url:{url}')
net_images.append(url)
image_count += 1
def upload_img(md_path,md):
global net_images
local_images = find_md_img(md)
if local_images: # 有本地图片,异步上传
tasks = []
for li in local_images:
image_full_path = os.path.join(dir_name, li)
task = asyncio.ensure_future(upload_md_img(image_full_path))
task.add_done_callback(get_image_url)
tasks.append(task)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
image_mapping = dict(zip(local_images, net_images))
md = replace_md_img(md_path, image_mapping)
else:
print('无需上传图片')
return md
if __name__ == "__main__":
if len(sys.argv) == 1:
exit(-1)
file_or_dir_path = sys.argv[1]
if os.path.isfile(file_or_dir_path):
md_paths = [file_or_dir_path]
dir_name = os.path.dirname(file_or_dir_path)
else:
md_paths = get_md_files(file_or_dir_path)
dir_name = file_or_dir_path
for md_path in md_paths:
md = read_md(md_path)
md = upload_img(md_path,md)
title, _ = os.path.splitext(os.path.basename(md_path)) # 文件名作为博客标题
post = dict(description=md, title=title, categories=['[Markdown]'],mt_keywords='anki')
server.metaWeblog.newPost(ST.blog_id ,ST.username , ST.password , post, ST.publish)
print(f"markdown上传成功, 博客标题为'{title}', 状态为'已发布', 请到博客园后台查看")
time.sleep(3)
recent_posts = server.metaWeblog.getRecentPosts( ST.blog_id , ST.username,ST.password, 1)
# 获取所有标题,需要处理HTML转义字符
out_md_path = os.path.join(dir_name,generate_file_name())
for post in recent_posts:
anki_title = post['title']
link = post['link']
content = post['description'].split('\n')[0]
write2csv(out_md_path,f'{anki_title}\t<a href={link}>{content}</a>\n')
break
time.sleep(3)
cnblog_upload/src/file/md.py
import os
def get_md_files(folder_path):
markdown_files = []
for file_name in os.listdir(folder_path):
if file_name.endswith(".md"):
markdown_files.append(os.path.join(folder_path, file_name))
return markdown_files
def read_md(path):
with open(path, encoding='utf-8') as f:
md = f.read()
return md
cnblog_upload/src/file/csv.py
from datetime import datetime
def generate_file_name():
# Get the current time
now = datetime.now()
# Format the time as a string
time_str = now.strftime('%Y-%m-%d_%H-%M-%S')
# Create the file name
file_name = f'Z_{time_str}.csv'
return file_name
def write2csv(path,msg):
with open(path, "a", encoding='utf-8') as f: # 打开文件
f.write(msg)
cnblog_upload/src/server/cnblog_server.py
import xmlrpc.client
from conf.conf import ST
try:
server = xmlrpc.client.ServerProxy(ST.blog_url)
except Exception as e:
e = str(e)
if 'unsupported XML-RPC protocol' in e:
print('请查看config.yaml文件中的blog_url,应该是这个URL地址没设置对')
cnblog_upload/src/img/mime.py
mime_mapping = {
".323": "text/h323",
".asx": "video/x-ms-asf",
".acx": "application/internet-property-stream",
".ai": "application/postscript",
".aif": "audio/x-aiff",
".aiff": "audio/aiff",
".axs": "application/olescript",
".aifc": "audio/aiff",
".asr": "video/x-ms-asf",
".avi": "video/x-msvideo",
".asf": "video/x-ms-asf",
".au": "audio/basic",
".application": "application/x-ms-application",
".bin": "application/octet-stream",
".bas": "text/plain",
".bcpio": "application/x-bcpio",
".bmp": "image/bmp",
".cdf": "application/x-cdf",
".cat": "application/vndms-pkiseccat",
".crt": "application/x-x509-ca-cert",
".c": "text/plain",
".css": "text/css",
".cer": "application/x-x509-ca-cert",
".crl": "application/pkix-crl",
".cmx": "image/x-cmx",
".csh": "application/x-csh",
".cod": "image/cis-cod",
".cpio": "application/x-cpio",
".clp": "application/x-msclip",
".crd": "application/x-mscardfile",
".deploy": "application/octet-stream",
".dll": "application/x-msdownload",
".dot": "application/msword",
".doc": "application/msword",
".dvi": "application/x-dvi",
".dir": "application/x-director",
".dxr": "application/x-director",
".der": "application/x-x509-ca-cert",
".dib": "image/bmp",
".dcr": "application/x-director",
".disco": "text/xml",
".exe": "application/octet-stream",
".etx": "text/x-setext",
".evy": "application/envoy",
".eml": "message/rfc822",
".eps": "application/postscript",
".flr": "x-world/x-vrml",
".fif": "application/fractals",
".gtar": "application/x-gtar",
".gif": "image/gif",
".gz": "application/x-gzip",
".hta": "application/hta",
".htc": "text/x-component",
".htt": "text/webviewhtml",
".h": "text/plain",
".hdf": "application/x-hdf",
".hlp": "application/winhlp",
".html": "text/html",
".htm": "text/html",
".hqx": "application/mac-binhex40",
".isp": "application/x-internet-signup",
".iii": "application/x-iphone",
".ief": "image/ief",
".ivf": "video/x-ivf",
".ins": "application/x-internet-signup",
".ico": "image/x-icon",
".jpg": "image/jpeg",
".jfif": "image/pjpeg",
".jpe": "image/jpeg",
".jpeg": "image/jpeg",
".js": "application/x-javascript",
".lsx": "video/x-la-asf",
".latex": "application/x-latex",
".lsf": "video/x-la-asf",
".manifest": "application/x-ms-manifest",
".mhtml": "message/rfc822",
".mny": "application/x-msmoney",
".mht": "message/rfc822",
".mid": "audio/mid",
".mpv2": "video/mpeg",
".man": "application/x-troff-man",
".mvb": "application/x-msmediaview",
".mpeg": "video/mpeg",
".m3u": "audio/x-mpegurl",
".mdb": "application/x-msaccess",
".mpp": "application/vnd.ms-project",
".m1v": "video/mpeg",
".mpa": "video/mpeg",
".me": "application/x-troff-me",
".m13": "application/x-msmediaview",
".movie": "video/x-sgi-movie",
".m14": "application/x-msmediaview",
".mpe": "video/mpeg",
".mp2": "video/mpeg",
".mov": "video/quicktime",
".mp3": "audio/mpeg",
".mpg": "video/mpeg",
".ms": "application/x-troff-ms",
".nc": "application/x-netcdf",
".nws": "message/rfc822",
".oda": "application/oda",
".ods": "application/oleobject",
".pmc": "application/x-perfmon",
".p7r": "application/x-pkcs7-certreqresp",
".p7b": "application/x-pkcs7-certificates",
".p7s": "application/pkcs7-signature",
".pmw": "application/x-perfmon",
".ps": "application/postscript",
".p7c": "application/pkcs7-mime",
".pbm": "image/x-portable-bitmap",
".ppm": "image/x-portable-pixmap",
".pub": "application/x-mspublisher",
".pnm": "image/x-portable-anymap",
".png": "image/png",
".pml": "application/x-perfmon",
".p10": "application/pkcs10",
".pfx": "application/x-pkcs12",
".p12": "application/x-pkcs12",
".pdf": "application/pdf",
".pps": "application/vnd.ms-powerpoint",
".p7m": "application/pkcs7-mime",
".pko": "application/vndms-pkipko",
".ppt": "application/vnd.ms-powerpoint",
".pmr": "application/x-perfmon",
".pma": "application/x-perfmon",
".pot": "application/vnd.ms-powerpoint",
".prf": "application/pics-rules",
".pgm": "image/x-portable-graymap",
".qt": "video/quicktime",
".ra": "audio/x-pn-realaudio",
".rgb": "image/x-rgb",
".ram": "audio/x-pn-realaudio",
".rmi": "audio/mid",
".ras": "image/x-cmu-raster",
".roff": "application/x-troff",
".rtf": "application/rtf",
".rtx": "text/richtext",
".sv4crc": "application/x-sv4crc",
".spc": "application/x-pkcs7-certificates",
".setreg": "application/set-registration-initiation",
".snd": "audio/basic",
".stl": "application/vndms-pkistl",
".setpay": "application/set-payment-initiation",
".stm": "text/html",
".shar": "application/x-shar",
".sh": "application/x-sh",
".sit": "application/x-stuffit",
".spl": "application/futuresplash",
".sct": "text/scriptlet",
".scd": "application/x-msschedule",
".sst": "application/vndms-pkicertstore",
".src": "application/x-wais-source",
".sv4cpio": "application/x-sv4cpio",
".tex": "application/x-tex",
".tgz": "application/x-compressed",
".t": "application/x-troff",
".tar": "application/x-tar",
".tr": "application/x-troff",
".tif": "image/tiff",
".txt": "text/plain",
".texinfo": "application/x-texinfo",
".trm": "application/x-msterminal",
".tiff": "image/tiff",
".tcl": "application/x-tcl",
".texi": "application/x-texinfo",
".tsv": "text/tab-separated-values",
".ustar": "application/x-ustar",
".uls": "text/iuls",
".vcf": "text/x-vcard",
".wps": "application/vnd.ms-works",
".wav": "audio/wav",
".wrz": "x-world/x-vrml",
".wri": "application/x-mswrite",
".wks": "application/vnd.ms-works",
".wmf": "application/x-msmetafile",
".wcm": "application/vnd.ms-works",
".wrl": "x-world/x-vrml",
".wdb": "application/vnd.ms-works",
".wsdl": "text/xml",
".xap": "application/x-silverlight-app",
".xml": "text/xml",
".xlm": "application/vnd.ms-excel",
".xaf": "x-world/x-vrml",
".xla": "application/vnd.ms-excel",
".xls": "application/vnd.ms-excel",
".xof": "x-world/x-vrml",
".xlt": "application/vnd.ms-excel",
".xlc": "application/vnd.ms-excel",
".xsl": "text/xml",
".xbm": "image/x-xbitmap",
".xlw": "application/vnd.ms-excel",
".xpm": "image/x-xpixmap",
".xwd": "image/x-xwindowdump",
".xsd": "text/xml",
".z": "application/x-compress",
".zip": "application/x-zip-compressed",
".*": "application/octet-stream",
}
cnblog_upload/src/img/unload_img.py
import os
import re
from conf.conf import ST
from img.mime import mime_mapping
from server.cnblog_server import server
def find_md_img(md):
"""查找markdown中的图片,排除网络图片(不用上传)"""
images = re.findall("!\\[.*?\\]\\((.*)\\)", md)
images += re.findall('<img src="(.*?)"', md)
images = [i for i in images if not re.match("((http(s?))|(ftp))://.*", i)]
print(f'共找到{len(images)}张本地图片{images}')
return images
async def upload_md_img(path):
"""上传图片"""
name = os.path.basename(path)
_, suffix = os.path.splitext(name)
with open(path, 'rb') as f:
file = {
"bits": f.read(),
"name": name,
"type": mime_mapping[suffix]
}
url = server.metaWeblog.newMediaObject(ST.blog_id,ST.username ,ST.password, file)
return url
def replace_md_img(path, img_mapping):
"""替换markdown中的图片链接"""
with open(path, 'r', encoding='utf-8') as fr:
md = fr.read()
for local, net in img_mapping.items(): # 替换图片链接
md = md.replace(local, net)
if ST.img_format:
md_links = re.findall("!\\[.*?\\]\\(.*?\\)", md)
md_links += re.findall('<img src=.*/>', md)
for ml in md_links:
img_url = re.findall("!\\[.*?\\]\\((.*?)\\)", ml)
img_url += re.findall('<img src="(.*?)"', ml)
img_url = img_url[0]
if ST.img_format == "typora":
zoom = re.findall(r'style="zoom:(.*)%;"', ml)
if zoom:
md = md.replace(ml, f'<center><img src="{img_url}" style="width:{zoom[0]}%;" /></center>')
else:
md = md.replace(ml, ST.img_format.format(img_url))
if ST.gen_network_file:
path_net = os.path.join(os.path.dirname(path), '_network'.join(os.path.splitext(os.path.basename(path))))
with open(path_net, 'w', encoding='utf-8') as fw:
fw.write(md)
print(f'图片链接替换完成,生成新markdown:{path_net}')
return md
cnblog_upload/src/conf/conf.py
class ST:
blog_url="https://rpc.cnblogs.com/metaweblog/xxxxx"
blog_id="xxxxxxx"
username="xxxxxxxxxxxxx"
password="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# 是否生成图片替换后本地文件,默认False关闭
gen_network_file=False
# 上传后是否发布,默认未发布,设置True为发布
publish=True
# 图片自定义显示格式,默认不设置
img_format="typora"
标签:md,markdown,text,博客园,application,file,path,上传,image
From: https://www.cnblogs.com/zhuoss/p/17539474.html