[KissAnime] Captcha Solver

Saves initial responses to KissAnime captcha and auto-selects images if it knows the answer.

目前為 2018-07-08 提交的版本,檢視 最新版本

// ==UserScript==
// @name         [KissAnime] Captcha Solver
// @namespace    https://greasyfork.org/en/users/193865-westleym
// @author       WestleyM
// @version      2018.07.07.2
// @icon         http://kissanime.ru/Content/images/favicon.ico
// @description  Saves initial responses to KissAnime captcha and auto-selects images if it knows the answer.
// @grant        none
// @include      http://kissanime.ru/Special/AreYouHuman2*
// @require      http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// ==/UserScript==


//Global variables
var currentVersion = "2018.07.07";
var installText = "Thank you for installing [KissAnime] Captcha Solver!";
var updateText = "The Import/Export section disapearing has been fixed.\n\nIf you would like to help out your fellow users, I would be grateful if you could send me your solutions using the 'export' option.  I will verify it and compile a master list to publish.\n\nYou can reach me through GreasyFork @WestleyM or Reddit @WarriorSolution\nPlease report any bugs or issues!";
var $ = window.jQuery;
var words = [];
var undefinedWords = [];
var unknownwords = [];
var knownwords = [];
var matchfound = 0;
var dataurl = "";
var imageSrc = [];
var clickImage = [];
var count = 0;
var formVerify = document.getElementById("formVerify");
var impExpFlag = 0;
var wordImagePairs = {};
var wordsObj = {};

if (formVerify === null) {
    var link = document.getElementsByTagName("a");
    link = link[0];
    if (localStorage.getItem("lastDescriptions") != null) {
        wordsObj = JSON.parse(localStorage.getItem("lastDescriptions"));
        localStorage.removeItem(wordsObj.firstWord);
        localStorage.removeItem(wordsObj.secondWord);
        localStorage.removeItem("lastDescriptions");
        console.log("Deleted the last two entries");
    }
    console.log("Redirecting page. . . .");
    link.click();
}


