Navigate back to the homepage

比 Hazel 更便宜强大的 Maid

宋辰文
April 1st, 2015 · 1 min read

桌面又成乱糟糟一片图标了,下载里也有数不清的文件。每次整理都很让人焦虑。相信以 OS X 为日常操作系统的人都会有这样的感触。当然其实 Windows 或者 Linux 也一样,收集文件并整理是每个人 IT 生活的一部分。

Maid

OS X 上有一款很有名的帮助我们整理文件的工具 HazelHazel 能让用户可视化地创建一系列规则,它会根据规则去监视文件夹,自动整理。但图形界面写规则毕竟限制较多,复杂的脚本规则在 Hazel 里编辑起来又不那么方便。何况 Hazel $29 的价格,多少还是有点贵呢。

于是今天的主角 Maid 应运而生。Maid 是一个 Ruby Gem。规则也是用 Ruby 写的,常用的工具方法被封装成了 DSL。Maid 的使用门槛比 Hazel 要高一些,但使用起来灵活性却要高的多了。关键是 Maid 是开源且免费的。

安装

Maid 只是一个 Ruby Gem,所以基本上能装 Ruby 的类 Unix 系统都可用。

OS X 上还是推荐使用 rvm 来管理 Ruby 版本。如果系统中还没装过 rvm 的话,先安装 rvm

1gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
2\curl -sSL https://get.rvm.io | bash -s stable --ruby
3rvm install 2.1
4rvm use 2.1

然后就可以用 Gem 来安装 Maid 了。

1gem install maid

使用

要让 Maid 工作只需要执行 maid 命令就可以了。

  • maid clean -n 测试执行 Maid,只列出将要做的操作,但不真正执行。
  • maid clean -f 真正执行 Maid
  • maid daemon 使 Maid 持续运行。配合 watchrepeat 使用。

规则

使用 Maid 必须先创建规则。Maid 的规则存储在 ~/.maid/rules.rb 里。

可以先让 Maid 生成一份示例规则给我们看看 maid sample

Sample Rules 里主要是做了一些简单的文件清理工作。

比如 OS X 的系统截图默认会保存在桌面。我们让 Maid 把一周没用过的截图从桌面移到归档文件夹中。

1rule 'Misc Screenshots' do
2 dir('~/Desktop/Screen shot *').each do |path|
3 if 1.week.since?(accessed_at(path))
4 move(path, '~/Documents/Misc Screenshots/')
5 end
6 end
7 end

这是 Sample Rules 的做法,我自己的做法是桌面上很久不用的文件,就直接放废纸篓了。

自动运行

如果每次都需要手动执行 maid clean -f 才能整理文件的话,显然 Maid 达不到 Hazel 的方便程度,也无法满足我们的需求。所以我们需要 maid daemon

daemon 模式,Maid 会持续运行,并执行标明了 watchrepeat 的规则。

  • watch 会让 Maid 去监视一个文件夹,如果这个文件夹内的文件有了变化,那这个 watch 内的规则会被执行。
  • repeat 会让 Maid 以一个固定的时间间隔去执行一些规则。

比如下面这些规则会把新下载的视频文件移动到影片文件夹里,并每天自动帮我做一些常规升级。

1watch '~/Downloads' do
2 rule 'Movie in Downloads' do
3 where_content_type(dir_safe('~/Downloads/*'), ['video', 'public.movie']).each do |path|
4 move(path, '~/Movies/') if duration_s(path) > 15 * 60
5 end
6 end
7end
8
9repeat '1d' do
10 rule 'Update System' do
11 pid = Process.spawn("brew update;brew upgrade")
12 Process.detach pid
13 pid = Process.spawn("npm update -g")
14 Process.detach pid
15 pid = Process.spawn("gem update")
16 Process.detach pid
17 end
18end

开机自动启动

maid daemon 已经能自动为我们整理文件了。但是我们总不能每次开机都自己打开终端输入一遍命令吧。所以我们需要让 Maid 能开机自动启动。

OS X 上自动启动要依赖 LaunchAgents,操作 LaunchAgents 的终端命令是 launchctl,不过这命令各种晦涩难懂,不如安装一个叫 lunchy 的 Gem 来简化操作。gem install lunchy

先创建一个 Shell 脚本 run.sh 来帮我们执行 maid daemon。其中需要用到 ruby 和 maid 的绝对路径,可以通过 which rubywhich maid 得到。

1#!/bin/sh
2export LC_ALL=en_US.UTF-8
3export LANG=en_US.UTF-8
4/path/to/ruby /path/to/maid daemon

然后再在 ~/Library/LaunchAgents 里创建对应的 plist 文件就可以了。比如 com.songchenwen.maid.plist

