NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Tumblr posts downloader // @author book777 // @namespace niknikolia@yahoo.com // @updateURL https://pastebin.com/raw/UFNzeTuE // @version 181209.1 // @description Use keys: s - Download and remove posts, c - Start autodownload and remove posts, v - Stop autodownload, q - Go to top, a - Go to footer // @match https://*.tumblr.com/* // @run-at document-end // @license MIT // @require http://danml.com/js/download.js // @grant window.close // ==/UserScript== //todo support text console.clear(); document.book777 = { keybinds: { runsingle: 83, // s runauto: 67, // c runstop: 86, // v gotop: 81, // q gofooter: 65, // a }, schedule: { add: 1000, // [msec (1000 = 1 sec)] Autoadd files add to queue duration download: 2000, // [msec] Duration for move files from queue to active download rawFileClose: 300, // [msec] Close window timeout for raw files. If a page resets itself indefinitely, you must to increase value. filesPer: 4, // How many files will be taken from queue queueMax: 20, // Max files in queue _queue: [], // struct {url: string, name: string} _active: [], // struct {url: string, name: string} _checker: null, _adder: null, }, }; //todo mark posts as scanned function scheduleChecker() { if (document.book777.schedule._checker === null) { document.book777.schedule._checker = setInterval(function () { // Move files from queue to active for (let i = 0; i < document.book777.schedule._queue.length && document.book777.schedule._active.length < document.book777.schedule.filesPer; ++i) { document.book777.schedule._active.push(document.book777.schedule._queue.shift()); } console.log(`[B] Scheduler: ${document.book777.schedule._queue.length} in queue, ${document.book777.schedule._active.length} downloading`); // Download all active while (document.book777.schedule._active.length > 0) { let file = document.book777.schedule._active.pop(); getURLAndDownload(file.url, file.name); } }, document.book777.schedule.download); } } document.onkeyup = function (e) { // You can change the binds https://css-tricks.com/snippets/javascript/javascript-keycodes/ if (e.keyCode === document.book777.keybinds.runsingle) { console.log("[B] Add files to download queue and remove posts"); scheduleChecker(); postsDowloadAndRemove(); } if (e.keyCode === document.book777.keybinds.runauto) { console.log("[B] Start autodownload and remove posts"); scheduleChecker(); if (document.book777.schedule._adder === null) { document.book777.schedule._adder = setInterval(function () { postsDowloadAndRemove(); }, document.book777.schedule.add); } else { console.error("[B] Autostart already running"); } } if (e.keyCode === document.book777.keybinds.runstop) { console.log("[B] Stop autodownload and remove posts"); clearInterval(document.book777.schedule._adder); document.book777.schedule._adder = null; } if (e.keyCode === document.book777.keybinds.gotop) { console.log("[B] Go to top"); window.scrollTo(0, 0); } if (e.keyCode === document.book777.keybinds.gofooter) { console.log("[B] Go to footer"); window.scrollTo(0, document.body.scrollHeight); } } function postsDowloadAndRemove() { if (document.book777.schedule._queue.length >= document.book777.schedule.queueMax) { console.log("[B] So many files in queue"); return; } // Remove strange requests if (window.cedexis && window.cedexis.MP) { window.cedexis.MP = ''; } let posts = document.getElementById("posts").getElementsByClassName("post"); //.querySelectorAll(".post") // Update and back to same position if (posts.length <= document.book777.schedule.queueMax) { let sy = window.scrollY; window.scrollTo(0, 0); window.scrollTo(0, document.body.scrollHeight); setTimeout(function () { window.scrollTo(0, sy); }, 200); } for (let post of posts) { if (document.book777.schedule._queue.length >= document.book777.schedule.queueMax) { console.log("[B] Stop adding files to queue"); break; } if (post.classList.contains("new_post_buttons")) { // First block "post create" } else if (post.getAttribute('data-type') === 'photo' && tryGetPhoto(post) === true) { //post.classList.contains("is_photo") } else if (post.getAttribute('data-type') === 'photoset' && tryGetPhotoSet(post) === true) { } else if (post.getAttribute('data-type') === 'video' && tryGetVideo(post) === true) { //post.classList.contains("is_video") || post.classList.contains("is_direct_video") } else if (post.getAttribute('data-type') === 'regular') { // post.classList.contains("is_reblog") // Reblog must be last if (tryGetFigures(post) === true) { } else if (tryGetPhoto(post) === true) { } else if (tryGetPhotoSet(post) === true) { } else if (tryGetVideo(post) === true) { } else { console.error("[B] Unknown post format \\/\n", post); } } else { console.error("[B] Unknown post format \\/\n", post); } } } function getURLAndDownload(url, filename) { let xhr = new XMLHttpRequest(); xhr.open('get', url); xhr.responseType = 'blob'; xhr.onreadystatechange = function () { if (this.readyState == 4) { // ready if (this.status >= 200 && this.status < 400) { download(xhr.response, filename); } else if (this.status >= 400) { console.error(`[B] '${url}' have bad response code: ${this.status}`); } else { //if (this.status == 0 && xhr.response === null) console.log(`[B] open '${url}' in new window`); window.open(`${url}#name=${filename}`, '_blank') //debugger; } } }; xhr.send(); } function getURLAndDownloadFeature(url, filename) { let req = new Request(url); //, {mode: "no-cors"} https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#Parameters fetch(req). catch(err => function () {}). //cross origin fix then(function (response) { //debugger; if (response.status >= 200 && response.status < 400) { console.log(`[B] File '${url}' has been downloaded. Status '${response.status}'`); return response.blob(); } else if (response.status >= 400) { console.error(`[B] Bad response status ${response.status} for '${url}'`); } else { console.error(`[B] Open url in new tab '${url}'. Response:`, response); window.open(`${url}#name=${filename}`, '_blank'); //try to open raw file } }). then(function (data) { if (data !== undefined) { download(data, filename); } }). catch(error => function () { console.error('[B] Error:', error); }); //console.log("#", myRequest); } function addToQueue(url, file) { document.book777.schedule._queue.push({ url: url, name: file }); } function tryGetPhoto(postElement) { let photos = postElement.getElementsByClassName("post_media_photo"); let getSomething = false; for (let photo of photos) { //console.log("[B] get user post", photo.src); let extension = photo.src.split('.').pop(); addToQueue(photo.src, postElement.getAttribute('data-id') + ".photo." + extension); getSomething = true; } if (getSomething === true) { postElement.remove(); return true; } else { return false; } } function tryGetFigures(postElement) { //todo sometimes are videos let figures = postElement.getElementsByTagName("figure"); //let figures = post.getElementsByClassName("tmblr-full"); let getSomething = false; for (let figure of figures) { let photos = figure.getElementsByTagName("img"); for (let photo of photos) { //console.log("[B] User repost", photo.src); let extension = photo.src.split('.').pop(); addToQueue(photo.src, postElement.getAttribute('data-id') + ".reblog." + extension); getSomething = true; } } if (getSomething === true) { postElement.remove(); return true; } else { return false; } } function tryGetPhotoSet(postElement) { let photosets = postElement.getElementsByClassName("photoset"); let getSomething = false; for (let photoset of photosets) { let photos = photoset.getElementsByTagName("img"); for (let photo of photos) { //console.log("[B] User repost", photo.src); let extension = photo.src.split('.').pop(); addToQueue(photo.src, postElement.getAttribute('data-id') + ".photoset." + extension); getSomething = true; } } if (getSomething === true) { postElement.remove(); return true; } else { return false; } } function tryGetVideo(postElement) { let getSomething = false; let sources = postElement.getElementsByTagName("source"); for (let source of sources) { //console.log(`[B] Video ${source.src}`); let extension = source.getAttribute('type').split('/').pop(); addToQueue(source.src, postElement.getAttribute('data-id') + ".video." + extension); getSomething = true; } let posters = postElement.getElementsByTagName("video"); for (let poster of posters) { //console.log(`[B] Video poster ${source.src}`); let extension = poster.getAttribute('poster').split('.').pop(); addToQueue(poster.getAttribute('poster'), postElement.getAttribute('data-id') + ".poster." + extension); } if (getSomething === true) { postElement.remove(); return true; } else { return false; } } function checkStatusCode() { let xhr = new XMLHttpRequest(); xhr.open('get', location.href); xhr.onloadend = function () { if (this.status >= 400) { window.close(); } } xhr.send(); } checkStatusCode(); function checkRawFile() { if (document.body.firstChild.nodeName === "#text") { console.log('[B] script initialization...'); return } let fChild = document.body.firstChild.tagName.toLowerCase(); if (fChild === "div") { return; } if (fChild === "video") { downloadAndClose(window.location.href, (getQueryVariable('name') !== false ? getQueryVariable('name') : window.location.href.split('/').pop())); document.body.firstChild.pause(); } if (fChild === "img") { downloadAndClose(window.location.href, (getQueryVariable('name') !== false ? getQueryVariable('name') : window.location.href.split('/').pop())); } } checkRawFile(); function downloadAndClose(url, filename) { let xhr = new XMLHttpRequest(); xhr.open('get', url); xhr.responseType = 'blob'; xhr.onreadystatechange = function () { if (this.readyState == 4) { // ready if (this.status >= 200 && this.status < 400) { download(xhr.response, filename); setTimeout(function () { window.close(); }, document.book777.schedule.rawFileClose); // fix infinity reload } else { console.error(`[B] ${url} have code ${this.status}`, xhr.response); } } }; xhr.send(); } function getQueryVariable(variable) { var query = window.location.hash.substring(1); //remove '#' var vars = query.split("&"); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split("="); if (pair[0] === variable) { return pair[1]; } } return false; }