AtoZ Utilities DEV

Utilities that are frequently used in other scripts.

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greasyfork.org/scripts/404603/941646/AtoZ%20Utilities%20DEV.js

// ==UserScript==
// @name        AtoZ Utilities DEV
// @namespace   AtoZ
// @author      AlienZombie [2176352]
// @credit      Jox [1714547] {For using various concepts and pieces of code to achieve my objectives}
// @description Utilities that are frequently used in other scripts.
// @version     1.0.0.29
// @source      https://greasyfork.org/en/scripts/404603-atoz-utilities
// @grant       GM_getValue
// @grant       GM_setValue
// ==/UserScript==


initialize();

function initialize() {
    Number.prototype.format = function(n, x) {
        var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\.' : '$') + ')';
        return this.toFixed(Math.max(0, ~~n)).replace(new RegExp(re, 'g'), '$&,');
    };
}

const localStorageAPIKey = "AtoZ_apikey";
const localStorageDKKAPIKey = "dkkutils_apikey";
const tornPlayerIdCookieName = "uid";

var Logging = {
    Identifier: "*** AtoZ ***",
    Debugging: {
        Active: false,
        Identifier: "*** AtoZ DEBUG ***"
    }
}

var thisScriptName = "Utilities";
var tornAPIKey = null;
var tornPlayerId = getCookie(tornPlayerIdCookieName);

//#region General Purpose
var setCheckbox = function(origin) {
    createDebugLog(thisScriptName, "setCheckbox", " origin Id: " + origin.target.id + " value" + origin.target.checked ? "1" : "0")
    localStorage.setItem(origin.target.id, origin.target.checked ? "1" : "0");
    //GM_setValue(origin.target.id, origin.target.checked ? "1" : "0");
};

var setText = function(origin) {
    createDebugLog(thisScriptName, "setText", " origin Id: " + origin.target.id + " value" + origin.target.value)
    localStorage.setItem(origin.target.id, origin.target.value);
    //GM_setValue(origin.target.id, origin.target.value);
};

function Startup(needAPI, activateDebugging) {
    if (!validateEmpty(needAPI) && needAPI) {
        if (validateEmpty(tornAPIKey)) {
            requestAPIKey();
        }
    }

    if (!validateEmpty(activateDebugging) && activateDebugging) {
        Logging.Debugging.Active = activateDebugging;
    }
}

function validateEmpty(value) {
    if (!value || value === undefined || value == "undefined" || value === null || value == "null" || value === ""){
        return true;
    }
    else {
        return false;
    }
}

function verifyJSONString(JSONString) {
    let response = {
        isError: null,
        errorName: null,
        errorMessage: null,
        content: null
    };

    let json = null;

    if (validateEmpty(JSONString)) {
        response.isError = true;
        response.errorName = "EmptyString";
        response.errorMessage = "The JSON string is empty.";
        return response;
    }
    try {
        json = JSON.parse(JSONString);
    } catch (e) {
        response.isError = true;
        response.errorName = e.errorName;
        response.errorMessage = e.errorMessage;
        return response;
    }

    response.isError = false;
    response.content = json;
    return response;
}

function observeMutationsFull(root, callback, options) {
    if (!options) options = {
        childList: true
    };

    new MutationObserver(callback).observe(root, options);
}

function observeMutations(root, selector, runOnce, callback, options, callbackRemoval) {
    var ran = false;
    observeMutationsFull(root, function(mutations, me) {
        var check = $(selector);

        if (check.length) {
            if (runOnce) me.disconnect();

            ran = true;
            callback(mutations, me);
        } else if (ran) {
            ran = false;
            if (callbackRemoval) callbackRemoval(mutations, me);
        }
    }, options);
}

function ajax(pageFilter, callback) {
    let funcName = "ajax";

    $(document).ajaxComplete((event, xhr, settings) => {
        if (xhr.readyState > 3 && xhr.status == 200) {
            if (settings.url.indexOf("torn.com/") < 0)
            settings.url = "torn.com" + (settings.url.startsWith("/") ? "" : "/") + settings.url;
            var page = settings.url.substring(settings.url.indexOf("torn.com/") + "torn.com/".length, settings.url.indexOf(".php"));

            if (pageFilter && (page == pageFilter)) {
                var json, uri;

                let verifyJSON = verifyJSONString(xhr.responseText);
                createDebugLog(thisScriptName, funcName, "Ajax Json verify response:");
                logDebugObject(verifyJSON);
                if (verifyJSON.isError) {
                    createDebugLog(thisScriptName, funcName, "JSON Error: " + verifyJSON.errorName + " - " + verifyJSON.errorMessage + " ResponseText: " + xhr.responseText);
                    uri = getUrlParams(xhr.responseText);
                } else if (verifyJSON.content.error) {
                    createDebugLog(thisScriptName, funcName, "ajax Error: " + verifyJSON.content.error.code)
                    uri = getUrlParams(xhr.responseText);
                } else {
                    json = verifyJSON.content;
                }
    
                callback(page, json, uri, xhr, settings);
            }

            return null;
        }
    });
}

