2012/07/22

カスタムクエリで番組予約、REST-APIでクエリ実行

Redmineはチケットを様々なフィルタリング条件で検索が出来る。
そして、それをカスタムクエリとして保存することが出来る。
カスタムクエリごとに、一覧に表示したいフィールドも設定できる。

既に番組検索で、以下の様なカスタムクエリを作って活用している
  • カテゴリごとのチケット一覧。映画とかスポーツとか。
  • ゴールデンタイムの70分以上の番組。(スペシャル番組かな)
  • 宇宙や科学に関する番組一覧(趣味です)
  • 予約チケット一覧(ここではjob_idも表示するようにしている)
  • 録画チケット一覧
こんな風に自分条件のクエリをどんどん作って利用していける。

カスタムフィールドの開始時間を文字列じゃなく数値タイプにしているために
0時10分とかだと、「10」って表示されて分かりにくいが、
クエリで数値フィルタが使えるようにするために敢えて数値タイプにしている。
出来れば、「00:10」って表示されて欲しいけどね。いずれ解決できるかな。

毎週予約
wavecastでも毎日とか毎週とかの設定は出来る。そのとおり実行はしてくれるけど、題目が毎週変わるとか、今週は休みとか、時間がちょっとずれてるとかには対応できていない。
epgrecでは条件設定が出来て、条件に合うものが、その都度予約されて便利だった。

スペシャル番組
特に毎週予約よりも重要なのがスペシャル番組だ。毎年恒例のスペシャルとか録り逃すことがあると(特に「はじめて○おつかい」とか)、カミさんに怒られる。あ~あ・・あ~あって。
そういうものには、キーワード予約が大活躍なはず!

これからオリンピック
番組表を眺めながら探すのは結構苦労するだろう。
そんな時にも、様々な条件設定をしたクエリを作っておいて、合致した番組を自動的に予約設定する仕組みにしておけば楽ちんだ。

予約クエリは公開クエリ
カスタムクエリには、公開と非公開というタイプがある。一般クエリは非公開、予約クエリは公開に設定して区別することにする。他に簡単に区別できる属性がなかっただけだけど。

ここまで引っ張る話でもなかったけど、勢いで書いてしまいました。

後はスクリプトでどうにかするんだけど・・・

外部スクリプトからどうやってクエリすればいいんだろ?
クエリレコードを完全に理解してActiveRecordで頑張る?ちょっと調べてみたけど複雑でかなり無理がありそう。

REST-APIでクエリ実行
いわゆるWEB-APIと言われるやつですね。Redmine独自の動作をさせるには、こういった方法が手っ取り早そうなので、使うことにしました。
GETだけではなく、POSTでチケット作ったり更新したり出来るらしいけれど、あまり具体的な情報がないので、いじり倒すのはまた今度の機会に。

RESTによるWebサービスを有効にする
Redmineが外からのWebAPIを受け付けるように、「管理」の「認証」ページで有効にしておく。

ユーザのAPIアクセスキー
外部アクセスするユーザのAPIアクセスキーが必要なので、作っておく。作り方は簡単。
ユーザの個人設定のサイドバーにAPIアクセスキーってところでリセットと表示が出来る。
表示して内容をスクリプトにコピペして使用する。
まだこのRedmine上に一般ユーザを作ってないので「admin」のAPIキーを使っている。

rest-client
これを利用すれば、rubyから簡単にRESTアクセスが出来るようになる。
インストール
$ sudo gem install rest-client
rubyで使うときは、
require 'rest_client'
RestClient.get "URL"
で結果を受けっ取れる。
URLは、REST-APIコマンドとAPIキー設定が必要。今回はこれだけ知っていれば使える。

自動予約スクリプト
いつものように、ActiveRecordを使ってQueryから公開クエリを検索して、REST-APIでクエリ実行して、結果をハッシュに変換して、ヒットしたチケットIDをリストする。そのチケットIDリストから検索されたチケットのトラッカーを「予約」に変更して保存する。

query.rb (ファイル名が安易だ)
#!/usr/bin/ruby
# -*- coding: utf-8 -*-

require 'rubygems'
require 'active_record'
require 'rest_client'

key = 'redmineで作ったAPIキーをここに'

# 特定のクエリ実行するAPI
api = "http://localhost/projects/%s/issues.xml?key="+key+"&query_id="

ActiveRecord::Base.establish_connection(
 :adapter => 'mysql2',
 :host => 'localhost',
 :username => 'redmine',
 :password => 'redmine',
 :database => 'redmine'
)

class Issue < ActiveRecord::Base
end

class Query < ActiveRecord::Base
end

class Project < ActiveRecord::Base
end

# project識別名を合成
api = api % Project.first(1)[0].identifier.to_s

# 予約クエリー検索
reserve = []
queries = Query.find :all, :conditions => { :project_id =>1, :is_public =>1 }
queries.each {|query|
  # REST-APIでクエリー実行
  result = Hash.from_xml( RestClient.get api+query.id.to_s )['issues']
  result.each {|i|
    if i['tracker'] ['id'].to_i == 1
      reserve << i['id'].to_i
    end
  }
}

Issue.find(reserve).each {|issue|
  issue.tracker_id = 2
  issue.save
  puts "ID:%d [%s]" % [issue.id, issue.subject]
}
プロジェクト識別名も決まってるから直に書いても良かったんだけれど、IDから検索して識別名を取得している。いずれハードコードなところを直していく時の覚書みたいなもの。

最初簡単だろうと思ってたけど、結構試行錯誤した。そして更に問題が増えた。

チューナ1つであることを考慮してないんで、こんな自動化だと重なった時には録画失敗する。
オリンピック番組は題名だけじゃなくて内容も検索条件に入れないと絞り込めないだろうね。
普通の操作ではチケット内容部分は検索条件に入れられないのだ。どうしようかな。

この辺の現実的問題と肝心の視聴部分が、いよいよとなって参りました。
どうしようかな・・・

0 件のコメント:

コメントを投稿