☰

Highlight Text Search Buttons

Show search buttons when text is highlighted on specific websites

Terá de instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

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

Terá de instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Terá de instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Terá de instalar uma extensão como Tampermonkey para instalar este script.

Terá de instalar uma extensão de gestão de scripts de utilizador para instalar este script.

(Já tenho um gestor de scripts de utilizador, deixe-me instalá-lo!)

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

(Já tenho um gestor de estilos de utilizador, deixe-me instalá-lo!)

// ==UserScript==
// @name         Highlight Text Search Buttons
// @namespace    http://tampermonkey.net/
// @version      2.1
// @description  Show search buttons when text is highlighted on specific websites
// @match        *://onlyfans.com/*
// @match        *://camwhores.tv/*
// @match        https://www.camwhores.tv/*
// @match         https://www.showcamrips.com/*
// @match        *://livecamrips.to/*
// @match        *://simpcity.cr/*
// @match        *://forums.socialmediagirls.com/*
// @match        *://camgirlfinder.net/*
// @match        *://nrtool.st/*
// @match         *://archivebate.com/*
// @match         *://nobodyhome.ws/*
// @match         *://camsmut.com/*
// @match         *://stripchat.com/*
// @match         *://*.bongocams.com/*
// @match         *://www.sexycamx.com/*
// @match         *://chaturbate.com/*
// @match         *://striptube.cc/*
// @match         *://forums.socialmediagirls.com/*
// @match         *://recu.me/*
// @match         *://camripvault.site/*
// @grant        GM_openInTab
// @grant        unsafeWindow
// @license MIT
// ==/UserScript==
(function() {
    'use strict';

    // ============ CONFIGURATION ============

    // Default search sites configuration
    const defaultSites = [
        { name: 'camripvault', url: 'https://camripvault.site/browse?query={username}' },
        { name: 'showcamrips', url: 'https://showcamrips.com/model/en/{username}/' },
        { name: 'livecamrips', url: 'https://www.livecamrips.to/search/{username}/1' },
        { name: 'archivebate', url: 'https://archivebate.com/profile/{username}' },
        { name: 'camsmut', url: 'https://camsmut.com/search?q={username}//' },
        { name: 'camwhores', url: 'https://camwhores.tv/search/{username}/' },
        { name: 'nobodyhome', url: 'https://nobodyhome.ws/search.php?action=do_search&postthread=1&keywords={username}' },
        { name: 'camgirlfinder', url: 'https://camgirlfinder.net/models?model={username}&platform=&gender=' },
        { name: 'nrtool', url: 'https://nrtool.st/nrtool/search?s={username}' },
        { name: 'simpcity', url: 'https://simpcity.cr/search/1/?q={username}' },
        { name: 'socialmediagirls', url: 'https://forums.socialmediagirls.com/search/579063442/?q={username}&o=relevance' },
        { name: 'bongocams', url: 'https://ru3.bongocams.com/{username}' },
        { name: 'stripchat', url: 'https://stripchat.com/{username}' },
        { name: 'onlyfans', url: 'https://onlyfans.com/{username}' },
        { name: 'sexycamx', url: 'https://www.sexycamx.com/{username}' },
        { name: 'recume', url: 'https://recu.me/performer/{username}' },
        { name: 'striphub', url: 'https://striptube.cc/performer/{username}' }
    ];


    // ============ SCRIPT LOGIC ============

    let buttonContainer = null;
    let selectedText = '';
    let useLowercase = false;

    // Enhanced function to open URL in new tab (bypasses site restrictions)
    function openUrlInNewTab(url) {
        // Method 1: Try GM_openInTab if available (most reliable)
        if (typeof GM_openInTab !== 'undefined') {
            try {
                GM_openInTab(url, { active: false, insert: true });
                return;
            } catch (e) {
                console.log('GM_openInTab failed, trying alternatives');
            }
        }

        // Method 2: Create a temporary anchor element with download attribute trick
        try {
            const a = document.createElement('a');
            a.href = url;
            a.target = '_blank';
            a.rel = 'noopener noreferrer';

            // This helps bypass some restrictions
            a.style.display = 'none';
            document.body.appendChild(a);

            // Dispatch a real click event
            const evt = new MouseEvent('click', {
                bubbles: true,
                cancelable: true,
                view: window
            });
            a.dispatchEvent(evt);

            // Clean up
            setTimeout(() => document.body.removeChild(a), 100);
            return;
        } catch (e) {
            console.log('Anchor method failed, trying window.open');
        }

        // Method 3: Standard window.open with enhanced parameters
        try {
            const newWindow = window.open(url, '_blank', 'noopener,noreferrer');
            if (newWindow) {
                newWindow.opener = null;
            }
        } catch (e) {
            // Method 4: Last resort - use location.href in a timeout
            console.log('All methods failed, using location fallback');
            setTimeout(() => {
                window.location.href = url;
            }, 100);
        }
    }

    // Create button container
    function createButtonContainer() {
        const container = document.createElement('div');
        container.id = 'highlight-search-container';
        container.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            display: none;
            flex-direction: column;
            gap: 6px;
            z-index: 999999;
            padding: 10px;
            background: rgba(255, 255, 255, 0.98);
            border-radius: 10px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
            backdrop-filter: blur(10px);
            border: 1px solid rgba(0, 0, 0, 0.1);
            max-width: 180px;
            max-height: 80vh;
            overflow-y: auto;
        `;

        // Add title
        const title = document.createElement('div');
        title.textContent = 'Search with:';
        title.style.cssText = `
            font-size: 11px;
            font-weight: 600;
            color: #666;
            margin-bottom: 2px;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
        `;
        container.appendChild(title);

        // Add lowercase checkbox
        const checkboxContainer = document.createElement('label');
        checkboxContainer.style.cssText = `
            display: flex;
            align-items: center;
            gap: 6px;
            font-size: 11px;
            color: #666;
            margin-bottom: 4px;
            cursor: pointer;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
        `;

        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.checked = useLowercase;
        checkbox.style.cssText = `
            cursor: pointer;
            width: 14px;
            height: 14px;
        `;

        checkbox.addEventListener('change', (e) => {
            useLowercase = e.target.checked;
        });

        const checkboxLabel = document.createElement('span');
        checkboxLabel.textContent = 'Lowercase';

        checkboxContainer.appendChild(checkbox);
        checkboxContainer.appendChild(checkboxLabel);
        container.appendChild(checkboxContainer);

        // Create buttons
        defaultSites.forEach(site => {
            const button = document.createElement('button');
            button.textContent = site.name;
            button.style.cssText = `
                padding: 6px 10px;
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                border: none;
                border-radius: 6px;
                cursor: pointer;
                font-size: 12px;
                font-weight: 500;
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
                transition: all 0.2s ease;
                white-space: nowrap;
                text-align: center;
            `;

            button.addEventListener('mouseenter', () => {
                button.style.transform = 'translateY(-1px)';
                button.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.2)';
            });

            button.addEventListener('mouseleave', () => {
                button.style.transform = 'translateY(0)';
                button.style.boxShadow = 'none';
            });

            button.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();

                const username = useLowercase ? selectedText.toLowerCase() : selectedText;
                const finalUrl = site.url.replace('{username}', encodeURIComponent(username));

                openUrlInNewTab(finalUrl);
            });

            container.appendChild(button);
        });

        // Add close button
        const closeBtn = document.createElement('button');
        closeBtn.textContent = '✕';
        closeBtn.style.cssText = `
            position: absolute;
            top: 6px;
            right: 6px;
            width: 20px;
            height: 20px;
            border: none;
            background: rgba(0, 0, 0, 0.1);
            border-radius: 50%;
            cursor: pointer;
            font-size: 12px;
            color: #666;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.2s ease;
        `;

        closeBtn.addEventListener('mouseenter', () => {
            closeBtn.style.background = 'rgba(0, 0, 0, 0.2)';
        });

        closeBtn.addEventListener('mouseleave', () => {
            closeBtn.style.background = 'rgba(0, 0, 0, 0.1)';
        });

        closeBtn.addEventListener('click', () => {
            container.style.display = 'none';
        });

        container.appendChild(closeBtn);
        document.body.appendChild(container);
        return container;
    }

    // Handle text selection
    function handleTextSelection() {
        const selection = window.getSelection();
        const text = selection.toString().trim();

        if (text.length > 0) {
            selectedText = text;
            if (!buttonContainer) {
                buttonContainer = createButtonContainer();
            }
            buttonContainer.style.display = 'flex';
        } else {
            if (buttonContainer) {
                buttonContainer.style.display = 'none';
            }
        }
    }

    // Event listeners
    document.addEventListener('mouseup', handleTextSelection);
    document.addEventListener('keyup', handleTextSelection);
    document.addEventListener('selectionchange', handleTextSelection);

    // Hide buttons when clicking outside
    document.addEventListener('click', (e) => {
        if (buttonContainer && !buttonContainer.contains(e.target)) {
            const selection = window.getSelection();
            if (selection.toString().trim().length === 0) {
                buttonContainer.style.display = 'none';
            }
        }
    });

})();