近期折腾的那些软件和脚本

renyuneyun 2020年01月29日(周三) 1 mins

忽然发现自己好像好久没写什么技术性的博文了,但想想好像最近除了继续在维护Easer 从而继续学一堆Android开发相关的东西(库和坑)以外,并没有什么成果可以说道(倒是有许多翻了资料,但没时间实现的东西)。但最近倒是折腾/试用了许多软件,拼拼凑凑来一篇文章倒也没什么不好意思的,毕竟许多情况下人们的问题是「不知道还有这个东西的存在」。

除了都是开源项目以及不依赖「云」以外,折腾了的这些软件并没有什么一致的目标。然而我却是很意外地有一条线索将这些软件串了起来。

同步软件——Syncthing

出于各种原因,我需要在几个设备间同步一些数据,主要是一些文档之类的东西。由于设备涉及手机、笔记本以及台式机,其存储、电能都不大不相同,所以需要一个较为灵活的软件;然而这些设备并不一定会同时全部在线,我又不喜欢「云」(噫,感觉好像找到了新一篇博文主题?),所以需要该软件支持分布式场景。挑来挑去,最后选择了Syncthing,试用之后感觉的确比较符合我的需求。

其实更早的时候我是在用网/云盘的,但很显然,免费的网盘肯定是没法完美的。用得最好的其实是坚果云——虽然有每30天1G上传的流量限制,总体来说还能接受(指早期;后来我因为流量问题充过会员),而且对开发者以及Linux用户(相对来说)比较友善。然而,它上传照片后会将照片重命名,官方说法是为了方便按时间倒序排列,但在社区(当时还是很简陋的一个小讨论板)中有很多人早就说了照片本身已经是按时间命名的/照片有EXIF所以干嘛不自动提取EXIF/干嘛不用文件修改时间直接完全重命名文件,这种所谓的排序根本毫无意义,然而官方始终对此无有回应。当然,除去这个问题,我真心是觉得坚果云是国内做得最好的网盘——哪怕光是后来严格按照法律规定,仅仅在分享文件时才会要求绑定手机这件事就远远甩开国内几乎所有其他对公众提供业务的企业/事业单位(不只是网盘公司)。

寻找合适软件的过程中,我最主要看的是这些需求:

  1. 去中心化
  2. 同步而非上传
  3. 增量传输
  4. 加密传输

满足这些条件的软件其实不多,尤其是满足前两项的。另一个比较知名的软件/协议是BT Sync(现在改名叫Resilio Sync了),但BT Sync是闭源的,我没有任何理由去用它。

试用Syncthing一段时间,感觉整体上很符合我的需求,尤其是它还有个简易的历史版本功能。但在几个细节上它还是不够令我满意。其中最主要的是没办法对「文件夹」(是的,Syncthing是这么叫的)进行编组,一打开它的控制面板就是一大堆文件夹,看起来很烦,而且不同设备上对哪些文件夹要同步来进行初始挑选时也很麻烦。其次就是没法移动同步目录,只能删除了重新再来;而且文档中没有提及能不能将原目录剪贴过去,所以我也不太敢这么做。不过好在基本上设置好了就再也不用去管它了,这些也就影响一下增加同步文件夹,其余时候也没什么影响,倒也不是太令人心烦。

文本格式的待办事项清单——todo.txt

用了一段Syncthing,将许多目录陆续纳入了同步清单,然后我就想弄个可以通过它同步的待办事项管理软件。找来找去弄得我哑然失笑:原来根本没有一个通用数据库格式,甚至没有好好描述自己存储格式的,除了唯一的选择——todo.txt(HTTP协议,嗯,不是我漏了s,是他们没配置对)。

据官网所说,todo.txt源于lifehacker上2006年有人放出来的管理脚本。文件格式很直观,每行一条记录,按规定分成几个部分,有些部分可选。更细节的直接看官方文档就好,我也不会比它说得更清楚。

除了其命令行的todo.sh脚本外,我还试了试efficient task这个todo.txt的GUI(Rust写的),以及gnome的time++插件(支持kanban化)。事实上,我是先用了gnome的time++插件的(相比Syncthing),所以其实用todo.txt的时间比Syncthing还长。但我本来仍然希望能有个别的软件,毕竟todo.txt并没有好看的前端,而且不支持子任务。

但其实用了一段时候发现,自己对子任务其实并没有那么大的依赖(或许是我仍然不是待办事项软件的重度用户吧)。我还额外用它记录自己的零食果汁等的过期时间,省得自己老是想不起来吃。于是顺便写了个count插件,方便操作那些有「数量」的项目。

备份软件——Borg

在用了Syncthing一段时间以后,忽然感觉这样似乎不够安全。毕竟虽然Syncthing有个「历史版本」机制,但毕竟它一直在运行,万一Syncthing软件本身有什么bug不就坑了么。于是又颠颠地去找备份软件,毕竟我之前的备份方案最初抄自仙子在这篇中提出的方案,后来改为btrfs send/recv,于是仅仅对HOME整坨整坨地进行复制。

