2ch
Version:
A JavaScript library for comfortable 2ch watching.
136 lines (121 loc) • 4.34 kB
JavaScript
(function() {
var EventEmitter2, Message, Thread, util, _,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
_ = require('lodash');
EventEmitter2 = require('eventemitter2').EventEmitter2;
util = require('./util');
Message = require('./message');
module.exports = Thread = (function(_super) {
__extends(Thread, _super);
function Thread(bbs, number, title) {
this.bbs = bbs;
this.number = number;
this.title = title != null ? title : '';
this.messages = [];
this.lastModified = null;
this.byteLength = 0;
this.lastIndex = 0;
this._ended = false;
}
Thread.prototype.isEnded = function() {
return this._ended;
};
Thread.prototype.toString = function() {
var m, rawStrings;
rawStrings = (function() {
var _i, _len, _ref, _results;
_ref = this.messages;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
m = _ref[_i];
_results.push(m.rawString);
}
return _results;
}).call(this);
return rawStrings.join('\n') + '\n';
};
Thread.prototype.update = function(done, force) {
var _this = this;
if (force == null) {
force = false;
}
return this.fetch(function(error, res) {
if (error) {
_this.emit('error', error);
return typeof done === "function" ? done(error) : void 0;
}
switch (res.status) {
case 200:
case 206:
return _this._updateOnSuccess(res, done);
case 302:
_this._ended = true;
_this.emit('end', _this.title);
return typeof done === "function" ? done(null, []) : void 0;
case 304:
if (_this.messages.length >= 1000) {
_this._ended = true;
_this.emit('end', _this.title);
}
return typeof done === "function" ? done(null, []) : void 0;
case 416:
_this.emit('reload', _this.title);
return _this.update(done, true);
default:
error = new Error("Unknown Status: " + res.status);
_this.emit('error', error);
return typeof done === "function" ? done(error) : void 0;
}
}, force);
};
Thread.prototype._updateOnSuccess = function(res, done) {
var messages, newMessages, rawMessages,
_this = this;
this.lastModified = res.headers['last-modified'];
if (res.status === 200) {
this.byteLength = res.body.byteLength;
this.messages = [];
this.emit('begin', this.title);
} else {
this.byteLength += res.body.byteLength;
}
rawMessages = res.body.text.trim().split('\n');
messages = rawMessages.map(function(m, i) {
return new Message(m, i + _this.messages.length + 1);
});
this.messages = this.messages.concat(messages);
newMessages = _.filter(this.messages, function(m) {
return m.number > _this.lastIndex;
});
this.lastIndex = this.messages.length;
this.emit('update', newMessages);
if (_.isEmpty(newMessages) && this.messages.length >= 1000) {
this._ended = true;
this.emit('end', this.title);
}
return typeof done === "function" ? done(null, newMessages) : void 0;
};
Thread.prototype.fetch = function(done, force) {
var req, url;
if (force == null) {
force = false;
}
url = this.bbs.getThreadUrl(this.number);
req = util.requestGet(url);
if (force) {
req.set('Accept-Encoding', 'gzip');
} else {
req.set('Accept-Encoding', this.lastModified != null ? 'identify' : 'gzip');
if (this.lastModified) {
req.set('If-Modified-Since', this.lastModified);
}
if (this.byteLength > 0) {
req.set('Range', "bytes=" + this.byteLength + "-");
}
}
return req.end(done);
};
return Thread;
})(EventEmitter2);
}).call(this);