// ==UserScript==
// @name 通用自动填充助手(按需版3.0)
// @namespace http://tampermonkey.net/
// @version 3.0
// @description 智能填充各种网站的邮箱和密码字段,按需在特定网站激活,持久化保存激活状态
// @author yaya
// @match *://*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @icon https://cdn-icons-png.flaticon.com/512/2977/2977425.png
// ==/UserScript==
(function() {
'use strict';
// ==============================
// 配置中心 - 在这里添加新网站配置
// ==============================
const siteConfigs = [
// 港英云配置
{
name: '港英云',
urlPattern: /港英云/,
fields: {
email: {
selector: 'input[placeholder="邮箱"]',
events: ['input', 'change', 'blur', 'keydown', 'keyup']
},
password: {
selector: 'input[placeholder="密码"][type="password"]',
events: ['input', 'change', 'blur', 'keydown', 'keyup']
}
},
loginButton: 'button.n-button--primary-type'
},
// 通用配置 (作为后备)
{
name: '通用配置',
urlPattern: /.*/,
fields: {
email: {
selector: 'input[type="email"], input[id*="email"], input[name*="email"], input[placeholder*="邮箱"]',
events: ['input', 'change']
},
password: {
selector: 'input[type="password"], input[id*="password"], input[name*="password"], input[placeholder*="密码"]',
events: ['input', 'change']
}
},
loginButton: 'button[type="submit"], #login-btn, .login-button'
}
];
// ==============================
// 用户信息
// ==============================
const USER_EMAIL = GM_getValue('user_email', '[email protected]');
const USER_PASSWORD = GM_getValue('user_password', 'xxx');
// ==============================
// 持久化激活的网站列表
// ==============================
let activatedSites = GM_getValue('activatedSites', []);
// **检查当前网站是否已激活**
function isSiteActivated() {
const currentDomain = location.hostname;
return activatedSites.includes(currentDomain);
}
// **添加当前网站到激活列表**
function activateSite() {
const currentDomain = location.hostname;
if (!activatedSites.includes(currentDomain)) {
activatedSites.push(currentDomain);
GM_setValue('activatedSites', activatedSites);
console.log(`已激活网站: ${currentDomain}`);
}
}
// ==============================
// 核心功能
// ==============================
// **增强填充函数** - 填充输入框并触发事件
function enhancedFillInput(selector, value, events = ['input', 'change']) {
let filled = false;
try {
const inputs = document.querySelectorAll(selector);
if (inputs.length > 0) {
inputs.forEach(input => {
input.value = value;
events.forEach(eventType => {
const event = new Event(eventType, { bubbles: true, cancelable: true });
input.dispatchEvent(event);
});
console.log(`填充成功: ${selector}`, value);
filled = true;
});
}
} catch (e) {
console.error(`填充错误: ${selector}`, e);
}
return filled;
}
// **获取当前网站配置** - 优先匹配特定配置,否则使用通用配置
function getCurrentSiteConfig() {
const specificConfig = siteConfigs.find(config =>
config.urlPattern.test(document.title) ||
config.urlPattern.test(location.href)
);
if (specificConfig && specificConfig.name !== '通用配置') {
return specificConfig;
}
return siteConfigs.find(config => config.name === '通用配置');
}
// **自动填充主函数** - 执行填充并尝试登录
function autoFill() {
const config = getCurrentSiteConfig();
if (!config) return {success: false, message: '未找到匹配的网站配置'};
let results = {
email: false,
password: false,
configName: config.name
};
if (config.fields.email) {
results.email = enhancedFillInput(
config.fields.email.selector,
USER_EMAIL,
config.fields.email.events
);
}
if (config.fields.password) {
results.password = enhancedFillInput(
config.fields.password.selector,
USER_PASSWORD,
config.fields.password.events
);
}
if (config.loginButton && results.email && results.password) {
setTimeout(() => {
const loginBtn = document.querySelector(config.loginButton);
if (loginBtn) {
loginBtn.click();
console.log('已尝试点击登录按钮');
}
}, 800);
}
return results;
}
// **创建控制面板**
function createControlPanel() {
const panel = document.createElement('div');
panel.id = 'universal-fill-panel';
panel.style = `
position: fixed;
bottom: 20px;
right: 20px;
background: white;
border: 1px solid #e1e1e1;
border-radius: 8px;
padding: 10px 15px;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
z-index: 99999;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
min-width: 120px;
max-width: 180px;
transition: all 0.3s;
`;
panel.innerHTML = `
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
<h3 style="margin:0; font-size: 14px; color: #2c3e50; font-weight: 500;">
<span style="background: #3498db; color: white; border-radius: 3px; padding: 1px 4px; font-size: 12px;">填充助手</span>
</h3>
<button id="close-panel" style="background: none; border: none; font-size: 16px; cursor: pointer; color: #95a5a6; line-height: 1;">×</button>
</div>
<div style="display: flex; gap: 8px; margin-bottom: 8px;">
<button id="fill-btn" style="flex:1; background: #3498db; color: white; border: none; border-radius: 4px; padding: 6px; cursor: pointer; font-size: 12px; min-width: 60px;">
填充
</button>
<button id="add-config-btn" style="flex:1; background: #9b59b6; color: white; border: none; border-radius: 4px; padding: 6px; cursor: pointer; font-size: 12px; min-width: 60px;">
添加配置
</button>
</div>
<div style="font-size: 11px; color: #7f8c8d; margin-top: 5px; text-align: center;">
<span id="fill-status">就绪</span>
</div>
`;
document.body.appendChild(panel);
document.getElementById('close-panel').addEventListener('click', () => {
panel.style.display = 'none';
});
document.getElementById('fill-btn').addEventListener('click', () => {
updateStatus('填充中...', '#e67e22');
setTimeout(executeFill, 300);
});
document.getElementById('add-config-btn').addEventListener('click', showAddSiteGuide);
}
// **执行填充操作**
function executeFill() {
const statusEl = document.getElementById('fill-status');
try {
const results = autoFill();
if (results.email && results.password) {
updateStatus('填充成功!', '#27ae60');
} else {
let message = '部分填充: ';
if (!results.email) message += '邮箱 ';
if (!results.password) message += '密码 ';
updateStatus(message, '#e74c3c');
}
} catch (e) {
updateStatus(`错误: ${e.message}`, '#e74c3c');
console.error('填充错误:', e);
}
}
// **更新状态显示**
function updateStatus(message, color = '#34495e') {
const statusEl = document.getElementById('fill-status');
if (statusEl) {
statusEl.textContent = message;
statusEl.style.color = color;
}
}
// **显示添加新网站指南**
function showAddSiteGuide() {
const panel = document.getElementById('universal-fill-panel');
panel.innerHTML = `
<div style="margin-bottom: 10px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<h3 style="margin:0; font-size: 14px; color: #2c3e50;">
✏️ 添加新配置
</h3>
<button id="back-btn" style="background: none; border: none; font-size: 16px; cursor: pointer; color: #95a5a6; line-height: 1;">←</button>
</div>
<div style="font-size: 11px; color: #34495e; line-height: 1.4; margin-bottom: 10px;">
1. 按 <strong>F12</strong> 打开开发者工具<br>
2. 使用选择器工具查找字段<br>
3. 右键元素 → 复制选择器
</div>
<div style="font-size: 11px; margin-bottom: 5px;">
<strong>配置模板:</strong>
</div>
<textarea id="config-template" style="width: 100%; height: 160px; font-family: monospace; font-size: 11px; padding: 6px; border-radius: 4px; border: 1px solid #ddd; resize: vertical;">
{
name: '网站名称',
urlPattern: /网站URL特征/,
fields: {
email: { selector: '...' },
password: { selector: '...' }
},
loginButton: '...'
}</textarea>
<div style="display: flex; gap: 6px; margin-top: 8px;">
<button id="copy-config-btn" style="flex:1; background: #9b59b6; color: white; border: none; border-radius: 4px; padding: 6px; cursor: pointer; font-size: 11px;">
复制模板
</button>
</div>
</div>
`;
document.getElementById('back-btn').addEventListener('click', () => {
panel.innerHTML = '';
createControlPanel();
});
document.getElementById('copy-config-btn').addEventListener('click', () => {
const textarea = document.getElementById('config-template');
textarea.select();
document.execCommand('copy');
alert('配置模板已复制到剪贴板');
});
}
// **注册Tampermonkey菜单命令**
GM_registerMenuCommand('激活填充助手', () => {
if (document.getElementById('universal-fill-panel')) {
alert('填充助手已在当前网站激活');
return;
}
activateSite();
createControlPanel();
alert('填充助手已激活并保存');
});
GM_registerMenuCommand('取消激活当前网站', () => {
const currentDomain = location.hostname;
if (!activatedSites.includes(currentDomain)) {
alert('当前网站未激活填充助手');
return;
}
activatedSites = activatedSites.filter(site => site !== currentDomain);
GM_setValue('activatedSites', activatedSites);
const panel = document.getElementById('universal-fill-panel');
if (panel) {
panel.remove();
}
alert(`已取消激活 ${currentDomain}`);
});
GM_registerMenuCommand('设置邮箱', () => {
const newEmail = prompt('请输入邮箱:', USER_EMAIL);
if (newEmail) {
GM_setValue('user_email', newEmail);
alert('邮箱已更新!');
}
});
GM_registerMenuCommand('设置密码', () => {
const newPassword = prompt('请输入密码:', USER_PASSWORD);
if (newPassword) {
GM_setValue('user_password', newPassword);
alert('密码已更新!');
}
});
// **初始化**
window.addEventListener('load', () => {
if (isSiteActivated()) {
setTimeout(() => {
if (!document.getElementById('universal-fill-panel')) {
createControlPanel();
}
}, 1500);
} else {
console.log('填充助手未激活,请通过Tampermonkey菜单激活');
}
});
})();