ほんじゃらねっと

ダイエット中プログラマのブログ

IFTTTのMakerチャンネルを使って、いろんなサービスの更新情報を通知してくれる仕組みを作る

仕事でチーム間のコミュニケーションツールとして使い始めたチャットワークだが、

最近は「いろんなサービスやスクリプトからの通知を集めるツール」としての利用がメインになってきている。

www.chatwork.com

以前記事にした、

「Subversionのコミット情報にメンバーがすぐに気づけるように通知するスクリプト」

blog.honjala.net

を書いたのがきっかけで、

この仕組みを流用すればメールを汚さずにいろんな通知を一元管理できるのでは?

と思いついて色々チャットワークに自動通知するスクリプトを書き始めた。

ただ通知するだけなのだけど、ボットが

「ブログのはてブが増えたよ!」とか

「AmazonにKindle本が追加されたよ!」とか

発言してくれることでチェックの手間が減るのが楽しい。

本題

そんな時に、「IFTTTにMakerチャンネルができた」という話を聞いて、

これを使えば自動通知がさらに捗りそうだ、ということで試してみた、というのが今回の本題だ。

IFTTT(If This Then That)とは

EvernoteやTwitter等様々なアプリやWebサービス(チャンネルと呼ばれる)の更新を監視して、

更新が発生するとをあらかじめ登録しておいたアクションを実行してくれるというサービスで、

これを使えばプログラムを自作しなくても手軽に連携の仕組みが作れるという、

自動化心をくすぐられるサービスだ。

ifttt.com

IFTTTは便利なサービスなのだが、以前はチャンネルが用意されていないサービス間の連携がしにくい、という欠点があった。

チャットワークもチャンネルが用意されていない。

それが、Makerチャンネルが使えるようになったことで多少やりやすくなった。

ifttt.com

Makerチャンネルは簡単に言うと「他のチャンネルとWebアプリを連携できる」チャンネルだ。

自作のWebアプリをトリガーとしてMakerチャンネル経由で他のチャンネルを呼び出したり、

特定のチャンネルで更新が発生したら指定したURLにリクエストを飛ばすようなことができる。

これを使えば、何かしらのサービスで更新が発生した時に自作のWebアプリを経由してチャットワークにメッセージを保存する、みたいなこともできるわけだ。

Makerチャンネルを使ってチャットワークに連携するサンプルを作る

試しに、Node.jsで作成したWebアプリ経由で「Date&Timeチャンネルをトリガーに、定時になったらチャットワークに通知するレシピ」を作ってみた。

Webアプリを準備する

まずはIFTTTからアクセス可能なWebアプリを用意する。

ここがややハードルの高いところ。

今回は「http://自分のサーバのドメイン:3000/ifttt/notify_workend」というURLを用意し、

POSTリクエストで「time:時間」「message:メッセージテキスト」をJSON形式で渡すとその内容をチャットワークに送れるようにした。

下記はnode.js + Express4のサンプルソース:

(Webアプリでパラメータを受け取れたら環境は問わないので、Apache + PHP環境とかでも可)

REST API Sample For IFTTT Maker Channel.

こういうものを1つ用意しておけば、URLを追加していくだけでいろんなチャンネルと連携できるようになる。

IFTTTのレシピを作成する

次はITFFF側で用意したURLを呼び出すレシピを作成する。

トリガーとなるチャンネルの選択後、Makerをアクションとして選択して新しいレシピを作成する。

f:id:piro_suke:20160215013908p:plain

アクションの設定を行って、

f:id:piro_suke:20160215013918p:plain

作成したWebアプリのURLとパラメータを定義する。

「Content Type」を「application/json」にしておき、BodyでJSONを渡すようにしている。

f:id:piro_suke:20160215013928p:plain

この内容で登録しておくと、平日の17:30になったら、「Time to leave work」というメッセージが

用意したURLに飛び、そこを経由してチャットルームにメッセージが投稿される。

おわり

とりあえず仕組みが作ってみたが、まだまだ活用法は模索中。

また良い通知レシピを思いついたら試してみたい。

実践Node.jsプログラミング Programmer's SELECTION

実践Node.jsプログラミング Programmer's SELECTION

Node.jsでドメインのはてなブックマーク合計件数を取得する

ブログを書いていると、

