The jonki

呼ばれて飛び出てじょじょじょじょーんき

Node.jsでGmailを監視してTwitterのプロフィール画像を動的に変更する

2014/06/1 コードを整理してgithubに置きました。

2014/05/13 メモ程度に書いた記事にブクマを多く頂いたので記事を補足します。


以前Postfixでメール受信をトリガーにTwitterの画像をImageMagickで動的に生成しました。ただちょっとpostfixを自前で用意するのは…というコメントを頂いたので、imapで新着メールを監視する方式に乗り換えました。これはNode.jsのinboxライブラリを使うとかなり簡単にできます。
できるものは前と同じで吹き出し部分に任意の文字を表示した画像を動的に生成し、Twitterの画像を書き換えます。
f:id:jonki:20140513231217p:plain
f:id:jonki:20140513232305p:plain

画像生成のトリガー例

メールを送りさえすれば良いので、色々な使い方が考えられると思います。私の場合はIFTTTのiOS locationとマニュアルによるメール送信を利用しています。

  • IFTTTであるエリアに入ったら
    • 帰ってきたなう、ディズニー楽しい等
  • メールを自分の好きなタイミングでマニュアルで送る
  • iBeaconと連携
  • 等々
ソースコード

依存するライブラリは下記のとおりです。すべてnpm installでは入ります。

下のプログラムでは受信したメールの件名をそのままTwitterのアイコンの吹き出しに利用しました。上記のinboxのgithubのページを参考に、他の値(CCやBody等)をサービスに応じて利用しても良いと思います。
また日本語は最初文字化けしたのですが、iconvパッケージをnpm installしただけ(プログラム内でrequireしていない!)で日本語も見れるようになりました。id:hecomiも同症状だったらしく、少し気持ち悪いですが解決したので良しとします。

 

 var gm = require('gm').subClass({ imageMagick: true });

 var inbox = require("inbox");
 var client = inbox.createConnection(false, "imap.gmail.com", {
     secureConnection: true,
     auth:{
         user: "your-email-address",
         pass: "your-email-password"
     }
 });

 client.connect();

 client.on("connect", function(){
   console.log("successfullly connected to server");
     client.openMailbox("INBOX", function(error, info){
         if(error) throw error;
         // client.listMessages(10, function(err, messages){
         //     messages.forEach(function(message){
         //         console.log(message.UID + ": " + message.title);
         //     });
         // });
     });
 });

 client.on('close', function (){
     console.log('DISCONNECTED!');
 });

 client.on("new", function(message){
     console.log("New incoming message " + message.title);
   if(message.from["address"] === "your-email-address") {
     GenerateImage(message.title);
   }
 });

 var twitterAPI = require('node-twitter-api');
 var twitter = new twitterAPI({
       consumerKey: 'xxxx',
       consumerSecret: 'yyyy',
       callback: 'http://yoururl.tld/something'
 });
 var accessToken = 'wwww';
 var accessTokenSecret = 'zzzz';

 function GenerateImage(text) {
   text = text || '';
   var x, y;
   if(text.length < 5) {
     x = 140;
     y = 160;
   } else if(text.length < 9){
     x = 140;
     y = 120;
     text = text.substr(0, 4) + "\n" + text.substr(4);
   }
   gm('pic/jonki.png')
     .font('font/setofont.ttf', 90)
     .drawText(x, y, text)
     .write("pic/jonki-out.png", function (err) {
       if(err) {
         console.log(err);
       } else {
         console.log("GenerateImage succeeded");
         console.log(text);
         twitter.updateProfileImage({'image' : 'pic/jonki-out.png'},
           accessToken,
           accessTokenSecret,
           function(error, data, response) {
             if(error) {
               console.log("failed updateProfileImage");
             } else {
               console.log("update profileImage succeed");
             }
           }
         );
       }
     });
 }