您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Reply to messages on HF Convo with formatted text
// ==UserScript== // @name HFReply // @version 2025-02-15 // @description Reply to messages on HF Convo with formatted text // @author NovoDev // @match https://hackforums.net/* // @grant none // @license MIT // @namespace https://greasyfork.org/users/1435467 // ==/UserScript== (function () { 'use strict'; function addReplyButtons() { const messageContainerXPath = "/html/body/div[3]/div[3]/div/div[3]/div[3]/div/div[2]/div[3]"; const commentBox = document.evaluate("//*[@id='comment']", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; if (!commentBox) { console.error("Comment box not found"); return; } const container = document.evaluate(messageContainerXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; if (!container) { console.error("Message container not found"); return; } const observer = new MutationObserver(() => { const messages = container.querySelectorAll(".message-convo-left, .message-convo-right, .message-convo-follow"); messages.forEach((msg) => { if (msg.dataset.replyAdded) return; const isOwnMessage = msg.classList.contains("message-convo-right"); if (isOwnMessage) return; const messageText = msg.textContent.trim().toLowerCase(); if (messageText.includes("/flip") || messageText.includes("/jackpot")) { return; } msg.dataset.replyAdded = "true"; let nameElement = msg.querySelector("[data-profile-username] a strong"); if (!nameElement) { let prevMsg = msg.previousElementSibling; while (prevMsg) { nameElement = prevMsg.querySelector("[data-profile-username] a strong"); if (nameElement) break; prevMsg = prevMsg.previousElementSibling; } } const textContainers = msg.querySelectorAll(".message-bubble-message"); if (nameElement && textContainers.length > 0) { let replyText = `@${nameElement.textContent.trim()}@ : ***"`; textContainers.forEach(container => { const textSpans = container.querySelectorAll("span"); textSpans.forEach(span => { replyText += `${span.textContent.trim()} `; }); }); replyText = replyText.trim() + `"***`; const replyButton = document.createElement("span"); replyButton.innerHTML = ` <span style=" cursor: pointer; color: #fff; background: #2563eb; padding: 4px 8px; margin-left: 10px; font-size: 12px; border-radius: 6px; display: inline-flex; align-items: center; gap: 4px; transition: filter 0.2s; "> <svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor"> <path d="M10 9V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z"/> </svg> Reply </span> `; replyButton.onmouseenter = () => { replyButton.firstElementChild.style.filter = "brightness(0.9)"; }; replyButton.onmouseleave = () => { replyButton.firstElementChild.style.filter = "none"; }; replyButton.onclick = () => { commentBox.value = `${replyText}\n${commentBox.value}`; commentBox.focus(); commentBox.scrollIntoView(); }; textContainers[textContainers.length - 1].appendChild(replyButton); } }); }); observer.observe(container, { childList: true, subtree: true }); } window.addEventListener("load", addReplyButtons); })();