NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Anime-Loads AntiCaptcha // @namespace https://github.com/leumasme // @version 1.1.1 // @description Solve the Captcha on anime-loads.org // @author Temm // @match http*://*.anime-loads.org/media/* // @icon https://www.google.com/s2/favicons?domain=anime-loads.org // @grant none // @run-at document-body // @license MIT // @updateURL https://openuserjs.org/meta/Temm/Anime-Loads_AntiCaptcha.meta.js // @downloadURL https://openuserjs.org/install/Temm/Anime-Loads_AntiCaptcha.user.js // ==/UserScript== function log(m) { console.log(`%c[AC] ${m}`, "border: 3px solid red; border-radius: 7px; padding: 3px") } window.addEventListener("unhandledrejection", console.error) // Hook JQuery captcha function jQuery.fn.extend = new Proxy(jQuery.fn.extend, { apply: function (target, thisArg, argsList) { if (argsList[0].iC) { log("Captcha Hook deployed!") target.apply(thisArg, [{ iC: fakeIc }]) return; } return target.apply(thisArg, argsList); } }) // on done will trigger event (bind) "success.iC" // Result storage: // .captcha-holder > input[name="captcha-idhf"] : value = 0 // .captcha-holder > input[name="captcha-hf"] : value = <correct hash> function fakeIc() { let holder = this; console.trace(); log("Starting Solve...") let txt = document.createElement("p"); txt.innerText = "[AC] Solving Captcha..."; holder.append(txt); // Get async context (async () => { let idhf = document.createElement("input"); idhf.name = "captcha-idhf"; idhf.hidden = true; idhf.value = "0"; let hf = document.createElement("input"); hf.name = "captcha-hf"; hf.hidden = true; hf.value = await getSolvedCaptcha(); holder.empty(); holder.append(idhf) holder.append(hf) txt.innerText = "[AC] Getting Links..."; holder.append(txt); console.log("Holder is ",holder) onSuccess() })(); // silence .bind calls after iC; save success event for manual calling return { bind: function (evt, fun) { if (evt == "success.iC") onSuccess = fun; return this } } } let cached = null; async function getSolvedCaptcha() { if (cached != null) { let c = cached; cached = null setTimeout(()=>generateSolvedCaptcha().then(r => { log("Restored Cache with " + r) cached = r }), 250); log("Solved from Cache! "+c) return c; } else { // return await generateSolvedCaptcha() await new Promise(r=>setTimeout(r, 250)) return await getSolvedCaptcha(); } } async function generateSolvedCaptcha(depth = 0) { let hashes = await createCaptcha(); let pimgs = hashes.map(async (h) => { return await loadImage("https://www.anime-loads.org/files/captcha?cid=0&hash=" + h); }) let imgs = await Promise.all(pimgs); let base = imgs[0]; let diffs = []; for (let i = 1; i < 5; i++) { let diff = diffImages(base, imgs[i]); diffs.push(diff); // console.log(base, imgs[i]) // console.log(hashes[0], hashes[i]) // console.log(diff) } let sorted = [...diffs].sort((a, b) => b - a); // console.log(hashes, imgs, diffs, sorted) let correct; // If different set produces lower diff, base is correct let checkDiff = diffImages(imgs[1], imgs[2]); if (sorted[sorted.length - 1] > checkDiff * 100) { console.log("First elem! Check was " + checkDiff + " ; regular was " + sorted[sorted.length - 1]) correct = hashes[0]; } else { correct = hashes[diffs.indexOf(sorted[0]) + 1]; } log("Found Solution: " + correct) let serverCheck = await fetch("https://www.anime-loads.org/files/captcha", { method: "POST", body: "cID=0&pC=" + correct + "&rT=2", headers: { "X-Requested-With": "XMLHttpRequest", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", } }).then(t => t.text()) if (serverCheck != "1") { log("Failed - retrying ("+(depth+1)+")") if (depth > 3) { alert("Unable to solve in 3 tries :/\nAre you blocked?") throw new Error("Failed"); } else return await generateSolvedCaptcha(depth + 1); } log("Success!") return correct; } generateSolvedCaptcha().then(r => { log("Created Cache with " + r) cached = r }); /** * @returns {Promise<string[]>} */ function createCaptcha() { return fetch("https://www.anime-loads.org/files/captcha", { method: "POST", body: "cID=0&rT=1", headers: { "X-Requested-With": "XMLHttpRequest", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Accept": "application/json, text/javascript, */*; q=0.01" } } ).then(r => r.json()) } /** * @param {HTMLImageElement} img * @returns {number} */ function diffImages(ia, ib) { let ctxa = makeContext(); console.log("[AC] Drawing and Hashing...") ctxa.drawImage(ia, 0, 0); let da = ctxa.getImageData(0, 0, ia.width, ia.width); var ctxb = makeContext(); ctxb.drawImage(ib, 0, 0); let db = ctxb.getImageData(0, 0, ia.width, ia.width); let diff = 0; for (let x = 0; x < ia.width; x++) { for (let y = 0; y < ia.width; y++) { let ca = getColor(x, y, ia.width, da); let cb = getColor(x, y, ia.width, db); let oa = ca[3] / 255, ob = cb[3] / 255; let difr = Math.abs(ca[0] * oa - cb[0] * ob) let difg = Math.abs(ca[1] * oa - cb[1] * ob) let difb = Math.abs(ca[2] * oa - cb[2] * ob) let difa = Math.abs(ca[3] * oa - cb[3] * ob) diff += difr + difg + difb + difa } } console.log("[AC] Hashed!") return diff; } function makeContext() { // var ctx = new OffscreenCanvas(48, 48).getContext("2d"); let c = document.createElement("canvas"); c.width = 48; c.height = 48; c.style.display = "none"; document.body.appendChild(c); return c.getContext("2d"); } /** * @param {string} url * @returns {HTMLImageElement} */ function loadImage(url) { return new Promise((resolve, reject) => { fetch(url, { //"mode": "no-cors" }) .then((res) => res.blob()) .then((blob) => { let reader = new FileReader(); reader.onloadend = () => { console.log("[AC]: Image Reader Finished") let img = new Image(); img.onload = () => { resolve(img); } img.src = reader.result; } // console.log(blob); reader.readAsDataURL(blob); }) }); } // RGBA /** * * @param {number} x * @param {number} y * @param {number} width * @param {ImageData} img * @returns {[number, number, number, number]} */ function getColor(x, y, width, img) { // stackoverflow magic const red = y * (width * 4) + x * 4; let [r, g, b, a] = [red, red + 1, red + 2, red + 3]; return [img.data[r], img.data[g], img.data[b], img.data[a]]; };