Sleazy Fork is available in English.

E-Hentai - Color Results By Tags

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

As of 21.03.2019. See ბოლო ვერსია.

// ==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
// @version      0.0.3
// @namespace    https://greasyfork.org/users/2168
// ==/UserScript==

function process() {

    extractTargets().forEach(function(target,n) {
        if (target.colors.length > 0) {
            target.item.style.backgroundColor = applyOpacity(chooseColor(target.colors));
            target.item.classList.add('eh-highlighted');
        } else {
            target.item.style.backgroundColor = null;
            target.item.classList.remove('eh-highlighted');
        }
        if (target.item.nodeName === 'TR')
            target.item.parentNode.appendChild(target.item);
        else
            target.item.style.order = n;
    });

    // Reposition header row if necessary (only needed for compact mode)
    var header = document.querySelector('.eh-highlighted + tr > th');
    if (header) header.parentNode.parentNode.insertBefore(header.parentNode, header.parentNode.parentNode.firstChild);

}

function extractTargets() {
    var targets = qSA('.itg > tbody > tr, .itg > .gl1t');
    var highlighted = [ ], ignored = [ ];
    targets.forEach(function(target) {
        var tags = qSA('.gt[style*="color"]', target);
        if (tags.length === 0) ignored.push({ item: target, colors: [ ] });
        else {
            var colors = [ ];
            tags.forEach(function(tag) { colors.push(extractColor(tag)); });
            highlighted.push({ item: target, colors: colors });
        }
    });
    return highlighted.concat(ignored);
}

/*------------------
  Color Manipulation
  ------------------*/

// Extracts the background color of a given tag (always picks the lighter color in the gradient)
function extractColor(element) {
    try {
        var background = element.style.background.replace(/\s/g, '');
        var colors = background.match(/rgb\(\d+,\d+,\d+\)/g)
            .concat(background.match(/rgba\(\d+,\d+,\d+,\d+\)/g))
            .concat(background.match(/#[0-9a-f]{2,8}/));
        if (colors.length < 2) return parseColor(element.style.borderColor);
        var parsed = [ parseColor(colors[0]), parseColor(colors[1]) ];
        var distance1 = distance(parsed[0], [ 255, 255, 255 ]);
        var distance2 = distance(parsed[1], [ 255, 255, 255 ]);
        return (distance1 < distance2 ? parsed[0] : parsed[1]);
    } catch (e) {
        return parseColor(element.style.borderColor);
    }
}

// Chooses which color to assign to the item/row (based on color weights)
function chooseColor(colors) {
    var map = { };
    var max = 0;
    colors.forEach(function(color) {
        var key = color.join(',');
        if (!map.hasOwnProperty(key)) map[key] = [ color, 1 ];
        else ++map[key][1];
        max = Math.max(max, map[key][1]);
    });
    var result = Object.keys(map)
        .filter(function(key) { return map[key][1] === max; })[0];
    return map[result][0];
}

// Parses a color into a numeric list of 3 elements from 0 to 255
function parseColor(color) {
    try {
        color = color.replace(/\s/g, '').trim();
        var tokens = color.match(/^rgba?\((\d+),(\d+),(\d+)(?:,[\d.]+)?\)/i);
        if (tokens) return [ parseInt(tokens[1], 10), parseInt(tokens[2], 10), parseInt(tokens[3], 10) ];
        if (/^#[0-9a-f]{3,3}$/.test(color)) color = color + color.slice(1);
        var hex = color.match(/^#([0-9a-f]{2,2})([0-9a-f]{2,2})([0-9a-f]{2,2})/i);
        if (hex) return [ parseInt(tokens[1], 16), parseInt(tokens[2], 16), parseInt(tokens[3], 16) || 255 ];
    } catch (e) {
        return [ 255, 255, 255 ];
    }
}

// Calculates the Euclidean distance between two colors
function distance(from, to) {
    return Math.sqrt(Math.pow(from[0] - to[0], 2) + Math.pow(from[1] - to[1], 2) + Math.pow(from[2] - to[2], 2));
}

// Applies opacity to a given background color
function applyOpacity(color) {
    var opacity = 0.6;
    var result = color.map(function(c) { return Math.round(c + (255 - c) * (1 - opacity)); });
    return 'rgb(' + result.join(',') + ')';
}

/*---------
  Utilities
  ---------*/

function qSA(query, parent) {
    if (!parent) parent = document;
    return [].slice.call(parent.querySelectorAll(query));
}

/*--------------
  Initialization
  --------------*/

var style = document.createElement('style');
style.innerHTML = '.eh-highlighted * { color: black !important; }' +
    '.eh-highlighted .glname:hover > a { color: #333333 !important; }';
document.head.appendChild(style);

process();