if (formVerify != null) { //User is on the regular captcha page
    //Alert for initial install of the script
    if (localStorage.getItem("version") === null) {
        console.log(installText);
        localStorage.setItem("version", currentVersion);
    }

    //Alerts based on new updates
    if (localStorage.getItem("version") != currentVersion && localStorage.getItem("version") != null) {
        alert("(You will only see this message once per update)\n\n" + updateText);
        localStorage.setItem("version", currentVersion);
    }


    var imageElements = $("#formVerify").find("img").toArray(); //All images under the "formVerify" form
    var imageNumber = imageElements.length; //How many images are in the captcha
    words = Words();

    //Image onclick events
    imageElements.forEach(function(currentImage, imageIndex) {
        currentImage.onclick = function() {
            if (!localStorage.getItem("helpword")) { //Saves the solution to local storage
                localStorage.setItem(localStorage.getItem("helpWord"), ProcessImages()[imageIndex]);
                localStorage.removeItem("helpword");
            }

            if (count === 1) { //Changes text in the alert box
                alertBoxText.innerText = "Selections complete.  Loading next page. . . .";
            }

            if (unknownwords[1] !== undefined && count < 1) { //If there is a word that is not known it will ask for help.  This specific if statement will only activate after you've made your first selection and if the second is unknown.
                askForHelp(unknownwords[1]);
                count++;
            }
        }
    });

    //Message box creation
    var firstDiv = $("#formVerify").find("div").toArray()[0];
    firstDiv.style.cssText = "width:100%;"; //The box holding the information at the top was not wide enough originally

    var PElements = $(firstDiv).find("p").toArray();
    if (PElements.length === 2) {
        PElements[0].style.cssText = "opacity:0; height:0px; width:100%; line-height:0px; font-size:0px;";
    }
    if (PElements.length === 3) {
        PElements[0].style.cssText = "display: none;";
        PElements[1].style.cssText = "opacity:0; height:0px; width:100%; line-height:0px; font-size:0px;";
    }

    var thirdPElement = PElements[PElements.length-1];
    thirdPElement.style.cssText = "opacity:0; height:0px; width:100%; line-height:0px; font-size:0px;"; //Hides where it lists both selection choices.  This is to insure users select the images in the correct order.

    var alertBoxDiv = document.createElement("div"); //Creation of div element which will contain the below text element
    alertBoxDiv.style.cssText = "background:#518203; color:white; height:30px; width:100%; line-height:30px; text-align:center;";

    var alertBoxText = document.createElement("h3"); //Creation of text element which will say the descriptions of images the script doesn't know the answer to
    alertBoxText.innerText = "Checking data. . . .";
    alertBoxText.style.cssText = "background:#518203; color:white; height:100%; width:100%; text-align:center; font-size: 20px; margin-top:0px;";

    alertBoxDiv.insertAdjacentElement("afterbegin", alertBoxText); //Inserting "alertBoxText" into "alertBoxDiv" at the top
    thirdPElement.insertAdjacentElement("afterend", alertBoxDiv); //Placing "alertBoxDiv" at the end of "mainBlock"


    //Import/Export area
    var importExport = document.createElement("div");
    importExport.style.cssText = "display:block; background: #111111; color:white; width:970px; padding:2px; text-align:center; margin-left:auto; margin-right:auto; border:1px solid #2f2f2f;";
    importExport.id = "importExport";

    var impExpButton = document.createElement("p");
    impExpButton.style.cssText = "background:#518203; color:white; height:15px; width:960px; margin-top:5px; margin-bottom:5px; text-align:center; font-size: 15px; padding:5px; cursor:pointer;";
    impExpButton.innerText = "[+] Solution List Importing/Exporting";
    impExpButton.id = "impExpButton";

    var inputJSON = document.createElement("input");
    inputJSON.type = "text";
    inputJSON.name = "JSON input";
    inputJSON.id = "inputJSON";
    inputJSON.placeholder = "Paste solution here (will not overwrite existing solutions)";
    inputJSON.style.cssText = "display:none; width:50%; margin-left:auto; margin-right:auto; margin-bottom:5px;";

    var inputSubmit = document.createElement("div");
    inputSubmit.style.cssText = "display:none; background:#518203; color:white; height:20px; width:50%; margin-left:auto; margin-right:auto; margin-bottom:5px; border:1px solid #5a5a5a; cursor:pointer;";
    inputSubmit.innerText = "Submit";
    inputSubmit.id = "inputSubmit";

    var lineSeparator = document.createElement("div");
    lineSeparator.style.cssText = "display:none; background:#5f5f5f; height:3px; width:100%; margin-left:auto; margin-right:auto; margin-bottom:5px;";
    lineSeparator.id = "lineSeparator";

    var exportButton = document.createElement("div");
    exportButton.style.cssText = "display:none; background:#518203; color:white; height:20px; width:50%; margin-left:auto; margin-right:auto; margin-bottom:5px; border:1px solid #5a5a5a; cursor:pointer;";
    exportButton.innerText = "Export list";
    exportButton.id = "exportButton";

    var exportDirections = document.createElement("div");
    exportDirections.style.cssText = "display:none; background:#518203; color:white; height:20px; width:50%; margin-left:auto; margin-right:auto; margin-bottom:5px; border:1px solid #5a5a5a;";
    exportDirections.innerText = "Copy the below data: (triple click to select all)";
    exportDirections.id = "exportDirections";

    var exportBox = document.createElement("p");
    exportBox.style.cssText = "display:none; #111111; color:white; width:75%; margin-left:auto; margin-right:auto; margin-top:0px; margin-bottom:5px; text-align:center; font-size:10px; border:1px solid #2f2f2f; word-wrap: break-word; overflow:auto; max-height:500px;";
    exportBox.innerText = "";
    exportBox.id = "exportBox";

    importExport.insertAdjacentElement("afterbegin", impExpButton);
    importExport.insertAdjacentElement("beforeend", inputSubmit);
    inputSubmit.insertAdjacentElement("afterend", lineSeparator);
    lineSeparator.insertAdjacentElement("afterend", exportButton);
    exportButton.insertAdjacentElement("afterend", exportDirections);
    exportDirections.insertAdjacentElement("afterend", exportBox);
    impExpButton.insertAdjacentElement("afterend", inputJSON);
    document.getElementById("containerRoot").insertAdjacentElement("afterend", importExport);

    //Import/Export onclick events
    impExpButton.onclick = function() {
        if (impExpFlag === 0) {
            impExpButton.innerText = "[-] Solution List Importing/Exporting";
            inputJSON.style.display = "block";
            inputSubmit.style.display = "block";
            lineSeparator.style.display = "block";
            exportButton.style.display = "block";
            impExpFlag = 1;
        } else {
            impExpButton.innerText = "[+] Solution List Importing/Exporting";
            inputJSON.style.display = "none";
            inputSubmit.style.display = "none";
            lineSeparator.style.display = "none";
            exportButton.style.display = "none";
            exportDirections.style.display = "none";
            exportBox.style.display = "none";
            impExpFlag = 0;
        }
    }

    inputSubmit.onclick = function() {
        var inputData = inputJSON.value;

        try {
            var newCaptchaData = JSON.parse(inputData);
            Object.keys(newCaptchaData).forEach(function(current) {
                if (localStorage.getItem(current) === null) {
                    localStorage.setItem(current, newCaptchaData[current]);
                }
            });
            inputSubmit.innerText = "Submitted successfully!";
            console.log("Solution list has been updated.");
        }
        catch(err) {
            inputSubmit.innerText = "There was an issue.  Check the console.";
            console.log("Issue with list upload: " + err);
        }
    }

    exportButton.onclick = function() {
        //Grab data from local storage and convert to JSON string
        for (var i = 0; i < localStorage.length; i++) {
            if (localStorage.key(i) != "helpWord" && localStorage.key(i) != "lastDescriptions" && localStorage.key(i) != "version") {
                wordImagePairs[localStorage.key(i)] = localStorage.getItem(localStorage.key(i));
            }
        }
        var wordImagePairsJSON = JSON.stringify(wordImagePairs);
        exportBox.innerText = wordImagePairsJSON;

        exportDirections.style.display = "block";
        exportBox.style.display = "block";
    }

    //Avoid conflicts
    this.$ = this.jQuery = jQuery.noConflict(true);
    $(document).ready(function() {
        unknownwords = UnknownWords();
        knownwords = KnownWords();
        console.log("Unknown words: " + unknownwords);
        console.log("Known words: " + knownwords);
        if (unknownwords[0] != undefined) { //Ask for help with the first unknown word
            askForHelp(unknownwords[0]);
        }
        knownwords.forEach(function(word) {
            matchfound = 0;
            console.log("processing known word:" + word);
            ProcessImages().forEach(function(image,counter) { //Grabs known value from local storage and clicks the corresponding image
                console.log("counter: " + counter);
                if (localStorage.getItem(word) == image) {
                    console.log("found match for word " + word);
                    matchfound = 1;
                    $("[indexValue='" + counter + "']").click();
                } else if (counter === imageNumber-1 && matchfound === 0) {
                    location.reload();
                }
            });
        });
    });

    //Functions
    function askForHelp(word) { //Asks you to select an answer when the script doesn't know.
        alertBoxText.innerText = "Please select image: " + word;
        localStorage.setItem("helpWord", word);
    }

    function UnknownWords() { //Finds the words that the script doesn't know the answer to
        words.forEach(function(word) {
            if(!localStorage.getItem(word)) { //If the solution isn't found in the local storage, it will be added to the "unknownwords" array
                unknownwords.push(word);
            }
        });
        return unknownwords;
    }

    function KnownWords() { //Finds the words that the script knows the answer to
        words.forEach(function(word) {
            if(localStorage.getItem(word)) { //If solution is found in the local storage, it will be added to the "Knownwords" array
                knownwords.push(word);
            }
        });
        return knownwords;
    }

    function SaveWord(word, dataurl) {
        if(!localStorage.getItem(word)) {
            localStorage.removeItem(word);
            localStorage.setItem(word, dataurl);
        } else {
            localStorage.setItem(word, dataurl);
        }
    }

    function Words() { //Grabs span elements that are children of the "formVerify" form.  This will include the two sections saying what to select.  Ex: "cat, glasses, 0"
        var pElements = $("#formVerify").find("p").toArray();
        var finalPElement = pElements[pElements.length-1];
        var words = $(finalPElement).find("span").toArray();
        var firstDesc = words[0].innerText;
        var secondDesc = words[1].innerText;

        //Saves the descriptions to local Storage
        var lastDescriptions = { "firstWord":firstDesc, "secondWord":secondDesc };
        var DescJSON = JSON.stringify(lastDescriptions);
        localStorage.setItem("lastDescriptions", DescJSON);
        return [firstDesc, secondDesc];
    }

    function Images() {
        return $("[indexValue]").toArray();
    }

    function ConvertToDataUrl(img) {
        var canvas = document.createElement("canvas");
        canvas.width = img.width;
        canvas.height = img.height;
        var ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
        var dataURL = canvas.toDataURL("image/png");
        return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
    }

    function MinimiseDataUrl(dataUrl,jump) {
        var a = "";
        for(var i = 0; i < dataUrl.length; i=i+jump) {
            a += dataUrl.charAt(i);
        }
        return a;
    }

    function ProcessImages() {
        var imagedata = [];
        Images().forEach(function(image, counter) {
            dataurl = ConvertToDataUrl(image);
            imagedata.push(MinimiseDataUrl(MinimiseDataUrl(MinimiseDataUrl(dataurl, 5), 4), 3));
        });
        return imagedata;
    }
}