NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Joyreactor Get All Images From Post
// @namespace http://tampermonkey.net/
// @version 0.1.3
// @description allows to download all images from post as .tar file / дает возможность скачать все картинки из поста одним файлом в формате .tar
// @author Gertykhon
// @updateURL https://openuserjs.org/meta/Gertykhon/Joyreactor_Get_All_Images_From_Post.meta.js
// @include *reactor.cc*
// @include *joyreactor.cc*
// @include *jr-proxy.com*
// @grant GM_xmlhttpRequest
// @license MIT
// ==/UserScript==
(function () {
'use strict';
/*
* Leoric(@joyreactor.cc)
*/
try {
var posts = document.getElementsByClassName('post_content');
for (var i of posts) {
var imgdivs = i.getElementsByClassName('image');
if (imgdivs.length > 1) { //0 - включить в т.ч. в постах с единственной картинкой, 1 - только с 2мя и более
var a = document.createElement('a');
a.textContent = 'скачать картинки';
a.style = 'border:2px solid gray; padding:0px 4px 2px; cursor:pointer; ' +
'display:block; width:200px; text-align:center; font-weight: bold';
i.insertBefore(a, i.firstChild);
a.addEventListener('click', download, {
once: true
});
}
}
}
catch (err) {
console.log('JR Get Images: ' + err);
}
function download(event) {
var file, base64;
var tape = new Tar();
var imgdivs = event.target.parentNode.getElementsByClassName('image');
var links = [];
var data;
for (var j of imgdivs) {
if (j.firstElementChild.tagName == 'A') {
links.push(j.firstElementChild.getAttribute('href'));
}
else if (j.firstElementChild.tagName == 'IMG') {
links.push(j.firstElementChild.getAttribute('src'));
}
else if (j.firstElementChild.firstElementChild.tagName == 'A') {
links.push(j.firstElementChild.firstElementChild.getAttribute('href'));
}
}
event.target.textContent = 'в процессе...';
var l = 0;
for (var k of links) {
if (k.substring(0, 2) == "//") k = location.protocol + k;
GM_xmlhttpRequest({
method: "GET",
url: k,
headers: {
referer: k,
origin: k
},
responseType: "arraybuffer",
onload: function (resp) {
var imgurl = decodeURI(resp.finalUrl);
var fdata = new Uint8Array(resp.response);
var fname = imgurl.substring(imgurl.lastIndexOf('/') + 1).split('.');
l++;
file = tape.append('file_' + fname[0].substring(fname[0].lastIndexOf('-') + 1) + '.' + fname[1], fdata);
event.target.textContent = l + '/' + links.length;
if (l == links.length) {
var blob = new Blob([file], {
type: "application/tar"
});
event.target.textContent = 'готово';
event.target.setAttribute('download', fname[0].substring(0, fname[0].lastIndexOf('-')) + '.tar');
var objectURL = window.URL.createObjectURL(blob);
event.target.setAttribute('href', objectURL);
event.target.click();
//возможность сразу после скачивания убрать за собой
/*window.URL.revokeObjectURL(objectURL);
event.target.removeAttribute("href");
event.target.removeAttribute("download");*/
}
},
onerror: function (resp) {
console.log('Joyreactor Get Images: GM_xmlhttpRequest failed. ' + (resp.status ? resp.statusText : ''));
event.target.textContent = 'ошибка';
}
});
}
}
/*
* tar-js
* MIT (c) 2011 T. Jameson Little
*/
function Utils() {
this.clean = function (length) {
var i, buffer = new Uint8Array(length);
for (i = 0; i < length; i += 1) {
buffer[i] = 0;
}
return buffer;
};
this.extend = function (orig, length, addLength, multipleOf) {
var newSize = length + addLength,
buffer = this.clean((parseInt(newSize / multipleOf) + 1) * multipleOf);
buffer.set(orig);
return buffer;
};
this.pad = function (num, bytes, base) {
num = num.toString(base || 8);
return "000000000000".substr(num.length + 12 - bytes) + num;
};
this.stringToUint8 = function (input, out, offset) {
var i, length;
out = out || this.clean(input.length);
offset = offset || 0;
for (i = 0, length = input.length; i < length; i += 1) {
out[offset] = input.charCodeAt(i);
offset += 1;
}
return out;
};
this.uint8ToBase64 = function (uint8) {
var i,
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
output = "",
temp, length;
function tripletToBase64(num) {
var lookup = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
];
return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];
};
// go through the array every three bytes, we'll deal with trailing stuff later
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
output += tripletToBase64(temp);
}
// this prevents an ERR_INVALID_URL in Chrome (Firefox okay)
switch (output.length % 4) {
case 1:
output += '=';
break;
case 2:
output += '==';
break;
default:
break;
}
return output;
};
}
var utils = new Utils();
function Header() {
/*
struct posix_header { // byte offset
char name[100]; // 0
char mode[8]; // 100
char uid[8]; // 108
char gid[8]; // 116
char size[12]; // 124
char mtime[12]; // 136
char chksum[8]; // 148
char typeflag; // 156
char linkname[100]; // 157
char magic[6]; // 257
char version[2]; // 263
char uname[32]; // 265
char gname[32]; // 297
char devmajor[8]; // 329
char devminor[8]; // 337
char prefix[155]; // 345
// 500
};
*/
this.structure = [{
'field': 'fileName',
'length': 100
},
{
'field': 'fileMode',
'length': 8
},
{
'field': 'uid',
'length': 8
},
{
'field': 'gid',
'length': 8
},
{
'field': 'fileSize',
'length': 12
},
{
'field': 'mtime',
'length': 12
},
{
'field': 'checksum',
'length': 8
},
{
'field': 'type',
'length': 1
},
{
'field': 'linkName',
'length': 100
},
{
'field': 'ustar',
'length': 8
},
{
'field': 'owner',
'length': 32
},
{
'field': 'group',
'length': 32
},
{
'field': 'majorNumber',
'length': 8
},
{
'field': 'minorNumber',
'length': 8
},
{
'field': 'filenamePrefix',
'length': 155
},
{
'field': 'padding',
'length': 12
}
];
this.format = function (data, cb) {
var buffer = utils.clean(512),
offset = 0;
this.structure.forEach(function (value) {
var str = data[value.field] || "",
i, length;
for (i = 0, length = str.length; i < length; i += 1) {
buffer[offset] = str.charCodeAt(i);
offset += 1;
}
offset += value.length - i; // space it out with nulls
});
if (typeof cb === 'function') {
return cb(buffer, offset);
}
return buffer;
};
}
var header = new Header();
function Tar(recordsPerBlock) {
var recordSize = 512,
blockSize;
this.written = 0;
blockSize = (recordsPerBlock || 20) * recordSize;
this.out = utils.clean(blockSize);
this.append = function (filepath, input, opts, callback) {
var data,
checksum,
mode,
mtime,
uid,
gid,
headerArr;
if (typeof input === 'string') {
input = utils.stringToUint8(input);
}
else if (input.constructor !== Uint8Array.prototype.constructor) {
//console.log('Invalid input type');
throw 'Invalid input type. You gave me: ' + input.constructor.toString().match(/function\s*([$A-Za-z_][0-9A-Za-z_]*)\s*\(/)[1];
}
if (typeof opts === 'function') {
callback = opts;
opts = {};
}
opts = opts || {};
mode = opts.mode || parseInt('777', 8) & 0xfff;
mtime = opts.mtime || Math.floor(+new Date() / 1000);
uid = opts.uid || 0;
gid = opts.gid || 0;
data = {
fileName: filepath,
fileMode: utils.pad(mode, 7),
uid: utils.pad(uid, 7),
gid: utils.pad(gid, 7),
fileSize: utils.pad(input.length, 11),
mtime: utils.pad(mtime, 11),
checksum: ' ',
type: '0', // just a file
ustar: 'ustar ',
owner: opts.owner || '',
group: opts.group || ''
};
// calculate the checksum
checksum = 0;
Object.keys(data).forEach(function (key) {
var i, value = data[key],
length;
for (i = 0, length = value.length; i < length; i += 1) {
checksum += value.charCodeAt(i);
}
});
data.checksum = utils.pad(checksum, 6) + "\u0000 ";
headerArr = header.format(data);
var i, offset, length;
this.out.set(headerArr, this.written);
this.written += headerArr.length;
// If there is not enough space in this.out, we need to expand it to
// fit the new input.
if (this.written + input.length > this.out.length) {
this.out = utils.extend(this.out, this.written, input.length, blockSize);
}
this.out.set(input, this.written);
// to the nearest multiple of recordSize
this.written += input.length + (recordSize - (input.length % recordSize || recordSize));
// make sure there's at least 2 empty records worth of extra space
if (this.out.length - this.written < recordSize * 2) {
this.out = utils.extend(this.out, this.written, recordSize * 2, blockSize);
}
if (typeof callback === 'function') {
callback(this.out);
}
return this.out;
};
this.clear = function () {
this.written = 0;
this.out = utils.clean(blockSize);
};
}
/*function uint8ToString(buf) {
var i, length, out = '';
for (i = 0, length = buf.length; i < length; i += 1) {
out += String.fromCharCode(buf[i]);
}
return out;
}
function stringToUint8 (input) {
var out = new Uint8Array(input.length), i;
for (i = 0; i < input.length; i += 1) {
out[i] = input.charCodeAt(i);
}
return out;
}*/
// end of tar js
function Uint8ToString(u8a) {
var CHUNK_SZ = 0x8000;
var c = [];
for (var i = 0; i < u8a.length; i += CHUNK_SZ) {
c.push(String.fromCharCode.apply(null, u8a.subarray(i, i + CHUNK_SZ)));
}
return c.join("");
}
})();