Skip to content

Instantly share code, notes, and snippets.

@TheGreatRambler
Created December 4, 2025 19:58
Show Gist options
  • Select an option

  • Save TheGreatRambler/107fb0b991c6222c56bd3417808e8c96 to your computer and use it in GitHub Desktop.

Select an option

Save TheGreatRambler/107fb0b991c6222c56bd3417808e8c96 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name OpenTripPlanner Randomize Routes
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Periodically query a random route in the center of the OpenTripPlanner map
// @author TheGreatRambler
// @match http://localhost/*
// @match http://127.0.0.1/*
// @match http://0.0.0.0/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
// === CONFIGURABLE SETTINGS ===
// How often to run the sequence (ms)
const CYCLE_INTERVAL_MS = 3000;
// Bounding box (in viewport coordinates, relative to top-left of the visible window)
// Adjust these for your target area
const BOX_MARGIN_LEFT = 660;
const BOX_MARGIN_RIGHT = 167;
const BOX_MARGIN_TOP = 201;
const BOX_MARGIN_BOTTOM = 27;
// Click offsets
const FIRST_LEFT_CLICK_OFFSET_Y = -90; // 20px up
const SECOND_LEFT_CLICK_OFFSET_Y = -50; // 10px up
// Delays between actions (ms)
const DELAY_AFTER_FIRST_RIGHT = 300;
const DELAY_AFTER_FIRST_LEFT = 300;
const DELAY_AFTER_SECOND_RIGHT = 300;
const DELAY_AFTER_SECOND_LEFT = 0; // end of sequence, can be 0
// === INTERNAL STATE ===
let isRunning = false;
let intervalId = null;
// === UTILS ===
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Random point inside the bounding box
function getRandomPointInBox() {
const left = BOX_MARGIN_LEFT;
const right = window.innerWidth - BOX_MARGIN_RIGHT;
const top = BOX_MARGIN_TOP;
const bottom = window.innerHeight - BOX_MARGIN_BOTTOM;
// Guard against weird cases
if (right <= left || bottom <= top) {
// fallback to center-ish
return {
x: Math.round(window.innerWidth / 2),
y: Math.round(window.innerHeight / 2),
};
}
const x = Math.round(left + Math.random() * (right - left));
const y = Math.round(top + Math.random() * (bottom - top));
return { x, y };
}
function dispatchMouse(element, type, button, x, y) {
if (!element) return;
const evt = new MouseEvent(type, {
bubbles: true,
cancelable: true,
view: window,
button: button, // 0 = left, 2 = right
buttons: 1 << button, // bitmask
clientX: x,
clientY: y,
});
element.dispatchEvent(evt);
}
function rightClickAt(x, y) {
const el = document.elementFromPoint(x, y) || document.body;
// Simulate a right click: mousedown, mouseup, contextmenu
dispatchMouse(el, 'mousedown', 2, x, y);
dispatchMouse(el, 'mouseup', 2, x, y);
dispatchMouse(el, 'contextmenu', 2, x, y);
}
function leftClickAt(x, y) {
const el = document.elementFromPoint(x, y) || document.body;
// Simulate a left click: mousedown, mouseup, click
dispatchMouse(el, 'mousedown', 0, x, y);
dispatchMouse(el, 'mouseup', 0, x, y);
dispatchMouse(el, 'click', 0, x, y);
}
// === MAIN SEQUENCE ===
async function runCycle() {
if (!isRunning) return;
// 1) Right click at random point in bounding box
const p1 = getRandomPointInBox();
rightClickAt(p1.x, p1.y);
await sleep(DELAY_AFTER_FIRST_RIGHT);
// 2) Left click ~20px up from that point
let y1Up = p1.y + FIRST_LEFT_CLICK_OFFSET_Y;
if (y1Up < 0) y1Up = 0;
leftClickAt(p1.x, y1Up);
await sleep(DELAY_AFTER_FIRST_LEFT);
// 3) Right click at another random point
const p2 = getRandomPointInBox();
rightClickAt(p2.x, p2.y);
await sleep(DELAY_AFTER_SECOND_RIGHT);
// 4) Left click ~10px up from second point
let y2Up = p2.y + SECOND_LEFT_CLICK_OFFSET_Y;
if (y2Up < 0) y2Up = 0;
leftClickAt(p2.x, y2Up);
await sleep(DELAY_AFTER_SECOND_LEFT);
}
function startAutoClicker() {
if (isRunning) return;
isRunning = true;
updateToggleButton();
intervalId = setInterval(runCycle, CYCLE_INTERVAL_MS);
}
function stopAutoClicker() {
isRunning = false;
updateToggleButton();
if (intervalId !== null) {
clearInterval(intervalId);
intervalId = null;
}
}
// === TOGGLE UI ===
let toggleBtn = null;
function createToggleButton() {
toggleBtn = document.createElement('button');
toggleBtn.id = 'bbox-auto-clicker-toggle';
toggleBtn.textContent = 'AutoClick: OFF';
toggleBtn.style.position = 'fixed';
toggleBtn.style.top = '10px';
toggleBtn.style.right = '10px';
toggleBtn.style.zIndex = '999999';
toggleBtn.style.padding = '6px 10px';
toggleBtn.style.fontSize = '12px';
toggleBtn.style.background = 'rgba(0,0,0,0.7)';
toggleBtn.style.color = '#fff';
toggleBtn.style.border = '1px solid #aaa';
toggleBtn.style.borderRadius = '4px';
toggleBtn.style.cursor = 'pointer';
toggleBtn.addEventListener('click', () => {
if (isRunning) {
stopAutoClicker();
} else {
startAutoClicker();
}
});
document.body.appendChild(toggleBtn);
}
function updateToggleButton() {
if (!toggleBtn) return;
if (isRunning) {
toggleBtn.textContent = 'AutoClick: ON';
toggleBtn.style.background = 'rgba(0,128,0,0.8)';
} else {
toggleBtn.textContent = 'AutoClick: OFF';
toggleBtn.style.background = 'rgba(128,0,0,0.8)';
}
}
// === INIT ===
function init() {
createToggleButton();
// default is OFF; user can click to enable
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment