您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
在 S1 论坛头像右上角显示按钮,点击后替换为 Dicebear 图像。
// ==UserScript== // @name S1头像替换 // @namespace https://bbs.saraba1st.com // @version 1.4 // @description 在 S1 论坛头像右上角显示按钮,点击后替换为 Dicebear 图像。 // @author hexie // @match https://*.saraba1st.com/2b/* // @match https://stage1st.com/2b/* // @icon https://www.google.com/s2/favicons?sz=64&domain=saraba1st.com // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_registerMenuCommand // @license MIT // ==/UserScript== (function() { 'use strict'; // Dicebear API 配置 const DICEBEAR_API_URL = 'https://api.dicebear.com/9.x/thumbs/svg'; /** * 从用户链接中提取 uid。 */ function extractUidFromHref(href) { if (!href) return null; const match = href.match(/uid-(\d+)\.html/); return match ? match[1] : null; } /** * 替换指定 uid 的头像。 */ function replaceAvatar(uid) { if (!uid) return; const seed = uid; const newSrc = `${DICEBEAR_API_URL}?seed=${seed}`; document.querySelectorAll(`img[data-uid="${uid}"]`).forEach((imgElement) => { if (!imgElement.hasAttribute('data-original-src')) { imgElement.setAttribute('data-original-src', imgElement.dataset.original || imgElement.src); } imgElement.src = newSrc; }); GM_setValue(uid, newSrc); // console.log(`[S1 Avatar Replacer] Replaced avatar for UID: ${uid}`); } /** * 恢复指定 uid 的头像为原始头像。 */ function resetAvatar(uid) { if (!uid) return; GM_deleteValue(uid); document.querySelectorAll(`img[data-uid="${uid}"]`).forEach((imgElement) => { const originalSrc = imgElement.getAttribute('data-original-src'); if (originalSrc) { imgElement.src = originalSrc; } }); // console.log(`[S1 Avatar Replacer] Reset avatar for UID: ${uid}`); } /** * 为头像元素添加替换按钮。 */ function addReplaceButton(avatarContainer, imgElement, uid) { const button = document.createElement('button'); button.textContent = '㔢'; button.title = '替换为 Dicebear 头像'; // --- 按钮样式 --- button.style.position = 'absolute'; button.style.top = '2px'; button.style.right = '2px'; button.style.zIndex = '1001'; button.style.cursor = 'pointer'; button.style.background = 'rgba(0, 123, 255, 0.8)'; button.style.color = '#ffffff'; button.style.border = '1px solid rgba(255, 255, 255, 0.5)'; button.style.borderRadius = '50%'; button.style.width = '18px'; button.style.height = '18px'; button.style.fontSize = '10px'; button.style.lineHeight = '16px'; button.style.textAlign = 'center'; button.style.padding = '0'; button.style.display = 'none'; button.style.boxShadow = '0 1px 3px rgba(0, 0, 0, 0.3)'; button.style.transition = 'background-color 0.2s ease, opacity 0.2s ease'; button.style.opacity = '0.8'; // --- 按钮交互 --- avatarContainer.style.position = 'relative'; avatarContainer.addEventListener('mouseover', () => { button.style.display = 'block'; }); avatarContainer.addEventListener('mouseout', () => { button.style.display = 'none'; }); button.addEventListener('mouseover', () => { button.style.background = 'rgba(0, 100, 210, 0.9)'; button.style.opacity = '1'; }); button.addEventListener('mouseout', () => { button.style.background = 'rgba(0, 123, 255, 0.8)'; button.style.opacity = '0.8'; }); button.onclick = function(event) { event.preventDefault(); event.stopPropagation(); replaceAvatar(uid); }; avatarContainer.appendChild(button); } /** * 初始化页面上的所有头像。 */ function initializeAvatars() { document.querySelectorAll('div.avatar, div.icn.avt').forEach(function(avatarContainer) { const imgElement = avatarContainer.querySelector('img'); const linkElement = avatarContainer.querySelector('a[href*="uid-"]'); if (!imgElement) return; const uid = linkElement ? extractUidFromHref(linkElement.href) : null; if (uid) { imgElement.setAttribute('data-uid', uid); if (!imgElement.hasAttribute('data-original-src')) { const originalSrc = imgElement.dataset.original || imgElement.src; imgElement.setAttribute('data-original-src', originalSrc); } const savedSrc = GM_getValue(uid); if (savedSrc) { imgElement.src = savedSrc; } else { imgElement.src = imgElement.getAttribute('data-original-src'); } addReplaceButton(avatarContainer, imgElement, uid); } else { if (!imgElement.hasAttribute('data-original-src')) { const originalSrc = imgElement.dataset.original || imgElement.src; imgElement.setAttribute('data-original-src', originalSrc); imgElement.src = originalSrc; } } }); } // --- Greasemonkey 菜单命令 --- // 清除所有保存的头像数据并恢复原始头像 GM_registerMenuCommand("清除所有S1替换头像数据", function() { let clearedCount = 0; document.querySelectorAll('img[data-uid]').forEach(function(imgElement) { const uid = imgElement.getAttribute('data-uid'); if (uid && GM_getValue(uid)) { resetAvatar(uid); clearedCount++; } else if (uid) { const originalSrc = imgElement.getAttribute('data-original-src'); if (originalSrc && imgElement.src !== originalSrc) { imgElement.src = originalSrc; } } }); if (clearedCount > 0) { alert(`已清除 ${clearedCount} 个用户的替换头像数据并恢复原始头像。`); } else { alert("没有找到已保存的替换头像数据。"); } }); // --- 初始化脚本 --- initializeAvatars(); // 使用 MutationObserver 监听 DOM 变化,处理动态加载的头像 const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.addedNodes.length) { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { if (node.matches('div.avatar, div.icn.avt') || node.querySelector('div.avatar, div.icn.avt')) { // 简单的重新扫描整个文档,确保处理新加载的头像 // 对于大型或频繁更新的页面,可以优化为只处理新添加的节点 initializeAvatars(); return; } } }); } }); }); observer.observe(document.body, { childList: true, subtree: true }); })();