您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Sanuli huijaus Käyttöliittymä
// ==UserScript== // @name SanuliHacksGUI // @namespace http://tampermonkey.net/ // @version 2025-05-24 // @description Sanuli huijaus Käyttöliittymä // @author @theyhoppingonme on discord // @match https://sanuli.fi/ // @icon https://www.google.com/s2/favicons?sz=64&domain=sanuli.fi // @grant none // ==/UserScript== function isMobile() { const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0; const smallScreen = window.innerWidth <= 820; const isPortrait = window.matchMedia('(orientation: portrait)').matches; const userAgentMobile = /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); return (hasTouch && smallScreen && isPortrait) || userAgentMobile; } function encode(input, key) { let encoded = ''; for (let i = 0; i < input.length; i++) { let charCode = input.charCodeAt(i); let keyCharCode = key.charCodeAt(i % key.length); let shifted = (charCode + keyCharCode) % 256; encoded += shifted.toString(16).padStart(2, '0'); } return encoded; } function decode(encoded, key) { let decoded = ''; for (let i = 0; i < encoded.length; i += 2) { let byte = parseInt(encoded.substr(i, 2), 16); let keyCharCode = key.charCodeAt((i/2) % key.length); let originalCharCode = (byte - keyCharCode + 256) % 256; decoded += String.fromCharCode(originalCharCode); } return decoded; } function main() { setTimeout(function() { (() => { if (document.location.href == 'https://sanuli.fi/') { let opacity = 0.95 if (localStorage.getItem('gui')) { const guid = JSON.parse(localStorage.getItem('gui')); if (guid.o != undefined) { opacity = guid.o; } else { localStorage.removeItem('gui'); } } const version = 1.4; const guiId = 'an-gui'; if (document.getElementById(guiId)) { console.log('GUI already exists.'); return; } let elz; let data; let settings = localStorage.getItem('settings'); let sjson = JSON.parse(settings); let game = `game|"${sjson.current_game_mode}"|"${sjson.current_word_list}"|${sjson.current_word_length}`; let json; const tabs = [ { id: 'set', label: 'Aseta', active: true }, { id: 'toggle', label: 'Kytkimet', active: false }, { id: 'button', label: 'Napit', active: false }, { id: 'settings', label: 'Asetukset', active: false } ]; const inputs = [{ tab: 'set', info: 'Aseta putki', placeholder: 'Putki', buttonText: 'Aseta', type: 'number', callback: (value) => { try { data = localStorage.getItem(game); if (!data) throw new Error('No data found'); json = JSON.parse(data); json.streak = Number(value); localStorage.setItem(game, JSON.stringify(json)); setTimeout(function() { location.reload(); }, 100); } catch (e) { console.error('Failed to set streak:', e); } } }, { tab: 'set', info: 'Aseta sana', placeholder: 'Sana', buttonText: 'Aseta', type: 'text', callback: (value) => { try { data = localStorage.getItem(game); if (!data) throw new Error('No data found'); json = JSON.parse(data); value = value.toUpperCase(); value = value.split(''); json.word = value; json.word_length = value.length; localStorage.setItem(game, JSON.stringify(json)); setTimeout(function() { location.reload(); }, 100); } catch (e) { console.error('Failed to set word:', e); } } }, { tab: 'set', info: 'Aseta viesti', placeholder: 'Viesti', buttonText: 'Aseta', type: 'text', callback: (value) => { try { data = localStorage.getItem(game); if (!data) throw new Error('No data found'); json = JSON.parse(data); json.message = value; localStorage.setItem(game, JSON.stringify(json)); setTimeout(function() { location.reload(); }, 100); } catch (e) { console.error('Failed to set message:', e); } } }, { tab: 'settings', info: 'Aseta sanulin taustaväri (Heksadesimaali)', placeholder: 'Esim: #000000', buttonText: 'Aseta', type: 'text', callback: (value) => { try { document.body.style.background = value; } catch (e) { console.error('Failed to set color:', e); } } }, ]; let interval; let recent; let word; const toggles = [{ tab: 'toggle', info: 'Automaattinen arvaus', name: 'autoguess', onFunc: () => { guess(); }, offFunc: () => { clearInterval(interval); } }, ]; function guess() { interval = setInterval(() => { data = localStorage.getItem(game); json = JSON.parse(data); const word = json.word.join(''); if (recent != word) { typeWord(word); recent = word; } document.dispatchEvent(enterEvent); document.dispatchEvent(enterEvent); }, 100); } const buttons = [{ tab: 'button', info: 'Selvitä sana', buttonText: 'Selvitä', callback: () => { data = localStorage.getItem(game); json = JSON.parse(data); json.message = 'Sana on: ' + json.word.join(''); localStorage.setItem(game, JSON.stringify(json)); alert(json.message); } }, { tab: 'button', info: 'Aseta Maksimiputki', buttonText: 'Aseta', callback: () => { data = localStorage.getItem(game); if (!data) throw new Error('No data found'); json = JSON.parse(data); json.streak = 0xFFFFFFFF; localStorage.setItem(game, JSON.stringify(json)); setTimeout(function() { location.reload(); }, 100); } }, { tab: 'button', info: 'Voita peli', buttonText: 'Voita', callback: () => { data = localStorage.getItem(game); if (!data) throw new Error('No data found'); json = JSON.parse(data); json.is_winner = true; json.is_guessing = false; json.is_unknown = false; json.streak += 1; localStorage.setItem(game, JSON.stringify(json)); setTimeout(function() { location.reload(); }, 100); } }, { tab: 'settings', info: 'Tallenna Sanulitiedot', buttonText: 'Tallenna', callback: () => { navigator.clipboard.writeText(encode(localStorage.getItem(game), 'SanuliHacksGUI')) .then(() => { alert('Tallennuskoodi on tallennettu leikepöytään.'); }); } }, { tab: 'settings', info: 'Lataa Sanulitiedot', buttonText: 'Lataa', callback: () => { const save = prompt('Anna tallennettu koodi.'); if (save) { const str = decode(save, 'SanuliHacksGUI'); try { JSON.parse(str); localStorage.setItem(game, str); alert('Ladattu!'); location.reload(); } catch (e) { alert('Virheellistä koodia!'); } } else { alert('Et vastannut mitään'); } } }, ]; const sliders = [{ tab: 'settings', info: 'Käyttöjärjestelmän läpinäkyvyys', value: opacity, step: 100, min: 0, max: 1, callback: (value) => { const element = document.getElementById(guiId); if (element) { element.style.opacity = value; data = JSON.parse(localStorage.getItem('gui')); data.o = value; localStorage.setItem('gui', JSON.stringify(data)); } } } ]; function simulateKeyPress(key) { const keyUpper = key.toUpperCase(); const keyCode = keyUpper.charCodeAt(0); const code = key === 'Enter' ? 'Enter' : 'Key' + keyUpper; ['keydown', 'keypress', 'keyup'].forEach(type => { const event = new KeyboardEvent(type, { key: key, code: code, keyCode: keyCode, which: keyCode, bubbles: true, cancelable: true, }); document.dispatchEvent(event); }); } function typeWord(word, delay = 10) { let i = 0; const interval = setInterval(() => { if (i >= word.length) return clearInterval(interval); simulateKeyPress(word[i++]); }, delay); } const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, which: 13, bubbles: true, }); const style = document.createElement('style'); style.textContent = ` #${guiId} { position: fixed; top: 20px; right: 20px; width: 320px; background: #2b2b2b; color: #e0e0e0; border-radius: 8px; font-family: Arial, sans-serif; box-shadow: 0 4px 12px rgba(0,0,0,0.4); z-index: 9999; overflow: hidden; transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); opacity: ${opacity}; } #${guiId} .gui-header { padding: 12px; background: #1e1e1e; cursor: move; display: flex; justify-content: space-between; align-items: center; border-radius: 8px 8px 0 0; user-select: none; } #${guiId} .gui-title { font-weight: bold; font-size: 14px; transition: color 0.2s ease; } #${guiId} .gui-tabs { display: flex; background: #262626; border-bottom: 1px solid #3a3a3a; } #${guiId} .gui-tab { padding: 10px 15px; font-size: 12px; cursor: pointer; transition: all 0.3s ease; user-select: none; border-bottom: 2px solid transparent; position: relative; overflow: hidden; } #${guiId} .gui-tab:hover { background: #303030; } #${guiId} .gui-tab.active { background: #2b2b2b; border-bottom: 2px solid #4CAF50; font-weight: bold; } #${guiId} .gui-tab::after { content: ''; position: absolute; top: 50%; left: 50%; width: 5px; height: 5px; background: rgba(255, 255, 255, 0.5); opacity: 0; border-radius: 100%; transform: scale(1, 1) translate(-50%); transform-origin: 50% 50%; } #${guiId} .gui-tab:focus:not(:active)::after { animation: ripple 0.5s ease-out; } @keyframes ripple { 0% { transform: scale(0, 0); opacity: 0.5; } 100% { transform: scale(20, 20); opacity: 0; } } #${guiId} .gui-content { padding: 16px; max-height: 70vh; overflow-y: auto; transition: max-height 0.4s ease-in-out; } #${guiId} .tab-content { display: none; animation-duration: 0.45s; animation-fill-mode: both; animation-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1); } #${guiId} .tab-content.active { display: block; animation-name: fadeIn; } #${guiId} .tab-content.fade-out { animation-name: fadeOut; } @keyframes fadeIn { 0% { opacity: 0; transform: translateY(10px); } 100% { opacity: 1; transform: translateY(0); } } @keyframes fadeOut { 0% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-10px); } } #${guiId} .gui-item { margin-bottom: 16px; display: flex; flex-direction: column; transition: transform 0.2s ease-out; } #${guiId} .gui-item:hover { transform: translateX(2px); } #${guiId} .gui-item-info { margin-bottom: 6px; font-size: 12px; color: #b0b0b0; transition: color 0.2s ease; } #${guiId} .gui-input-container { display: flex; gap: 8px; } #${guiId} input { flex: 1; padding: 8px; background: #3a3a3a; border: 1px solid #4a4a4a; color: #e0e0e0; border-radius: 4px; outline: none; transition: border-color 0.25s ease, box-shadow 0.25s ease; } #${guiId} input:focus { border-color: #6a6a6a; box-shadow: 0 0 0 2px rgba(106, 106, 106, 0.3); } #${guiId} button { padding: 8px 12px; background: #4a4a4a; border: none; color: #e0e0e0; border-radius: 4px; cursor: pointer; transition: background 0.25s ease, transform 0.15s ease; outline: none; } #${guiId} button:hover { background: #5a5a5a; transform: translateY(-1px); } #${guiId} button:active { background: #6a6a6a; transform: translateY(1px); } #${guiId} .toggle-container { display: flex; align-items: center; gap: 8px; } #${guiId} .toggle-switch { position: relative; width: 40px; height: 20px; } #${guiId} .toggle-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #3a3a3a; transition: background-color 0.3s cubic-bezier(0.4, 0.0, 0.2, 1); border-radius: 20px; } #${guiId} .toggle-slider:before { position: absolute; content: ''; height: 16px; width: 16px; left: 2px; bottom: 2px; background-color: #e0e0e0; transition: transform 0.3s cubic-bezier(0.4, 0.0, 0.2, 1), background-color 0.3s ease; border-radius: 50%; } #${guiId} input:checked + .toggle-slider { background-color: #4CAF50; } #${guiId} input:checked + .toggle-slider:before { transform: translateX(20px); } #${guiId} .gui-slider-container { display: flex; flex-direction: column; margin-bottom: 12px; width: 85%; } #${guiId} .gui-slider-header { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 12px; color: #b0b0b0; } #${guiId} .gui-slider-value { font-weight: bold; color: #e0e0e0; transition: color 0.2s ease; } #${guiId} .gui-slider { -webkit-appearance: none; appearance: none; width: 100%; height: 6px; background: #3a3a3a; border-radius: 3px; outline: none; transition: background 0.2s ease, box-shadow 0.2s ease; } #${guiId} .gui-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 16px; height: 16px; border-radius: 50%; background: #4CAF50; cursor: pointer; transition: background 0.2s ease, transform 0.15s ease, box-shadow 0.2s ease; } #${guiId} .gui-slider::-moz-range-thumb { width: 16px; height: 16px; border: none; border-radius: 50%; background: #4CAF50; cursor: pointer; transition: background 0.2s ease, transform 0.15s ease, box-shadow 0.2s ease; } #${guiId} .gui-slider:hover { background: #444444; } #${guiId} .gui-slider:hover::-webkit-slider-thumb { transform: scale(1.1); box-shadow: 0 0 8px rgba(76, 175, 80, 0.4); } #${guiId} .gui-slider:hover::-moz-range-thumb { transform: scale(1.1); box-shadow: 0 0 8px rgba(76, 175, 80, 0.4); } #${guiId} .gui-slider:focus { box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2); } #${guiId} .gui-slider:focus::-webkit-slider-thumb { background: #5dbb61; box-shadow: 0 0 0 4px rgba(76, 175, 80, 0.3); } #${guiId} .gui-slider:focus::-moz-range-thumb { background: #5dbb61; box-shadow: 0 0 0 4px rgba(76, 175, 80, 0.3); } #${guiId} .gui-slider:active::-webkit-slider-thumb { transform: scale(1.2); background: #3d9140; } #${guiId} .gui-slider:active::-moz-range-thumb { transform: scale(1.2); background: #3d9140; } `; document.head.appendChild(style); const gui = document.createElement('div'); gui.id = guiId; let jss; const guiHeader = document.createElement('div'); guiHeader.className = 'gui-header'; const guiTitle = document.createElement('div'); guiTitle.className = 'gui-title'; guiTitle.textContent = `AnGUI - Sanuli V${version}`; const guiTabs = document.createElement('div'); guiTabs.className = 'gui-tabs'; const guiContent = document.createElement('div'); guiContent.className = 'gui-content'; guiHeader.appendChild(guiTitle); gui.appendChild(guiHeader); gui.appendChild(guiTabs); gui.appendChild(guiContent); document.body.appendChild(gui); tabs.forEach(tab => { const tabButton = document.createElement('div'); tabButton.className = `gui-tab ${tab.active ? 'active' : ''}`; tabButton.textContent = tab.label; tabButton.dataset.tabId = tab.id; guiTabs.appendChild(tabButton); const tabContent = document.createElement('div'); tabContent.className = `tab-content ${tab.active ? 'active' : ''}`; tabContent.id = `tab-${tab.id}`; guiContent.appendChild(tabContent); tabButton.addEventListener('click', () => { document.querySelectorAll(`#${guiId} .gui-tab`).forEach(t => { t.classList.remove('active'); }); document.querySelectorAll(`#${guiId} .tab-content`).forEach(c => { c.classList.remove('active'); }); tabButton.classList.add('active'); tabContent.classList.add('active'); }); }); let isVisible = true; let dragActive = false; let dragStartX, dragStartY, initialX, initialY; document.addEventListener('keydown', (e) => { if (e.key === 'Insert') { isVisible = !isVisible; gui.style.display = isVisible ? 'block' : 'none'; } }); guiHeader.addEventListener('mousedown', (e) => { startD(e.clientX, e.clientY); e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (dragActive) { moveD(e.clientX, e.clientY); } }); document.addEventListener('mouseup', () => { endD(); }); guiHeader.addEventListener('touchstart', (e) => { if (e.touches.length === 1) { const touch = e.touches[0]; startD(touch.clientX, touch.clientY); e.preventDefault(); } }); document.addEventListener('touchmove', (e) => { if (dragActive && e.touches.length === 1) { const touch = e.touches[0]; moveD(touch.clientX, touch.clientY); e.preventDefault(); } }); document.addEventListener('touchend', () => { endD(); }); document.addEventListener('touchcancel', () => { endD(); }); function startD(x, y) { dragActive = true; dragStartX = x; dragStartY = y; initialX = gui.offsetLeft; initialY = gui.offsetTop; gui.style.cursor = 'grabbing'; } function moveD(x, y) { const dx = x - dragStartX; const dy = y - dragStartY; gui.style.left = initialX + dx + 'px'; gui.style.top = initialY + dy + 'px'; gui.style.right = 'auto'; if (!localStorage.getItem('gui')) { const jss = { 'l': gui.style.left, 't': gui.style.top, 'r': gui.style.right, 'o': 0.95, }; localStorage.setItem('gui', JSON.stringify(jss)); } else { const read = JSON.parse(localStorage.getItem('gui')); const jss = { 'l': gui.style.left, 't': gui.style.top, 'r': gui.style.right, 'o': read.o, }; localStorage.setItem('gui', JSON.stringify(jss)); } } function endD() { if (dragActive) { dragActive = false; gui.style.cursor = 'default'; } } let inputFocused = false; document.addEventListener('keydown', function(event) { if (event.key === '=') { if (confirm('Oletko varma, että haluat nollaa käyttöjärjestelmän?')) { localStorage.removeItem('gui'); alert('käyttöjärjestelmä on nollattu.'); location.reload(); } } }); document.addEventListener('keydown', function(event) { if (event.key === '!') { if (confirm('Oletko varma, että haluat nollaa sanulin tiedot?')) { const keep = localStorage.getItem('gui'); for (let i = localStorage.length - 1; i >= 0; i--) { const key = localStorage.key(i); if (key !== 'gui') { localStorage.removeItem(key); } } if (keep !== null) { localStorage.setItem('gui', keep); } alert('sanulin tiedot on nollattu.'); location.reload(); } } }); const createInput = (tabId, info, placeholder, buttonText, type, callback) => { const tabContent = document.getElementById(`tab-${tabId}`); if (!tabContent) return; const item = document.createElement('div'); item.className = 'gui-item'; const itemInfo = document.createElement('div'); itemInfo.className = 'gui-item-info'; itemInfo.textContent = info; const inputContainer = document.createElement('div'); inputContainer.className = 'gui-input-container'; const input = document.createElement('input'); input.type = type; input.placeholder = placeholder; input.addEventListener('focus', () => { inputFocused = true; }); input.addEventListener('blur', () => { inputFocused = false; }); input.addEventListener('keydown', (event) => { event.stopPropagation(); }); const button = document.createElement('button'); button.textContent = buttonText; button.addEventListener('click', () => { callback(input.value); }); inputContainer.appendChild(input); inputContainer.appendChild(button); item.appendChild(itemInfo); item.appendChild(inputContainer); tabContent.appendChild(item); }; const createSlider = (tabId, info, value, step, min, max, callback) => { const tabContent = document.getElementById(`tab-${tabId}`); if (!tabContent) return; const item = document.createElement('div'); item.className = 'gui-item'; const itemInfo = document.createElement('div'); itemInfo.className = 'gui-item-info'; itemInfo.textContent = info; const sliderContainer = document.createElement('div'); sliderContainer.className = 'gui-slider-container'; const sliderHeader = document.createElement('div'); sliderHeader.className = 'gui-slider-header'; const sliderLabel = document.createElement('span'); sliderLabel.textContent = info; const valueLabel = document.createElement('span'); valueLabel.className = 'gui-slider-value'; valueLabel.textContent = value; sliderHeader.appendChild(sliderLabel); sliderHeader.appendChild(valueLabel); const slider = document.createElement('input'); slider.className = 'gui-slider'; slider.type = 'range'; slider.min = min; slider.max = max; slider.step = (max - min) / step; slider.value = value; slider.addEventListener('input', () => { valueLabel.textContent = slider.value; callback(slider.value); }); sliderContainer.appendChild(sliderHeader); sliderContainer.appendChild(slider); item.appendChild(sliderContainer); tabContent.appendChild(item); return slider; }; const createToggle = (tabId, info, name, onFunc, offFunc) => { const tabContent = document.getElementById(`tab-${tabId}`); if (!tabContent) return; const item = document.createElement('div'); item.className = 'gui-item'; const itemInfo = document.createElement('div'); itemInfo.className = 'gui-item-info'; itemInfo.textContent = info; const toggleContainer = document.createElement('div'); toggleContainer.className = 'toggle-container'; const toggleLabel = document.createElement('label'); toggleLabel.className = 'toggle-switch'; const toggleInput = document.createElement('input'); toggleInput.type = 'checkbox'; toggleInput.name = name; const toggleSlider = document.createElement('span'); toggleSlider.className = 'toggle-slider'; toggleInput.addEventListener('change', () => { if (toggleInput.checked) { onFunc(); } else { offFunc(); } }); toggleLabel.appendChild(toggleInput); toggleLabel.appendChild(toggleSlider); toggleContainer.appendChild(toggleLabel); item.appendChild(itemInfo); item.appendChild(toggleContainer); tabContent.appendChild(item); return toggleInput; }; const createButton = (tabId, info, buttonText, callback) => { const tabContent = document.getElementById(`tab-${tabId}`); if (!tabContent) return; const item = document.createElement('div'); item.className = 'gui-item'; const itemInfo = document.createElement('div'); itemInfo.className = 'gui-item-info'; itemInfo.textContent = info; const button = document.createElement('button'); button.textContent = buttonText; button.addEventListener('click', callback); item.appendChild(itemInfo); item.appendChild(button); tabContent.appendChild(item); return button; }; inputs.forEach(input => { createInput(input.tab, input.info, input.placeholder, input.buttonText, input.type, input.callback); }); toggles.forEach(toggle => { createToggle(toggle.tab, toggle.info, toggle.name, toggle.onFunc, toggle.offFunc); }); buttons.forEach(button => { createButton(button.tab, button.info, button.buttonText, button.callback); }); sliders.forEach(slider => { createSlider(slider.tab, slider.info, slider.value, slider.step, slider.min, slider.max, slider.callback); }); if (localStorage.getItem('gui')) { const vals = JSON.parse(localStorage.getItem('gui')); gui.style.left = vals.l; gui.style.right = vals.r; gui.style.top = vals.t; } let item = null; if (isMobile()) { const elems = document.querySelectorAll('div.keyboard-row'); const target = Array.from(elems).find(el => el.childElementCount === 13); item = document.createElement('button'); item.className = 'keyboard-button keyboard-button-submit'; item.style.backgroundColor = 'purple'; item.textContent = 'angui'; target.appendChild(item); } if (item) { item.addEventListener('touchstart', (e) => { if (e.touches.length === 1) { isVisible = !isVisible; gui.style.display = isVisible ? 'block' : 'none'; } }); } } else { alert('Tämä koodi toimii vain sivustolla sanuli.fi, avataan sivu.'); document.location.href = 'https://sanuli.fi/'; } })(); // tekijä: theyhoppingonme }, 200); } const waitForDiv = () => { const div = document.querySelector('.keyboard'); if (div) { main(); } else { requestAnimationFrame(waitForDiv); } }; waitForDiv();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址