2014-11-12 , ,

Feedly Open All Unread Button Nov.2014

(2021-07-22追記:新しいのを作りました)

Feedlyに対する色々なユーザースクリプトが大分前に動かなくなったのを面倒くさいので放置していたのですが、重い腰を上げて未読を一気に別タブで開くのだけ実装しました。探せばどこかにあるのかもしれませんが、userscripts.orgが止まってからというものそれも面倒になりましたし、度々使えなくなるものなので、この際自分で調べて実装することにしました。

Feedlyサイト内の一つ一つのエントリーは.u0Entry(Title Only表示時)とか.u4Entry(Magazine表示時)とか.u5Entry(Cards表示時)とか.u100Frame(Full Articles表示時)とか、表示モードによって違うクラス名のdiv(以下、エントリーdiv)に囲まれるようですね。 エントリーdivではdata-で始まる属性で記事における様々な情報を表現しているようです。URLなんかはありますが、残念ながら既読未読の情報は無いようです。

未読だけを列挙するには、セレクターa.title.unreadにマッチするものを列挙すれば良さそうです。このa要素はエントリーdivの子孫ですが、何段下になるかは状況によって変わるようです。つまり、a.parentNode.parentNodeが必ずしもエントリーdivになるとは限りません。ただ、parentNodeをたどっていくといつかはエントリーdivにたどり着くようではあります。

記事のオリジナルURLは、aのhref=から求めても良いですし、エントリーdivのdata-alternate-link=から求めても良いでしょう。

URLを開いた後、記事を既読としてマークして一覧から消したいところです。Title Only表示の時はimg[title="Mark as read and hide"]にマッチする要素を、それ以外はspan.action[title="mark as read and remove from list"]にマッチする要素をクリックすることで実現できます。

後はUIです。開くボタンや一度に開く記事数のUIをページ内に追加したいです。しかしfeedlyが余分な要素を削除してしまう場合があるようだったので、1秒ごとに document.bodyの直下 (2014-11-13変更: .pageActionBarの直下) に挿入し直すようにしてみます。

以上を勘案して、次のようなスクリプトになりました。

function openUnreadEntries(limit){
    var unreads = document.querySelectorAll(".title.unread");
    var count = Math.min(unreads.length, limit || 5);
    for(var i = 0; i < count; ++i){
        // determine elements
        var title = unreads[i];
        var entry = (function(e){
            while(e && !e.getAttribute("data-alternate-link"))
                e = e.parentNode;
            return e;})(title.parentNode);

        // open url
        var url = (entry && entry.getAttribute("data-alternate-link")) ||
                title.getAttribute("href");
        window.open(url, "_blank");

        // mark as read and hide
        var readAndHideButton = entry && (
            entry.querySelector('.condensedTools img[title="Mark as read and hide"]') || //Title Only
            entry.querySelector('.action[title="mark as read and remove from list"]') //Magazine, Card, Full Articles
        );
        (readAndHideButton || entry || title).click();
    };
}
var BUTTON_CLASS_NAME = "openUnreadButton";
function createButton(){
    var div = document.createElement("div");
    div.style.display = "inline-block";
    div.style.border = "1px solid #bbb";
    div.style.borderRadius = "3px";
    div.style.verticalAlign = "top";
    div.className = "pageAction " + BUTTON_CLASS_NAME;

    div.innerHTML =
        '<input type="number" value="5" style="width:3em">'+
        '<input type="button" value="Open Unread">';

    var count = div.querySelector('input[type="number"]');
    var button = div.querySelector('input[type="button"]');
    button.addEventListener("click", function(e){
        openUnreadEntries(parseInt(count.value, 10));
    }, false);
    return div;
}
function setupUI(){
    var bars = document.getElementsByClassName("pageActionBar");
    for(var i = 0; i < bars.length; ++i){
        var bar = bars[i];
        if(!bar.querySelector("."+BUTTON_CLASS_NAME)){
            bar.insertBefore(createButton(), bar.firstChild);
        }
    }
}
setInterval(setupUI, 1000);

あとはこれをGreasemonkeyに登録して、 http://feedly.com/* で有効になるようにすればOKです。

Pingback / Trackback