pixiv insideは移転しました! ≫ http://inside.pixiv.blog/

Slackを情報収集に使おう!SlackにRSS/Atomを簡単に追加できるChrome拡張機能の紹介

qiita.com

ピクシブ株式会社 Advent Calendar 2016の14日目担当のsyoichiです。
今年の2月に入社しました。現在はプレミアムチームに所属し、主にPHP/JavaScript/CSSで開発しています。個人ではブラウザの拡張機能やUser Script/User Styleをよく弄っています。

さて、私は入社する前まではプログラミングに関わるチャットサービスとしてはGitterぐらいしかまともに触ったことがなかったのですが、入社直後は社内でIdobataを主に利用し、数週間後には社内全体でSlackに移行と、一気にチャットサービスを常用することになりました。当時のSlackに対しては巷で話題のイケてるサービスという印象だったので、移行の時はワクワクしたものでした。それから数ヶ月経ち、すっかりSlack漬けの生活になっています。

フィードリーダーとしても活用できるSlack

最近になって知ったのですが、このSlackをフィードリーダーとして利用する事例がいくつかありました。

なるほど、確かにSlackは慣れ親しんでいるから投稿の読み方も身に付いているし、フィードだけでなくTwitterなどのより多様なコンテンツストリームを扱うこともできる…。Google Readerに始まり、feedlyLive Dwango Readerを常用してきた自分にとっては目から鱗でした。

こうした事例に触発されて私も個人用Slack Teamを作り現在試験運用中です。その際、RSS integrationにフィードを追加するのがスムーズにできないことに気付きました。フィードURLがわかっていればSlack上でコマンドから登録することはできますが、例えばブラウザでブログを読んでいる時にSlackに登録したいと思った時には自分でフィードURLを探さねばなりません。
こうした問題は、通常のフィードリーダーのようにフィード登録用のURLが無いことが大きな原因であると感じています。それさえあれば、既存の仕組み(ブラウザ内蔵のフィード登録ボタン、または拡張機能)で簡単にフィードを登録できるのですが…。

残念ながら、この「ブラウザからSlackに手軽にフィードを登録できるツール」は無さそうだったので、Chrome拡張機能として自分で作ってみました。以下はその紹介です。

github.com

ブラウザからSlackにフィード登録が簡単にできる「Add feed to Slack」の紹介

そのものズバリな「Add feed to Slack」は、フィードがあるブログなどに反応したPage Actionを押すと、SlackのRSS integrationのページを開いてフィードURLを自動的に登録フォームに入力してくれるChrome拡張機能です。

f:id:Syoichi:20161213154541p:plain フィードがあるブログなどにアクセスするとPage Actionが反応

f:id:Syoichi:20161213155029p:plain 反応したPage Actionを押すとSlackのRSS integrationのページが開いてフィードURLを自動的に登録フォームに入力
フィードが見つからない場合はPage Actionのアイコンはグレースケール化

Chrome拡張機能を作ったのはかなり久しぶり(いつの間にかPage ActionがOmniboxに表示されず、Browser Actionと変わらないような形になっていたことに驚いた)でしたが、Chrome ウェブストアに公開するのはこれが初めてです。

最初はBookmarkletかUser Scriptでできないか考えたのですが、拡張機能の形で落ち着きました。

拡張機能の実装について

ここからは具体的な実装の解説をしてみます。シンプルさを重視した為、かなりコンパクトなものになりました。コアとなる実装は以下の2つのファイルだけです。

background.js

'use strict';

const SLACK_RSS_APP_URL = 'https://slack.com/apps/A0F81R7U7-rss';

let urlMap = new Map();

chrome.runtime.onMessage.addListener(({url}, {tab}) => {
  urlMap.set(tab.id, url);
  chrome.pageAction.show(tab.id);
});

chrome.pageAction.onClicked.addListener(tab => {
  chrome.tabs.create({
    url: SLACK_RSS_APP_URL
  }, () => {
    chrome.tabs.executeScript(null, {
      code: `
        document.getElementById('feed_url').value = '${urlMap.get(tab.id)}';
        document.querySelector('#settings + .card').scrollIntoView()
      `,
      runAt: 'document_end'
    });
  });
});

content.js

'use strict';

try {
  chrome.runtime.sendMessage(null, {
    url: (new URL(
      document.querySelector(`
        link[rel="alternate"][type="application/rss+xml"][href],
        link[rel="alternate"][type="application/atom+xml"][href]
      `).href
    )).toString()
  });
} catch (err) {
  // do nothing
}

処理の流れについて

  • Content Script(content.js)で、適切なフィードURLを取得できたらBackground Page(background.js)に送る
    • 不適切なURLをURL constructorに渡すとエラーになるので、エラーハンドリングをする必要がある。ここでは、簡略化の為、処理全体をtry-catchで囲んでいる。
  • Background Pageで、送られてきたフィードURLを一旦保持してPage Actionを反応させる
  • Page Actionが押されたらSlackのRSS integrationのページを開く
  • 開かれたページでフィードURLを登録フォームに挿入する
  • 多くのフィードが登録されていた場合を考慮して登録フォームまでスクロールする

というのが処理の流れです。コード的にはES2015を使用していてモダンなように見えますが、実装的には昔ながらのChrome拡張機能という感じになりました。

使用している拡張機能のAPIについては以下を参照すると良いでしょう。

chrome.declarativeContentを使ってみたかったのですが…

可能であれば、chrome.declarativeContentを使用してみたかったです。このAPIは特定のページで特定のCSS Selectorにマッチする要素があればPage Actionを反応させるなどの特定のアクションを取ることができるのですが、なんと、このAPIは表示されているコンテンツのみにしかマッチしない方針になっていました。

CSS conditions only match displayed elements

残念ながら、非表示コンテンツのlink要素を扱うRSS Subscriber的な拡張機能とは縁の無いAPIとなります。ただ、これを活用すればContent Scriptが不要になるケースがありそうなので、いつか別の拡張機能で試してみたいですね。

今後の改善について

実装的にいくつか改善できそうな点があるので、それらはIssuesにまとめています。ご興味のある方はPull Requestをどうぞ!


この拡張機能を作成したことで、ブラウザでブログを読んでいるところからフィード登録ボタンを使用する感覚でSlackにフィードを登録できるようになりました!
フィードリーダーとしてSlackを利用している方、利用しようと考えている方は是非インストールしてみてください。

chrome.google.com


それでは、明日からも引き続きピクシブ株式会社 Advent Calendar 2016をお楽しみください。
明日の担当は@f_subalさんです。今日に引き続きSlackに関するもので、Slack Botについて書いてくださるそうです。