备份软件还是很多的,alternativeto上就有至少十数个,archlinux的wiki上也有很多。Arch wiki其实对此进行了分类,极大地方便了我的挑选。

其实我的挑选并没有一个很特定的目标,只是有这些大概的目的:

  1. 必须支持增量备份
  2. 必须支持自动去重
  3. 必须有办法保留历史版本
  4. 最好有加密(没有的话自己套一个cryfs)
  5. 最好能支持主从备份

其中前四个都比较好理解,但第五个我其实是不太确定的。这个想法的出发点其实是担心我的移动硬盘万一挂了,这些数据还有第二个备份点。由于之前是用的Synchting,所以思考这个问题的时候其实还是沿用了Syncthing的思路:在任意地方都可以操作备份,然后其他存储点之间相互同步。但稍微一想觉得不对,因为这样的自动同步万一中间出了问题,造成数据不一致怎么办——Syncthing毕竟是同步的文件,就算不一致还或许能挽救,但这些备份可是专门的二进制格式啊。于是就想着应该能手动在各个存储点之间传输,类似于git push和git pull这样的手动分布式同步的方式。

然而看来看去,似乎这个第五点没有任何软件能满足,无论是前后哪种想法。所以只好抛弃软件自带主从支持,改为只要存储为固定的文件,我之后自己手动用外部工具来同步。于是对着分类比了比,打开一些软件的官网看了看,最后看上了Borg。

我不会说选它还因为它的名称。虽然我并不喜欢《星际迷航》里Borg的理念(如果那能称为理念的话),但其技术性上优点很多,尤其是分布式的备份。当然我不可避免地会期望这个软件也有这个功能(也就可以完成第五点),但实际上并没有。

Borg默认提供的是命令行工具,用法还算比较直观。它官方似乎是有个(有限功能的)web端的,我也能找到,但没能成功使用,所以最后还是放弃了。

它的优点很多,比如它完全满足我的前四点要求,而且还带自动压缩。它的去重是按区块进行的,所以效果非常好。它还有个FUSE可以直接将备份挂载起来查看。另外,Borg真的只是「备份」——一旦创建,归档几乎就是只读的了(除了可以改名和删除外)。当然,实际上它还有个(实验性的)borg recreate命令,但我没怎么弄懂这个命令的用法。哦,对了,Borg创建归档(一个备份)的时候,可以同时指定多个目录一起纳入备份,避免了为了备份而重新整理目录结构的麻烦。

但同样,由于它是「备份」,所以归档不可修改这点在某些情况下就是缺点了:我备份HOME的时候会指定归档名称为home;但当我再次备份的时候,我就必须想办法解决名称冲突了。于是我的最后解决方案是指定归档名称为home.yyyy-mm-dd。但这样实在有点蠢,因为Borg本来就会自动添加时间戳,我这样额外增加一个没有什么意义。

在转移备份的时候,我还注意到官方说Borg其实是会缓存每个归档(有UUID)的一些元信息的。所以很不建议将仓库复制到其他地方,尤其是警告道不要在两个地方分别修改。官方推荐的做法是对两个仓库个执行一次borg create——因为Borg可以直接通过ssh传输过去,尤其是当对面有borg的时候会更快一些(我暂时没有实际尝试,但过一段说不定会)。当然,官方也说了,仅仅复制仓库只是不建议,而没有实际的危险。所以目前我仍是采取复制的方式。

即时加密文件传输——MagicWormhole

发现这个软件纯属意外,因为我本来是在找如何直接建立点对点的SSH通道,以便通过Borg直接推到远程服务器上的。

寻找建立点对点SSH通道的后续其实就是我所谓的「翻了资料没时间实现」中最主要的那个。我翻了不少资料来查询如何打洞,但发现好像没有标准的协议来实现——STUN和ICE似乎是,但又似乎不是。在SU上倒是有人提到一个ssh-p2p,但毕竟仅限于SSH。于是就起了自己写一个通用软件的念头。但除了在crates.io上搜到个打洞的库,自己跑了一下示例代码,测试了一下连接维持时间以外,什么都没写。

这个软件的使用很简单,指定文件,自动生成密码句,密码句交给对方,对方输入密码、接收就行。它的特点就是点对点——除了密码以及协商的时候需要依赖一个公网服务器外,传输的时候并不需要。后续使用中发现,其实它还是往往使用relay的,并没有我之前想的打洞。查询文档发现,它只是试图直接建立TCP连接,不成就进行relay……而打洞是在「未来计划」中的……

照片集管理软件——digiKam

再然后,在有了稳定的备份方案之后,我终于想起来仔细整理一下照片了。这时候就需要一个照片整理软件了。

