// ==UserScript==
// @name WordSleuth
// @namespace https://greasyfork.org/en/users/1084087-kueldev
// @version 0.4.1
// @description A script that helps you guess words in skribblio
// @author kueldev
// @match http*://www.skribbl.io/*
// @match http*://skribbl.io/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=skribbl.io
// @grant GM_setValue
// @grant GM_getValue
// @license MIT
// ==/UserScript==
(function() {
'use strict';
let correctAnswers = GM_getValue('correctAnswers', []);
const guessElem = createGuessElement();
let possibleWords = [];
let exportButton = document.createElement('button');
exportButton.innerHTML = 'Export Answers';
exportButton.style = 'position: fixed; bottom: 65px; right: 10px; z-index: 9999; padding: 5px 10px; font-size: 12px; background-color: #333; color: #fff; border: none; border-radius: 5px;';
document.body.appendChild(exportButton);
exportButton.addEventListener('click', function() {
let blob = new Blob([correctAnswers.join('\n')], {
type: 'text/plain;charset=utf-8'
});
let a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'correctAnswers.txt';
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
// Fetch the latest wordlist
fetchWords('https://raw.githubusercontent.com/kuel27/wordlist/main/wordlist.txt').then(words => {
words.forEach(word => {
if (!correctAnswers.includes(word)) {
correctAnswers.push(word);
}
});
observeHints();
observeInput();
});
function fetchWords(url) {
return fetch(url)
.then(response => response.text())
.then(data => data.split('\n')
.map(word => word.trim())
.map(word => word.replace(/[^a-zA-Z\s]/g, ''))
);
}
function observeHints() {
const targetNodes = [
document.querySelector('.hints .container'),
document.querySelector('.words'),
document.querySelector('#game-word'),
];
const config = {
childList: true,
subtree: true
};
const callback = function(mutationsList, observer) {
const inputElem = document.querySelector('#game-chat input[data-translate="placeholder"]');
if (inputElem.value) return;
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
checkIfAllHintsRevealed();
checkWordsElement();
generateGuesses();
}
}
};
const observer = new MutationObserver(callback);
targetNodes.forEach(targetNode => {
if (targetNode) {
observer.observe(targetNode, config);
}
});
}
function checkIfAllHintsRevealed() {
const hintElems = Array.from(document.querySelectorAll('.hints .hint'));
if (hintElems.every(elem => elem.classList.contains('uncover'))) {
const correctAnswer = hintElems.map(elem => elem.textContent).join('').trim().toLowerCase();
if (!correctAnswer) {
return;
}
const filteredAnswer = correctAnswer.replace(/[^a-zA-Z\s]/g, '');
if (filteredAnswer && !correctAnswers.includes(filteredAnswer)) {
correctAnswers.push(filteredAnswer);
GM_setValue('correctAnswers', correctAnswers);
console.log("added " + filteredAnswer + " to the wordlist");
}
}
}
function checkWordsElement() {
const wordElems = Array.from(document.querySelectorAll('.words.show .word'));
wordElems.forEach(elem => {
const word = elem.textContent.trim().toLowerCase();
if (!word) {
return;
}
const filteredWord = word.replace(/[^a-zA-Z\s]/g, '');
if (filteredWord && !correctAnswers.includes(filteredWord)) {
correctAnswers.push(filteredWord);
GM_setValue('correctAnswers', correctAnswers);
console.log("added " + filteredWord + " to the wordlist");
}
});
}
function observeInput() {
const inputElem = document.querySelector('#game-chat input[data-translate="placeholder"]');
inputElem.addEventListener('input', generateGuesses);
inputElem.addEventListener('keydown', handleKeyDown);
const formElem = document.querySelector('#game-chat form');
formElem.addEventListener('submit', generateGuesses);
}
function handleKeyDown(event) {
if (event.key === 'Tab' && possibleWords.length > 0) {
event.preventDefault();
const inputElem = document.querySelector('#game-chat input[data-translate="placeholder"]');
inputElem.value = possibleWords[0];
inputElem.focus();
generateGuesses();
}
}
function generateGuesses() {
const hintElems = Array.from(document.querySelectorAll('.hints .hint'));
const inputElem = document.querySelector('#game-chat input[data-translate="placeholder"]');
const hintParts = hintElems.map(elem => elem.textContent === '_' ? '.' : elem.textContent).join('').split(' ');
const inputText = inputElem.value ? String(inputElem.value) : '';
possibleWords = correctAnswers.filter(word => {
let wordParts = word.split(' ');
if (wordParts.length !== hintParts.length) {
return false;
}
for (let i = 0, len = wordParts.length; i < len; i++) {
if (wordParts[i].length !== hintParts[i].length) {
return false;
}
}
if (hintParts.join(' ').trim().length <= 0 && inputText.trim().length <= 0) {
return true;
}
let hintRegex = new RegExp(`^${hintParts.join(' ')}$`, 'i');
if (!hintRegex.test(word)) {
return false;
}
let inputTextRegex = new RegExp(`^${inputText}`, 'i');
if (!inputTextRegex.test(word)) {
return false;
}
return true;
});
guessElem.innerHTML = '';
renderGuesses(possibleWords, inputElem);
}
function renderGuesses(possibleWords, inputElem) {
possibleWords.slice(0, 100).forEach((word, index) => {
const wordElem = document.createElement('div');
wordElem.textContent = word;
wordElem.style = 'font-weight: bold; display: inline-block; padding: 5px; margin-right: 2px; color: white;';
const maxValue = possibleWords.length > 100 ? 100 : possibleWords.length;
let colorValue = possibleWords.length > 1 ? Math.floor(255 * index / (maxValue - 1)) : 0;
wordElem.style.backgroundColor = `rgb(${colorValue}, ${255 - colorValue}, 0)`;
addHoverEffect(wordElem, colorValue);
addClickFunctionality(wordElem, word, inputElem, colorValue);
guessElem.appendChild(wordElem);
});
}
function addHoverEffect(wordElem, colorValue) {
wordElem.addEventListener('mouseenter', function() {
if (!wordElem.classList.contains('pressed')) {
wordElem.style.backgroundColor = 'lightgray';
}
wordElem.classList.add('hovered');
});
wordElem.addEventListener('mouseleave', function() {
if (!wordElem.classList.contains('pressed')) {
wordElem.style.backgroundColor = `rgb(${colorValue}, ${255 - colorValue}, 0)`;
}
wordElem.classList.remove('hovered');
});
}
function addClickFunctionality(wordElem, word, inputElem, colorValue) {
wordElem.addEventListener('mousedown', function() {
wordElem.classList.add('pressed');
wordElem.style.backgroundColor = 'gray';
});
wordElem.addEventListener('mouseup', function() {
wordElem.classList.remove('pressed');
if (!wordElem.classList.contains('hovered')) {
wordElem.style.backgroundColor = `rgb(${colorValue}, ${255 - colorValue}, 0)`;
} else {
wordElem.style.backgroundColor = 'lightgray';
}
});
wordElem.addEventListener('click', function() {
const formElem = document.querySelector('#game-chat form');
inputElem.value = word;
formElem.dispatchEvent(new Event('submit', {
bubbles: true,
cancelable: true
}));
});
}
function createGuessElement() {
let guessElem = document.createElement('div');
guessElem.style = 'position: fixed; bottom: 0; left: 0; right: 0; padding: 10px; background-color: white; max-height: 200px; overflow-x: auto; white-space: nowrap; max-width: 100vw;';
document.body.appendChild(guessElem);
return guessElem;
}
})();