前言

obsidian是一款基于本地文件的笔记软件,所以笔记的多端同步是个问题,虽然官方推出了自己的同步服务,但是本着能自己解决就自己解决的态度,我自己研究出了一个比较完美的同步方案。

解决方案

因为我用的是苹果手机,所以自然而然的考虑到了icloud同步这个方法。
在手机版obsidian上创建笔记库,在windows上下载icloud,登录icloud账号,obsidian选择在icloud中打开笔记文件。
经过如上操作之后就解决了同步问题,本篇完(并没有) ^8fe52d

起初我是通过这种方案,但是使用一段时间后发现,在写笔记的过程中,obsidian经常弹出“文件被外部修改,正在合并”的提示,然后再icloud中就会出现若干个重复笔记。
类似这样:

而且写着写着经常会有几行笔记消失了。
所以以上几宗罪使icloud同步变得很难用。

真·解决方案

自动同步icloud和本地

为了解决上述问题,我写了一个自动同步的程序,使其每隔两分钟在本地文件和icloud中同步一次。
同步的代码如下:

def file_cmp(f1,f2):
res = filecmp.dircmp(f1,f2)
common_dirs = res.common_dirs
common_files = res.common_files
same_files = res.same_files
left_only = res.left_only
right_only = res.right_only

# 只有目标地址有的文件则直接删除
if right_only != []:
for i in range(0,len(right_only)):
_newpath = f2+"\\"+right_only[i]
if os.path.isdir(_newpath):
os.removedirs(_newpath)
else:
os.remove(_newpath)


# 共有但有不同的文件进行拷贝
if common_files != []:
for i in range(0,len(common_files)):
if common_files[i] not in same_files:
shutil.copy(f1+"\\"+common_files[i],f2+"\\"+common_files[i])

# 只有源地址有的文件和目录则直接拷贝
if left_only != []:
for i in range(0,len(left_only)):
if os.path.isdir(f1+"\\"+left_only[i]):
shutil.copytree(f1+"\\"+left_only[i],f2+"\\"+left_only[i])
else:
shutil.copy(f1+"\\"+left_only[i],f2+"\\"+left_only[i])


# 有共同目录则递归比较子目录
if common_dirs != []:
for i in range(0,len(common_dirs)):
file_cmp(f1+"\\"+common_dirs[i],f2+"\\"+common_dirs[i])

然后我们建立一个while循环,持续运行这段代码,并且监测时间,当时间超过2分钟后进行一次备份。

nowtime = time.time()
oldtime = nowtime + backuptime*60
while True:
nowtime = time.time()
if nowtime >= oldtime:
file_cmp(filepath1,filepath2)
oldtime += backuptime*60

文件同步就实现了,但是我的笔记是需要经常在不同的设备上打开的,所以在主程序中我们加入这么一行:

# 打开软件时先从目标地址拉取最新版本
file_cmp(filepath2,filepath1)

这样,当打开程序时,首先先拉取一次icloud上的笔记文件,之后就每隔2分钟向icloud中同步一次。

让obsidian和我的程序同步启动和关闭

同步关闭

思路是要让obsidian和我的程序同步关闭,则需要持续监听obsidian进程是否存在,如果obsidian进程不存在,则自动关闭程序。
代码如下:

# 监听某个进程是否存在
def checkprocess(processname):
plist = psutil.pids()
msgcode = 0
for pid in plist:
try:
if psutil.Process(pid).name() == processname:
msgcode = 1
break
else:
msgcode = 0
except Exception:
msgcode = 0
return msgcode

以上代码是用于监听某个程序是否存在,接着我们写一个方法,让obsidian关闭之后,程序过140秒之后再结束,这样就有充足的时间备份到云端,代码如下:

def delay():
while True:
if checkprocess("Obsidian.exe") == 0:
# 让程序延迟一会儿再执行,以便程序完成备份
time.sleep(backuptime*70)
os._exit(0)

然后在主函数中新建一个线程打开这个方法:

thread_it(delay)

现在就实现了当Obsidian进程关闭时,就自动关闭程序

同步启动

我们将写好的程序打包成EXE,这里我是用pyinstaller作为打包工具
在命令行中输入:

pyinstaller -F -w comfile.py

等待片刻,将dist中的exe文件拷到别的地方(方便你自己找到)。
假设你已经拷好了,在同一个目录下建立一个txt,名称和后缀改成:”obsidian.bat”,如下:

start "" "obsidian的路径"
start "" "刚才的拷贝的exe的路径"

上面输入你自己的路径,保存。
接下来,还是在这个文件夹下的空白位置右键,新建一个快捷方式,在弹出的窗口中输入如下内容:

同样的,后面输入刚才创建的的bat文件路径,点击下一步。

这里命名为obsidian.exe,点击完成,这时文件夹下就出现了一个“obsidian.exe”的快捷方式,为了更直观的操作,我们改一下他的图标,接着我们右键这个快捷方式,找到“更改图标”按钮,在弹出来的窗口中找到obsidian.exe的文件路径,点击确定。

到此,所有的操作完毕,你可以像其他快捷方式一样,将这个快捷方式拖到开始界面,任务栏或者桌面。并且,点击它会自动打开obsidian和文件同步程序,点开后,我们在任务管理里可以看到程序已经在运行了
当obsidian关闭时,该进程也会自动关闭,基本是无缝无感的操作体验。这样我的多端同步问题就解决了。

结语

本篇是基于icloud方式进行同步,其实icloud还可以替换为坚果云或者其他的云盘软件。
如果不想使用云盘软件,那么在本文的基础上,你也可以搭建基于webdav的同步方案,如果有需要的话我可以再出一期webdav的笔记同步方案。