読者です 読者をやめる 読者になる 読者になる
スポンサーリンク

「全タブを要約するアドオン」を改良。ページ内の選択部分を要約に反映。ブコメも自動収集

ブラウザ 作品 XUL

下記のアドオンを改良した。

開いている全タブのURLとタイトルを,列挙して抽出するFirefoxアドオン (XUL形式プラグインのソースコード付)
http://language-and-engineering.hatenablog.jp/entry/20121221/p1


改良点:

  • 各ページ内で選択範囲があれば,その部分を要約部分に引用するようにした。
  • ショートカットキーを「Ctrl + Shift + U」とした。
  • URLの末尾の一番最後の文字が「#」である場合,それをカットするようにした。(はてブ追加ブックマークレットを実行したときの名残を削除している。)
  • ページのタイトルにタグ記号が含まれる場合,動作不良を起こさず,「<>」の全角記号に変換するようにした。
  • (2/2追記):はてなブックマークのブックマークレット(http://b.hatena.ne.jp/register)が開いた状態であれば,ブコメを自動的に抽出するようにした。
  • (6/3追記):キーボードのショートカットを,CTRL+SHIFT+Zにも対応させた。片手で実行しやすくするために。また,Youtubeのタブを要約する際には,URLをシンプルに短縮し,画面上で何も選択していない場合には動画情報をコメントに含めるようにした。
  • (6/29追記):要約形式以外にも,aリンクを並べた形式,およびaリンクにはてブブックマーク数の画像を付属させた形式の合計3通りで同時に出力するようにした。
  • (12/30追記):Youtubeの動画再生ページのDOM構造が少し変わっていたので,動画のアップロードユーザ名を正しく抽出できるように修正。

※下記URLからダウンロード・インストールできます。

TabSum.xpi
http://www.name-of-this-site.org/codi...


XULのソースコードは下記の通り。

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>

<overlay id="TabSum" 
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

  <!-- 「ツール」メニューに,実行したい関数とショートカットキーを割り当て -->
  <menupopup id="menu_ToolsPopup">
    <menuitem label='create summary of all tabs' oncommand='createSummary()' key="createSummaryKey" />
  </menupopup>

  <!-- ショートカットキーが呼び出すコマンド -->
  <keyset id="mainKeyset">
    <key id="createSummaryKey" modifiers="control shift" key="U" command="createSummary" />
    <key id="createSummaryKey2" modifiers="control shift" key="Z" command="createSummary" />
  </keyset>

  <!-- コマンドが呼び出す関数 -->
  <commandset id="mainCommandSet">
    <command id="createSummary" oncommand="createSummary()"/>
  </commandset>
  

  <!-- JavaScript関数 -->
  <script type="application/x-javascript"><![CDATA[

    /*
    
      このアドオンの機能:
    
      CTRL + SHIFT + U で,全タブの要約を生成。
    
    */


    // @see http://language-and-engineering.hatenablog.jp/entry/20081129/1227955571
    

    // 要約を生成
    function createSummary()
    {
      // ログ用の関数
      var log = function( s ){
        try{
          Firebug.Console.log( s );
            // http://www.borngeek.com/2013/01/23/logging-to-firebug-from-xul/
        }catch(e)
        {
          //
        }
      };
      
      
      // HTMLトリム用の関数
      var trimStr = function( s ){
        s = ( s + "" )
          .replace( /</g, "<" )
          .replace( />/g, ">" )
        ;
        
        return s;
      };
    
    
      var sum = "";
      var sum_alinks = "";
      var sum_alinks_with_hatebu = "";
    
      // 全タブ
      var tabs = gBrowser.browsers;
        // http://stackoverflow.com/questions/3844793/xul-javascript-tabs-and-url
        // https://developer.mozilla.org/en-US/docs/Code_snippets/Tabbed_browser
      
        // Android Firefoxの場合:
        // var tabs = window.BrowserApp.tabs;
        // https://developer.mozilla.org/en-US/docs/Extensions/Mobile/API/Tab
      
      // 収集
      for( var i = 0; i < tabs.length; i ++ )
      {
        var tab = tabs[i];
        
        // このタブの情報を抽出
        log( i + "番目のタブを要約・・・");
        
        
        // タブのタイトル
        var str_title = "" + trimStr( tab.contentTitle );
          // https://developer.mozilla.org/ja/docs/XUL/tabbrowser#p-contentTitle
        log( "title:" + str_title );
        
        
        // タブのURL
        var str_url = tab.contentDocument.location + "";
          // http://stackoverflow.com/questions/12779639/firefox-xul-browser-doesnt-have-a-page-title
        log( "location:" + str_url );
        str_url = str_url.replace( /^([^#]+)#?$/g, "$1" ); // 末尾の#は除去。ブクマ直後の場合があるので
        str_url = str_url.replace(/^http(s)?:\/\/www\.youtube\.com\/watch\?.*(v=[^&]+).*$/, "https://www.youtube.com/watch?$2"); // Youtubeの場合は素のビデオIDにする
        log( "URL:" + str_url );
        
        
        // タブのコメント
        // 画面に選択範囲があれば
        var str_comment = tab.contentWindow.getSelection() + "";
          // https://forums.mozilla.org/addons/viewtopic.php?p=911&sid=bc675fb1933d12410dc4a1c8a4aadc80
        
        // はてブコメントから引用したい場合
        var hatebu_iframe = tab.contentDocument.getElementById("hatena-bookmark-bookmarklet-iframe");

        if( 
          // 選択範囲が存在しなくて
          ( ! str_comment.length )
          &&
          // なおかつはてブ窓を開いていれば
          ( hatebu_iframe )
        )
        {
          // はてブ窓から文字列を調達する
          str_comment = hatebu_iframe
            .contentWindow
            .document
            .getElementById("comment")
            .value
          ;
            // http://language-and-engineering.hatenablog.jp/entry/20090207/p1
          
          // はてブのブックマークカテゴリタグは除去する
          str_comment = str_comment.replace( /^(.*\])?([^\[\]]*)$/, "$2" );
        }
        else if( str_url.match("https://www.youtube.com/watch?") )
        {
          // 動画のアップユーザー名
          var movie_up_by = tab.contentDocument.querySelectorAll("a.yt-user-name")[0].innerHTML;
          
          // 動画の公開日
          var movie_up_time = tab.contentDocument.querySelectorAll("#watch-uploader-info strong")[0].innerHTML;
          
          str_comment = movie_up_time + ", by " + movie_up_by
        }
        
        // コメントの整形
        if( str_comment.length > 0 )
        {
          str_comment = trimStr( str_comment );
        }
        console.log( "comment:" + str_comment );
        
        
        if( str_title.length < 1 ){
          str_title = "…";
        }
        
        // 要約
        sum += str_title + "<br>"
          + str_url      + "<br>"
          + (
              ( str_comment.length > 0 )
              ? "-" + str_comment + "<br>"
              : ""
          )
          + "<br><br>"
        ;
        sum_alinks += "-&lt;a href='" 
          + str_url
          + "'&gt;"
          + str_title
          + "&lt;/a&gt; "
          + str_comment
          + "<br>"
        ;
        sum_alinks_with_hatebu += "-&lt;a href='" 
          + str_url
          + "'&gt;"
          + str_title
          + "&lt;/a&gt; "
          + "&lt;img src='http://b.hatena.ne.jp/entry/image/"
          + str_url
          + "'&gt; "
          + str_comment
          + "<br>"
        ;
      };
      
      // 新タブに表示
      var newTabBrowser = gBrowser.getBrowserForTab(gBrowser.addTab("https://www.google.co.jp/"));
      newTabBrowser.addEventListener("load", function () {
        newTabBrowser.contentDocument.body.innerHTML = sum
          + "<br><br><hr><br><br>"
          + sum_alinks
          + "<br><br><hr><br><br>"
          + sum_alinks_with_hatebu
          + "<br><br>"
        ;
      }, true);
    }

  ]]></script>
</overlay>

コードのハマり所としては,

  • locationオブジェクトに直接.replace() で置換をかける事はできないので,一回 + "" して文字列オブジェクトに変換してやる必要があった

ということ。

あと,XULからFirebugにデバッグ情報を出力するために Firebug.Console.log している。


関連する記事:

タブブラウザで,「開いている大量のタブ」をテキストで保存し,復元する方法
http://language-and-engineering.hatenablog.jp/entry/20140123/p1


Firefoxのサイドバーを作ろう (XUL形式のアドオンでbrowser要素を設定する方法)
http://language-and-engineering.hatenablog.jp/entry/20081203/1228262334


今から3分で,IE 上で .NET のDLLを動かそう (ブラウザ上で C# のコードを動かす方法)
http://language-and-engineering.hatenablog.jp/entry/20100705/p1