Skip to content

Instantly share code, notes, and snippets.

@cikichen
Last active April 30, 2024 03:02
Show Gist options
  • Save cikichen/f3bee8ab777ad8f4bd348f88b1868e2f to your computer and use it in GitHub Desktop.
Save cikichen/f3bee8ab777ad8f4bd348f88b1868e2f to your computer and use it in GitHub Desktop.
// ==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