続・ #prayforjapan を眺める

ようやく実家の両親とも電話が繋がるようになり、少し安心。あとは大船渡にいる親友の無事が確かめられれば良いのだけど…


祈りを込めて。


#prayforjapan を眺める - すぎゃーんメモから諸々変えた。
http://sugyan.no.de/prayforjapan
現時点で#prayforjapanタグの画像は10916件。
リアルタイム更新と別に、過去に投稿されたものも遡れるようにしてみた。
instagram APIからは特定タグの画像情報を20件ずつ取れるので、約500回叩かせてもらえば全件取得可能。最初はperlスクリプトでやろうとしてたけど折角なのでnodeで書いた。

var access_token = '**************************************************';
var https = require('https');
var fs    = require('fs');

function get_data(max_id) {
    https.get({
        host: 'api.instagram.com',
        path: '/v1/tags/prayforjapan/media/recent?access_token=' + access_token + (max_id ? '&max_id=' + max_id : '')
    }, function(res) {
        var body = '';
        res.on('data', function(data) {
            body += data;
        });
        res.on('end', function() {
            fs.writeFile('json/' + (max_id ? max_id : 'start') + '.json', body, function() {
                var obj = JSON.parse(body);
                console.log(obj);
                setTimeout(function() {
                    get_data(obj.pagination.next_max_id);
                }, 1000);
            });
        });
        res.on('error', function() {
            console.log('failed:' + max_id);
        });
    })
};
get_data();

これで一度すべての#prayforjapan関連画像のjsonデータをローカルに保存できた。
ここから全データを舐めて、likesとcommentsを除外し、idの剰余で300個のファイルに振り分けた。1ファイルあたり30〜40件ずつ収まることになる。

var fs = require('fs');

var array = [];
fs.readdir('json', function(err, files) {
    for (var i = 0, l1 = files.length; i < l1; i++) {
        var data = fs.readFileSync('json/' + files[i], 'utf8');
        var obj = JSON.parse(data);
        var images = obj.data;
        for (var j = 0, l2 = images.length; j < l2; j++) {
            var image = images[j];
            delete image.likes;
            delete image.comments;
            if (! array[image.id % 300]) {
                array[image.id % 300] = {};
            }
            array[image.id % 300][image.id] = image;
        }
    }
    for (var i = 0, l = array.length; i < l; i++) {
        var data = Object.keys(array[i]).map(function(key) {
            return array[i][key];
        });
        fs.writeFileSync('data/' + (i < 100 ? '0' : '') + (i < 10 ? '0' : '') + i + '.json', JSON.stringify(data));
    }
});

出来上がった"000.json"〜"299.json"をtarで固めてno.deサーバにscp送信、サーバ側は以下のようにclientからのmessageを受け取ってローカルJSONファイルの情報を返すようにした。

var access_token = '*************************************';
var http = require('http');

var express = require('express');
var app = express.createServer();
app.set('view options', { layout: false });

var flg = false, recent;
app.post('/', function(req, res) {
    console.log('POST');
    if (! flg) {
        flg = true;
        require('https').get({
            host: 'api.instagram.com',
            path: '/v1/tags/prayforjapan/media/recent?access_token=' + access_token
        }, function(res) {
            var body = ""
            res.on('data', function(data) {
                body += data.toString();
            });
            res.on('end', function() {
                // console.log(body);
                recent = JSON.parse(body);
                socket.broadcast(recent);
                flg = false;
            });
        });
    }
    res.send(200);
});

app.get('/', function(req, res) {
    res.redirect('/prayforjapan');
});
app.get('/prayforjapan', function(req, res) {
    res.render('prayforjapan.ejs');
});
app.listen(80);

var fs     = require('fs');
var socket = require('socket.io').listen(app);
socket.on('connection', function(client) {
    if (recent) {
        client.send(recent);
    }
    client.on('message', function(msg) {
        if (! msg.match(/[012]\d\d/)) return;
        fs.readFile(process.env.HOME + '/data/' + msg + '.json', 'utf8', function(err, data) {
            client.send({ data: JSON.parse(data), append: true });
        });
    });
});

client側のjsではリアルタイム更新の受信の他、スクロールの再下端を検出してランダムな番号の過去データをサーバにリクエストするように。こちらは受け取ったときに下に追加するようにしている。

$(function() {
  var d1 = {}, d2 = {};
  var socket = new io.Socket();
  function onScroll() {
    if (document.body.scrollHeight == window.innerHeight + window.scrollY) {
      while (true) {
        var n = Math.floor(Math.random() * 300);
        var s = (n < 100 ? '0' : '') + (n < 10 ? '0' : '') + String(n);
        if (! d2[s]) break;
      }
      d2[s] = true;
      socket.send(s);
    }
  }
  socket.on("connect", function() {
    $(document).scroll(onScroll);
    onScroll();
  });
  socket.on("message", function(msg) {
    var method = msg.append ? "append" : "prepend";
    for (var l = msg.data.length - 1, i = l; i >= 0; i--) {
      var e = msg.data[i];
      if (! d1[e.id]) {
        d1[e.id] = 1;
        $("#images")[method]($("<a>").attr("href", e.link).attr("target", "_blank").html($("<img>").attr("src", e.images.thumbnail.url)));
      }
    }
  });
  socket.connect();
});

あとno.deでは普通にcronが使えたのでサーバに溜めてあるjsonファイルは上記スクリプトを組み合わせて毎分アップデートするようにしている。
コイツをミスっていたせいでちょっと動かなくなっていた orz 修正済み


世界の皆様、今日もたくさんの祈りをありがとうございました。明日はまた良い日でありますように。