はじめに
なんやかんやあって大量の壁紙画像があり、気分にあわせて切り替えられる量をはるかに越え、"デスクトップとスクリーンセーバー"から画像フォルダを選択すると落ちる、Finderもサムネイル生成で固まる、そういった自分向けの記事です。本記事執筆時点で31000枚の画像が壁紙フォルダにある。
落とさないための戦略
Finder関係で死ぬのは要はファイルがいっぱいあるからです。分けましょう。
ハッシュ値と、その先頭数桁を使ったサブフォルダに割り振る、みたいなのがいいと思います。
Zshだと以下みたいにやるとできます。
BGROOT=/path/to/new/wallpapers/
function mmd5 (){
pic="$1"
#ext=$(identify -format "%m" "$pic""[0]" | tr "[A-Z]" "[a-z]")
ext=${pic##*.}
md5sum=$(md5 -q "$pic")t
target=$BGROOT/$(echo $md5sum | head -c 2| sed -e 's/./&\//')/$md5sum"."$ext
mv "$pic" $target
}
zargs -l -- /path/to/wallpapers/**/*(.) -- mmd5
自動で壁紙を切り替える
サブフォルダに分けてしまうと、"デスクトップとスクリーンセーバー"から最早制御できないので、直接コマンドを叩いて切り替える。AppleScriptでFinderのdesktop picture
にパスを与えればいい。切り替え時のフェードイン・フェードアウトができなくなるが、致し方ない。毎回素直に全ファイルランダムにソートするとそれだけで重いので、手を抜いている。昔はMac起動時に全ファイルをランダムに並べたものをOSX標準のmemcachedに載せておいて取得するようなものを書いていたが、いつからかmemcachedがプリインストールされなくなったのでやめた。一時ファイルをつくりたくないという縛りをしていたので、一時ファイルやsqliteのデータベースなどあればもっと楽にできるであろう。
BGROOT=$HOME/Pictures/wallpaper
BGDGT=$BGROOT/$(printf "%04x" $(jot -r 1 0 255) | perl -pe 's/.*(.)(.)$/$1\/$2/')
NOFBG=$(ls $BGDGT | wc -l)
find $BGDGT | tail -n $(jot -r 1 1 $NOFBG) | head -n 1 \
| xargs -I{} osascript -e "tell application \"Finder\" to set desktop picture to (POSIX file \"{}\" as alias)"
上記スクリプトを適当に纏めて、LaunchAgentに食わせればOK。以下のようなplistで30秒ごとに切り替わる。
<?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.example.desktop.changerr</string>
<key>OnDemand</key>
<true/>
<key>Program</key>
<string>/path/to/script</string>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>30</integer>
</dict>
</plist>
壁紙の参照
以下のスクリプトでPreview.appに出る。手違いで入ってしまった画像に気付いたらこれで呼び出せばフルパスがわかるので削除できる。PreviewがLionぐらいからファイルを1枚しか開いてないときに削除ができなくなったのは改悪だと思う。
tell application "Finder"
set randomImage to desktop picture as alias
end tell
tell application "Preview"
launch
open randomImage
end tell
メモリリークについて
長時間前述の自動切り替えplistを回していると、Dock.appの使用メモリが徐々に増えていく(ことがある)。どうも無圧縮TIFFのあつかいが正しくないらしく、気がつくとメモリ圧縮前で8GBとかまで食っていることがある。JPGにすると解決する、との報告もあるが、JPGやPNGばっかりでも起きるように思う。この場合、Dockをkillして対応する。数回に一回killall Dock
をするようスクリプトに書いてもよさそう。