Baidu & Google 双引擎同屏

在百度搜索结果页右侧显示谷歌搜索结果。

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

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Baidu & Google 双引擎同屏
// @namespace    476321082
// @version      1.2
// @description  在百度搜索结果页右侧显示谷歌搜索结果。
// @author       476321082
// @match        https://www.baidu.com/s*
// @license      MIT
// @connect      www.google.com
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(function() {
    'use strict';

    // --- NEW: 配置中心 ---
    const CONFIG = {
        PERFORMANCE: {
            DEBOUNCE_DELAY: 400,
            FETCH_TIMEOUT: 15000,
            RETRY_ATTEMPTS: 2,
            RETRY_DELAY_MS: 1000,
        },
        UI: {
            MIN_PANEL_WIDTH: 300,
            WIDE_SCREEN_BREAKPOINT: 1921,
        },
        GOOGLE: {
            RESULTS_PER_PAGE: 10,
        },
        CACHE: {
            SESSION_STORAGE_KEY_PREFIX: 'BaiduGoogleDualSearchCache_'
        }
    };

    // --- 常量定义 ---
    const C = {
        GM_SETTINGS_KEY: 'BaiduGoogleDualSearchSettings',
        IDS: {
            container: 'google-results-container',
            baiduPageContainer: 'container',
            settingsModal: 'google-settings-modal',
            settingEnabled: 'setting-enabled',
            settingCount: 'setting-count',
            settingNewTab: 'setting-newtab',
            settingAutofit: 'setting-autofit',
            settingWideLeft: 'setting-wide-left',
            settingReset: 'google-settings-reset',
            settingSave: 'google-settings-save',
            baiduContent: 'content_left',
            fetchStatus: 'google-fetch-status',
        },
        CLASSES: {
            header: 'google-results-header',
            settingsIcon: 'google-settings-icon',
            content: 'google-results-content',
            resizeHandle: 'resize-handle-right',
            settingsModalContent: 'google-settings-modal-content',
            formItem: 'google-settings-form-item',
            buttons: 'google-settings-buttons',
            resultItem: 'google-result-item',
            url: 'url',
            description: 'description',
            status: 'status',
        },
        SELECTORS: {
            googleResult: 'div#rso > div > div > div',
            link: 'a[href]',
            keyword: 'em',
            title: 'h3',
        }
    };

    // --- 默认设置 ---
    const defaultSettings = {
        scriptEnabled: true,
        resultCount: 15,
        openInNewTab: true,
        autoFitHeight: false,
        panelPosition: { top: '140px', left: '58%' },
        panelPositionWide: { left: '65%' },
        panelSize: { width: '40%', height: '500px' }
    };

    let currentSettings = {};

    // --- 架构类和管理器 ---
    const state = { lastQuery: "", isLoading: false };
    class DOMCache {
        constructor() { this.cache = new Map(); }
        get(selector, parent = document) {
            const key = `${parent.id || parent.tagName}-${selector}`;
            if (!this.cache.has(key)) { this.cache.set(key, parent.querySelector(selector)); }
            return this.cache.get(key);
        }
        clear() { this.cache.clear(); console.log('[DOMCache] Cache cleared.'); }
    }
    const domCache = new DOMCache();

    class ObserverManager {
        constructor() { this.observers = []; this.eventListeners = []; }
        addObserver(observer) { this.observers.push(observer); return observer; }
        addEventListener(element, event, handler, options) {
            element.addEventListener(event, handler, options);
            this.eventListeners.push({ element, event, handler, options });
        }
        cleanup() {
            this.observers.forEach(observer => observer.disconnect());
            this.eventListeners.forEach(({ element, event, handler, options }) => {
                element.removeEventListener(event, handler, options);
            });
            console.log('[ObserverManager] Cleaned up all observers and listeners.');
        }
    }
    const observerManager = new ObserverManager();

    class ErrorHandler {
        static handle(error, context) {
            console.error(`[Gemini Script Error] ${context}:`, error);
            if (error.name === 'NetworkError' || error.message.includes('NetworkError')) { return '网络连接失败,请检查网络设置或代理。'; }
            if (error.status === 429) { return 'Google 请求过于频繁,请稍后再试。'; }
            return `发生未知错误: ${error.message || '详情请查看控制台'}`;
        }
    }

    // --- NEW: 搜索结果会话缓存 ---
    const SessionCache = {
        getKey: (query) => `${CONFIG.CACHE.SESSION_STORAGE_KEY_PREFIX}${query}`,
        get: (query) => {
            try {
                const cached = sessionStorage.getItem(SessionCache.getKey(query));
                return cached ? JSON.parse(cached) : null;
            } catch (e) {
                console.error("Failed to read from session cache:", e);
                return null;
            }
        },
        set: (query, data) => {
            try {
                sessionStorage.setItem(SessionCache.getKey(query), JSON.stringify(data));
            } catch (e) {
                console.error("Failed to write to session cache:", e);
            }
        }
    };

    const regexCache = new Map();

    // --- 设置管理 ---
    function loadSettings() {
        const savedSettings = GM_getValue(C.GM_SETTINGS_KEY, {});
        currentSettings = { ...defaultSettings, ...savedSettings };
        currentSettings.panelPosition = { ...defaultSettings.panelPosition, ...(savedSettings.panelPosition || {}) };
        currentSettings.panelPositionWide = { ...defaultSettings.panelPositionWide, ...(savedSettings.panelPositionWide || {}) };
        currentSettings.panelSize = { ...defaultSettings.panelSize, ...(savedSettings.panelSize || {}) };
    }

    function saveSettings() { GM_setValue(C.GM_SETTINGS_KEY, currentSettings); }
    function debounce(func, delay) {
        let timeout;
        return function(...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), delay); };
    }

    // --- 样式定义 ---
    function applyStyles() {
        GM_addStyle(`...`); // Styles are unchanged, omitting for brevity.
        GM_addStyle(`
            #${C.IDS.container} { position: absolute; top: ${currentSettings.panelPosition.top}; left: ${currentSettings.panelPosition.left}; width: ${currentSettings.panelSize.width}; min-width: ${CONFIG.UI.MIN_PANEL_WIDTH}px; min-height: 200px; background-color: #fff; border: 1px solid #e4e7ed; border-radius: 8px; box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1); z-index: 9999; display: flex; flex-direction: column; overflow: hidden; }
            .${C.CLASSES.header} { display: flex; justify-content: space-between; align-items: center; padding: 10px 15px; border-bottom: 1px solid #ebeef5; cursor: move; background-color: #f7f7f7; user-select: none; }
            .${C.CLASSES.header} h2 { font-size: 16px; font-weight: 600; color: #303133; margin: 0; }
            .${C.CLASSES.settingsIcon} { cursor: pointer; font-size: 18px; }
            .${C.CLASSES.content} { padding: 15px; flex-grow: 1; overflow-y: auto; }
            .${C.CLASSES.resultItem} { margin-bottom: 18px; border-bottom: 1px solid #f0f2f5; padding-bottom: 15px; }
            .${C.CLASSES.resultItem}:last-child { border-bottom: none; }
            .${C.CLASSES.resultItem} a { font-size: 16px; font-weight: 500; color: #1a0dab; text-decoration: none; }
            .${C.CLASSES.resultItem} a:hover { text-decoration: underline; }
            .${C.CLASSES.resultItem} .${C.CLASSES.url} { font-size: 13px; color: #006621; padding-top: 2px; word-break: break-all; }
            .${C.CLASSES.resultItem} .${C.CLASSES.description} { font-size: 14px; color: #545454; line-height: 1.5; padding-top: 4px; }
            .${C.CLASSES.content} .${C.CLASSES.status} { color: #909399; padding: 10px; text-align: center; }
            .${C.CLASSES.resultItem} em, #${C.IDS.container} em { color: rgb(247, 49, 49) !important; font-style: normal !important; font-weight: 500 !important; background: none !important; }
            #${C.IDS.settingsModal} { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.4); z-index: 10001; display: flex; align-items: center; justify-content: center; }
            .${C.CLASSES.settingsModalContent} { background: white; padding: 20px; border-radius: 8px; width: 400px; box-shadow: 0 5px 15px rgba(0,0,0,0.3); }
            .${C.CLASSES.settingsModalContent} h3 { margin-top: 0; }
            .${C.CLASSES.formItem} { margin-bottom: 15px; display: flex; align-items: center; }
            .${C.CLASSES.formItem} label { display: block; margin-bottom: 0; }
            .${C.CLASSES.formItem} input[type="number"] { width: 80px; }
            .${C.CLASSES.formItem} input[type="checkbox"] { margin-right: 10px; height: 16px; width: 16px; }
            .${C.CLASSES.buttons} { text-align: right; margin-top: 20px; }
            .${C.CLASSES.buttons} button { padding: 8px 15px; border: none; border-radius: 4px; cursor: pointer; margin-left: 10px; }
            #${C.IDS.settingSave} { background: #409eff; color: white; }
            #${C.IDS.settingReset} { background: #f56c6c; color: white; }
            .${C.CLASSES.resizeHandle} { position: absolute; right: 0; top: 0; width: 10px; height: 100%; cursor: col-resize; z-index: 1; }
        `);
    }

    // --- UI & 交互 (No changes from V4.5) ---
    function setupUI() {
        const parentElement = document.getElementById(C.IDS.baiduPageContainer) || document.body;
        const container = document.createElement('div');
        container.id = C.IDS.container;
        parentElement.appendChild(container);

        if (parentElement.id !== C.IDS.baiduPageContainer) container.style.position = 'fixed';
        container.style.top = currentSettings.panelPosition.top;
        container.style.left = currentSettings.panelPosition.left;
        container.style.width = currentSettings.panelSize.width;
        container.style.height = currentSettings.panelSize.height;
        updatePositionByWidth();
        container.innerHTML = `...`; // Unchanged
        container.innerHTML = `
            <div class="${C.CLASSES.header}">
                <h2>Google 搜索结果</h2>
                <span class="${C.CLASSES.settingsIcon}">⚙️</span>
            </div>
            <div class="${C.CLASSES.content}"></div>
            <div class="${C.CLASSES.resizeHandle}"></div>`;

        const header = container.querySelector('.' + C.CLASSES.header);
        const settingsIcon = container.querySelector('.' + C.CLASSES.settingsIcon);
        const resizeHandle = container.querySelector('.' + C.CLASSES.resizeHandle);

        observerManager.addEventListener(settingsIcon, 'mousedown', (e) => { e.stopPropagation(); showSettingsModal(); });
        makeDraggable(container, header);
        makeResizable(container, resizeHandle);

        const debouncedSaveSettings = debounce(saveSettings, 500);
        observerManager.addObserver(new ResizeObserver(() => {
            if (document.getElementById(C.IDS.container)) {
                currentSettings.panelSize.width = container.style.width;
                if (!currentSettings.autoFitHeight) { currentSettings.panelSize.height = container.style.height; }
                debouncedSaveSettings();
            }
        })).observe(container);
        updatePanelStyle(container);
        return container;
    }

    function updatePanelStyle(container) {
        if (!container) return;
        const contentDiv = container.querySelector('.' + C.CLASSES.content);
        container.style.resize = 'none';
        if (currentSettings.autoFitHeight) {
            container.style.height = 'auto';
            if(contentDiv) contentDiv.style.overflowY = 'visible';
        } else {
            container.style.height = currentSettings.panelSize.height;
            if(contentDiv) contentDiv.style.overflowY = 'auto';
        }
    }

    function makeResizable(element, handle) {
        handle.onmousedown = function(e) {
            e.preventDefault(); e.stopPropagation();
            const initialWidth = element.offsetWidth;
            const initialX = e.clientX;
            const resizeElement = (e) => {
                const newWidth = initialWidth + (e.clientX - initialX);
                if (newWidth > CONFIG.UI.MIN_PANEL_WIDTH) { element.style.width = newWidth + 'px'; }
            };
            const stopResize = () => {
                document.removeEventListener('mousemove', resizeElement);
                document.removeEventListener('mouseup', stopResize);
            };
            document.addEventListener('mousemove', resizeElement);
            document.addEventListener('mouseup', stopResize);
        };
    }

    function makeDraggable(element, handle) {
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        handle.onmousedown = function(e) {
            if (e.target.classList.contains(C.CLASSES.settingsIcon)) return;
            e.preventDefault();
            pos3 = e.clientX; pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        };
        function elementDrag(e) {
            e.preventDefault();
            pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY;
            pos3 = e.clientX; pos4 = e.clientY;
            requestAnimationFrame(() => {
                element.style.top = (element.offsetTop - pos2) + "px";
                element.style.left = (element.offsetLeft - pos1) + "px";
            });
        }
        function closeDragElement() {
            document.onmouseup = null; document.onmousemove = null;
            currentSettings.panelPosition.top = element.style.top;
            if (window.innerWidth > CONFIG.UI.WIDE_SCREEN_BREAKPOINT) {
                currentSettings.panelPositionWide.left = element.style.left;
            } else {
                currentSettings.panelPosition.left = element.style.left;
            }
            saveSettings();
        }
    }

    function showSettingsModal() {
        let modal = document.getElementById(C.IDS.settingsModal);
        if (!modal) {
            modal = document.createElement('div');
            modal.id = C.IDS.settingsModal;
            modal.innerHTML = `...`; // Unchanged
            modal.innerHTML = `
            <div class="${C.CLASSES.settingsModalContent}" onclick="event.stopPropagation();">
                <h3>脚本设置</h3>
                <div class="${C.CLASSES.formItem}"><label><input type="checkbox" id="${C.IDS.settingEnabled}"> 启用脚本</label></div>
                <div class="${C.CLASSES.formItem}"><label for="${C.IDS.settingCount}">搜索结果数量</label><input type="number" id="${C.IDS.settingCount}" min="1" max="50" step="1"></div>
                <div class="${C.CLASSES.formItem}"><label><input type="checkbox" id="${C.IDS.settingNewTab}"> 在新标签页中打开链接</label></div>
                <div class="${C.CLASSES.formItem}"><label><input type="checkbox" id="${C.IDS.settingAutofit}"> 自适应内容高度</label></div>
                <div class="${C.CLASSES.formItem}"><label>大屏幕横向位置 (>${CONFIG.UI.WIDE_SCREEN_BREAKPOINT}px)</label><input type="text" id="${C.IDS.settingWideLeft}" placeholder="65%"></div>
                <div class="${C.CLASSES.buttons}"><button id="${C.IDS.settingReset}">恢复默认</button><button id="${C.IDS.settingSave}">保存并关闭</button></div>
            </div>`;
            document.body.appendChild(modal);

            const hideModal = () => { modal.style.display = 'none'; };
            observerManager.addEventListener(modal, 'click', hideModal);

            observerManager.addEventListener(document.getElementById(C.IDS.settingSave), 'click', () => {
                currentSettings.scriptEnabled = document.getElementById(C.IDS.settingEnabled).checked;
                currentSettings.resultCount = parseInt(document.getElementById(C.IDS.settingCount).value, 10);
                currentSettings.openInNewTab = document.getElementById(C.IDS.settingNewTab).checked;
                currentSettings.autoFitHeight = document.getElementById(C.IDS.settingAutofit).checked;
                currentSettings.panelPositionWide.left = document.getElementById(C.IDS.settingWideLeft).value;
                saveSettings(); hideModal(); runCheck({ forceUpdate: true }); updatePositionByWidth();
            });
            observerManager.addEventListener(document.getElementById(C.IDS.settingReset), 'click', () => {
                if (confirm('确定要恢复所有默认设置吗?')) {
                    GM_setValue(C.GM_SETTINGS_KEY, defaultSettings);
                    loadSettings(); hideModal(); runCheck({ forceUpdate: true });
                }
            });
        }
        document.getElementById(C.IDS.settingEnabled).checked = currentSettings.scriptEnabled;
        document.getElementById(C.IDS.settingCount).value = currentSettings.resultCount;
        document.getElementById(C.IDS.settingNewTab).checked = currentSettings.openInNewTab;
        document.getElementById(C.IDS.settingAutofit).checked = currentSettings.autoFitHeight;
        document.getElementById(C.IDS.settingWideLeft).value = currentSettings.panelPositionWide.left;
        modal.style.display = 'flex';
    }


    // --- 关键词标红功能 (No changes from V4.5) ---
    function getBaiduKeywords() {
        const baiduResultContainer = document.getElementById(C.IDS.baiduContent);
        if (!baiduResultContainer) return [];
        const keywordElements = baiduResultContainer.querySelectorAll(C.SELECTORS.keyword);
        return Array.from(new Set(Array.from(keywordElements).map(em => em.textContent.trim()).filter(Boolean)));
    }

    function highlightKeywords(text, keywordArray) {
        if (!text || !keywordArray || keywordArray.length === 0) return text;
        const cacheKey = keywordArray.join('|');
        let regex = regexCache.get(cacheKey);
        if (!regex) {
            const regexPattern = keywordArray.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
            if (!regexPattern) return text;
            regex = new RegExp(`(${regexPattern})`, 'gi');
            regexCache.set(cacheKey, regex);
        }
        return text.replace(regex, `<em>$1</em>`);
    }

    // --- 数据获取与渲染 ---
    function gmFetch(url) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET", url: url, timeout: CONFIG.PERFORMANCE.FETCH_TIMEOUT,
                onload: resolve,
                onerror: (err) => reject(new Error('NetworkError', { cause: err })),
                ontimeout: () => reject(new Error('RequestTimeout')),
            });
        });
    }

    async function gmFetchWithRetry(url, maxRetries = CONFIG.PERFORMANCE.RETRY_ATTEMPTS) {
        for (let i = 0; i < maxRetries; i++) {
            try { return await gmFetch(url); } catch (error) {
                console.warn(`Fetch attempt ${i + 1} failed for ${url}. Retrying...`, error);
                if (i === maxRetries - 1) throw error;
                await new Promise(resolve => setTimeout(resolve, CONFIG.PERFORMANCE.RETRY_DELAY_MS * (i + 1)));
            }
        }
    }

    async function fetchAndDisplayGoogleResults(query) {
        if (state.isLoading) return;

        const container = document.getElementById(C.IDS.container);
        if(!container) return;
        updatePanelStyle(container);

        const contentDiv = container.querySelector('.' + C.CLASSES.content);
        if (!contentDiv) return;

        // --- NEW: Check cache first ---
        const cachedData = SessionCache.get(query);
        if (cachedData) {
            console.log(`[Cache] Hit for query: ${query}`);
            contentDiv.innerHTML = cachedData.html;
            return;
        }

        console.log(`[Cache] Miss for query: ${query}. Fetching from network.`);
        state.isLoading = true;

        contentDiv.innerHTML = '';
        const statusDiv = document.createElement('div');
        statusDiv.id = C.IDS.fetchStatus;
        statusDiv.className = C.CLASSES.status;
        statusDiv.textContent = '正在加载...';
        contentDiv.appendChild(statusDiv);

        let renderedCount = 0;
        let startIndex = 0;
        const baiduKeywords = getBaiduKeywords();
        const highlightKeywordsList = baiduKeywords.length > 0 ? baiduKeywords : query.split(' ');
        let collectedHTML = ''; // To store the generated HTML for caching

        try {
            while (renderedCount < currentSettings.resultCount) {
                statusDiv.textContent = `已获取 ${renderedCount} 条,正在加载第 ${startIndex + 1}-${startIndex + CONFIG.GOOGLE.RESULTS_PER_PAGE} 条...`;
                const searchUrl = `https://www.google.com/search?q=${encodeURIComponent(query)}&num=${CONFIG.GOOGLE.RESULTS_PER_PAGE}&start=${startIndex}`;
                const response = await gmFetchWithRetry(searchUrl);
                const doc = new DOMParser().parseFromString(response.responseText, "text/html");
                const results = Array.from(doc.querySelectorAll(C.SELECTORS.googleResult));

                if (results.length === 0) {
                    if (renderedCount === 0) statusDiv.textContent = `未找到 Google 结果。`;
                    break;
                }

                let newResultsFoundInPage = 0;
                results.forEach(result => {
                    if (renderedCount >= currentSettings.resultCount) return;
                    const link = result.querySelector(C.SELECTORS.link);
                    const title = result.querySelector(C.SELECTORS.title);
                    if (link?.href && title) {
                        newResultsFoundInPage++;
                        if (link.getAttribute('href').startsWith('/')) { link.href = 'https://www.google.com' + link.getAttribute('href'); }

                        const descriptionContainer = Array.from(result.querySelectorAll('div')).find(d => d.innerText && d.innerText.length > 40 && !d.querySelector('div'));
                        const item = document.createElement('div');
                        item.className = C.CLASSES.resultItem;
                        const target = currentSettings.openInNewTab ? 'target="_blank"' : '';

                        const highlightedTitle = highlightKeywords(title.innerText, highlightKeywordsList);
                        const highlightedDescription = highlightKeywords(descriptionContainer?.innerText || '', highlightKeywordsList);

                        // Build item's innerHTML
                        item.innerHTML = `<a href="${link.href}" ${target} rel="noopener noreferrer">${highlightedTitle}</a><div class="${C.CLASSES.url}">${new URL(link.href).hostname}</div><div class="${C.CLASSES.description}">${highlightedDescription}</div>`;

                        // Insert into DOM
                        contentDiv.insertBefore(item, statusDiv);

                        // Append its outerHTML to our collection for caching
                        collectedHTML += item.outerHTML;

                        renderedCount++;
                    }
                });
                if (newResultsFoundInPage === 0) break;
                startIndex += CONFIG.GOOGLE.RESULTS_PER_PAGE;
            }
            statusDiv.textContent = `已加载全部 ${renderedCount} 条结果。`;
            collectedHTML += statusDiv.outerHTML; // Also cache the final status message

            // --- NEW: Set data in cache after successful fetch ---
            SessionCache.set(query, { html: collectedHTML, timestamp: Date.now() });

        } catch (error) {
            statusDiv.textContent = ErrorHandler.handle(error, 'Google Fetch');
        } finally {
            state.isLoading = false;
        }
    }

    // --- 主逻辑与监听 ---
    function getQuery() { return new URLSearchParams(window.location.search).get('wd'); }

    function runCheck(options = {}) {
        loadSettings();
        const query = getQuery();

        let mainContainer = document.getElementById(C.IDS.container);
        if (!mainContainer) {
            domCache.clear();
            mainContainer = setupUI();
        }

        if (!query || !currentSettings.scriptEnabled) {
            mainContainer.style.display = 'none';
            return;
        }
        mainContainer.style.display = 'flex';
        applyStyles();

        if (query !== state.lastQuery || options.forceUpdate) {
            state.lastQuery = query;
            fetchAndDisplayGoogleResults(query);
        }
    }

    function updatePositionByWidth() {
        const container = document.getElementById(C.IDS.container);
        if (!container) return;
        container.style.left = window.innerWidth > CONFIG.UI.WIDE_SCREEN_BREAKPOINT ? currentSettings.panelPositionWide.left : currentSettings.panelPosition.left;
    }

    // --- Entry Point ---
    runCheck();
    const debouncedRunCheck = debounce(runCheck, CONFIG.PERFORMANCE.DEBOUNCE_DELAY);

    const observer = observerManager.addObserver(new MutationObserver((mutationsList) => {
        for (const mutation of mutationsList) {
            if (mutation.type === 'childList') {
                for (const node of mutation.addedNodes) {
                    if (node.nodeType === 1 && (node.id === C.IDS.baiduContent || node.querySelector('#' + C.IDS.baiduContent))) {
                        debouncedRunCheck();
                        return;
                    }
                }
            }
        }
    }));
    observer.observe(document.body, { childList: true, subtree: true });

    const debouncedUpdatePosition = debounce(updatePositionByWidth, 200);
    setTimeout(updatePositionByWidth, 500);
    observerManager.addEventListener(window, 'resize', debouncedUpdatePosition);
    observerManager.addEventListener(window, 'beforeunload', () => observerManager.cleanup());

})();