您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Sends messages to multiple users
当前为
- // ==UserScript==
- // @name MZ - Message Sender
- // @namespace douglaskampl
- // @version 1.0
- // @description Sends messages to multiple users
- // @author Douglas
- // @match https://www.managerzone.com/?p=guestbook
- // @icon https://www.google.com/s2/favicons?sz=64&domain=managerzone.com
- // @grant GM_addStyle
- // @license MIT
- // @run-at document-idle
- // ==/UserScript==
- (function () {
- 'use strict';
- GM_addStyle(`
- .custom-button {
- margin-left: 10px;
- background-color: #74ACDF;
- color: white;
- position: relative;
- overflow: hidden;
- transition: all 0.3s ease;
- }
- .custom-button:hover {
- background-color: #6B9FD0;
- transform: translateY(-2px);
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
- }
- .custom-button:after {
- content: '';
- position: absolute;
- top: 0;
- left: -100%;
- width: 100%;
- height: 100%;
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
- transition: 0.5s;
- }
- .custom-button:hover:after {
- left: 100%;
- }
- .modal {
- display: none;
- position: fixed;
- z-index: 9999;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- overflow: auto;
- background-color: rgba(0, 0, 0, 0.7);
- opacity: 0;
- transition: opacity 0.3s ease;
- }
- .modal.show {
- opacity: 1;
- }
- .modal-content {
- background-color: #2E2E2E;
- color: #F5F5F5;
- margin: 15% auto;
- padding: 25px;
- border: 2px solid #F0F0F0;
- width: 80%;
- max-width: 600px;
- border-radius: 8px;
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
- transform: translateY(-50px);
- opacity: 0;
- transition: all 0.4s ease;
- }
- .modal.show .modal-content {
- transform: translateY(0);
- opacity: 1;
- }
- .modal-header {
- border-bottom: 3px solid #74ACDF;
- padding-bottom: 15px;
- margin-bottom: 20px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .modal-title {
- color: #F5F5F5;
- margin: 0;
- font-size: 22px;
- text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3);
- }
- .close {
- color: #F0F0F0;
- float: right;
- font-size: 28px;
- font-weight: bold;
- cursor: pointer;
- transition: color 0.2s ease;
- }
- .close:hover,
- .close:focus {
- color: #74ACDF;
- text-decoration: none;
- }
- .form-group {
- margin-bottom: 20px;
- }
- .form-group label {
- display: block;
- margin-bottom: 8px;
- font-weight: bold;
- color: #74ACDF;
- }
- .form-group input,
- .form-group textarea {
- width: 100%;
- padding: 12px;
- background-color: #3D3D3D;
- color: #F5F5F5;
- border: 1px solid #555;
- border-radius: 6px;
- box-sizing: border-box;
- transition: all 0.3s ease;
- }
- .form-group input:focus,
- .form-group textarea:focus {
- outline: none;
- border-color: #74ACDF;
- box-shadow: 0 0 8px rgba(116, 172, 223, 0.5);
- }
- .form-group textarea {
- height: 120px;
- resize: vertical;
- }
- .send-button {
- background: linear-gradient(to right, #74ACDF, #85C2F5);
- color: white;
- padding: 12px 20px;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- font-weight: bold;
- letter-spacing: 0.5px;
- transition: all 0.3s ease;
- position: relative;
- overflow: hidden;
- }
- .send-button:hover {
- background: linear-gradient(to right, #85C2F5, #74ACDF);
- transform: translateY(-2px);
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
- }
- .send-button:after {
- content: '';
- position: absolute;
- top: 0;
- left: -100%;
- width: 100%;
- height: 100%;
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
- transition: 0.5s;
- }
- .send-button:hover:after {
- left: 100%;
- }
- .send-button:disabled {
- background: #555;
- cursor: not-allowed;
- transform: none;
- box-shadow: none;
- }
- .status-area {
- margin-top: 20px;
- padding: 15px;
- border: 1px solid #444;
- border-radius: 6px;
- max-height: 180px;
- overflow-y: auto;
- display: none;
- background-color: #222;
- transition: all 0.3s ease;
- }
- .status-area.show {
- display: block;
- animation: fadeIn 0.5s ease forwards;
- }
- .status-message {
- margin: 8px 0;
- padding: 5px 10px;
- border-radius: 4px;
- transition: opacity 0.3s ease;
- animation: slideIn 0.3s ease forwards;
- }
- @keyframes slideIn {
- from {
- opacity: 0;
- transform: translateY(-10px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
- }
- @keyframes fadeIn {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
- }
- .status-success {
- color: #7CFC00;
- background-color: rgba(124, 252, 0, 0.1);
- border-left: 3px solid #7CFC00;
- }
- .status-error {
- color: #FF6B6B;
- background-color: rgba(255, 107, 107, 0.1);
- border-left: 3px solid #FF6B6B;
- }
- .status-info {
- color: #74ACDF;
- background-color: rgba(116, 172, 223, 0.1);
- border-left: 3px solid #74ACDF;
- }
- .footer {
- margin-top: 20px;
- padding-top: 15px;
- border-top: 1px solid #444;
- text-align: center;
- color: #AAA;
- font-size: 12px;
- }
- .footer img {
- height: 20px;
- vertical-align: middle;
- margin-left: 5px;
- }
- .progress-bar {
- height: 4px;
- width: 0%;
- background: linear-gradient(to right, #74ACDF, #FCBF49);
- position: absolute;
- top: 0;
- left: 0;
- transition: width 0.5s ease;
- }
- .toggle-container {
- display: flex;
- justify-content: center;
- margin-bottom: 20px;
- background-color: #222;
- border-radius: 6px;
- padding: 4px;
- width: 100%;
- }
- .toggle-option {
- flex: 1;
- padding: 10px;
- text-align: center;
- cursor: pointer;
- border-radius: 4px;
- transition: all 0.3s ease;
- color: #AAA;
- }
- .toggle-option.active {
- background-color: #74ACDF;
- color: white;
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
- }
- .toggle-option:not(.active):hover {
- background-color: #333;
- color: #DDD;
- }
- .input-container {
- display: none;
- }
- .input-container.active {
- display: block;
- animation: fadeIn 0.3s ease;
- }
- `);
- window.addEventListener('load', function() {
- const postButton = document.getElementById('formpostbutton');
- if (!postButton) return;
- const sendMessagesButton = document.createElement('div');
- sendMessagesButton.style.display = 'inline-block';
- sendMessagesButton.innerHTML = `
- <a href="#" class="mzbtn button_account buttondiv custom-button" id="sendMessagesBtn">
- <span class="buttonClassMiddle"><span style="white-space: nowrap">Send Messages</span></span><span class="buttonClassRight"> </span>
- </a>
- `;
- postButton.parentNode.insertBefore(sendMessagesButton, postButton.nextSibling);
- const modal = document.createElement('div');
- modal.className = 'modal';
- modal.id = 'messageModal';
- modal.innerHTML = `
- <div class="modal-content">
- <div class="progress-bar" id="progressBar"></div>
- <div class="modal-header">
- <h2 class="modal-title">メッセージ送信者の翻訳</h2>
- <span class="close">×</span>
- </div>
- <div class="form-group">
- <label for="messageText">Message:</label>
- <textarea id="messageText" placeholder="Enter your message here"></textarea>
- </div>
- <div class="toggle-container">
- <div class="toggle-option active" data-target="users-input">Users</div>
- <div class="toggle-option" data-target="federation-input">Federation</div>
- </div>
- <div class="input-container active" id="users-input">
- <div class="form-group">
- <label for="usersInput">Usernames (comma separated):</label>
- <input type="text" id="usersInput" placeholder="user1, user2, user3">
- </div>
- </div>
- <div class="input-container" id="federation-input">
- <div class="form-group">
- <label for="federationId">Federation ID:</label>
- <input type="text" id="federationId" placeholder="Enter fid">
- </div>
- </div>
- <button id="sendButton" class="send-button">Send Messages</button>
- <div id="statusArea" class="status-area">
- <div id="statusMessages"></div>
- </div>
- <div class="footer">
- requested by gordola
- <svg width="18" height="12" viewBox="0 0 18 12" style="vertical-align: middle; margin-left: 5px;">
- <rect width="18" height="4" fill="#74ACDF" />
- <rect y="4" width="18" height="4" fill="#FFFFFF" />
- <rect y="8" width="18" height="4" fill="#74ACDF" />
- <circle cx="9" cy="6" r="1.5" fill="#FCBF49" />
- </svg>
- </div>
- </div>
- `;
- document.body.appendChild(modal);
- const toggleOptions = document.querySelectorAll('.toggle-option');
- toggleOptions.forEach(option => {
- option.addEventListener('click', function() {
- toggleOptions.forEach(opt => opt.classList.remove('active'));
- this.classList.add('active');
- const targetId = this.getAttribute('data-target');
- document.querySelectorAll('.input-container').forEach(container => {
- container.classList.remove('active');
- });
- document.getElementById(targetId).classList.add('active');
- });
- });
- document.getElementById('sendMessagesBtn').addEventListener('click', function(e) {
- e.preventDefault();
- const modalEl = document.getElementById('messageModal');
- modalEl.style.display = 'block';
- setTimeout(() => {
- modalEl.classList.add('show');
- }, 10);
- });
- document.querySelector('.close').addEventListener('click', function() {
- const modalEl = document.getElementById('messageModal');
- modalEl.classList.remove('show');
- setTimeout(() => {
- modalEl.style.display = 'none';
- }, 300);
- });
- window.addEventListener('click', function(event) {
- const modalEl = document.getElementById('messageModal');
- if (event.target === modalEl) {
- modalEl.classList.remove('show');
- setTimeout(() => {
- modalEl.style.display = 'none';
- }, 300);
- }
- });
- document.getElementById('sendButton').addEventListener('click', async function() {
- const message = document.getElementById('messageText').value.trim();
- if (!message) {
- alert('Please enter a message');
- return;
- }
- const statusArea = document.getElementById('statusArea');
- const statusMessages = document.getElementById('statusMessages');
- const progressBar = document.getElementById('progressBar');
- statusArea.classList.add('show');
- statusMessages.innerHTML = '';
- updateProgressBar(progressBar, 0);
- const activeMode = document.querySelector('.toggle-option.active').getAttribute('data-target');
- if (activeMode === 'users-input') {
- const usersText = document.getElementById('usersInput').value.trim();
- if (!usersText) {
- alert('Please enter at least one username');
- return;
- }
- const users = usersText.split(',').map(u => u.trim()).filter(u => u);
- if (users.length === 0) {
- alert('Please enter valid usernames');
- return;
- }
- const totalUsers = users.length;
- let processedUsers = 0;
- addStatus('Starting to send messages...', 'status-info');
- for (const username of users) {
- try {
- const userId = await getUserId(username);
- if (!userId) {
- addStatus(`Could not find user ID for ${username}`, 'status-error');
- continue;
- }
- addStatus(`Found user ID: ${userId}`, 'status-info');
- await sendMessage(userId, message);
- addStatus(`Message sent to ${username}`, 'status-success');
- processedUsers++;
- updateProgressBar(progressBar, (processedUsers / totalUsers) * 100);
- if (processedUsers < totalUsers) {
- addStatus(`Waiting 5 seconds before sending the next message...`, 'status-info');
- await new Promise(resolve => setTimeout(resolve, 5000));
- }
- } catch (error) {
- addStatus(`Error: ${error.message}`, 'status-error');
- }
- }
- updateProgressBar(progressBar, 100);
- addStatus('All messages have been sent!', 'status-success');
- } else {
- const federationId = document.getElementById('federationId').value.trim();
- if (!federationId) {
- alert('Please enter a federation ID');
- return;
- }
- if (!/^\d+$/.test(federationId)) {
- alert('Federation ID must be a number');
- return;
- }
- addStatus(`Starting to fetch federation members for federation ID: ${federationId}...`, 'status-info');
- try {
- const users = await getFederationMembers(federationId);
- if (users.length === 0) {
- addStatus('No users found in federation', 'status-error');
- return;
- }
- addStatus(`Found ${users.length} federation members`, 'status-info');
- if (!confirm(`You are about to send messages to ${users.length} users. Do you want to continue?`)) {
- addStatus('Operation cancelled by user', 'status-info');
- return;
- }
- const totalUsers = users.length;
- let processedUsers = 0;
- addStatus('Starting to send messages...', 'status-info');
- for (const username of users) {
- try {
- const userId = await getUserId(username);
- if (!userId) {
- addStatus(`Could not find user ID for ${username}`, 'status-error');
- continue;
- }
- addStatus(`Found user ID: ${userId}`, 'status-info');
- await sendMessage(userId, message);
- addStatus(`Message sent to ${username}`, 'status-success');
- processedUsers++;
- updateProgressBar(progressBar, (processedUsers / totalUsers) * 100);
- if (processedUsers < totalUsers) {
- addStatus(`Waiting 5 seconds before sending the next message...`, 'status-info');
- await new Promise(resolve => setTimeout(resolve, 5000));
- }
- } catch (error) {
- addStatus(`Error: ${error.message}`, 'status-error');
- }
- }
- updateProgressBar(progressBar, 100);
- addStatus('All messages have been sent!', 'status-success');
- } catch (error) {
- addStatus(`Error fetching federation members: ${error.message}`, 'status-error');
- }
- }
- });
- async function getFederationMembers(federationId) {
- const users = [];
- let offset = 0;
- let hasMoreMembers = true;
- while (hasMoreMembers) {
- addStatus(`Fetching federation members (offset: ${offset})...`, 'status-info');
- try {
- const url = `https://www.managerzone.com/ajax.php?p=federations&sub=federation_members&fid=${federationId}&offset=${offset}&sport=soccer`;
- const response = await fetch(url);
- const data = await response.json();
- if (!data || !data[0] || !data[0].length) {
- hasMoreMembers = false;
- break;
- }
- const newUsers = extractUsernames(data[0]);
- if (newUsers.length === 0) {
- hasMoreMembers = false;
- break;
- }
- users.push(...newUsers);
- addStatus(`Found ${newUsers.length} members at offset ${offset}`, 'status-info');
- hasMoreMembers = data[1] && data[1].includes(`offset=${offset + 10}`);
- offset += 10;
- await new Promise(resolve => setTimeout(resolve, 1000));
- } catch (error) {
- addStatus(`Error fetching members at offset ${offset}: ${error.message}`, 'status-error');
- hasMoreMembers = false;
- }
- }
- return [...new Set(users)];
- }
- function extractUsernames(html) {
- const regex = /\"(?:Epic|Legendary|Elite|Gold|Senior|\"|\s)*\s*([a-zA-Z0-9_-]+)<\/a>/g;
- const matches = [];
- let match;
- while ((match = regex.exec(html)) !== null) {
- if (match[1] && match[1].trim()) {
- matches.push(match[1].trim());
- }
- }
- const simpleRegex = /([a-zA-Z0-9_-]+)<\/a><\/span><\/td>/g;
- while ((match = simpleRegex.exec(html)) !== null) {
- if (match[1] && match[1].trim() && !matches.includes(match[1].trim())) {
- matches.push(match[1].trim());
- }
- }
- return matches;
- }
- function addStatus(message, className) {
- const statusMessages = document.getElementById('statusMessages');
- const messageElement = document.createElement('div');
- messageElement.className = `status-message ${className}`;
- messageElement.textContent = message;
- statusMessages.appendChild(messageElement);
- statusMessages.scrollTop = statusMessages.scrollHeight;
- }
- function updateProgressBar(progressBar, percentage) {
- progressBar.style.width = `${percentage}%`;
- }
- async function getUserId(username) {
- const response = await fetch(`https://www.managerzone.com/xml/manager_data.php?sport_id=1&username=${encodeURIComponent(username)}`);
- const text = await response.text();
- const parser = new DOMParser();
- const xmlDoc = parser.parseFromString(text, "text/xml");
- const userDataElement = xmlDoc.querySelector('UserData');
- if (userDataElement && userDataElement.hasAttribute('userId')) {
- return userDataElement.getAttribute('userId');
- }
- return null;
- }
- async function sendMessage(userId, message) {
- await fetch(`https://www.managerzone.com/ajax.php?p=messageBoard&sub=write&template=1&ident_id=${userId}&sport=soccer`, {
- method: 'POST',
- body: new URLSearchParams({
- 'msg': message
- }),
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
- 'X-Requested-With': 'XMLHttpRequest'
- }
- });
- return true;
- }
- });
- })();