ehentai tag translator

hover tag, show translation

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name        ehentai tag translator
// @namespace   Violentmonkey Scripts
// @match       https://exhentai.org/*
// @exclude-match https://exhentai.org/s/*
// @grant       GM_addStyle
// @grant       GM_xmlhttpRequest
// @grant       GM_getValue
// @grant       GM_setValue
// @version     1.1
// @author      -
// @description hover tag, show translation
// ==/UserScript==

/**
 * find node
 * if have node, define translation, css
 * add translation div
 */

const $ = s => document.querySelector(s);
const $$ = s => document.querySelectorAll(s);

main();

function fetch2(detail) {
    return new Promise((resolve, reject) => {
        detail.onload = resolve;
        detail.onerror = reject;
        GM_xmlhttpRequest(detail);
    });
}

async function updateDB(db) {
    console.info('[ehentai_tag_translator] updating translation database.');
    const DBversion = 6;
    const dbUrl = 'https://github.com/EhTagTranslation/Database/releases/latest/download/db.text.json';
    const remoteDB = await fetch2({ url: dbUrl, method: 'GET' }).then(rsp => JSON.parse(rsp.responseText)).catch(err => alert('failed to download tag database from github'));
    if (remoteDB.version !== DBversion) {
        // database changelog: https://github.com/EhTagTranslation/Database/wiki/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%BB%93%E6%9E%84%E7%89%88%E6%9C%AC%E4%BF%A1%E6%81%AF
        alert('EhTag Database version changed, please update script');
        return;
    }
    if (remoteDB.head.sha === db.sha) {
        return;
    }

    db.sha = remoteDB.head.sha;
    db.data = {};
    for (let data of remoteDB.data) {
        const key = data.namespace;
        db.data[key] = {};
        for (let subKey in data.data) {
            // needs name translation only
            const value = data.data[subKey]['name'];
            if (subKey !== value) {
                // ignore invalid translation
                db.data[key][subKey] = value;
            }
        }
    }
    console.info('[ehentai_tag_translator] translation database updated.');
    return db;
}

async function loadDB() {
    let db = GM_getValue('db', {});
    // update database after 7 days
    const expiration = 7 * 24 * 60 * 60 * 1000;
    if (db.lastUpdate === undefined) {
        db.lastUpdate = 0; // needs update
    }
    const expired = Date.now() - db.lastUpdate > expiration ? true : false;
    if (expired) {
        db = await updateDB(db);
        db.lastUpdate = Date.now();
        GM_setValue('db', db);
    }
    // console.log(db);
    return db;
}

function translateTagEl(el, translation) {
    const translationEl = document.createElement('div');
    translationEl.classList.add('eh-tag-translation');
    translationEl.innerText = translation;
    el.append(translationEl);
}

async function main() {
    let tagEls = $$('div[class^="gt"]');

    if (tagEls.length > 0) {
        // load db only if needs translation
        const db = await loadDB();
        const css = `
             .eh-tag-translation{
                 display:none;
                 position: absolute;
                 top: 20px;
                 left: 0;
                 z-index: 999;
                 background: #5f636b;
                 padding: 5px;
                 width: max-content;
                 max-width: 300px;
                 border-radius: 2px;
                 box-shadow: 1px 1px 2px 0 #0005;
                 transition-duration: 1000ms;
             }
             /*show translation in list page*/
             .gl3c > a > div{
                 overflow: inherit!important;
             }
             div.gt,
             div.gtl{
                 opacity: 1!important;
             }
             div.gt:hover .eh-tag-translation,
             div.gtl:hover .eh-tag-translation{
                 display: block;
             }
             .eh-tag-translation::before {
                 border: 5px solid transparent;
                 border-bottom-color: transparent;
                 border-bottom-color: #5f636b;
                 content: '';
                 top: -10px;
                 width: 0;
                 height: 0;
                 position: absolute;
             }
         `;
        GM_addStyle(css);
        for (let el of tagEls) {
            let arr;
            if (el.id === 'ehv-panel-btn') {
                continue;
            } else if (el.id !== '') {
                arr = el.id.replace('td_', '').split(':');
            } else if (el.title !== '') {
                arr = el.title.split(':');
            } else {
                console.log('tag not found in element', el);
                continue;
            }
            if (arr.length === 2) {
                const key = arr[0];
                const subKey = arr[1].replace('_', ' ');
                if(db.data[key]){
                    const translation = db.data[key][subKey];
                    if (translation) {
                        translateTagEl(el, translation);
                    } else {
                        console.log('[ehentai_tag_translator] translation not found:', { key, subKey });
                    }
                }else{
                    console.log('[ehentai_tag_translator] unknown tag type: ', key);
                }
            } else {
                console.log('[ehentai_tag_translator] unknown attribute:', arr);
            }
        }
    }
}