您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Blocks reaction packets, shows GUI, resends with chosen emoji, updates client UI
当前为
// ==UserScript== // @name InvadedLands Reactions // @namespace http://tampermonkey.net/ // @version 6.9 // @description Blocks reaction packets, shows GUI, resends with chosen emoji, updates client UI // @author PillowPB // @match *https://invadedlands.net/* // @grant none // @license Creative Commons license, // @run-at document-end // ==/UserScript== (function() { 'use strict'; const reactionMap = { "1": "👍", "2": "❤️", "3": "😂", "4": "😮", "5": "😢", "6": "😡" }; let isHacking = true; let hackedPostId = null; let lastClickEvent = null; // packets are very cool i do not hate them const originalOpen = XMLHttpRequest.prototype.open; const originalSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function(method, url) { this._method = method; this._url = url; return originalOpen.apply(this, arguments); }; XMLHttpRequest.prototype.send = function(body) { if (isHacking && this._url?.includes('/react?reaction_id=')) { const postIdMatch = this._url.match(/\/posts\/(\d+)\/react/); hackedPostId = postIdMatch ? postIdMatch[1] : null; console.log('[invadedlands is the best] Blocked reaction packet for post', hackedPostId); const x = lastClickEvent?.clientX || window.innerWidth / 2; const y = lastClickEvent?.clientY || window.innerHeight / 2; if (hackedPostId) showReactionMenu(hackedPostId, x, y); return; // block original packet } return originalSend.apply(this, arguments); }; // positioning menu mouse document.addEventListener('click', e => lastClickEvent = e, true); function sendCustomReaction(postId, reactionId) { isHacking = false; const xfToken = document.querySelector('input[name="_xfToken"]')?.value; if (!xfToken) { console.warn('Missing _xfToken'); return; } const formData = new FormData(); formData.append('_xfToken', xfToken); formData.append('_xfRequestUri', window.location.pathname); formData.append('_xfWithData', '1'); formData.append('_xfResponseType', 'json'); fetch(`/posts/${postId}/react?reaction_id=${reactionId}`, { method: 'POST', body: new URLSearchParams(formData), headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(response => { if (!response.ok) throw new Error('Network response was not ok'); return response.json(); }) .then(data => { console.log(`[omg] Sent reaction ${reactionId} to post ${postId}`, data); // Update reaction count UI const postElem = document.querySelector(`[data-content*="post-${postId}"]`); if (postElem) { const reactionBtn = postElem.querySelector(`a.messageReactionLink[href*="reaction_id=${reactionId}"]`); if (reactionBtn) { let countSpan = reactionBtn.querySelector('.reactionCount'); if (countSpan) { countSpan.textContent = (parseInt(countSpan.textContent) || 0) + 1; } else { const span = document.createElement('span'); span.className = 'reactionCount'; span.textContent = '1'; reactionBtn.appendChild(span); } reactionBtn.classList.add('reactionSelected'); setTimeout(() => reactionBtn.classList.remove('reactionSelected'), 1500); } } document.dispatchEvent(new CustomEvent('reactionSent', { detail: { postId, reactionId } })); }) .catch(error => { console.error('[WTF] Failed to send reaction:', error); }) .finally(() => { setTimeout(() => isHacking = true, 100); }); } function showReactionMenu(postId, x, y) { document.querySelectorAll('.reaction-menu-container').forEach(el => el.remove()); const menu = document.createElement('div'); menu.className = 'reaction-menu-container'; menu.style.cssText = ` position: fixed; left: ${Math.min(x, window.innerWidth - 220)}px; top: ${Math.min(y, window.innerHeight - 120)}px; background: #2d2d2d; border-radius: 8px; padding: 10px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; z-index: 99999; box-shadow: 0 2px 10px rgba(0,0,0,0.5); border: 1px solid #444; `; Object.entries(reactionMap).forEach(([id, emoji]) => { const btn = document.createElement('div'); btn.className = 'reaction-emoji-btn'; btn.textContent = emoji; btn.title = `Reaction ID: ${id}`; btn.style.cssText = ` font-size: 24px; cursor: pointer; padding: 4px; border-radius: 4px; transition: all 0.2s; text-align: center; `; btn.addEventListener('mouseenter', () => { btn.style.background = '#3e3e3e'; btn.style.transform = 'scale(1.2)'; }); btn.addEventListener('mouseleave', () => { btn.style.background = 'transparent'; btn.style.transform = 'scale(1)'; }); btn.addEventListener('click', () => { sendCustomReaction(postId, id); menu.remove(); }); menu.appendChild(btn); }); document.body.appendChild(menu); setTimeout(() => { const clickHandler = (e) => { if (!menu.contains(e.target)) { menu.remove(); document.removeEventListener('click', clickHandler); } }; document.addEventListener('click', clickHandler); }, 10); } console.log('Reaction invadedlands initialized'); })();