Bypass Google Search Region

Add button to bypass Google Search region

目前為 2025-05-05 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Bypass Google Search Region
// @namespace    http://tampermonkey.net/
// @version      2.2
// @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 = {
        'CN': 'China',
        '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 ensureBypassCookie(gl) {
        const expectedValue = `gl=${gl}:safe=${ACTIVE_SAFE}`;
        const maxAge = 60 * 60 * 24 * 365 * 5; // 5년

        const hasPrefCookie = document.cookie.includes(`PREF=${expectedValue}`);
        if (!hasPrefCookie) {
            const cookieValue = `PREF=${expectedValue}; max-age=${maxAge}; path=/`;
            document.cookie = `${cookieValue}; domain=.google.com`;
            document.cookie = `${cookieValue}; domain=${window.location.hostname}`;
        }
    }

    // 우회 검색을 적용하는 함수
    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'); // 개인화된 검색 결과 비활성화

        ensureBypassCookie(gl);

        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 + window.scrollX}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);
    }

    // 쿠키 주기적 유지
    function keepBypassCookieAlive() {
        const gl = localStorage.getItem('google_settings_gl');
        if (gl) ensureBypassCookie(gl);
    }

    window.addEventListener('load', keepBypassCookieAlive);
    setInterval(keepBypassCookieAlive, 60 * 60 * 1000); // 1시간마다

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

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