自分が書いた記事にどれくらいブックマークがついているかが

気になるものである。

はてなブログでブログを管理している場合は、

ブログ管理画面や「はてなのお知らせ」というChrome拡張で

ブックマークされたことを知ることができる。

chrome.google.com

Wordpress等でブログを管理している場合は、

はてなブックマークのトップページの検索欄にブログのURLを入力すると

記事ごとのブックマーク数を表示してくれる。

このブログなら下記のページ:

『ほんじゃら堂』 の新着エントリー - はてなブックマーク

まあ確認するにはこれで十分なのだけど、

「もっとサクッとブックマークの総数が知りたいんや!」

という人向けに(かどうかは知らないが)

はてなブックマークのAPIに、

「指定したドメインの合計はてブ件数を取得できるAPI」

というものがちゃんと用意されている。

下記サイトの「被ブックマーク合計数取得API」のところだ。

はてなブックマーク件数取得API - Hatena Developer Center

XMLRPC経由ではてブ合計件数が知りたいドメインを渡すと、

その件数を返してくれる。

このAPIを使えば、

例えばブックマーク件数が増えた時に通知する、みたいなこともできそうだ。

このAPIを呼び出すスクリプトを作成して、

前回の件数と異なる件数が返ってきたらメールなりチャットなりに通知するような

内容にしておけば、即座に知ることができるだろう。

Node.jsでAPIにアクセスするスクリプトを作る

今回はXMLRPC経由で件数を取得するだけのスクリプトを作成してみよう。

練習も兼ねてNode.jsで作成してみた。

Node.js XMLRPC Client Sample

sample_hatebu.jsを実行するとはてブ件数が表示される。

Hatebu.getHatebuCountに渡しているURLを変更すれば

好きなドメインのはてブ数を表示することができる。

XMLRPCには下記のライブラリを使用している:

github.com

Node.js実行環境のインストール方法やスクリプトの実行方法については

入門記事を作成したので、下記を参照いただきたい:

blog.honjala.net

おわり

モチベーションアップに繋がるので、

こういったポジティブな情報の取得はどんどん自動化して

目に入るようにしておきたいものだ。

Subversionにコミットしたらチャットワークに通知するNode.jsスクリプト

ある開発プロジェクトで、

非技術系のメンバーにも進捗を知っておいてもらいたいものの、

「お前らSubversion入れろ」とか「リポジトリログを見ろ」といっても見そうになく、

いちいち伝えるのも面倒大変そうだったので、

Subversionにコミットがあったらメッセージ内容がリアルタイムで

チャットワークに流れる仕組みを作ってやった。

www.chatwork.com

チャットワークはチーム間でのやりとりに使っていたので、ここに流してやろうというわけだ。

チャットワークはプレビュー版ながらAPIを公開してくれているので、

developer.chatwork.com

API経由でメッセージ投稿を行うスクリプトと、

Subversionのフック機能を組み合わせることで実現することができた。

Node.jsでチャットワークのAPIにアクセスするスクリプトを作成する

今回はNode.jsでスクリプトを作成した。

手軽に環境が作れて、速くて、一通りライブラリが揃っているので気に入っている。

スクリプトの内容としては、

コマンドラインからリポジトリパスとリビジョン番号を受け取って、

svnlookコマンドでリビジョンをコミットしたユーザー名、メッセージログを取得して、

メッセージを組み立てて、

チャットワークのAPI経由で投稿している。

Subversionが動いているサーバにnode.js環境をインストールして、このスクリプトを配置する。

svn2chatwork.js

var execSync = require('child_process').execSync;
var _ = require('underscore');
var request = require('request');

if (process.argv.length < 4) {
    return;
}

var repo = process.argv[2];
var rev = process.argv[3];

var cwApiKey = '<ChatworkのAPIキー>';
var endpointBase = 'https://api.chatwork.com/v1/';

var svnRootPath = '/var/www/svn'; //Subversionのリポジトリルートパス

var targetRepos = {}; 
// このtargetReposにリポジトリパスを追加したら複数のリポジトリに対応可能
targetRepos[svnRootPath + '/<SVNリポジトリパス>'] = {'roomId': '<投稿先ChatworkのルームID>'};

