漫画导入器优化版

将漫画信息导入到Notion数据库(优化移动端体验)

// ==UserScript==
// @name         漫画导入器优化版
// @namespace    http://tampermonkey.net/
// @version      2.1
// @description  将漫画信息导入到Notion数据库(优化移动端体验)
// @author       pipi
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_addStyle
// @grant        GM_notification
// @connect      api.notion.com
// @license      pipi
// ==/UserScript==

(function() {
    'use strict';

    // 配置存储
    const CONFIG_KEY = 'NotionImporterConfig';
    const SITE_SELECTORS_KEY = 'NotionImporterSiteSelectors';
    const IMPORTED_PAGES_KEY = 'NotionImporterImportedPages';

    // 默认配置
    const defaultConfig = {
        apiKey: '',
        mangaDbId: ''
    };

    // 粉色主题颜色
    const PRIMARY_COLOR = '#fd9abd';
    const SECONDARY_COLOR = '#ffb3d1';
    const DANGER_COLOR = '#ff6b8b';
    const SUCCESS_COLOR = '#a8e6cf';
    const INFO_COLOR = '#84c7f9';

    // 获取或初始化配置
    function getConfig() {
        const savedConfig = GM_getValue(CONFIG_KEY, JSON.stringify(defaultConfig));
        return JSON.parse(savedConfig);
    }

    // 保存配置
    function saveConfig(config) {
        GM_setValue(CONFIG_KEY, JSON.stringify(config));
    }

    // 获取站点选择器配置
    function getSiteSelectors(domain) {
        const selectors = GM_getValue(SITE_SELECTORS_KEY, '{}');
        return JSON.parse(selectors)[domain] || {};
    }

    // 保存站点选择器配置
    function saveSiteSelectors(domain, selectorConfig) {
        const allSelectors = JSON.parse(GM_getValue(SITE_SELECTORS_KEY, '{}'));
        allSelectors[domain] = selectorConfig;
        GM_setValue(SITE_SELECTORS_KEY, JSON.stringify(allSelectors));
    }

    // 获取已导入页面
    function getImportedPages() {
        const pages = GM_getValue(IMPORTED_PAGES_KEY, '{}');
        return JSON.parse(pages);
    }

    // 保存已导入页面
    function saveImportedPage(url, pageId) {
        const pages = getImportedPages();
        pages[url] = pageId;
        GM_setValue(IMPORTED_PAGES_KEY, JSON.stringify(pages));
    }

    // 创建悬浮按钮
    function createFloatingButton(isImported = false) {
        const existingBtn = document.getElementById('notion-importer-floating-btn');
        if (existingBtn) existingBtn.remove();

        const floatingBtn = document.createElement('div');
        floatingBtn.id = 'notion-importer-floating-btn';
        floatingBtn.style.position = 'fixed';
        floatingBtn.style.right = '20px';
        floatingBtn.style.bottom = '20px';
        floatingBtn.style.zIndex = '9999';
        floatingBtn.style.width = '50px';
        floatingBtn.style.height = '50px';
        floatingBtn.style.borderRadius = '50%';
        floatingBtn.style.backgroundColor = isImported ? SUCCESS_COLOR : PRIMARY_COLOR;
        floatingBtn.style.color = 'white';
        floatingBtn.style.display = 'flex';
        floatingBtn.style.justifyContent = 'center';
        floatingBtn.style.alignItems = 'center';
        floatingBtn.style.cursor = 'pointer';
        floatingBtn.style.boxShadow = '0 2px 10px rgba(0,0,0,0.2)';
        floatingBtn.innerHTML = isImported ?
            '<span style="font-size: 24px;">✓</span>' :
            '<span style="font-size: 24px;">+</span>';
        floatingBtn.style.touchAction = 'manipulation';

        document.body.appendChild(floatingBtn);
        return floatingBtn;
    }

    // 创建确认对话框
    function createConfirmDialog(message, onConfirm, onCancel) {
        const overlay = document.createElement('div');
        overlay.style.position = 'fixed';
        overlay.style.top = '0';
        overlay.style.left = '0';
        overlay.style.width = '100%';
        overlay.style.height = '100%';
        overlay.style.backgroundColor = 'rgba(0,0,0,0.5)';
        overlay.style.zIndex = '10000';
        overlay.style.display = 'flex';
        overlay.style.justifyContent = 'center';
        overlay.style.alignItems = 'center';

        const dialog = document.createElement('div');
        dialog.style.backgroundColor = 'white';
        dialog.style.padding = '20px';
        dialog.style.borderRadius = '8px';
        dialog.style.width = '80%';
        dialog.style.maxWidth = '400px';

        const messageEl = document.createElement('div');
        messageEl.textContent = message;
        messageEl.style.marginBottom = '20px';
        messageEl.style.fontSize = '16px';

        const buttonContainer = document.createElement('div');
        buttonContainer.style.display = 'flex';
        buttonContainer.style.justifyContent = 'flex-end';
        buttonContainer.style.gap = '10px';

        const confirmBtn = document.createElement('button');
        confirmBtn.textContent = '确定';
        confirmBtn.style.padding = '10px 20px';
        confirmBtn.style.fontSize = '16px';
        confirmBtn.style.backgroundColor = PRIMARY_COLOR;
        confirmBtn.style.color = 'white';
        confirmBtn.style.border = 'none';
        confirmBtn.style.borderRadius = '6px';
        confirmBtn.onclick = function() {
            document.body.removeChild(overlay);
            onConfirm && onConfirm();
        };

        const cancelBtn = document.createElement('button');
        cancelBtn.textContent = '取消';
        cancelBtn.style.padding = '10px 20px';
        cancelBtn.style.fontSize = '16px';
        cancelBtn.style.backgroundColor = DANGER_COLOR;
        cancelBtn.style.color = 'white';
        cancelBtn.style.border = 'none';
        cancelBtn.style.borderRadius = '6px';
        cancelBtn.onclick = function() {
            document.body.removeChild(overlay);
            onCancel && onCancel();
        };

        buttonContainer.appendChild(cancelBtn);
        buttonContainer.appendChild(confirmBtn);
        dialog.appendChild(messageEl);
        dialog.appendChild(buttonContainer);
        overlay.appendChild(dialog);
        document.body.appendChild(overlay);

        return overlay;
    }

    // 去除文本中的括号内容
    function cleanText(text) {
        if (!text) return '';
        return text.replace(/\[.*?\]/g, '').replace(/\(.*?\)/g, '').trim();
    }

    // 获取元素值
    function getElementValue(selector) {
        if (!selector) return '';

        try {
            const element = document.querySelector(selector);
            return element ? cleanText(getTextContent(element)) : '';
        } catch (e) {
            console.error('获取元素值出错:', e);
            return '';
        }
    }

    // 获取文本内容
    function getTextContent(element) {
        if (!element) return '';

        // 如果是输入元素
        if (element.tagName.toLowerCase() === 'input' || element.tagName.toLowerCase() === 'textarea') {
            return element.value || '';
        }

        // 如果是选择元素
        if (element.tagName.toLowerCase() === 'select') {
            return element.options[element.selectedIndex]?.text || '';
        }

        // 默认获取文本内容
        return element.textContent?.trim() || '';
    }

    // 获取图片URL(自动匹配第一张大图)
    function getImageUrl(selector) {
        // 优先使用选择器指定的图片
        if (selector) {
            try {
                const element = document.querySelector(selector);
                if (element) {
                    // 如果是img标签
                    if (element.tagName.toLowerCase() === 'img') {
                        return element.src || '';
                    }

                    // 如果是背景图
                    const backgroundImage = window.getComputedStyle(element).backgroundImage;
                    if (backgroundImage && backgroundImage !== 'none') {
                        const urlMatch = backgroundImage.match(/url\(["']?(.*?)["']?\)/);
                        if (urlMatch && urlMatch[1]) {
                            return urlMatch[1];
                        }
                    }
                }
            } catch (e) {
                console.error('获取图片URL出错:', e);
            }
        }

        // 如果没有选择器或选择器无效,自动获取页面第一张大图
        const images = document.querySelectorAll('img');
        for (let img of images) {
            // 过滤小图标(宽度或高度大于100px)
            if (img.naturalWidth > 100 && img.naturalHeight > 100) {
                return img.src || '';
            }
        }

        return '';
    }

    // Notion API请求
    function notionApiRequest(endpoint, data, method = 'POST') {
        const config = getConfig();
        const apiKey = config.apiKey;

        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: method,
                url: `https://api.notion.com/v1/${endpoint}`,
                headers: {
                    'Authorization': `Bearer ${apiKey}`,
                    'Content-Type': 'application/json',
                    'Notion-Version': '2022-06-28'
                },
                data: JSON.stringify(data),
                onload: function(response) {
                    if (response.status >= 200 && response.status < 300) {
                        try {
                            resolve(JSON.parse(response.responseText));
                        } catch (e) {
                            resolve(response.responseText);
                        }
                    } else {
                        try {
                            const error = JSON.parse(response.responseText);
                            reject(new Error(error.message || 'Notion API错误'));
                        } catch (e) {
                            reject(new Error(`HTTP ${response.status}: ${response.statusText}`));
                        }
                    }
                },
                onerror: function(error) {
                    reject(error);
                }
            });
        });
    }

    // 更新Notion页面
    async function updateNotionPage(pageId, data) {
        try {
            const response = await notionApiRequest(`pages/${pageId}`, data, 'PATCH');
            return response;
        } catch (error) {
            console.error('更新Notion页面出错:', error);
            throw error;
        }
    }

    // 创建选择器界面
    function createSelectorInterface(propertyName, callback) {
        // 隐藏悬浮按钮
        const floatingBtn = document.getElementById('notion-importer-floating-btn');
        if (floatingBtn) floatingBtn.style.display = 'none';

        // 创建选择器覆盖层
        const selectorOverlay = document.createElement('div');
        selectorOverlay.id = 'notion-importer-selector-overlay';
        selectorOverlay.style.position = 'fixed';
        selectorOverlay.style.top = '0';
        selectorOverlay.style.left = '0';
        selectorOverlay.style.width = '100%';
        selectorOverlay.style.height = '100%';
        selectorOverlay.style.zIndex = '10000';
        selectorOverlay.style.pointerEvents = 'none';

        // 创建提示框
        const tooltip = document.createElement('div');
        tooltip.style.position = 'fixed';
        tooltip.style.bottom = '20px';
        tooltip.style.left = '50%';
        tooltip.style.transform = 'translateX(-50%)';
        tooltip.style.backgroundColor = 'rgba(0,0,0,0.7)';
        tooltip.style.color = 'white';
        tooltip.style.padding = '15px 20px';
        tooltip.style.borderRadius = '8px';
        tooltip.style.zIndex = '10001';
        tooltip.style.maxWidth = '90%';
        tooltip.style.textAlign = 'center';
        tooltip.style.fontSize = '16px';
        tooltip.innerHTML = `
            <div style="font-weight: bold; margin-bottom: 8px;">正在选择: ${propertyName}</div>
            <div style="margin-bottom: 8px;">点击页面元素进行选择</div>
            <div style="margin-bottom: 8px;">按住Shift可多选</div>
            <div id="notion-importer-current-selector" style="margin-top: 8px; font-family: monospace; word-break: break-all;"></div>
        `;

        selectorOverlay.appendChild(tooltip);
        document.body.appendChild(selectorOverlay);

        // 高亮元素
        function highlightElement(element) {
            if (!element) return;
            element.style.outline = '2px solid ' + PRIMARY_COLOR;
            element.style.outlineOffset = '2px';
        }

        // 取消高亮
        function unhighlightElement(element) {
            if (!element) return;
            element.style.outline = '';
            element.style.outlineOffset = '';
        }

        let selectedElements = [];
        let currentSelector = '';
        let hoveredElement = null;
        let shiftPressed = false;

        // 更新当前悬停元素的提示
        function updateHoveredElementInfo(element) {
            const selectorInfo = document.getElementById('notion-importer-current-selector');
            if (element) {
                selectorInfo.textContent = generateSelector(element, false);
            } else {
                selectorInfo.textContent = '未悬停在元素上';
            }
        }

        // 生成选择器
        function generateSelector(element, isMultiSelect = false) {
            if (!element || !element.tagName) return '';

            // 多选模式直接返回通用选择器
            if (isMultiSelect) {
                // 优先返回类选择器
                if (element.className && typeof element.className === 'string') {
                    const classes = element.className.split(/\s+/).filter(c => c);
                    if (classes.length > 0) {
                        return `.${classes[0]}`;
                    }
                }
                // 没有类名则返回标签名
                return element.tagName.toLowerCase();
            }

            // 单选模式生成精确选择器
            const path = [];
            let current = element;

            while (current && current !== document.body) {
                const siblings = Array.from(current.parentNode.children);
                const index = siblings.indexOf(current) + 1;
                const tag = current.tagName.toLowerCase();

                // 优先使用带位置的选择器
                path.unshift(`${tag}:nth-child(${index})`);

                // 如果有类名则添加
                if (current.className && typeof current.className === 'string') {
                    const classes = current.className.split(/\s+/).filter(c => c);
                    if (classes.length > 0) {
                        path[0] = `${tag}.${classes[0]}:nth-child(${index})`;
                    }
                }

                current = current.parentNode;
            }

            return path.join(' > ');
        }

        // 元素悬停逻辑
        function handleElementHover(e) {
            const target = e.target;

            // 如果悬停在选择器界面本身,不处理
            if (selectorOverlay.contains(target)) {
                if (hoveredElement) {
                    unhighlightElement(hoveredElement);
                    hoveredElement = null;
                    updateHoveredElementInfo(null);
                }
                return;
            }

            // 如果悬停的元素变化了
            if (target !== hoveredElement) {
                if (hoveredElement) {
                    unhighlightElement(hoveredElement);
                }
                hoveredElement = target;
                highlightElement(hoveredElement);
                updateHoveredElementInfo(hoveredElement);
            }
        }

        // 元素选择逻辑
        document.addEventListener('keydown', function(e) {
            if (e.key === 'Shift') {
                shiftPressed = true;
            }
        });

        document.addEventListener('keyup', function(e) {
            if (e.key === 'Shift') {
                shiftPressed = false;
            }
        });

        function handleElementClick(e) {
            e.preventDefault();
            e.stopPropagation();

            const target = e.target;

            // 如果点击的是选择器界面本身,不处理
            if (selectorOverlay.contains(target)) {
                return;
            }

            if (shiftPressed) {
                // 多选模式
                if (!selectedElements.includes(target)) {
                    selectedElements.push(target);
                    highlightElement(target);
                }
            } else {
                // 单选模式
                selectedElements.forEach(el => unhighlightElement(el));
                selectedElements = [target];
                highlightElement(target);
            }

            // 更新选择器
            if (selectedElements.length > 0) {
                currentSelector = generateSelector(selectedElements[0], shiftPressed);
                createConfirmationInterface();
            }
        }

        // 创建确认界面
        function createConfirmationInterface() {
            document.body.removeChild(selectorOverlay);
            document.removeEventListener('mouseover', handleElementHover);
            document.removeEventListener('click', handleElementClick, true);
            document.removeEventListener('keydown', handleKeyDown);

            const overlay = document.createElement('div');
            overlay.className = 'notion-importer-interface';
            overlay.style.position = 'fixed';
            overlay.style.top = '0';
            overlay.style.left = '0';
            overlay.style.width = '100%';
            overlay.style.height = '100%';
            overlay.style.backgroundColor = 'rgba(0,0,0,0.5)';
            overlay.style.zIndex = '10000';
            overlay.style.display = 'flex';
            overlay.style.flexDirection = 'column';
            overlay.style.alignItems = 'center';
            overlay.style.justifyContent = 'center';

            const container = document.createElement('div');
            container.style.backgroundColor = 'white';
            container.style.padding = '20px';
            container.style.borderRadius = '12px';
            container.style.width = '90%';
            container.style.maxWidth = '500px';
            container.style.maxHeight = '80vh';
            container.style.overflowY = 'auto';

            const title = document.createElement('h3');
            title.textContent = `确认选择: ${propertyName}`;
            title.style.marginTop = '0';
            title.style.marginBottom = '15px';
            title.style.color = PRIMARY_COLOR;
            title.style.fontSize = '18px';

            const selectedInfo = document.createElement('div');
            selectedInfo.style.marginBottom = '20px';
            selectedInfo.style.padding = '15px';
            selectedInfo.style.backgroundColor = '#f9f9f9';
            selectedInfo.style.borderRadius = '8px';
            selectedInfo.style.fontSize = '16px';

            if (selectedElements.length === 0) {
                selectedInfo.innerHTML = '<p>未选择任何元素</p>';
            } else {
                let infoHTML = `<p style="margin-bottom: 10px;">已选择 ${selectedElements.length} 个元素:</p>`;
                const allTexts = [];

                selectedElements.forEach((el, index) => {
                    const text = cleanText(el.textContent?.trim().substring(0, 50)) || '空内容';
                    allTexts.push(text);
                    infoHTML += `<div style="margin-top: 8px;">
                        <strong>元素 ${index + 1}:</strong> ${text}
                    </div>`;
                });

                infoHTML += `<div style="margin-top: 15px;">
                    <strong>选择器:</strong> ${currentSelector}
                </div>`;

                if (selectedElements.length > 1) {
                    infoHTML += `<div style="margin-top: 15px;">
                        <strong>合并文本:</strong> ${allTexts.join(', ')}
                    </div>`;
                }

                selectedInfo.innerHTML = infoHTML;
            }

            const inputGroup = document.createElement('div');
            inputGroup.style.display = 'flex';
            inputGroup.style.flexDirection = 'column';
            inputGroup.style.marginBottom = '20px';

            const selectorLabel = document.createElement('label');
            selectorLabel.textContent = '选择器 (可编辑)';
            selectorLabel.style.marginBottom = '8px';
            selectorLabel.style.fontSize = '16px';

            const selectorInput = document.createElement('input');
            selectorInput.type = 'text';
            selectorInput.value = currentSelector;
            selectorInput.placeholder = '点击选择按钮选择元素或直接输入选择器';
            selectorInput.style.padding = '12px';
            selectorInput.style.border = '1px solid #ddd';
            selectorInput.style.borderRadius = '6px';
            selectorInput.style.fontSize = '16px';
            selectorInput.style.marginBottom = '10px';

            const selectButton = document.createElement('button');
            selectButton.textContent = '重新选择';
            selectButton.style.padding = '12px';
            selectButton.style.fontSize = '16px';
            selectButton.style.backgroundColor = SECONDARY_COLOR;
            selectButton.style.color = 'white';
            selectButton.style.border = 'none';
            selectButton.style.borderRadius = '6px';
            selectButton.style.cursor = 'pointer';
            selectButton.onclick = function() {
                document.body.removeChild(overlay);
                createSelectorInterface(propertyName, callback);
            };

            inputGroup.appendChild(selectorLabel);
            inputGroup.appendChild(selectorInput);
            inputGroup.appendChild(selectButton);

            const buttonContainer = document.createElement('div');
            buttonContainer.style.display = 'flex';
            buttonContainer.style.justifyContent = 'flex-end';
            buttonContainer.style.marginTop = '20px';
            buttonContainer.style.gap = '10px';

            const confirmButton = document.createElement('button');
            confirmButton.textContent = '确认';
            confirmButton.style.padding = '12px 20px';
            confirmButton.style.fontSize = '16px';
            confirmButton.style.backgroundColor = PRIMARY_COLOR;
            confirmButton.style.color = 'white';
            confirmButton.style.border = 'none';
            confirmButton.style.borderRadius = '6px';
            confirmButton.style.cursor = 'pointer';

            const cancelButton = document.createElement('button');
            cancelButton.textContent = '取消';
            cancelButton.style.padding = '12px 20px';
            cancelButton.style.fontSize = '16px';
            cancelButton.style.backgroundColor = DANGER_COLOR;
            cancelButton.style.color = 'white';
            cancelButton.style.border = 'none';
            cancelButton.style.borderRadius = '6px';
            cancelButton.style.cursor = 'pointer';

            buttonContainer.appendChild(cancelButton);
            buttonContainer.appendChild(confirmButton);

            container.appendChild(title);
            container.appendChild(selectedInfo);
            container.appendChild(inputGroup);
            container.appendChild(buttonContainer);
            overlay.appendChild(container);
            document.body.appendChild(overlay);

            // 确认选择
            confirmButton.onclick = function() {
                const finalSelector = selectorInput.value.trim();
                if (!finalSelector) {
                    alert('请提供有效的选择器');
                    return;
                }

                // 清除高亮
                selectedElements.forEach(el => unhighlightElement(el));

                // 如果是多选模式,合并文本内容
                let result;
                if (selectedElements.length > 1) {
                    const allTexts = selectedElements.map(el => cleanText(getTextContent(el))).filter(t => t);
                    result = allTexts.join(', ');
                } else {
                    result = cleanText(getTextContent(selectedElements[0]));
                }

                // 执行回调
                if (callback) {
                    callback(finalSelector, result);
                }

                // 关闭界面
                document.body.removeChild(overlay);

                // 恢复悬浮按钮
                const floatingBtn = document.getElementById('notion-importer-floating-btn');
                if (floatingBtn) floatingBtn.style.display = 'flex';
            };

            // 取消选择
            cancelButton.onclick = function() {
                // 清除高亮
                selectedElements.forEach(el => unhighlightElement(el));

                // 关闭界面
                document.body.removeChild(overlay);

                // 恢复悬浮按钮
                const floatingBtn = document.getElementById('notion-importer-floating-btn');
                if (floatingBtn) floatingBtn.style.display = 'flex';
            };

            // 点击外部关闭
            overlay.onclick = function(e) {
                if (e.target === overlay) {
                    // 清除高亮
                    selectedElements.forEach(el => unhighlightElement(el));
                    document.body.removeChild(overlay);

                    // 恢复悬浮按钮
                    const floatingBtn = document.getElementById('notion-importer-floating-btn');
                    if (floatingBtn) floatingBtn.style.display = 'flex';
                }
            };
        }

        // 添加事件监听器
        document.addEventListener('mouseover', handleElementHover);
        document.addEventListener('click', handleElementClick, true);

        // 添加键盘快捷键 (ESC取消)
        function handleKeyDown(e) {
            if (e.key === 'Escape') {
                // 取消选择
                selectedElements.forEach(el => unhighlightElement(el));
                document.body.removeChild(selectorOverlay);
                document.removeEventListener('mouseover', handleElementHover);
                document.removeEventListener('click', handleElementClick, true);
                document.removeEventListener('keydown', handleKeyDown);

                // 恢复悬浮按钮
                const floatingBtn = document.getElementById('notion-importer-floating-btn');
                if (floatingBtn) floatingBtn.style.display = 'flex';
            }
        }
        document.addEventListener('keydown', handleKeyDown);
    }

    // 创建漫画导入界面
    function createMangaImportInterface(isUpdate = false, pageId = null) {
        const domain = window.location.hostname;
        const currentUrl = window.location.href;
        const selectors = getSiteSelectors(domain);
        const isConfigured = Object.keys(selectors).length > 0;

        const overlay = document.createElement('div');
        overlay.className = 'notion-importer-interface';
        overlay.style.position = 'fixed';
        overlay.style.top = '0';
        overlay.style.left = '0';
        overlay.style.width = '100%';
        overlay.style.height = '100%';
        overlay.style.backgroundColor = 'rgba(0,0,0,0.5)';
        overlay.style.zIndex = '10000';
        overlay.style.display = 'flex';
        overlay.style.flexDirection = 'column';
        overlay.style.alignItems = 'center';
        overlay.style.justifyContent = 'center';

        const container = document.createElement('div');
        container.style.backgroundColor = 'white';
        container.style.padding = '20px';
        container.style.borderRadius = '12px';
        container.style.width = '90%';
        container.style.maxWidth = '500px';
        container.style.maxHeight = '80vh';
        container.style.overflowY = 'auto';

        const title = document.createElement('h3');
        title.textContent = isUpdate ? '更新漫画信息' : (isConfigured ? '导入漫画到Notion' : '配置漫画选择器');
        title.style.marginTop = '0';
        title.style.marginBottom = '15px';
        title.style.color = PRIMARY_COLOR;
        title.style.fontSize = '18px';

        const form = document.createElement('div');
        form.style.display = 'flex';
        form.style.flexDirection = 'column';
        form.style.gap = '15px';

        // 创建表单组
        function createFormGroup(label, currentSelector, onSelect) {
            const group = document.createElement('div');
            group.style.display = 'flex';
            group.style.flexDirection = 'column';

            const labelElement = document.createElement('label');
            labelElement.textContent = label;
            labelElement.style.marginBottom = '8px';
            labelElement.style.fontSize = '16px';

            const input = document.createElement('input');
            input.type = 'text';
            input.value = currentSelector || '';
            input.placeholder = '点击选择按钮选择元素或直接输入选择器';
            input.style.padding = '12px';
            input.style.border = '1px solid #ddd';
            input.style.borderRadius = '6px';
            input.style.fontSize = '16px';
            input.style.marginBottom = '10px';

            const selectButton = document.createElement('button');
            selectButton.textContent = '选择';
            selectButton.style.padding = '12px';
            selectButton.style.fontSize = '16px';
            selectButton.style.backgroundColor = PRIMARY_COLOR;
            selectButton.style.color = 'white';
            selectButton.style.border = 'none';
            selectButton.style.borderRadius = '6px';
            selectButton.style.cursor = 'pointer';
            selectButton.onclick = function(e) {
                e.stopPropagation();
                // 隐藏整个导入界面
                overlay.style.display = 'none';
                createSelectorInterface(label, function(selector, value) {
                    // 选择完成后恢复导入界面
                    overlay.style.display = 'flex';
                    input.value = selector;
                    if (onSelect) onSelect(selector);
                });
            };

            group.appendChild(labelElement);
            group.appendChild(input);
            group.appendChild(selectButton);

            return group;
        }

        // 漫画名
        const nameGroup = createFormGroup('漫画名', selectors['漫画名'] || '', (selector) => {
            selectors['漫画名'] = selector;
            saveSiteSelectors(domain, selectors);
        });

        // 作者
        const authorGroup = createFormGroup('作者', selectors['作者'] || '', (selector) => {
            selectors['作者'] = selector;
            saveSiteSelectors(domain, selectors);
        });

        // 简介
        const descriptionGroup = createFormGroup('简介', selectors['简介'] || '', (selector) => {
            selectors['简介'] = selector;
            saveSiteSelectors(domain, selectors);
        });

        // 最新章节
        const latestChapterGroup = createFormGroup('最新章节', selectors['最新章节'] || '', (selector) => {
            selectors['最新章节'] = selector;
            saveSiteSelectors(domain, selectors);
        });

        // 更新状态
        const statusGroup = createFormGroup('更新状态', selectors['更新状态'] || '', (selector) => {
            selectors['更新状态'] = selector;
            saveSiteSelectors(domain, selectors);
        });

        // 封面
        const coverGroup = createFormGroup('封面', selectors['封面'] || '', (selector) => {
            selectors['封面'] = selector;
            saveSiteSelectors(domain, selectors);
        });

        // 追更
        const trackingGroup = createFormGroup('追更', selectors['追更'] || '', (selector) => {
            selectors['追更'] = selector;
            saveSiteSelectors(domain, selectors);
        });

        // 类型
        const typeGroup = createFormGroup('类型', selectors['类型'] || '', (selector) => {
            selectors['类型'] = selector;
            saveSiteSelectors(domain, selectors);
        });

        // 别名
        const aliasGroup = createFormGroup('别名', selectors['别名'] || '', (selector) => {
            selectors['别名'] = selector;
            saveSiteSelectors(domain, selectors);
        });

        // 地区
        const regionGroup = createFormGroup('地区', selectors['地区'] || '', (selector) => {
            selectors['地区'] = selector;
            saveSiteSelectors(domain, selectors);
        });

        form.appendChild(nameGroup);
        form.appendChild(authorGroup);
        form.appendChild(descriptionGroup);
        form.appendChild(latestChapterGroup);
        form.appendChild(statusGroup);
        form.appendChild(coverGroup);
        form.appendChild(trackingGroup);
        form.appendChild(typeGroup);
        form.appendChild(aliasGroup);
        form.appendChild(regionGroup);

        const buttonContainer = document.createElement('div');
        buttonContainer.style.display = 'flex';
        buttonContainer.style.justifyContent = 'flex-end';
        buttonContainer.style.marginTop = '20px';
        buttonContainer.style.gap = '10px';

        const importButton = document.createElement('button');
        importButton.textContent = isUpdate ? '更新' : '导入';
        importButton.style.padding = '12px 20px';
        importButton.style.fontSize = '16px';
        importButton.style.backgroundColor = PRIMARY_COLOR;
        importButton.style.color = 'white';
        importButton.style.border = 'none';
        importButton.style.borderRadius = '6px';
        importButton.style.cursor = 'pointer';

        const cancelButton = document.createElement('button');
        cancelButton.textContent = '取消';
        cancelButton.style.padding = '12px 20px';
        cancelButton.style.fontSize = '16px';
        cancelButton.style.backgroundColor = DANGER_COLOR;
        cancelButton.style.color = 'white';
        cancelButton.style.border = 'none';
        cancelButton.style.borderRadius = '6px';
        cancelButton.style.cursor = 'pointer';

        buttonContainer.appendChild(cancelButton);
        buttonContainer.appendChild(importButton);

        container.appendChild(title);
        container.appendChild(form);
        container.appendChild(buttonContainer);
        overlay.appendChild(container);
        document.body.appendChild(overlay);

        // 导入/更新逻辑
        importButton.onclick = async function() {
            const config = getConfig();
            if (!config.apiKey || !config.mangaDbId) {
                alert('请先配置Notion API和数据库ID');
                return;
            }

            try {
                // 获取所有输入框的值
                const inputs = container.querySelectorAll('input');
                const selectorValues = {};
                inputs.forEach(input => {
                    const label = input.closest('div').firstChild.textContent;
                    selectorValues[label] = input.value;
                });

                // 保存选择器配置
                Object.keys(selectorValues).forEach(key => {
                    selectors[key] = selectorValues[key];
                });
                saveSiteSelectors(domain, selectors);

                // 获取数据
                const mangaData = {
                    '漫画名': selectorValues['漫画名'] ? getElementValue(selectorValues['漫画名']) : '',
                    '作者': selectorValues['作者'] ? getElementValue(selectorValues['作者']) : '',
                    '简介': selectorValues['简介'] ? getElementValue(selectorValues['简介']) : '',
                    '最新章节': selectorValues['最新章节'] ? getElementValue(selectorValues['最新章节']) : '',
                    '更新状态': selectorValues['更新状态'] ? getElementValue(selectorValues['更新状态']) : '',
                    '封面': getImageUrl(selectorValues['封面']), // 自动获取封面
                    '追更': selectorValues['追更'] ? getElementValue(selectorValues['追更']) : '',
                    '类型': selectorValues['类型'] ? getElementValue(selectorValues['类型']) : '',
                    '别名': selectorValues['别名'] ? getElementValue(selectorValues['别名']) : '',
                    '地区': selectorValues['地区'] ? getElementValue(selectorValues['地区']) : ''
                };

                const requestData = {
                    parent: { database_id: config.mangaDbId },
                    properties: {
                        '漫画名': {
                            title: [
                                {
                                    text: {
                                        content: mangaData['漫画名'] || '未命名'
                                    }
                                }
                            ]
                        },
                        '作者': {
                            rich_text: [
                                {
                                    text: {
                                        content: mangaData['作者'] || ''
                                    }
                                }
                            ]
                        },
                        '简介': {
                            rich_text: [
                                {
                                    text: {
                                        content: mangaData['简介'] || ''
                                    }
                                }
                            ]
                        },
                        '最新章节': {
                            rich_text: [
                                {
                                    text: {
                                        content: mangaData['最新章节'] || ''
                                    }
                                }
                            ]
                        },
                        '更新状态': {
                            select: {
                                name: mangaData['更新状态'] || '未知'
                            }
                        },
                        '追更': {
                            rich_text: [
                                {
                                    text: {
                                        content: mangaData['追更'] || ''
                                    }
                                }
                            ]
                        },
                        '类型': {
                            select: {
                                name: mangaData['类型'] || '其他'
                            }
                        },
                        '别名': {
                            rich_text: [
                                {
                                    text: {
                                        content: mangaData['别名'] || ''
                                    }
                                }
                            ]
                        },
                        '地区': {
                            select: {
                                name: mangaData['地区'] || '其他'
                            }
                        }
                    },
                    cover: mangaData['封面'] ? {
                        type: "external",
                        external: {
                            url: mangaData['封面']
                        }
                    } : null
                };

                let response;
                if (isUpdate && pageId) {
                    // 更新现有页面
                    delete requestData.parent; // 更新时不需要parent
                    response = await updateNotionPage(pageId, requestData);
                } else {
                    // 创建新页面
                    response = await notionApiRequest('pages', requestData);
                }

                if (response && response.id) {
                    // 保存已导入页面
                    saveImportedPage(currentUrl, response.id);

                    // 更新悬浮按钮状态
                    createFloatingButton(true);

                    // 显示成功通知
                    GM_notification({
                        text: isUpdate ? '更新成功!' : '导入成功!',
                        title: 'Notion导入器',
                        image: 'https://www.notion.so/images/favicon.ico'
                    });

                    document.body.removeChild(overlay);
                } else {
                    alert(isUpdate ? '更新失败: ' + (response.message || '未知错误') : '导入失败: ' + (response.message || '未知错误'));
                }
            } catch (error) {
                alert((isUpdate ? '更新出错: ' : '导入出错: ') + error.message);
                console.error('Notion API错误:', error);
            }
        };

        // 取消
        cancelButton.onclick = function() {
            document.body.removeChild(overlay);

            // 恢复悬浮按钮
            const floatingBtn = document.getElementById('notion-importer-floating-btn');
            if (floatingBtn) floatingBtn.style.display = 'flex';
        };

        // 点击外部关闭
        overlay.onclick = function(e) {
            if (e.target === overlay) {
                document.body.removeChild(overlay);

                // 恢复悬浮按钮
                const floatingBtn = document.getElementById('notion-importer-floating-btn');
                if (floatingBtn) floatingBtn.style.display = 'flex';
            }
        };
    }

    // 初始化
    function init() {
        // 添加CSS样式
        GM_addStyle(`
            .notion-importer-highlighted {
                outline: 2px solid ${PRIMARY_COLOR} !important;
                outline-offset: 2px !important;
            }

            #notion-importer-floating-btn {
                background-color: ${PRIMARY_COLOR} !important;
                transition: transform 0.2s;
                touch-action: manipulation;
            }

            #notion-importer-floating-btn:hover {
                transform: scale(1.1);
                background-color: ${SECONDARY_COLOR} !important;
            }

            .notion-importer-interface {
                font-size: 16px;
            }

            .notion-importer-interface input,
            .notion-importer-interface button,
            .notion-importer-interface select {
                font-size: 16px;
                min-height: 44px;
            }

            .notion-importer-interface button {
                padding: 12px;
                margin: 5px 0;
            }

            .notion-importer-interface input {
                padding: 12px;
                margin-bottom: 10px;
            }

            @media (max-width: 768px) {
                #notion-importer-floating-btn {
                    width: 60px !important;
                    height: 60px !important;
                    right: 15px !important;
                    bottom: 15px !important;
                }

                .notion-importer-interface {
                    width: 90% !important;
                    padding: 15px !important;
                }

                .notion-importer-interface h3 {
                    font-size: 18px !important;
                }

                .notion-importer-interface label {
                    font-size: 16px !important;
                }
            }
        `);

        // 检查是否已导入当前页面
        const currentUrl = window.location.href;
        const importedPages = getImportedPages();
        const isImported = importedPages.hasOwnProperty(currentUrl);

        // 创建悬浮按钮
        const floatingBtn = createFloatingButton(isImported);

        // 点击悬浮按钮
        floatingBtn.addEventListener('click', function(e) {
            e.stopPropagation();

            if (isImported) {
                // 如果已导入,询问是否更新
                createConfirmDialog(
                    '此页面已导入过,是否要更新数据?',
                    function() {
                        // 更新数据
                        createMangaImportInterface(true, importedPages[currentUrl]);
                    },
                    function() {
                        // 取消操作
                        floatingBtn.style.display = 'flex';
                    }
                );
            } else {
                // 首次导入
                createMangaImportInterface();
            }
        });

        // 点击外部隐藏菜单
        document.addEventListener('click', function(e) {
            const floatingBtn = document.getElementById('notion-importer-floating-btn');
            if (floatingBtn && !floatingBtn.contains(e.target)) {
                floatingBtn.style.display = 'flex';
            }
        });
    }

    // 启动脚本
    init();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址