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(""); } })();