Betty Modern

Enhanced open directory finder for modern Google search

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name            Betty Modern
// @namespace       mario0318.com
// @author          Raul Torres (Modern adaptation of Betty - Open directory search assistant)
// @version         0.7.0
// @license         GPLv3
// @description     Enhanced open directory finder for modern Google search
// @icon            https://raw.githubusercontent.com/sgeto/Betty/master/betty-space%20invader%20emoji.png
// @match           https://www.google.com/*
// @exclude         https://www.google.com/images/*
// @exclude         https://www.google.com/video/*
// @run-at          document-end
// @require         https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js
// @grant           GM_xmlhttpRequest
// ==/UserScript==
/*
 * Original Betty script created by:
 * - Ali Abdulkadir (sgeto)
 * - Jorge Frisancho (teocci)
 * - jO9GEc
 *
 * Modern adaptation by mario0318
 *
 * This work is derived from:
 * https://github.com/sgeto/Betty (Original repository)
 * Licensed under GPL-3.0 - https://www.gnu.org/licenses/gpl-3.0.html
 */

(function() {
    'use strict';

    // Modern Google search form handling
    function enhanceSearchForm() {
        const searchBox = document.querySelector('textarea[name="q"], input[name="q"]');
        if (!searchBox) return;

        const form = searchBox.closest('form');
        if (!form) return;

        // Preserve original form submission
        const originalSubmit = form.submit.bind(form);
        form.addEventListener('submit', function(e) {
            e.preventDefault();
            originalSubmit();
        });

        // Create radio buttons container
        const radioContainer = document.createElement('div');
        radioContainer.id = 'betty-radio-container';
        radioContainer.style.margin = '10px 0';
        radioContainer.style.display = 'flex';
        radioContainer.style.flexWrap = 'wrap';
        radioContainer.style.gap = '12px';

        // Radio button definitions
        const options = [
            { name: 'Web', value: '' },
            { name: 'Music', value: '+(mp3|wav|ac3|ogg|flac|wma|m4a) -inurl:(jsp|pl|php|html|aspx|htm|cf|shtml) intitle:index.of "last modified" -inurl:(listen77|mp3raid|mp3toss|mp3drug|index_of|wallywashis)' },
            { name: 'Video', value: '+(mkv|mp4|avi|mov|mpg|wmv) -inurl:(jsp|pl|php|html|aspx|htm|cf|shtml) intitle:index.of "last modified" -inurl:(listen77|mp3raid|mp3toss|mp3drug|index_of|wallywashis)' },
            { name: 'Files', value: 'intitle:"index of" -inurl:(jsp|pl|php|html|aspx|htm|cf|shtml) -inurl:(listen77|mp3raid|mp3toss|mp3drug|index_of|wallywashis)' },
            { name: 'Archives', value: '+(rar|zip|tar|tgz|7zip|iso|cso|gz|7z|bz2|gzip) intitle:"index of" -inurl:(jsp|pl|php|html|aspx|htm|cf|shtml) -inurl:(listen77|mp3raid|mp3toss|mp3drug|index_of|wallywashis)' },
            { name: 'Software', value: '+(exe|iso|tar|msi|rar|deb|zip|apk) -inurl:(jsp|pl|php|html|aspx|htm|cf|shtml) intitle:index.of "last modified" -inurl:(listen77|mp3raid|mp3toss|mp3drug|index_of|wallywashis)' },
            { name: 'Books', value: '+(mobi|cbz|cbr|cbc|chm|epub|fb2|lit|lrf|odt|pdf|prc|pdb|pml|rb|rtf|tcr|doc|docx) -inurl:(jsp|pl|php|html|aspx|htm|cf|shtml) intitle:index.of "last modified" -inurl:(listen77|mp3raid|mp3toss|mp3drug|index_of|wallywashis)' }
        ];

        // Create radio buttons
        options.forEach(opt => {
            const wrapper = document.createElement('div');
            wrapper.style.display = 'flex';
            wrapper.style.alignItems = 'center';
            wrapper.style.gap = '4px';

            const radio = document.createElement('input');
            radio.type = 'radio';
            radio.name = 'betty-search-type';
            radio.value = opt.value;
            radio.id = `betty-${opt.name.toLowerCase()}`;
            radio.style.margin = '0';

            if (opt.name === 'Web') radio.checked = true;

            radio.addEventListener('change', () => {
                searchBox.value = opt.value ? opt.value : '';
            });

            const label = document.createElement('label');
            label.htmlFor = radio.id;
            label.textContent = opt.name;
            label.style.color = '#70757a';
            label.style.fontSize = '14px';

            wrapper.appendChild(radio);
            wrapper.appendChild(label);
            radioContainer.appendChild(wrapper);
        });

        // Insert radio buttons after search box
        searchBox.parentElement.insertAdjacentElement('afterend', radioContainer);
    }

    // Enhanced cache link exposure
    function enhanceCacheLinks() {
        const results = document.querySelectorAll('div.g, div[data-snc]');

        results.forEach(result => {
            const menu = result.querySelector('div[role="button"][aria-label="More options"]');
            if (!menu) return;

            const cachedLink = Array.from(menu.parentElement.querySelectorAll('a')).find(a =>
                a.href.includes('webcache.googleusercontent.com')
            );

            if (cachedLink) {
                const clone = cachedLink.cloneNode(true);
                clone.textContent = 'Cached';
                clone.style.marginLeft = '12px';
                clone.style.fontSize = '14px';
                result.querySelector('a[href]:first-child').insertAdjacentElement('afterend', clone);
            }
        });
    }

    // Initialize
    function init() {
        if (window.location.href === 'https://www.google.com/' ||
            window.location.href.startsWith('https://www.google.com/search')) {
            enhanceSearchForm();
        }

        if (window.location.href.startsWith('https://www.google.com/search')) {
            const observer = new MutationObserver(mutations => {
                if (document.querySelector('div#betty-radio-container')) return;
                enhanceCacheLinks();
            });

            observer.observe(document.body, {
                childList: true,
                subtree: true
            });

            enhanceCacheLinks();
        }
    }

    // Wait for DOM and initialize
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();