Bypass Google Search Region

Add button to bypass Google Search region

当前为 2025-05-04 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Bypass Google Search Region
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  Add button to bypass Google Search region
// @match        *://*.google.com/search*
// @match        *://*.google.co.kr/search*
// @match        *://*.google.*/search*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const SCRIPT_ID = 'bypass-button';
    const DESKTOP_ID = 'bypass-desktop-button';
    const MOBILE_ID = 'bypass-mobile-button';
    const ACTIVE_SAFE = 'off';

    // 지역 코드와 이름을 매핑한 객체 (알파벳 순으로 정렬)
    const REGION_OPTIONS = {
        'GH': 'Ghana',
        'JP': 'Japan',
        'KR': 'Korea',
        'US': 'USA'
    };

    let activeGl = null;  // 기본적으로 아무 지역도 선택되지 않음

    // 페이지 언어를 확인 (ko, en만 체크)
    function getPageLanguage() {
        const lang = navigator.language || navigator.userLanguage;
        if (lang.startsWith('ko')) return 'ko';
        if (lang.startsWith('en')) return 'en';
        return null;
    }

    // 우회 검색을 적용하는 함수
    function applyBypass(gl) {
        if (!gl) return;

        const url = new URL(window.location.href);
        url.searchParams.set('gl', gl);  // 선택한 국가 코드로 gl 파라미터 설정
        url.searchParams.set('safe', ACTIVE_SAFE);
        url.searchParams.set('pws', '0'); // 개인화된 검색 결과 비활성화

        // 쿠키와 로컬 스토리지에 설정 저장
        document.cookie = `PREF=gl=${gl}:safe=${ACTIVE_SAFE}; expires=Fri, 31 Dec 2030 23:59:59 GMT; path=/; domain=.google.com`;
        document.cookie = `PREF=gl=${gl}:safe=${ACTIVE_SAFE}; expires=Fri, 31 Dec 2030 23:59:59 GMT; path=/; domain=${window.location.hostname}`;

        try {
            localStorage.setItem('google_settings_gl', gl);
            localStorage.setItem('google_settings_safe', ACTIVE_SAFE);
        } catch (e) {}

        // 페이지 리디렉션
        window.location.href = url.toString();
    }

    // 우회 검색을 해제하는 함수
    function clearBypass() {
        const url = new URL(window.location.href);
        url.searchParams.delete('gl');
        url.searchParams.delete('safe');
        url.searchParams.delete('pws');

        // 쿠키와 로컬 스토리지에서 설정 삭제
        document.cookie = `PREF=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.google.com`;
        document.cookie = `PREF=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${window.location.hostname}`;

        try {
            localStorage.removeItem('google_settings_gl');
            localStorage.removeItem('google_settings_safe');
        } catch (e) {}

        // 페이지 리디렉션
        window.location.href = url.toString();
    }

    // 현재 우회 상태를 확인하는 함수
    function isBypassActive() {
        const url = new URL(window.location.href);
        return url.searchParams.has('gl') && url.searchParams.get('safe') === ACTIVE_SAFE;
    }

    // 우회 상태를 토글하는 함수
    function toggleBypass() {
        if (isBypassActive()) {
            clearBypass();
        } else if (activeGl) {
            applyBypass(activeGl);
        }
    }

    // 버튼 텍스트를 현재 언어 및 상태에 따라 업데이트
    function updateText(btn) {
        if (btn) {
            const lang = getPageLanguage();
            const bypassText = lang === 'ko' ? '우회 검색' : 'Bypass Search';
            const clearText = lang === 'ko' ? '우회 해제' : 'Remove Bypass';
            btn.textContent = isBypassActive() ? clearText : bypassText;
        }
    }

    // 지역 선택 팝업 생성
    function createRegionPopup(triggerEl) {
        const existing = document.getElementById('gl-popup');
        if (existing) existing.remove();

        const popup = document.createElement('div');
        popup.id = 'gl-popup';
        popup.style.position = 'absolute';
        popup.style.top = `${triggerEl.getBoundingClientRect().bottom + window.scrollY}px`;
        popup.style.left = `${triggerEl.getBoundingClientRect().left}px`;
        popup.style.background = '#fff';
        popup.style.border = '1px solid #ccc';
        popup.style.zIndex = '9999';
        popup.style.fontSize = '14px';
        popup.style.boxShadow = '0 2px 6px rgba(0,0,0,0.2)';

        Object.entries(REGION_OPTIONS).forEach(([code, name]) => {
            const item = document.createElement('div');
            item.textContent = name;
            item.style.padding = '6px 12px';
            item.style.cursor = 'pointer';
            item.onclick = () => {
                activeGl = code;  // 선택된 지역 코드 저장
                applyBypass(code); // 선택된 지역으로 우회 적용
            };
            popup.appendChild(item);
        });

        document.body.appendChild(popup);
        document.addEventListener('click', function onClickOutside(e) {
            if (!popup.contains(e.target)) {
                popup.remove();
                document.removeEventListener('click', onClickOutside);
            }
        });
    }

    // 데스크톱 버튼 추가
    function addDesktopButton() {
        const interval = setInterval(() => {
            const tool = document.querySelector('#hdtb-tls');
            if (tool && tool.parentElement && !document.getElementById(DESKTOP_ID)) {
                clearInterval(interval);
                const btn = document.createElement('div');
                btn.id = DESKTOP_ID;
                btn.className = 'hdtb-mitem';
                btn.style.cursor = 'pointer';
                btn.style.userSelect = 'none';
                updateText(btn);  // 버튼 텍스트를 현재 언어에 맞게 업데이트
                btn.onclick = toggleBypass;

                const arrow = document.createElement('div');
                arrow.className = 'hdtb-mitem';
                arrow.style.cursor = 'pointer';
                arrow.style.marginLeft = '6px';
                arrow.style.marginRight = '12px';  // 화살표와 버튼 사이에 여유 공간 추가
                arrow.textContent = '▼';
                arrow.onclick = (e) => {
                    e.stopPropagation();
                    createRegionPopup(arrow);
                };

                tool.parentElement.insertBefore(arrow, tool.nextSibling);
                tool.parentElement.insertBefore(btn, arrow);
            }
        }, 500);
    }

    // 모바일 버튼 추가
    function addMobileButton() {
        if (document.getElementById(MOBILE_ID)) return;

        const lang = getPageLanguage();
        const label = lang === 'ko' ? '고급검색' : (lang === 'en' ? 'Advanced Search' : null);
        if (!label) return;

        const advancedSearch = Array.from(document.querySelectorAll('a')).find(a => a.textContent.trim() === label);
        if (!advancedSearch || !advancedSearch.parentElement) return;

        const clone = advancedSearch.parentElement.cloneNode(true);
        const link = clone.querySelector('a');
        if (!link) return;

        clone.id = MOBILE_ID;
        updateText(link);  // 버튼 텍스트를 현재 언어에 맞게 업데이트
        link.style.cursor = 'pointer';
        link.removeAttribute('href');
        link.onclick = toggleBypass;

        const arrow = document.createElement('a');
        arrow.textContent = '▼';
        arrow.style.marginLeft = '6px';
        arrow.style.marginRight = '12px';  // 화살표와 버튼 사이에 여유 공간 추가
        arrow.style.cursor = 'pointer';
        arrow.onclick = (e) => {
            e.stopPropagation();
            createRegionPopup(arrow);
        };

        advancedSearch.parentElement.insertAdjacentElement('afterend', clone);
        clone.insertAdjacentElement('afterend', arrow);
    }

    // DOM 변화 감지하여 모바일 버튼 계속 감시
    const observer = new MutationObserver(() => {
        addMobileButton();
    });
    observer.observe(document.body, { childList: true, subtree: true });

    // 초기 실행
    addDesktopButton();
    addMobileButton();
})();