Androidの動画プレイヤーですけど。
https://play.google.com/store/apps/details?id=com.mxtech.videoplayer.pro
自分がエンコードしてるファイルHTTP越しに問題なく再生できるし最高だったので広告なし版を買いました。
といってもNexus7購入でもらった2000円クーポンで。
便利です。
Androidの動画プレイヤーですけど。
https://play.google.com/store/apps/details?id=com.mxtech.videoplayer.pro
自分がエンコードしてるファイルHTTP越しに問題なく再生できるし最高だったので広告なし版を買いました。
といってもNexus7購入でもらった2000円クーポンで。
便利です。
スクリーンショットやギャラリーの画像を簡単にGyazoにアップロードしてURLをシェアできるAndroidアプリをつくりました。
超便利なのでダウンロードとくわしくはこちらのREADMEをどうぞ。
https://github.com/xtuaok/android_share_gyazo
髪を斬ったのだが、美容師に望むのはひとつ、今日の予定を聞くというマニュアル会話はやめて欲しい。
今日は台風だしできる会話はこんなだ。
美容師「今日、このあと予定とかあるんっスか?」
俺「川の様子を見に行く」
TVRockを動かしていたマシンがどうもよく再起動するしもうTVRock使いたくないからとレコーダーを作っていたのだ
けれど、だいぶ軌道にのってきたのでレコーダー専用にマシンを作ることにした。
自作するのもう学生以来かと思う。
アイオーエススィックス!
Ruby の Process::spawn で返ってくる pid でハマったので、後世にこのことを残してから死のうと思いました。
レコーダーネタまだ一杯ある。
というわけで、予約を登録して、実行まで待機して、実行するまでの流れについて。
予約はTwitterで「うぽって録画して」みたいにつぶやくだけである。
中はどうなってるかというと Programs テーブルから要求された単語を検索して、見つかったら Reserves テーブルに追加する。
word = "うぽって" descs = Groonga['Programs'].select do |record| (record.description =~ word) & (record.stop > Time.now) end titles = Groonga['Programs'].select do |record| target = record.match_target do |match_record| match_record.title * 5 end (target =~ word) & (record.stop > Time.now) end programs = descs.union!(titles).sort([ {:key => "_score", :order => "descending" }, 'start', { :key => 'channel.type', :order => "descending" } ]) programs.each do |program| unless Groonga['Reserves'].has_key?(program._key) reserve = Groonga['Reserves'].add(program._key, {} ) reserve.title = program.title reserve.start = program.start # 省略 break else # 予約済み end end
ほんとは一連の流れを排他で処理しなきゃならないけどそれはまた今度。まぁこんな感じ。
検索のスコアリングは好き好きあるだろうけどこの例だとタイトルでのヒットは番組詳細に対して5倍のスコアで算出するようにしてる。
予約から実行までの流れをざっくり考えてみる。もっとも単純なのはきっとこう。
でもどう考えてもこんな簡単なのではだめで、予約は任意のタイミングで追加されるし、その都度待機時間を調整しなくてはならない。
それを考慮すると、方法は2つ浮かんできて、
ようするにパッシブかアクティブかのどちらか。
予約リストの監視をするにはおそらく 短時間 sleep を挟んだ無限ループで行うことになるが、これはどうもスマートではないし、十分なマージンをとって録画を開始しなきゃならない。(まぁどのみちマージンはあったほうがいいのだが)
では、通知を受け取る方法はどうやるのか。
inotify を使うとかもあるけど、簡単なIPCは名前付きパイプでできるし、pipe のIOをselectで待ってれば、タイムアウト付きで待機できる。
次の録画開始までの待機時間をタイムアウトに設定すればうまいことやれそうである。
実際のコードはこんな感じ
シェルで名前付きパイプをつくっとく
$ mkfifo -m 600 var/run/recorder
Ruby のコード
REC_MERGIN = 10 # 10秒マージン IPC_PIPE = 'var/run/recorder' ipc = open(IPC_PIPE, "r") loop do reserve = Groonga['Reserves'].select do |r| (r.running == false) end.sort(['start']).first wait = reserve.start - Time.now + REC_MERGIN ret = IO::select([ipc], nil, nil, wait > 0 ? wait : 0.1) if ret ipc.gets puts "io event" end reserve = Groonga['Reserves'].select do |r| (r.running == false) end.sort(['start']).first if reserve and reserve.start <= Time.now + REC_MERGIN start_recording(reserve) end end
適当だけどこんな感じ。
別のスレッドやプロセスから "var/run/recorder" に対して "\n" を書けば select が起きて処理が進むし、でなければ次の録画開始時間まで待機する。
start_recording() は中で reserve.running = true にして 別スレッド生成。
案外簡単。
※ 他プロセスが絡まない待機なら timeout(sec) { Queue.pop } や observer なんかでもいいかもしれない。
あとは、待機時間が大変長い時に適当にEPG取得するような処理いれたり(いつ予約が入るかわからないからいつでも殺せるような仕組みで)したらよい。
注意しなきゃならないのは、外部プログラムで録画していると何が起こるかわからないのでちゃんと例外をキャッチして情報を得られるようにしておかないと後で辛い。
あとは例外でプロセスが死なないようにうまく retry したり。
録画開始から終了までの話はまた別エントリで。