NH ↔ EH Crosslinker

Adds cross-links between nhentai and e-hentai/exhentai galleries

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         NH ↔ EH Crosslinker
// @namespace    github.com/longkidkoolstar
// @version      0.3.0
// @description  Adds cross-links between nhentai and e-hentai/exhentai galleries
// @author       longkidkoolstar
// @match        https://nhentai.net/g/*
// @match        https://e-hentai.org/g/*
// @match        https://exhentai.org/g/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @license      MIT
// @icon         https://i.postimg.cc/fb6L0sx9/e-h.png
// ==/UserScript==
(function () {
    'use strict';
    const url = location.href;

    // --- Settings & Menu ---
    const PREF_KEY = 'search_title_type';
    const PREF_DISPLAY = {
        'english': 'English',
        'romanized': 'Romanized',
        'japanese': 'Japanese'
    };

    function getPreferredTitleType() {
        return GM_getValue(PREF_KEY, 'english');
    }

    function setPreferredTitleType(type) {
        GM_setValue(PREF_KEY, type);
        location.reload();
    }

    // Register Menu Commands
    const currentType = getPreferredTitleType();
    GM_registerMenuCommand(`Search with English Title ${currentType === 'english' ? '✅' : ''}`, () => setPreferredTitleType('english'));
    GM_registerMenuCommand(`Search with Romanized Title ${currentType === 'romanized' ? '✅' : ''}`, () => setPreferredTitleType('romanized'));
    GM_registerMenuCommand(`Search with Japanese Title ${currentType === 'japanese' ? '✅' : ''}`, () => setPreferredTitleType('japanese'));

    // --- Title Logic ---
    function getTitle(site) {
        const type = getPreferredTitleType();
        let title = '';

        if (site === 'nhentai') {
            const h1 = document.querySelector('#info h1'); // Pretty/English/Romanized
            const h2 = document.querySelector('#info h2'); // Original/Japanese

            if (type === 'japanese' && h2 && h2.innerText.trim()) {
                title = h2.innerText;
            } else if (h1) {
                title = h1.innerText;
            }
        } else if (site === 'ehentai') {
            const gn = document.querySelector('#gn'); // English/Romanized
            const gj = document.querySelector('#gj'); // Japanese

            if (type === 'japanese' && gj && gj.innerText.trim()) {
                title = gj.innerText;
            } else if (gn) {
                title = gn.innerText;
            } else if (gj) {
                title = gj.innerText;
            }
        }
        
        return cleanTitle(title, type);
    }

    /* ---------------- NHENTAI → E-HENTAI ---------------- */
    if (url.includes('nhentai.net/g/')) {
        const title = getTitle('nhentai');
        if (!title) return;

        const artistEl = document.querySelector(
            '.tag-container.field-name a[href^="/artist/"] .name'
        );
        const artist = artistEl ? artistEl.textContent.trim() : '';
        let query = title;
        if (artist) query += ` artist:${artist}`;
        const ehUrl = 'https://e-hentai.org/?f_search=' + encodeURIComponent(query);
        addButton('#info', `🔗 Search on e-hentai (${PREF_DISPLAY[currentType]})`, ehUrl);
        return;
    }

    /* ---------------- E / EXHENTAI → NHENTAI ---------------- */
    if (url.includes('e-hentai.org/g/') || url.includes('exhentai.org/g/')) {
        const title = getTitle('ehentai');
        if (!title) return;

        const artistEl = document.querySelector(
            '#taglist a[href^="https://e-hentai.org/tag/artist:"]'
        );
        const artist = artistEl ? artistEl.textContent.trim() : '';
        let query = title;
        if (artist) query += ` ${artist}`;
        const nhUrl =
            'https://nhentai.net/search/?q=' + encodeURIComponent(query);
        addButton('#gd2', `🔗 Search on nhentai (${PREF_DISPLAY[currentType]})`, nhUrl);
    }

    /* ---------------- SWITCH e-hentai → exhentai ---------------- */
    if (
        url.startsWith('https://e-hentai.org/?') ||
        url.startsWith('https://e-hentai.org/?f_search=')
    ) {
        const exhUrl = url.replace('https://e-hentai.org/', 'https://exhentai.org/');
        addFloatingButton('🔄 Switch to exhentai', exhUrl);
    }

    /* ---------------- Helpers ---------------- */
    function cleanTitle(title, type) {
        if (!title) return '';
        // If title contains |, take only the left part
        if (title.includes('|')) {
            if (type === 'english') {
                // For English, take the right part
                title = title.split('|')[1];
            } else {
                // For others (e.g. Romanized), take the left part
                title = title.split('|')[0];
            }
        }

        // Remove bracketed content
        title = title.replace(/\[[^\]]*\]/g, '');

        // Remove numbers (standalone digits and sequences)
        title = title.replace(/\b\d+\b/g, '');

        // Clean up extra whitespace
        title = title.replace(/\s+/g, ' ').trim();

        return title;
    }

    function addButton(parentSelector, text, link) {
        const parent = document.querySelector(parentSelector);
        if (!parent) return;
        const a = document.createElement('a');
        a.href = link;
        a.target = '_blank';
        a.textContent = text;
        a.style.display = 'block';
        a.style.marginTop = '10px';
        a.style.fontSize = '16px';
        parent.appendChild(a);
    }

    function addFloatingButton(text, link) {
        const a = document.createElement('a');
        a.href = link;
        a.textContent = text;
        a.style.position = 'fixed';
        a.style.bottom = '20px';
        a.style.right = '20px';
        a.style.padding = '10px 14px';
        a.style.background = '#34353b';
        a.style.color = '#fff';
        a.style.borderRadius = '6px';
        a.style.fontSize = '14px';
        a.style.zIndex = '9999';
        a.style.textDecoration = 'none';
        document.body.appendChild(a);
    }
})();