// ==UserScript==
// @name Green Tools - Script Manager
// @namespace http://tampermonkey.net/
// @version 3.3
// @description Green Tools: Script Manager with Speed & Jump Boost for Narrow One
// @author Green Tools
// @match https://narrow.one/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @run-at document-start
// @license MIT
// ==/UserScript==
(function() {
'use strict';
function getPassword() {
const part1 = [71, 114, 101, 101, 110];
const part2 = [80, 64];
const part3 = [115, 115, 119, 111, 114, 100];
return part1.map(c => String.fromCharCode(c)).join('') +
part2.map(c => String.fromCharCode(c)).join('') +
part3.map(c => String.fromCharCode(c)).join('');
}
const validPassword = getPassword();
let isSpeedBoostActive = false;
let isJumpBoostActive = false;
let savedScripts = GM_getValue('savedScripts', {});
function getRandomColor() {
const colors = [
'rgba(255, 99, 132, 0.9)', 'rgba(54, 162, 235, 0.9)', 'rgba(255, 206, 86, 0.9)',
'rgba(75, 192, 192, 0.9)', 'rgba(153, 102, 255, 0.9)', 'rgba(255, 159, 64, 0.9)',
'rgba(199, 199, 199, 0.9)', 'rgba(83, 102, 255, 0.9)', 'rgba(40, 159, 64, 0.9)',
'rgba(210, 105, 30, 0.9)', 'rgba(139, 69, 19, 0.9)', 'rgba(0, 128, 128, 0.9)'
];
return colors[Math.floor(Math.random() * colors.length)];
}
function createKeyOverlay() {
const overlay = document.createElement('div');
overlay.id = 'keyOverlay';
overlay.style.position = 'fixed';
overlay.style.top = '0';
overlay.style.left = '0';
overlay.style.width = '100%';
overlay.style.height = '100%';
overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
overlay.style.zIndex = '99999';
overlay.style.display = 'flex';
overlay.style.alignItems = 'center';
overlay.style.justifyContent = 'center';
overlay.style.color = 'white';
overlay.style.fontSize = 'clamp(20px, 6vw, 30px)'; // 响应式字体
overlay.style.fontWeight = 'bold';
overlay.style.touchAction = 'manipulation'; // 改善触摸响应
const randomColor = getRandomColor();
overlay.innerHTML = `
<div style="text-align: center; background: ${randomColor}; padding: 20px; border-radius: 10px; box-shadow: 0 0 20px rgba(255,255,255,0.3); max-width: 90vw; width: 400px;">
<h1 style="margin-bottom: 20px; font-size: clamp(18px, 5vw, 24px);">Enter the Password:</h1>
<input id="keyInput" type="password" placeholder="Enter Password" style="font-size: clamp(16px, 4vw, 20px); padding: 12px; margin: 10px; border: 2px solid white; border-radius: 5px; background: rgba(255,255,255,0.1); color: white; width: 100%; box-sizing: border-box;"/>
<br>
<button id="submitKey" style="font-size: clamp(16px, 4vw, 20px); padding: 12px 24px; margin: 10px; border: none; border-radius: 5px; background: white; color: black; cursor: pointer; min-height: 44px;">Submit</button>
<div id="errorMessage" style="color: yellow; font-size: clamp(16px, 4vw, 20px); margin-top: 10px;"></div>
</div>
`;
document.body.appendChild(overlay);
// 添加触摸事件支持
const keyInput = document.getElementById('keyInput');
keyInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
verifyPassword();
}
});
// 确保输入框在iPad上能正常获得焦点
setTimeout(() => {
keyInput.focus();
}, 500);
}
function verifyPassword() {
const userInput = document.getElementById('keyInput').value;
if (userInput === validPassword) {
document.getElementById('keyOverlay').style.display = 'none';
console.log('Password valid. Green Tools activated.');
createFloatingWindow();
} else {
document.getElementById('errorMessage').innerText = 'Invalid password, please try again.';
// 重新聚焦输入框
setTimeout(() => {
document.getElementById('keyInput').focus();
}, 100);
}
}
function initPasswordSystem() {
const submitKey = document.getElementById('submitKey');
if (submitKey) {
submitKey.addEventListener('click', verifyPassword);
// 添加触摸事件
submitKey.addEventListener('touchend', function(e) {
e.preventDefault();
verifyPassword();
});
}
}
function createFloatingWindow() {
const floatingWindow = document.createElement('div');
floatingWindow.id = 'greenToolsWindow';
floatingWindow.style.position = 'fixed';
floatingWindow.style.top = '20px';
floatingWindow.style.right = '20px';
floatingWindow.style.width = 'min(350px, 90vw)'; // 响应式宽度
floatingWindow.style.backgroundColor = 'rgba(0, 100, 0, 0.9)';
floatingWindow.style.border = '2px solid #00ff00';
floatingWindow.style.borderRadius = '10px';
floatingWindow.style.boxShadow = '0 0 20px rgba(0, 255, 0, 0.5)';
floatingWindow.style.zIndex = '10000';
floatingWindow.style.fontFamily = 'Arial, sans-serif';
floatingWindow.style.color = 'white';
floatingWindow.style.overflow = 'hidden';
floatingWindow.style.touchAction = 'none'; // 防止浏览器处理触摸事件
floatingWindow.innerHTML = `
<div style="background: rgba(0, 80, 0, 0.9); padding: 15px; display: flex; justify-content: space-between; align-items: center; cursor: move; border-bottom: 1px solid #00ff00; min-height: 44px;">
<div style="font-weight: bold; font-size: clamp(14px, 4vw, 16px);">Green Tools</div>
<div>
<button id="minimizeBtn" style="background: transparent; border: none; color: white; cursor: pointer; margin-right: 10px; font-size: 18px; min-width: 44px; min-height: 44px;">−</button>
<button id="closeBtn" style="background: transparent; border: none; color: white; cursor: pointer; font-size: 18px; min-width: 44px; min-height: 44px;">×</button>
</div>
</div>
<div id="windowContent" style="padding: 15px; max-height: 60vh; overflow-y: auto;">
<div style="margin-bottom: 15px;">
<h3 style="margin-top: 0; border-bottom: 1px solid #00ff00; padding-bottom: 5px; font-size: clamp(14px, 4vw, 16px);">Built-in Features</h3>
<div style="display: flex; justify-content: space-between; margin-bottom: 15px; align-items: center;">
<span style="font-size: clamp(12px, 3.5vw, 14px);">Speed Boost</span>
<button id="speedToggle" style="background: #ff4444; border: none; border-radius: 15px; width: 60px; height: 30px; position: relative; cursor: pointer; min-height: 30px;">
<div style="position: absolute; top: 2px; left: 2px; width: 26px; height: 26px; background: white; border-radius: 50%; transition: left 0.3s;"></div>
</button>
</div>
<div style="display: flex; justify-content: space-between; margin-bottom: 15px; align-items: center;">
<span style="font-size: clamp(12px, 3.5vw, 14px);">Jump Boost</span>
<button id="jumpToggle" style="background: #ff4444; border: none; border-radius: 15px; width: 60px; height: 30px; position: relative; cursor: pointer; min-height: 30px;">
<div style="position: absolute; top: 2px; left: 2px; width: 26px; height: 26px; background: white; border-radius: 50%; transition: left 0.3s;"></div>
</button>
</div>
</div>
<div style="margin-bottom: 15px;">
<h3 style="border-bottom: 1px solid #00ff00; padding-bottom: 5px; font-size: clamp(14px, 4vw, 16px);">Custom Scripts</h3>
<textarea id="scriptInput" placeholder="Paste your script here..." style="width: 100%; height: 100px; background: rgba(255,255,255,0.1); color: white; border: 1px solid #00ff00; border-radius: 5px; padding: 10px; margin-bottom: 10px; resize: vertical; font-size: clamp(12px, 3.5vw, 14px); box-sizing: border-box;"></textarea>
<div style="display: flex; justify-content: space-between; gap: 5px; flex-wrap: wrap;">
<button id="runScript" style="background: #00aa00; border: none; border-radius: 5px; color: white; padding: 10px; cursor: pointer; flex: 1; min-height: 44px; font-size: clamp(12px, 3.5vw, 14px);">Run</button>
<button id="saveScript" style="background: #0088cc; border: none; border-radius: 5px; color: white; padding: 10px; cursor: pointer; flex: 1; min-height: 44px; font-size: clamp(12px, 3.5vw, 14px);">Save</button>
<input type="text" id="scriptName" placeholder="Script name" style="background: rgba(255,255,255,0.1); color: white; border: 1px solid #00ff00; border-radius: 5px; padding: 10px; flex: 1; min-width: 100px; font-size: clamp(12px, 3.5vw, 14px); box-sizing: border-box;">
</div>
</div>
<div>
<h3 style="border-bottom: 1px solid #00ff00; padding-bottom: 5px; font-size: clamp(14px, 4vw, 16px);">Saved Scripts</h3>
<div id="savedScriptsList" style="max-height: 200px; overflow-y: auto;">
<!-- Saved scripts will be listed here -->
</div>
</div>
</div>
`;
document.body.appendChild(floatingWindow);
makeDraggable(floatingWindow);
// 为所有按钮添加触摸事件支持
const addTouchSupport = (element, handler) => {
element.addEventListener('click', handler);
element.addEventListener('touchend', function(e) {
e.preventDefault();
handler();
});
};
addTouchSupport(document.getElementById('speedToggle'), toggleSpeedBoost);
addTouchSupport(document.getElementById('jumpToggle'), toggleJumpBoost);
addTouchSupport(document.getElementById('runScript'), runCustomScript);
addTouchSupport(document.getElementById('saveScript'), saveCustomScript);
addTouchSupport(document.getElementById('minimizeBtn'), toggleMinimize);
addTouchSupport(document.getElementById('closeBtn'), closeWindow);
loadSavedScripts();
}
function makeDraggable(element) {
const header = element.querySelector('div');
let isDragging = false;
let currentX, currentY, initialX, initialY, xOffset = 0, yOffset = 0;
const dragStart = (clientX, clientY) => {
initialX = clientX - xOffset;
initialY = clientY - yOffset;
isDragging = true;
};
const dragEnd = () => {
initialX = currentX;
initialY = currentY;
isDragging = false;
};
const drag = (clientX, clientY) => {
if (isDragging) {
currentX = clientX - initialX;
currentY = clientY - initialY;
xOffset = currentX;
yOffset = currentY;
setTranslate(currentX, currentY, element);
}
};
const setTranslate = (xPos, yPos, el) => {
el.style.transform = `translate3d(${xPos}px, ${yPos}px, 0)`;
};
// 鼠标事件
header.addEventListener("mousedown", (e) => {
dragStart(e.clientX, e.clientY);
});
document.addEventListener("mouseup", dragEnd);
document.addEventListener("mousemove", (e) => {
drag(e.clientX, e.clientY);
});
// 触摸事件
header.addEventListener("touchstart", (e) => {
e.preventDefault();
const touch = e.touches[0];
dragStart(touch.clientX, touch.clientY);
}, { passive: false });
document.addEventListener("touchend", dragEnd);
document.addEventListener("touchmove", (e) => {
if (isDragging) {
e.preventDefault();
const touch = e.touches[0];
drag(touch.clientX, touch.clientY);
}
}, { passive: false });
}
// 其余函数保持不变(toggleSpeedBoost, applySpeedBoost, removeSpeedBoost, toggleJumpBoost, applyJumpBoost, removeJumpBoost, runCustomScript, saveCustomScript, loadSavedScripts, toggleMinimize, closeWindow, showNotification)
function toggleSpeedBoost() {
const toggle = document.getElementById('speedToggle');
const toggleCircle = toggle.querySelector('div');
if (!isSpeedBoostActive) {
toggle.style.background = '#44ff44';
toggleCircle.style.left = '32px';
applySpeedBoost();
isSpeedBoostActive = true;
showNotification('Speed Boost Activated');
} else {
toggle.style.background = '#ff4444';
toggleCircle.style.left = '2px';
removeSpeedBoost();
isSpeedBoostActive = false;
showNotification('Speed Boost Deactivated');
}
}
function applySpeedBoost() {
const targetWalkSpeed = 115;
Object.defineProperty(Object.prototype, 'walkSpeed', {
get() {
return this._walkSpeed || targetWalkSpeed;
},
set(value) {
this._walkSpeed = targetWalkSpeed;
console.log('walkSpeed set to ' + this._walkSpeed);
},
configurable: true
});
Object.defineProperty(Object.prototype, 'flagWalkSpeed', {
get() {
return this._flagWalkSpeed || targetWalkSpeed;
},
set(value) {
this._flagWalkSpeed = targetWalkSpeed;
console.log('flagWalkSpeed set to ' + this._flagWalkSpeed);
},
configurable: true
});
}
function removeSpeedBoost() {
delete Object.prototype.walkSpeed;
delete Object.prototype.flagWalkSpeed;
}
function toggleJumpBoost() {
const toggle = document.getElementById('jumpToggle');
const toggleCircle = toggle.querySelector('div');
if (!isJumpBoostActive) {
toggle.style.background = '#44ff44';
toggleCircle.style.left = '32px';
applyJumpBoost();
isJumpBoostActive = true;
showNotification('Jump Boost Activated');
} else {
toggle.style.background = '#ff4444';
toggleCircle.style.left = '2px';
removeJumpBoost();
isJumpBoostActive = false;
showNotification('Jump Boost Deactivated');
}
}
function applyJumpBoost() {
const targetJumpForce = 20;
Object.defineProperty(Object.prototype, 'jumpForce', {
get() {
return this._jumpForce || targetJumpForce;
},
set(value) {
this._jumpForce = targetJumpForce;
console.log('jumpForce set to ' + this._jumpForce);
},
configurable: true
});
}
function removeJumpBoost() {
delete Object.prototype.jumpForce;
}
function runCustomScript() {
const scriptCode = document.getElementById('scriptInput').value;
if (scriptCode.trim()) {
try {
eval(scriptCode);
showNotification('Custom script executed');
} catch (error) {
showNotification('Error in script: ' + error.message, true);
}
} else {
showNotification('Please enter a script', true);
}
}
function saveCustomScript() {
const scriptCode = document.getElementById('scriptInput').value;
const scriptName = document.getElementById('scriptName').value;
if (scriptCode.trim() && scriptName.trim()) {
savedScripts[scriptName] = scriptCode;
GM_setValue('savedScripts', savedScripts);
loadSavedScripts();
showNotification('Script saved: ' + scriptName);
document.getElementById('scriptName').value = '';
} else {
showNotification('Please enter both script and name', true);
}
}
function loadSavedScripts() {
const savedScriptsList = document.getElementById('savedScriptsList');
savedScriptsList.innerHTML = '';
for (const name in savedScripts) {
const scriptItem = document.createElement('div');
scriptItem.style.display = 'flex';
scriptItem.style.justifyContent = 'space-between';
scriptItem.style.alignItems = 'center';
scriptItem.style.marginBottom = '8px';
scriptItem.style.padding = '8px';
scriptItem.style.backgroundColor = 'rgba(255,255,255,0.1)';
scriptItem.style.borderRadius = '5px';
scriptItem.innerHTML = `
<span style="font-size: clamp(12px, 3.5vw, 14px);">${name}</span>
<div>
<button class="run-saved-script" data-name="${name}" style="background: #00aa00; border: none; border-radius: 5px; color: white; padding: 8px 12px; margin-right: 5px; cursor: pointer; font-size: clamp(11px, 3vw, 12px); min-height: 36px;">Run</button>
<button class="delete-script" data-name="${name}" style="background: #ff4444; border: none; border-radius: 5px; color: white; padding: 8px 12px; cursor: pointer; font-size: clamp(11px, 3vw, 12px); min-height: 36px;">Delete</button>
</div>
`;
savedScriptsList.appendChild(scriptItem);
}
// 为保存的脚本按钮添加触摸支持
document.querySelectorAll('.run-saved-script').forEach(button => {
button.addEventListener('click', function() {
const scriptName = this.getAttribute('data-name');
try {
eval(savedScripts[scriptName]);
showNotification('Script executed: ' + scriptName);
} catch (error) {
showNotification('Error in script: ' + error.message, true);
}
});
button.addEventListener('touchend', function(e) {
e.preventDefault();
const scriptName = this.getAttribute('data-name');
try {
eval(savedScripts[scriptName]);
showNotification('Script executed: ' + scriptName);
} catch (error) {
showNotification('Error in script: ' + error.message, true);
}
});
});
document.querySelectorAll('.delete-script').forEach(button => {
button.addEventListener('click', function() {
const scriptName = this.getAttribute('data-name');
delete savedScripts[scriptName];
GM_setValue('savedScripts', savedScripts);
loadSavedScripts();
showNotification('Script deleted: ' + scriptName);
});
button.addEventListener('touchend', function(e) {
e.preventDefault();
const scriptName = this.getAttribute('data-name');
delete savedScripts[scriptName];
GM_setValue('savedScripts', savedScripts);
loadSavedScripts();
showNotification('Script deleted: ' + scriptName);
});
});
}
function toggleMinimize() {
const content = document.getElementById('windowContent');
if (content.style.display === 'none') {
content.style.display = 'block';
} else {
content.style.display = 'none';
}
}
function closeWindow() {
document.getElementById('greenToolsWindow').style.display = 'none';
showNotification('Green Tools minimized to system tray');
const reopenBtn = document.createElement('div');
reopenBtn.innerHTML = 'GT';
reopenBtn.style.position = 'fixed';
reopenBtn.style.bottom = '20px';
reopenBtn.style.right = '20px';
reopenBtn.style.width = '50px';
reopenBtn.style.height = '50px';
reopenBtn.style.backgroundColor = 'rgba(0, 100, 0, 0.9)';
reopenBtn.style.border = '2px solid #00ff00';
reopenBtn.style.borderRadius = '50%';
reopenBtn.style.display = 'flex';
reopenBtn.style.alignItems = 'center';
reopenBtn.style.justifyContent = 'center';
reopenBtn.style.color = 'white';
reopenBtn.style.fontSize = '16px';
reopenBtn.style.fontWeight = 'bold';
reopenBtn.style.cursor = 'pointer';
reopenBtn.style.zIndex = '10000';
reopenBtn.style.touchAction = 'manipulation';
reopenBtn.id = 'greenToolsReopen';
const reopenHandler = function() {
document.getElementById('greenToolsWindow').style.display = 'block';
this.remove();
};
reopenBtn.addEventListener('click', reopenHandler);
reopenBtn.addEventListener('touchend', function(e) {
e.preventDefault();
reopenHandler.call(this);
});
document.body.appendChild(reopenBtn);
}
function showNotification(message, isError = false) {
const notification = document.createElement('div');
notification.textContent = message;
notification.style.position = 'fixed';
notification.style.top = '20px';
notification.style.left = '50%';
notification.style.transform = 'translateX(-50%)';
notification.style.backgroundColor = isError ? 'rgba(255, 0, 0, 0.8)' : 'rgba(0, 255, 0, 0.8)';
notification.style.color = 'white';
notification.style.padding = '15px 25px';
notification.style.borderRadius = '8px';
notification.style.zIndex = '10001';
notification.style.fontSize = 'clamp(14px, 4vw, 16px)';
notification.style.fontWeight = 'bold';
notification.style.boxShadow = '0 0 15px rgba(0,0,0,0.5)';
notification.style.textAlign = 'center';
notification.style.maxWidth = '80vw';
document.body.appendChild(notification);
setTimeout(() => {
if (document.body.contains(notification)) {
document.body.removeChild(notification);
}
}, 3000);
}
// 改进的初始化函数
function init() {
console.log(`
____ _____ _
/ ___| _ __ ___ ___ _ __ |_ _| ___ ___ | | ___
| | _ | '__| / _ \\ / _ \\ | '_ \\ | | / _ \\ / _ \\ | | / __|
| |_| | | | | __/ | __/ | | | | | | | (_) | | (_) | | | \\__ \\
\\____| |_| \\___| \\___| |_| |_| |_| \\___/ \\___/ |_| |___/
Green Tools - Script Manager for Narrow One
`);
// 使用更可靠的初始化方法
const initInterval = setInterval(() => {
if (document.body) {
clearInterval(initInterval);
createKeyOverlay();
initPasswordSystem();
// 确保密码输入框获得焦点
setTimeout(() => {
const keyInput = document.getElementById('keyInput');
if (keyInput) {
keyInput.focus();
}
}, 1000);
}
}, 100);
// 10秒后停止检查
setTimeout(() => {
clearInterval(initInterval);
}, 10000);
}
// 启动脚本
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
setTimeout(init, 100);
}
})();