- // ==UserScript==
- // @name Bing Human Search
- // @namespace http://tampermonkey.net/
- // @version 5.3
- // @description Ricerche umanizzate senza scrolling
- // @author Nayila Yassin
- // @license MIT
- // @match https://www.bing.com/*
- // @grant GM_xmlhttpRequest
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_addStyle
- // @connect api.datamuse.com
- // @connect random-word-api.herokuapp.com
- // ==/UserScript==
- (function() {
- 'use strict';
-
- const STATE_KEY = 'BingHumanSearch_State';
- const WORD_CACHE_KEY = 'BingHumanSearch_Words';
-
- // Configurazione aggiornata (tempo ridotto)
- const config = {
- typing: {
- min: 150, // Minimo tempo per digitare un carattere (ms)
- max: 500, // Massimo tempo per digitare un carattere (ms)
- errorRate: 0.15, // Probabilità di errore di battitura
- correctionProbability: 0.2 // Probabilità di correzione dell'errore
- },
- timing: {
- // 🔁 Tempo tra una ricerca e l'altra (15-30 secondi)
- searchDelay: { min: 15000, max: 30000 }, // Modificato da originale (60s-120s)
-
- // ⏱️ Tempo di caricamento risultati (6-12 secondi)
- resultLoad: { min: 6000, max: 12000 },
-
- // 🕵️ Tempo massimo di attesa per gli elementi (15 secondi)
- elementWait: { max: 15000, interval: 500 },
-
- // 📜 Configurazione dello scroll
- scrollStep: { min: 300, max: 500 }, // Altezza singolo scroll (px)
- scrollPause: { min: 500, max: 1500 }, // Pausa tra scroll consecutivi (ms)
- scrollCount: { min: 2, max: 4 } // Numero di scroll effettuati
- }
- };
-
- let isRunning = GM_getValue(STATE_KEY, false);
- let wordCache = GM_getValue(WORD_CACHE_KEY, []);
- let controlPanel;
-
- // Stili CSS globali
- GM_addStyle(`
- .bhs-control-panel {
- position: fixed;
- bottom: 25px;
- right: 25px;
- z-index: 99999;
- background: rgba(255,255,255,0.95);
- border-radius: 15px;
- padding: 15px;
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
- border: 1px solid #e0e0e0;
- min-width: 180px;
- font-family: 'Segoe UI', system-ui;
- }
- .bhs-button {
- background: ${isRunning ? '#e74c3c' : '#2ecc71'};
- color: white;
- border: none;
- padding: 12px 20px;
- border-radius: 8px;
- cursor: pointer;
- width: 100%;
- transition: all 0.25s ease;
- font-weight: 600;
- text-transform: uppercase;
- letter-spacing: 0.5px;
- }
- .bhs-button:hover {
- opacity: 0.9;
- transform: translateY(-1px);
- }
- .bhs-status {
- margin-top: 12px;
- font-size: 0.9em;
- color: #555;
- text-align: center;
- }
- `);
-
- async function init() {
- createControlPanel();
- refreshWordCache();
- if(isRunning) startAutomation();
- }
-
- function createControlPanel() {
- controlPanel = document.createElement('div');
- controlPanel.className = 'bhs-control-panel';
- const btn = document.createElement('button');
- btn.className = 'bhs-button';
- btn.textContent = isRunning ? '⏹ STOP' : '▶ START';
- btn.onclick = toggleAutomation;
- const status = document.createElement('div');
- status.className = 'bhs-status';
- status.textContent = 'Status: ' + (isRunning ? 'Active 🔄' : 'Paused ⏸');
- controlPanel.append(btn, status);
- document.body.appendChild(controlPanel);
- }
-
- function updateStatus(text) {
- const status = controlPanel.querySelector('.bhs-status');
- if(status) status.textContent = `Status: ${text}`;
- }
-
- function toggleAutomation() {
- isRunning = !isRunning;
- GM_setValue(STATE_KEY, isRunning);
- refreshControlPanel();
- if(isRunning) {
- startAutomation();
- } else {
- updateStatus('Paused ⏸');
- }
- }
-
- function refreshControlPanel() {
- const btn = controlPanel.querySelector('.bhs-button');
- if(btn) {
- btn.textContent = isRunning ? '⏹ STOP' : '▶ START';
- btn.style.backgroundColor = isRunning ? '#e74c3c' : '#2ecc71';
- }
- }
-
- async function refreshWordCache() {
- if(wordCache.length > 20) return;
- try {
- const source = config.wordSources[Math.floor(Math.random() * config.wordSources.length)];
- const words = await fetchJSON(source);
- if(Array.isArray(words)) {
- wordCache = words.slice(0, 50).map(w => w.word || w);
- GM_setValue(WORD_CACHE_KEY, wordCache);
- }
- } catch(e) {
- console.warn('Failed to refresh word cache, using fallback');
- wordCache = ['test', 'search', 'demo', 'example', 'hello'];
- }
- }
-
- function getRandomWord() {
- return wordCache.length > 0
- ? wordCache.splice(Math.floor(Math.random() * wordCache.length), 1)[0]
- : 'search';
- }
-
- async function waitForElement(selector, timeout = config.timing.elementWait.max) {
- return new Promise((resolve, reject) => {
- const start = Date.now();
- const check = setInterval(() => {
- const el = document.querySelector(selector);
- if(el) {
- clearInterval(check);
- resolve(el);
- } else if(Date.now() - start > timeout) {
- clearInterval(check);
- reject(new Error('Element not found'));
- }
- }, config.timing.elementWait.interval);
- });
- }
-
- async function humanType(text, element) {
- let currentText = '';
- for(const char of text) {
- if(!isRunning) break;
- if(Math.random() < config.typing.errorRate) {
- const fakeChar = String.fromCharCode(97 + Math.floor(Math.random() * 26));
- currentText += fakeChar;
- await updateElement(element, currentText);
- if(Math.random() < config.typing.correctionProbability) {
- currentText = currentText.slice(0, -1);
- await updateElement(element, currentText);
- await randomDelay(50, 150);
- }
- }
- currentText += char;
- await updateElement(element, currentText);
- await randomDelay(config.typing.min, config.typing.max);
- }
- }
-
- async function updateElement(element, value) {
- element.value = value;
- element.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
- element.dispatchEvent(new Event('change', { bubbles: true }));
- }
-
- async function smoothScrollDown() {
- const scrollCount = Math.floor(Math.random() *
- (config.timing.scrollCount.max - config.timing.scrollCount.min + 1)) +
- config.timing.scrollCount.min;
-
- for(let i = 0; i < scrollCount && isRunning; i++) {
- const scrollAmount = Math.floor(Math.random() *
- (config.timing.scrollStep.max - config.timing.scrollStep.min + 1)) +
- config.timing.scrollStep.min;
-
- window.scrollBy({
- top: scrollAmount,
- left: 0,
- behavior: 'smooth'
- });
-
- await randomDelay(config.timing.scrollPause.min, config.timing.scrollPause.max);
- }
- }
-
- async function performSearch() {
- try {
- updateStatus('Starting search... ⏳');
- const searchBox = await waitForElement('input[name="q"], textarea[name="q"]');
- searchBox.value = '';
- searchBox.focus();
- await randomDelay(500, 1200);
- const word = getRandomWord();
- updateStatus(`Typing: ${word} ⌨️`);
- await humanType(word, searchBox);
- updateStatus('Submitting form... 📨');
- searchBox.dispatchEvent(new KeyboardEvent('keydown', {
- key: 'Enter',
- code: 'Enter',
- keyCode: 13,
- bubbles: true,
- composed: true
- }));
- updateStatus('Loading results... ⏳');
- await waitForElement('#b_results');
- await randomDelay(
- config.timing.resultLoad.min,
- config.timing.resultLoad.max
- );
-
- // Nuovo scroll aggiunto qui
- updateStatus('Scrolling results... 📜');
- await smoothScrollDown();
-
- updateStatus('Waiting next cycle... ⏳');
- await randomDelay(
- config.timing.searchDelay.min,
- config.timing.searchDelay.max
- );
- if(isRunning) performSearch();
- } catch(error) {
- console.error('Automation error:', error);
- updateStatus(`Error: ${error.message} ⚠️`);
- if(isRunning) setTimeout(performSearch, 5000);
- }
- }
-
- function startAutomation() {
- if(!isRunning) return;
- updateStatus('Initializing... ⚡');
- performSearch().catch(e => console.error('Fatal error:', e));
- }
-
- function randomDelay(min, max) {
- return new Promise(r => setTimeout(r, Math.random() * (max - min) + min));
- }
-
- function fetchJSON(url) {
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- method: 'GET',
- url,
- onload: r => resolve(JSON.parse(r.responseText)),
- onerror: reject
- });
- });
- }
-
- window.addEventListener('load', init, false);
- })();