作者:Chancel, 更新:2022 Dec 14, 字数:5855, 已阅:824
前几天安装了lsky图床,但是使用VSC写Markdown的时候右键粘贴文件是存储到本地的,于是思考了下如何将Markdown的本地文件链接转换成在线形式的
如何安装Lsky图床可以参考我之前写的
Visual Studio Code 安装Paste Image之后,如下图在配置文件中配置好图片保存的本地路径,使用Ctrl+Shift+V即可直接粘贴图片
这里直接贴出我写的自动上传本地Markdown中引用的图片文件到Lsky图床的代码,也方便有需求的同学可以自行更改这个脚本
# /usr/bin/python3.8
# author:chancel.yang
import os
import sys
import requests
import json
import re
token_url = 'https://example.com/api/token'
upload_url = 'https://example.com/api/upload'
lsky_email = 'example@gmail.com'
lsky_password = 'example'
lsky_token = None
def get_token():
"""获取Lsky的Token
"""
data = {'email': lsky_email, 'password': lsky_password}
r = requests.post(url=token_url, data=data)
if r.status_code == 200:
reponse = json.loads(r.text)
reponse_data = reponse['data']
return reponse_data['token']
return None
def get_all_local_image_quote():
"""获取所有本地Markdown文件的图片链接
"""
# ^!\[\]\([^http].+\)$
def get_all_files(diretory_path):
_list = []
files = os.listdir(diretory_path)
for _file in files:
if not os.path.isdir(os.path.join(diretory_path, _file)):
_list.append(os.path.join(diretory_path, _file))
if os.path.isdir(os.path.join(diretory_path, _file)):
_list.extend(get_all_files(os.path.join(diretory_path, _file)))
return _list
file_list = get_all_files(sys.path[0])
image_quote_list = {}
# re_telephone = re.compile(r'!\[\]\([^http].+?\)')
re_telephone = re.compile(u'!\[\]\([^http].+?\)')
for _file in file_list:
if _file[-2:] == 'md':
with open(_file, 'r') as f:
_content = f.read()
_re = re_telephone.findall(_content)
if len(_re) > 0:
image_quote_list[f.name] = _re
return image_quote_list
def upload_file(file_path):
""" 上传文件方法,返回上传之后的url
:params file_path 文件路径
"""
with open(file_path, 'rb') as f:
files = {'image': f}
headers = {'token': lsky_token}
r = requests.post(upload_url, files=files, headers=headers)
if r.status_code == 200:
reponse = json.loads(r.text)
reponse_data = reponse['data']
return reponse_data['url']
return None
def replace_quote_url(screenshot_path, markdown_file_path, quote_list):
""" 上传图片文件并替换Markdown文件中的图片链接
:params screenshot_path Markdown引用图片链接的目录(Paste_Image插件设置的目录)
:params markdown_file_path 包含图片链接的文件路径
:params quote_list 包含图片链接的集合
"""
for quote_item in quote_list:
split_list = quote_item.split('/')
quote_file_name = split_list[-1]
quote_file_name = quote_file_name.replace(')', '')
file_name = os.path.join(screenshot_path, quote_file_name)
if os.path.exists(file_name) is False:
print('上传失败,本地引用的图片文件并不存在:"' + markdown_file_path)
continue
print('正在上传' + file_name)
url = upload_file(file_name)
if url is None:
print('上传失败,文件路径"' + markdown_file_path + '",图片引用路径"' + quote_item +
'"')
continue
print('上传' + file_name + '成功,URL是' + url)
file_content = None
with open(file=markdown_file_path, mode='r', encoding='utf-8') as f:
file_content = f.read()
url = ''
file_content = file_content.replace(quote_item, url)
with open(file=markdown_file_path, mode='w', encoding='utf-8') as f:
f.write(file_content)
print(markdown_file_path + '中的' + quote_item + '替换成' + url)
if __name__ == "__main__":
# 配置信息
screenshot_path = os.path.join(sys.path[0], '.config/screenshot/')
print('配置文件路径:' + screenshot_path)
# 获取所有带本地图片引用链接的笔记文件
image_quote_list = get_all_local_image_quote()
if len(image_quote_list) == 0:
print('没有检测到需要上传的本地文件,程序运行结束')
os._exit(0)
# 获取图床Token
lsky_token = get_token()
if lsky_token is None:
print('Error: Can\'t get user token')
os._exit(0)
print('图床返回Token:' + lsky_token)
print('即将上传数据内容为:' + str(image_quote_list))
while True:
str = input("确认上传(y/n):");
if str == 'y':
for key, value in image_quote_list.items():
replace_quote_url(screenshot_path, key, value)
print('程序运行结束')
break
if str == 'n':
print('用户终止运行')
break
下面简单讲一下这个代码的构成部分
根据Lsky的接口文档,向'/api/token'发起POST请求,表单内容帐号密码即可返回请求成功之后的Token
使用Python的requests模块可以比较简单的发起POST请求,如果显示'requests not found'则需要安装requests模块(默认不自带这个模块)
pip install requests
这一块主要比较麻烦主要是循环递归目录找出所有markdown文件,然后根据正则表达式解析内容
循环递归这块没什么好讲的,主要是正则表达式,Markdown的本地图片链接大抵如下

与HTTP链接有些相似

所以我们需要写一条可以解析这种格式同时也要排除已经是HTTP格式的图片链接
!\[\]\([^http].+?\)
Python中负责正则表达式解析的模块是re,在代码里我们需要多次循环正则解析内容,所以每次都创建一个Python的re对象比较消耗资源
我们可以先预编译正则表达式再使用"findall"方法找出文本中所有符合该正则表达式的内容
_content=""
re_telephone = re.compile(u'!\[\]\([^http].+?\)')
_re = re_telephone.findall(_content)
文件上传与Token的获取其实很类似,只是这次我们需要上传一个文件,不是传统的字符串类型表单,requests也支持直接POST文件
得益于强大的动态类型支持,我们直接创建一个带文件二进制的字典对象并上传即可
with open(file_path, 'rb') as f:
files = {'image': f}
headers = {'token': lsky_token}
r = requests.post('https://www.example.com/api/upload', files=files, headers=headers)
文件上传成功之后我们就获取了文件url,已知Markdown文件路径与图片本地链接
那么直接替换内容即可,这一部分直接查看代码即可,没有什么特别的地方
最后,有一点比较糟糕的是,如果你的图床速度不怎么样,那么将Markdown转换图片输出时(VSC插件支持)会非常慢甚至程序假死