JavaScript
api
gas
Slack
Scrapbox

GASを使ってScrapboxの新着ページだけをSlackに通知する


ねらい

エンジニアのアウトプット?Scrapboxで決まりでしょ!を読んで以来、情報共有サービスのScrapboxを愛用しています。

Scrapboxには、Slackに更新を通知する機能があります。Scrapboxではリアルタイムで編集が反映されるため、通知タイミングは最後の書き込みから90秒経過した時となっています。

ただし、ある程度人数のいるチームで使っていると、通知のタイミングが多すぎると感じることがあります。Scrapboxの開発思想では書いた後からどんどん修正していくことが推奨されていますが、都度全員に通知が飛んでしまうと細かく追記・修正しにくいと思う人がいるかもしれません。

そこで通知の量を減らしたいところですが、Scrapbox側の機能では細かい設定が用意されていません。代わりに、Google Apps Script(GAS)を間に挟んで通知をカスタマイズするというアイデアが以下の記事で紹介されています。

本記事では、ページが作成されたときに限り通知することで、通知の量を減らす方法をご紹介します。


環境


コード

全体のコードはGistに公開しました。コピペしたい方はこちらからどうぞ。


新着ページ判定の流れ

新着ページの通知にあたって、GAS側で行っていることを解説します。


  1. 事前に全ページのタイトルを保存しておく

  2. (初回のみ)ScrapboxのAPIから全ページを取得する

  3. Scrapboxからの通知を受け取る

  4. タイトルが新しい場合はSlackに通知し、全ページタイトルに新しいタイトルを追加して保存する


事前に全ページのタイトルを保存しておく

GASは実行時間に制限が付いているので、データをずっと保持したい場合は外部に保存しなければなりません。Google SpreadSheetとの連携がよく使われますが、今回はタイトルを配列で持っておくだけで良いので、JSONファイルをGoogle Driveへ保存するようにしました。


newpage.gs

function getJsonFileFromDrive(name) {

var files = DriveApp.searchFiles('title = "' + name + '"');
if (files.hasNext()) return files.next();
return DriveApp.createFile(name, '');
}

nameというファイルがあれば取得し、なければ作成します。どちらにしてもFileクラスで返り、getBlob().getDataAsString()で内容の文字列が得られます。


newpage.gs

/* ファイルから配列を取得する */

var titles = JSON.parse(getJsonFileFromDrive(jsonName).getBlob().getDataAsString() || '[]');
/* 配列をファイルに保存する */
getJsonFileFromDrive(jsonName).setContent(JSON.stringify(titles));

作成したJSONファイルは、自分のGoogle Driveで存在を確認できます。

Google Drive上のjsonファイル


(初回のみ)ScrapboxのAPIから全ページを取得する

ScrapboxにはAPIが用意されており、ページリストなどを取得できます。「予告なく変更を行う」とのことなので、使う際は最新の情報をご確認ください。

使い方はURLをGETするだけで、例えばhelp-jpの全ページリストはscrapbox.io/api/pages/help-jpで見ることができます。ただし、デフォルトでは100ページまでしか取れないので、ご自身のプロジェクト規模によっては?limit=1000などとしておきましょう。


Privateプロジェクトの場合

公式のヘルプページには非公開プロジェクトでAPIを利用する方法が載っていませんが、こちらで解説されています。

connect.sidが分かったら、リクエストヘッダにCookieとして設定してからAPIを呼べばよいです。


newpage.gs

function getPageListFromApi() {

var headers = { 'Cookie' : 'connect.sid=' + sid };
var response = UrlFetchApp.fetch('https://scrapbox.io/api/pages/' + projectName + '?limit=1000', {
method : 'get',
headers : headers
});
return JSON.parse(response);
}

今回欲しいのはページのタイトルだけなので、mapで取り出して配列化します。


newpage.gs

if(titles.length === 0) // fetch the list of the page titles