找了一圈,看下来似乎只有digiKam可用。另一个被人提到的是shotwell,但打开看一眼就发现其功能比digiKam少得很多。

我本来其实只希望找这些功能:

  1. 能够按EXIF的时间排铺
  2. 能够寻找相同照片
  3. 能够在地图显示

想要一是因为文件名并不统一,我也不想费事去统一文件命名,而且其实也没法统一(因为有的照片是别人传给我的,命名早就乱了)。想要二是因为以前备份比较混乱,有的照片(目录)有很多地方都有,但我又不敢轻易说某个目录的文件一定全过其他目录。想要三则和一类似,都是为了方便查看。

而digiKam其实让我大喜过望,因为它不光提供了这些功能,还提供了人物识别——不光是检测出人脸,还能(基于用户的标记)自动识别人脸(而且有用户确认步骤,不自作聪明地完全相信模型的结论)。它也不是寻找「相同」图片,而是可以更宽泛地寻找「相似」图片。

当然,要说问题也还是有的。比如说我发现它在识别相似照片后,只能一组一组分别手动操作,效率很低,而且都是机械劳动。再比如它读取EXIF中照片时间的时候,如果有「数字化时间」,它就会使用这个,而不是「原始时间」,哪怕「原始时间」比数字化时间更新(这实际上是我当时那个手机相机的问题,它的数字化时间永远都是2002年某日)。

为了解决这个EXIF时间的问题,我最开始尝试用digiKam自己提供的批处理功能。但那个功能实在太慢,十分钟也就处理了没多少(我一共有数千张要处理)。最后不得已,自己动手用Python撸了一个来处理。这时候发现,原来处理效率真的低下,因为我撸的这个每秒只能处理十来张。要知道我可是换了好几个库,最后选了这个仅处理EXIF的piexif库来(而不是像PIL/Pillow一样处理整张图片的),是尝试的所有库里边最快的了。

人物识别功能也并不是十全十美,但比没有要好得多。其中不乏一些有意思的识别结果,比如将不是人的识别成人,将某人识别成另一个人之类的。当然,最有意思的是将溶洞中一个暗处的石壁上一小块辨识成人脸,而且那块还真的有点像脸。前面提到它也可以基于你之前的标签来识别人物,而且在识别完并不自动确定,而是归类到「未确定」等待用户自行确定或修改,以便(万一错了)再次识别。但比较烦人的是它并没有一个「忽略」组所以有些明确知道不认识的人(或者不是人)也没法处理,总是会(在再次扫描时)被再次识别的。

目录对比

另外,在解决照片重复问题时,我还尝试了几种文件对比方案。我的实际需求是很明确的:每次指定两个目录,告诉我这两个目录中哪些文件是仅在一个目录中存在的,以及哪些文件是修改过的。有少量的文件名修改识别不出来无所谓,只要不是大量的就行(而且从结果上来看,其实我根本没改过文件名或移动文件到子目录中过)。

搜索一番能看到两个主要的推荐:diff --briefrsync --dry-run,以及还有一些围绕其上的前端。然而,实际使用下来,我发现这两个的效率实在都是很低,需要耗费大量时间(和内存,不过主要是时间)。

这个现象的因素大约是我要对比的目录文件数太多:较大的目录有6000余个文件,30G+,另一个并不少太多。不过这次我实在是没有预期到会用这么久,总是觉得「快完了吧」,所以并没有自己去写对比脚本。而有趣的是,我本来以为rsync应该会比diff快很多,但实际上并不是,甚至还慢了。

备份和还原文件修改时间

在解决照片的EXIF信息错误时,我使用了自制的脚本。但很显然,在运行脚本之后文件的修改时间便被更新了。虽然不太要紧(因为EXIF毕竟有时间),但我还是觉得不太舒服,所以就去查找了如何批量备份和回复文件修改时间。

在SuperUser上有人问了这个问题,也有人给了脚本来做。虽然需要perl,但毕竟perl还是很常见的,我的机器上也是有的,所以就用了这个方案。由于是文件系统的操作,故而理所当然地,其效率非常之高。

当然,其中细节部分还是要调整的,比如那个find /就得换成目标目录。

沙盒软件——firejail

我其实早就听过firejail的名字,而且也装了它。但直到在整理照片时候,才真正想起来可以用它来限制软件对目录的读写权限——主要是防止自己一个手残rsync忘了写--dry-run把目标目录修改了。

实际上firejail的沙盒功能很全面,基于Linux Namespace,所以可以对很多东西进行隔离,而不仅仅是文件系统。当然,它的配置也比较复杂,我其实也直到得不多。但好在可以以自定义profile来启动shell,所以调试profile还是比较方便的。

我目前对firejail的主要用途也就是测试软件和控制命令行只读;日常主要用来限制firefox对大多数目录的访问,防止潜在的浏览器漏洞。


Related posts:

您可以在Hypothesis上的該群組內進行評論,或使用下面的Disqus評論。