function getUrlParams(url, prop) {
    var params = {};
    var search = decodeURIComponent(((url) ? url : window.location.href).slice(window.location.href.indexOf('?') + 1));
    var definitions = search.split('&');

    definitions.forEach(function(val, key) {
        var parts = val.split('=', 2);
        params[parts[0]] = parts[1];
    });

    return (prop && prop in params) ? params[prop] : params;
}


//#endregion General Purpose

//#region API Key

function validateAPIKey(apiKey) {
    let funcName = "validateAPIKey";

    if (validateEmpty(apiKey)) {
        if (validateEmpty(tornAPIKey)) {
            createDebugLog(thisScriptName, funcName, "[failure]: " + apiKey);
            return null;
        }
        else {
            apiKey = tornAPIKey;
        }
    }

    if (apiKey.length != 16) {
        createDebugLog(thisScriptName, funcName, "[failure]: " + apiKey);
        return null;
    }

    createDebugLog(thisScriptName, funcName, "[success]: " + apiKey);
    return apiKey;
}

function storeAPIKey(apiKey) {
    let funcName = "storeAPIKey";

    createDebugLog(thisScriptName, funcName, "Checking key for storage")
    let apiVar = validateAPIKey(apiKey);

    if (validateEmpty(apiVar)) {
        createDebugLog(thisScriptName, funcName, "[failure]: " + apiVar);
        localStorage.removeItem(localStorageAPIKey);
    }
    else{
        localStorage.setItem(localStorageAPIKey, apiVar);
        createDebugLog(thisScriptName, funcName, "[success]: " + apiVar);
    }

    tornAPIKey = apiVar;
}

function clearAPIKey() {
    localStorage.removeItem(localStorageAPIKey);
    tornAPIKey = null;
    createDebugLog(thisScriptName, "clearAPIKey", "User API Key removed.")
}

function retrieveAPIKey() {
    let funcName = "retrieveAPIKey";

    createDebugLog(thisScriptName, funcName, "Check for local API Key")
    let apiVar = validateAPIKey(localStorage.getItem(localStorageAPIKey));
    if (!validateEmpty(apiVar)) {
        createDebugLog(thisScriptName, funcName, "[success]: " + apiVar);
        return apiVar;
    }
    
    //Maybe the user has DKK scripts, so use that key instead:
    createDebugLog(thisScriptName, funcName, "No local key, trying DKK key")
    apiVar = validateAPIKey(localStorage.getItem(localStorageDKKAPIKey));
    if (!validateEmpty(apiVar)) {
        storeAPIKey(apiVar);
        return apiVar;
    }

    createDebugLog(thisScriptName, funcName, "[failure]:" + apiVar);
    return null
}

function requestAPIKey() {
    let funcName = "requestAPIKey";

    tornAPIKey = retrieveAPIKey();
    if (validateEmpty(tornAPIKey)) {
        createDebugLog(thisScriptName, funcName, "No api key")
        let response = prompt("Enter your API key for the AtoZ script(s) to work: ");
        tornAPIKey = validateAPIKey(response);
        if (!validateEmpty(tornAPIKey)) {
            createDebugLog(thisScriptName, funcName, "[VALID] key obtained from user: " + tornAPIKey)
            storeAPIKey(tornAPIKey);
        } else {
            createDebugLog(thisScriptName, funcName, "[INVALID] key obtained from user: " + tornAPIKey)
            alert("The key you entered is invalid.\nWithout it, this script cannot work.\nRefresh to try again.")
        }
    }
}

//#endregion API Key

//#region Logging

function createFatalLog(scriptName, functionName, errorMessage) {
    console.log(Logging.Debugging.Identifier, "!!! FATAL ERROR !!! [", scriptName, "] - [", functionName, "] - ", errorMessage);
    throw new FatalError(errorMessage);
}

function createDebugLog(scriptName, functionName, debugMessage) {
    if (!Logging.Debugging.Active) {
        return;
    }

    console.log(Logging.Debugging.Identifier, " [", scriptName, "] - [", functionName, "] - ", debugMessage);
}

function logDebugObject(object) {
    if (!Logging.Debugging.Active) {
        return;
    }

    console.log(JSON.parse(JSON.stringify(object)));
}

