PlaggerServer を Yahoo PipesのUIで使ってみる。

とりあえず動いたけど、できることが、1つのURLに1つFilterを使えるくらいだ。。。
一応日本語のフィルタができる。けど、ほかにどうしようもない。。。
yamlを生成してそれでPublish::Plaggerみたいのを作った方がほかにも使えそうな気がした。(すでにあるんだろうか?)

モジュールのリストとか、モジュールのUI?みたいのも返す部分も自分でなんとかできるようなんで
そういうのもありなのかな。

うまくdescriptionがはいらない。。。
適当な定数がはいっていたり、変数名が適当だったりで、とりあえず動いているが。。。
自分のperlの知らなさを実感。。。がんばろう自分。

YahooP.pm

元にしたのは、SimpleBbs.pm、フィルタもこの中でやっているなど、なおせるならなおしたほうがよさそう。。。

package Plagger::Plugin::Server::Pull::YahooP;
use JSON::Syck;
use strict;
use base qw( Plagger::Plugin::Server::Pull);
use Encode;

sub register {
    my($self, $context) = @_;

    $context->register_hook(
        $self,
        'pull.handle' => \&handle,
        'pull.publish' => \&publish,
    );
}

sub dispatch_rule_on { 1 }

sub handle {
    my($self, $context, $args) = @_;

    $context->log(debug => "handle.");
    my $req = $args->{req}->protocol;
    my $r = $req->cgi;


    return unless $r->param('title') || $r->param('body');

    my $feed = $args->{feed};
    my $format = DateTime::Format::Strptime->new(pattern => '%Y-%m-%d %H:%M:%S');
    my $entry = Plagger::Entry->new;
    $entry->link($feed->link . time);

    my $title  = $r->param('title') || 'no title';
    my $author = $r->param('name') || 'no name';
    my $body   = $r->param('body') || '';
    utf8::decode($title)  unless utf8::is_utf8($title);
    utf8::decode($author) unless utf8::is_utf8($author);
    utf8::decode($body)   unless utf8::is_utf8($body);
    $entry->title($title);
    $entry->author($author);
    $entry->body($body);

    my $dt = DateTime->from_epoch( epoch => time );
    $dt->set_time_zone($context->conf->{timezone});
    $entry->date( Plagger::Date->parse($format, $dt->ymd . ' ' . $dt->hms) );
    my $u = $args->{req}->protocol->uri;
}

sub publish {
    my($self, $context, $args) = @_;

    $context->log(debug => "finalize.");

    my $feed = $args->{feed};
    my @entries = $feed->entries;
    for my $entry (reverse @entries) {
        $feed->delete_entry($entry);
        $feed->add_entry($entry);
    }

    $args->{req}->protocol->body($self->feed2json($context, $args));
}

sub feed2json_module {
  my( $self, $context, $args, $yp_module, $yp_id, $conf ) = @_;

  my $entries = $args->{feed}->entries;

  my @items;

  my $mo2={
      "prop"=>{
        "_OUTPUT"=>{
          "_type"=>"item",
          "_attr"=>{
            "link"=>{
              "_type"=>"url",
              "_count"=>0
            },
            "guid"=>{
              "_type"=>"url",
              "_count"=>0
            },
            "title"=>{
              "_type"=>"text",
              "_count"=>0
            },
            "description"=>{
              "_type"=>"text",
              "_count"=>0
            }
          }
        }
      },
      "count"=>0,
      "id"=>"$yp_id",
      "duration"=>0.06116,
      "start"=>1172355889,
      "module"=>"$yp_module",
      "items" => undef
     };

  my $count = 0;
  my $prop = $mo2->{prop};
  
  for my $item (@$entries) {
    my $link = $item->{link};
    my $guid = $item->{guid};
    my $title = $item->{title};
    my $description=$item->{description};

    $description = $item->{content} if( $description eq '');
    $description = $item->{summary} if( $description eq '');
    $guid = $link if( $guid eq '');

    my $new_item ={
		"link"=> $link,
		"guid"=> $guid,
		"title"=>$title,
		"description"=>$description
		};
    
    if( $conf ){
      my $isMatch = 0;
      my $rules = $conf->{RULE};
      for my $rule (@$rules){
	my $match_str = decode_utf8($rule->{value}->{value}, Encode::FB_CROAK);
	if( $new_item->{$rule->{field}->{value}} =~ /$match_str/ ){
		$isMatch = 1;
		last;
	      }
      }
      next if( $isMatch );
    }
    
    push( @items, $new_item);
    $prop->{_OUTPUT}->{_attr}->{link}->{_count}++;
    $prop->{_OUTPUT}->{_attr}->{guid}->{_count}++;
    $prop->{_OUTPUT}->{_attr}->{title}->{_count}++;
    $prop->{_OUTPUT}->{_attr}->{description}->{_count}++;
    

    $count++;
  }
  $mo2->{count}=$count;
  $mo2->{items}=\@items;
  
  return \$mo2;
  
}

