Hatena::Groupsubtech

ういはるかぜの化学

Saturday, June 16, 2007

[Plagger] Plaggerを使ってイラストサイトを楽にチェックする 23:35  [Plagger] Plaggerを使ってイラスト系サイトを楽にチェックする - ういはるかぜの化学 を含むブックマーク はてなブックマーク -  [Plagger] Plaggerを使ってイラスト系サイトを楽にチェックする - ういはるかぜの化学

絵師さんの際とってメインがトップとかぺらいちなところが多くて、フィードなんてないケースが結構あります。とはいえサイトごとにEFTなassetsを書くのはメンドイしかといって毎度全文落ちてきても困る。でもそんなサイトを楽に見て回りたい!

ということで今手元でやっている方法を書いてみるテスト。追加で用意するのは Filter::Diff ぐらいです。

まず1サイト1エントリフィードを作ります。はてなアンテナWebで管理できてさくさく増減できるのでオススメですね(ただしmetaでいろいろ拒否られてるとRSSに出てこなくなるので注意)。

で、以下のようなyamlをつくります。Dedupedとかは適当dbを指定したほうがいいです。

plugins:
  - module: Subscription::Config
    config:
      feed:
        - http://www.example.com/rss
        #- http://a.hatena.ne.jp/sample/rss?gid=nnnnnn

  # 一度見たのはいらないですわ
  - module: Filter::Rule
    rule:
      module: Deduped
      compare_body: 1

  # とりあえずHTMLを丸ごと拾う
  - module: Filter::EntryFullText
    config:
      force_upgrade: 1
      store_html_on_failure: 1

  # 差分をとるときに困るので広告を削除します。
  # infoseekとかshinobiとかのpatなassetを作っておきましょう
  - module: Filter::StripRSSAd

  # 差分をとる
  - module: Filter::Diff

  # 差分をとるとHTMLが壊れるのでTidyするといいかも(試してないです)
  # - module: Filter::HTMLTidy

  # エントリ(サイト)をフィードにばらす。
  - module: Filter::BreakEntriesToFeeds

  - module: Filter::ResolveRelativeLink

  # 絵を。
  - module: Filter::FindEnclosures
  #- module: Filter::FetchEnclosure

  # Publish
  # Publish::Gmail+attach_enclosuresとか

これではてなアンテナに登録されたサイト更新されると更新箇所の差分がメールで飛んできます。増やしたいときははてなアンテナで登録すればよいです。

ちなみに実行する間隔は半日から1日に一回で十分だと思います。あんまり短くしてPlaggerが疎まれても困るし(キャッシュはしてるけど)。

[Plagger] ダウンロードに失敗してたりしてたら消す 22:52  [Plagger] ダウンロードに失敗してたりしてたら消す - ういはるかぜの化学 を含むブックマーク はてなブックマーク -  [Plagger] ダウンロードに失敗してたりしてたら消す - ういはるかぜの化学

  - module: Filter::Rule
    rule:
      expression: $args->{entry}->{enclosures} = [ grep { -e $_->local_path } $args->{entry}->enclosures ]; 1;

[Plagger] Filter::Diff 22:52  [Plagger] Filter::Diff - ういはるかぜの化学 を含むブックマーク はてなブックマーク -  [Plagger] Filter::Diff - ういはるかぜの化学

http://subtech.g.hatena.ne.jp/mayuki/20061029/1162120080 の改良版。

前のdiffを保持するようにしたのではてなアンテナっぽいものを作れるように。アンテナっぽいのをつくるならCustomFeed::Debugかはてなアンテナフィードを使うのがよいかもですわ?

package Plagger::Plugin::Filter::Diff;

use strict;
use base qw( Plagger::Plugin );

use Plagger::Cache;