titles = getPageListFromApi().pages.map(function(p){ return p.title; });


Scrapboxからの通知を受け取る

Scrapboxからの通知はdoPost()関数で受け取ります。Slackに渡すことが想定されているため、通知内容の取得が少し面倒です。


newpage.gs

function doPost(e) {

var attachment = JSON.parse(e.postData.getDataAsString()).attachments[0];

console.log(attachment.title); // ページタイトル
// ...
}



Slackへの通知とタイトルの保存

titlesattachment.titleがなければ新着ページと判定し1titlesに新しいタイトルを加え、Slackに通知を出します。


newpage.gs

function doPost(e) {

// ...
if(titles.indexOf(attachment.title) === -1) { // New page!
titles.push(attachment.title);

var message = projectName + 'に記事"' + attachment.title + '"が作成されました';
console.log(message);
UrlFetchApp.fetch(webHookUrl, options(message, attachment));
}
getJsonFileFromDrive(jsonName).setContent(JSON.stringify(titles));
}


Slack通知用にリクエストを組み立てる部分はoptions()に分離しています。usernameicon_emojiを設定すると通知の見た目がよくなるのでオススメです(あらかじめアイコン用にカスタム絵文字を追加しておきましょう)。


newpage.gs

function options(message, attachment) {

return {
method : 'post',
contentType : 'application/json',
payload : JSON.stringify({
username : 'Scrapbox',
icon_emoji : ':scrapbox:',
text : message,
attachments : [attachment]
})
};
}

それっぽい通知の例


通知がGASを経由するように設定する

最後に、設定の手順を簡単に説明します。GASを使うのが初めてという場合はお読みください。


GASの設定

コードをGASに貼り付けた段階では、このような画面になっているはずです。

GAS画面

メニューから「ファイル」→「プロジェクトのプロパティ」と選んで出てくる画面で「スクリプトのプロパティ」を選択します。ここに設定した文字列は、コードから読み取って使えます。

本記事のコードではScrapboxやSlackの認証情報などを保存するのに使いました。以下3つ(2つ)を設定してください。



  • SCRAPBOX_PROJECT:通知したいScrapboxのプロジェクト名です。


  • SLACK_WEBHOOK_URL:Slackで通知を受け取るのに使うIncoming WebhookのURLです。


  • SCRAPBOX_SID:公開プロジェクトの場合は不要です。privateプロジェクトの場合で説明したconnect.sidを貼り付けてください。

スクリプトのプロパティ

特に下の2つは流出すると悪用されかねないので、扱いにはお気をつけください。

プロパティを設定したら、「公開」→「ウェブアプリケーションとして導入」に進みます。「アプリケーションにアクセスできるユーザー:」を「全員(匿名ユーザーを含む)」に変更します。

ウェブアプリケーションとして導入

「導入」を押すと、「現在のアプリケーションのURL」が表示されます。こちらはScrapboxからGASに通知を渡すのに必要なので、コピーしておきましょう。


Scrapboxの設定

「Setting」→「Notifications」から通知をセットアップし、GASで表示されたURLを貼り付けます。既に設定済みの場合は、古い方を消して再設定しましょう。

スクリーンショット 0031-03-16 17.43.36.png

これでScrapbox→GAS→Slackの順に通知が流れるようになるはずです。うまく動いていない場合は、StackDriverのログなどを確認してみると切り分けができます。


おわりに

本記事では、Scrapboxのタイトル一覧を保存して新着ページだけをSlackに通知する手法をご紹介しました。応用次第では、「○日以上編集されなかったページが編集されたら通知する」など、さらに複雑な動作も作れそうです。

皆様の快適なScrapboxライフのヒントとなれば幸いです。





  1. この判定法では、ページの名称を変更した際も新着として通知が流れてしまいます。内部的にはページにIDを振っているようなので、IDも考慮すれば区別が可能だと考えられます。ただし、本記事の目的は通知を減らすことなので特に対処していません。