E-Hentai - Color Results By Tags

Highlights galleries with tag flags using the color(s) of their own tag flags.

As of 2019-03-19. See the latest version.

// ==UserScript==
// @name         E-Hentai - Color Results By Tags
// @description  Highlights galleries with tag flags using the color(s) of their own tag flags.
// @match        https://e-hentai.org/*
// @match        https://exhentai.org/*
// @run-at       document-end
// @grant        GM_addStyle
// @version      0.0.1
// @namespace    https://greasyfork.org/users/2168
// ==/UserScript==

function process() {
    extractTargets().forEach((target,n) => {
        if (target.tags.length > 0) {
            const color = chooseColor(target.tags);
            target.item.style.backgroundColor = color;
            target.item.classList.add('eh-' + getBestForeground(color));
        } else {
            target.item.style.backgroundColor = null;
            target.item.classList.remove('eh-white,eh-black');
        }
        if (target.item.nodeName === 'TR')
            target.item.parentNode.appendChild(target.item);
        else
            target.item.style.order = n;
    });
}

function extractTargets() {
    // Compact & Extended
    const rows = document.querySelectorAll('.itg > tbody > tr');
    if (rows.length > 0) {
        const results = [ ...rows ] .map(row => ({
            item: row,
            tags: [ ...row.querySelectorAll('.gt[style*="color"]') ].map(tag => ({
                tag: tag.getAttribute('title'),
                color: tag.style.borderColor
            }))
        }));
        return results.filter(r => r.tags.length).concat(results.filter(r => !r.tags.length));
    }
    // Thumbnails
    const thumbs = document.querySelectorAll('.itg > .gl1t');
    if (thumbs.length > 0) {
        const results = [ ...thumbs ].map(thumb => ({
            item: thumb,
            tags: [ ...thumb.querySelectorAll('.gt') ].map(tag => ({
                tag: tag.getAttribute('title'),
                color: tag.style.borderColor
            }))
        }));
        return results.filter(r => r.tags.length).concat(results.filter(r => !r.tags.length));
    }
    // Minimal
    return [ ];
}

function chooseColor(tags) {
    const map = { };
    let max = 0;
    tags.forEach(tag => {
        map[tag.color] = (map[tag.color] || 0) + 1;
        max = Math.max(max, map[tag.color]);
    });
    return Object.keys(map)
        .filter(key => map[key] === max)[0];
}

function getBestForeground(color) {
    var parsedColor = null, div = null;
    try {
        div = document.createElement('div');
        div.style.color = color;
        document.body.appendChild(div);
        parsedColor = window.getComputedStyle(div).color.match(/(\d+)/g);
        parsedColor = [ parseInt(parsedColor[0], 10), parseInt(parsedColor[1], 10), parseInt(parsedColor[2], 10) ];
    } catch (e) {
        parsedColor = [ 255, 255, 255 ];
    } finally {
        if (div && div.parentNode)
            div.parentNode.removeChild(div);
    }
    var whiteDistance = Math.sqrt(Math.pow(255 - parsedColor[0], 2) + Math.pow(255 - parsedColor[1], 2) + Math.pow(255 - parsedColor[2], 2));
    var blackDistance = Math.sqrt(Math.pow(-parsedColor[0], 2) + Math.pow(-parsedColor[1], 2) + Math.pow(-parsedColor[2], 2));
    return (whiteDistance > blackDistance ? 'white' : 'black');
}

GM_addStyle(`
.eh-white * { color: white !important; }
.eh-black * { color: black !important; }
.eh-white .gt, .eh-white .gtl,
.eh-black .gt, .eh-white .gtl {
    color: black !important;
}
`);

process();