予約日時になったらちゃんと目覚めるtimerコマンドが欲しい
前回、radikoやらじる★らじるを録音するrec_radikoru.appを作った。どうにか録音することはできるようになったのだけど...じゃあ、その他のネットラジオを録音したいとか、iTunesを目覚まし代わりに起動したいとか、その他いろいろな欲求が湧いてきた時に、現状のrec_radikoru.appではどうにもならない...。
ところで、OSXにも時間管理の仕組みは用意されている。システム環境設定 >> 省エネルギーで、繰り返しのスケジュールを設定できる。でも設定できることは、起動・スリープ解除か、終了・スリープだけ。起動したり、スリープ解除するということは、その時点で実行したいことがあるはずなんだけど、何を実行するかまでは指定できないのだ。設定できる繰り返しスケジュールも起動系と終了系でそれぞれ1つだけ。
何を実行するかの予約は、launchdやcron、それにカレンダーイベントなどを使えば設定できる。ただし、それらがちゃんと機能するためにはmacが覚醒していなければならない。スリープ中だと、予約した時間になっても何もしてくれないのだ...。それを回避するためには、スリープしない設定で運用してしまう、という手もある。(何の苦労もなく、すべてが解決してしまう)
でも、せっかく備わっている高度なスリープ関連の機能を無視してしまうことは、あまり好まない。何のために、Wake On DemandやPower Napはあるのか。やはり、使っていない時は正しくスリープして消費電力を最小に押さえ、必要に応じてスリープを解除して、必要な処理を行うという姿勢がベストである。
しかし、スリープ解除と連携したタイマー駆動の仕組みは、OSX環境には用意されていない*1。(と思っている)自分でpmsetを使って、設定したタイマーと連携するように事前に設定しておく必要がある。これでは非常に面倒である。高度なインターフェースを備えたOSなのに、タイマー機能については泣けてくるくらいお粗末である。
rec_radikoru.appで実現したスリープ解除と連携したタイマー駆動の仕組みを、もっと汎用的に利用できるようにしておきたい。テレビやラジオの録画予約程度のことを実現するのに手間のかかる現状を、少しでも改善したいのだ。
timerコマンドプロジェクトの開始
- 汎用的に使うためには、アプリケーションにするよりコマンドにしておいた方がいい。
- コマンドならほとんどのスクリプト言語から簡単に呼び出せるし、アプリケーションに組み込むこともできる。
- 理想は、cronのようにcrontabを利用して設定できるのがベストなのだが、cronレベルのものを作る技術は自分にはない。
- そもそも、スリープ解除と連携させるのだから、毎時単位のタイマー機能は不要である。
- そんなに頻繁に実行したいものがあるのなら、スリープしない設定にして、cronを使えばいいのだ。
- 求めるのは毎日単位より間隔の長いタイマー機能である。
- それから、毎年単位のタイマー機能も不要である。
- そんなに長い間隔のタイマーで何時何分まで指定する必要性はほとんどない。
- 素直にカレンダーに繰り返しの予定を入れておけば、きっと満足できる。
よって、必要なのは日単位以上、年単位未満のスリープ解除と連携したタイマー機能である。
タイマーの設定フォーマット
- これはもう素直にcronを見習う。
- でもcronほど細かな制御は必要ないので、曜日と時刻、日付と時刻の二つの引数とそれに続くコマンドを実行するようにしたい。
- 毎週日曜の17時からのJ-WAVE サウジ・サウダージを録音したい場合は、以下のように指定できると良さそう。
- 0から6の数字が、日から土の曜日に対応する。
0 1700 /usr/local/bin/rec_radiko.sh -t 3600 FMJ
- それから、月曜から金曜とか、月水金などの指定もcronを見習って、できるようにしたい。
1-5 0600 /usr/local/bin/rec_radiko.sh -t 3600 FMJ 1,3,5 0600 /usr/local/bin/rec_radiko.sh -t 3600 FMJ
- また、曜日でなく日付指定をする場合はこんな感じ。
- 2/3は日曜日なので、曜日0を指定したタイマーと同じくサウジ・サウダージが録音されるはず。
2/3 1700 /usr/local/bin/rec_radiko.sh -t 3600 FMJ
- ただし、曜日指定は週単位の繰り返しタイマーだが、日付指定はその日限りの単発のタイマーとしたい。
- そうしておけば、自分の使い方の範囲ではほとんどの欲求が満たされそう。
- 週単位の時刻指定の繰り返しはあるけど、月単位の時刻指定の繰り返しはほとんどないので。
- 月単位の繰り返しなら、カレンダーにイベントを設定しておくだけで十分という判断。
timerコマンド
- まず必要になるのは、timerコマンド。
- CUIのインターフェースを提供して、予約設定の処理を行うのだ。
- 予約設定はlaunchd.plistに変換される。
- 例えば、以下のようなコマンド入力によって...
timer -e 0 1700 /usr/local/bin/rec_radiko.sh -t 3600 FMJ
- 毎週日曜の17時に起動させるlaunchd.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.bebekoubou.timer-week 0 1700 /usr/local/bin/rec_radikoru.sh -o radikoru/ -t 3600 FMJ</string> <key>ProgramArguments</key> <array> <string>/usr/bin/caffeinate</string> <string>/bin/sh</string> <string>-c</string> <string>/usr/local/bin/rec_radikoru.sh -o radikoru/ -t 3600 FMJ; /usr/local/bin/timer-sync-wake;</string> </array> <key>StartCalendarInterval</key> <array> <dict> <key>Hour</key> <integer>17</integer> <key>Minute</key> <integer>0</integer> <key>Weekday</key> <integer>0</integer> </dict> </array> </dict> </plist>
- と、ここまでは前回作ったradiko・らじる録音専用のrec_radikoru.appで実現できていたのだけど、
- timerコマンドはさらに「1-5」とか「1,3,5」などの複数の曜日指定もサポートしている。
- さらには「2/3」などの日付指定もサポートし、日付指定の場合は繰り返さない単発のタイマー予約としている。
- 地味な機能だけど、そうゆうことを実現するのは意外と面倒である。
- 悩みながら書いたコードはこんな感じになった。(200行くらい)
#!/bin/bash IDENTIFIER=com.bebekoubou.timer weekdays() { safe_chars=`echo $1|sed 's/[^0-9,-\/]//g'` bash_format=`echo $safe_chars|sed 's/\(.-.\)/{\1}/g'|sed 's/-/../g'|tr ',' ' '` bash -c "echo $bash_format"|tr ' ' '\n'|sort -u } formed_args() { m=`echo $1|grep /|cut -d/ -f1|xargs printf %02s` d=`echo $1|grep /|cut -d/ -f2|xargs printf %02s` w=`echo $1|grep -v /` hhmm=`echo $2|sed s/://|xargs printf %04s` cmd=`echo $@|cut -d' ' -f3-` echo -n ${w:-$m/$d} $hhmm $cmd } week_or_date() { echo $1|grep -q / || echo week echo $1|grep -q / && echo date } plist_fname() { echo -n $IDENTIFIER-`week_or_date $1` `formed_args $@|sed 's/\//_/g'` } launchd_path() { echo -n $HOME/Library/LaunchAgents/`plist_fname $@`.plist } plist_Label() { echo -n $IDENTIFIER-`week_or_date $1` `formed_args $@` } plist_StartCalendarInterval_week() { hh=`echo $2|sed s/://|xargs printf %04s|cut -c 1-2` mm=`echo $2|sed s/://|xargs printf %04s|cut -c 3-4` for w in `weekdays $1` do echo "<dict><key>Hour</key><integer>$hh</integer><key>Minute</key><integer>$mm</integer><key>Weekday</key><integer>$w</integer></dict> " done } plist_StartCalendarInterval_date() { m=`echo $1|cut -d/ -f1` d=`echo $1|cut -d/ -f2` hh=`echo $2|sed s/://|xargs printf %04s|cut -c 1-2` mm=`echo $2|sed s/://|xargs printf %04s|cut -c 3-4` echo "<dict><key>Month</key><integer>$m</integer><key>Day</key><integer>$d</integer><key>Hour</key><integer>$hh</integer><key>Minute</key><integer>$mm</integer></dict> " } plist_StartCalendarInterval() { echo $1|grep -q / || plist_StartCalendarInterval_week $@ echo $1|grep -q / && plist_StartCalendarInterval_date $@ } plist_ProgramArguments_week() { shift 2 echo "$@; /usr/local/bin/timer-sync-wake;" } plist_ProgramArguments_date() { launchd_plist=`launchd_path $@` launchd_label=`plist_Label $@` shift 2 echo "$@; rm -f '$launchd_plist'; /usr/local/bin/timer-sync-wake; launchctl remove '$launchd_label'" } plist_ProgramArguments() { echo $1|grep -q / || plist_ProgramArguments_week $@ echo $1|grep -q / && plist_ProgramArguments_date $@ } list_launchd() { echo ======== launchd list >&2 launchd_plist_paths=`ls $HOME/Library/LaunchAgents/$IDENTIFIER* 2>/dev/null` status=$? local IFS=$'\n' for f in $launchd_plist_paths do echo -e `defaults read "${f%.plist}" Label|cut -d' ' -f2-|sed 's/ /\\\t/'`|expand done return $status } list_schedule() { echo ======== schedule list pmset -g sched } add_launchd() { echo ======== edit launchd_plist=`launchd_path $@` defaults write "${launchd_plist%.plist}" Label "`plist_Label $@`" defaults write "${launchd_plist%.plist}" ProgramArguments -array /usr/bin/caffeinate /bin/sh -c "`plist_ProgramArguments $@`" defaults write "${launchd_plist%.plist}" StartCalendarInterval -array `plist_StartCalendarInterval $@` launchctl load "$launchd_plist" echo -e `echo $@|sed 's/ / \\\t/'` } rm_launchd() { echo ======== delete launchd_plist=`launchd_path $@` launchctl unload "$launchd_plist" rm -f "$launchd_plist" echo -e `echo $@|sed 's/ / \\\t/'` } show_usage() { echo "Usage: $COMMAND [-li]" echo " $COMMAND [-de] mm/dd HHMM command; ..." echo " $COMMAND [-de] weeknum HHMM command; ..." echo " mm/dd : 02/01=2/1" echo " weeknum: 0=日 1=月 2=火 3=水 4=木 5=金 6=土 7=日" echo " 1-5 = 月から金まで" echo " 5-7 = 金土日" echo " 1,3,5 = 月水金" echo " HHMM : 0600=6:00" echo "Example:" echo " $COMMAND -e 02/01 1700 /usr/local/bin/rec_radiko.sh -o radikoru/ -t 3600 FMJ" echo " $COMMAND -d 02/01 1700 /usr/local/bin/rec_radiko.sh -o radikoru/ -t 3600 FMJ" echo " $COMMAND -e 0 1700 /usr/local/bin/rec_radiko.sh -o radikoru/ -t 3600 FMJ" echo " $COMMAND -e 1-5 0600 /usr/local/bin/rec_radiru.sh -o radikoru/ -t 1800 NHK-FM" } command_v() { osascript -e 'delay .5' -e 'tell application "System Events"' -e 'keystroke "v" using command down' -e 'end tell' } cd `dirname $0` COMMAND=`basename $0` # 引数解析 while getopts deli OPTION do case $OPTION in d ) OPTION_d="TRUE" ; VALUE_d="$OPTARG" ;; e ) OPTION_e="TRUE" ; VALUE_e="$OPTARG" ;; l ) OPTION_l="TRUE" ;; i ) OPTION_i="TRUE" ;; * ) show_usage ; exit 1 ;; esac done shift $(($OPTIND - 1)) #残りの非オプションな引数のみが、$@に設定される if [ $# = 0 -a "$OPTION_l" != "TRUE" -a "$OPTION_i" != "TRUE" ]; then show_usage ; exit 1 fi if [ $OPTIND = 1 ]; then echo Needs option!! ; show_usage ; exit 1 fi # オプション処理 if [ "$OPTION_d" = "TRUE" ]; then rm_launchd $@ ./timer-sync-wake list_launchd list_schedule fi if [ "$OPTION_e" = "TRUE" ]; then add_launchd $@ ./timer-sync-wake list_launchd list_schedule fi if [ "$OPTION_l" = "TRUE" ]; then list_launchd list_schedule fi if [ "$OPTION_i" = "TRUE" ]; then list_launchd &>/dev/null || exit 1 list_launchd 2>/dev/null|nl -s': ' read -p 'Select Number :' NUM echo -n $NUM|grep -q '[0-9]\{1,\}' || exit 1 [ $NUM -gt `list_launchd 2>/dev/null|wc -l` ] && exit 1 command_args=`list_launchd 2>/dev/null|head -$NUM|tail -1|sed 's/ \{2,\}/ /'` read -p '[c]opy [d]elete :' ACTION case $ACTION in c) echo -en "$0 -e $command_args"|pbcopy command_v & ;; d) rm_launchd $command_args ./timer-sync-wake list_launchd list_schedule ;; *) exit 1;; esac fi
スリープ解除を連携させるtimer-sync-wakeコマンド
- 設定したlaunchd.plistは、pmset scheduleと連携させることで、予約した時刻にスリープが解除され、指定したコマンドが実行される仕組み。
- 繰り返し設定ができないpmset scheduleを、毎週繰り返しのlaunchd.plistと連携させるため、launchd.plistに設定した処理の最後で、次週のpmset scheduleを設定している。
- そのlaunchd.plistとpmset scheduleの設定を同期させる仕事をするのが、このtimer-sync-wakeコマンドである。
- timerコマンドで指定された曜日指定の予約処理は、launchd.plistに変換される際に、その最後に必ずこのtimer-sync-wakeコマンドが付加される。
- timer-sync-wakeコマンドによって、次に必要なpmset scheduleが設定され、次週の予約日時のスリープ解除に備えるのである。
- 以上の処理は、timerコマンドで予約した時に自動的に設定されるので、ユーザー自らがtimer-sync-wakeコマンドを実行する必要性はないのである。
#!/bin/sh IDENTIFIER=com.bebekoubou.timer pmdate_from_w_hhmm() { w=`expr $1 % 7` hh=`echo $2|sed s/://|xargs printf %04s|cut -c 1-2` mm=`echo $2|sed s/://|xargs printf %04s|cut -c 3-4` current_date=`date +%s` preset_date=`date -v${w}w -v${hh}H -v${mm}M -v0S +%s` n=`expr $current_date / $preset_date` date -v${w}w -v+${n}w -v${hh}H -v${mm}M -v0S -v-30S "+%m/%d/%y %H:%M:%S" } pmdate_from_md_hhmm() { m=`echo $1|cut -d/ -f1` d=`echo $1|cut -d/ -f2` hh=`echo $2|sed s/://|xargs printf %04s|cut -c 1-2` mm=`echo $2|sed s/://|xargs printf %04s|cut -c 3-4` current_date=`date +%s` preset_date=`date -v${m}m -v${d}d -v${hh}H -v${mm}M -v0S +%s` n=`expr $current_date / $preset_date` date -v+${n}y -v${m}m -v${d}d -v${hh}H -v${mm}M -v0S -v-30S "+%m/%d/%y %H:%M:%S" } add_schedule() { pmset -g sched|grep -q "wake at $1" || ./timer-add-schedule "$1" } rm_schedule() { pmset -g sched|grep -q "wake at $1" && ./timer-rm-schedule "$1" } weekdays() { safe_chars=`echo $1|sed 's/[^0-9,-\/]//g'` bash_format=`echo $safe_chars|sed 's/\(.-.\)/{\1}/g'|sed 's/-/../g'|tr ',' ' '` bash -c "echo $bash_format"|tr ' ' '\n'|sort -u } echo ======== sync-wake cd `dirname $0` _IFS="$IFS"; IFS=$'\n'; # launchd.plistを見て、不足するscheduleを追加する launchd_plist_paths="`ls $HOME/Library/LaunchAgents/$IDENTIFIER* 2>/dev/null`" for f in $launchd_plist_paths do args=`defaults read "${f%.plist}" Label` word=`echo $args|cut -d' ' -f2` hhmm=`echo $args|cut -d' ' -f3` for wd in `weekdays $word` do if `echo $wd|grep -q /`; then pmdate=`pmdate_from_md_hhmm $wd $hhmm` else pmdate=`pmdate_from_w_hhmm $wd $hhmm` fi add_schedule "$pmdate" launchd_pmdate_list+="${pmdate}\n" done done # launchd.plistに存在しない、余分なscheduleを削除する schedule_wake_list=`pmset -g sched|grep '^\W\['|grep 'wake at'|cut -d' ' -f6-7` for s in $schedule_wake_list do echo $launchd_pmdate_list|grep -q "$s" || rm_schedule "$s" done IFS="$_IFS"
その日限りの単発予約にする方法
- 今度は逆に日付指定の繰り返さない予約も設定しなくてはならない。
- launchdのStartCalendarIntervalは一旦設定がloadされると、その設定がある限り、永遠に繰り返す。
- 例えば2月3日を設定しておくと、それは毎年繰り返されることになる。
- その繰り返しを止めるために、予約処理の最後でunloadして、不要になったlaunchd.plistを削除しようとした。
- ところが、launchd.plistによって起動された処理Aの中で、そのlaunchd.plistをunloadしてしまうと、unloadした瞬間にその処理Aも中止されてしまうようなのだ。
- その後に続くlaunchd.plistの削除の処理が実行されず、ずっと残ったままになってしまう...。
- 一方、unloadするためには、その設定ファイルであるlaunchd.plistが必要である。先に削除してしまうとunloadもできなくなる。
- それなら削除するlaunchd.plistとは無関係の、定期的に監視して削除する処理Bを追加するしかないか...と悩んでいたら、launcdctlの中にremoveがあることに気付いた!
- removeなら、稼働中のジョブをLabel指定で削除できる。先にlaunchd.plistを削除してしまってもOK。
timer -e 02/03 1700 /usr/local/bin/rec_radiko.sh -t 3600 FMJ
- 例えば、2/3の1700のタイマー予約をすると、以下のようなlaunchd.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.bebekoubou.timer-date 02/03 1700 /usr/local/bin/rec_radiko.sh -t 3600 FMJ</string> <key>ProgramArguments</key> <array> <string>/usr/bin/caffeinate</string> <string>/bin/sh</string> <string>-c</string> <string>/usr/local/bin/rec_radiko.sh -t 3600 FMJ; rm -f '/Users/zari/Library/LaunchAgents/com.bebekoubou.timer-date 02_03 1700 _usr_local_bin_rec_radiko.sh -t 3600 FMJ.plist'; /usr/local/bin/timer-sync-wake; launchctl remove 'com.bebekoubou.timer-date 02/03 1700 /usr/local/bin/rec_radiko.sh -t 3600 FMJ'</string> </array> <key>StartCalendarInterval</key> <array> <dict> <key>Day</key> <integer>3</integer> <key>Hour</key> <integer>17</integer> <key>Minute</key> <integer>0</integer> <key>Month</key> <integer>2</integer> </dict> </array> </dict> </plist>
これでひとまず、予約した時刻になったら、ちゃんとスリープを解除して、コマンドを実行するtimerコマンドの出来上がり!
rec_radikoru.shコマンド
- radikoとらじる★らじるで二つのシェルスクリプトを使い分けるのは面倒だ。
- いつかNHK-FMをrec_radiko.shで選局してしまって、あとで録音できていなくて、ガッカリすること必至。
- radikoとらじる★らじるを賢く使い分けるrec_radikoru.shというラッパースクリプトを作ることにした。
- ついでに、その地域で視聴可能なラジオ局の一覧も表示する機能が欲しい。よって、こんなコードになった。
#!/bin/bash cd `dirname $0` while getopts l OPTION do case $OPTION in l ) OPTION_l="TRUE" ;; esac done if [ "$OPTION_l" = "TRUE" ]; then areaid=`/usr/local/bin/rec_radiko.sh -a|tail -1|cut -d, -f1` station_names=`echo ---- NAME ----,NHK-R1,NHK-R2,NHK-FM,` station_names+=`curl -s http://radiko.jp/v2/station/list/$areaid.xml|xpath //name 2>/dev/null|sed -e 's/<name>//g' -e 's/<\\/name>/,/g'` station_ids=`echo ---- ID ----,NHK-R1,NHK-R2,NHK-FM,` station_ids+=`curl -s http://radiko.jp/v2/station/list/$areaid.xml|xpath //id 2>/dev/null|sed -e 's/<id>//g' -e 's/<\/id>/,/g'` paste <(echo $station_ids|tr ',' '\n') <(echo $station_names|tr ',' '\n')|expand -t 16 exit 0 fi echo $@|grep 'NHK-\(R1\|R2\|FM\)$' && ./rec_radiru.sh $@ echo $@|grep 'NHK-\(R1\|R2\|FM\)$' || ./rec_radiko.sh $@
- ラジオ局の一覧は-lオプションを指定するのだ。
$ rec_radikoru.sh -l ---- ID ---- ---- NAME ---- NHK-R1 NHK-R1 NHK-R2 NHK-R2 NHK-FM NHK-FM TBS TBSラジオ QRR 文化放送 LFR ニッポン放送 RN1 ラジオNIKKEI第1 RN2 ラジオNIKKEI第2 INT InterFM FMT TOKYO FM FMJ J-WAVE JORF ラジオ日本 BAYFM78 bayfm78 NACK5 NACK5 YFM FMヨコハマ HOUSOU-DAIGAKU 放送大学
ダウンロードとインストール
開発&利用環境
- OSX10.8.2
- bash -version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12) Copyright (C) 2007 Free Software Foundation, Inc.
timerコマンド
- timer0.1.zipをダウンロードする。
- 解凍したら、install.shを実行する。
- デフォルトは、/usr/local/binにインストールされる。
- 引数でパスを指定すると、指定したディレクトリにインストールされる。
radikoやらじる★らじるを録音する場合
- radikoru0.1.zipもダウンロードする。
- 解凍したら、install.shを実行する。
- デフォルトは、/usr/local/binにインストールされる。
- 引数でパスを指定すると、指定したディレクトリにインストールされる。
- Xcodeをインストールして、Preferences... >> Downloads >> Components >> Command Line Tools をインストールしておく。
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" $ brew install wget $ brew install swftools $ brew install rtmpdump $ brew install ffmpeg
- さらに、rtmpdump2.4(バイナリ版)もダウンロードして、インストール。
使い方
以下、すべてのスクリプトを/usr/local/binにインストールして、/usr/local/binがコマンドサーチパスになっているbash環境。
$ timer -e 02/10 1700 /usr/local/bin/rec_radikoru.sh -o radikoru/ -t 3600 NHK-FM $ timer -e 0 1700 /usr/local/bin/rec_radikoru.sh -o radikoru/ -t 3600 FMJ
- 現在の予約リストを表示する。(-l=リストのL)
$ timer -l ======== launchd list 02/10 1700 /usr/local/bin/rec_radikoru.sh -o radikoru/ -t 3600 NHK-FM 0 1700 /usr/local/bin/rec_radikoru.sh -o radikoru/ -t 3600 FMJ ======== schedule list Repeating power events: wakepoweron at 0:00AM every day Scheduled power events: [0] wake at 02/10/13 16:59:30
- 対話モード(-i=インタラクティブのi)
- 対象のタイマー予約を番号で指定して、
- (c)コピーか、(d)削除を、選択する。
$ timer -i 1: 02/10 1700 /usr/local/bin/rec_radikoru.sh -o radikoru/ -t 3600 NHK-FM 2: 0 1700 /usr/local/bin/rec_radikoru.sh -o radikoru/ -t 3600 FMJ Select Number :1 [c]opy [d]elete :
- 既存のタイマー予約を修正する場合は...
- (c)コピーして修正し、
- その後、古いタイマー予約を(d)削除するのだ。
例
timer -e 0 1700 /usr/local/bin/rec_radikoru.sh -o radikoru/ -t 3600 FMJ
- 毎週日曜の17:00からJ-WAVEを1時間録音する。
timer -e 1-5 0515 open -a iTunes /Users/zari/Music/iTunes/iTunes\ Music/Unknown\ Artist/Unknown\ Album/J-WAVE_20130203-1701.m4a
timer -e 1-5 0515 afplay -v 200 -t 300 /Users/zari/Music/iTunes/iTunes\ Music/Unknown\ Artist/Unknown\ Album/J-WAVE_20130203-1701.m4a
- 毎週月曜から金曜の朝5時15分に、afplayコマンドで、録音したサウジ・サウダージを目覚まし代わりに再生する。
- ボリューム:200、再生時間:300秒=5分。
timer -e 1-5 0515 osascript -e 'tell application "iTunes"' -e 'set sound volume to 100' -e 'play playlist "トップレート"' -e 'delay 60' -e 'stop' -e 'end tell'
- 毎週月曜から金曜の朝5時15分に、AppleScriptでiTunesのトップレートを選択して、目覚まし代わりに再生する。
- ボリューム:iTunesボリューム=100(システムサウンドは未設定なので既存の設定に影響される)、再生時間:60秒
- iTunesでシャッフルの設定をしておけば、毎朝違う音楽が聴ける。
timer -e 1-5 0515 osascript /Users/zari/Library/Scripts/timer_sample.scpt
- さらに長いAppleScriptコードであれば、ファイルに保存しておき、それをtimer起動時に実行することもできる。
- AppleScriptを実行できるということは、たいていのことはtimerコマンドから実行できるのだ。
*1:StationTVなどのTV視聴専用のアプリケーションなら、予約録画はスリープ解除と連動して実行される。それと同じことをTVの録画に限らず、一般的な処理すべてにおいて予約日時に実行できるようにしたいのだ。