[E/Ex]Switch

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

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Userscripts installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey installieren.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

(Ich habe bereits einen Benutzerstil Verwaltung, ich möchte ihn installieren!)

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