大概背景
事情的起因还是因为做笔记,我喜欢利用插件Obsidian Git自动同步笔记到Gitee
,写md
文档有个问题就是关于图片如何存储。
我个人习惯是将所有图片都保存到指定的文件夹下,如图👇
由于Obsidian
对粘贴图片默认格式为这样的:![[Pasted image 20240802143131.png]]
这是Obsidian
特有的,并不对md
文档通用,于是在码云上在线浏览,图片将无法展示。
于是就迫切的希望有一种插件,能够将粘贴得图片进行格式化,比如![image-demo](./static/image-demo.png)
这种markdown
通用语法。
实际上,还真有:Image Classify Paste
,然而此插件并没有完成全部的功能,于是有了下面的插件开发正文。
插件安装
Obsidian
的插件和其他应用程序略有差别,每一个Vault
仓库对应了自己的所属插件,比如我新建一个Vault
仓库,那么这个仓库默认是没有插件的。
关于vault
的概念,对应本地的一个文件夹,为obsidian
中的顶级目录。
可以看到目录中存在一个隐藏文件.obsidian/plugins
,实际上这就是插件目录,每个vault
仓库都有自己的插件。通过在Obsidian
应用程序中安装插件(设置 > 第三方插件 > 插件市场浏览安装
),其实就是下载插件文件夹到此目录下。
由于各种原因,国内有时候无法正常访问,应该说大部份时候都无法浏览插件和安装插件,需要git
加速,这里推荐使用dev-sidecar。
也可以通过插件obsidian-proxy-github实现,但是由于长时间无人维护,内置的一些加速网址其实已经不好用了,或者说完全用不了了,因此并不推荐。
安装方式
Obsidian
内直接安装
前提是你已经可以Git
加速正常访问插件市场。
直接下载文件安装
无论你从哪里找到的资源,通常来讲都是github
,你只需要下载下来解压缩,然后将此插件目录放到你的vault
仓库下的.obsidian/plugin
目录下即可。
Mac通过Command + Shift + .
在访达中查看隐藏文件
插件启动和设置
无论哪种方式安装的插件,最后都需要启用(默认是不启用的)。
左下角第三方插件可进行设置。
插件开发
插件本质是JavaScript
,所以进行Obsidian plugin
的开发其实就是js
语言的使用。
官方有很好的指导手册:Obsidian Docs
插件目录结构
正常插件目录结构如下:
main.js
核心部分,所有插件功能都在这里实现。
快速入门参考官方指导:# Obsidian Developer Docs
manifest.json
插件的描述信息,这些信息将在社区插件市场浏览展示用。
{
"id": "image-classify-paste",
"name": "Image Classify Paste",
"version": "0.1.4",
"minAppVersion": "0.15.0",
"description": "paste your image like typora, the image link name not `![[Paste xxx]]` but `![some name](relative-directory/xxx.png)`with a relative directory. 类比于typora的方式粘贴图片到本地,存放在以当前md文档命名的文件夹里。",
"author": "tianfx",
"authorUrl": "https://github.com/ostoe",
"isDesktopOnly": true
}
社区插件市场
data.json
在设置插件功能后,会自动生成此文件,用于保存用户的设置,比如我的设置👇
生成的data.json
{
"defaultSetting": "default",
"imageNamePattern": "{{fileName}}",
"dupNumberAtStart": false,
"dupNumberDelimiter": "-",
"dupNumberAlways": false,
"autoRename": false,
"handleAllAttachments": false,
"excludeExtensionPattern": "",
"disableRenameNotice": false,
"IsShowCustomPath": true,
"PasteImageOption": "tocustom",
"CustomPath": "static",
"IsEscapeUriPath": true,
"IsAddRelativePath": true,
"IsApplyLocalImage": true,
"IsApplyNetworklImage": true,
"IsRelativePath": true
}
可以看到CustomPath
的目录为我指定的static
。
插件调试debug
Obsidian
提供了内置的调试工具,可以很好的支持插件开发调试,通过快捷键Windows
用户Win + Shift + I
或者Mac
用户Command + Shift + I
。但也可能是其他的,比如我的Command + Option + I
,无论哪种,最通用的是通过View
菜单栏查看。
打开后调试窗口如下👇
在Console
输入app.plugins.plugins['Plugin ID']
就可以获取到插件对象了,也就是main.js
中定义的变量和函数,其中Plugin ID
为定义在manifest.json
中的ID
。
热更新插件
每次修改main.js
要想在console
控制台看到效果都需要进行插件的停用和启用(需要程序重新加载文件),可以利用插件hot-reload进行热更新,实现每次修改自动更新插件的目的,关于此插件的安装只能通过github
网站下载安装,插件市场无此插件。
此插件有个特别注意的点就是,需要在进行热更新的插件目录添加.hotreload
文件。比如我的插件目录为myPlugin
,具体存放在MyVault/.obsidian/plugins/myPlugin
,那么在myPlugin
目录下就需要存在文件.hotreload
。
这样每次修改内容都可以即时的在obsidian
内置的开发工具中调试查看内容了。
修改插件
如果你也跟我一样有这样的需求,将粘贴的图片格式化Markdown
标准语法格式,那么下面对插件Image Classify Paste
的修改同样也适合你。
前提,在设置中进行自定义,并且图片存在在指定目录下。
关键方法入口
getRenameFilePath(mdFile, filename)
方法参数如下:
参数mdFile
其实就是当前的md
文档对象。
参数fileName
就是当前的md文档
的文件名。
修改部分
在getRenameFilePath(mdFile, filename)
方法内修改:
// 改动1: 这一行实际没有用到,注释了
// const linkName = this.settings.IsEscapeUriPath ? encodeURI(path.join(dirPath, newFilename)) : path.join(dirPath, newFilename);
// 改动2: 新增相对路径生成方法 path.relateJoin()
//添加相对路径,比如dirPath为:/static,mdFile为:/a/b/c/demo.md newFileName为:imageDemo,则输出==> ../../../static/imageDemo
const IsAddRelativePath = this.settings.IsAddRelativePath ? path.relateJoin(dirPath,mdFile,newFilename) : "";
const newLinkText = "![" + newFilename + "](" + IsAddRelativePath +")";
这里进行了IsAddRelativePath
判断是否进行相对路径引用,但是原作者并没有实现此功能,这里做了变动。
relateJoin()
/**
* 返回相对目录
*
* 场景1:mdFile为顶级目录
* mdFile
* dirPath: a/b
* a
* b
* 返回 ==> ./dirPath/imageName 即 ./a/b/imageName
*
* 场景2: mdFile和dirPath同级目录(非顶级同级)
* mdFile:a/mdFile
* dirPath:a/b
* a
* mdFile
* b
* 返回 ==> ./b/imageName
*
* 场景3: mdFile在深层目录
* mdFile:a/mdFile
* dirPath:b/c
* a
* mdFile
* b
* c
* 返回 ==> ../dirPath/imageName 即 ../b/c/imageName
*
* @param dirPath 图片存储路径
* @param mdFile 当前操作的MD文件
* @param imageName 图片名称
* @returns {string} 图片相对路径引用
*/
relateJoin(dirPath,mdFile,imageName){
// 如果为顶级mdFile直接返回 ./
if(mdFile.parent.path == "/"){
return "./" + dirPath + "/" + imageName;
}
// 如果为同级目录,比如 a/b/static a/b/mdFile ==> ./static/imageName
let mdFileParts = mdFile.parent.path.split("/")
let dirPathParts = dirPath.split("/");
// 比如 dirPath: a/b/static ==> 得到 a/b 父目录数组
const dirPathLastName = dirPathParts.pop();
if(mdFileParts.length == dirPathParts.length){
let flag = true;
for(let i = 0; i< mdFileParts.length; i++){
if(mdFileParts[i] != dirPathParts[i]){
flag = false;
}
}
if(flag){
return "./" + dirPathLastName + "/" + imageName;
}
}
// 其他情况,mdFile需要../到父目录层级
let prefix = ""
for (let i = 0; i < mdFileParts.length; i++) {
prefix += "../"
}
return prefix + dirPath + "/" + imageName;
},
将此方法添加到path
变量中即可。
如果出现其他问题也可按照上面的插件开发内容自行调试。
插件推荐
obsidian git
将笔记内容自动同步到远程仓库(github
或者gitee
)都可以。
安装教程参考:# 【Obsidian】【Git】使用gitee同步/保存obsidian笔记
Image Classify Paste
如果你也和我一样想要同步的笔记能够在线查看图片,那么大概率也会存在我这种问题,利用这个插件进行粘贴图片的格式化。
Clear Unused Images
从名字就知道,用来清除没有用到的图片,比如我粘贴一张图片,默认就会保存到/static
目录,但是发现图片有问题,于是重新截屏了一张,但是原来的图片并不会删除,也就是无效文件的存在。这个插件会在侧边栏生成一个Ribbon
,需要手动点击清除,会弹出清除文件的日志。