AppleScriptでiTunesのテレビ番組を連続再生する
iTunes のテレビ番組を連続再生するには再生したいテレビ番組をプレイリストに登録してリピート再生するという方法がある。
しかし、毎度毎度プレイリストを作るのは大変なので AppleScript を使って自動で次のエピソードに移動するようにしてみる
仕組み
- Scriptを起動したら TV Show が再生されていないか20秒毎にチェックする
- 再生されていたらそのEpisode の合計時間と現在の再生位置から残りの再生時間を3分ごとに調べる
- 残りの再生時間が3分以下になったら1分ごとにチェック、1分以下になったら1秒ごとにチェック
- 残りの再生時間が1秒以下になったら次のEpisode に移動する
- 2にもどる
今回使った命令いろいろ
次のEpisode に移動
- これは他の種類のメディア(音楽とか)にも使えてキーボードについている送りキー[▶︎▶︎]と同じ機能を持つ
tell application "iTunes" next track end tell
再生中のトラックの合計時間を調べる
- 1:20:30(h:m:s) のように出力される
tell application "iTunes" set timeSize to time of current track as text end tell
再生中のトラックの再生済みの時間を調べる
- 秒で出力される
- 再生されていない時は
missing value
となる
tell application "iTunes" set nowPositionSec to player position end tell
コードは Gist にある
This applescript will automatically play the episode of the next iTunes TV show. · GitHub
- 右にある
Download ZIP
からダウンロードする - Script Editor で開いて
.app
形式で保存する - Spotlight から起動したり、iTunes Scriptフォルダに入れて iTunes からも起動できる
- iTunes Scriptフォルダは
~/Library/iTunes/Scripts
参考ページ
- 鳶嶋工房 / AppleScript / Tips / スクリプトの中断
- スクリプトの中断
- iTunes for Mac まとめ - AppleScript
- iTunes関連の命令について
- life log: AppleScript 最速基本文法マスター
- AppleScriptについて
- iTunes Scripts の使い方
- iTunes Scriptフォルダの場所
ありがとうございます
Raspberry Pi で家電を操作する1
目次
今回は長くなるので複数回に分ける
- Raspberry Pi で家電を操作する1 (MacにWebサーバを設置して照明を操作する)
- Raspberry Pi で家電を操作する2 (Raspberry PiにWebサーバを設置して照明を操作する)[未投稿]
やりたいこと
- 今回はブラウザから部屋の照明のスイッチをサーボモータで動かしon/offさせたい
- 最初は Mac で作ってからRaspberry Pi に移す
構成と環境
Raspberry Pi とArduino の通信はシリアル通信を使用した
Raspberry Pi から直接サーボを操れるようだが、慣れているので Arduino を使用した。そのうち変更するかもしれない
作業の軌跡
- Arduino でシリアルを受信してサーボを動かす
- Sinatra からシリアル信号を送る
- 時間差をつけてシリアル信号を送る
- Sinatra にタイマー機能をつける
- Raspberry Pi に移す
- IPを固定する
- ホスト名でリモート接続できるようにする
- 作成したSinatraアプリケーションをデーモンにする
Arduino でシリアルを受信してサーボを動かす
シリアル信号に応じてサーボを右もしくは左に少し回して照明などのスイッチをon/offする
スケッチは以下のような感じになった
- loop で常時シリアル信号を監視する
- 信号は数字になっていてそれぞれに対応したアクションを探す
- アクションが決定したら実行する
- サーボをデフォルトの位置に戻す
codeはgistにある
Arduino のコード
Sinatra からシリアル信号を送る
Sinatra でブラウザにon/offボタンを表示させ押せれたらシリアル信号を送るとようにしたい
Sinatra とは Ruby on Rails のような Ruby で Webサーバを立てるためのドメイン特化言語(DSL)です
Sinatra でシリアル通信を扱うためにはgemのserialportが必要なのでinstallする
gem install serialport
コードは以下のようになった
- 初期動作
- textで保存したシリアルポートの名前(環境によって異なる)を読み込む
- シリアルのインスタンスを作成
/
がリクエストされたらon/offボタンのあるhtmlを送る- スタンドライトのonのボタン
/standOn
が押されたらシリアルを送信し/
にリダイレクトする
嵌ったところ1 逆引きDNS
localhost:4567
でアクセルするとロードが100ms程度で終わるのに対しIPアドレスを直接指定すると1分以上かかってしまった
どうやらSinatra側がアクセスしてきたクライアントのIPアドレスをホスト名に変換するときに hosts が設定されていないとタイムアウトするまで時間がかかってしまうらしい (この解釈であってるかわからない)
DNS逆引きを止めるコードがネット上にあったので使わせてもらうことにした
sinatraでDNS逆引きを止める | TechRacho
嵌ったところ2 inline-block の隙間
今回 inline-block を使ったがリストタグ<ul>
内に改行があると改行が半角スペースとなって表示されるらしい
その影響で各ボタンの間に隙間ができてしまって結果的にレイアウトが崩れてしまった
CSS で inline-block の文字間を 0em にして inline-block中 のul
の文字間を xx-large とすることで解決した
一部を抜粋
ul{ list-style:none; font-size: 0em; /* inline-block 隙間対応*/ } li p, .on, .off, .timer{ padding: 30px 0px; margin: 0px; display: inline-block; font-size: xx-large; /* inline-block 隙間対応*/ color: #FFFFFF; }
rerun
余談だが今回始めてrerun
を使ってみた
rerun は関連するコードが更新されるとsinatraを再起動してくれる
sinatra-contrib
だとイマイチ動こかないことがあったが rerun はいい感じに再起動してくれる
gem install rerun
してrerun 'ruby app.rb'
する
Sinatra: Frequently Asked Questions
タイマー機能を作る
今回は簡単に指定時間 sleep させたあと任意のアクションのアドレス(例えばlocalhost:4567/standOn
)にアクセスするようにする
コードはこんな感じになった
require "open-uri" Hour = 3600 #Create mode print("Select Mode\n1. Stand Light On\n2. Stand Light Off\n3. Room Light On\n4. Room Light Off\n--> ") mode = gets.to_i case mode when 1 then mode = "standOn" when 2 then mode = "standOff" when 3 then mode = "roomOn" when 4 then mode = "roomOff" else print("Mode error\n") return 0 end print("Select #{mode}\n\n") #Create timelimit print("Select Time(hour)\n--> ") limit = gets.to_i print("Select #{limit}hour\n\n") #Wait print("Waiting #{limit}hour...") sleep(Hour * limit) print("\n\n") #Acsess open("http://localhost:4567/#{mode}").read print("Done\n")
Sinatra にタイマー機能をつける
上記のタイマだとターミナルからしか使えないのですこし面倒 しかもターミナルウインドウを閉じてしまうとプロセスも閉じてしまうので困ってしまう なので Sinatra と同じプロセスで動かして尚且つブラウザからも操作できるようにしてみる
コードはこんな感じになった
- '/'でタイマのボタン
T
(/timer/standOn)を押す - 2つめのパスに記したアクション(例えばstandOn)を引数に
/timer
が開く /timer/standOn
で時間を入力して時間とアクションをpostで送るapp.rb
がpostを受けて別スレッドでsleepさせておき本スレッドではすぐに/
にリダイレクトする- 別スレッドが時間になったら任意のアクションのアドレス(例えば
localhost:4567/standOn
) にアクセスする
このように直接時刻(6:30)を指定する方法と数時間後(4時間30分後)を指定する方法を用意した
雑感
- タイマの時間指定をするフォームで
input type="tell"
にするとiPhone等で数字入力するときにテンキーキーボードが出てくるのでカッコイイ - 将来的にはタイマボタン
T
で/timer/standOn
に画面遷移するのではなくon/offボタンの長押しで画面遷移したい - iosのブラウザで
input type="time"
を表示するとinputの親要素ごと上下に数ピクセルずれてしまったのでなんとかしたい - Mac や iPhone でアクセスできるとお布団から出なくても部屋の明かりをon,offできて寝る時に便利
- 照明のタイマー機能でやすやす起きれると思っていたら、布団に頭まで潜っているので意味がなかった(特に冬は)
コードはGithubとgistにある
- Sinatra のコード Coro365/home-control
- Arduino のコード It receives the serial signals to control the switches.
次回予告
次回は今回のコードを Raspberry Pi に移します
Raspberry Pi で家電を操作する2 (Raspberry PiにWebサーバを設置して照明を操作する)[未投稿]です
参考ページ
- Sinatraについての質問です Sinatraのサーバにlocalhost:4567で… - 人力検索はてな
- ありがとうございました
- sinatraでDNS逆引きを止める | TechRacho
- DNS逆引きキャンセル
- Ruby - rerunでSinatraのファイル変更時にリロード - Qiita
- rerunについて
- inline-blockを並べた場合に発生する「隙間」を消去するCSS » INSPIRE TECH
- inline-blockの隙間
ありがとうございます
Ruby で Pushbullet を使う
Pushbullet の API を使って各デバイスに通知を送ってみる
Pushbullet
Pushbullet はブラウザ又は Mac/Windows/iOS/Android のアプリからアクセスできて特定のデバイスにテキストや地図、ファイル等を送信できる。送信を受けたデバイスには通知センターに表示できる
今回はこれを使って Mac から任意のタイミングで iPhone にpush通知 を送るようにしたい
Gem インストール
Ruby で扱うための gem が公開されていたのでこれをインストール
gem install washbullet
自分のアクセストークンを Pushbullet の Setting から入手
32桁の文字列がアクセストークンになっている
アクセストークンを使って API から自分のid とデバイスのid を調べる
ターミナルで以下のコマンドを実行する
自分のid
curl -u Your_Token: https://api.pushbullet.com/v2/users/me
デバイスのid
curl -u Your_Token: https://api.pushbullet.com/v2/devices
JSON が帰ってる。 "iden":に続く文字列がidになる
取得したidで通知を送る
require 'washbullet' client = Washbullet::Client.new('Your_Token') client.push_note('Your_Device_Id', 'title', 'messege')
これを実行するとで送信された
id を Ruby から調べる
手動でidを読むのは面倒なのでアクセストークンを入力すると自動で自分のid と Pushbullet に登録されたデバイスのid を返すようにしてみた
require "json" def getUserId (token) api_response = `curl -s -u #{token}: https://api.pushbullet.com/v2/users/me` userId = JSON.parse(api_response) return userId["iden"] end def getDeviceId (token) api_response = `curl -s -u #{token}: https://api.pushbullet.com/v2/devices` deviceInfo = JSON.parse(api_response) deviceIds = Array.new deviceInfo["devices"].size.times do |i| deviceId = deviceInfo["devices"][i]["iden"] deviceName = deviceInfo["devices"][i]["nickname"] deviceModel = deviceInfo["devices"][i]["model"] deviceIds.push([deviceId, deviceName, deviceModel]) end return deviceIds end token = "Your_Token" p getUserId (token) p getDeviceId (token)
実行すると自分のidとデバイスid,デバイスのニックネーム,デバイスモデルが表示される
参考ページ
- Pushbullet API Documentation
- 公式ドキュメント
- hrysd/washbullet
- 今回使ったgem、お世話になります
- Ruby 1.9 以降で JSON を扱う - 見上げれば、空
- jsonの扱い方
ありがとうございます。
TerminalでAppleScriptを実行した時のlogコマンド挙動
追記 この情報は古くなりました。
- OS X 10.10 Yosimete ではtell application内のlogも表示されるようです
Ruby 経由でAppleScriptを実行する
test.rb
result = `osascript test.scpt`
test.scpt
on run {} funcA() end run on funcA() log "in funcA" funcB() funcC() end funcA on funcB() log "in funcB" end funcB on funcC() log "in funcC" tell application "Finder" log "in tell application Finder" tell application "Terminal" log "in tell application Terminal" end tell end tell end funcC
すると
結果
$ ruby test.rb in funcA in funcB in funcC
他のハンドラ内のlogコマンドを表示されるのに、tell application内では表示されなかった
そこで表示用のハンドラを作りtell application内から呼ぶことで解決した
test.rb
on run {} funcA() end run on funcA() log "in funcA" funcB() funcC() end funcA on funcB() log "in funcB" end funcB on funcC() log "in funcC" tell application "Finder" display("in tell application Finder") of me tell application "Terminal" display("in tell application Terminal") of me end tell end tell end funcC on display(message) log message end display
結果
$ ruby test.rb in funcA in funcB in funcC in tell application Finder in tell application Terminal