// ==UserScript==
// @name YAD Multiple Auto Clicker
// @namespace https://greasyfork.org/en/users/781396
// @version 2.7
// @description Automates clicks at various locations on the screen with customizable intervals
// @author YAD
// @license MIT
// @icon https://i.ibb.co/z7JVjSp/image.png
// @match *://*/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
let buttons = [];
let buttonId = 1;
let isRunning = false;
let clickIntervals = [];
// Load button positions and settings from localStorage
const loadButtonData = () => JSON.parse(localStorage.getItem('buttonData') || '[]');
// Save button positions and settings to localStorage
const saveButtonData = () => {
const buttonData = buttons.map(button => ({
id: button.id,
top: button.style.top,
left: button.style.left,
interval: button.dataset.interval,
clicks: button.dataset.clicks
}));
localStorage.setItem('buttonData', JSON.stringify(buttonData));
};
// Save the current running state in localStorage
const saveRunningState = () => {
localStorage.setItem('isRunning', JSON.stringify(isRunning));
};
// Load the running state from localStorage on page reload
const loadRunningState = () => {
return JSON.parse(localStorage.getItem('isRunning') || 'false');
};
// Create the main interface
const mainInterface = document.createElement('div');
mainInterface.style.position = 'fixed';
mainInterface.style.right = '10px';
mainInterface.style.top = '50%';
mainInterface.style.transform = 'translateY(-50%)';
mainInterface.style.zIndex = '9999';
// Plus button to add new auto-click buttons
const plusButton = document.createElement('button');
plusButton.textContent = '➕';
plusButton.style.display = 'block';
plusButton.style.padding = '10px';
plusButton.style.marginBottom = '5px';
plusButton.style.fontSize = '16px';
plusButton.style.cursor = 'pointer';
plusButton.style.backgroundColor = '#28a745'; // Green background
plusButton.style.border = 'none';
plusButton.style.color = 'transparent';
plusButton.style.textShadow = '0 0 0 white';
plusButton.style.borderRadius = '5px';
mainInterface.appendChild(plusButton);
// Start/Stop button
const startStopButton = document.createElement('button');
startStopButton.textContent = '👆';
startStopButton.style.display = 'block';
startStopButton.style.padding = '10px';
startStopButton.style.marginBottom = '5px';
startStopButton.style.fontSize = '16px';
startStopButton.style.cursor = 'pointer';
startStopButton.style.backgroundColor = '#007bff'; // Blue background
startStopButton.style.border = 'none';
startStopButton.style.color = 'white';
startStopButton.style.borderRadius = '5px';
mainInterface.appendChild(startStopButton);
// Reset button
const resetButton = document.createElement('button');
resetButton.textContent = '♻️';
resetButton.style.display = 'block';
resetButton.style.padding = '10px';
resetButton.style.fontSize = '16px';
resetButton.style.cursor = 'pointer';
resetButton.style.backgroundColor = '#dc3545'; // Red background
resetButton.style.border = 'none';
resetButton.style.color = 'transparent';
resetButton.style.textShadow = '0 0 0 white';
resetButton.style.borderRadius = '5px';
mainInterface.appendChild(resetButton);
document.body.appendChild(mainInterface);
// Plus button functionality
plusButton.addEventListener('click', () => {
createAutoClickButton();
});
// Start/Stop button functionality
startStopButton.addEventListener('click', () => {
isRunning = !isRunning;
saveRunningState();
if (isRunning) {
startStopButton.textContent = '🛑';
startAutoClick();
} else {
startStopButton.textContent = '👆';
stopAutoClick();
}
});
// Reset button functionality
resetButton.addEventListener('click', () => {
stopAutoClick(); // Ensure all running intervals are stopped
buttons.forEach(button => button.remove());
buttons = [];
localStorage.removeItem('buttonData');
buttonId = 1;
startStopButton.textContent = '👆';
saveRunningState();
});
// Function to create a new auto-click button
function createAutoClickButton(buttonData = null) {
const autoButton = document.createElement('div');
autoButton.id = buttonId++;
autoButton.textContent = autoButton.id;
autoButton.style.width = '50px';
autoButton.style.height = '50px';
autoButton.style.borderRadius = '50%';
autoButton.style.backgroundColor = '#0061ffcc';
autoButton.style.position = 'absolute';
autoButton.style.top = buttonData?.top || '50%';
autoButton.style.left = buttonData?.left || '50%';
autoButton.style.display = 'flex';
autoButton.style.alignItems = 'center';
autoButton.style.justifyContent = 'center';
autoButton.style.cursor = 'pointer';
autoButton.style.zIndex = '9999';
autoButton.style.color = 'white'; // Ensure text is visible
autoButton.dataset.interval = buttonData?.interval || 1000; // Default interval
autoButton.dataset.clicks = buttonData?.clicks || 1; // Default number of clicks
document.body.appendChild(autoButton);
makeDraggable(autoButton);
buttons.push(autoButton);
saveButtonData();
// Open settings modal on right-click
autoButton.addEventListener('contextmenu', (e) => {
e.preventDefault();
openSettingsModal(autoButton);
});
}
// Function to make the buttons draggable
function makeDraggable(element) {
let posX = 0, posY = 0, mouseX = 0, mouseY = 0;
element.onmousedown = function (e) {
e.preventDefault();
mouseX = e.clientX;
mouseY = e.clientY;
document.onmousemove = moveElement;
document.onmouseup = stopMovingElement;
};
function moveElement(e) {
posX = mouseX - e.clientX;
posY = mouseY - e.clientY;
mouseX = e.clientX;
mouseY = e.clientY;
element.style.top = (element.offsetTop - posY) + 'px';
element.style.left = (element.offsetLeft - posX) + 'px';
}
function stopMovingElement() {
document.onmouseup = null;
document.onmousemove = null;
saveButtonData();
}
}
// Function to open settings modal
function openSettingsModal(button) {
const modal = document.createElement('div');
modal.style.position = 'fixed';
modal.style.top = '50%';
modal.style.left = '50%';
modal.style.transform = 'translate(-50%, -50%)';
modal.style.zIndex = '10000';
modal.style.padding = '15px';
modal.style.backgroundColor = '#6f42c1';
modal.style.borderRadius = '8px';
modal.style.boxShadow = '0px 4px 12px rgba(0, 0, 0, 0.1)';
modal.style.width = '300px'; // Make it more compact
modal.style.fontFamily = 'Arial, sans-serif';
const title = document.createElement('h3');
title.textContent = 'Settings';
title.style.marginTop = '0';
title.style.marginBottom = '15px';
title.style.color = '#fff';
title.style.textAlign = 'center';
title.style.fontSize = '18px';
modal.appendChild(title);
const form = document.createElement('form');
form.style.display = 'flex';
form.style.flexDirection = 'column';
form.style.gap = '10px';
modal.appendChild(form);
const createInputField = (labelText, inputType, inputValue) => {
const fieldWrapper = document.createElement('div');
fieldWrapper.style.display = 'flex';
fieldWrapper.style.flexDirection = 'column';
const label = document.createElement('label');
label.textContent = labelText;
label.style.fontSize = '14px';
label.style.color = '#fff';
label.style.marginBottom = '5px';
fieldWrapper.appendChild(label);
const input = document.createElement('input');
input.type = inputType;
input.value = inputValue;
input.style.padding = '5px';
input.style.borderRadius = '4px';
input.style.border = '1px solid #ccc';
input.style.fontSize = '14px';
fieldWrapper.appendChild(input);
form.appendChild(fieldWrapper);
return input;
};
const intervalInput = createInputField('Interval (ms):', 'number', button.dataset.interval);
const clicksInput = createInputField('Clicks per Interval:', 'number', button.dataset.clicks);
const saveButton = document.createElement('button');
saveButton.textContent = 'Save';
saveButton.style.padding = '10px';
saveButton.style.borderRadius = '5px';
saveButton.style.border = 'none';
saveButton.style.backgroundColor = '#28a745';
saveButton.style.color = 'white';
saveButton.style.cursor = 'pointer';
form.appendChild(saveButton);
saveButton.addEventListener('click', (e) => {
e.preventDefault();
button.dataset.interval = intervalInput.value;
button.dataset.clicks = clicksInput.value;
saveButtonData();
document.body.removeChild(modal);
});
const cancelButton = document.createElement('button');
cancelButton.textContent = 'Cancel';
cancelButton.style.padding = '10px';
cancelButton.style.borderRadius = '5px';
cancelButton.style.border = 'none';
cancelButton.style.backgroundColor = '#dc3545';
cancelButton.style.color = 'white';
cancelButton.style.cursor = 'pointer';
form.appendChild(cancelButton);
cancelButton.addEventListener('click', (e) => {
e.preventDefault();
document.body.removeChild(modal);
});
document.body.appendChild(modal);
}
// Function to simulate real auto-clicks on elements, including canvases
function autoClick(button) {
const rect = button.getBoundingClientRect();
button.style.visibility = 'hidden';
// If there's a canvas, click based on coordinates
const elemUnderButton = document.elementFromPoint(
rect.left + rect.width / 2,
rect.top + rect.height / 2
);
button.style.visibility = 'visible';
if (elemUnderButton.tagName === 'CANVAS') {
const canvas = elemUnderButton;
const ctx = canvas.getContext('2d');
if (ctx) {
const canvasClickEvent = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window,
clientX: rect.left + rect.width / 2,
clientY: rect.top + rect.height / 2,
});
canvas.dispatchEvent(canvasClickEvent);
}
} else if (elemUnderButton) {
const interval = button.dataset.interval ? parseInt(button.dataset.interval) : 1000;
const clicks = button.dataset.clicks ? parseInt(button.dataset.clicks) : 1;
// Reduce opacity to indicate clicking
button.style.opacity = '0.6';
// Delay before the first click set
return new Promise(resolve => {
setTimeout(() => {
for (let i = 0; i < clicks; i++) {
simulateClick(elemUnderButton);
}
// Restore opacity after the clicks
button.style.opacity = '1';
resolve(); // Resolve the promise when done
}, interval);
});
}
}
// Function to simulate clicks, including handling iframes and shadow DOMs
function simulateClick(target) {
const eventNames = ['mousedown', 'mouseup', 'click'];
eventNames.forEach(eventName => {
const event = new MouseEvent(eventName, {
bubbles: true,
cancelable: true,
view: window
});
target.dispatchEvent(event);
});
// Handle iframes
if (target.tagName === 'IFRAME') {
const iframeDoc = target.contentDocument || target.contentWindow.document;
const clickableElement = iframeDoc.querySelector('selector'); // Update this selector for specific iframe content
clickableElement?.click();
}
// Handle Shadow DOM
if (target.shadowRoot) {
const clickableElement = target.shadowRoot.querySelector('selector'); // Update this selector for Shadow DOM
clickableElement?.click();
}
}
// Start auto-clicking in sequence
async function startAutoClick() {
for (const button of buttons) {
const interval = parseInt(button.dataset.interval);
await autoClick(button); // Wait for the current button to finish before starting the next
}
if (isRunning) {
setTimeout(startAutoClick, 0); // Wait 500ms before starting the next sequence if still running
}
}
// Stop auto-clicking
function stopAutoClick() {
isRunning = false;
}
// Load buttons and state on page load
window.addEventListener('load', () => {
loadButtonData().forEach(buttonData => createAutoClickButton(buttonData));
if (loadRunningState()) {
isRunning = true;
startStopButton.textContent = '🛑';
startAutoClick();
}
});
})();