var post2Chatwork = function (roomId, message, callback) {
    var options = { 
        url: endpointBase + 'rooms/' + roomId + '/messages',
         headers: {
             'X-ChatWorkToken': cwApiKey
         },  
        form: {
            body: message
        },
        json: true
    };

    request.post(options, function (error, response, body) {
        if (!error &amp;&amp; response.statusCode == 200) {
            callback(body);
        }   
    }); 
}
if (_.has(targetRepos, repo)) {
    var repoInfo = targetRepos[repo];
    var message = 'New Commit\n';

    var result = '' + execSync('svnlook author ' + repo + ' -r ' + rev);
    message += 'User:' + result;

    result = '' + execSync('svnlook log ' + repo + ' -r ' + rev);
    message += result;

    // 下記のコメントを外すと更新ファイル一覧もメッセージに追加できる(大量にファイルが更新されると結構うざい)
    // result = '' + execSync('svnlook changed ' + repo + ' -r ' + rev);
    // message += 'Files Updated:\n';
    // message += result;

    post2Chatwork(repoInfo.roomId, message, function (body) {});
}

Subversionのフックスクリプトを作成する

Subversionのリポジトリを作成すると、その中にhooksフォルダが作成され、

そこに置いたフックスクリプトを各種タイミングで実行してくれる。

Subversion フックスクリプト

今回はコミット後に上で作成したスクリプトを実行してもらいたいので、

「post-commit」という名前で下記のような内容のファイルを作成する。

作成したスクリプトにパラメータとしてリポジトリパスとリビジョン番号を渡し、nodeコマンドで実行するコマンドを書いてる。

最初のexport文を書かないと、日本語が文字化けしてしまうので注意。

あと、node.jsのバージョンとか、どこにsvn2chatwork.jsを置いたかでパスが変わるので注意。

post-commit

export LANG=ja_JP.UTF-8

REPOS='$1'
REV='$2'

# <nodeコマンドへのパス> <svn2chatwork.jsへのパス> $REPOS $REV
/usr/local/node-v0.12.7/bin/node /home/test/svn2chatwork/svn2chatwork.js $REPOS $REV

編集後、post-commitに実行権限をつけたら以降のコミットがチャットワークに通知されるはず。

おわり

ソースを整理したり、リポジトリとルームの関連付けを外部化したりしたものをGitHubに置いている。

よかったら参考にしていただきたい。

github.com

今時Subversionなんか使わねーよ!と言われるかもしれないが。

blog.honjala.net

Subversion実践入門:達人プログラマに学ぶバージョン管理(第2版)

Subversion実践入門:達人プログラマに学ぶバージョン管理(第2版)

Node.jsでRedmineのREST APIにアクセスしてチケット取得&一括登録

とあるWeb開発プロジェクトで

WBS(Excel製)に書かれた、機能ごとの開発担当・開始日・期日・予定工数を

そのままRedmineのチケットとして登録するという、

手作業でやったらえらく時間のかかりそうな作業があったので、

RedmineのAPI経由でチケットを一括登録できるスクリプトを作成した。

続きを読む

Node.jsのRESTクライアントモジュールでBit.lyのAPIにアクセスする

Node.jsのRESTクライアントモジュールを試すため、 以前Groovyで作成したBit.lyの履歴を取得するスクリプトをNode.jsで焼きなおしてみる。

node-rest-client」というモジュールを使用した。

get_bitlinks.js

var RestClient = require('node-rest-client').Client;

var ACCESS_TOKEN = '<your access token>';
var ENDPOINT_BASE = 'https://api-ssl.bitly.com/';
var bitlyClient = new RestClient();

bitlyClient.get(ENDPOINT_BASE + 'v3/user/link_history', {
    headers: {
        'Content-type': 'application/json'
    },
    parameters: {
        access_token: ACCESS_TOKEN,
        limit: 10,
        offset: 0
    }
}, function (data, response) {
    var result = JSON.parse(data.toString('utf8'));
    var linkList = result.data.link_history;
    linkList.forEach(function (link) {
        console.log(link.title);
    }); 
});

RestClientで呼び出すメソッドをgetからpostやputに変更すれば 登録、更新も行えるようなので、これ1つ覚えておけば色々なAPIアクセスに 使用できそうだ。

RESTful Webサービス

RESTful Webサービス

MongoDBに保存したデータをNode.js+ExpressでWeb表示する簡単なサンプル

