ehentai tag translator

hover tag, show translation

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

ستحتاج إلى تثبيت إضافة مثل Stylus لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتتمكن من تثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

(لدي بالفعل مثبت أنماط للمستخدم، دعني أقم بتثبيته!)

// ==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);
            }
        }
    }
}