LDR でコンテンツ・フィルタ (Part 2)

id:reinyannyan:20060714:p1 で、記事本文やタグ等を調べて不要な記事を削除する方法を考えました。

今回はさらに、もしフィードが不要な記事しか含んでいなかった場合、それをフィード一覧から自動的に削除する方法を考えてみました。

(不要な記事だけを含むフィードなんて無い (と言うか購読しない) だろうと思われるでしょうが、広告だけが定期的にアップされるようなフィードもあったりしますので…)

先読み関数をハックします。

prefetch = function(sid, count) {
  var max_prefetch = LDR_VARS.MaxPrefetch;
  var api = new API("/api/unread");
  get_unread.cache.set(sid, "prefetch");
  switchClass("subs_item_" + sid, "ps-prefetching");
  message("先読み中");
  api.post({ subscribe_id : sid },function(json){
    // ここから
    var ignore = item_ignore(json);               // NG 判定関数をゲット
    if (ignore && json.items.every(ignore)) {     // 全部 NG ならば
      delete get_unread.cache._index["_" + sid];  // キャッシュ (のプレースホルダ) を削除
      touch(sid, Config.touch_when);              // 既読化

      Ordered.list = Ordered.list.filter(function(v){ return v != sid });
      DOM.remove("subs_item_" + sid);             // フィード一覧から削除
      Control.prefetch();                         // さらに先読み
      return;
    }
    // ここまで追加
    get_unread.cache.set(sid,json);
    if(json.channel){
      var expr = json.channel.expires * 1000;
    }
    get_unread.cache.set_expr(sid, expr);
    switchClass("subs_item_" + sid, "ps-prefetched");
    message("先読み完了");
  });
};

また、記事表示時のイベント・フック (after_printfeed / before_printfeed) と共用できるように、NG 判定関数を生成する関数を切り出しておきます。

(概要のみ再掲):

function item_ignore(feed) {
  var link = feed.channel.link;         // サイト URL
  var feedlink = feed.channel.feedlink; // フィード URL
  var ignore, pat;

  // ignore (記事の無視判定を行う関数) をサイト毎に生成
  /*
  ignore = function(item) {
    return true if item.[body|title|category|author|link] matches NG criteria
  };
  */

  return ignore;
}

これにより、以前のフック版はこのように書き換えられます:

register_hook("after_printfeed", function(feed) {
  var ignore = item_ignore(feed);
  ignore && feed.items.forEach(function(item) {
    if (ignore(item))
      (function(id) {
        var self = arguments.callee;
        self.fails = self.fails || 0;

        try {
          close_item(id);
        }
        catch (e) {
          // 数値は適当に調節してください
          if (self.fails++ > 50) return;
          setTimeout(function(){ self(id) }, 200);
        }
      })(item.id);
  });
});


追記 [20060805]:

ついでに、before_printfeed を使用するバージョンです:

register_hook("before_printfeed", function(feed) {
  var ignore = item_ignore(feed);
  if (!ignore) return;
  for (var i = 0, items = feed.items; i < items.length; i++)
    if (ignore(items[i]))
      items.splice(i--, 1);
});

after フックよりこちらの方が良いかも知れません。