1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3<plist version="1.0">
4<dict>
5 <key>Label</key>
6 <string>com.songchenwen.maid.plist</string>
7 <key>Program</key>
8 <string>/path/to/run.sh</string>
9 <key>RunAtLoad</key>
10 <true/>
11 <key>KeepAlive</key>
12 <true/>
13 <key>EnvironmentVariables</key>
14 <dict>
15 <key>PATH</key>
16 <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
17 </dict>
18</dict>
19</plist>

使用 lunchy 载入 Maid。在终端里执行 lunchy start maid。打开 console.app 看看有没有报错,如果没有的话,就说明 Maid 已经能自动运行了。

文件标记

Hazel 集成了 OS X 的文件标记功能,对于整理文件来说,这个功能很实用。

Maid 当前的稳定版 0.7.0 并未支持这个功能。

不过 Maid 的作者 Benjamin Oakes 已经让我提交了一个 Pull Request。现在最新的测试版 0.8.0.alpha.2 已经支持这个功能了。

文件标记功能依赖于 Tag。需要用户手动安装 brew install tag

对于像我一样还在使用 0.7.0 稳定版 Maid 的用户,可以在 rules.rb 里添加以下方法来使用文件标记功能。

1def tags(path)
2 path = sh_escape(expand(path))
3 raw = cmd("tag -lN #{path}")
4 raw.strip.split(',')
5end
6
7def has_tags?(path)
8 ts = tags(path)
9 ts && ts.count > 0
10end
11
12def contains_tag?(path, tag)
13 path = expand(path)
14 ts = tags(path)
15 ts.include? tag
16end
17
18def add_tag(path, tag)
19 path = expand(path)
20 ts = Array(tag).join(",")
21 log "add tags #{ts} to #{path}"
22 cmd("tag -a #{ts} #{sh_escape(path)}")
23end
24
25def remove_tag(path, tag)
26 path = expand(path)
27 ts = Array(tag).join(",")
28 puts "remove tags #{ts} from #{path}"
29 log "remove tags #{ts} from #{path}"
30 `tag -r "#{ts}" "#{path}"`
31end
32
33def set_tag(path, tag)
34 path = expand(path)
35 ts = Array(tag).join(",")
36 puts "set tags #{ts} to #{path}"
37 log "set tags #{ts} to #{path}"
38 `tag -s "#{ts}" "#{path}"`
39end

电池优化

如果你也像我一样用 watch 监视了下载文件夹的话,那你应该也会遇到这个问题。

当 Macbook 由电池供电的时候,如果用迅雷或 Aria2 之类的下载工具下载文件,耗电量会大量增加,电池可用时间会迅速减少。打开 Activiy Monitor.app 会发现 ruby 进程成了耗电大户。

这是因为被 watch 的文件夹中每次出现文件改动,都会触发 Maid 的规则。如果规则比较多的话,就会大量消耗 CPU 资源。

Maid 的文件夹监视功能是使用 Listen 来实现的。根据这个文件里的写法,我们其实可以给 Listen 传递配置参数,而且 Listen 也会给我们的规则回传文件变化的列表。那么我们就可以通过自己的规则来使 Maid 更省电了。

1watch('~/Downloads', {wait_for_delay: 10, ignore: [/\.crdownload$/, /\.download$/, /\.aria2$/, /\.td$/, /\.td.cfg$/]}) do
2 rule 'Downloads Change' do |modified, added, removed|
3 if added.any?()
4 # add tags or move files
5 end
6 end
7end

上面这段 watch 规则的触发间隔不会低于10秒,忽略了正在下载的文件的变化,并且只有当出现新增文件的时候才去执行规则。当对 watch 做了这样的优化之后,Maid 的耗电量就显著减少了。

我的规则

这里是我目前使用的 Maid 规则。也欢迎大家也贴出自己使用的规则来一起交流。

More articles from 宋辰文

解决21世纪十大难题之一 AirDrop 传输失败

OS X 的 AirDrop 功能在近距离传文件又快又方便,比 QQ 好用得多。但却经常抽风,或者是打开 AirDrop 却不显示对方的设备,或者是刚一传文件直接就显示传输失败,实在是让人沮丧。

March 21st, 2015 · 1 min read

将安卓的多语言文件转为 iOS 格式的 Workflow

抽空写了一个将 Android 的 `strings.xml` 文件转为 iOS 的 `Localizable.strings` 格式的小脚本。而且把它封装撑了一个 Alfred Workflow。

March 18th, 2015 · 1 min read
© 2019 宋辰文
Link to $https://mp.weixin.qq.com/s?__biz=MzAxNTI3MTUwMA==&mid=2247483701&idx=2&sn=34613cbb3252ac5eb6c31724f3109b59Link to $https://weibo.com/songchenwenLink to $https://twitter.com/songchenwenLink to $https://stackoverflow.com/users/2210682/songchenwen