ラベル podcast の投稿を表示しています。 すべての投稿を表示
ラベル podcast の投稿を表示しています。 すべての投稿を表示

2012/07/29

録画ビデオのpodcast対応をredmineプラグインで

録画ビデオ視聴をredmineプラグインで出来るようにしたので、podcastも対応させる。
普通の録画ビデオフォーマットだとiPodTouch初代だと観れない問題を解決すべく、mpeg4フォーマットに更に変換したものをpodcastで観れるようにするというもので、
以前の記事でepgrecを対応させたが、便利だったのでredmineシステムでもやってみた。

前回は録画したものを何でもかんでもpodcastで出すようにしていたが、今回は録画が終了したものをredmine上で選択したものだけpodcastへ公開する形にした。

録画が正常終了したものはredmineステートで「完了」になるのだけど、新たに「公開」ステートを設けた。マニュアル操作で録画チケットを「公開」にしておくと、次の日にはpodcast上に出てくるという感じ。

そのステート監視と変換処理をするスクリプト
podcast.rb
#!/usr/bin/ruby
# -*- coding: utf-8 -*-
#
require 'rubygems'
require 'active_record'
require 'digest/md5'

@media_path = '/opt/videos/'

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

class Issue < ActiveRecord::Base
end
class CustomValues < ActiveRecord::Base
end
class Attachments < ActiveRecord::Base
end

def attach( desc, container_id, filename, type )
  if Attachments.first( :conditions => {
                          :container_id => container_id,
                          :digest => Digest::MD5.hexdigest(filename)
                        }).nil?
    Attachments.create( :container_id => container_id,
                        :container_type => "Issue",
                        :filename => filename,
                        :disk_filename => filename,
                        :filesize => File::stat( @media_path + filename ).size,
                        :content_type => type,
                        :digest => Digest::MD5.hexdigest(filename),
                        :author_id => 1,
                        :description => desc
                        )
  end
end

def start_date_time issue
  start_time = CustomValues.first( :conditions => {:customized_id=>issue.id, :custom_field_id=>1} )
  if start_time
    time = format("%04d", start_time.value.to_i)
    Time.parse(issue.start_date.strftime("%Y%m%d") + time)
  else
    Time.now
  end
end

# 公開ステータスの録画チケット
Issue.find( :all, :conditions => {:tracker_id => 3,:status_id => 6}).each {|issue|

  t_start = start_date_time issue
  filename = t_start.strftime("%Y%m%d%H%M")
  outfile = filename + '-p.mp4'

  if !FileTest.exists?( @media_path + outfile )
    # MPEG4
    if system '/opt/task/podcast.sh ' + @media_path + filename
      # アタッチ
      attach "MPEG4", issue.id, outfile, "video/m4v"
    end
  end
}
録画で公開ステータスになっているチケットを検索して、podcast用(mpeg4フォーマットのスモールバージョン)ビデオファイルが存在していなければ、作ってチケットにアタッチする処理。
ここでのポイント(微妙だけど・・)は、アタッチするファイルタイプを'video/mp4'ではなく、'video/m4v'にしたことかな。直接クリックして視聴できないんでタイプに意味はないけど、後でこれをキーワードにして検索したりするんで、他のアタッチファイルと区別できるようにしておく。

ipod-touch初代で観れるmpeg4ビデオを作成するシェルスクリプトはこちら
#!/bin/sh
OUT=$1
echo "OUTPUT  : $OUT"
ffmpeg -y -i ${OUT}.mp4 -threads 0 -s 480x272 -c:a copy -c:v mpeg4 -b:v 900k -qmin 3 -qmax 5 -f mp4 ${OUT}-p.mp4
この辺は前記事と変わりはないかな。ファイルの置き場所とかファイル名が違うくらい。

下回りはこんなでいいとして、podcastのGET部分をredmineのプラグインで簡単に組み込んでみた。この記事で書いたプラグインのビューとして作ってみた。

app/controllers/video_controller.rb に’podcast'関数を追加
  def podcast
    @issues = get_public_issues
    render :layout => false, :content_type => 'text/xml'
  end
  def get_public_issues
    Issue.find(:all, :conditions => {:tracker_id => 3, :status_id => 6}, :order => "start_date DESC")
  end

podcastはrss(xml)だ。xml出力をビューで処理したい。ということで、
render :layout => false; って書いておく。redmineのビューフォーマット全部をなしにしてくれる。

ビューの部分 app/views/video/podcast.html.erb を記述
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
  <channel>
    <title>公開ビデオ</title>
    <language>jp</language>
    <itunes:category text="録画">
      <itunes:category text="TV録画"/>
    </itunes:category>

    <% @issues.each do |issue|
       video = issue.attachments.detect {|a| a.content_type == "video/m4v"}

       if video
       channel = issue.custom_values.detect {|v| v.customized_id == issue.id and v.custom_field_id == 2 }
       pubdate = video.filename.sub(/\..*/,'')
       %>
    <item>
      <title><%= issue.subject %></title>
      <enclosure url="http://<%= request.host + path_to_video(video.disk_filename) %>" type="video/mp4"/\
>
      <pubDate><%= pubdate %></pubDate>
      <itunes:author><%= channel.value %></itunes:author>
      <itunes:summary><%= issue.description %></itunes:summary>
      <itunes:category><%= issue.category %></itunes:category>
      <itunes:duration><%= issue.estimated_hours %></itunes:duration>
    </item>
    <% end %>
    <% end %>

  </channel>