そろそろNode.jsスクリプト作成にも慣れてきたので、

簡単なWebアプリ作成に挑戦してみた。

Meteor、MEAN.js、Sails.jsなど色々あって迷ったけど、

まずはシンプルにExpressを使ってみる。

MongoDBコレクションに保存された情報を

Webページ上に一覧表示するスクリプトを、

Node.js+Express+MongoDBで作成した。

続きを読む

ApacheのアクセスログをMongoDBコレクションにインポートするNode.jsスクリプト

MongoDBの勉強を兼ねて、Apacheアクセスログを後でログ分析や ビジュアライズに使えるようにMongoDBにインポートするスクリプトを書いた。

下記のスクリプトはログファイルを行単位で読み込んでMongoDBの 特定のコレクションに登録する。 行単位のファイル読み込み処理はNode.js標準で簡単にできる方法が用意されていない ようなので、node-bylineを使用している。

log_importer.js

var fs = require('fs');
var byline = require('byline');
var MongoClient = require('mongodb').MongoClient;

var dbUrl = 'mongodb://localhost:27017/<database name>';
var targetPath = '<path to access log>';

var logPattern = /(\S+) \- \- \[([^\]]+)\] '([^']+)' (\d+) (\S+) '([^']+)' '([^']*)'/;

var rs = fs.createReadStream(targetPath);
var stream = byline.createStream(rs);

MongoClient.connect(dbUrl, function (err, db) {
    if (err) {
        throw err;
    }   

    var apacheLogs = db.collection('apache_logs');

    var i = 0;
    stream.on('readable', function () {

        var line = null;
        while (null !== (line = stream.read())) {
            console.log(i + ':line start ' + line);
            var match = logPattern.exec(line);
            if (match != null) {
                var methodParams = match[3].split(' ');
                var method = methodParams[0];
                var path = methodParams[1];
                var http = methodParams[2];
                var log = {
                    host: match[1],
                    ts: match[2],
                    method: method,
                    path: path,
                    http: http,
                    status: match[4],
                    size: match[5],
                    agent: match[7]
                };
                apacheLogs.insert(log, function (err, result) {
                    if (err) {
                        console.log('log insert error:', err);
                    } else {
                        console.log(i + ':inserted');
                    }
                });
            } else {
                console.log(i + ':match error');
            }
            i++;
        }
    });
    stream.on('end', function () {
        db.close();
    });
});

参考にしたサイトや使用したライブラリ:

RegExp - Mdn https://developer.mozilla.org/ja/doc/Web/JavaScript/Reference/Global_Objects/RegExp

Read large text files in nodejs https://coderwall.com/p/ohjerg/read-large-text-files-in-nodejs

Node.js how to read one line of numbers from a file into an array http://stackoverflow.com/questions/7379310/node-js-how-to-read-one-line-of-numbers-from-a-file-into-an-array

npm line-reader https://github.com/nickewing/line-reader

npm node-byline https://github.com/jahewson/node-byline

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

Javascript(node.js)でExcelのシート一覧を出力する

node.jsはWindowsでもLinuxでも同じスクリプトが そこそこ安定して動くので嬉しい。

今回は、ExcelJSモジュールを使って、 Excelのシート一覧を出力するスクリプトを書いた。 リダイレクトでファイルに出力できる。 簡単なスクリプトだけど、こういうものを作っておくと必要な時にすぐ使えて便利。

output_excel_sheets.js

var Excel = require('exceljs');

var targetExcelPath = '<Excelファイルのパス>';

var workbook = new Excel.Workbook();
workbook.xlsx.readFile(targetExcelPath).then(function () {
    workbook.eachSheet(function (worksheet, sheetId) {
        console.log(worksheet.name);
    }); 
}); 

Node.jsとwebshotパッケージでWebサイトのスクリーンショットリスト作成を自動化する

Web開発を仕事にしていると

「マニュアルやプレゼンに使うのでWebアプリのスクリーンショットをくれ」

と依頼されることがよくある。

ChromeのFireshotのようなブラウザの拡張機能を使ったりすれば

1画面ずつ撮っていけるのだけど、

chrome.google.com

たくさんのページのスクリーンショットを、

変更がある度に撮り直すのは面倒なのでなんとか自動化したい。

「node-webshot」モジュールを使う

探してみると、

