rrrrrrrrrriyjiiiiiuzhao / NGA安科

// ==UserScript==
// @name         NGA安科
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  安科用
// @author       rrrrrrrrrriyjiiiiiuzhao
// @match        https://ngabbs.com/read.php?*
// @match        https://nga.178.com/read.php?*
// @grant        none
// @license MIT
// ==/UserScript==


(function () {
    'use strict';

    // --- 环境检测 ---
    function isMobileView() {
        return !!document.querySelector('body.bodyVsmall');
    }

    // --- 通用功能 ---
    function angaToText(angas) {
        const result = []
        angas.forEach(element => {
            element.options.forEach(opt => {
                result.push(`${element.floor}:${element.author}:${opt}`)
            })
        });
        return `\n${result.join('\n')}\n`
    }

    function updateTextarea(content) {
        const textarea = document.querySelector('#fast_post_c textarea');
        if (textarea) {
            textarea.value = content;
            textarea.focus();
        }
    }

    function appendTextarea(content) {
        const textarea = document.querySelector('#fast_post_c textarea');
        if (textarea) {
            textarea.value += content;
            textarea.focus(
                
            );
        }
    }

    function floor2page(floor) {
        return Math.floor(floor / 20) + 1;
    }

    function page2floor(page) {
        return (page - 1) * 20;
    }

    function purifyContent(htmlNode) {
        const tempContainer = document.createElement('div');
        const clone = htmlNode.cloneNode(true);
        clone.querySelectorAll('*').forEach(node => {
            node.removeAttribute('onerror');
            node.removeAttribute('onload');
            if (node.tagName === 'SCRIPT') node.remove();
        });
        tempContainer.appendChild(clone);
        const quoteBlocks = tempContainer.querySelectorAll('div.quote');
        quoteBlocks.forEach(block => block.remove());
        const cleanHTML = tempContainer.innerHTML;
        tempContainer.remove();
        const textContainer = document.createElement('div');
        textContainer.innerHTML = cleanHTML;
        const text = textContainer.textContent.replace(/\s+/g, ' ').trim();
        textContainer.remove();
        return text;
    }

    function findAngaOptions(text) {
        const pattern = /安价[::]\s*((?:(?!安价[::])[\s\S])+)/gi;
        const matches = [];
        const segments = text.split(/(?=安价[::])/gi);
        segments.forEach(segment => {
            if (!segment.toLowerCase().startsWith('安价')) return;
            const match = segment.match(pattern);
            if (match) {
                const content = match[0].replace(/^安价[::]\s*/i, '').replace(/\s+/g, ' ').trim();
                if (content) {
                    matches.push(content);
                }
            }
        });
        return matches;
    }

    function showCustomPrompt(content) {
        // Prevent multiple prompts
        if (document.getElementById('angaCustomPrompt')) return;

        // Overlay
        const overlay = document.createElement('div');
        overlay.id = 'angaCustomPrompt';
        overlay.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            z-index: 9999;
            display: flex;
            justify-content: center;
            align-items: center;
        `;

        // Modal Box
        const modal = document.createElement('div');
        modal.style.cssText = `
            background-color: #fff8e7;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            width: 90%;
            max-width: 500px;
            display: flex;
            flex-direction: column;
            gap: 15px;
        `;

        // Title
        const title = document.createElement('h3');
        title.textContent = '安价结果 (长按复制)';
        title.style.cssText = `
            margin: 0;
            font-size: 18px;
            font-weight: normal;
            color: #591804;
            text-align: center;
        `;

        // Textarea for content
        const textarea = document.createElement('textarea');
        textarea.readOnly = true;
        textarea.value = content;
        textarea.style.cssText = `
            width: 100%;
            height: 200px;
            padding: 10px;
            border: 1px solid #bd7b68;
            border-radius: 4px;
            font-family: inherit; /* Inherit font from body */
            font-size: 16px; /* Match page font */
            font-weight: normal;
            line-height: 1.5;
            white-space: pre-wrap; /* Ensure line breaks are respected */
            word-wrap: break-word; /* Ensure long lines wrap */
            resize: none;
            box-sizing: border-box;
        `;

        // Close Button
        const closeButton = document.createElement('button');
        closeButton.textContent = '关闭';
        closeButton.style.cssText = `
            padding: 10px 20px;
            border: none;
            background-color: #bd7b68;
            color: #fff8e7;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            align-self: center;
        `;

        // Event Listeners
        closeButton.onclick = () => document.body.removeChild(overlay);
        overlay.onclick = (e) => {
            if (e.target === overlay) {
                document.body.removeChild(overlay);
            }
        };

        // Assemble
        modal.appendChild(title);
        modal.appendChild(textarea);
        modal.appendChild(closeButton);
        overlay.appendChild(modal);
        document.body.appendChild(overlay);

        // Select text for easy copying
        textarea.select();
    }

    // --- 桌面端专用函数 ---
    function scanAllFloorsInPage_desktop(root, fromFloor, toFloor) {
        const results = [];
        const floorElements = root.querySelectorAll('tr.postrow');
        floorElements.forEach(floor => {
            const floorNumber = Number(floor.querySelector('a[name^="l"]')?.textContent.match(/\d+/)?.[0]);
            if (floorNumber > toFloor || floorNumber < fromFloor) {
                return;
            }
            const author = floor.querySelector('.userlink.author')?.textContent.trim();
            const contentSpan = floor.querySelector('span.postcontent.ubbcode');
            if (!contentSpan) return;
            const cleanText = purifyContent(contentSpan);
            const angas = findAngaOptions(cleanText);
            if (angas.length > 0) {
                results.push({ floor: floorNumber, author, options: angas });
            }
        });
        return results;
    }

    // --- 移动端专用函数 ---
    function scanAllFloorsInPage_mobile(root, fromFloor, toFloor) {
        const results = [];
        const floorElements = root.querySelectorAll('tr.postrow');
        floorElements.forEach(floor => {
            const floorNumberText = floor.querySelector('.postinfot.postoptswb')?.textContent;
            const floorNumber = Number(floorNumberText?.match(/\d+/)?.[0]);
            if (!floorNumber || floorNumber > toFloor || floorNumber < fromFloor) {
                return;
            }
            const author = floor.querySelector('.userlink.author')?.textContent.trim();
            const contentSpan = floor.querySelector('span.postcontent.ubbcode');
            if (!contentSpan) return;
            const cleanText = purifyContent(contentSpan);
            const angas = findAngaOptions(cleanText);
            if (angas.length > 0) {
                results.push({ floor: floorNumber, author, options: angas });
            }
        });
        return results;
    }

    // --- 动态调用扫描函数 ---
    function scanAllFloorsInPage(root, fromFloor, toFloor) {
        if (isMobileView()) {
            return scanAllFloorsInPage_mobile(root, fromFloor, toFloor);
        } else {
            return scanAllFloorsInPage_desktop(root, fromFloor, toFloor);
        }
    }


    function onQuickAngaBtnClick() {
        const urlParams = new URLSearchParams(window.location.search);
        const page = urlParams.get('page') || '1';
        const pageNumber = parseInt(page, 10);
        var startFloor = page2floor(pageNumber)
        const angas = scanAllFloorsInPage(document, startFloor, startFloor + 19);
        if (angas.length === 0) {
            alert('未检测到安价内容');
            return;
        }
        const resultText = `安价数据:${angaToText(angas)}`;
        if (isMobileView()) {
            showCustomPrompt(resultText);
        } else {
            updateTextarea(resultText);
        }
    }

    function findUrlForPage(page) {
        const urlObj = new URL(window.location.href);
        const params = urlObj.searchParams;
        params.set('page', page);
        return urlObj.toString();
    }

    async function loadPageInBackground(url) {
        return new Promise((resolve, reject) => {
            const iframe = document.createElement('iframe');
            iframe.style.display = 'none';
            document.body.appendChild(iframe);
            iframe.onload = async () => {
                try {
                    await new Promise(resolve => setTimeout(resolve, 2000));
                    const doc = iframe.contentDocument || iframe.contentWindow.document;
                    const html = doc.documentElement.outerHTML;
                    document.body.removeChild(iframe);
                    resolve(html);
                } catch (error) {
                    reject(error);
                }
            };
            iframe.onerror = () => {
                document.body.removeChild(iframe);
                reject(new Error('Failed to load page'));
            };
            iframe.src = url;
        });
    }

    async function fetchAllPage() {
        var startFloor = Number(startInput.value)
        var startPage = floor2page(startFloor)
        var endFloor = Number(endInput.value)
        var endPage = floor2page(endFloor)
        const mergedResults = [];
        for (let page = startPage; page <= endPage; page++) {
            const url = new URL(findUrlForPage(page), window.location.origin).href;
            const html = await loadPageInBackground(url);
            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');
            var nowStartFloor = page2floor(page)
            nowStartFloor = (nowStartFloor < startFloor) ? startFloor : nowStartFloor;
            var nowEndFloor = page2floor(page) + 19
            nowEndFloor = (nowEndFloor > endFloor) ? endFloor : nowEndFloor;
            const currentResults = scanAllFloorsInPage(doc, nowStartFloor, nowEndFloor);
            mergedResults.push(...currentResults);
            if (!isMobileView()) {
                appendTextarea(`页码 ${page} 完成\n`)
            }
        }
        return mergedResults;
    }

    var startInput, endInput;
    function onAngaBtnClick() {
        if (!isMobileView()) {
            updateTextarea("开始统计安价\n")
        }
        fetchAllPage().then(results => {
            const resultText = `安价数据:${angaToText(results)}`;
            if (isMobileView()) {
                showCustomPrompt(resultText);
            } else {
                appendTextarea(resultText);
            }
        })
    }

    function createAngaButton(textContent, onClick) {
        const td = document.createElement('td');
        const btn = document.createElement('a');
        btn.className = 'uitxt1 cell rep txtbtnx nobr';
        btn.style.cssText = 'font-size:1.23em;';
        btn.textContent = textContent;
        btn.addEventListener('click', onClick);
        td.appendChild(btn);
        return td;
    }

    function getReplyButtons_desktop() {
        const buttons = Array.from(document.querySelectorAll('a.uitxt1'));
        return buttons.filter(btn => btn.textContent.trim() === '发表回复(Ctrl+Enter)');
    }

    function getQuickReplyButtons_desktop() {
        const allButtons = Array.from(document.querySelectorAll('a.uitxt1'));
        return allButtons.filter(btn => {
            const span = btn.querySelector('span');
            return span && span.textContent.trim() === '发表回复';
        });
    }

    function getReplyButtons_mobile() {
        return Array.from(document.querySelectorAll('#postbbtm a, #postbtop a')).filter(a => a.textContent.trim() === '回复');
    }

    function createInputsContainer() {
        const container = document.createElement('div');
        container.style.cssText = 'margin:10px 0; text-align:left;';
        startInput = document.createElement('input');
        startInput.type = 'text';
        startInput.placeholder = '开始楼层';
        startInput.style.cssText = 'width:48%; margin-right:2%;';
        endInput = document.createElement('input');
        endInput.type = 'text';
        endInput.placeholder = '结束楼层';
        endInput.style.cssText = 'width:48%;';
        container.append(startInput, endInput);
        return container;
    }

    function injectFloorInputs_desktop() {
        const targetButton = document.querySelector('td.c2 button[title="插入表情"]');
        if (!targetButton) return;
        const existingInputs = document.querySelector('td.c2 input[placeholder="开始楼层"]');
        if (existingInputs) return;
        const container = createInputsContainer();
        targetButton.parentNode.insertBefore(container, targetButton);
    }

    function injectFloorInputs_mobile() {
        const quickReplyTextarea = document.querySelector('#fast_post_c textarea');
        if (!quickReplyTextarea) return;
        const parentContainer = quickReplyTextarea.closest('div');
        if (!parentContainer) return;
        const existingInputs = parentContainer.querySelector('input[placeholder="开始楼层"]');
        if (existingInputs) return;
        const container = createInputsContainer();
        parentContainer.insertBefore(container, quickReplyTextarea);
    }

    const ANGA_BUTTON_CLASS = 'anga-json-btn';

    function injectButtons_desktop() {
        getQuickReplyButtons_desktop().forEach(originBtn => {
            const container = originBtn.closest('tr');
            if (!container || container.querySelector(`.${ANGA_BUTTON_CLASS}`)) return;
            const newBtn = createAngaButton("本页安价", onQuickAngaBtnClick);
            newBtn.classList.add(ANGA_BUTTON_CLASS);
            originBtn.closest('td').insertAdjacentElement('afterend', newBtn);
        });
        getReplyButtons_desktop().forEach(originBtn => {
            const container = originBtn.closest('tr');
            if (!container || container.querySelector(`.${ANGA_BUTTON_CLASS}`)) return;
            const newBtn = createAngaButton("生成安价", onAngaBtnClick);
            newBtn.classList.add(ANGA_BUTTON_CLASS);
            originBtn.closest('td').insertAdjacentElement('afterend', newBtn);
        });
    }

    function injectButtons_mobile() {
        getReplyButtons_mobile().forEach(originBtn => {
            const container = originBtn.closest('tr');
            if (!container || container.querySelector(`.${ANGA_BUTTON_CLASS}`)) return;

            const quickAngaBtn = createAngaButton("本页安价", onQuickAngaBtnClick);
            quickAngaBtn.classList.add(ANGA_BUTTON_CLASS);
            originBtn.closest('td').insertAdjacentElement('beforebegin', quickAngaBtn);
        });
    }

    function initialize() {
        if (isMobileView()) {
            injectButtons_mobile();
            injectFloorInputs_mobile();
        } else {
            injectButtons_desktop();
            injectFloorInputs_desktop();
        }
    }

    const observer = new MutationObserver(() => {
        if (document.querySelector(`.${ANGA_BUTTON_CLASS}`)) {
            return;
        }
        initialize();
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true,
    });

    initialize();

})();