use Algorithm::Diff qw( traverse_sequences );

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self,
        'plugin.init'        => \&initialize,
        'update.entry.fixup' => \&filter,
    );
}

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

    my $params = {
        base    => $self->conf->{path} || File::Spec->catfile(Plagger->context->cache->{base}, 'Filter-Diff'),
        expires => $self->conf->{expires},
    };

    $self->{cache} = Plagger::Cache->new($params);
}

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

    my $entry = $args->{entry};

    my $prev_cache = $self->{cache}->get($entry->permalink) || {};
    my $prev = (ref $prev_cache eq 'HASH') ? $prev_cache : { body => $prev_cache };
    my $body_new = $entry->body ? $entry->body->utf8 : undef;
    my $lastmod_new = $entry->date || Plagger::Date->now;

    my $body_diffed = '';
    if ($prev->{body}) {
        Plagger->context->log( debug => "previous entry data found (".$prev->{modified_on}.")" );

        my @lines = split /^/, $body_new;
        my @lines_prev = split /^/, $prev->{body};

        traverse_sequences(\@lines_prev, \@lines,
            {
                DISCARD_B => sub {
                    Plagger->context->log( debug => "new line: $lines[$_[1]]" );
                    $body_diffed .= $lines[$_[1]];
                }
            }
        );
        $body_diffed =~ s/(?:^\s+|\s+$)//g;
        $entry->body($body_diffed);
        $entry->date($lastmod_new) unless $entry->date;
    }
    else {
        $entry->body('') unless $self->conf->{store_on_firsttime};
    }

    if (!$prev->{modified_on} || ($body_diffed ne '' && ($prev->{modified_on} < $lastmod_new))) {
        Plagger->context->log( debug => "Save entry data: ".$entry->permalink );
        $self->{cache}->set($entry->permalink, { body => $body_new, diff => $entry->body, modified_on => $lastmod_new });
    }
    else {
        Plagger->context->log( debug => "use previous diff data.");
        $entry->body($prev->{diff});
        $entry->date($prev->{modified_on});
    }
}

1;
__END__

=head1 NAME

Plagger::Plugin::Filter::Diff -

=head1 SYNOPSIS

- module: Filter::Diff

=head1 DESCRIPTION

[ato de kaku]

=head1 CONFIG

=over 4

=item store_on_firsttime

=item path

=item expires

=back

=head1 AUTHOR

Mayuki Sawatari

=head1 SEE ALSO

L<Plagger>

=cut

[Plagger] Filter::BreakEntriesToFeedsAtAggregatorFinalize 22:52  [Plagger] Filter::BreakEntriesToFeedsAtAggregatorFinalize - ういはるかぜの化学 を含むブックマーク はてなブックマーク -  [Plagger] Filter::BreakEntriesToFeedsAtAggregatorFinalize - ういはるかぜの化学

update.entry.fixupやupdate.feed.fixupより先にばらばらにしたい!ということでBreakEntriesToFeedsをちょろちょろ書き換えて作った。

なんてやる気の感じられない名前。

package Plagger::Plugin::Filter::BreakEntriesToFeedsAtAggregatorFinalize;
use strict;
use base qw( Plagger::Plugin );

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self,
        'aggregator.finalize' => \&break,
    );
}

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

    for my $feed ($context->update->feeds) {
        next unless grep { $_ eq $feed->link }  @{$self->conf->{feed}};
        for my $entry ($feed->entries) {
            my $new_feed = $feed->clone;
            $new_feed->clear_entries;
            $new_feed->url($entry->link);
            $new_feed->link($entry->link);
            $new_feed->add_entry($entry);
            $new_feed->title($entry->title)
                if $self->conf->{use_entry_title};
            $context->update->add($new_feed);
            $context->log( info => "break entry to feed: ".$new_feed->link );
        }
        $context->update->delete_feed($feed);
    }
}

1;

__END__

=head1 NAME

Plagger::Plugin::Filter::BreakEntriesToFeedsAtAggregatorFinalize - 1 entry = 1 feed

=head1 SYNOPSIS

  - module: Filter::BreakEntriesToFeedsAtAggregatorFinalize
    config:
      feed:
        - http://www.example.com/rss

=head1 DESCRIPTION

This plugin breaks all the updated entries into a single feed. This is
a bit hackish plugin but allows things like sending a single mail
containing single entry, rather than a feed containing multiple
entries, with Publish::Gmail plugin.

=head1 CONFIG

=over 4

=item use_entry_title

Use entry's title as a newly generated feed title. Defaults to 0.

=back

=head1 AUTHOR

Tatsuhiko Miyagawa, Mayuki Sawatari

=head1 SEE ALSO

L<Plagger>

=cut
トラックバック - http://subtech.g.hatena.ne.jp/mayuki/20070616