Add script.js
This commit is contained in:
commit
ebd67e084d
404
script.js
Normal file
404
script.js
Normal file
@ -0,0 +1,404 @@
|
||||
// ==UserScript==
|
||||
// @name fuck-twitter
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 1.3
|
||||
// @match https://x.com/*
|
||||
// @grant none
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// Configuration
|
||||
const SCROLL_INCREMENT_MIN = 100; // Minimum scroll step in pixels
|
||||
const SCROLL_INCREMENT_MAX = 300; // Maximum scroll step in pixels
|
||||
const SCROLL_DELAY_MIN = 200; // Minimum delay between scroll steps in ms
|
||||
const SCROLL_DELAY_MAX = 500; // Maximum delay between scroll steps in ms
|
||||
const CLICK_DELAY_MIN = 500; // Minimum delay before clicking in ms
|
||||
const CLICK_DELAY_MAX = 1500; // Maximum delay before clicking in ms
|
||||
const RETWEET_CONFIRM_DELAY_MIN = 500; // Minimum delay before confirming retweet in ms
|
||||
const RETWEET_CONFIRM_DELAY_MAX = 1500; // Maximum delay before confirming retweet in ms
|
||||
|
||||
// State variables
|
||||
let isRunning = false;
|
||||
let isRetweetEnabled = false;
|
||||
let maxInteractions = 0; // 0 means unlimited
|
||||
let currentInteractions = 0;
|
||||
let speedScale = 1; // Default scale factor
|
||||
let scrollTimeout = null;
|
||||
let clickTimeout = null;
|
||||
let retweetConfirmTimeout = null;
|
||||
|
||||
// Create Control Panel
|
||||
const controlPanel = document.createElement('div');
|
||||
controlPanel.style.position = 'fixed';
|
||||
controlPanel.style.bottom = '20px';
|
||||
controlPanel.style.right = '20px';
|
||||
controlPanel.style.padding = '15px';
|
||||
controlPanel.style.backgroundColor = 'rgba(255, 255, 255, 0.95)';
|
||||
controlPanel.style.border = '1px solid #ccc';
|
||||
controlPanel.style.borderRadius = '8px';
|
||||
controlPanel.style.zIndex = '1000';
|
||||
controlPanel.style.boxShadow = '0 2px 6px rgba(0,0,0,0.3)';
|
||||
controlPanel.style.fontFamily = 'Arial, sans-serif';
|
||||
controlPanel.style.fontSize = '14px';
|
||||
controlPanel.style.color = '#333';
|
||||
controlPanel.style.width = '250px';
|
||||
|
||||
// Create Start/Pause Button
|
||||
const toggleButton = document.createElement('button');
|
||||
toggleButton.innerText = 'Start Auto Like';
|
||||
toggleButton.style.marginBottom = '10px';
|
||||
toggleButton.style.padding = '8px 16px';
|
||||
toggleButton.style.backgroundColor = '#1DA1F2';
|
||||
toggleButton.style.color = '#fff';
|
||||
toggleButton.style.border = 'none';
|
||||
toggleButton.style.borderRadius = '4px';
|
||||
toggleButton.style.cursor = 'pointer';
|
||||
toggleButton.style.width = '100%';
|
||||
toggleButton.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';
|
||||
controlPanel.appendChild(toggleButton);
|
||||
|
||||
// Create Retweet Checkbox
|
||||
const retweetContainer = document.createElement('div');
|
||||
retweetContainer.style.display = 'flex';
|
||||
retweetContainer.style.alignItems = 'center';
|
||||
retweetContainer.style.marginTop = '10px';
|
||||
|
||||
const retweetCheckbox = document.createElement('input');
|
||||
retweetCheckbox.type = 'checkbox';
|
||||
retweetCheckbox.id = 'enableRetweet';
|
||||
retweetCheckbox.style.marginRight = '8px';
|
||||
|
||||
const retweetLabel = document.createElement('label');
|
||||
retweetLabel.htmlFor = 'enableRetweet';
|
||||
retweetLabel.innerText = 'Enable Retweeting';
|
||||
|
||||
retweetContainer.appendChild(retweetCheckbox);
|
||||
retweetContainer.appendChild(retweetLabel);
|
||||
controlPanel.appendChild(retweetContainer);
|
||||
|
||||
// Create Interaction Limit Input
|
||||
const interactionContainer = document.createElement('div');
|
||||
interactionContainer.style.marginTop = '10px';
|
||||
|
||||
const interactionLabel = document.createElement('label');
|
||||
interactionLabel.htmlFor = 'maxInteractions';
|
||||
interactionLabel.innerText = 'Max Interactions: ';
|
||||
interactionLabel.style.display = 'block';
|
||||
interactionLabel.style.marginBottom = '4px';
|
||||
|
||||
const interactionInput = document.createElement('input');
|
||||
interactionInput.type = 'number';
|
||||
interactionInput.id = 'maxInteractions';
|
||||
interactionInput.min = '0';
|
||||
interactionInput.placeholder = '0 for unlimited';
|
||||
interactionInput.style.width = '100%';
|
||||
interactionInput.style.padding = '6px';
|
||||
interactionInput.style.border = '1px solid #ccc';
|
||||
interactionInput.style.borderRadius = '4px';
|
||||
|
||||
interactionContainer.appendChild(interactionLabel);
|
||||
interactionContainer.appendChild(interactionInput);
|
||||
controlPanel.appendChild(interactionContainer);
|
||||
|
||||
// Create Interaction Counter Display
|
||||
const counterDisplay = document.createElement('div');
|
||||
counterDisplay.style.marginTop = '10px';
|
||||
counterDisplay.style.display = 'none'; // Hidden by default
|
||||
|
||||
const counterText = document.createElement('span');
|
||||
counterText.id = 'interactionCounter';
|
||||
counterText.innerText = 'Interactions: 0/0';
|
||||
counterDisplay.appendChild(counterText);
|
||||
controlPanel.appendChild(counterDisplay);
|
||||
|
||||
// Create Speed Scale Input
|
||||
const speedContainer = document.createElement('div');
|
||||
speedContainer.style.marginTop = '10px';
|
||||
|
||||
const speedLabel = document.createElement('label');
|
||||
speedLabel.htmlFor = 'speedScale';
|
||||
speedLabel.innerText = 'Speed Scale: ';
|
||||
speedLabel.style.display = 'block';
|
||||
speedLabel.style.marginBottom = '4px';
|
||||
|
||||
const speedInput = document.createElement('input');
|
||||
speedInput.type = 'number';
|
||||
speedInput.id = 'speedScale';
|
||||
speedInput.min = '0.5';
|
||||
speedInput.max = '3';
|
||||
speedInput.step = '0.1';
|
||||
speedInput.value = '1';
|
||||
speedInput.style.width = '100%';
|
||||
speedInput.style.padding = '6px';
|
||||
speedInput.style.border = '1px solid #ccc';
|
||||
speedInput.style.borderRadius = '4px';
|
||||
|
||||
speedContainer.appendChild(speedLabel);
|
||||
speedContainer.appendChild(speedInput);
|
||||
controlPanel.appendChild(speedContainer);
|
||||
|
||||
// Append the Control Panel to the Document Body
|
||||
document.body.appendChild(controlPanel);
|
||||
|
||||
// Event Listener for Toggle Button
|
||||
toggleButton.addEventListener('click', () => {
|
||||
isRunning = !isRunning;
|
||||
toggleButton.innerText = isRunning ? 'Pause Auto Like' : 'Start Auto Like';
|
||||
toggleButton.style.backgroundColor = isRunning ? '#e0245e' : '#1DA1F2';
|
||||
|
||||
if (isRunning) {
|
||||
// Retrieve and set maximum interactions
|
||||
const maxInput = parseInt(interactionInput.value, 10);
|
||||
maxInteractions = isNaN(maxInput) || maxInput < 0 ? 0 : maxInput;
|
||||
currentInteractions = 0;
|
||||
updateCounterDisplay();
|
||||
|
||||
// Show the counter display if maxInteractions is set
|
||||
if (maxInteractions > 0) {
|
||||
counterDisplay.style.display = 'block';
|
||||
counterText.innerText = `Interactions: ${currentInteractions}/${maxInteractions}`;
|
||||
} else {
|
||||
counterDisplay.style.display = 'none';
|
||||
}
|
||||
|
||||
// Retrieve and set speed scale
|
||||
const speedValue = parseFloat(speedInput.value);
|
||||
speedScale = isNaN(speedValue) || speedValue <= 0 ? 1 : speedValue;
|
||||
|
||||
startScrolling();
|
||||
} else {
|
||||
clearTimeout(scrollTimeout);
|
||||
clearTimeout(clickTimeout);
|
||||
clearTimeout(retweetConfirmTimeout);
|
||||
}
|
||||
});
|
||||
|
||||
// Event Listener for Retweet Checkbox
|
||||
retweetCheckbox.addEventListener('change', (e) => {
|
||||
isRetweetEnabled = e.target.checked;
|
||||
console.log('Retweeting Enabled:', isRetweetEnabled);
|
||||
});
|
||||
|
||||
// Event Listener for Speed Scale Input
|
||||
speedInput.addEventListener('change', (e) => {
|
||||
const speedValue = parseFloat(e.target.value);
|
||||
speedScale = isNaN(speedValue) || speedValue <= 0 ? 1 : speedValue;
|
||||
console.log('Speed Scale set to:', speedScale);
|
||||
});
|
||||
|
||||
// Utility function to get a random integer between min and max (inclusive), multiplied by speedScale
|
||||
function getRandomIntScaled(min, max) {
|
||||
const scaledMin = min * speedScale;
|
||||
const scaledMax = max * speedScale;
|
||||
return Math.floor(Math.random() * (scaledMax - scaledMin + 1)) + scaledMin;
|
||||
}
|
||||
|
||||
// Function to update the interaction counter display
|
||||
function updateCounterDisplay() {
|
||||
counterText.innerText = `Interactions: ${currentInteractions}/${maxInteractions}`;
|
||||
}
|
||||
|
||||
// Function to smoothly scroll down
|
||||
function startScrolling() {
|
||||
if (!isRunning) return;
|
||||
|
||||
// Check if maximum interactions reached
|
||||
if (maxInteractions > 0 && currentInteractions >= maxInteractions) {
|
||||
console.log('Maximum interactions reached. Stopping the script.');
|
||||
isRunning = false;
|
||||
toggleButton.innerText = 'Start Auto Like';
|
||||
toggleButton.style.backgroundColor = '#1DA1F2';
|
||||
return;
|
||||
}
|
||||
|
||||
// Scroll by a random small increment, scaled by speedScale
|
||||
const scrollStep = getRandomIntScaled(SCROLL_INCREMENT_MIN, SCROLL_INCREMENT_MAX);
|
||||
window.scrollBy({
|
||||
top: scrollStep,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
|
||||
// After scrolling, check for the target elements
|
||||
// Delay to allow scrolling to complete
|
||||
scrollTimeout = setTimeout(() => {
|
||||
processElements();
|
||||
}, getRandomIntScaled(SCROLL_DELAY_MIN, SCROLL_DELAY_MAX));
|
||||
}
|
||||
|
||||
// Function to process Like and Retweet buttons
|
||||
function processElements() {
|
||||
if (!isRunning) return;
|
||||
|
||||
const likeButton = findVisibleLikeButton();
|
||||
const retweetButton = isRetweetEnabled ? findVisibleRetweetButton() : null;
|
||||
|
||||
if (likeButton) {
|
||||
handleLikeButton(likeButton);
|
||||
}
|
||||
|
||||
if (retweetButton) {
|
||||
handleRetweetButton(retweetButton);
|
||||
}
|
||||
|
||||
// Continue scrolling if no actions were taken
|
||||
if (!likeButton && !retweetButton) {
|
||||
startScrolling();
|
||||
}
|
||||
}
|
||||
|
||||
// Function to find a <button> with data-testid="like" that is fully visible and not yet clicked
|
||||
function findVisibleLikeButton() {
|
||||
const buttons = document.querySelectorAll('button[data-testid="like"]');
|
||||
for (let btn of buttons) {
|
||||
if (isElementFullyVisible(btn) && isButtonEligible(btn)) {
|
||||
return btn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Function to find a <button> with data-testid="retweet" that is fully visible and not yet clicked
|
||||
function findVisibleRetweetButton() {
|
||||
const buttons = document.querySelectorAll('button[data-testid="retweet"]');
|
||||
for (let btn of buttons) {
|
||||
if (isElementFullyVisible(btn) && isButtonEligible(btn)) {
|
||||
return btn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Function to handle clicking the Like button
|
||||
function handleLikeButton(btn) {
|
||||
// Scroll to make sure the button is fully visible
|
||||
btn.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
|
||||
// Wait for scrolling to finish
|
||||
setTimeout(() => {
|
||||
// Pause for a random short duration before clicking
|
||||
const clickDelay = getRandomIntScaled(CLICK_DELAY_MIN, CLICK_DELAY_MAX);
|
||||
clickTimeout = setTimeout(() => {
|
||||
// Double-check before clicking
|
||||
if (isButtonEligible(btn)) {
|
||||
btn.click();
|
||||
console.log('Like button clicked:', btn);
|
||||
// Mark the button as clicked to prevent double-clicking
|
||||
btn.setAttribute('data-autoclicked', 'true');
|
||||
// Increment interaction counter
|
||||
incrementInteractions();
|
||||
}
|
||||
// Continue the loop
|
||||
startScrolling();
|
||||
}, clickDelay);
|
||||
}, getRandomIntScaled(500, 1000)); // Additional delay to ensure scrolling has completed
|
||||
}
|
||||
|
||||
// Function to handle clicking the Retweet button and confirming
|
||||
function handleRetweetButton(btn) {
|
||||
// Scroll to make sure the button is fully visible
|
||||
btn.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
|
||||
// Wait for scrolling to finish
|
||||
setTimeout(() => {
|
||||
// Pause for a random short duration before clicking
|
||||
const clickDelay = getRandomIntScaled(CLICK_DELAY_MIN, CLICK_DELAY_MAX);
|
||||
clickTimeout = setTimeout(() => {
|
||||
// Double-check before clicking
|
||||
if (isButtonEligible(btn)) {
|
||||
btn.click();
|
||||
console.log('Retweet button clicked:', btn);
|
||||
// Mark the button as clicked to prevent double-clicking
|
||||
btn.setAttribute('data-autoclicked', 'true');
|
||||
// Increment interaction counter
|
||||
|
||||
incrementInteractions();
|
||||
|
||||
// After clicking retweet, wait and confirm
|
||||
retweetConfirmTimeout = setTimeout(() => {
|
||||
const confirmButton = findRetweetConfirmButton();
|
||||
if (confirmButton) {
|
||||
confirmButton.click();
|
||||
console.log('Retweet confirmed:', confirmButton);
|
||||
// Mark the confirm button as clicked
|
||||
confirmButton.setAttribute('data-autoclicked', 'true');
|
||||
// Increment interaction counter
|
||||
incrementInteractions();
|
||||
}
|
||||
// Continue the loop
|
||||
startScrolling();
|
||||
}, getRandomIntScaled(RETWEET_CONFIRM_DELAY_MIN, RETWEET_CONFIRM_DELAY_MAX));
|
||||
} else {
|
||||
// Continue the loop
|
||||
startScrolling();
|
||||
}
|
||||
}, clickDelay);
|
||||
}, getRandomIntScaled(500, 1000)); // Additional delay to ensure scrolling has completed
|
||||
}
|
||||
|
||||
// Function to find the Retweet Confirm button
|
||||
function findRetweetConfirmButton() {
|
||||
const buttons = document.querySelectorAll('div[data-testid="retweetConfirm"]');
|
||||
for (let btn of buttons) {
|
||||
if (isElementFullyVisible(btn) && isButtonEligible(btn)) {
|
||||
return btn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Function to check if an element is fully visible in the viewport
|
||||
function isElementFullyVisible(el) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
return (
|
||||
rect.top >= 0 &&
|
||||
rect.left >= 0 &&
|
||||
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
||||
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
||||
);
|
||||
}
|
||||
|
||||
// Function to check if the button is eligible for clicking
|
||||
function isButtonEligible(btn) {
|
||||
// Check if the button has already been clicked by this script
|
||||
if (btn.getAttribute('data-autoclicked') === 'true') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the button is still the correct type ('like', 'retweet', or 'retweetConfirm')
|
||||
const currentTestId = btn.getAttribute('data-testid');
|
||||
if (currentTestId !== 'like' && currentTestId !== 'retweet' && currentTestId !== 'retweetConfirm') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Function to increment interactions and update the counter
|
||||
function incrementInteractions() {
|
||||
currentInteractions += 1;
|
||||
if (maxInteractions > 0) {
|
||||
counterText.innerText = `Interactions: ${currentInteractions}/${maxInteractions}`;
|
||||
if (currentInteractions >= maxInteractions) {
|
||||
console.log('Maximum interactions reached. Stopping the script.');
|
||||
isRunning = false;
|
||||
toggleButton.innerText = 'Start Auto Like';
|
||||
toggleButton.style.backgroundColor = '#1DA1F2';
|
||||
clearTimeout(scrollTimeout);
|
||||
clearTimeout(clickTimeout);
|
||||
clearTimeout(retweetConfirmTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optional: Observe DOM changes to handle dynamically loaded content
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
if (isRunning) {
|
||||
// You can trigger actions based on specific mutations if needed
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
})();
|
Loading…
Reference in New Issue
Block a user