2008年1月23日水曜日

Yahoo!Pipesその後

以前にYahoo!Pipesを試したと書いた(前編後編)が、TumblrのFeedのdescriptionが途中で切れているとか、twitterのtitleに自分のアカウント名が入っていてうざいとかあったので、それらのDataSourceとして「Fetch Feed」部品を使うのをやめる事にした。
  1. TumblrとTwitterのDataSourceを削除する。
  2. 「Fetch Data」部品を追加し、「URL」に"http://shin1o.tumblr.com/api/read"、「Path to item list」に"posts.post"を設定する。てっきりxpathかと思いきや、要素の階層の区切りは"/"ではなく"."なので注意。これがTumblr用のDataSource。
  3. もぅひとつ「Fetch Data」部品を追加し、「URL」に"http://twitter.com/statuses/user_timeline/shin1ogawa.xml"、「Path to item list」に"status"を設定する。
  4. で、このままだとそれぞれ全然違う構造(DTD)でデータが流れてしまい、Blogger達と統合できない。そこで、それぞれのDataSource部品から流れてくるデータの構造を変換する部品を一旦経由させることにする。
  5. 「Operators」カテゴリにある「Rename」部品を追加する。
  6. Tumblr用のDataSourceから、追加した「Rename」部品へPipeをつなぐ。
  7. 「Mappings」を「+」アイコンで追加しながら、以下の4種類のマッピングを行う。
    • "item.link-text"を"title"に。
    • "item.link-description"を"description"に。
    • "item.date"を"pubDate"に。
    • "item.url"を"link"に。
  8. Twitter用のRename部品も追加し、以下の4種類のマッピングを行う。
    • "item.text"を"title"に。
    • "item.test"を"description"に。
    • "item.created_at"を"pubDate"に。
    • "item.user.url"を"link"に。
  9. これでBlogger等他のFeed類と統合できるようになるので、両方をUnion部品に流し込む。
これらで目的が達成できるはず。。。と思いきや、日付の書式に問題があるようでSortが正しく動作しない!これをなんとか解決しようと部品を探したが、見つけることはできなかった。「Date」カテゴリに「Date Formatter」なる部品があるのだが、こいつに流し込む事ができないorそのやり方がわからない。 なので、下手に悩むよりもJSで操作した方がいいや!て事でHTML側で処理することにした。ついでにjQueryの使い方も調べながらやってみた。というわけでとりあえずは完成。だが、JSのソースを見ると「Pipes使わなくても良かったか?」という疑問がわいたりもするが…イーンダヨ!Pipesには可能性を感じたし、何よりあのモデリングを実現するUIが良い。業務フローとかをパッパ!と表現できそぅじゃないですか?
allfeeds.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="alternate" type="application/rss+xml" title="shin1のつぶやき(ごった煮) - RSS" href="http://pipes.yahoo.com/pipes/pipe.run?_id=6010ea4aabef4c56a04963a77e79fd7f&_render=rss"/>
<style><!--
ul.feeds li {
  list-style: none;
  background-repeat: no-repeat;
  padding: 0 0 0 17px;
  margin-bottom: 0.1em;
}
li.twitter { background:url(http://twitter.com/favicon.ico); }
li.tumblr { background:url(http://assets.tumblr.com/images/favicon.gif); }
li.blogger { background:url(http://www.blogger.com/favicon.ico); }
li.delicious { background:url(http://del.icio.us/favicon.ico); }
--></style>
<!-- jQuery -->
<script src='http://shin1.s4.xrea.com/jquery/jquery-1.2.2.pack.js' type='text/javascript'></script>
<script type="text/javascript"><!--
function renderItems(data) {
  $('#allitems').text('now parsing...');
  var intCount = data.count;
  var pipesFeeds = new Array(intCount);
  $.each(data.value.items, function(i, item) {
    // 2008-01-20T13:04:55Z delicious用の日付変換
    item.pubDate = item.pubDate.replace(
        /([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9:]{8})Z$/
        , '$1/$2/$3 $4 +00:00');
    // 2008-01-20T23:01:00.000+09:00 blogger用の日付変換
    item.pubDate =
      item.pubDate.replace(
        /([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9:]{8})[0-9\.]{4}([0-9\+:]{6})$/
        , '$1/$2/$3 $4 $5');
    pipesFeeds[i] = {};
    pipesFeeds[i].pubDate = new Date(item.pubDate);
    pipesFeeds[i].title = item.title;
    pipesFeeds[i].link = item.link;
    pipesFeeds[i].id = item.id;
    pipesFeeds[i].description = item.description;
    if (item.user) {
      pipesFeeds[i].type = 'twitter';
    } else if (pipesFeeds[i].link.match(/tumblr.com/)) {
      pipesFeeds[i].type = 'tumblr';
    } else if (pipesFeeds[i].id && pipesFeeds[i].id.match(/blogger.com/)) {
      pipesFeeds[i].type = 'blogger';
    } else {
      pipesFeeds[i].type = 'delicious';
    }
  });
  data = null;
  pipesFeeds.sort(function (x, y) { return y.pubDate - x.pubDate });
  $('#allitems').empty();
  var domUl = null, strPreDate = "";
  $.each(pipesFeeds, function(i, item) {
    var strDate = item.pubDate.getFullYear() + "/" 
      + (item.pubDate.getMonth() + 1) + "/"
      + item.pubDate.getDate();
    if (strPreDate != strDate) {
      $('<h2></h2>').html(strDate).appendTo($('#allitems'));
      domUl = $('<ul></ul>').attr('class', 'feeds').appendTo($('#allitems'));
      strPreDate = strDate;
    }
    if (item.title) {
      if (item.type == 'tumblr') {
        $('<li></li>').attr('class', item.type)
          .append('<a></a>').children('a').attr('href', item.link)
            .attr('target', '_shin1').html(item.title)
          .parent().append('<div></div>').children('div')
            .html(item.description)
          .parent().appendTo(domUl);
      } else if (item.link) {
        $('<li></li>').attr('class', item.type)
          .append('<a></a>').children('a').attr('href', item.link)
            .attr('target', '_shin1').html(item.title)
          .parent().appendTo(domUl);
      } else {
        $('<li></li>').attr('class', item.type)
          .html(item.title).appendTo(domUl);
      }
    }
  });
  pipesFeeds = null;
  $('#chkTwitter').click(function() { $('.twitter').slideToggle('fast');} );
  $('#chkDelicious').click(function() { $('.delicious').slideToggle('fast');} );
  $('#chkTumblr').click(function() { $('.tumblr').slideToggle('fast');} );
  $('#chkBlogger').click(function() { $('.blogger').slideToggle('fast');} );
  $('#header').css('display', 'block'); 
  $('#header > input').attr('checked', 'true'); 
}
$(function init() {
  $('#header').css('display', 'none'); 
  $('#allitems').text('now loading...'); 
});
$(function pipes() {
  var s = document.createElement('script');
  s.charset = 'utf-8';
  s.src = 'http://pipes.yahoo.com/pipes/pipe.run?_id=6010ea4aabef4c56a04963a77e79fd7f&_render=json&_callback=renderItems'; 
  document.body.appendChild(s);
});
--></script>
</head>
<body><h1>shin1のつぶやきごった煮</h1>
<div id="header">
<input type="checkbox" id="chkTwitter">twitter</check>
<input type="checkbox" id="chkDelicious">delicious</check>
<input type="checkbox" id="chkBlogger">blogger</check>
<input type="checkbox" id="chkTumblr">tumblr</check>
</div><div id="allitems"></div></body></html>
コメントを投稿