// スレッド内の表示されているすべてのレスに含まれる、キャッシュ済みの画像を保存します。
// 同じリンクが複数あった場合もすべて保存します。
// レス表示: ${SCRIPT:Frw} SaveImages.js
var options = {
// 保存先のディレクトリを指定
// 空文字列の場合は、<v2c.saveDir>/userdata/imagesに保存されます。
saveDirectory: "",
// {0}: レス番号, {1}: レス内の画像index, {2}: 画像のファイル名
fileNameFormatString: "{0}_{1}_{2}"
};
var util = (function() {
var scriptName = "SaveImages.js";
var format_ = function(formatString, args) {
if(!formatString || typeof formatString !== "string")
throw "引数 formatString を指定してください。";
return formatString.replace(/\{(\d)\}/g, function(m, c) {
return args[parseInt(c)];
});
};
return {
println: function(formatString /*, ...*/) {
var message = format_(formatString, Array.prototype.slice.call(arguments, 1));
v2c.println("[" + scriptName + "] " + message);
},
format: function(formatString /*, ...*/) {
return format_(formatString, Array.prototype.slice.call(arguments, 1));
}
};
})();
function getFilteredResponses() {
var thread = v2c.context.thread;
return Array.map(v2c.context.filteredResIndex, function(x) { return thread.getRes(x); });
}
function repeat(s, count) {
return new Array(count + 1).join(s);
}
function padLeft(x, ch, count) {
return (repeat(ch, count) + x).slice(-count);
}
function formatFileName(resIndex, n, count, original) {
return util.format(options.fileNameFormatString,
padLeft(resIndex, '0', 4),
padLeft(n, '0', String(count).length),
original);
}
function escape(s) {
return ('' + s).replace(/(?:\\|\/|\:|\*|\?|\"|<|>|\|)/g, '_');
}
var th = v2c.context.thread;
var saveDirectoryRoot = options.saveDirectory
|| v2c.saveDir.getPath() + "/userdata/images";
var saveDirectory = new java.io.File(saveDirectoryRoot,
util.format("{0}/[{1}] {2}", th.board.key, th.key, escape(th.title)));
var images = getFilteredResponses()
.reduce(function(a, x) {
var imageLinks = x.links.filter(function(x) {
return x.type_IMAGE && x.imageCacheFile;
});
return a.concat(imageLinks.map(function(link, i) {
var originalName = java.nio.file.Paths.get(link.url.getPath()).getFileName();
return {
res: x,
imageIndex: i,
imageLink: link,
fileName: formatFileName(x.number, i + 1, imageLinks.length, originalName)
};
}));
}, []);
if(0 < images.length) {
if(!saveDirectory.exists()) {
if(!saveDirectory.mkdirs())
throw '保存先ディレクトリの作成に失敗しました。';
}
images.forEach(function(x) {
var destFile = new java.io.File(saveDirectory, x.fileName);
var path = destFile.getPath();
if(destFile.exists()) {
util.println("既にファイルが存在するため、この項目を無視します: {0}", path);
return;
}
if(!v2c.copyFile(x.imageLink.imageCacheFile, path)) {
util.println("保存に失敗しました: {0}", path);
return;
}
//util.println("保存しました: {0}", path);
});
v2c.context.setStatusBarText("[SaveImages.js] 完了しました。");
} else {
v2c.context.setStatusBarText("[SaveImages.js] このスレッドにはキャッシュ済みの画像はありません。");
}
Ci8vIOOCueODrOODg+ODieWGheOBruihqOekuuOBleOCjOOBpuOBhOOCi+OBmeOBueOBpuOBruODrOOCueOBq+WQq+OBvuOCjOOCi+OAgeOCreODo+ODg+OCt+ODpea4iOOBv+OBrueUu+WDj+OCkuS/neWtmOOBl+OBvuOBmeOAggovLyDlkIzjgZjjg6rjg7Pjgq/jgYzopIfmlbDjgYLjgaPjgZ/loLTlkIjjgoLjgZnjgbnjgabkv53lrZjjgZfjgb7jgZnjgIIKLy8g44Os44K56KGo56S6OiAke1NDUklQVDpGcnd944CAU2F2ZUltYWdlcy5qcwoKdmFyIG9wdGlvbnMgPSB7CgkvLyDkv53lrZjlhYjjga7jg4fjgqPjg6zjgq/jg4jjg6rjgpLmjIflrpoKCS8vIOepuuaWh+Wtl+WIl+OBruWgtOWQiOOBr+OAgTx2MmMuc2F2ZURpcj4vdXNlcmRhdGEvaW1hZ2Vz44Gr5L+d5a2Y44GV44KM44G+44GZ44CCCglzYXZlRGlyZWN0b3J5OiAiIiwKCS8vIHswfTog44Os44K555Wq5Y+3LCB7MX06IOODrOOCueWGheOBrueUu+WDj2luZGV4LCB7Mn06IOeUu+WDj+OBruODleOCoeOCpOODq+WQjQoJZmlsZU5hbWVGb3JtYXRTdHJpbmc6ICJ7MH1fezF9X3syfSIKfTsKCnZhciB1dGlsID0gKGZ1bmN0aW9uKCkgewoJdmFyIHNjcmlwdE5hbWUgPSAiU2F2ZUltYWdlcy5qcyI7CgoJdmFyIGZvcm1hdF8gPSBmdW5jdGlvbihmb3JtYXRTdHJpbmcsIGFyZ3MpIHsKCQlpZighZm9ybWF0U3RyaW5nIHx8IHR5cGVvZiBmb3JtYXRTdHJpbmcgIT09ICJzdHJpbmciKQoJCQkJdGhyb3cgIuW8leaVsCBmb3JtYXRTdHJpbmcg44KS5oyH5a6a44GX44Gm44GP44Gg44GV44GE44CCIjsKCgkJcmV0dXJuIGZvcm1hdFN0cmluZy5yZXBsYWNlKC9ceyhcZClcfS9nLCBmdW5jdGlvbihtLCBjKSB7CgkJCXJldHVybiBhcmdzW3BhcnNlSW50KGMpXTsKCQl9KTsKCX07CglyZXR1cm4gewoJCXByaW50bG46IGZ1bmN0aW9uKGZvcm1hdFN0cmluZyAvKiwgLi4uKi8pIHsKCQkJdmFyIG1lc3NhZ2UgPSBmb3JtYXRfKGZvcm1hdFN0cmluZywgQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7CgkJCXYyYy5wcmludGxuKCJbIiArIHNjcmlwdE5hbWUgKyAiXSAiICsgbWVzc2FnZSk7CgkJfSwKCQlmb3JtYXQ6IGZ1bmN0aW9uKGZvcm1hdFN0cmluZyAvKiwgLi4uKi8pIHsKCQkJcmV0dXJuIGZvcm1hdF8oZm9ybWF0U3RyaW5nLCBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpKTsKCQl9Cgl9Owp9KSgpOwoKZnVuY3Rpb24gZ2V0RmlsdGVyZWRSZXNwb25zZXMoKSB7Cgl2YXIgdGhyZWFkID0gdjJjLmNvbnRleHQudGhyZWFkOwoJcmV0dXJuIEFycmF5Lm1hcCh2MmMuY29udGV4dC5maWx0ZXJlZFJlc0luZGV4LCBmdW5jdGlvbih4KSB7IHJldHVybiB0aHJlYWQuZ2V0UmVzKHgpOyB9KTsKfQoKZnVuY3Rpb24gcmVwZWF0KHMsIGNvdW50KSB7CglyZXR1cm4gbmV3IEFycmF5KGNvdW50ICsgMSkuam9pbihzKTsKfQpmdW5jdGlvbiBwYWRMZWZ0KHgsIGNoLCBjb3VudCkgewoJcmV0dXJuIChyZXBlYXQoY2gsIGNvdW50KSArIHgpLnNsaWNlKC1jb3VudCk7Cn0KCmZ1bmN0aW9uIGZvcm1hdEZpbGVOYW1lKHJlc0luZGV4LCBuLCBjb3VudCwgb3JpZ2luYWwpIHsKCXJldHVybiB1dGlsLmZvcm1hdChvcHRpb25zLmZpbGVOYW1lRm9ybWF0U3RyaW5nLAoJCXBhZExlZnQocmVzSW5kZXgsICcwJywgNCksCgkJcGFkTGVmdChuLCAnMCcsIFN0cmluZyhjb3VudCkubGVuZ3RoKSwKCQlvcmlnaW5hbCk7Cn0KCmZ1bmN0aW9uIGVzY2FwZShzKSB7CglyZXR1cm4gKCcnICsgcykucmVwbGFjZSgvKD86XFx8XC98XDp8XCp8XD98XCJ8PHw+fFx8KS9nLCAnXycpOwp9Cgp2YXIgdGggPSB2MmMuY29udGV4dC50aHJlYWQ7CnZhciBzYXZlRGlyZWN0b3J5Um9vdCA9IG9wdGlvbnMuc2F2ZURpcmVjdG9yeQoJfHwgdjJjLnNhdmVEaXIuZ2V0UGF0aCgpICsgIi91c2VyZGF0YS9pbWFnZXMiOwp2YXIgc2F2ZURpcmVjdG9yeSA9IG5ldyBqYXZhLmlvLkZpbGUoc2F2ZURpcmVjdG9yeVJvb3QsCgl1dGlsLmZvcm1hdCgiezB9L1t7MX1dIHsyfSIsIHRoLmJvYXJkLmtleSwgdGgua2V5LCBlc2NhcGUodGgudGl0bGUpKSk7Cgp2YXIgaW1hZ2VzID0gZ2V0RmlsdGVyZWRSZXNwb25zZXMoKQoJLnJlZHVjZShmdW5jdGlvbihhLCB4KSB7CgkJdmFyIGltYWdlTGlua3MgPSB4LmxpbmtzLmZpbHRlcihmdW5jdGlvbih4KSB7CgkJCXJldHVybiB4LnR5cGVfSU1BR0UgJiYgeC5pbWFnZUNhY2hlRmlsZTsKCQl9KTsKCgkJcmV0dXJuIGEuY29uY2F0KGltYWdlTGlua3MubWFwKGZ1bmN0aW9uKGxpbmssIGkpIHsKCQkJdmFyIG9yaWdpbmFsTmFtZSA9IGphdmEubmlvLmZpbGUuUGF0aHMuZ2V0KGxpbmsudXJsLmdldFBhdGgoKSkuZ2V0RmlsZU5hbWUoKTsKCgkJCXJldHVybiB7CgkJCQlyZXM6IHgsCgkJCQlpbWFnZUluZGV4OiBpLAoJCQkJaW1hZ2VMaW5rOiBsaW5rLAoJCQkJZmlsZU5hbWU6IGZvcm1hdEZpbGVOYW1lKHgubnVtYmVyLCBpICsgMSwgaW1hZ2VMaW5rcy5sZW5ndGgsIG9yaWdpbmFsTmFtZSkKCQkJfTsKCQl9KSk7Cgl9LCBbXSk7CgppZigwIDwgaW1hZ2VzLmxlbmd0aCkgewoJaWYoIXNhdmVEaXJlY3RvcnkuZXhpc3RzKCkpIHsKCQlpZighc2F2ZURpcmVjdG9yeS5ta2RpcnMoKSkKCQkJdGhyb3cgJ+S/neWtmOWFiOODh+OCo+ODrOOCr+ODiOODquOBruS9nOaIkOOBq+WkseaVl+OBl+OBvuOBl+OBn+OAgic7Cgl9CgoJaW1hZ2VzLmZvckVhY2goZnVuY3Rpb24oeCkgewoJCXZhciBkZXN0RmlsZSA9IG5ldyBqYXZhLmlvLkZpbGUoc2F2ZURpcmVjdG9yeSwgeC5maWxlTmFtZSk7CgkJdmFyIHBhdGggPSBkZXN0RmlsZS5nZXRQYXRoKCk7CgkJaWYoZGVzdEZpbGUuZXhpc3RzKCkpIHsKCQkJdXRpbC5wcmludGxuKCLml6Ljgavjg5XjgqHjgqTjg6vjgYzlrZjlnKjjgZnjgovjgZ/jgoHjgIHjgZPjga7poIXnm67jgpLnhKHoppbjgZfjgb7jgZk6IHswfSIsIHBhdGgpOwoJCQlyZXR1cm47CgkJfQoKCQlpZighdjJjLmNvcHlGaWxlKHguaW1hZ2VMaW5rLmltYWdlQ2FjaGVGaWxlLCBwYXRoKSkgewoJCQl1dGlsLnByaW50bG4oIuS/neWtmOOBq+WkseaVl+OBl+OBvuOBl+OBnzogezB9IizjgIBwYXRoKTsKCQkJcmV0dXJuOwoJCX0KCQkKCQkvL3V0aWwucHJpbnRsbigi5L+d5a2Y44GX44G+44GX44GfOiB7MH0iLOOAgHBhdGgpOwoJfSk7CgoJdjJjLmNvbnRleHQuc2V0U3RhdHVzQmFyVGV4dCgiW1NhdmVJbWFnZXMuanNdIOWujOS6huOBl+OBvuOBl+OBn+OAgiIpOwp9IGVsc2UgewoJdjJjLmNvbnRleHQuc2V0U3RhdHVzQmFyVGV4dCgiW1NhdmVJbWFnZXMuanNdIOOBk+OBruOCueODrOODg+ODieOBq+OBr+OCreODo+ODg+OCt+ODpea4iOOBv+OBrueUu+WDj+OBr+OBguOCiuOBvuOBm+OCk+OAgiIpOwp9