You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
doushio/upkeep/clean.js

147 lines
3.5 KiB

/* Deletes the original images and thumbnails of archived posts,
* leaving just the 'vint' thumbnail.
*/
var imgConfig = require('../imager/config'),
crypto = require('crypto'),
db = require('../db'),
etc = require('../etc'),
fs = require('fs'),
path = require('path'),
imager = require('../imager'),
tail = require('../tail'),
winston = require('winston');
function Recycler() {
this.tag = 'archive';
this.y = new db.Yakusoku(this.tag, db.UPKEEP_IDENT);
}
var R = Recycler.prototype;
R.recycle_post = function (post, cb) {
if (!post.image || !post.image.src || post.hideimg)
return cb(null);
var r = this.y.connect();
var image = post.image
var src = imager.media_path('src', image.src);
var toDelete = [];
if (image.thumb) {
toDelete.push(src);
src = imager.media_path('thumb', image.thumb);
}
if (image.realthumb) {
toDelete.push(imager.media_path('thumb', image.realthumb));
}
if (image.mid) {
toDelete.push(imager.media_path('mid', image.mid));
}
MD5_file(src, function (err, MD5) {
if (err) {
if (err.code == 'ENOENT')
winston.warn(src + " doesn't exist.");
else
winston.error(err);
return cb(null);
}
var dest = MD5 + path.extname(src);
var dest_path = imager.media_path('vint', dest);
etc.movex(src, dest_path, function (err) {
if (err)
return cb(err);
var m = r.multi();
var key = post.op ? 'post:' + post.num
: 'thread:' + post.num;
m.hdel(key, 'src');
m.hdel(key, 'thumb');
m.hdel(key, 'mid');
m.hset(key, 'vint', dest);
m.exec(function (err) {
if (err) {
// move it back
etc.movex(dest_path, src,
function (e) {
if (e)
winston.error(e);
return cb(err);
});
return;
}
toDelete.forEach(function (victim) {
fs.unlink(victim, function (err) {
if (err)
winston.error(err);
});
});
if (toDelete.length) {
var info = post.num + ': del ' +
toDelete.length;
winston.info(info);
}
cb(null);
});
});
});
};
R.recycle_thread = function (op, cb) {
op = parseInt(op, 10);
var reader = new db.Reader(this.y);
reader.get_thread(this.tag, op, {});
var do_post = this.recycle_post.bind(this);
reader.on('thread', function (thread) {
if (thread.immortal)
return cb(null);
// grrr, ought to stream
var posts = [thread];
reader.on('post', function (post) {
posts.push(post);
});
reader.on('endthread', function () {
tail.forEach(posts, do_post, cb);
});
reader.on('error', cb);
});
};
R.recycle_archive = function (cb) {
var key = 'tag:' + this.tag.length + ':' + this.tag;
var r = this.y.connect();
var do_thread = this.recycle_thread.bind(this);
r.zrange(key + ':threads', 0, -1, function (err, threads) {
if (err)
return cb(err);
tail.forEach(threads, do_thread, cb);
});
};
function MD5_file(path, callback) {
var stream = fs.createReadStream(path);
var hash = crypto.createHash('md5');
stream.once('error', function (err) {
stream.destroy();
callback(err);
});
stream.on('data', function (buf) {
hash.update(buf);
});
stream.on('end', function () {
stream.destroy();
/* grr stupid digest() won't give us a Buffer */
hash = new Buffer(hash.digest('binary'), 'binary');
callback(null, imager.squish_MD5(hash));
});
}
if (require.main === module) process.nextTick(function () {
var recycler = new Recycler;
recycler.recycle_archive(function (err) {
if (err) throw err;
recycler.y.disconnect();
process.exit(0);
});
});