Last active
April 30, 2024 03:02
-
-
Save cikichen/f3bee8ab777ad8f4bd348f88b1868e2f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name 多账号自动登录脚本 | |
// @namespace http://tampermonkey.net/ | |
// @version 1.1 | |
// @description 自动登录多个账户并登出 | |
// @author Linux.do | |
// @match https://linux.do/* | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=linux.do | |
// @grant GM_setValue | |
// @grant GM_getValue | |
// @grant GM_registerMenuCommand | |
// ==/UserScript== | |
(function () { | |
'use strict'; | |
// 初始化账号信息和脚本启动状态 | |
let accounts = GM_getValue('accounts', []); | |
let scriptEnabled = GM_getValue('scriptEnabled', false); | |
// 添加菜单命令以打开配置界面和切换脚本启动状态 | |
GM_registerMenuCommand('配置账号', openConfig); | |
GM_registerMenuCommand('启动/停止脚本', toggleScript); | |
// 显示消息并在一段时间后自动消失 | |
function showMessage(message, timeout = 3000) { | |
let messageDiv = document.createElement('div'); | |
messageDiv.textContent = message; | |
messageDiv.style.position = 'fixed'; | |
messageDiv.style.top = '10px'; | |
messageDiv.style.left = '10px'; | |
messageDiv.style.zIndex = '9999'; | |
messageDiv.style.background = 'white'; | |
messageDiv.style.padding = '10px'; | |
messageDiv.style.border = '1px solid black'; | |
messageDiv.style.borderRadius = '5px'; | |
document.body.appendChild(messageDiv); | |
setTimeout(() => { | |
document.body.removeChild(messageDiv); | |
}, timeout); | |
} | |
// 切换脚本启动状态 | |
function toggleScript() { | |
scriptEnabled = !scriptEnabled; | |
GM_setValue('scriptEnabled', scriptEnabled); | |
showMessage('脚本现在' + (scriptEnabled ? '启动' : '停止') + '。'); | |
if (scriptEnabled) { | |
GM_setValue('shouldRunMain', true); // 设置标志,指示需要运行main函数 | |
main(); // 启动主函数 | |
} else { | |
GM_setValue('shouldRunMain', false); // 清除标志 | |
} | |
} | |
// 打开配置界面 | |
function openConfig() { | |
let configHtml = ` | |
<div id="tm-config" style="position: fixed; top: 20px; left: 20px; z-index: 9999; background: white; padding: 10px; border: 1px solid black;"> | |
<h2>账号配置</h2> | |
<div id="tm-accounts"></div> | |
<button id="tm-add-account">添加账号</button> | |
<button id="tm-save-config">保存配置</button> | |
</div> | |
`; | |
document.body.insertAdjacentHTML('beforeend', configHtml); | |
// 显示已保存的账号信息 | |
accounts.forEach((account, index) => { | |
addAccountFields(index, account.username, account.password); | |
}); | |
// 绑定添加账号事件 | |
document.getElementById('tm-add-account').addEventListener('click', () => { | |
addAccountFields(accounts.length); | |
}); | |
// 绑定保存配置事件 | |
document.getElementById('tm-save-config').addEventListener('click', saveConfig); | |
} | |
// 添加账号输入字段 | |
function addAccountFields(index, username = '', password = '') { | |
let accountHtml = ` | |
<div class="tm-account" data-index="${index}"> | |
用户名:<input type="text" class="tm-username" value="${username}"> | |
密码:<input type="password" class="tm-password" value="${password}"> | |
<button class="tm-remove-account">移除</button> | |
</div> | |
`; | |
document.getElementById('tm-accounts').insertAdjacentHTML('beforeend', accountHtml); | |
// 绑定移除账号事件 | |
let removeButtons = document.getElementsByClassName('tm-remove-account'); | |
let lastButton = removeButtons[removeButtons.length - 1]; | |
lastButton.addEventListener('click', function () { | |
this.parentElement.remove(); | |
}); | |
} | |
// 保存配置 | |
function saveConfig() { | |
let accountDivs = document.getElementsByClassName('tm-account'); | |
accounts = Array.from(accountDivs).map(div => { | |
return { | |
username: div.querySelector('.tm-username').value, | |
password: div.querySelector('.tm-password').value | |
}; | |
}); | |
GM_setValue('accounts', accounts); | |
alert('配置已保存!'); | |
document.getElementById('tm-config').remove(); | |
} | |
// 检查是否已登录 | |
function isLoggedIn() { | |
return !document.querySelector('.widget-button.btn.btn-primary.btn-small.login-button.btn-icon-text'); | |
} | |
// 等待元素显示 | |
function waitForElement(selector, callback, checkVisibility = false, timeout = 5000) { | |
let start = Date.now(); | |
let interval = setInterval(() => { | |
let element = document.querySelector(selector); | |
let isVisible = element && (element.offsetParent !== null); | |
if (element && (!checkVisibility || isVisible)) { | |
clearInterval(interval); | |
callback(element); | |
} else if (Date.now() - start >= timeout) { // 超时处理 | |
clearInterval(interval); | |
console.error('等待元素超时: ', selector); | |
showMessage('操作超时,脚本停止。'); | |
GM_setValue('scriptEnabled', false); | |
} | |
}, 100); // 每100毫秒检查一次 | |
} | |
function login(account, callback) { | |
if (!isLoggedIn()) { | |
let loginButton = document.querySelector('.widget-button.btn.btn-primary.btn-small.login-button.btn-icon-text'); | |
if (loginButton) { | |
loginButton.click(); | |
waitForElement('#login-account-name', () => { | |
let usernameField = document.getElementById('login-account-name'); | |
let passwordField = document.getElementById('login-account-password'); | |
// 清空输入框的值 | |
usernameField.value = ''; | |
passwordField.value = ''; | |
// 使用setTimeout来确保输入框已被清空再填入新值 | |
setTimeout(() => { | |
// 重新填入用户名和密码 | |
usernameField.value = account.username; | |
passwordField.value = account.password; | |
// 触发input事件,以便页面脚本响应 | |
usernameField.dispatchEvent(new Event('input', { bubbles: true })); | |
passwordField.dispatchEvent(new Event('input', { bubbles: true })); | |
// 延迟点击登录按钮,以确保所有状态都已更新 | |
setTimeout(() => { | |
document.getElementById('login-button').click(); | |
// if (typeof callback === "function") { | |
// callback(); | |
// } | |
setTimeout(() => { | |
let alertElement = document.querySelector('#modal-alert.alert.alert-error'); | |
if (alertElement && alertElement.textContent.includes('请稍后再尝试登录。')) { | |
// 如果出现错误提示,等待500ms后再次点击登录按钮 | |
console.log('出现错误提示,正在重试登录...'); | |
setTimeout(() => { | |
document.getElementById('login-button').click(); | |
}, 500); // 等待500ms后再次尝试 | |
} else if (typeof callback === "function") { | |
// 如果没有错误提示,调用回调函数 | |
callback(); | |
} | |
}, 100); | |
}, 1000); // 延迟800毫秒点击登录按钮 | |
}, 200); // 确保输入框清空后稍作等待 | |
}); | |
} | |
} | |
} | |
// 登出账号 | |
function logout(callback) { | |
waitForElement('#current-user > button[aria-haspopup="true"]', (profileButton) => { | |
profileButton.click(); | |
waitForElement('a[id="user-menu-button-profile"]', (profileTab) => { | |
profileTab.click(); | |
waitForElement('li.logout button.profile-tab-btn', (logoutButton) => { | |
logoutButton.click(); | |
if (typeof callback === "function") { // 检查callback是否为函数 | |
callback(); | |
} | |
}); | |
}); | |
}); | |
} | |
// 主函数 | |
function main() { | |
// 如果脚本不应该运行,则直接返回 | |
if (!GM_getValue('shouldRunMain', false)) { | |
return; | |
} | |
console.log('开始处理账号'); | |
// 等待1秒后开始执行主函数的内容 | |
setTimeout(() => { | |
console.log('开始处理账号'); | |
let accountIndex = GM_getValue('accountIndex', 0); | |
if (scriptEnabled && accountIndex < accounts.length) { | |
// 检查是否已登录 | |
if (isLoggedIn()) { | |
console.log('已登录,准备登出'); | |
// 如果已登录,则先登出 | |
logout(() => { | |
// 登出后,重置账号索引并重新登录下一个账号 | |
let nextAccountIndex = (GM_getValue('accountIndex', 0) + 1) % accounts.length; | |
GM_setValue('accountIndex', nextAccountIndex); | |
// 监听DOMContentLoaded事件,等待页面加载完成后再继续处理下一个账号 | |
document.addEventListener('DOMContentLoaded', main); | |
}); | |
} else { | |
// 如果未登录,直接登录当前账号 | |
let account = accounts[accountIndex]; | |
console.log('准备登录账号:', account.username); | |
GM_setValue('currentAccount', account.username); | |
login(account, () => { // 提供一个函数作为回调 | |
GM_setValue('accountIndex', accountIndex + 1); | |
// 监听DOMContentLoaded事件,等待页面加载完成后再准备登出 | |
document.addEventListener('DOMContentLoaded', main); | |
}); | |
} | |
} else { | |
// 如果所有账号都处理完毕,可以在这里进行一些收尾工作 | |
console.log('所有账号处理完毕'); | |
GM_setValue('accountIndex', 0); // 重置账号索引,为下次执行做准备 | |
GM_setValue('shouldRunMain', false); // 清除执行标志 | |
GM_setValue('scriptEnabled', false); | |
showMessage('操作完成'); | |
} | |
}, 4000); // 设置延迟为4秒 | |
} | |
// 页面加载完成时调用main函数 | |
window.addEventListener('load', function () { | |
if (GM_getValue('shouldRunMain', false) && GM_getValue('scriptEnabled', false)) { | |
main(); | |
} | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment