本文最后更新于:2024年5月7日 下午
通过 Nginx 建立自己的图床后,之前的 Picgo 无法使用,导致在文档中插入图片十分不便,本文记录自己搭建 Python 后端服务来为自己的图床适配 Picgo 的方法。
背景
实现要点
不同的使用者可能有不同的需求,我提供自己的实现思路,供大家参考。
调试
- 链路没有打通前调试十分重要,具体方法为:
- 在服务器安装 Python
- 本地 VScode 远程调试服务器代码
- 运行 flask 服务,本地使用 Picgo 发送数据包进行调试
思路
- 服务器上使用 Python 开启 flask 监听特定端口
- 服务器开通防火墙暴露端口
- 本地 Picgo 向服务器地址发送数据包
- flask 接收、解析数据,按照需求处理业务逻辑,返回文件 url
- 将该服务设置为服务器开机启动服务,之后便再也不用操心无人接管 Picgo 数据包
实现方法
PicGo 端配置
API 地址为服务器地址,后面 /
后可以接一段字符作为输入参数,我将其作为存放文件的子文件夹
post 参数名为文件所在参数名
其余建议不要填,不然会上传失败,不知道原因
服务器端配置
1 2 3 4 5
| from flask import Flask, request import io from PIL import Image import mtutils as mt import numpy as np
|
1 2 3 4 5 6
| key_para = 'file' save_root = 'path-to-your-file' host = 'https://1.1.1.1' default_name = 'imgbed' log_file_path = '/usr/local/imgbed/log.log' port = '6789'
|
1 2 3 4
| app = Flask(__name__) app.last_file = None
app.logger = mt.log_init(log_file_path)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| def specific_path(save_to): file = request.files[key_para] file_content = file.read() save_dir = mt.OS_join(save_root, save_to) mt.dir_check(save_dir)
if file.content_type[:5].lower() == 'image' and file.content_type[-4:].lower() not in ['/jpg', 'jpeg']: image_obj = Image.open(io.BytesIO(file_content))
file_name = str(mt.Path(file.filename).with_suffix('.jpg')) save_path = mt.OS_join(save_dir, file_name) image_save_path = mt.Path(save_path) image_save_path.parent.mkdir(parents=True, exist_ok=True) image_obj.save(str(image_save_path)) app.logger(f'Transfer and save image to {save_path}.') else: file_name = file.filename save_path = mt.OS_join(save_dir, file_name) obj = open(save_path, mode='wb') obj.write(file_content) app.logger(f'Save file to {save_path}.')
app.last_file = save_path back_link = mt.OS_join(host, 'HexoFiles', save_to, file_name) return back_link
|
- 之前使用 PicGo 传图时经常遇到想要删除刚刚上传图像的需求,此处加了相关功能
1 2 3 4 5 6 7 8
| if '__del__' in save_to: res_str = 'nothing happened.' if app.last_file is not None: mt.remove_file(app.last_file) res_str = f"File deleted {app.last_file}" app.logger(res_str) app.last_file = None return res_str
|
在 API 链接里 /
后的字符串中如包含 __del__
则删除刚刚上传的图像,返回操作结果
- 如果没有配置 API 后的文件夹作为参数,使用默认二级文件夹
1 2 3 4
| @app.route("/", methods=['GET','POST']) def default_save_path(): default_path = default_name return specific_path(default_path)
|
1 2 3 4
| if __name__ == '__main__': app.logger("**************** Sever Start *******************") app.run('0.0.0.0', port=port) pass
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| from flask import Flask, request import io from PIL import Image import mtutils as mt import numpy as np
key_para = 'file' save_root = 'path-to-your-file' host = 'https://1.1.1.1' default_name = 'imgbed' log_file_path = '/usr/local/imgbed/log.log' port = '6789'
app = Flask(__name__) app.last_file = None app.logger = mt.log_init(log_file_path)
@app.route("/<save_to>", methods=['GET','POST']) def specific_path(save_to):
if '__del__' in save_to: res_str = 'nothing happened.' if app.last_file is not None: mt.remove_file(app.last_file) res_str = f"File deleted {app.last_file}" app.logger(res_str) app.last_file = None return res_str
file = request.files[key_para] file_content = file.read()
save_dir = mt.OS_join(save_root, save_to) mt.dir_check(save_dir)
if file.content_type[:5].lower() == 'image' and file.content_type[-4:].lower() not in ['/jpg', 'jpeg']: image_obj = Image.open(io.BytesIO(file_content))
file_name = str(mt.Path(file.filename).with_suffix('.jpg')) save_path = mt.OS_join(save_dir, file_name) image_save_path = mt.Path(save_path) image_save_path.parent.mkdir(parents=True, exist_ok=True) image_obj.save(str(image_save_path)) app.logger(f'Transfer and save image to {save_path}.') else: file_name = file.filename save_path = mt.OS_join(save_dir, file_name) obj = open(save_path, mode='wb') obj.write(file_content) app.logger(f'Save file to {save_path}.')
app.last_file = save_path back_link = mt.OS_join(host, 'HexoFiles', save_to, file_name) return back_link
@app.route("/", methods=['GET','POST']) def default_save_path(): default_path = default_name return specific_path(default_path)
if __name__ == '__main__': app.logger("**************** Sever Start *******************") app.run('0.0.0.0', port=port) pass
|
设置开机运行服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| [Unit] Description = Service for uploading file to target dir After = network.target
[Service] ExecStart = path-to-your-python main.py WorkingDirectory = /usr/local/imgbed/ StandardOutput = inherit StandardError = inherit Restart = always User = lighthouse
[Install] WantedBy=multi-user.target
|
参考资料
文章链接:
https://www.zywvvd.com/notes/hexo/website/34-uploader-for-myimgbed/uploader-for-myimgbed/