</rss>
Railsのviewsになっただけで、以前Smartyテンプレートで記述したのとほとんど同じ。前回は内部処理をPHPで記述していたが、今回はrubyだ。(今回はペースト成功した!)

config/routes.rb に忘れないように以下の1行を追加
get 'video/podcast',:to=>'video#podcast'                                                                       
iTunesからhttp://(redmine-home)/video/podcast をpodcast登録しておく。
前回悩んだguidタグだけど、記述しなくても大丈夫そうだったのでなしにした。

オリンピック録画中なので、あまり大きな変更修正で失敗しない程度の拡張でした。

2012/06/15

podcastで使い分け

wavecast購入後色々試行錯誤して、家で見るときはブラウザから観たり、iTunesに自動登録された方をiPad/AppleTVで観たり、出先ではiPodTouch(1st)に同期させて観たり、やりたかった事はだいたい出来たかな。

ただ、使いにくい事が1つある!

前記事にも書いたが、リビング用高画質版とモバイル用低画質版の2つを同じようにiTunesへ登録しているためにサムネイルも名前も同じようだから分かりにくい。選ぶときもどっちがどっちやら。

podcast使えないかな? と思い立った。
iTunesムービーは高画質版。podcastを低画質版って使い分ければいいんじゃ?
そうすればiPodTouchの同期設定もpodcastだけにすればいいし。
管理フォルダも別だからメンテもしやすそうだし。
ということで、やってみた。


podcast

については、podcastを制作するを参考に、お勉強。RSSなのね。というかXMLなのね。


プランとしては、podcast用のRSSを出力するスクリプトを用意してiTunesへ登録する。
最近はepgrecで録画するのが多くなって来たので、そっち側に構築。epgrecは、smartyを使っているので、そのまま活用させていただく。

/epgrec/podcast.php
<?php
include_once('config.php');
include_once( INSTALL_PATH . '/DBRecord.class.php' );
include_once( INSTALL_PATH . '/Smarty/Smarty.class.php' );
include_once( INSTALL_PATH . '/Settings.class.php' );

$host = "http://192.168.X.X";

$settings = Settings::factory();
$dbh = @mysql_connect( $settings->db_host, $settings->db_user, $settings->db_pass );

$rvs = DBRecord::createRecords(RESERVE_TBL, "WHERE complete='1' and mode>1");
$records = array();
foreach( $rvs as $r ) {
    $cat = new DBRecord(CATEGORY_TBL, "id", $r->category_id );
    $ch  = new DBRecord(CHANNEL_TBL,  "id", $r->channel_id );
    $arr = array();

    $r->title = str_replace('【デ】','',$r->title);
    $r->title = str_replace('【二】','',$r->title);
    $r->title = str_replace('【字】','',$r->title);

    $arr['title'] = $r->title;
    $arr['author'] = $ch->name;
    $arr['subtitle'] = "";
    $arr['description'] = $r->description;
    $arr['thumb'] = $host.$settings->install_url.$settings->thumbs."/".$r->path.".jpg";
    $arr['url'] = $host.$settings->install_url."/podcast/".$r->path;
    $arr['pubdate'] = $r->starttime;
    $arr['duration'] = strftime("%T",strtotime($r->endtime)-strtotime($r->starttime)-60*60*9);
    $arr['category'] = $cat->name_jp;
    array_push( $records, $arr );
}

$smarty = new Smarty();
$smarty->assign("site_title","録画一覧");
$smarty->assign("site_link",$host.$settings->install_url);
$smarty->assign( "records", $records );
$smarty->display("podcast.xml");
?>

/epgrec/templates/podcast.xml
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
  <channel>
    <title>{$site_title}</title>
    <language>jp</language>
    <itunes:category text="録画">
      <itunes:category text="TV録画"/>
    </itunes:category>

{foreach from=$records item=rec}
<item>
  <title>{$rec.title}</title>
  <itunes:author>{$rec.author}</itunes:author>
  <itunes:summary>{$rec.description}</itunes:summary>
  <enclosure url="{$rec.url}" type="video/mp4"/>
  <guid>{$rec.pubdate}</guid>
  <pubDate>{$rec.pubdate}</pubDate>
  <itunes:category>{$rec.category}</itunes:category>
  <itunes:duration>{$rec.duration}</itunes:duration>
</item>
{/foreach}

  </channel>
</rss>
を作成。(うまく入らないので、どちらも">","<"を全角にしてます

iTunesのpodcastに、http://192.168.?.?/epgrec/podcast.php で登録して出来上がり。家の中だけでいいので、LAN固定IPで問題なし。iTunesの方から勝手に吸い取ってくれるので自動登録フォルダにコピーするより、結果こっちの方が楽だね。

必要最小限のタグしか使ってない。もっと沢山あるみたいだけど、いらないかな。

今回はまったところは、2つ以上のアイテム(エピソード)が追加できなかったこと。最初の1つしかpodcastに出てこないのだ。エラーとかも出ないし・・悩んだよ。
結局、<guid>タグが必要だった事とその内容に日本語が入れられない事だった。
<pubdata>と同じ公開日(録画日)を入れる事にした。そうしたら出たよ。ふぅ。

Webプログラマじゃないんで知らない事だらけ。実際には色々試行錯誤があったけれど、やってみると簡単で面白い。知ってる人にすれば、この辺は既に古い話なんだろうね。実際ネット上を調べてみても数年前の情報がほとんど。今から追いつけるかなぁ。