[E/Ex]Switch

E/Ex-Hentai switch + HentaiVerse quick launch + e-hentai login-reward peek

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

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

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu betiği yüklemek için bir betik yöneticisi eklentisi yüklemeniz gerekecektir.

(Zaten bir betik yöneticim var, hadi yükleyelim!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name        [E/Ex]Switch
// @name:JP     [E/Ex]切替
// @name:zh-TW  E網 表/裏站切換
// @name:zh-CN  E网 表/里站切换
// @namespace   https://github.com/awdrrawd
// @version     1.1
// @description E/Ex-Hentai switch + HentaiVerse quick launch + e-hentai login-reward peek
// @description:zh-tw E網表/裏站切換,並在 exhentai 加上 HentaiVerse 按鈕與登入獎勵提示
// @description:zh-cn E网表/里站切换,并在 exhentai 加上 HentaiVerse 按钮与登入奖励提示
// @match       https://e-hentai.org/*
// @match       https://exhentai.org/*
// @icon        https://e-hentai.org/favicon.ico
// @grant       GM_xmlhttpRequest
// @grant       GM_getValue
// @grant       GM_setValue
// @connect     e-hentai.org
// @license     MIT
// ==/UserScript==
(function () {
    'use strict';

    /* =====================================================================
     * 0. 共用小工具
     * ===================================================================*/
    const $el = (tag, attrs) => {
        const element = document.createElement(tag);
        for (const key in attrs) {
            if (key === 'textContent') {
                element.textContent = attrs[key];
            } else {
                element.setAttribute(key, attrs[key]);
            }
        }
        return element;
    };

    // 語言偵測(沿用原本邏輯)
    const getButtonText = () => {
        const lang = navigator.language || navigator.userLanguage;
        const isTraditionalChinese = /^(zh-TW|zh-HK|zh-Hant)/.test(lang);
        const isSimplifiedChinese = /^(zh-CN|zh-Hans)/.test(lang);
        const isJapanese = /^ja/.test(lang);
        if (isTraditionalChinese) return '[E/Ex]切換';
        if (isSimplifiedChinese) return '[E/Ex]切换';
        if (isJapanese) return '[E/Ex]切替';
        return '[E/Ex]Switch';
    };

    /* =====================================================================
     * 1. 不顯示 [E/Ex]切換 按鈕的頁面清單
     * ===================================================================*/
    const SWITCH_EXCLUDED_PAGES = [
        { path: '/home.php' },
        { path: '/stats.php' },
        { path: '/hentaiathome.php' },
        { path: '/bitcoin.php' },
        { path: '/hathperks.php' },
        { path: '/exchange.php', params: { t: 'hath' } },
        { path: '/exchange.php', params: { t: 'gp' } },
        { path: '/logs.php', params: { t: 'credits' } },
        { path: '/logs.php', params: { t: 'karma' } },
        { path: '/toplist.php' },
        // /bounty.php 不論有沒有 ?act=tops / topt / tope 或根本沒有 query,一律排除
        { path: '/bounty.php' },
        { path: '/news.php' },
        // repo.e-hentai.org/bounty_post.php 不在 @match 範圍內,這裡列出僅供備查
    ];

    function matchesRule(rule) {
        const { pathname, search } = window.location;
        if (rule.path !== pathname) return false;
        if (!rule.params) return true;
        const params = new URLSearchParams(search);
        return Object.entries(rule.params).every(([k, v]) => params.get(k) === v);
    }

    function isSwitchExcludedPage() {
        return SWITCH_EXCLUDED_PAGES.some(matchesRule);
    }

    /* =====================================================================
     * 2. 建立導覽列按鈕的共用函式(改良版)
     * ===================================================================*/
    function addNavButton({ id, text, href = '#', onClick, title }) {
        if (document.getElementById(id)) return null; // 已存在就不重複插入
        const nb = document.getElementById('nb');
        if (!nb) {
            console.error('[E/Ex]Switch: 導覽列 #nb 未找到,無法添加按鈕');
            return null;
        }
        const a = $el('a', { id, href, textContent: text });
        if (title) a.title = title;
        if (onClick) {
            a.addEventListener('click', (e) => {
                e.preventDefault();
                onClick(e);
            });
        }
        const wrapper = $el('div');
        wrapper.appendChild(a);
        nb.appendChild(wrapper);
        return a;
    }

    /* =====================================================================
     * 3. [E/Ex]切換按鈕
     * ===================================================================*/
    function initSwitchButton() {
        if (isSwitchExcludedPage()) return;
        addNavButton({
            id: 'switch-btn',
            text: getButtonText(),
            onClick: () => {
                const currentUrl = window.location.href;
                const newUrl = currentUrl.startsWith('https://exhentai.org')
                    ? currentUrl.replace('https://exhentai.org', 'https://e-hentai.org')
                    : currentUrl.replace('https://e-hentai.org', 'https://exhentai.org');
                window.location.href = newUrl;
            },
        });
    }

    /* =====================================================================
     * 4. HentaiVerse 按鈕(只在 exhentai.org 顯示)
     * ===================================================================*/
    function initHentaiVerseButton() {
        if (location.hostname !== 'exhentai.org') return;
        if (isSwitchExcludedPage()) return; // 工具頁一律不加,跟 [E/Ex]切換 保持一致
        addNavButton({
            id: 'hv-btn',
            text: 'HentaiVerse',
            href: 'https://hentaiverse.org/',
            onClick: () => {
                if (typeof window.popUp === 'function') {
                    window.popUp('https://hentaiverse.org/', 1250, 720);
                } else {
                    const w = 1250, h = 720;
                    window.open(
                        'https://hentaiverse.org/',
                        '_hentaiverse',
                        `toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=${w},height=${h},left=${(screen.width - w) / 2},top=${(screen.height - h) / 2}`
                    );
                }
            },
        });
    }

    /* =====================================================================
     * 5.(選用)在 exhentai.org 也提示 e-hentai.org 的 HentaiVerse 登入獎勵
     * ===================================================================*/
    const EVENTPANE_CACHE_KEY = 'eex_eventpane_cache';
    const EVENTPANE_TTL_MS = 10 * 60 * 1000; // 10 分鐘節流

    function fetchHomeEventPaneHtml() {
        return new Promise((resolve, reject) => {
            if (typeof GM_xmlhttpRequest !== 'function') {
                reject(new Error('GM_xmlhttpRequest 未授權,無法跨網域讀取 e-hentai.org/home.php'));
                return;
            }
            GM_xmlhttpRequest({
                method: 'GET',
                url: 'https://e-hentai.org/home.php',
                onload: (res) => {
                    try {
                        const doc = new DOMParser().parseFromString(res.responseText, 'text/html');
                        const pane = doc.getElementById('eventpane');
                        resolve(pane ? pane.outerHTML : null);
                    } catch (e) {
                        reject(e);
                    }
                },
                onerror: reject,
            });
        });
    }

    /* =====================================================================
     * 執行
     * ===================================================================*/
    initHentaiVerseButton();
    initSwitchButton();
})();