Load saves for whatbeatsrock.com with pause functionality, adjustable wait time, file-based save selection, improved UI with padding, and edge-only dragging with scrollable middle
// ==UserScript==
// @name WhatBeatsRock Save Loader
// @namespace http://violentmonkey.net/
// @version 3.0
// @description Load saves for whatbeatsrock.com with pause functionality, adjustable wait time, file-based save selection, improved UI with padding, and edge-only dragging with scrollable middle
// @author JoTheStupid
// @match https://www.whatbeatsrock.com/*
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
let paused = false;
let saveEntries = [];
let index = 0;
let isDragging = false;
let dragStartX, dragStartY, startX, startY;
// UI Styles
const buttonStyle = `
padding: 8px 16px;
margin-top: 10px;
background-color: #4CAF50;
border: 2px solid #333;
color: white;
cursor: pointer;
font-size: 14px;
border-radius: 5px;
text-align: center;
`;
const pauseButtonStyle = `
padding: 8px 16px;
margin-top: 10px;
background-color: #f44336;
border: 2px solid #333;
color: white;
cursor: pointer;
font-size: 14px;
border-radius: 5px;
text-align: center;
`;
const containerStyle = `
padding: 10px;
background-color: white;
border: 2px solid black;
border-radius: 10px;
position: fixed;
top: 10px;
right: 10px;
width: 320px;
height: 500px;
z-index: 1000;
resize: both;
overflow: auto;
min-width: 200px;
min-height: 200px;
`;
const edgeThreshold = 10; // The distance from the edge in pixels to allow dragging
// Create a container for input elements
let container = document.createElement('div');
container.style.cssText = containerStyle;
document.body.appendChild(container);
// Handle dragging the container (only from edges)
container.addEventListener('mousedown', function (e) {
const rect = container.getBoundingClientRect();
const isEdge = e.clientX - rect.left < edgeThreshold ||
rect.right - e.clientX < edgeThreshold ||
e.clientY - rect.top < edgeThreshold ||
rect.bottom - e.clientY < edgeThreshold;
if (isEdge) {
isDragging = true;
dragStartX = e.clientX;
dragStartY = e.clientY;
startX = container.offsetLeft;
startY = container.offsetTop;
e.preventDefault();
}
});
document.addEventListener('mousemove', function (e) {
if (isDragging) {
let offsetX = e.clientX - dragStartX;
let offsetY = e.clientY - dragStartY;
container.style.left = startX + offsetX + 'px';
container.style.top = startY + offsetY + 'px';
}
});
document.addEventListener('mouseup', function () {
isDragging = false;
});
// Create a file input for save file upload
let fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.txt';
fileInput.style.width = '100%';
fileInput.style.marginBottom = '10px';
container.appendChild(fileInput);
// Create a textbox for input
let inputBox = document.createElement('textarea');
inputBox.style.width = '100%';
inputBox.style.height = '100px';
inputBox.style.padding = '5px';
inputBox.style.border = '1px solid #ccc';
inputBox.style.borderRadius = '5px';
inputBox.style.marginBottom = '10px';
container.appendChild(inputBox);
// Create a button to apply the save
let enterSaveButton = document.createElement('button');
enterSaveButton.innerHTML = 'Enter Save';
enterSaveButton.style.cssText += buttonStyle;
container.appendChild(enterSaveButton);
// Create a pause/resume button
let pauseButton = document.createElement('button');
pauseButton.innerHTML = 'Pause';
pauseButton.style.cssText += pauseButtonStyle;
container.appendChild(pauseButton);
pauseButton.addEventListener('click', () => {
paused = !paused;
pauseButton.innerHTML = paused ? 'Resume' : 'Pause';
pauseButton.style.backgroundColor = paused ? '#f44336' : '#4CAF50';
if (!paused) {
processNextEntry();
}
});
// Create a label for the slider
let sliderLabel = document.createElement('label');
sliderLabel.innerHTML = 'Wait Time (ms):';
container.appendChild(sliderLabel);
// Create a slider for wait time
let waitTimeSlider = document.createElement('input');
waitTimeSlider.type = 'range';
waitTimeSlider.min = '100';
waitTimeSlider.max = '3000';
waitTimeSlider.value = '1000';
waitTimeSlider.style.width = '100%';
waitTimeSlider.style.marginBottom = '10px';
container.appendChild(waitTimeSlider);
// Display the current wait time
let waitTimeDisplay = document.createElement('div');
waitTimeDisplay.innerHTML = `Current wait time: ${waitTimeSlider.value} ms`;
waitTimeDisplay.style.marginBottom = '10px';
container.appendChild(waitTimeDisplay);
// Create a div to show color-coded save options
let saveListContainer = document.createElement('div');
saveListContainer.style.width = '100%';
saveListContainer.style.height = '150px'; // Set height and make it scrollable
saveListContainer.style.overflowY = 'auto'; // Enable vertical scrolling for the save list
saveListContainer.style.border = '1px solid #ccc';
saveListContainer.style.borderRadius = '5px';
container.appendChild(saveListContainer);
// Color cycle for the saves
const colors = ['red', 'orange', 'yellow', 'blue', 'purple'];
// Handle file reading and populate the saveList with color-coded saves
fileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
const contents = e.target.result;
const saves = contents.split('\n').map(save => save.trim()).filter(save => save !== '');
// Clear previous saves
saveListContainer.innerHTML = '';
// Populate the save list with color-coded clickable divs
saves.forEach((save, idx) => {
let saveItem = document.createElement('div');
saveItem.textContent = save;
saveItem.style.cursor = 'pointer';
saveItem.style.padding = '5px';
saveItem.style.border = '1px solid black';
saveItem.style.marginBottom = '5px';
saveItem.style.backgroundColor = colors[idx % colors.length]; // Alternate colors
// Click to insert the save into the input box
saveItem.addEventListener('click', () => {
inputBox.value = save;
});
saveListContainer.appendChild(saveItem);
});
console.log('Saves loaded:', saves);
};
reader.readAsText(file);
}
});
// Update the wait time display as the slider is moved
waitTimeSlider.addEventListener('input', () => {
waitTimeDisplay.innerHTML = `Current wait time: ${waitTimeSlider.value} ms`;
});
// Function to find the Next button
function findNextButton() {
return document.querySelector('button.py-4.px-8.border.border-1-black.text-lg');
}
// Function to simulate typing and clicking
function simulateInput(input, callback) {
if (paused) return;
console.log(`Simulating input: ${input}`);
let inputField = document.querySelector('.pl-4.py-4.text-lg.border.border-1-black');
let submitButton = document.querySelector('.p-4.border.border-1-black.text-lg.bg-green-200, .p-4.border.border-1-black.text-lg.text-gray-400');
if (inputField && submitButton) {
inputField.focus();
Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set.call(inputField, input);
let inputEvent = new Event('input', { bubbles: true });
let changeEvent = new Event('change', { bubbles: true });
inputField.dispatchEvent(inputEvent);
inputField.dispatchEvent(changeEvent);
setTimeout(() => {
submitButton.click();
setTimeout(() => {
let nextButton = findNextButton();
if (nextButton) {
nextButton.click(); // Click the next button
setTimeout(callback, parseInt(waitTimeSlider.value));
} else {
console.log('Next button not found, retrying...');
setTimeout(() => simulateInput(input, callback), parseInt(waitTimeSlider.value)); // Retry if the next button is not found
}
}, parseInt(waitTimeSlider.value));
}, parseInt(waitTimeSlider.value));
} else {
console.log('Input field or submit button not found, retrying...');
setTimeout(() => simulateInput(input, callback), parseInt(waitTimeSlider.value));
}
}
// Function to enter the save from the input box and start processing it
function enterSave() {
let saveText = inputBox.value.trim();
if (!saveText) {
alert('Please enter a save');
console.log('No save text entered.');
return;
}
saveEntries = saveText.split('🤜').map(entry => entry.trim()).reverse();
index = 0;
processNextEntry();
}
function processNextEntry() {
if (paused) return;
if (index < saveEntries.length) {
let currentInput = checkTextBoxForCurrentInput();
let currentIndex = saveEntries.findIndex(entry => entry.toLowerCase() === currentInput.toLowerCase());
if (currentIndex !== -1 && currentIndex + 1 < saveEntries.length) {
console.log(`Current input is "${currentInput}". Inputting next entry: ${saveEntries[currentIndex + 1]}`);
simulateInput(saveEntries[currentIndex + 1], () => {
index = currentIndex + 2;
processNextEntry();
});
} else {
console.log(`Current input "${currentInput}" does not match any expected input. Retrying...`);
setTimeout(processNextEntry, parseInt(waitTimeSlider.value));
}
} else {
console.log('All entries processed.');
}
}
function checkTextBoxForCurrentInput() {
let currentInputElement = document.querySelector('.text-2xl.text-center');
if (currentInputElement) {
let currentInput = currentInputElement.textContent.trim();
if (currentInput.endsWith('?')) {
currentInput = currentInput.slice(0, -1);
}
return currentInput;
}
return null;
}
// Add the Enter Save button click event
enterSaveButton.addEventListener('click', () => {
console.log('Enter Save button clicked.');
enterSave();
});
})();