forked from flanchan/doushio
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.
147 lines
3.5 KiB
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);
|
|
});
|
|
});
|