Skip to content

比 Hazel 更便宜强大的 Maid

Posted on:April 1, 2015 at 04:00 PM
0

桌面又成乱糟糟一片图标了,下载里也有数不清的文件。每次整理都很让人焦虑。相信以 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

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

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

gem install maid

使用

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

规则

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

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

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

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

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

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

自动运行

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

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

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

watch '~/Downloads' do
	rule 'Movie in Downloads' do
		where_content_type(dir_safe('~/Downloads/*'), ['video', 'public.movie']).each do |path|
			move(path, '~/Movies/') if duration_s(path) > 15 * 60
		end
	end
end

repeat '1d' do
	rule 'Update System' do
		pid = Process.spawn("brew update;brew upgrade")
		Process.detach pid
		pid = Process.spawn("npm update -g")
		Process.detach pid
		pid = Process.spawn("gem update")
		Process.detach pid
	end
end

开机自动启动

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

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

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

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

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

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>com.songchenwen.maid.plist</string>
	<key>Program</key>
	<string>/path/to/run.sh</string>
	<key>RunAtLoad</key>
	<true/>
	<key>KeepAlive</key>
	<true/>
	<key>EnvironmentVariables</key>
	<dict>
		<key>PATH</key>
		<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
	</dict>
</dict>
</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 里添加以下方法来使用文件标记功能。

def tags(path)
	path = sh_escape(expand(path))
	raw = cmd("tag -lN #{path}")
	raw.strip.split(',')
end

def has_tags?(path)
	ts = tags(path)
	ts && ts.count > 0
end

def contains_tag?(path, tag)
	path = expand(path)
	ts = tags(path)
	ts.include? tag
end

def add_tag(path, tag)
	path = expand(path)
	ts = Array(tag).join(",")
	log "add tags #{ts} to #{path}"
	cmd("tag -a #{ts} #{sh_escape(path)}")
end

def remove_tag(path, tag)
	path = expand(path)
	ts = Array(tag).join(",")
	puts "remove tags #{ts} from #{path}"
	log "remove tags #{ts} from #{path}"
	`tag -r "#{ts}" "#{path}"`
end

def set_tag(path, tag)
	path = expand(path)
	ts = Array(tag).join(",")
	puts "set tags #{ts} to #{path}"
	log "set tags #{ts} to #{path}"
	`tag -s "#{ts}" "#{path}"`
end

电池优化

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

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

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

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

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

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

我的规则

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