sub feed2json {
  my( $self, $context, $args ) = @_;

  my @items;

  my $preview = [];
  my $req = $args->{req}->protocol;
  my $r = $req->cgi;

  my $final_result ={
		  "ok"=>1,
	     "preview"=>undef,
  "stats"=>undef
  };
  #$final_result->{stats} = undef;

  my $obj= JSON::Syck::Load($r->param('def'));
  my $modules =$obj->{modules};
  my $conf = undef;
  for my $module ( @$modules ){
    if( $module->{type} =~ /filter/ ){
      $conf = $module->{conf};
    }
  }
  for my $module ( @$modules ){
    my $module_name = $module->{id};
    if( $module->{type} =~ /fetch/ ){
      my $mo1 = $self->feed2json_module($context, $args, "Yahoo::RSS::Fetch",$module_name,$conf);
      $final_result->{preview}->{$module_name} = $mo1;
    }
    if( $module->{type} =~ /output/ ){
      my $mo2 = $self->feed2json_module($context, $args, "Yahoo::RSS::Output",$module_name,$conf);
      $final_result->{preview}->{_OUTPUT} = $mo2;
    }
    if( $module->{type} =~ /filter/ ){
      my $mo3 = $self->feed2json_module($context, $args, "Yahoo::RSS::Filter",$module_name,$conf);
      $final_result->{preview}->{$module_name} = $mo3;
    }
  }


  return JSON::Syck::Dump($final_result);
}


1;

pipes.yaml
10080でまっている。

global:
  plugin_path:
  timezone: Asia/Tokyo
  cache:
      base: /tmp/plaggercache


plugins:
  - module: Aggregator::Simple
  - module: Server::Engine::PreFork

  - module: Server::Protocol::HTTP
    config:
        port: 10080
        host: 127.0.0.1

  - module: Server::Pull::YahooP
    rule:
      expression: $args->{req}->protocol->service eq 'http' && $args->{req}->protocol->uri->path =~ m!^/ajax/pipe/preview!  && $args->{feed}->link =~ m!^http://!

  - module: Subscription::Config
    config:
      feed:
        - url: file:///tmp/dummy.rss
      id: DUMMY

  - module: Aggregator::AggregateYP

  - module: Publish::Debug

greasemonkey
pipes2plaggerserver.js
元にしたのは
http://blog.tkmr.org/tatsuya/show/265-yahoo-pipes-plagger-greasemonkey-1
ただ、alertはでたんだが、先に進めなかったので、
readyStateなどを適当に、処理してみる。

    {
      for(var prop in this._http_header){
	if(this._http_header.hasOwnProperty(prop)){
	  // TODO: ヘッダーをきちんと設定する必要があるだろう
	  //o.conn.setRequestHeader(prop,this._http_header[prop]);
	}
      }
      delete this._http_header;
      this._http_header={};
      this._has_http_headers=false;
    }

    w.YAHOO.util.Connect.getConnectionObject = function(){
      var o;
      var tId=w.YAHOO.util.Connect._transaction_id;
      try{
        o=w.YAHOO.util.Connect.createXhrObject(tId);
        if(o){
	  w.readyState[tId]=0;
	  w.statusHash[tId]=0;
	  w.responseText[tId]='';
          w.YAHOO.util.Connect._transaction_id++;
        }
	
        o.conn.open = function(method, uri, bool){
          o.conn.hoge = {
	   // gettid: function(){ return o.tId; },
	    tId: o.tId,
            method: method,
            uri: uri,
            bool: bool,
	    state:0
          };
        };
        
        o.conn.send = function(postdata){
          //alert("send GM_xmlhttprequest to " + myServerUri + this.hoge.uri);
          w.console.log("send GM_xmlhttprequest to [%s]\n[%s]" , this.hoge.uri,postdata);
	  o.conn2=o.conn;
	  
	  o.conn = {readyState:0,status:0,responseText:"", setRequestHeader:o.conn2.setRequestHeader };

	  serverUri = myServerUri;
	  if( this.hoge.uri.indexOf("/ajax/pipe/preview") != -1){
	    w.console.log("ServerUri CHANGE!!!!");
	    serverUri = "http://127.0.0.1:10080";
	  }
          GM_xmlhttpRequest({
			      
	    gettid: function(){ return o.tId; },
			      tid: this.tId,
            method: this.hoge.method,
			      url: serverUri + this.hoge.uri,
            data: postdata,
            headers: { "Content-Type": "application/x-www-form-urlencoded" },
			      
            onload: function(response){
				  w.statusHash[this.gettid()]=response.status;
				  w.responseText[this.gettid()]=response.responseText;
	      //w.console.log("[%s]",response.responseText);
            },

				onreadystatechange : function(response){
				  w.readyState[this.gettid()]=response.readyState;
				  w.statusHash[this.gettid()]=response.status;
				}
			      ,
          });
	    
        };
      }
      catch(e){}
      finally{
        return o;
      }
    };

    ///////////////////////
   
    w.readyState= {};
    w.statusHash= {};
    w.responseText= {};

    
    w.YAHOO.util.Connect.handleReadyState=function(o,callback)
{
  var oConn=this;
  if(callback&&callback.timeout){
    this._timeOut[o.tId]=window.setTimeout(function(){
					     oConn.abort(o,callback,true);
					   },callback.timeout);
  }
  this._poll[o.tId]=window.setInterval(function(){
				       if(w.readyState[o.tId]==4){
					 window.clearInterval(oConn._poll[o.tId]);
					 delete oConn._poll[o.tId];
					 if(callback&&callback.timeout){
					   delete oConn._timeOut[o.tId];
					 }
					 o.conn.readyState=    w.readyState[o.tId];
					 o.conn.status=    w.statusHash[o.tId];
					 o.conn.responseText = w.responseText[o.tId];
					 oConn.handleTransactionResponse(o,callback);}
				     },this._polling_interval);
}
  };
   
})();