利用阿里云 OSS 服务为 sublime 提供自动上传图片的图片的插件
OSS 的相关操作云对象存储服务(Object Storage Service,简称 OSS),能够提供的海量、安全、低成本、高可靠的云存储服务。通俗的讲就是一个『网络上的大硬盘』,你可以通过自己写代码进行读写、访问控制等操作。对象存储的概念视频播放,这里会介绍图床只是一种OSS的应用。阿里官方的链接1、 申请相关的 OSS 账号2、 获得申请后的 OSS 账号的 、购买 OSS 服务...
OSS 的相关操作
云对象存储服务(Object Storage Service,简称 OSS),能够提供的海量、安全、低成本、高可靠的云存储服务。通俗的讲就是一个『网络上的大硬盘』,你可以通过自己写代码进行读写、访问控制等操作。
视频播放,这里会介绍图床只是一种OSS的应用。
1、 申请相关的 OSS 账号
2、 获得申请后的 OSS 账号的 、购买 OSS 服务、创建存储空间。 在 OSS 的管理控制台,“概览”中可以看到
如果不存在 AccessKey 则按照官方的教程进行新建子账号,并且为改子账号提供 OSS 服务的读写权限。
3、 验证 OSS 服务,能否通过 sdk 进行相关的操作。主要的编程开发参考
4、 完成将本地图片通过代码自动上传到 OSS
本插件程序采用 Python 语言开发,首先是因为比较方便,其次 sublime 插件也是基于 Python 进行的二次开发。官方 API
- 通过程序获得指定 bucket 名称的 bucket 对象
# -*- coding: utf-8 -*-
import oss2
# 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>')
# Endpoint以杭州为例,其它Region请按实际情况填写。
bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>')
# 设置存储空间为私有读写权限。
bucket.create_bucket(oss2.models.BUCKET_ACL_PRIVATE)
- 往指定的 Bucket 中上传图片(文件)
# -*- coding: utf-8 -*-
import oss2
# 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>')
# Endpoint以杭州为例,其它Region请按实际情况填写。
bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>')
# <yourLocalFile>由本地文件路径加文件名包括后缀组成,例如/users/local/myfile.txt
bucket.put_object_from_file('<yourObjectName>', '<yourLocalFile>')
# 设置上传文件的访问权限
bucket.put_object_acl(fileName, oss2.OBJECT_ACL_PUBLIC_READ)
官方 API 的快速开始中没有介绍对上传的文件进行权限访问设置操作。一定要设置权限访问,不然无法获得一个永久性的可读 url
- 根据阿里对上传文件的规则生成上传文件的 url
主要的规则如下:
<scheme>://<yourBucketName>.<RegionName>/<fileNameUrlEncode>
https://i-blog.csdnimg.cn/blog_migrate/f8449f29603647dc6de3888e9c48c926.png
- scheme:通常就是 http 协议,可以根据 bucket._make_url.scheme 属性获得
- yourBucketName:就是你前面创建的 bucket 对象的名称,通过 bucket.bucket_name 获得
- RegionName: 就是这个区域所划分的域名,通过属性 bucket._make_url.netloc 获得。
- fileNameUrlEncode:就是我们上传文件名的 urlencode 编码
主要的内容代码如下,需要导入 from urllib import parse
模块。
# 上传文件
# <yourLocalFile>由本地文件路径加文件名包括后缀组成,例如/users/local/myfile.txt
callback = bucket.put_object_from_file(fileName, filePath)
# 设置上传文件的访问权限
bucket.put_object_acl(fileName, oss2.OBJECT_ACL_PUBLIC_READ)
# 进行url 编码
newFileName = parse.quote_plus(fileName)
url = "{}://{}.{}/{}".format(bucket._make_url.scheme, bucket.bucket_name, bucket._make_url.netloc, newFileName)
PS: 为了避免文件的重复,我们可以考虑将文件内容的hash值作为我们上传文件的文件名。
优化本地的 Markdown 编辑体验
- 打造一个Markdown本地编辑器
- 实现拷贝图片自动的上传到阿里云图床,并且插入到本地编写的Markdown文件中
1、 主要的问题在于如何在Markdown中导入第三方的python模块,并且使用
其实考虑清楚Python的运行原理可以清楚地知道,python也是在 sys.path 中寻找指定名称的模块。所以,需要导入第三方模块,就需要告诉 python 在那些路径上寻找相关的python模块代码。
具体分析,打印出Python的系统路径就可以看到导入的模块存在哪些问题
import sys
print(sys.path)
为了方便,我在本地的 anaconda 中安装了阿里的 OSS2 模块,但是 sublime 使用的是一个隔离的 python 模块。所以需要制定 sublime 自带的 python 环境使用 anaconda 模块的内容。
在 sublime 插件的模块中,导入相关的模块的模块的路径,我这里导入了所有的 anaconda 模块路径。
import sys
# 加载第三方的模块
sys.path.append("D:/ProgramData/Anaconda3/Lib/site-packages")
ps:建议将模块 cropty 模块中的所有 .cp37-win_amd64.pyd
模块的文件都重命名为 .pyd
,因为不这样的话在导入模块的时候可能会存在相关问题。如果在 sublime 中使用未出现问题最好。
- 在 sublime 中调试图片插入代码?
参考我的另外一篇文章可以看到,实战:在 sublime text3 中开发一个 markdown 图片插入插件,可以看到如何插入本地的图片到 Markdown 文档中。
然后就是加上一个编写本地文件的脚本进行上传操作。为了解决文件内容重复的问题,会将图片内容在本地进行一个 hash 计算,求出内容的 hash 值作为上传文件的文件名。
sublime 中代码实现如下:(相关的配置内容会写入到 markdown.sublime-settings
文件中)
import sublime
import sublime_plugin
import os
import os.path
import sys
import shutil
import re
import sys
import time
import hashlib
# 加载第三方的模块
sys.path.append("D:/ProgramData/Anaconda3/Lib/site-packages")
import oss2
from urllib import parse
# 获得配置信息
settings = sublime.load_settings('markdown.sublime-settings')
def get_bucket():
'''
获得默认的阿里云的 oss bucket 模块
:param yourAccessKeyId:
:param yourAccessKeySecret:
:param yourBucketName:
:return: 返回默认的 bucket 模块
'''
# 判断账号密码是否为空
yourAccessKeyId = settings.get("yourAccessKeyId")
if not yourAccessKeyId:
print("yourAccessKeyId is none in markdown.sublime-settings file")
yourAccessKeySecret = settings.get("yourAccessKeySecret")
if not yourAccessKeySecret:
print("yourAccessKeySecret is none in markdown.sublime-settings file")
yourBucketName = settings.get("yourBucketName")
if not yourBucketName:
print("yourBucketName is none in markdown.sublime-settings file")
# 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
auth = oss2.Auth(yourAccessKeyId, yourAccessKeySecret)
# Endpoint以杭州为例,其它Region请按实际情况填写。
bucket = oss2.Bucket(auth, 'http://oss-cn-shanghai.aliyuncs.com', yourBucketName)
if not bucket:
print("bucket is none, will create new bucket")
# 设置存储空间为私有读写权限。
bucket.create_bucket(oss2.models.BUCKET_ACL_PRIVATE)
return bucket
def get_File_Md5(filename):
"""
获得文件内容的Hash值
:param filename: 文件路径
:return: 该文件内容的hash值
"""
if not os.path.isfile(filename):
return
myhash = hashlib.md5()
f = open(filename, 'rb')
while True:
b = f.read(8096)
if not b:
break
myhash.update(b)
f.close()
return myhash.hexdigest()
class InsertPictrueCommand(sublime_plugin.TextCommand):
def up_and_create_url(self,filePath, bucket=get_bucket()):
'''
上传一个指定的路径的文件到指定的bucket模块中,设置为只读权限
:param filePath: 本地文件路径
:param bucket: bucket对象
:return: 上传后的url链接
'''
absPath = os.path.abspath(filePath)
fileName = os.path.basename(absPath)
# 如果文件不存在
if not os.path.exists(filePath):
print("file path not exist ", filePath)
return
# 上传文件-在文件名前面加上当前时间,防止文件重复
# nowTime=time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
fileName = get_File_Md5(absPath)
# <yourLocalFile>由本地文件路径加文件名包括后缀组成,例如/users/local/myfile.txt
callback = bucket.put_object_from_file(fileName, filePath)
# 设置上传文件的访问权限
bucket.put_object_acl(fileName, oss2.OBJECT_ACL_PUBLIC_READ)
# 进行转码
newFileName = parse.quote_plus(fileName)
url = "{}://{}.{}/{}".format(bucket._make_url.scheme, bucket.bucket_name, bucket._make_url.netloc, newFileName)
return url
"""插入图片"""
def run(self, edit):
# 获得当前编辑窗口对象
window = self.view.window()
# 当前文件名
current_file_name = self.view.file_name()
current_file_extension = window.extract_variables()["file_extension"]
if(not current_file_extension in ["md"]):
print("插入文件名不是 markdown 类型文件")
return
# 当前的 sheet
current_sheet = window.active_sheet()
# 打开对话框选择文件
window.run_command("prompt_open_file",{"initial_directory":"C:/Users/Public/Pictures"})
# 查找文件,并且关闭
file = None
window = self.view.window()
for sheet in window.sheets():
# 强制切换到当前 sheet 否则,无法获取文件名
window.focus_sheet(sheet)
# 获取当前 sheet 的文件后缀
try:
# 如果没有后缀的话,会报错
file_extension = window.extract_variables()["file_extension"]
except Exception as e:
continue
if(file_extension in ["jpg","png","gif","bmp"]):
file = window.extract_variables()["file"]
file_base_name = window.extract_variables()["file_base_name"]
window.run_command("close")
# 激活之前编辑的窗口
window.focus_sheet(current_sheet)
if file and file_base_name:
ismove=settings.get("ismove") # 判断当前的获得图片是否进行移动
if ismove:
# 图片将要存储的目录
dir_pic = self.getPicturePath(current_file_name)
# 移动文件到相对目录下
rel_path = self.movePicToRelPath(file,dir_pic)
else:
# 阿里云链接
rel_path = self.up_and_create_url(file)
self.view.run_command("insert_snippet",
{
"contents": "![%s](%s)" % (file_base_name, rel_path)
}
)
def getPicturePath(self,file_path):
"""
"""
# 获得文件名
file_name = os.path.basename(file_path)
# 文件夹名
dir_name = os.path.dirname(file_path)
# 图片存放在相对路径中,新建同名的文件夹+.assert
dir_pic_name = file_name.replace(" ","_").replace(".md",".image")
dir_pic = os.path.join(dir_name,dir_pic_name)
# 如果不存在,则新建
if(not os.path.exists(dir_pic)):
os.mkdir(dir_pic)
return dir_pic
def movePicToRelPath(self,file_path, dist_dir_path):
"""将图片移动到指定目录 文件 → 文件夹, 并且返回移动后的相对路径"""
try:
shutil.move(file_path, dist_dir_path)
print("move file: ",file_path," → ",dist_dir_path)
except Exception as e:
print("存在相同文件")
pass
file_name = os.path.basename(file_path)
dir_name = os.path.basename(dist_dir_path)
return dir_name+"/"+file_name
更多推荐
所有评论(0)