// ==UserScript== // @name 共享账号搜索 // @namespace http://tampermonkey.net/ // @version 1.3 // @description 获取共享账号并自动填写 // @author Hồng Minh Tâm & Gemini // @icon http://bugmenot.com/favicon.ico // @include * // @connect bugmenot.com // @grant GM_addStyle // @grant GM_xmlhttpRequest // @license GNU GPLv3 // @downloadURL https://update.greasyfork.icu/scripts/553059/%E5%85%B1%E4%BA%AB%E8%B4%A6%E5%8F%B7%E6%90%9C%E7%B4%A2.user.js // @updateURL https://update.greasyfork.icu/scripts/553059/%E5%85%B1%E4%BA%AB%E8%B4%A6%E5%8F%B7%E6%90%9C%E7%B4%A2.meta.js // ==/UserScript== (function () { 'use strict'; const icons = { mail: '' } GM_addStyle([ '.bmn-list { display:none; list-style: none; border: 1px solid rgba(128, 128, 128, 0.5); padding: 0; margin: 0; background-color: rgb(44,44,44); color: rgb(203, 203, 203); position: fixed; cursor: default; z-index: 9999999999; box-sizing: border-box; overflow: auto; text-align: left; width: 300px; }', '.bmn-list.show { display:block; }', '.bmn-list .bmn-item { position: relative; padding: 8px 10px 8px 15px; margin: 0; cursor: pointer; border-bottom: 1px solid rgba(128, 128, 128, 0.2); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-size: 9pt; line-height: 1.4;}', '.bmn-list .bmn-item:last-child { border-bottom: 0; }', '.bmn-list .bmn-item:hover { background-color: rgba(255, 255, 255, 0.1); }', '.bmn-list .bmn-item:before { position: absolute; content: ""; width: 5px; top: 0; left: 0; bottom: 0; background-color: #f7704f; }', '.bmn-list .bmn-item .bmn-label { font-weight: 600; }', '.bmn-list .bmn-item .bmn-username { color: rgb(246, 182, 78); }', '.bmn-list .bmn-item .bmn-password { color: rgb(118, 202, 83); }', '.bmn-list .bmn-item .bmn-email-entry { cursor: pointer; }', '.bmn-list .bmn-item .bmn-email-entry .bmn-value { color: rgb(138, 180, 248); text-decoration: none; }', '.bmn-list .bmn-item .bmn-email-entry:hover .bmn-value { text-decoration: underline; }', '.bmn-list .bmn-item .bmn-success-rate { float: right; font-weight: 700; margin-left: 10px; }', '.bmn-list .bmn-item.bmn-success-100 .bmn-success-rate { color: rgb(0,198,0); }', '.bmn-list .bmn-item.bmn-success-100:before { background-color: rgb(0,198,0); }', '.bmn-list .bmn-item.bmn-success-90 .bmn-success-rate { color: rgb(50,180,0); }', '.bmn-list .bmn-item.bmn-success-90:before { background-color: rgb(50,180,0); }', '.bmn-list .bmn-item.bmn-success-80 .bmn-success-rate { color: rgb(99,164,0); }', '.bmn-list .bmn-item.bmn-success-80:before { background-color: rgb(99,164,0); }', '.bmn-list .bmn-item.bmn-success-70 .bmn-success-rate { color: rgb(149,146,0); }', '.bmn-list .bmn-item.bmn-success-70:before { background-color: rgb(149,146,0); }', '.bmn-list .bmn-item.bmn-success-60 .bmn-success-rate { color: rgb(199,129,0); }', '.bmn-list .bmn-item.bmn-success-60:before { background-color: rgb(199,129,0); }', '.bmn-list .bmn-item.bmn-success-50 .bmn-success-rate { color: rgb(247,112,0); }', '.bmn-list .bmn-item.bmn-success-50:before { background-color: rgb(247,112,0); }', '.bmn-list .bmn-item.bmn-success-40 .bmn-success-rate { color: rgb(247,90,0); }', '.bmn-list .bmn-item.bmn-success-40:before { background-color: rgb(247,90,0); }', '.bmn-list .bmn-item.bmn-success-30 .bmn-success-rate { color: rgb(247,67,0); }', '.bmn-list .bmn-item.bmn-success-30:before { background-color: rgb(247,67,0); }', '.bmn-list .bmn-item.bmn-success-20 .bmn-success-rate { color: rgb(247,45,0); }', '.bmn-list .bmn-item.bmn-success-20:before { background-color: rgb(247,45,0); }', '.bmn-list .bmn-item.bmn-success-10 .bmn-success-rate { color: rgb(247,22,0); }', '.bmn-list .bmn-item.bmn-success-10:before { background-color: rgb(247,22,0); }', '.bmn-list .bmn-no-logins-found, .bmn-list .bmn-loading { padding: 10px 15px; margin: 0; cursor: default; text-align: center; background-color: #a90000; color: #fff; font-size: 9pt; }', '.bmn-list .bmn-loading { background-color: #007bff; color: #fff; }', // --- [核心修复] 强制 box-sizing 防止尺寸计算错误 --- '.bmn-floating-button { position: fixed !important; background: transparent !important; border: none !important; cursor: pointer !important; padding: 2px !important; display: flex !important; align-items: center; justify-content: center; z-index: 999999 !important; opacity: 0.5; transition: opacity 0.2s ease, transform 0.2s ease !important; color: grey !important; pointer-events: auto !important; margin: 0 !important; width: 24px; height: 24px; box-sizing: border-box !important; }', '.bmn-floating-button:hover { opacity: 1 !important; transform: scale(1.1); }', '.bmn-floating-button svg { width: 18px; height: 18px; display: block; }', '.bmn-list::-webkit-scrollbar { width: 8px; }', '.bmn-list::-webkit-scrollbar-track { background: rgb(44, 44, 44); }', '.bmn-list::-webkit-scrollbar-thumb { background-color: rgb(159, 159, 159); border-radius: 4px; }', '.bmn-list::-webkit-scrollbar-thumb:hover { background-color: rgb(190, 190, 190); }' ].join('')); // --- 工具函数 --- Object.defineProperty(String.prototype, 'toDOM', { value: function (isFull) { var parser = new DOMParser(), dom = parser.parseFromString(this, 'text/html'); return isFull ? dom : dom.body.childNodes[0]; }, enumerable: false }); function debounce(func, wait) { let timeout; return function(...args) { const context = this; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), wait); }; } function setValueInput(input, value, isInputSimulate) { var setValue = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set; setValue.call(input, value); if (isInputSimulate) { var e = new Event('input', { bubbles: true }); input.dispatchEvent(e); } } function getOffset(element) { var elementRect = element.getBoundingClientRect(); return { left: elementRect.left, right: elementRect.right, top: elementRect.top, bottom: elementRect.bottom, width: elementRect.width, height: elementRect.height }; } function handleEvent(func, data) { return function (event) { func.bind(this)(event, data); }; } // --- 核心变量 --- var accounts = []; var dataFetched = false; var isLoading = false; var inputUsernameCurrentEl, inputPasswordCurrentEl; var listBMNEl = null; var buttonMap = new Map(); // --- 主要功能 --- function fetchData(callback) { if (isLoading) return; isLoading = true; listBMNEl.innerHTML = '
  • 正在加载...
  • '; showListBMNEl(); GM_xmlhttpRequest({ method: 'GET', url: 'http://bugmenot.com/view/' + location.hostname, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, onload: function (response) { var bmnEl = response.responseText.toDOM(true); var accountEls = bmnEl.getElementsByClassName('account'); accounts = []; for (var i = 0; i < accountEls.length; i++) { var accountEl = accountEls[i]; var infoEl = accountEl.getElementsByTagName('kbd'); var statsEl = accountEl.getElementsByClassName('stats')[1].getElementsByTagName('li'); var account = { username: infoEl[0].innerHTML || '', password: infoEl[1].innerHTML || '', email: (infoEl[2] && infoEl[2].innerHTML) ? infoEl[2].innerHTML : '', success: parseInt(statsEl[0].innerHTML.match(/\d+(?=%)/)[0]), vote: parseInt(statsEl[1].innerHTML.match(/\d+(?=\svotes)/)[0]), time: statsEl[2].innerHTML }; accounts.push(account); } dataFetched = true; isLoading = false; populateList(); if (callback) callback(); }, onerror: function (response) { isLoading = false; listBMNEl.innerHTML = '
  • 获取数据失败
  • '; } }); } function initListContainer() { if (listBMNEl) return; listBMNEl = document.createElement('ul'); listBMNEl.classList.add('bmn-list'); document.body.appendChild(listBMNEl); } function populateList() { if (!listBMNEl) return; listBMNEl.innerHTML = ''; if (accounts.length) { accounts.forEach(function (account, index) { var itemBMNEl = document.createElement('li'); itemBMNEl.classList.add('bmn-item'); itemBMNEl.classList.add(getClassSuccess(account.success)); var emailHTML = ''; if (account.email && account.email.trim() !== '') { emailHTML = `
    邮箱: ${account.email}
    `; } var itemBMNElHTML = `
    ${account.success}% 账号: ${account.username}
    密码: ${account.password}
    ${emailHTML} `; itemBMNEl.innerHTML = itemBMNElHTML; var titleLines = [ '账号: ' + account.username, '密码: ' + account.password, ]; if (account.email && account.email.trim() !== '') { titleLines.push('邮箱: ' + account.email); } titleLines.push( '', '成功率: ' + account.success + '%', '投票数: ' + account.vote, '提交于: ' + account.time ); itemBMNEl.title = titleLines.join('\n'); itemBMNEl.onmousedown = handleEvent(onMouseDownItem); itemBMNEl.onclick = handleEvent(onClickItem, account); itemBMNEl.onmouseover = handleEvent(onMouseOverItem, account); itemBMNEl.onmouseout = handleEvent(onMouseOutItem); var emailEl = itemBMNEl.querySelector('.bmn-email-entry'); if (emailEl) { emailEl.onmousedown = handleEvent(onMouseDownItem); emailEl.onclick = handleEvent(onClickEmailItem, account); emailEl.onmouseover = handleEvent(onMouseOverEmailItem, account); } listBMNEl.appendChild(itemBMNEl); }); } else { var itemBMNNoLoginsFoundEl = document.createElement('li'); itemBMNNoLoginsFoundEl.classList.add('bmn-no-logins-found'); itemBMNNoLoginsFoundEl.innerHTML = '未找到共享账号'; listBMNEl.appendChild(itemBMNNoLoginsFoundEl); } } function closeOnClickOutside(event) { if (listBMNEl && !listBMNEl.contains(event.target) && !event.target.closest('.bmn-floating-button')) { hideListBMNEl(); } } function showListBMNEl() { if (listBMNEl) { listBMNEl.classList.add('show'); document.addEventListener('mousedown', closeOnClickOutside, true); } } function hideListBMNEl() { if (listBMNEl) { listBMNEl.classList.remove('show'); document.removeEventListener('mousedown', closeOnClickOutside, true); } } var enableMouseOut = true; function setValueInputItem(inputUsernameEl, inputPasswordEl, username, password, isInputSimulate) { setValueInput(inputUsernameEl, username, isInputSimulate); setValueInput(inputPasswordEl, password, isInputSimulate); } function onMouseDownItem(event) { event.stopPropagation(); event.preventDefault(); } function onClickItem(event, account) { event.stopPropagation(); enableMouseOut = false; if (inputUsernameCurrentEl && inputPasswordCurrentEl) { setValueInputItem(inputUsernameCurrentEl, inputPasswordCurrentEl, account.username, account.password, true); inputUsernameCurrentEl.setAttribute('value', account.username); hideListBMNEl(); } } function onClickEmailItem(event, account) { event.stopPropagation(); enableMouseOut = false; if (inputUsernameCurrentEl && inputPasswordCurrentEl) { setValueInputItem(inputUsernameCurrentEl, inputPasswordCurrentEl, account.email, account.password, true); inputUsernameCurrentEl.setAttribute('value', account.email); hideListBMNEl(); } } function onMouseOverItem(event, account) { if (inputUsernameCurrentEl && inputPasswordCurrentEl) { setValueInputItem(inputUsernameCurrentEl, inputPasswordCurrentEl, account.username, account.password); } } function onMouseOverEmailItem(event, account) { event.stopPropagation(); if (inputUsernameCurrentEl && inputPasswordCurrentEl) { setValueInputItem(inputUsernameCurrentEl, inputPasswordCurrentEl, account.email, account.password); } } function onMouseOutItem(event) { if (!enableMouseOut) { enableMouseOut = true; return; } if (inputUsernameCurrentEl && inputPasswordCurrentEl) { setValueInputItem(inputUsernameCurrentEl, inputPasswordCurrentEl, '', ''); } } function getClassSuccess(success) { if (success > 91) return 'bmn-success-100'; else if (success > 81) return 'bmn-success-90'; else if (success > 71) return 'bmn-success-80'; else if (success > 61) return 'bmn-success-70'; else if (success > 51) return 'bmn-success-60'; else if (success > 31) return 'bmn-success-50'; else if (success > 21) return 'bmn-success-30'; else if (success > 11) return 'bmn-success-20'; else return 'bmn-success-10'; } function addStyleListBMNEl(inputEl) { if (!listBMNEl) return; const offsetTarget = getOffset(inputEl); const windowHeight = document.documentElement.clientHeight; const windowWidth = document.documentElement.clientWidth; const listWidth = listBMNEl.offsetWidth || 300; const gap = 5; listBMNEl.style.top = offsetTarget.top + 'px'; listBMNEl.style.bottom = ''; listBMNEl.style.maxHeight = (windowHeight - offsetTarget.top - 10) + 'px'; const spaceOnRight = windowWidth - offsetTarget.right; const spaceOnLeft = offsetTarget.left; if (spaceOnRight >= listWidth + gap) { listBMNEl.style.left = (offsetTarget.right + gap) + 'px'; listBMNEl.style.right = ''; } else if (spaceOnLeft >= listWidth + gap) { listBMNEl.style.left = (offsetTarget.left - listWidth - gap) + 'px'; listBMNEl.style.right = ''; } else { listBMNEl.style.right = gap + 'px'; listBMNEl.style.left = ''; } } function updateButtonPosition(inputEl, button) { if (!inputEl || !button || !document.body.contains(inputEl)) { if (button) button.style.display = 'none'; return; } const rect = getOffset(inputEl); const buttonSize = 24; const rightMargin = 10; button.style.top = (rect.top + (rect.height - buttonSize) / 2) + 'px'; button.style.left = (rect.right - buttonSize - rightMargin) + 'px'; if (rect.width > 0 && rect.height > 0 && isVisible(inputEl)) { button.style.display = 'flex'; } else { button.style.display = 'none'; } } function updateAllButtonPositions() { buttonMap.forEach((button, inputEl) => { updateButtonPosition(inputEl, button); }); } function onButtonClick(event, data) { event.preventDefault(); event.stopPropagation(); if (listBMNEl && listBMNEl.classList.contains('show')) { hideListBMNEl(); return; } inputUsernameCurrentEl = data.inputUsernameEl; inputPasswordCurrentEl = data.inputPasswordEl; initListContainer(); addStyleListBMNEl(inputUsernameCurrentEl); if (dataFetched) { populateList(); showListBMNEl(); addStyleListBMNEl(inputUsernameCurrentEl); } else { fetchData(() => { showListBMNEl(); addStyleListBMNEl(inputUsernameCurrentEl); }); } } function onInputInput(event) { enableMouseOut = false; hideListBMNEl(); } function onInputFocus(event, data) { const button = data.button; if (button) { button.style.opacity = '0.8'; } } function onInputBlur(event, data) { const button = data.button; if (button) { button.style.opacity = '0.5'; } } function isVisible(el) { return !!(el && (el.offsetWidth || el.offsetHeight || el.getClientRects().length)); } function isValidUsernameInput(el) { if (!el || !(el instanceof Element) || el.dataset.bmnChecked) { return false; } const isPassword = el.type === 'password'; const isInput = el.tagName.toLowerCase() === 'input'; const isValidType = ['text', 'email', 'tel', 'url', 'number', undefined, ''].includes(el.type); return isInput && !isPassword && isValidType && isVisible(el); } function attachButton(inputUsernameEl, inputPasswordEl) { inputUsernameEl.dataset.bmnChecked = true; inputPasswordEl.dataset.bmnChecked = true; const data = { inputUsernameEl: inputUsernameEl, inputPasswordEl: inputPasswordEl }; const button = document.createElement('button'); button.className = 'bmn-floating-button'; button.type = 'button'; button.title = '获取共享账号'; button.innerHTML = icons.mail; data.button = button; button.onclick = handleEvent(onButtonClick, data); document.body.appendChild(button); buttonMap.set(inputUsernameEl, button); updateButtonPosition(inputUsernameEl, button); inputUsernameEl.oninput = handleEvent(onInputInput); inputUsernameEl.onfocus = handleEvent(onInputFocus, data); inputUsernameEl.onblur = handleEvent(onInputBlur, data); const resizeObserver = new ResizeObserver(() => { updateButtonPosition(inputUsernameEl, button); }); resizeObserver.observe(inputUsernameEl); const cleanupObserver = new MutationObserver((mutations) => { if (!document.body.contains(inputUsernameEl)) { button.remove(); buttonMap.delete(inputUsernameEl); resizeObserver.disconnect(); cleanupObserver.disconnect(); } }); cleanupObserver.observe(document.body, { childList: true, subtree: true }); } function checkAndEventToInput() { const passwordInputs = document.querySelectorAll('input[type=password]:not([data-bmn-checked])'); if (passwordInputs.length === 0) return; const allPotentialInputs = Array.from(document.querySelectorAll( 'input:not([type]), input[type=text], input[type=email], input[type=tel], input[type=password]' )); passwordInputs.forEach(passwordInput => { if (!isVisible(passwordInput)) return; let foundUsernameInput = null; let siblingCandidate = passwordInput.previousElementSibling; for (let i = 0; i < 3 && siblingCandidate; i++) { if (isValidUsernameInput(siblingCandidate)) { foundUsernameInput = siblingCandidate; break; } siblingCandidate = siblingCandidate.previousElementSibling; } if (foundUsernameInput) { attachButton(foundUsernameInput, passwordInput); return; } const passwordDomIndex = allPotentialInputs.indexOf(passwordInput); if (passwordDomIndex > 0) { for (let i = passwordDomIndex - 1; i >= 0; i--) { const globalCandidate = allPotentialInputs[i]; if (isValidUsernameInput(globalCandidate)) { foundUsernameInput = globalCandidate; break; } } } if (foundUsernameInput) { attachButton(foundUsernameInput, passwordInput); } }); } // --- 启动与监视 --- function initialScan() { checkAndEventToInput(); setTimeout(checkAndEventToInput, 500); } if (document.readyState === 'complete') { initialScan(); } else { window.addEventListener('load', initialScan); } const debouncedUpdateAllPositions = debounce(updateAllButtonPositions, 150); window.addEventListener('scroll', debouncedUpdateAllPositions, true); window.addEventListener('resize', debouncedUpdateAllPositions); const observer = new MutationObserver(() => { checkAndEventToInput(); debouncedUpdateAllPositions(); }); observer.observe(document.body, { childList: true, subtree: true, attributes: true }); })();