Mac OS Xで時間帯ごとに壁紙を変えたい

# やりたいこと
プログラミングに集中していると「気づいたら夜に！」みたいなことがあったので、壁紙が時間帯ごとに勝手に変わるようにしてみました。

ちょうどよいアプリがなかった＆自分でネイティブアプリを作るのはスキル的に厳しいので、今回はシェルスクリプト＆cronでやりました。
注意：当方シェルスクリプトやcron、osascriptの理解が浅いため、利用する場合は自己責任でお願いします:bow:

# 動作確認環境など
- OS: Mac OS X EL Capitan ver.10.11.6
- Terminal: iTerm2 Build 3.1.5
- osascriptコマンド
- crontabコマンド
- OS標準のログイン時自動実行機能

# 手順
## 1. 壁紙にしたい画像を用意しておく
保存場所はどこでもよいが、ピクチャフォルダがよいと思います。

今回は以下の場所に保存しました。
`~/Pictures/wallpaper/`

ファイル名
- wp_daytime.jpg -> 日中に表示する画像
- wp_evening.jpg -> 夕方に表示する画像
- wp_night.jpg -> 夜に表示する画像

## 2. 時間帯によって壁紙を変えるシェルスクリプトを作る
ターミナルを起動して、以下の手順でシェルスクリプトを作成。
ターミナルは一応iTerm2を使いましたが、なんでもいいと思います。

```shell
# 作業用フォルダに移動（なければmkdirコマンドで作る)
$ cd ~/work/scripts
# シェルスクリプトを新規作成(.shだと起動時に自動実行できなかったので.command)
$ vim set_wallpaper_by_time.command
```

set_wallpaper_by_time.commandの内容

```shell
#!/bin/bash

function usage() {
cat <<_EOT_
Usage:
  $0 [OPTION]...

Description:
  set wallpaper by time.

Options:
  -h,--help       display help
  --skip-waiting  skip waiting for connection to multi monitor

_EOT_
exit 
}

# オプション処理
for arg in "$@"; do
  shift
  case "$arg" in
    --help)  set -- "$@" "-h" ;;
    --skip-waiting)   skip_waiting=1   ;;
    *) set -- "$@" "$arg" ;;
  esac
done

while getopts hl: opts
do
  case $opts in
    h) usage ;;
    \?)
      echo illegal option -- $OPTARG >&
      usage ;;
  esac
done

# 起動してすぐに実行するとマルチモニタ側の壁紙が変わらなかったので少し待つ
if [[ ! $skip_waiting ]]; then
  echo "Waiting for connection to multi monitor to be completed..."
  sleep 60s
fi

# メイン処理
echo "Start setting wallpaper"
current_time=`date +%H%M`

if [ "$current_time" -ge 700 -a "$current_time" -lt 1700 ]; then
  osascript -e 'tell application "System Events" to set picture of every desktop to "~/Pictures/wallpaper/wp_daytime.jpg"'
elif [ "$current_time" -ge 1700 -a "$current_time" -lt 1800 ]; then
  osascript -e 'tell application "System Events" to set picture of every desktop to "~/Pictures/wallpaper/wp_evening.jpg"'
else
  osascript -e 'tell application "System Events" to set picture of every desktop to "~/Pictures/wallpaper/wp_night.jpg"'
fi

echo Done.
exit 0
```

ターミナルに戻って、以下のコマンドで動作確認ができます。

```shell
$ ~/work/scripts/set_wallpaper_by_time.command
```

### 3.毎時自動で実行する
cronを使って毎時自動で実行するように設定をします。
設定にはcrontabコマンドを使います。

```shell
# 実行権限を付与
$ chmod +x set_wallpaper_by_time.command
# 付与できたか確認
$ ls -l set_wallpaper_by_time.command
-rwxr-xr-x  1 username  usergroup  154 12 22 10:37 set_wallpaper_by_time.command

# エディタを指定してからcron jobの設定を編集
$ export EDITOR=vim
$ crontab -e
# open vim
```

以下の内容を追記します。

```shell
# usage
# min hour day month weekday script

# change wallpaper hourly (without mail)
0 * * * * ~/work/scripts/set_wallpaper_by_time.command --skip-waiting 1> /dev/null

# every 30 minutes (without mail)
# */30 * * * * ~/work/scripts/set_wallpaper_by_time.command --skip-waiting 1> /dev/null
```

## 4.起動時にも実行する
1. [システム環境設定] -> [ユーザとグループ] -> [ログイン項目] を開く
2. [+]ボタンを押して、先程作ったCommandファイルを選択
3. 一覧に追加されるのでチェックをして完了

# 問題点
- 全画面でアプリを表示しているモニタは壁紙が変わらない。
- マルチデスクトップで表示しているモニタは、アクティブなデスクトップ以外の壁紙が変わらない。
- 自分の環境でしか動作確認していない。

# ハマったところ
## 1. マルチモニタ環境ときにメインモニタしか壁紙が変更されない。
```
osascript -e 'tell application "Finder" to set desktop picture to POSIX file "/Library/Desktop Pictures/Aqua Blue.jpg"'
```

のようなやり方で壁紙を変更ように書いてある記事が多かったが、これだとメインモニタしか壁紙が変更されませんでした。

```
osascript -e 'tell application "System Events" to set picture of every desktop to "~/Pictures/desktop-pc-5120x2880-wallpaper_00074.jpg"'
```
にすることで解決しました。

## 2. *.shだとOS起動時に実行してくれない
*.shだと起動時にエディタで開かれてしまった。
*.command に修正したら実行されました。

# あとがき
壁紙を変えるだけで結構大層な作業になってしまいしたが、シェルスクリプトやcronの勉強目的でやってみました。
問題点や誤字脱字の指摘は大歓迎です。また、これを使えば実現できるor簡単に作れるなどあれば教えてください:pray:

# 参考
[How do I change desktop background with a terminal command? - StackExchange](https://apple.stackexchange.com/questions/40644/how-do-i-change-desktop-background-with-a-terminal-command)
[Macでcron。 - Developers.IO](https://dev.classmethod.jp/etc/mac_de_cron/)
[Macでログイン時にスクリプトを実行する(Automator不使用) - Qiita](https://qiita.com/flashingwind/items/0cdcefc5aa4f0acb35f8)
[bashコーディング規約 - Qiita](https://qiita.com/mashumashu/items/f5b5ff62fef8af0859c5)
[シェルスクリプト(bash)のif文とtestコマンド([])自分メモ](https://qiita.com/toshihirock/items/461da0f60f975f6acb10)