Xelion / Crypto Kitty Info Extension

// ==UserScript==
// @name         Crypto Kitty Info Extension
// @namespace    https://github.com/HaJaeKyung/KittyExtension
// @version      0.21
// @description  Adds stat info to the site
// @author       HaJaeKyung
// @match        *.cryptokitties.co/*
// @match        *.kittyexplorer.com/*
// @grant        none
// @require      http://code.jquery.com/jquery-3.2.1.min.js
// @license      MIT
// ==/UserScript==

document.searchSimilarKitties = function(e, query) {
    e.preventDefault();
    window.location.href = "https://www.cryptokitties.co/marketplace/sale" + query;
};
$(function() {
    console.log('CryptoKitties Extension Loaded');
    $("head").append("<style> .extAttUl { overflow: visible; z-index: 3;  padding: 0px; margin: 0px; } </style>");
    $("head").append("<style> .extAtt { padding-left: 2px; padding-right: 2px; color: rgb(42, 40, 37); text-align: center; line-height: 1.85rem; font-size: 1.6rem; border-style: solid; border-width: 2px; border-radius: 20px; background-color: #bbdefb; } </style>");
    $("head").append("<style> .extBounce {animation: mover 1s infinite  alternate; padding-right: 2px;} @keyframes mover {0% { transform: translateY(0); }100% { transform: translateY(-6px); } </style>");
    $("head").append("<style> .KittyCard { overflow: visible; } </style>");
    $("head").append("<style> .extWrapper {position:absolute; bottom: 0; right: 0; display: flex; flex-direction: row-reverse; align-items: flex-end; } </style>");

    var found = false;
    var foundId = [];
    var curCat = 'n/a';
    var curId = 'n/a';
    var url = location.href;
    document.body.addEventListener('click', function() {
        requestAnimationFrame(function() {
            if (url!==location.href) {
                //Clears id cache on page change
                foundId = [];
                url = location.href;
            }
        });
    }, true);
    var tbl = {
        "violet": { "count": 0.0001 },
        "googly": { "count": 0.06 },
        "mainecoon": { "count": 0.35 },
        "wingtips": { "count": 0.275 },
        "jaguar": { "count": 0.2 },
        "whixtensions": { "count": 0.49 },
        "cerulian": { "count": 0.8 },
        "chartreux": { "count": 0.95 },
        "fabulous": { "count": 1.5 },
        "gold": { "count": 1.9 },
        "peach": { "count": 2.1 },
        "bubblegum": { "count": 3.4 },
        "scarlet": { "count": 4 },
        "bloodred": { "count": 4.4 },
        "otaku": { "count": 4 },
        "dali": { "count": 4 },
        "skyblue": { "count": 4.7 },
        "emeraldgreen": { "count": 5.0 },
        "spock": { "count": 5.3 },
        "limegreen": { "count": 5.5 },
        "tigerpunk": { "count": 5.5 },
        "mauveover": { "count": 7.7 },
        "beard": { "count": 6 },
        "cloudwhite": { "count": 7.9 },
        "barkbrown": { "count": 7.9 },
        "laperm": { "count": 7.9 },
        "calicool": { "count": 7.9 },
        "cymric": { "count": 8.6 },
        "chestnut": { "count": 8.8 },
        "saycheese": { "count": 10.5 },
        "tongue": { "count": 10.5 },
        "shadowgrey": { "count": 14 },
        "coffee": { "count": 14 },
        "salmon": { "count": 14.7 },
        "royalpurple": { "count": 15.3 },
        "chocolate": { "count": 16.9 },
        "swampgreen": { "count": 17 },
        "mintgreen": { "count": 17.3 },
        "topaz": { "count": 17.3 },
        "lemonade": { "count": 17.4 },
        "orangesoda": { "count": 17.4 },
        "simple": { "count": 17.4 },
        "sphynx": { "count": 18 },
        "munchkin": { "count": 18 },
        "aquamarine": { "count": 18 },
        "raisedbrow": { "count": 18.6 },
        "greymatter": { "count": 18.8 },
        "happygokitty": { "count": 21 },
        "strawberry": { "count": 21.2 },
        "soserious": { "count": 21.6 },
        "ragamuffin": { "count": 21.8 },
        "sizzurp": { "count": 22.5 },
        "himalayan": { "count": 25 },
        "pouty": { "count": 25 },
        "crazy": { "count": 25 },
        "thicccbrowz": { "count": 25 },
        "luckystripe": { "count": 25 },
        "granitegrey": { "count": 25 },
        "kittencream": { "count": 25 },
        "totesbasic": { "count": 25 },
    };
    var hasLocalStorage = typeof(Storage) !== "undefined";
    var storageTbl = JSON.parse(localStorage.getItem('kittyExtensionTbl')) || {};
    var storageMyTbl = JSON.parse(localStorage.getItem('kittyExtensionMyTbl')) || {};

    function saveStorage(id, cattributes) {
        if (window.location.pathname == "/my-kitties") {
            storageMyTbl['id'+id] = cattributes;
            localStorage.setItem('kittyExtensionMyTbl', JSON.stringify(storageMyTbl));
        } else {
            storageTbl['id'+id] = cattributes;
            if (Object.keys(storageTbl).length > 1000) {
                for (var first in storageTbl) break;
                delete storageTbl[first];
            }
            localStorage.setItem('kittyExtensionTbl', JSON.stringify(storageTbl));
        }
    }

    function getColor(catt) {
        var color, count;
        if (tbl[catt]) {
            if (tbl[catt].count <= 2.5) {
                color = "#EC7063";
            } else if (tbl[catt].count < 10) {
                color = "#F7DC6F";
            } else if (tbl[catt].count <= 17) {
                color = "#48C9B0";
            } else if (tbl[catt].count <= 20) {
                color = "white";
            } else {
                color = "white";
            }
            count = tbl[catt].count <= 20 ? " ("+ tbl[catt].count +"%)" : " (20%+)";
        } else {
            color = "#f1cbff";
            count = " (Ultra%)";
        }
        return [color, count];
    }

    function requestId(element, id, gen, fast) {
        $.getJSON( "https://api.cryptokitties.co/kitties/"+id, function( data ) {
            finalizeOverlay(data.cattributes, element, gen, id, fast);
            if (hasLocalStorage) {
                saveStorage(id, data.cattributes);
            }
        }).fail(function() {
            var ul = element.getElementsByClassName("extAttUl")[0];
            ul.classList.remove("extBounce");
            ul.innerHTML = "😿";
        });
    }

    function finalizeOverlay(cattributes, element, gen, id, fast) {
        var ul = element.getElementsByClassName("extAttUl")[0];
        ul.classList.remove("extBounce");
        ul.innerHTML = "";
        for (var x in cattributes) {
            if (cattributes[x]) {
                ul.innerHTML += "<li class='extAtt' style=\'background-color:"+getColor(cattributes[x])[0]+"\'>"+cattributes[x]+"</li>";
            }
        }

        if (window.location.hostname == 'www.cryptokitties.co') {
            calcPrice(id , cattributes, gen, element, fast);
        }
    }

    function isValidId(id) {
      return !isNaN(id) && id !== "" && id.substring(0,2) != "0x" && id != curId && !foundId.includes(id) && !document.URL.includes("activity");
    }

    //Creates overlay on hover
    function overlay() {
        var nativeElement = $( this )[0];
        var id = /[^/]*$/.exec(nativeElement)[0];
        if (isValidId(id)) {
            curId = id;
            foundId.push(id);
            var mainSite = window.location.hostname == 'www.cryptokitties.co';
            var element = mainSite ? nativeElement.children[0].children[0] : nativeElement;
            if (element) {
                var fast = false;
                var gen = false;
                if (mainSite) {
                    if (nativeElement.children[0].children[1].children[2].innerText) {
                    var cdTbl = ["Fast", "Swift", "Snappy", "Brisk", "Plodding", "Slow", "Sluggish", "Catatonic"];
                    fast = cdTbl.indexOf(nativeElement.children[0].children[1].children[2].innerText);
                    }
                    gen = nativeElement.children[0].children[1].children[1].innerText.split('Gen ').pop();
                }
                element.innerHTML += "<div class='extWrapper'><ul style='list-style: none;' class='extBounce extAttUl'>🐈</ul></div>";
                if ('id'+id in storageMyTbl) {
                    console.log('KittyExtension: Retrieved - '+ id);
                    finalizeOverlay(storageMyTbl['id'+id], element, gen, id, fast);
                } else if ('id'+id in storageTbl) {
                    console.log('KittyExtension: Retrieved - '+ id);
                    finalizeOverlay(storageTbl['id'+id], element, gen, id, fast);
                } else {
                    console.log('KittyExtension: Requesting - '+ id);
                    requestId(element, id, gen, fast);
                }
            }
        }
    }
    $( "body").on( "mouseover", "a", overlay);

    //Updates attributes on specific kitty page
    setInterval(function() {
        var curPage = document.getElementsByClassName("KittyHeader-details");
        if (curPage.length > 0 && curPage[0].innerHTML.substr(0, curPage[0].innerHTML.indexOf('</span>')) != curCat) {
            curCat = curPage[0].innerHTML.substr(0, curPage[0].innerHTML.indexOf('</span>'));
            if (document.getElementsByClassName("ListAttributes-item").length > 0) {
                var cattributes = document.getElementsByClassName("ListAttributes-item");

                for (var att in cattributes) {
                    if (cattributes[att].style) {
                        var catt = cattributes[att].innerText;
                        var arr = getColor(catt);
                        var color = arr[0];
                        var num = arr[1];
                        cattributes[att].style.backgroundColor = color;
                        cattributes[att].innerHTML += num;
                    }
                }
            }
        }
    }, 2000);

    function calcPrice(id, cattributes, gen, element, fast) {
        var base = "https://api.cryptokitties.co/auctions";
        var query = "?type=sale&limit=2&sorting=cheap&orderBy=current_price&orderDirection=asc&sorting=cheap&status=open&search=";
        var totalGen = ' gen:'+gen;
        if (gen >= 10) {
            totalGen += ' gen:'+(gen-1)+' gen:';
            totalGen += parseInt(gen)+1;
        }
        var search = totalGen + getBestRares(cattributes);

        $.getJSON( base+query+search, function( data ) {
            if (data.total > 0) {
                if (data.total == 1) {
                    if (data.auctions[0].kitty.id == id) {
                        renderPrice(element, 'Name your price', query + search, false);
                    } else {
                        renderPrice(element, (data.auctions[0].current_price/1000000000000000000).toFixed(2), query + search, true);
                    }
                } else {
                    for (var x in data.auctions) {
                        if (data.auctions[x] && data.auctions[x].kitty.id != id) {
                            renderPrice(element, (data.auctions[x].current_price/1000000000000000000).toFixed(2), query + search, fast < 3);
                            return;
                        }
                    }
                }
            } else {
                renderPrice(element, 'Name your price', query + search, false);
            }
        }).fail(function() {

        });
    }

    function renderPrice(element, price, url, fast) {
        if (price >= 50) {
            price = Math.ceil(price / 10) * 10;
            price += '+';
        } else if (fast) {
            price += '+';
        }
        var ul = element.getElementsByClassName("extWrapper")[0];
        ul.innerHTML += "<ul class='extAttUl' onclick='searchSimilarKitties(event, &quot;"+ url +"&quot;)'><li style='list-style: none;' class='extAtt'><span style='font-weight: 500;'>value:</span> " + price + "</li></ul>";
    }

    function getBestRares(cattributes, adjust) {
        var best = '';
        var hasRare = false;
        var count = adjust || 0;

        if (cattributes.length === 0) {
            hasRare = ' type:fancy';
        }
        for (var x in cattributes) {
            if (!tbl[cattributes[x]]) {
                best += ' ' + x;
                count += 2;
                hasRare = ' ' + x;
            }
        }
        for (var key in tbl) {
            if (cattributes.includes(key)) {
                best += ' ' + key;
                if (tbl[key].count <= 5) {
                    count += 2;
                    hasRare = ' '+key;
                } else if (tbl[key].count <= 17) {
                    count += 1.5;
                }
            }
            if (count >= 3) {
                return ' ' + best;
            }
        }
        return hasRare ? hasRare : '';
    }
});