function createLog(scriptName, functionName, message) {
    console.log(Logging.Identifier, " [", scriptName, "] - [", functionName, "] - ", message);
}

function logObject(object) {
    console.log(JSON.parse(JSON.stringify(object)));
}

//#endregion Logging

//#region Torn API

var tornAPIParts = {
    User: {
        Key: "user",
        Selections: {
            Ammo: "ammo",
            Attacks: "attacks",
            AttacksFull: "attacksfull",
            Bars: "bars",
            Basic: "basic",
            BattleStats: "battlestats",
            Bazaar: "bazaar",
            Cooldowns: "cooldowns",
            Crimes: "crimes",
            Discord: "discord",
            Display: "display",
            Education: "education",
            Events: "events",
            Gym: "gym",
            Hof: "hof",
            Honors: "honors",
            Icons: "icons",
            Inventory: "inventory",
            JobPoints: "jobpoints",
            Medals: "medals",
            Merits: "merits",
            Messages: "messages", 
            Money: "money", 
            Networth: "networth",
            Notifications: "notifications",
            Perks: "perks",
            PersonalStats: "personalstats",
            Profile: "profile",
            Properties: "properties",
            ReceivedEvents: "receivedevents",
            Refills: "refills",
            Revives: "revives",
            RevivesFull: "revivesfull",
            Stocks: "stocks",
            Timestamp: "timestamp",
            Travel: "travel",
            WeaponExp: "weaponexp",
            WorkStats: "workstats"
        }
    },
    Properties: {
        Key: "property",
        Selections: null
    },
    Faction: {
        Key: "faction",
        Selections: null
    },
    Company: {
        Key: "company",
        Selections: null
    },
    ItemMarket: {
        Key: "market",
        Selections: null
    },
    Torn: {
        Key: "torn",
        Selections: null
    }
}

function tornAPIRequest(part, selections, key) {
    let funcName = "tornAPIRequest";

    createDebugLog(thisScriptName, funcName, `Torn API request for Part: ${part} Player Id: ${tornPlayerId} Selections: ${selections}`);
    if (validateEmpty(key)) {
         key = tornAPIKey;
    }

    return new Promise((resolve, reject) => {

        GM_xmlhttpRequest({
            method: "GET",
            url: `https://api.torn.com/${part}/${tornPlayerId}?selections=${selections}&key=${key}`,
            onreadystatechange: function(response) {
                if (response.readyState > 3 && response.status === 200) {
                    createDebugLog(thisScriptName, funcName, "Torn API response received: ")
                    logDebugObject(response);
                    let verifyJSON = verifyJSONString(response.responseText);
                    createDebugLog(thisScriptName, funcName, "Torn API Json verify response:");
                    logDebugObject(verifyJSON);
                    if (verifyJSON.isError) {
                        createDebugLog(thisScriptName, funcName, "JSON Error: " + verifyJSON.errorName + " - " + verifyJSON.errorMessage + " ResponseText: " + response.responseText);
                        reject("JSON Error", response.responseText);
                        return;
                    }

                    resolve(verifyJSON.content);

                    if (verifyJSON.content.error) {
                        createDebugLog(thisScriptName, funcName, "Torn API Error: " + verifyJSON.content.error.code)
                        if (verifyJSON.content.error.code == 2) {
                            clearAPIKey();
                        }
                    }
                }
            },
            onerror: function(errorResponse) {
                createDebugLog(thisScriptName, funcName, "httpRequest Error: " + errorResponse);
                reject('httpRequest error.');
            }
        })
    }).catch(err => {
        createDebugLog(thisScriptName, funcName, "Promise Error: " + err);
    });
}

//#endregion Torn API

//#region Generic API

function genericAPIRequest(destUrl, requestMethod) {
    let funcName = "genericAPIRequest";

    createDebugLog(thisScriptName, funcName, `API request to ${destUrl}`);

    return new Promise((resolve, reject) => {
        GM_xmlhttpRequest({
            method: requestMethod,
            url: destUrl,
            headers:    {'Cookie': document.cookie},
            onload:     function (respData) {
                console.log('*****GET Resp')
                logDebugObject(respData);

                //TODO: Parse response properly and send back at least the status code as well

                resolve(respData.responseText);
            },
            onerror: function(errorResponse) {
                console.log('*****GET Error', errorResponse);
                reject('httpRequest error.');
            }
        })
    }).catch(err => {
        createDebugLog(thisScriptName, funcName, "Promise Error: " + err);
    });
}

//#endregion Generic API


//#region Cookies

function getCookie(cname) {
    var name = cname + "=";
    var ca = document.cookie.split(';');
    for(var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) == 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}

//#endregion