Advanced Search Assistant for Google

Add an advanced search form to the top of the page

目前為 2023-11-24 提交的版本,檢視 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name                    Advanced Search Assistant for Google
// @name:zh-CN              Google 高级搜索助手
// @namespace               http://tampermonkey.net/
// @version                 0.1.7
// @description             Add an advanced search form to the top of the page
// @description:zh-CN       在谷歌搜索页面顶部添加一个高级搜索表单
// @author                  shiquda
// @namespace               https://github.com/shiquda/shiquda_UserScript
// @supportURL              https://github.com/shiquda/shiquda_UserScript/issues
// @match                   *://www.google.com/search*
// @include                 *://*google*/search*
// @grant                   GM_addStyle
// @grant                   GM_setValue
// @grant                   GM_getValue
// @license                 MIT
// ==/UserScript==

(function () {

    'use strict';
    let isMobile = false;
    if (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) ||
        navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) ||
        navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) ||
        navigator.userAgent.match(/Windows Phone/i)) {
        // On mobile device
        isMobile = true;
    }

    let isDarkMode = false;
    try {
        let logoImg = document.querySelector('#logo')?.querySelector('img') ? document.querySelector('#logo')?.querySelector('img') : document.querySelector('#qslc')?.querySelector('img'); //
        if (logoImg.src.match(/light/)) {
            // Dark mode is enabled
            isDarkMode = true;
        }
    }
    catch {
        console.log("Failed to determine the color mode.")
    }


    const userLanguage = '' // You can set your language config here manually. 'zh-CN' & 'en' are supported now.

    const supportedLanguages = ['zh-CN', 'en']

    const translation = {
        'as_q': {
            'zh-CN': '搜索字词:',
            'en': 'Search word:'
        },
        'as_epq': {
            'zh-CN': '与以下字词完全匹配:',
            'en': 'Match the following words exactly:'
        },
        'as_oq': {
            'zh-CN': '包含以下任意字词:',
            'en': 'Contains any of the following words:'
        },
        'as_eq': {
            'zh-CN': '排除以下字词:',
            'en': 'Exclude the following words:'
        },
        'as_nlo': {
            'zh-CN': '包含的数字范围:从',
            'en': 'Number range: from'
        },
        'as_nhi': {
            'zh-CN': '到:',
            'en': 'to:'
        },
        'lr': {
            'zh-CN': '语言:',
            'en': 'Language:'
        },
        'cr': {
            'zh-CN': '地区:',
            'en': 'Region:'
        },
        'as_qdr': {
            'zh-CN': '最后更新时间:',
            'en': 'Last update time:'
        },
        'as_sitesearch': {
            'zh-CN': '网站或域名:',
            'en': 'Website or domain:'
        },
        'as_occt': {
            'zh-CN': '字词出现位置:',
            'en': 'Word position:'
        },
        'as_filetype': {
            'zh-CN': '文件类型:',
            'en': 'File type:'
        },
        'tbs': {
            'zh-CN': '使用权限:',
            'en': 'Usage rights:'
        },
        'advancedSearch': {
            'zh-CN': '高级搜索',
            'en': 'Advanced Search'
        },
        'search': {
            'zh-CN': '搜索',
            'en': 'Search'
        },
        'clear': {
            'zh-CN': '清空',
            'en': 'Clear'
        },
        'as_qdr_select': {
            '': {
                'zh-CN': '请选择',
                'en': 'Please select',
            },
            'd': {
                'zh-CN': '一天内',
                'en': 'Past 24 hours',
            },
            'w': {
                'zh-CN': '一周内',
                'en': 'Past week',
            },
            'm': {
                'zh-CN': '一月内',
                'en': 'Past month',
            },
            'y': {
                'zh-CN': '一年内',
                'en': 'Past year',
            },
        },
        'as_occt_select': {
            '': {
                'zh-CN': '请选择',
                'en': 'Please select',
            },
            'title': {
                'zh-CN': '网页标题中',
                'en': 'In the title of the web page',
            },
            'body': {
                'zh-CN': '网页正文中',
                'en': 'In the body of the web page',
            },
            'url': {
                'zh-CN': '网页网址中',
                'en': 'In the URL of the web page',
            },
            'links': {
                'zh-CN': '指向网页的链接中',
                'en': 'In the links to the web page',
            },
        }
    }
    const style = `
    #advancedSearchToggleButton {
        margin-right: 10px;
        border: none;
        border-radius: 5px;
        background-color: #007bff;
        color: #fff;
        font-size: 14px;
        font-weight: bold;
        margin: 10px;
    }


    #advancedSearchFormContainer {
        position: fixed;
        ${isMobile ? 'top: 150px;' : 'top: 130px;'}
        ${isMobile ? 'left: 15px;' : 'left: 30px;'}
        display: none;
        padding: 10px;
        border: 1px solid #ccc;
        border-radius: 5px;
        font-size: 14px;
        font-weight: bold;
        ${isDarkMode ? 'background-color: rgba(0, 0, 0, 1);' : 'background-color: rgba(255, 255, 255, 1);'}
        ${isMobile ? 'column-count: 2;' : ''} /* 在移动设备上分为两列 */
    }


    #advancedSearchFormContainer label {
        display: block;
        margin-top: 5px;
    }


    #advancedSearchFormContainer input[type="text"] {
        margin-top: 5px;
        padding: 5px;
        border: 1px solid #ccc;
        border-radius: 5px;
    }

    #advancedSearchFormContainer select {
        margin-top: 5px;
        padding: 5px;
        border-radius: 5px;
    }

    #advancedSearchFormContainer button {
        border: none;
        border-radius: 5px;
        background-color: #007bff;
        color: #fff;
        font-size: 14px;
        font-weight: bold;
        margin: 20px;
    }
    `
    GM_addStyle(style)

    const language = supportedLanguages.includes(userLanguage) ? userLanguage : supportedLanguages.includes(navigator.language) ? navigator.language : 'en'
    // Create user interface
    const toggleButton = document.createElement('button');
    toggleButton.className = 'nfSF8e';
    toggleButton.textContent = translation['advancedSearch'][language];
    toggleButton.id = 'advancedSearchToggleButton'
    if (isMobile) {
        document.querySelector('.Fh5muf').appendChild(toggleButton);
    } else {
        document.querySelector('.logo').appendChild(toggleButton);
    }


    const formContainer = document.createElement('div');
    formContainer.id = 'advancedSearchFormContainer'
    document.body.appendChild(formContainer);

    // 
    const form = document.createElement('form');
    formContainer.appendChild(form);

    const params = {
        'as_q': translation['as_q'][language],
        'as_epq': translation['as_epq'][language],
        'as_oq': translation['as_oq'][language],
        'as_eq': translation['as_eq'][language],
        'as_nlo': translation['as_nlo'][language],
        'as_nhi': translation['as_nhi'][language],
        // 'lr': translation['lr'][language],
        // 'cr': translation['cr'][language],
        'as_qdr': {
            'name': translation['as_qdr'][language],
            'options':
            {
                '': translation['as_qdr_select'][''][language],
                'd': translation['as_qdr_select']['d'][language],
                'w': translation['as_qdr_select']['w'][language],
                'm': translation['as_qdr_select']['m'][language],
                'y': translation['as_qdr_select']['y'][language],
            }
        },
        'as_sitesearch': translation['as_sitesearch'][language],
        'as_occt': {
            'name': translation['as_occt'][language],
            'options':
            {
                '': translation['as_occt_select'][''][language],
                'title': translation['as_occt_select']['title'][language],
                'body': translation['as_occt_select']['body'][language],
                'url': translation['as_occt_select']['url'][language],
                'links': translation['as_occt_select']['links'][language],
            }
        },
        'as_filetype': translation['as_filetype'][language],
        // 'tbs': translation['tbs'][language],
    }

    for (const param in params) {
        if (typeof params[param] === 'object') {
            const label = document.createElement('label');
            label.textContent = params[param].name;
            const select = document.createElement('select');
            select.name = param;

            Object.keys(params[param]['options']).forEach(option => {
                const optionElement = document.createElement('option');
                optionElement.value = option;
                optionElement.textContent = params[param]['options'][option];
                select.appendChild(optionElement);
            });

            form.appendChild(label);
            form.appendChild(select);
            form.appendChild(document.createElement('br'));
            continue;
        }
        const label = document.createElement('label');
        label.textContent = params[param];
        const input = document.createElement('input');
        input.name = param;
        input.type = 'text';
        form.appendChild(label);
        form.appendChild(input);
        form.appendChild(document.createElement('br'));
    }

    const searchButton = document.createElement('button');
    searchButton.textContent = translation['search'][language];
    form.appendChild(searchButton);

    // Add a clear button to reset the form
    const clearButton = document.createElement('button');
    clearButton.textContent = translation['clear'][language];
    clearButton.addEventListener('click', function (event) {
        event.preventDefault();
        form.reset();
    });
    form.appendChild(clearButton);

    // Load saved data and fill the form when opening a new page
    window.addEventListener('load', function () {
        for (const param in params) {
            const savedValue = GM_getValue(param);
            if (savedValue) {
                form[param].value = savedValue;
            }
        }
    });

    // Save form data to Greasemonkey storage
    form.addEventListener('input', function () {
        for (const param in params) {
            GM_setValue(param, form[param].value);
        }
    });

    // Toggle the form display
    toggleButton.addEventListener('click', function (event) {
        event.preventDefault();
        let status = formContainer.style.display;
        status = status === 'none' || status === '' ? 'block' : 'none';
        formContainer.style.display = status;
    });

    // Submit the form
    form.addEventListener('submit', function (event) {
        event.preventDefault();
        const searchParams = new URLSearchParams();
        for (const param in params) {
            const value = form[param].value;
            if (value) {
                searchParams.set(param, value);
            }
        }
        const searchUrl = 'https://www.google.com/search?' + searchParams.toString();
        window.location.href = searchUrl;
    });
}
)();