您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自动在 Skribbl.io 中猜词,快速、简单、有效。
当前为
// ==UserScript== // @name Skribbl AutoGuesser // @name:zh-CN Skribbl 自动猜词器 // @name:zh-TW Skribbl 自動猜詞器 // @name:hi Skribbl स्वतः अनुमान स्क्रिप्ट // @name:es Skribbl Adivinador Automático // @namespace http://tampermonkey.net/ // @version 1.03 // @description Automatically suggests guesses in Skribbl.io. Fast, easy, and effective. // @description:zh-CN 自动在 Skribbl.io 中猜词,快速、简单、有效。 // @description:zh-TW 自動在 Skribbl.io 中猜詞,快速、簡單、有效。 // @description:hi Skribbl.io में शब्दों का अनुमान लगाने वाली तेज़ और आसान स्क्रिप्ट। // @description:es Adivina palabras automáticamente en Skribbl.io de forma rápida y sencilla. // @author Zach Kosove // @supportURL https://github.com/zkisaboss/reorderedwordlist // @match https://skribbl.io/* // @icon https://skribbl.io/favicon.png // @grant GM_setValue // @grant GM_getValue // @license MIT // @compatible chrome // @compatible firefox // @compatible opera // @compatible safari // @compatible edge // ==/UserScript== (function() { 'use strict'; const correctAnswers = GM_getValue('correctAnswers', []); async function fetchWords(url) { const response = await fetch(url); if (!response.ok) return []; const data = await response.text(); return data.split('\n').filter(elem => elem !== ''); } async function fetchAndStoreLatestWordlist() { const words = await fetchWords('https://raw.githubusercontent.com/zkisaboss/reorderedwordlist/main/wordlist.txt'); words.forEach(word => { if (!correctAnswers.includes(word)) correctAnswers.push(word); }); } fetchAndStoreLatestWordlist(); let myUsername = ''; function findUsername() { const target = document.querySelector(".players-list"); if (!target) return; const observer = new MutationObserver(() => { myUsername = document.querySelector(".me").textContent.replace(" (You)", "") observer.disconnect(); }); observer.observe(target, { childList: true }); } findUsername(); function observeDrawingTurn() { const target = document.querySelector('.words'); if (!target) return; const observer = new MutationObserver(() => { target.childNodes.forEach(word => { const text = word.textContent.toLowerCase(); if (!correctAnswers.includes(text)) { correctAnswers.push(text); console.log(`New Word: ${text}`) GM_setValue('correctAnswers', correctAnswers); } }); }); observer.observe(target, { childList: true }); } observeDrawingTurn(); function createUI() { const container = document.createElement('div'); container.innerHTML = ` <div id="bottom-ui"> <div id="settings-shelf" class="section"> <button class="ui-btn" id="remaining-guesses">Remaining Guesses: 0</button> <button class="ui-btn" id="auto-guess">Auto Guess: OFF</button> <button class="ui-btn" id="export-answers">Export Answers</button> </div> <div id="other-shelf" class="section"></div> </div> <style> #bottom-ui { position: fixed; bottom: 0; left: 0; width: 100%; background: #f9f9fb; box-shadow: 0 -2px 8px rgba(0,0,0,0.1); border-top-left-radius: 16px; border-top-right-radius: 16px; display: flex; flex-direction: column; z-index: 1000; } .section { display: flex; gap: 8px; padding: 8px 16px; overflow-x: auto; white-space: nowrap; -webkit-overflow-scrolling: touch; } .section::-webkit-scrollbar { height: 6px; } .section::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.2); border-radius: 3px; } .ui-btn { flex: 0 0 auto; font-family: 'Segoe UI','Helvetica Neue',sans-serif; font-size: 14px; padding: 8px 12px; border: none; border-radius: 8px; background: #6366f1; color: #fff; cursor: pointer; box-shadow: 0 2px 6px rgba(0,0,0,0.15); transition: background 0.3s ease; } .ui-btn:hover { background: #4f46e5; } </style> `; document.body.appendChild(container); } createUI(); // Core functionality const remainingButton = document.getElementById('remaining-guesses'); const otherShelf = document.getElementById('other-shelf'); let possibleWords = []; function renderGuesses(possibleWords) { otherShelf.innerHTML = ''; remainingButton.textContent = `Remaining Guesses: ${possibleWords.length}`; possibleWords.forEach(word => { const btn = document.createElement('button'); btn.className = 'ui-btn'; btn.textContent = word; btn.addEventListener('click', () => { document.querySelector('#game-chat input[data-translate="placeholder"]').value = word; document.querySelector('#game-chat form').dispatchEvent(new Event('submit', { bubbles: true, cancelable: true })); }); otherShelf.appendChild(btn); }); }; function generateGuesses() { const inputElem = document.querySelector('#game-chat input[data-translate="placeholder"]'); const pattern = inputElem.value.toLowerCase().trim(); const filteredWords = possibleWords.filter(word => word.startsWith(pattern)); if (possibleWords.length === 1) { inputElem.value = possibleWords.shift(); inputElem.closest('form').dispatchEvent(new Event('submit', { bubbles: true, cancelable: true })); } renderGuesses(filteredWords); } function filterHints(inputWords) { const hints = Array.from(document.querySelectorAll('.hints .hint')); // turn into helper function or use a cleaner method to find allUncovered const allUncovered = hints.every(elem => elem.classList.contains('uncover')); if (allUncovered) { const correctAnswer = hints.map(elem => elem.textContent).join('').toLowerCase(); if (correctAnswers.includes(correctAnswer)) { const currentIndex = correctAnswers.indexOf(correctAnswer); const newIndex = Math.max(0, currentIndex - 1); correctAnswers.splice(currentIndex, 1); correctAnswers.splice(newIndex, 0, correctAnswer); } else { correctAnswers.push(correctAnswer); console.log(`New Word: ${correctAnswer}`); } GM_setValue('correctAnswers', correctAnswers); return []; } const hintPattern = hints.map(hint => hint.textContent === '_' ? '[a-z]' : hint.textContent).join(''); const hintRegex = new RegExp(`^${hintPattern}$`, 'i'); return inputWords.filter(word => hintRegex.test(word)); } function observeHints() { const target = document.querySelector('.hints .container'); if (!target) return; const observer = new MutationObserver(() => { possibleWords = filterHints(possibleWords); generateGuesses(); }); observer.observe(target, { childList: true, subtree: true }); } observeHints(); // https://youtu.be/Dd_NgYVOdLk function levenshteinDistance(a, b) { const matrix = []; for (let i = 0; i <= b.length; i++) matrix[i] = [i]; for (let j = 0; j <= a.length; j++) matrix[0][j] = j; for (let i = 1; i <= b.length; i++) { for (let j = 1; j <= a.length; j++) { if (b.charAt(i - 1) === a.charAt(j - 1)) { matrix[i][j] = matrix[i - 1][j - 1]; } else { matrix[i][j] = Math.min( matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1 ); } } } return matrix[b.length][a.length]; } let previousWords = []; function handleChatMessage(messageNode) { const messageColor = window.getComputedStyle(messageNode).color; const message = messageNode.textContent; if (messageColor === 'rgb(57, 117, 206)' && message.endsWith('is drawing now!')) { possibleWords = filterHints(correctAnswers); generateGuesses(); } if (message.includes(': ')) { const [username, guess] = message.split(': '); possibleWords = possibleWords.filter(word => word !== guess); previousWords = possibleWords; if (username === myUsername) { possibleWords = possibleWords.filter(word => levenshteinDistance(word, guess) > 1); } generateGuesses(); } if (messageColor === 'rgb(226, 203, 0)' && message.endsWith('is close!')) { const closeWord = message.replace(' is close!', ''); possibleWords = previousWords.filter(word => levenshteinDistance(word, closeWord) === 1); generateGuesses(); } } function observeChat() { const target = document.querySelector('.chat-content'); if (!target) return; const observer = new MutationObserver(() => { const lastMessage = target.lastElementChild; if (lastMessage) handleChatMessage(lastMessage); }); observer.observe(target, { childList: true }); } observeChat(); function observeInput() { const inputElem = document.querySelector('#game-chat input[data-translate="placeholder"]'); inputElem.addEventListener('input', generateGuesses); inputElem.addEventListener('keydown', ({ key }) => { if (key === 'Enter') { const guessDiv = guessElem.querySelector('div'); if (guessDiv) { inputElem.value = guessDiv.innerText; inputElem.closest('form').dispatchEvent(new Event('submit', { bubbles: true, cancelable: true })); } } }); } observeInput(); let autoGuessInterval; let autoGuessing = false; function startAutoGuessing() { if (autoGuessing) { autoGuessInterval = setInterval(() => { if (possibleWords.length > 0) { document.querySelector('#game-chat input[data-translate="placeholder"]').value = possibleWords.shift(); document.querySelector('#game-chat form').dispatchEvent(new Event('submit', { bubbles: true, cancelable: true })); } }, 8000); } } startAutoGuessing(); const autoGuessButton = document.getElementById('auto-guess'); function toggleAutoGuessing() { autoGuessing = !autoGuessing; autoGuessButton.innerHTML = `Auto Guess: ${autoGuessing ? 'ON' : 'OFF'}`; if (autoGuessing) { startAutoGuessing(); } else { clearInterval(autoGuessInterval); autoGuessInterval = null; } } autoGuessButton.addEventListener('click', toggleAutoGuessing); async function exportNewWords() { const old = await fetchWords('https://raw.githubusercontent.com/zkisaboss/reorderedwordlist/main/wordlist.txt'); const newWords = correctAnswers.filter(word => !old.includes(word)); const blob = new Blob([newWords.join('\n')], { type: 'text/plain;charset=utf-8' }); const anchor = document.createElement('a'); anchor.href = URL.createObjectURL(blob); anchor.download = 'newWords.txt'; document.body.appendChild(anchor); anchor.click(); document.body.removeChild(anchor); } const exportButton = document.getElementById('export-answers'); exportButton.addEventListener('click', exportNewWords); })();