Node.jsの「node-webshot」パッケージを使えば

手軽にスクリーンショット撮影スクリプトが作れそうだ。

www.npmjs.com

Node.jsでWebKitブラウザの機能を利用可能にするPhantomJSの

スクリーンキャプチャ機能をラップしたものらしい。

PhantomJS | PhantomJS

PhantomJSはブラウザで行っている処理を

色々自動化するのに使えそうなので、また調査してみよう。

「node-webshot」パッケージは

下記のnpmコマンドでアプリにインストールできる。

npm install webshot --save-dev

URLのリストを作って、連続でスクリーンショットを撮るスクリプトを作成する

早速このwebshotパッケージを使って

スクリーンショット自動撮影スクリプトを作ってみる。

URLのリストを読み込んで

各URLのスクリーンショットを保存するようなものを作っておけば

画面に変更があってもコマンド1つで再作成できるので良さそうだ。

下記のようなスクリプトを作成してみた。

capture_screen.js

var webshot = require('webshot');
var fs = require('fs');

// 保存ファイル名とURLのリストを作成する
var baseUrl = 'http://test-domain.com';
var links = { 
    '01_login': baseUrl + '/login.html',
    '02_top': baseUrl + '/top.html',
    '03_shohin_list': baseUrl + '/shohin_list.html',
    '04_shohin_edit': baseUrl + '/shohin_edit.html'
};

// 各URLのスクリーンショットを指定したファイル名で「shots」フォルダに保存する
Object.keys(links).forEach(function (key) {
    var href = links[key];
    webshot(href, 'shots/' + key + '.png', {}, function () {}); 
}); 

URLリストの部分は撮影したいWebサイトのアドレスに合わせて変更する。

今回はデフォルトの設定で撮影を行っているが、

生成される画像のサイズ等はwebshot関数のオプションで指定できる。

サーバサイドJavaScript Node.js入門 (アスキー書籍)

サーバサイドJavaScript Node.js入門 (アスキー書籍)

  • 作者: 清水俊博,大津繁樹,小林秀和,佐々木庸平,篠崎祐輔,高木敦也,西山雄也,Jxck
  • 出版社/メーカー: KADOKAWA / アスキー・メディアワークス
  • 発売日: 2014/02/27
  • メディア: Kindle版
  • この商品を含むブログを見る

treeコマンドで出力したJSONをExcelで階層表示できるように変換する

あるプロジェクトのソース分析を行う必要があったので、

まずはソースファイルの一覧をExcelに出力してみることにした。

treeコマンドがいい感じで階層出力してくれるのだけど、

それをそのままExcelに持っていくと文字化けするので、

treeコマンドから一旦JSON形式で階層情報を出力し、

それをnodejsスクリプトで変換してcsvに出力する方法をとった。

treeコマンドで「-J」オプションを指定するとJSON形式で出力してくれる。

$ cd <プロジェクトディレクトリ>
$ tree -J &gt; file_tree.json

こうやって出力したjsonを下記のスクリプトでCSVにコンバートする。

階層毎に列がインデントされるようにして、

Excel上で拡張子でフィルタリングできるようにファイルの拡張子を出力する。

filetree2csv.js

//treeから出力したJSONをrequireで読み込み
var fileTreeJson = require('./file_tree.json');
var path = require('path');

//カンマの繰り返し出力のためのfunctionをStringに追加
String.prototype.repeat = function (num) {
    for (var str = ''; (this.length * num) > str.length; str += this);
    return str;
};

var parseFileList = function (level, fileNo, fileList) {
    fileList.forEach(function (file) {
        if (file.type != 'report') {
            var line = ''; 
            var type = ''; 
            if (file.type == 'file') {
                fileNo += 1;
                line += fileNo;
                type = path.extname(file.name);
            } else {
                type = 'dir';
            }   
            line += ',' + type;
            line += ','.repeat(level) + file.name;
            console.log(line);
            if (file.type == 'directory') {
                fileNo = parseFileList(level + 1, fileNo, file.contents);
            }   
        }   
    }); 
    return fileNo;
};

parseFileList(0, 0, fileTreeJson);

これを、下記のコマンドで実行する。

$ node filetree2csv.js > file_tree.csv

出力されたCSVをExcelで開き、タイトル行や罫線を整えたら、

ファイル一覧資料として使える。