Advanced Search Assistant for Google

Add an advanced search form to the top of the page

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

// ==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;
    });
}
)();