is not present
let attempts = 0;
while (document.querySelector("div.loading") && attempts < 100) {
log("β³ Waiting for page to load... (processEggQueue)");
attempts += 1;
await new Promise((r) => setTimeout(r, 100));
}
log(`Page loaded for egg ${egg.egg_id}`);
// look for a single instance of each CLASS_NAME from CLASS_NAMES on the page, anywhere
// not just as a class name but as any string of text anywhere in the entire HTML/JS/plaintext of the page
var classesOnPage = true;
var classes_to_use = isEvil ? CLASS_NAMES_EVIL : CLASS_NAMES;
for (const className of classes_to_use) {
if (!document.body.innerHTML.includes(className)) {
log(
`β Egg ${egg.egg_id} does not have required class: ${className}`
);
classesOnPage = false;
break; // No need to check further if one is missing
}
}
if (!classesOnPage) {
log(
`β Egg ${egg.egg_id} does not have all required classes on the page, skipping`
);
continue;
}
// Try to click turn button with retries
let turnAttempts = 0;
const maxTurnAttempts = 0;
const tryTurn = async () => {
const turnBtn = document.querySelector(
'button[onclick*="pet_turn_egg"]'
);
if (turnBtn) {
log("Found turn button, clicking...");
turnBtn.click();
await new Promise((r) => setTimeout(r, 300));
// Check if puzzle dialog appeared
const dlg = document.querySelector('div.ui-dialog[role="dialog"]');
if (dlg && dlg.innerHTML.includes("Name the Species")) {
log("Puzzle dialog detected, solving...");
await solveAndSubmit();
} else {
const closeButtons = document.querySelectorAll(
".ui-dialog-titlebar-close"
);
while (closeButtons.length > 0) {
closeButtons.forEach((btn) => {
log("Clicking close button");
btn.click();
});
await new Promise((r) => setTimeout(r, 300)); // Wait for dialog to close
// Re-fetch close buttons
closeButtons = document.querySelectorAll(
".ui-dialog-titlebar-close"
);
}
log("No puzzle dialog, egg turned successfully");
}
return true;
} else if (turnAttempts++ < maxTurnAttempts) {
log(
`Turn button not found, attempt ${turnAttempts}/${maxTurnAttempts}`
);
await new Promise((r) => setTimeout(r, 300));
return await tryTurn();
} else {
log("Turn button not found after all attempts");
return false;
}
};
await tryTurn();
// Wait before processing next egg
await new Promise((r) => setTimeout(r, 50));
while (document.querySelector("div.loading")) {
log("β³ Waiting for page to load... (after egg turn)");
await new Promise((r) => setTimeout(r, 100));
}
} catch (error) {
log(`Error processing egg ${egg.egg_id}:`, error);
}
}
isProcessing = false;
// Update visualizer when queue is empty
updateQueueVisualizer();
}
function pollForEggs() {
if (isPuzzleSolving) {
log("Skipping poll - puzzle in progress");
return;
}
GM_xmlhttpRequest({
method: "GET",
url: `${API_BASE}/get_eggs`,
onload: function (response) {
try {
const data = JSON.parse(response.responseText);
if (data.eggs && data.eggs.length > 0) {
log(`Found ${data.eggs.length} new eggs!`);
const oldQueueLength = eggQueue.length;
eggQueue.push(...data.eggs);
// Update queue visualizer after adding eggs
setTimeout(() => {
updateQueueVisualizer();
}, 100);
if (!isProcessing && !isPuzzleSolving) {
processEggQueue();
}
}
// If server is idle, restart collection
if (data.status === "idle" && isRunning() && !isPuzzleSolving) {
log("Server idle, restarting collection...");
startCollection();
}
} catch (error) {
log("Error parsing eggs:", error);
}
},
onerror: function (error) {
log("Error fetching eggs:", error);
},
});
}
function updateProgress() {
if (!isRunning()) return;
GM_xmlhttpRequest({
method: "GET",
url: `${API_BASE}/progress`,
onload: function (response) {
try {
const data = JSON.parse(response.responseText);
log(
`Progress update: ${data.friends_completed}/${data.friends_total}, running: ${data.is_running}`
); // Debug log
const progressElement = document.getElementById("friend-progress");
if (progressElement) {
if (data.is_running && data.friends_total > 0) {
progressElement.textContent = `π₯ ${data.friends_completed}/${data.friends_total}`;
progressElement.style.display = "block";
log(
`Updated progress display to: ${progressElement.textContent}`
); // Debug log
} else {
log(
`Hiding progress - running: ${data.is_running}, total: ${data.friends_total}`
); // Debug log
}
}
// Update status indicator
updateStatusIndicator();
} catch (error) {
log("Error updating progress:", error);
}
},
onerror: function (error) {
log("Error fetching progress:", error);
},
});
// Replace the problematic code block with this:
if (isEvil) {
const evilToggle = document.getElementById("evil-mode-toggle");
if (evilToggle) {
// The toggle is a checkbox input, not a div with classes
evilToggle.checked = true;
// The visual slider is the span with class "slider"
const slider = evilToggle.nextElementSibling; // This gets the .slider span
if (slider && slider.classList.contains("slider")) {
// Trigger the CSS :checked state by ensuring the input is checked
slider.style.backgroundColor = "#e74c3c"; // Red background for evil mode
slider.style.transition =
"background-color 0.3s ease, box-shadow 0.3s ease";
}
}
// Update panel background color (correct ID)
const panel = document.getElementById("bot-controls");
if (panel) {
panel.style.background = "rgba(139, 0, 0, 0.8)"; // Dark red with transparency
}
}
}
function updateStatusIndicator() {
const statusDot = document.getElementById("status-dot");
if (statusDot) {
if (isRunning()) {
statusDot.style.backgroundColor = "#00ff00"; // Green when running
statusDot.title = "Bot is running";
} else {
statusDot.style.backgroundColor = "#ff0000"; // Red when stopped
statusDot.title = "Bot is stopped";
}
}
}
function updateQueueVisualizer() {
const queueContainer = document.getElementById("queue-visualizer");
if (!queueContainer) return;
const currentQueueLength = eggQueue.length;
const maxBarWidth = 220; // Maximum width of the queue bar
const segmentWidth = 0.22; // Width of each egg segment
const maxSegments = Math.floor(maxBarWidth / segmentWidth);
// Get or create the background bar (gray bar)
let backgroundBar = queueContainer.querySelector(".queue-background-bar");
if (!backgroundBar) {
backgroundBar = document.createElement("div");
backgroundBar.className = "queue-background-bar";
backgroundBar.style.cssText = `
height: 14px;
width: ${maxBarWidth}px;
background: rgba(255,255,255,0.1);
border-radius: 7px;
position: relative;
overflow: hidden;
`;
// Insert the background bar into the existing container
const existingBarContainer = queueContainer.querySelector(
'div[style*="height: 14px"]'
);
if (existingBarContainer) {
existingBarContainer.replaceWith(backgroundBar);
} else {
queueContainer.appendChild(backgroundBar);
}
}
// Get or create the queue bar (orange bar) - make it a child of background bar
let queueBar = backgroundBar.querySelector(".queue-bar");
if (!queueBar) {
queueBar = document.createElement("div");
queueBar.className = "queue-bar";
queueBar.style.cssText = `
height: 100%;
background: linear-gradient(90deg, #ff6b35, #f7931e);
border-radius: 6px;
transition: width 0.3s ease;
position: absolute;
top: 0;
left: 0;
overflow: hidden;
border: 1px solid rgba(255,255,255,0.3);
box-sizing: border-box;
`;
backgroundBar.appendChild(queueBar);
// also make sure the ui changes (switch and background color) are applied
// if evil mode is enabled
if (isEvil) {
queueBar.style.background = "linear-gradient(90deg, #ff0000, #aa0000)";
queueBar.style.boxShadow = "0 2px 8px rgba(255, 0, 0, 0.3)";
// make sure the switch is actually on
const evilToggle = document.getElementById("evil-mode-toggle");
if (evilToggle) {
evilToggle.classList.add("active");
}
// Update panel background color
const panel = document.getElementById("ovipets-bot-panel");
if (panel) {
panel.style.background = "rgba(139, 0, 0, 0.8)"; // Dark red with transparency
}
} else {
queueBar.style.background = "linear-gradient(90deg, #ff6b35, #f7931e)";
queueBar.style.boxShadow = "0 2px 8px rgba(255, 107, 53, 0.3)";
}
}
// Calculate target width - constrain to max bar width
const visibleSegments = Math.min(currentQueueLength, maxSegments);
const targetWidth = Math.min(visibleSegments * segmentWidth, maxBarWidth);
// Get current width
const currentWidth = parseInt(queueBar.style.width) || 0;
// Update width with animation
queueBar.style.width = `${targetWidth}px`;
// Add segments effect
if (targetWidth > currentWidth) {
// Queue growing - animate segments flying in from right
animateSegmentsIn(
queueBar,
Math.ceil((targetWidth - currentWidth) / segmentWidth)
);
} else if (targetWidth < currentWidth) {
// Queue shrinking - animate segments leaving from left
animateSegmentsOut(
queueBar,
Math.ceil((currentWidth - targetWidth) / segmentWidth)
);
}
// Update queue counter
const queueCounter = queueContainer.querySelector(".queue-counter");
if (queueCounter) {
queueCounter.textContent = `π₯ ${currentQueueLength}`;
// Pulse effect when queue changes
queueCounter.style.transform = "scale(1.1)";
setTimeout(() => {
queueCounter.style.transform = "scale(1)";
}, 150);
}
// if isEvil is true just make sure the switch is on and the background color is dark red
console.log(`isEvil: ${isEvil}`);
if (isEvil) {
const evilToggle = document.getElementById("evil-mode-toggle");
while (!evilToggle) {
console.log("Waiting for evil toggle to be available...");
evilToggle = document.getElementById("evil-mode-toggle");
}
if (evilToggle) {
evilToggle.classList.add("active");
}
// Update panel background color
const panel = document.getElementById("ovipets-bot-panel");
if (panel) {
panel.style.background = "rgba(139, 0, 0, 0.8)"; // Dark red with transparency
}
}
}
function animateSegmentsIn(queueBar, segmentCount) {
for (let i = 0; i < segmentCount; i++) {
setTimeout(() => {
const segment = document.createElement("div");
segment.style.cssText = `
position: absolute;
right: -10px;
top: 0;
width: 6px;
height: 100%;
background: linear-gradient(90deg, #ffaa35, #ff8535);
border-radius: 3px;
animation: flyInFromRight 0.4s ease-out forwards;
`;
// Add keyframes if not already added
if (!document.getElementById("queue-animations")) {
const style = document.createElement("style");
style.id = "queue-animations";
style.textContent = `
@keyframes flyInFromRight {
0% {
right: -10px;
opacity: 0;
transform: scale(0.5) rotate(45deg);
}
50% {
opacity: 1;
transform: scale(1.1) rotate(10deg);
}
100% {
right: 2px;
opacity: 0.8;
transform: scale(1) rotate(0deg);
}
}
@keyframes slideOutLeft {
0% {
left: 0;
opacity: 0.8;
transform: scale(1);
}
50% {
opacity: 0.5;
transform: scale(0.8);
}
100% {
left: -10px;
opacity: 0;
transform: scale(0.3);
}
}
.queue-bar {
box-shadow: 0 2px 8px rgba(255, 107, 53, 0.3);
}
`;
document.head.appendChild(style);
}
queueBar.appendChild(segment);
// Remove segment after animation
setTimeout(() => {
if (segment.parentNode) {
segment.remove();
}
}, 500);
}, i * 100); // Stagger the animations
}
}
function animateSegmentsOut(queueBar, segmentCount) {
for (let i = 0; i < segmentCount; i++) {
setTimeout(() => {
const segment = document.createElement("div");
segment.style.cssText = `
position: absolute;
left: 2px;
top: 0;
width: 6px;
height: 100%;
background: linear-gradient(90deg, #ff6b35, #f7931e);
border-radius: 3px;
animation: slideOutLeft 0.3s ease-in forwards;
`;
queueBar.appendChild(segment);
// Remove segment after animation
setTimeout(() => {
if (segment.parentNode) {
segment.remove();
}
}, 350);
}, i * 50); // Faster staggering for removal
}
}
function startCollection() {
const userId = extractUserIdFromPage() || prompt("Enter your user ID:");
if (!userId) return;
GM_xmlhttpRequest({
method: "POST",
url: `${API_BASE}/start_collection/${userId}${
isPeaceful ? "?peaceful=true" : ""
}`,
onload: function (response) {
try {
const data = JSON.parse(response.responseText);
log("Collection started:", data);
} catch (error) {
log("Error parsing start collection response:", error);
}
},
onerror: function (error) {
log("Error starting collection:", error);
},
});
}
function startBot() {
log("Starting bot...");
sessionStorage.setItem(RUN_KEY, "true");
startCollection();
// Poll for eggs every 3 seconds
pollInterval = setInterval(() => {
pollForEggs();
updateProgress();
}, 3000);
// Update progress immediately
updateProgress();
// Update status indicator
updateStatusIndicator();
}
function stopBot() {
log("Stopping bot...");
sessionStorage.removeItem(RUN_KEY);
if (pollInterval) {
clearInterval(pollInterval);
pollInterval = null;
}
// Clean up saved state when manually stopping
sessionStorage.removeItem("ovipets_bot_evil_mode");
sessionStorage.removeItem("ovipets_bot_queue");
sessionStorage.removeItem("ovipets_bot_accumulator");
sessionStorage.removeItem("ovipets_bot_is_processing");
sessionStorage.removeItem("ovipets_bot_is_puzzle_solving");
// Hide progress display
const progressElement = document.getElementById("friend-progress");
if (progressElement) {
// set to 0/0
progressElement.textContent = "π₯ 0/0";
}
// Update status indicator
updateStatusIndicator();
// Notify server to stop collection
GM_xmlhttpRequest({
method: "POST",
url: `${API_BASE}/stop_collection`,
onload: function (response) {
log("Collection stopped on server");
},
onerror: function (error) {
log("Error stopping collection:", error);
},
});
eggQueue = [];
isProcessing = false;
isPuzzleSolving = false;
accum = 0;
}
// --- Befriender Module ---
const Befriender = (function () {
const RUN_KEY = "befriender_running";
const LINKS_KEY = "befriender_links";
const IDX_KEY = "befriender_index";
const BASE_KEY = "befriender_base_href";
const UL_KEY = "befriender_selected_ul";
function log(...args) {
console.log("%c[BEFRIENDER]", "background:#0055aa;color:#fff;", ...args);
}
function startBot() {
log(
"Starting Befriender - Please click on the UL element containing the user avatars"
);
// Store the current location as base
sessionStorage.setItem(BASE_KEY, location.href);
sessionStorage.setItem(RUN_KEY, "true");
sessionStorage.setItem(IDX_KEY, "0");
sessionStorage.removeItem(LINKS_KEY);
sessionStorage.removeItem(UL_KEY);
// Enable UL selection mode
enableULSelection();
}
function stopBot() {
sessionStorage.removeItem(RUN_KEY);
sessionStorage.removeItem(UL_KEY);
disableULSelection();
log("Stopped Befriender");
}
function isRunning() {
return sessionStorage.getItem(RUN_KEY) === "true";
}
function getBase() {
return sessionStorage.getItem(BASE_KEY);
}
function getLinks() {
try {
return JSON.parse(sessionStorage.getItem(LINKS_KEY)) || [];
} catch {
return [];
}
}
function saveLinks(a) {
sessionStorage.setItem(LINKS_KEY, JSON.stringify(a));
}
function getIndex() {
return parseInt(sessionStorage.getItem(IDX_KEY) || "0", 10);
}
function setIndex(i) {
sessionStorage.setItem(IDX_KEY, String(i));
}
function getSelectedUL() {
return sessionStorage.getItem(UL_KEY);
}
function setSelectedUL(selector) {
sessionStorage.setItem(UL_KEY, selector);
}
function enableULSelection() {
// Create visual indicators
const style = document.createElement("style");
style.id = "befriender-ul-selection-style";
style.textContent = `
.befriender-ul-highlight {
outline: 3px solid #0055aa !important;
outline-offset: 2px !important;
cursor: pointer !important;
position: relative !important;
}
.befriender-ul-highlight::before {
content: "Click to select this list for befriending";
position: absolute;
top: -25px;
left: 0;
background: #0055aa;
color: white;
padding: 2px 8px;
font-size: 12px;
border-radius: 3px;
white-space: nowrap;
z-index: 10000;
}
.befriender-selection-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.3);
z-index: 9999;
pointer-events: none;
}
.befriender-instruction {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #0055aa;
color: white;
padding: 20px;
border-radius: 8px;
font-family: monospace;
font-size: 16px;
z-index: 10001;
text-align: center;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
}
`;
document.head.appendChild(style);
// Create overlay
const overlay = document.createElement("div");
overlay.className = "befriender-selection-overlay";
overlay.id = "befriender-overlay";
document.body.appendChild(overlay);
// Create instruction
const instruction = document.createElement("div");
instruction.className = "befriender-instruction";
instruction.id = "befriender-instruction";
instruction.innerHTML = `
π¨ Befriender Setup
Hover over UL elements and click the one containing the user avatars you want to befriend
Press ESC to cancel
`;
document.body.appendChild(instruction);
// Find all UL elements and add hover effects
const uls = document.querySelectorAll("ul");
uls.forEach((ul) => {
ul.addEventListener("mouseenter", handleULHover);
ul.addEventListener("mouseleave", handleULLeave);
ul.addEventListener("click", handleULClick);
});
// ESC to cancel
document.addEventListener("keydown", handleEscapeKey);
log(
`Found ${uls.length} UL elements - hover to highlight, click to select`
);
}
function disableULSelection() {
// Remove style
const style = document.getElementById("befriender-ul-selection-style");
if (style) style.remove();
// Remove overlay and instruction
const overlay = document.getElementById("befriender-overlay");
if (overlay) overlay.remove();
const instruction = document.getElementById("befriender-instruction");
if (instruction) instruction.remove();
// Remove event listeners from all ULs
const uls = document.querySelectorAll("ul");
uls.forEach((ul) => {
ul.removeEventListener("mouseenter", handleULHover);
ul.removeEventListener("mouseleave", handleULLeave);
ul.removeEventListener("click", handleULClick);
ul.classList.remove("befriender-ul-highlight");
});
document.removeEventListener("keydown", handleEscapeKey);
}
// Replace the handleULHover function in the Befriender module:
function handleULHover(event) {
const ul = event.target;
ul.classList.add("befriender-ul-highlight");
// Add debug info overlay
const debugInfo = document.createElement("div");
debugInfo.id = "befriender-debug-info";
debugInfo.style.cssText = `
position: fixed;
top: 10px;
right: 10px;
background: #0055aa;
color: white;
padding: 10px;
border-radius: 5px;
font-family: monospace;
font-size: 12px;
z-index: 10002;
max-width: 300px;
`;
const userAvatars = ul.querySelectorAll("a.user.avatar").length;
const totalLis = ul.querySelectorAll("li").length;
const selector = generateUniqueSelector(ul);
debugInfo.innerHTML = `
π UL Preview
Selector: ${selector}
Total LIs: ${totalLis}
User Avatars: ${userAvatars}
${
userAvatars > 0
? "β Contains user avatars!"
: "β No user avatars found"
}
`;
document.body.appendChild(debugInfo);
}
function handleULLeave(event) {
event.target.classList.remove("befriender-ul-highlight");
// Remove debug info
const debugInfo = document.getElementById("befriender-debug-info");
if (debugInfo) debugInfo.remove();
}
// Replace the handleULClick function in the Befriender module:
// Replace the handleULClick and collectLinks functions in the Befriender module:
function handleULClick(event) {
event.preventDefault();
event.stopPropagation();
const ul = event.target;
// Remove highlight class
ul.classList.remove("befriender-ul-highlight");
log(`Selected UL with ${ul.children.length} children`);
// Clean up selection mode first
disableULSelection();
// Collect links immediately from the selected UL - no timeout needed
collectLinksFromElement(ul);
}
// New function to collect links directly from the element
function collectLinksFromElement(ul) {
if (!isRunning()) return;
log("Collecting avatar links from selected UL");
if (!ul) {
log("No UL element provided");
stopBot();
return;
}
log(`Found UL element with ${ul.children.length} child elements`);
// Extract avatar links specifically
const avatarLinks = [];
const lis = ul.querySelectorAll("li");
log(`Scanning ${lis.length} li elements for avatar links...`);
lis.forEach((li, index) => {
// Look for user avatar links
const avatarLink =
li.querySelector("a.user.avatar") ||
li.querySelector("a.avatar") ||
li.querySelector('a[href*="usr="]') ||
li.querySelector('a[href*="#!/"]');
if (avatarLink && avatarLink.href) {
const href = avatarLink.href;
// Check if it's a user profile link (not a pet link)
const isUserLink =
(href.includes("usr=") && !href.includes("pet=")) ||
(href.includes("#!/") &&
!href.includes("pet=") &&
href !== "https://ovipets.com/#");
if (isUserLink) {
avatarLinks.push(href);
log(`Found avatar link ${index + 1}: ${href}`);
}
}
});
if (!avatarLinks.length) {
log("No avatar links found in selected UL");
log("UL HTML preview:", ul.innerHTML.substring(0, 500));
// Debug what we actually found
log("Debug: Found links in UL:");
const allLinks = ul.querySelectorAll("a");
allLinks.forEach((link, i) => {
log(` Link ${i + 1}: href="${link.href}" class="${link.className}"`);
});
stopBot();
return;
}
log(`Found ${avatarLinks.length} avatars to befriend`);
saveLinks(avatarLinks);
goToProfile();
}
// Keep the old collectLinks function for when we're at the base page
function collectLinks() {
if (!isRunning()) return;
log("Looking for previously selected UL...");
// This function is only called when we're back at the base page
// and need to re-find the UL. Since we don't persist the selector,
// we'll just let the user re-select if needed.
log("Please re-select the UL containing user avatars");
enableULSelection();
}
function handleEscapeKey(event) {
if (event.key === "Escape") {
log("Selection cancelled");
stopBot();
}
}
function generateUniqueSelector(element) {
// Remove the highlight class before generating selector
element.classList.remove("befriender-ul-highlight");
// Try ID first
if (element.id) {
return `#${element.id}`;
}
// Try class combination (excluding our highlight class)
if (element.className) {
const classes = element.className
.split(" ")
.filter((c) => c.trim() && c !== "befriender-ul-highlight");
if (classes.length > 0) {
let selector = `ul.${classes.join(".")}`;
if (document.querySelectorAll(selector).length === 1) {
return selector;
}
}
}
// Try parent-child relationship
let parent = element.parentElement;
if (parent) {
if (parent.id) {
return `#${parent.id} > ul`;
}
if (parent.className) {
const classes = parent.className.split(" ").filter((c) => c.trim());
if (classes.length > 0) {
let selector = `.${classes.join(".")} > ul`;
if (document.querySelectorAll(selector).length === 1) {
return selector;
}
}
}
}
// Try to find position among siblings
const siblings = Array.from(element.parentElement?.children || []);
const ulSiblings = siblings.filter((el) => el.tagName === "UL");
if (ulSiblings.length === 1) {
// Only UL child
if (parent && parent.id) {
return `#${parent.id} ul`;
}
if (parent && parent.className) {
const classes = parent.className.split(" ").filter((c) => c.trim());
if (classes.length > 0) {
return `.${classes.join(".")} ul`;
}
}
} else {
// Multiple UL siblings, use nth-of-type
const index = ulSiblings.indexOf(element) + 1;
if (parent && parent.id) {
return `#${parent.id} ul:nth-of-type(${index})`;
}
if (parent && parent.className) {
const classes = parent.className.split(" ").filter((c) => c.trim());
if (classes.length > 0) {
return `.${classes.join(".")} ul:nth-of-type(${index})`;
}
}
}
// Final fallback: use XPath-like approach
function getElementPath(el) {
if (el.id) return `#${el.id}`;
if (el === document.body) return "body";
const parent = el.parentElement;
if (!parent) return el.tagName.toLowerCase();
const siblings = Array.from(parent.children);
const sameTagSiblings = siblings.filter(
(sibling) => sibling.tagName === el.tagName
);
if (sameTagSiblings.length === 1) {
return `${getElementPath(parent)} > ${el.tagName.toLowerCase()}`;
} else {
const index = sameTagSiblings.indexOf(el) + 1;
return `${getElementPath(
parent
)} > ${el.tagName.toLowerCase()}:nth-of-type(${index})`;
}
}
return getElementPath(element);
}
// Replace the collectLinks function in the Befriender module:
// Replace the collectLinks function in the Befriender module:
function collectLinks() {
if (!isRunning()) return;
log("Collecting avatar links from selected UL");
const ulSelector = getSelectedUL();
if (!ulSelector) {
log("No UL selected");
stopBot();
return;
}
let ul;
// Handle special fallback selector
if (ulSelector.startsWith("ul-signature:")) {
ul = window.befrienderSelectedUL;
if (!ul) {
log("Element reference lost");
stopBot();
return;
}
} else {
ul = document.querySelector(ulSelector);
}
if (!ul) {
log(`Selected UL not found: ${ulSelector}`);
stopBot();
return;
}
log(`Found UL element with ${ul.children.length} child elements`);
// Extract avatar links specifically (improved detection)
const avatarLinks = [];
const lis = ul.querySelectorAll("li");
log(`Scanning ${lis.length} li elements for avatar links...`);
lis.forEach((li, index) => {
// Look for user avatar links with improved selectors
const avatarLink =
li.querySelector("a.user.avatar") ||
li.querySelector("a.avatar") ||
li.querySelector('a[href*="usr="]') ||
li.querySelector('a[href*="#!/"]');
if (avatarLink && avatarLink.href) {
// More flexible user link detection
const href = avatarLink.href;
// Check if it's a user profile link (not a pet link)
const isUserLink =
(href.includes("usr=") && !href.includes("pet=")) ||
(href.includes("#!/") &&
!href.includes("pet=") &&
!href === "https://ovipets.com/#");
if (isUserLink) {
avatarLinks.push(href);
log(`Found avatar link ${index + 1}: ${href}`);
}
}
});
if (!avatarLinks.length) {
log("No avatar links found in selected UL");
log("UL HTML preview:", ul.innerHTML.substring(0, 500));
// Let's also log what we actually found for debugging
log("Debug: Found links in UL:");
const allLinks = ul.querySelectorAll("a");
allLinks.forEach((link, i) => {
log(` Link ${i + 1}: href="${link.href}" class="${link.className}"`);
});
stopBot();
return;
}
log(`Found ${avatarLinks.length} avatars to befriend`);
saveLinks(avatarLinks);
goToProfile();
}
function goToProfile() {
if (!isRunning()) return;
const links = getLinks();
const idx = getIndex();
if (idx >= links.length) {
log("All friend requests sent! Befriending complete!");
stopBot();
location.href = getBase();
return;
}
log(`π¨ Visiting profile ${idx + 1}/${links.length}...`);
location.href = links[idx];
}
function handleProfile() {
if (!isRunning()) return;
log("π Looking for friend request button...");
let tries = 0;
const maxTries = 1;
const tryFriendButton = () => {
const btn = document.querySelector('button[onclick*="friend_request"]');
if (btn) {
log("β Found friend request button, clicking...");
btn.click();
log("π¨ Friend request sent!");
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
location.href = getBase();
}
}, 300);
} else if (tries++ < maxTries) {
log(
`β³ Friend request button not found, retrying... (${tries}/${maxTries})`
);
setTimeout(tryFriendButton, 300);
} else {
log("β No friend request button found, skipping this user");
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToProfile();
}
}, 300);
}
};
setTimeout(tryFriendButton, 300);
}
function main() {
if (!isRunning()) return;
const href = location.href;
const base = getBase();
log("π Befriender main executing...", href);
// If we haven't collected links yet and we're at the base
if (!sessionStorage.getItem(LINKS_KEY) && href === base) {
log("π At base, need to collect avatar links");
setTimeout(() => {
if (isRunning()) {
collectLinks();
}
}, 300);
}
// If we're back at the base and have collected links
else if (href === base) {
log("π At base, have links, continuing to next profile...");
setTimeout(() => {
if (isRunning()) {
goToProfile();
}
}, 300);
}
// If we're on a user profile page
else {
log("π On user profile, sending friend request...");
setTimeout(() => {
if (isRunning()) {
handleProfile();
}
}, 300);
}
}
return { startBot, stopBot, main };
})();
// --- Old Ovipets AutoβTurn Eggs Across Friends ---
const OvipetsOldAcross = (function () {
const RUN_KEY = "ovipets_old_across_running";
const FR_KEY = "ovipets_old_across_friends";
const FI_KEY = "ovipets_old_across_friend_index";
const EG_KEY = "ovipets_old_across_eggs";
const EI_KEY = "ovipets_old_across_egg_index";
function log(...args) {
console.log(
"%c[OVIPETS-OLD-ACROSS]",
"background:#444;color:#bada55;",
...args
);
}
function startBot() {
log("Starting Old Across bot");
sessionStorage.setItem(RUN_KEY, "true");
sessionStorage.removeItem(FR_KEY);
sessionStorage.setItem(FI_KEY, "0");
sessionStorage.removeItem(EG_KEY);
sessionStorage.setItem(EI_KEY, "0");
hideResume();
main();
}
function stopBot() {
sessionStorage.removeItem(RUN_KEY);
log("Stopped Old Across bot");
}
function resumeBot() {
sessionStorage.setItem(RUN_KEY, "true");
hideResume();
stepEggIndex();
navigateEggProfile();
}
function showResume() {
const btn = document.getElementById("ovipets-old-across-resume");
if (btn) btn.style.display = "inline-block";
}
function hideResume() {
const btn = document.getElementById("ovipets-old-across-resume");
if (btn) btn.style.display = "none";
}
function isRunning() {
return sessionStorage.getItem(RUN_KEY) === "true";
}
function getFriends() {
try {
return JSON.parse(sessionStorage.getItem(FR_KEY)) || [];
} catch {
return [];
}
}
function setFriends(a) {
sessionStorage.setItem(FR_KEY, JSON.stringify(a));
}
function getFI() {
return parseInt(sessionStorage.getItem(FI_KEY) || "0", 10);
}
function setFI(i) {
sessionStorage.setItem(FI_KEY, String(i));
log(`Friend index set to ${i}`);
}
function stepFI() {
setFI(getFI() + 1);
}
function getEggs() {
try {
return JSON.parse(sessionStorage.getItem(EG_KEY)) || [];
} catch {
return [];
}
}
function setEggs(a) {
sessionStorage.setItem(EG_KEY, JSON.stringify(a));
}
function getEI() {
return parseInt(sessionStorage.getItem(EI_KEY) || "0", 10);
}
function setEI(i) {
sessionStorage.setItem(EI_KEY, String(i));
}
function stepEggIndex() {
setEI(getEI() + 1);
}
function collectFriends() {
if (!isRunning()) return;
log("Collecting friends");
const ul =
document.querySelector("body div#friends-list-modal ul") ||
document.querySelector("body div.friends-list ul") ||
document.querySelector("body ul");
if (!ul) {
log("Friends list not found");
stopBot();
return;
}
const friends = Array.from(ul.querySelectorAll("a.user.avatar"))
.map((a) => a.href)
.filter(Boolean)
.filter((h) => h !== window.location.origin + window.location.hash);
log(`Found ${friends.length} friends`);
setFriends(friends);
navigateToNextFriend();
}
function navigateToNextFriend() {
if (!isRunning()) return;
const friends = getFriends();
let idx = getFI();
if (idx >= friends.length) {
log("Restarting friends at 0");
idx = 0;
setFI(0);
}
const friendUrl = friends[idx];
if (!friendUrl || typeof friendUrl !== "string") {
log(`Invalid URL at ${idx}, skipping`);
stepFI();
setTimeout(navigateToNextFriend, 300);
return;
}
let url = friendUrl.replace("#!/", "#!/?src=pets&sub=hatchery&usr=");
if (url.includes("&usr=?usr=")) url = url.replace("&usr=?usr=", "&usr=");
log(`Go to friend ${idx + 1}/${friends.length}`);
location.href = url;
}
function hideAnnoyingDiv() {
const annoyingSection = document.querySelector("#unnamed");
if (annoyingSection) {
annoyingSection.style.display = "none";
log("Hiding annoying section");
}
}
function collectEggs(retries = 3) {
if (!isRunning()) return;
setTimeout(function () {
hideAnnoyingDiv();
log("Collecting eggs (enhanced scan)");
const progressiveScan = async () => {
const found = new Set();
for (let i = 0; i < retries; i++) {
log(`Scan attempt ${i + 1}/${retries}`);
var usr = document.querySelector("#src_pets")?.getAttribute("usr");
while (!usr) {
await new Promise((r) => setTimeout(r, 100));
usr = document.querySelector("#src_pets")?.getAttribute("usr");
}
const response = await fetch(
`https://ovipets.com/?src=pets&sub=hatchery&usr=${usr}&!=jQuery36001195479668276287_1748584681454&_=1748584681455`
);
if (!response.ok) {
log("Failed to fetch hatchery page");
continue;
}
log("Response received, parsing HTML");
var text = await response.text();
text = text.replace(/^[^{]*\(/, "").replace(/\);?$/, "");
text = JSON.parse(text);
text = text["output"];
const parser = new DOMParser();
const doc = parser.parseFromString(text, "text/html");
const lis = doc.querySelectorAll('img[title="Turn Egg"]');
lis.forEach((li) => {
const a =
li.parentElement?.parentElement?.parentElement?.querySelector(
"a.pet"
);
if (a) found.add(a.href);
});
}
log(`Found ${found.size} eggs`);
return Array.from(found);
};
(async () => {
let looseDone = false;
async function attempt(n) {
log(`Attempt ${n}/${retries}`);
var lis = await progressiveScan();
if (!looseDone) {
looseDone = true;
document
.querySelectorAll('img[title="Turn Egg"]')
.forEach((img) => {
log("checking img", img);
const li = img.parentElement?.parentElement?.parentElement;
const a = li?.querySelector("a.pet");
if (a) {
lis.push(a);
log("Found!");
}
});
log("Loose fallback");
if (lis.length) {
log(`Loose found ${lis.length}`);
setEggs(lis.map((a) => a.href).filter(Boolean));
return navigateEggProfile();
}
}
if (n < retries) return attempt(n + 1);
log("No eggs β next friend");
stepFI();
navigateToNextFriend();
}
attempt(1);
})();
}, 1500);
}
function navigateEggProfile() {
if (!isRunning()) return;
const eggs = getEggs(),
idx = getEI();
if (idx >= eggs.length) {
log("Eggs done for this friend");
stepFI();
navigateToNextFriend();
return;
}
log(`Go to egg page ${idx + 1}/${eggs.length}`);
location.href = eggs[idx];
}
async function solveAndSubmitAll() {
const dlgSel = 'div.ui-dialog[role="dialog"]',
turnSel = 'button[onclick*="pet_turn_egg"]',
maxR = 2;
for (let a = 1; a <= maxR; a++) {
const dlg = document.querySelector(dlgSel);
if (!dlg) continue;
const img = dlg.querySelector("fieldset img");
if (!img) {
log("No modal image");
break;
}
const url = img.src.replace(/^\/\//, "https://");
log(`Solve attempt ${a}: fetch ${url}`);
const blob = await new Promise((res, rej) =>
GM_xmlhttpRequest({
method: "GET",
url,
responseType: "blob",
onload: (r) => res(r.response),
onerror: (e) => rej(e),
})
);
const form = new FormData();
form.append("file", blob, "egg.jpg");
log("Sending to AI");
const resp = await fetch("http://127.0.0.1:8000/predict", {
method: "POST",
body: form,
});
const { predicted_class } = await resp.json();
log("Predicted", predicted_class);
Array.from(dlg.querySelectorAll("label")).forEach((lbl) => {
if (lbl.textContent.trim() === predicted_class) lbl.click();
});
dlg.querySelector(".ui-dialog-buttonpane button").click();
await new Promise((r) => setTimeout(r, 1000));
const err = Array.from(document.querySelectorAll(dlgSel)).find(
(d) => d.querySelector(".ui-dialog-title")?.innerText === "Error"
);
if (err) {
log("Error modal, retry");
err.querySelector(".ui-dialog-buttonpane button").click();
document.querySelector(turnSel).click();
await new Promise((r) => setTimeout(r, 1000));
continue;
}
break;
}
log("All solved, moving on");
stepEggIndex();
setTimeout(() => {
const prev = location.href;
navigateEggProfile();
setTimeout(() => {
if (location.href === prev) {
log("Stuck, retry nav");
navigateEggProfile();
}
}, 1500);
}, 500);
}
function handleProfile() {
if (!isRunning()) return;
log("On egg profile");
let tries = 0,
max = 6;
(function clickTry() {
const btn = document.querySelector('button[onclick*="pet_turn_egg"]');
if (btn) {
log("Click turn");
btn.click();
setTimeout(async () => {
const dlg = document.querySelector('div.ui-dialog[role="dialog"]');
if (dlg && /Name the Species/.test(dlg.innerHTML)) {
log("Puzzle");
await solveAndSubmitAll();
} else {
log("No puzzle");
stepEggIndex();
navigateEggProfile();
}
}, 800);
} else if (tries++ < max) {
setTimeout(clickTry, 200);
} else {
log("No button");
stepEggIndex();
navigateEggProfile();
}
})();
}
function main() {
if (!isRunning()) return;
const h = location.hash || "";
log("Old Across main", h);
if (h.includes("sub=profile") && h.includes("pet=")) {
handleProfile();
} else if (h.includes("sub=hatchery")) {
collectEggs();
} else {
collectFriends();
}
}
return { startBot, stopBot, resumeBot, main };
})();
// --- Old Ovipets Thorough ---
const OvipetsOldThorough = (function () {
const RUN_KEY = "ovipets_old_thorough_running";
const FR_KEY = "ovipets_old_thorough_friends";
const FI_KEY = "ovipets_old_thorough_friend_index";
const EG_KEY = "ovipets_old_thorough_eggs";
const EI_KEY = "ovipets_old_thorough_egg_index";
function log(...args) {
console.log(
"%c[OVIPETS-OLD-THOROUGH]",
"background:#666;color:#bada55;",
...args
);
}
function startBot() {
log("Starting Old Thorough bot");
sessionStorage.setItem(RUN_KEY, "true");
sessionStorage.removeItem(FR_KEY);
sessionStorage.setItem(FI_KEY, "0");
sessionStorage.removeItem(EG_KEY);
sessionStorage.setItem(EI_KEY, "0");
hideResume();
main();
}
function stopBot() {
sessionStorage.removeItem(RUN_KEY);
log("Stopped Old Thorough bot");
}
function resumeBot() {
sessionStorage.setItem(RUN_KEY, "true");
hideResume();
stepEggIndex();
navigateEggProfile();
}
function showResume() {
const btn = document.getElementById("ovipets-old-thorough-resume");
if (btn) btn.style.display = "inline-block";
}
function hideResume() {
const btn = document.getElementById("ovipets-old-thorough-resume");
if (btn) btn.style.display = "none";
}
function isRunning() {
return sessionStorage.getItem(RUN_KEY) === "true";
}
function getFriends() {
try {
return JSON.parse(sessionStorage.getItem(FR_KEY)) || [];
} catch {
return [];
}
}
function setFriends(a) {
sessionStorage.setItem(FR_KEY, JSON.stringify(a));
}
function getFI() {
return parseInt(sessionStorage.getItem(FI_KEY) || "0", 10);
}
function setFI(i) {
sessionStorage.setItem(FI_KEY, String(i));
log(`Friend index set to ${i}`);
}
function stepFI() {
setFI(getFI() + 1);
}
function getEggs() {
try {
return JSON.parse(sessionStorage.getItem(EG_KEY)) || [];
} catch {
return [];
}
}
function setEggs(a) {
sessionStorage.setItem(EG_KEY, JSON.stringify(a));
}
function getEI() {
return parseInt(sessionStorage.getItem(EI_KEY) || "0", 10);
}
function setEI(i) {
sessionStorage.setItem(EI_KEY, String(i));
}
function stepEggIndex() {
setEI(getEI() + 1);
}
function collectFriends() {
if (!isRunning()) return;
log("Collecting friends");
const ul =
document.querySelector("body div#friends-list-modal ul") ||
document.querySelector("body div.friends-list ul") ||
document.querySelector("body ul");
if (!ul) {
log("Friends list not found");
stopBot();
return;
}
const friends = Array.from(ul.querySelectorAll("a.user.avatar"))
.map((a) => a.href)
.filter(Boolean)
.filter((h) => h !== window.location.origin + window.location.hash);
log(`Found ${friends.length} friends`);
setFriends(friends);
navigateToNextFriend();
}
function navigateToNextFriend() {
if (!isRunning()) return;
const friends = getFriends();
let idx = getFI();
if (idx >= friends.length) {
log("Restarting friends at 0");
idx = 0;
setFI(0);
}
const friendUrl = friends[idx];
if (!friendUrl || typeof friendUrl !== "string") {
log(`Invalid URL at ${idx}, skipping`);
stepFI();
setTimeout(navigateToNextFriend, 500);
return;
}
let url = friendUrl.replace("#!/", "#!/?src=pets&sub=hatchery&usr=");
if (url.includes("&usr=?usr=")) url = url.replace("&usr=?usr=", "&usr=");
log(`Go to friend ${idx + 1}/${friends.length}`);
location.href = url;
}
function hideAnnoyingDiv() {
const annoyingSection = document.querySelector("#unnamed");
if (annoyingSection) {
annoyingSection.style.display = "none";
log("Hiding annoying section");
}
}
function collectEggs(retries = 3) {
if (!isRunning()) return;
setTimeout(function () {
hideAnnoyingDiv();
log("Collecting eggs (thorough scan)");
const progressiveScan = async () => {
const found = new Set();
const stepY = window.innerHeight * 0.1;
log("--- SCAN DOWN ---");
for (let y = 0; y <= document.body.scrollHeight; y += stepY) {
window.scrollTo(0, y);
}
hideAnnoyingDiv();
window.scrollTo(0, 0);
log(`Scan complete, found ${found.size} li`);
return Array.from(
document.querySelectorAll(
"#hatchery > div > form > ul > li > div > a"
)
);
};
(async () => {
let looseDone = false;
async function attempt(n) {
log(`Attempt ${n}/${retries}`);
var lis = await progressiveScan();
looseDone = true;
log("Thorough fallback");
if (lis.length) {
log(`Thorough found ${lis.length}`);
setEggs(lis.map((a) => a.href).filter(Boolean));
return navigateEggProfile();
}
if (n < retries) return attempt(n + 1);
log("No eggs β next friend");
stepFI();
navigateToNextFriend();
}
attempt(1);
})();
}, 1500);
}
function navigateEggProfile() {
if (!isRunning()) return;
const eggs = getEggs(),
idx = getEI();
if (idx >= eggs.length) {
log("Eggs done for this friend");
stepFI();
navigateToNextFriend();
return;
}
log(`Go to egg page ${idx + 1}/${eggs.length}`);
location.href = eggs[idx];
}
async function solveAndSubmitAll() {
const dlgSel = 'div.ui-dialog[role="dialog"]',
turnSel = 'button[onclick*="pet_turn_egg"]',
maxR = 2;
for (let a = 1; a <= maxR; a++) {
const dlg = document.querySelector(dlgSel);
if (!dlg) continue;
const img = dlg.querySelector("fieldset img");
if (!img) {
log("No modal image");
break;
}
const url = img.src.replace(/^\/\//, "https://");
log(`Solve attempt ${a}: fetch ${url}`);
const blob = await new Promise((res, rej) =>
GM_xmlhttpRequest({
method: "GET",
url,
responseType: "blob",
onload: (r) => res(r.response),
onerror: (e) => rej(e),
})
);
const form = new FormData();
form.append("file", blob, "egg.jpg");
log("Sending to AI");
const resp = await fetch("http://127.0.0.1:8000/predict", {
method: "POST",
body: form,
});
const { predicted_class } = await resp.json();
log("Predicted", predicted_class);
Array.from(dlg.querySelectorAll("label")).forEach((lbl) => {
if (lbl.textContent.trim() === predicted_class) lbl.click();
});
dlg.querySelector(".ui-dialog-buttonpane button").click();
await new Promise((r) => setTimeout(r, 1000));
const err = Array.from(document.querySelectorAll(dlgSel)).find(
(d) => d.querySelector(".ui-dialog-title")?.innerText === "Error"
);
if (err) {
log("Error modal, retry");
err.querySelector(".ui-dialog-buttonpane button").click();
document.querySelector(turnSel).click();
await new Promise((r) => setTimeout(r, 1000));
continue;
}
break;
}
log("All solved, moving on");
stepEggIndex();
setTimeout(() => {
const prev = location.href;
navigateEggProfile();
setTimeout(() => {
if (location.href === prev) {
log("Stuck, retry nav");
navigateEggProfile();
}
}, 1500);
}, 500);
}
function handleProfile() {
if (!isRunning()) return;
log("On egg profile");
let tries = 0,
max = 2;
(function clickTry() {
const btn = document.querySelector('button[onclick*="pet_turn_egg"]');
if (btn) {
log("Click turn");
btn.click();
setTimeout(async () => {
const dlg = document.querySelector('div.ui-dialog[role="dialog"]');
if (dlg && /Name the Species/.test(dlg.innerHTML)) {
log("Puzzle");
await solveAndSubmitAll();
} else {
log("No puzzle");
stepEggIndex();
navigateEggProfile();
}
}, 800);
} else if (tries++ < max) {
setTimeout(clickTry, 100);
} else {
log("No button");
stepEggIndex();
navigateEggProfile();
}
})();
}
function main() {
if (!isRunning()) return;
const h = location.hash || "";
log("Old Thorough main", h);
if (h.includes("sub=profile") && h.includes("pet=")) {
handleProfile();
} else if (h.includes("sub=hatchery")) {
collectEggs();
} else {
collectFriends();
}
}
return { startBot, stopBot, resumeBot, main };
})();
// --- Adopter Module ---
const Adopter = (function () {
const RUN_KEY = "adopter_running";
const PETS_KEY = "adopter_pets";
const IDX_KEY = "adopter_index";
const BASE_KEY = "adopter_base_href";
const UL_KEY = "adopter_selected_ul";
function log(...args) {
console.log("%c[ADOPTER]", "background:#ff6600;color:#fff;", ...args);
}
function startBot() {
log(
"Starting Adopter - Please click on the UL element containing the pets"
);
// Store the current location as base
sessionStorage.setItem(BASE_KEY, location.href);
sessionStorage.setItem(RUN_KEY, "true");
sessionStorage.setItem(IDX_KEY, "0");
sessionStorage.removeItem(PETS_KEY);
sessionStorage.removeItem(UL_KEY);
// Enable UL selection mode
enableULSelection();
}
function stopBot() {
sessionStorage.removeItem(RUN_KEY);
sessionStorage.removeItem(UL_KEY);
disableULSelection();
log("Stopped Adopter");
}
function isRunning() {
return sessionStorage.getItem(RUN_KEY) === "true";
}
function getBase() {
return sessionStorage.getItem(BASE_KEY);
}
function getPets() {
try {
return JSON.parse(sessionStorage.getItem(PETS_KEY)) || [];
} catch {
return [];
}
}
function savePets(pets) {
sessionStorage.setItem(PETS_KEY, JSON.stringify(pets));
}
function getIndex() {
return parseInt(sessionStorage.getItem(IDX_KEY) || "0", 10);
}
function setIndex(i) {
sessionStorage.setItem(IDX_KEY, String(i));
}
function getSelectedUL() {
return sessionStorage.getItem(UL_KEY);
}
function setSelectedUL(selector) {
sessionStorage.setItem(UL_KEY, selector);
}
function enableULSelection() {
// Create visual indicators
const style = document.createElement("style");
style.id = "adopter-ul-selection-style";
style.textContent = `
.adopter-ul-highlight {
outline: 3px solid #ff6600 !important;
outline-offset: 2px !important;
cursor: pointer !important;
position: relative !important;
}
.adopter-ul-highlight::before {
content: "Click to select this list for adoption";
position: absolute;
top: -25px;
left: 0;
background: #ff6600;
color: white;
padding: 2px 8px;
font-size: 12px;
border-radius: 3px;
white-space: nowrap;
z-index: 10000;
}
.adopter-selection-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.3);
z-index: 9999;
pointer-events: none;
}
.adopter-instruction {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #ff6600;
color: white;
padding: 20px;
border-radius: 8px;
font-family: monospace;
font-size: 16px;
z-index: 10001;
text-align: center;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
}
`;
document.head.appendChild(style);
// Create overlay
const overlay = document.createElement("div");
overlay.className = "adopter-selection-overlay";
overlay.id = "adopter-overlay";
document.body.appendChild(overlay);
// Create instruction
const instruction = document.createElement("div");
instruction.className = "adopter-instruction";
instruction.id = "adopter-instruction";
instruction.innerHTML = `
π Adopter Setup
Hover over UL elements and click the one containing the pets you want to adopt
Press ESC to cancel
`;
document.body.appendChild(instruction);
// Find all UL elements and add hover effects
const uls = document.querySelectorAll("ul");
uls.forEach((ul) => {
ul.addEventListener("mouseenter", handleULHover);
ul.addEventListener("mouseleave", handleULLeave);
ul.addEventListener("click", handleULClick);
});
// ESC to cancel
document.addEventListener("keydown", handleEscapeKey);
log(
`Found ${uls.length} UL elements - hover to highlight, click to select`
);
}
function disableULSelection() {
// Remove style
const style = document.getElementById("adopter-ul-selection-style");
if (style) style.remove();
// Remove overlay and instruction
const overlay = document.getElementById("adopter-overlay");
if (overlay) overlay.remove();
const instruction = document.getElementById("adopter-instruction");
if (instruction) instruction.remove();
// Remove event listeners from all ULs
const uls = document.querySelectorAll("ul");
uls.forEach((ul) => {
ul.removeEventListener("mouseenter", handleULHover);
ul.removeEventListener("mouseleave", handleULLeave);
ul.removeEventListener("click", handleULClick);
ul.classList.remove("adopter-ul-highlight");
});
document.removeEventListener("keydown", handleEscapeKey);
}
function handleULHover(event) {
event.target.classList.add("adopter-ul-highlight");
}
function handleULLeave(event) {
event.target.classList.remove("adopter-ul-highlight");
}
function handleULClick(event) {
event.preventDefault();
event.stopPropagation();
const ul = event.target;
// Remove highlight class before generating selector
ul.classList.remove("adopter-ul-highlight");
// Generate a unique selector for this UL
let selector = generateUniqueSelector(ul);
log(`Selected UL with selector: ${selector}`);
// Test the selector immediately
const testElement = document.querySelector(selector);
if (testElement === ul) {
log("β Selector test passed");
} else {
log("β Selector test failed, trying alternative...");
// Try a more specific approach
if (ul.parentElement) {
const parent = ul.parentElement;
if (parent.id) {
selector = `#${parent.id} ul:nth-child(${
Array.from(parent.children).indexOf(ul) + 1
})`;
} else if (parent.className) {
const classes = parent.className.split(" ").filter((c) => c.trim());
selector = `.${classes.join(".")} ul:nth-child(${
Array.from(parent.children).indexOf(ul) + 1
})`;
} else {
// Ultimate fallback - store the innerHTML signature
const signature = ul.innerHTML.substring(0, 100);
selector = `ul-signature:${btoa(signature)}`;
// Store the actual element reference temporarily
window.adopterSelectedUL = ul;
log("Using element reference fallback");
}
}
log(`Alternative selector: ${selector}`);
}
setSelectedUL(selector);
// Clean up selection mode
disableULSelection();
// Start collecting pets from the selected UL
setTimeout(() => {
collectPets();
}, 300);
}
function handleEscapeKey(event) {
if (event.key === "Escape") {
log("Selection cancelled");
stopBot();
}
}
function generateUniqueSelector(element) {
// Remove the highlight class before generating selector
element.classList.remove("adopter-ul-highlight");
// Try ID first
if (element.id) {
return `#${element.id}`;
}
// Try class combination (excluding our highlight class)
if (element.className) {
const classes = element.className
.split(" ")
.filter((c) => c.trim() && c !== "adopter-ul-highlight");
if (classes.length > 0) {
let selector = `ul.${classes.join(".")}`;
if (document.querySelectorAll(selector).length === 1) {
return selector;
}
}
}
// Try parent-child relationship
let parent = element.parentElement;
if (parent) {
if (parent.id) {
return `#${parent.id} > ul`;
}
if (parent.className) {
const classes = parent.className.split(" ").filter((c) => c.trim());
if (classes.length > 0) {
let selector = `.${classes.join(".")} > ul`;
if (document.querySelectorAll(selector).length === 1) {
return selector;
}
}
}
}
// Try to find position among siblings
const siblings = Array.from(element.parentElement?.children || []);
const ulSiblings = siblings.filter((el) => el.tagName === "UL");
if (ulSiblings.length === 1) {
// Only UL child
if (parent && parent.id) {
return `#${parent.id} ul`;
}
if (parent && parent.className) {
const classes = parent.className.split(" ").filter((c) => c.trim());
if (classes.length > 0) {
return `.${classes.join(".")} ul`;
}
}
} else {
// Multiple UL siblings, use nth-of-type
const index = ulSiblings.indexOf(element) + 1;
if (parent && parent.id) {
return `#${parent.id} ul:nth-of-type(${index})`;
}
if (parent && parent.className) {
const classes = parent.className.split(" ").filter((c) => c.trim());
if (classes.length > 0) {
return `.${classes.join(".")} ul:nth-of-type(${index})`;
}
}
}
// Final fallback: use XPath-like approach
function getElementPath(el) {
if (el.id) return `#${el.id}`;
if (el === document.body) return "body";
const parent = el.parentElement;
if (!parent) return el.tagName.toLowerCase();
const siblings = Array.from(parent.children);
const sameTagSiblings = siblings.filter(
(sibling) => sibling.tagName === el.tagName
);
if (sameTagSiblings.length === 1) {
return `${getElementPath(parent)} > ${el.tagName.toLowerCase()}`;
} else {
const index = sameTagSiblings.indexOf(el) + 1;
return `${getElementPath(
parent
)} > ${el.tagName.toLowerCase()}:nth-of-type(${index})`;
}
}
return getElementPath(element);
}
function collectPets() {
if (!isRunning()) return;
log("Collecting adoption pets from selected UL");
const ulSelector = getSelectedUL();
if (!ulSelector) {
log("No UL selected");
stopBot();
return;
}
let ul;
// Handle special fallback selector
if (ulSelector.startsWith("ul-signature:")) {
ul = window.adopterSelectedUL;
if (!ul) {
log("Element reference lost");
stopBot();
return;
}
} else {
ul = document.querySelector(ulSelector);
}
if (!ul) {
log(`Selected UL not found: ${ulSelector}`);
stopBot();
return;
}
log(`Found UL element with ${ul.children.length} child elements`);
// Extract all pet links from li elements
const petLinks = [];
const lis = ul.querySelectorAll("li");
log(`Scanning ${lis.length} li elements for pet links...`);
lis.forEach((li, index) => {
const petLink =
li.querySelector('a.pet[href*="pet="]') ||
li.querySelector('a[href*="pet="]') ||
li.querySelector('a[href*="sub=profile"]');
if (petLink && petLink.href) {
petLinks.push(petLink.href);
log(`Found pet link ${index + 1}: ${petLink.href}`);
}
});
if (!petLinks.length) {
log("No adoption pets found in selected UL");
log("UL HTML preview:", ul.innerHTML.substring(0, 500));
stopBot();
return;
}
log(`Found ${petLinks.length} adoption pets`);
savePets(petLinks);
goToPet();
}
function goToPet() {
if (!isRunning()) return;
const pets = getPets();
const idx = getIndex();
if (idx >= pets.length) {
log("All pets processed - adoption complete!");
stopBot();
location.href = getBase();
return;
}
log(`π Going to adopt pet ${idx + 1}/${pets.length}...`);
location.href = pets[idx];
}
function handlePetProfile() {
if (!isRunning()) return;
log("π Looking for adoption button on pet profile...");
let tries = 0;
const maxTries = 10;
const tryAdoptButton = () => {
// Look for adoption button
let adoptBtn = null;
// Method 1: Look for button with "adopt" text
const buttons = document.querySelectorAll(
'button, input[type="button"], input[type="submit"]'
);
for (let btn of buttons) {
if (
btn.textContent.toLowerCase().includes("adopt") ||
btn.value?.toLowerCase().includes("adopt") ||
btn.onclick?.toString().includes("adopt")
) {
adoptBtn = btn;
break;
}
}
// Method 2: Look for links with adopt in onclick
if (!adoptBtn) {
const links = document.querySelectorAll(
'a[onclick*="adopt"], a[href*="adopt"]'
);
if (links.length > 0) {
adoptBtn = links[0];
}
}
if (adoptBtn) {
log("β Found adoption button, clicking...");
adoptBtn.click();
// Wait for adoption modal or confirmation
setTimeout(() => {
if (isRunning()) {
handleAdoptionModal();
}
}, 300);
} else if (tries++ < maxTries) {
log(
`β³ Adoption button not found, retrying... (${tries}/${maxTries})`
);
setTimeout(tryAdoptButton, 300);
} else {
log("β No adoption button found, moving to next pet");
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 300);
}
};
// Initial delay to let page load
setTimeout(tryAdoptButton, 300);
}
function handleAdoptionModal() {
if (!isRunning()) return;
log("π Looking for adoption confirmation modal...");
let modalTries = 0;
const maxModalTries = 10;
const tryModal = () => {
let confirmBtn = null;
// Method 1: Look for visible dialog with adoption confirmation
const modals = document.querySelectorAll(
'div.ui-dialog[role="dialog"]'
);
for (let modal of modals) {
if (modal.style.display !== "none" && modal.offsetParent !== null) {
// Check if this modal contains adoption-related content
if (
modal.innerHTML.includes("adopt") ||
modal.innerHTML.includes("Adopt")
) {
const buttonPane = modal.querySelector(".ui-dialog-buttonpane");
if (buttonPane) {
confirmBtn = buttonPane.querySelector("button:first-child");
if (confirmBtn) {
log("Found adoption modal confirmation button");
break;
}
}
}
}
}
// Method 2: Look for any visible dialog button as fallback
if (!confirmBtn) {
const dialogButtons = document.querySelectorAll(
".ui-dialog-buttonpane button"
);
for (let btn of dialogButtons) {
if (btn.offsetParent !== null) {
// visible
confirmBtn = btn;
log("Found dialog button via visibility fallback");
break;
}
}
}
if (confirmBtn) {
log("β Found adoption confirmation button, clicking...");
confirmBtn.click();
log("π Adoption confirmed! Moving to next pet...");
// Move to next pet
setTimeout(() => {
if (isRunning()) {
setIndex(getIndex() + 1);
goToPet();
}
}, 300);
} else if (modalTries++ < maxModalTries) {
log(
`β³ Modal button not found, retrying... (${modalTries}/${maxModalTries})`
);
setTimeout(tryModal, 300);
} else {
log("β No modal confirmation button found, moving to next pet");
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 300);
}
};
tryModal();
}
function main() {
if (!isRunning()) return;
const href = location.href;
const base = getBase();
log("π Adopter main executing...", href);
// If we're on a pet profile page
if (href.includes("sub=profile") && href.includes("pet=")) {
log("π On pet profile, looking for adoption button");
setTimeout(() => {
if (isRunning()) {
handlePetProfile();
}
}, 300);
}
// If we're back at the base page and haven't collected pets yet
else if (href === base && !sessionStorage.getItem(PETS_KEY)) {
log("π At base, need to collect pets");
setTimeout(() => {
if (isRunning()) {
collectPets();
}
}, 300);
}
// If we're back at the base page and have pets collected
else if (href === base) {
log("π At base, have pets, continuing...");
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 300);
}
// If we're on a different page
else {
const pets = getPets();
if (pets.length > 0) {
log("π On different page, going to next pet");
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 300);
} else {
log("π No pets collected, returning to base");
location.href = base;
}
}
}
return { startBot, stopBot, main };
})();
// --- Breeder Module ---
const Breeder = (function () {
const RUN_KEY = "breeder_running";
const PETS_KEY = "breeder_pets";
const IDX_KEY = "breeder_index";
const BASE_KEY = "breeder_base_href";
const UL_KEY = "breeder_selected_ul";
const JUST_BREAD = "breeder_just_bred";
function log(...args) {
console.log("%c[BREEDER]", "background:#ff1493;color:#fff;", ...args);
}
function startBot() {
log(
"Starting Breeder - Please click on the UL element containing the pets"
);
// Store the current location as base
sessionStorage.setItem(BASE_KEY, location.href);
sessionStorage.setItem(RUN_KEY, "true");
sessionStorage.setItem(IDX_KEY, "0");
sessionStorage.setItem(JUST_BREAD, "false");
sessionStorage.removeItem(PETS_KEY);
sessionStorage.removeItem(UL_KEY);
// Enable UL selection mode
enableULSelection();
}
function stopBot() {
sessionStorage.removeItem(RUN_KEY);
sessionStorage.removeItem(UL_KEY);
sessionStorage.removeItem(JUST_BREAD);
disableULSelection();
log("Stopped Breeder");
}
function isRunning() {
return sessionStorage.getItem(RUN_KEY) === "true";
}
function getBase() {
return sessionStorage.getItem(BASE_KEY);
}
function getPets() {
try {
return JSON.parse(sessionStorage.getItem(PETS_KEY)) || [];
} catch {
return [];
}
}
function savePets(pets) {
sessionStorage.setItem(PETS_KEY, JSON.stringify(pets));
}
function getIndex() {
return parseInt(sessionStorage.getItem(IDX_KEY) || "0", 10);
}
function setIndex(i) {
sessionStorage.setItem(IDX_KEY, String(i));
}
function getSelectedUL() {
return sessionStorage.getItem(UL_KEY);
}
function setSelectedUL(selector) {
sessionStorage.setItem(UL_KEY, selector);
}
function enableULSelection() {
// Create visual indicators
const style = document.createElement("style");
style.id = "breeder-ul-selection-style";
style.textContent = `
.breeder-ul-highlight {
outline: 3px solid #ff1493 !important;
outline-offset: 2px !important;
cursor: pointer !important;
position: relative !important;
}
.breeder-ul-highlight::before {
content: "Click to select this list for breeding";
position: absolute;
top: -25px;
left: 0;
background: #ff1493;
color: white;
padding: 2px 8px;
font-size: 12px;
border-radius: 3px;
white-space: nowrap;
z-index: 10000;
}
.breeder-selection-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.3);
z-index: 9999;
pointer-events: none;
}
.breeder-instruction {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #ff1493;
color: white;
padding: 20px;
border-radius: 8px;
font-family: monospace;
font-size: 16px;
z-index: 10001;
text-align: center;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
}
`;
document.head.appendChild(style);
// Create overlay
const overlay = document.createElement("div");
overlay.className = "breeder-selection-overlay";
overlay.id = "breeder-overlay";
document.body.appendChild(overlay);
// Create instruction
const instruction = document.createElement("div");
instruction.className = "breeder-instruction";
instruction.id = "breeder-instruction";
instruction.innerHTML = `
π Breeder Setup
Hover over UL elements and click the one containing the pets you want to breed
Press ESC to cancel
`;
document.body.appendChild(instruction);
// Find all UL elements and add hover effects
const uls = document.querySelectorAll("ul");
uls.forEach((ul) => {
ul.addEventListener("mouseenter", handleULHover);
ul.addEventListener("mouseleave", handleULLeave);
ul.addEventListener("click", handleULClick);
});
// ESC to cancel
document.addEventListener("keydown", handleEscapeKey);
log(
`Found ${uls.length} UL elements - hover to highlight, click to select`
);
}
function disableULSelection() {
// Remove style
const style = document.getElementById("breeder-ul-selection-style");
if (style) style.remove();
// Remove overlay and instruction
const overlay = document.getElementById("breeder-overlay");
if (overlay) overlay.remove();
const instruction = document.getElementById("breeder-instruction");
if (instruction) instruction.remove();
// Remove event listeners from all ULs
const uls = document.querySelectorAll("ul");
uls.forEach((ul) => {
ul.removeEventListener("mouseenter", handleULHover);
ul.removeEventListener("mouseleave", handleULLeave);
ul.removeEventListener("click", handleULClick);
ul.classList.remove("breeder-ul-highlight");
});
document.removeEventListener("keydown", handleEscapeKey);
}
function handleULHover(event) {
event.target.classList.add("breeder-ul-highlight");
}
function handleULLeave(event) {
event.target.classList.remove("breeder-ul-highlight");
}
function handleULClick(event) {
event.preventDefault();
event.stopPropagation();
const ul = event.target;
// Remove highlight class before generating selector
ul.classList.remove("breeder-ul-highlight");
// Generate a unique selector for this UL
let selector = generateUniqueSelector(ul);
log(`Selected UL with selector: ${selector}`);
// Test the selector immediately
const testElement = document.querySelector(selector);
if (testElement === ul) {
log("β Selector test passed");
} else {
log("β Selector test failed, trying alternative...");
// Try a more specific approach
if (ul.parentElement) {
const parent = ul.parentElement;
if (parent.id) {
selector = `#${parent.id} ul:nth-child(${
Array.from(parent.children).indexOf(ul) + 1
})`;
} else if (parent.className) {
const classes = parent.className.split(" ").filter((c) => c.trim());
selector = `.${classes.join(".")} ul:nth-child(${
Array.from(parent.children).indexOf(ul) + 1
})`;
} else {
// Ultimate fallback - store the innerHTML signature
const signature = ul.innerHTML.substring(0, 100);
selector = `ul-signature:${btoa(signature)}`;
// Store the actual element reference temporarily
window.breederSelectedUL = ul;
log("Using element reference fallback");
}
}
log(`Alternative selector: ${selector}`);
}
setSelectedUL(selector);
// Clean up selection mode
disableULSelection();
// Start collecting pets from the selected UL
setTimeout(() => {
collectPets();
}, 300);
}
function handleEscapeKey(event) {
if (event.key === "Escape") {
log("Selection cancelled");
stopBot();
}
}
function generateUniqueSelector(element) {
// Remove the highlight class before generating selector
element.classList.remove("breeder-ul-highlight");
// Try ID first
if (element.id) {
return `#${element.id}`;
}
// Try class combination (excluding our highlight class)
if (element.className) {
const classes = element.className
.split(" ")
.filter((c) => c.trim() && c !== "breeder-ul-highlight");
if (classes.length > 0) {
let selector = `ul.${classes.join(".")}`;
if (document.querySelectorAll(selector).length === 1) {
return selector;
}
}
}
// Try parent-child relationship
let parent = element.parentElement;
if (parent) {
if (parent.id) {
return `#${parent.id} > ul`;
}
if (parent.className) {
const classes = parent.className.split(" ").filter((c) => c.trim());
if (classes.length > 0) {
let selector = `.${classes.join(".")} > ul`;
if (document.querySelectorAll(selector).length === 1) {
return selector;
}
}
}
}
// Try to find position among siblings
const siblings = Array.from(element.parentElement?.children || []);
const ulSiblings = siblings.filter((el) => el.tagName === "UL");
if (ulSiblings.length === 1) {
// Only UL child
if (parent && parent.id) {
return `#${parent.id} ul`;
}
if (parent && parent.className) {
const classes = parent.className.split(" ").filter((c) => c.trim());
if (classes.length > 0) {
return `.${classes.join(".")} ul`;
}
}
} else {
// Multiple UL siblings, use nth-of-type
const index = ulSiblings.indexOf(element) + 1;
if (parent && parent.id) {
return `#${parent.id} ul:nth-of-type(${index})`;
}
if (parent && parent.className) {
const classes = parent.className.split(" ").filter((c) => c.trim());
if (classes.length > 0) {
return `.${classes.join(".")} ul:nth-of-type(${index})`;
}
}
}
// Final fallback: use XPath-like approach
function getElementPath(el) {
if (el.id) return `#${el.id}`;
if (el === document.body) return "body";
const parent = el.parentElement;
if (!parent) return el.tagName.toLowerCase();
const siblings = Array.from(parent.children);
const sameTagSiblings = siblings.filter(
(sibling) => sibling.tagName === el.tagName
);
if (sameTagSiblings.length === 1) {
return `${getElementPath(parent)} > ${el.tagName.toLowerCase()}`;
} else {
const index = sameTagSiblings.indexOf(el) + 1;
return `${getElementPath(
parent
)} > ${el.tagName.toLowerCase()}:nth-of-type(${index})`;
}
}
return getElementPath(element);
}
function collectPets() {
if (!isRunning()) return;
log("Collecting breeding pets from selected UL");
const ulSelector = getSelectedUL();
if (!ulSelector) {
log("No UL selected");
stopBot();
return;
}
let ul;
// Handle special fallback selector
if (ulSelector.startsWith("ul-signature:")) {
ul = window.breederSelectedUL;
if (!ul) {
log("Element reference lost");
stopBot();
return;
}
} else {
ul = document.querySelector(ulSelector);
}
if (!ul) {
log(`Selected UL not found: ${ulSelector}`);
stopBot();
return;
}
log(`Found UL element with ${ul.children.length} child elements`);
// Extract all pet links from li elements
const petLinks = [];
const lis = ul.querySelectorAll("li");
log(`Scanning ${lis.length} li elements for pet links...`);
lis.forEach((li, index) => {
const petLink =
li.querySelector('a.pet[href*="pet="]') ||
li.querySelector('a[href*="pet="]') ||
li.querySelector('a[href*="sub=profile"]');
if (petLink && petLink.href) {
petLinks.push(petLink.href);
log(`Found pet link ${index + 1}: ${petLink.href}`);
}
});
if (!petLinks.length) {
log("No breeding pets found in selected UL");
log("UL HTML preview:", ul.innerHTML.substring(0, 500));
stopBot();
return;
}
log(`Found ${petLinks.length} breeding pets`);
savePets(petLinks);
goToPet();
}
function goToPet() {
if (!isRunning()) return;
const pets = getPets();
const idx = getIndex();
if (idx >= pets.length) {
log("All pets processed - breeding complete!");
stopBot();
location.href = getBase();
return;
}
log(`πΎ Going to pet ${idx + 1}/${pets.length}...`);
location.href = pets[idx];
}
function handlePetProfile() {
if (!isRunning()) return;
log("π Looking for breeding tab on pet profile...");
let tries = 0;
const maxTries = 1; // Increased wait time
const tryBreedingTab = () => {
if (!isRunning()) return;
// Try multiple selectors for the breeding tab
let breedingTab = null;
// Method 1: Look for the specific li with breeding panel attribute
const breedingLi = document.querySelector(
'#tabs > div > form > div > ul > li[panel*="sec=breeding"]'
);
if (breedingLi) {
breedingTab = breedingLi.querySelector("a.ui-tabs-anchor");
}
// Method 2: Look for tab with "Breeding" text
if (!breedingTab) {
const tabs = document.querySelectorAll("#tabs a.ui-tabs-anchor");
for (let tab of tabs) {
if (tab.textContent.trim().toLowerCase().includes("breeding")) {
breedingTab = tab;
break;
}
}
}
// Method 3: Try the specific selector you provided
if (!breedingTab) {
breedingTab = document.querySelector("#ui-id-35");
}
// Method 4: Look for any tab with breeding in the href
if (!breedingTab) {
const allTabs = document.querySelectorAll(
'#tabs a[href*="breeding"], #tabs a[href*="Breeding"]'
);
if (allTabs.length > 0) {
breedingTab = allTabs[0];
}
}
if (breedingTab) {
log("β Found breeding tab, clicking...");
breedingTab.click();
// Wait longer for breeding section to load
setTimeout(() => {
if (isRunning()) {
handleBreedingSection();
}
}, 300); // Increased wait time
} else if (tries++ < maxTries) {
log(`β³ Breeding tab not found, retrying... (${tries}/${maxTries})`);
setTimeout(tryBreedingTab, 300); // Wait longer between retries
} else {
log("β No breeding tab found after all attempts, skipping this pet");
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 300);
}
};
// Initial delay to let page load
setTimeout(tryBreedingTab, 300);
}
// Replace the handleBreedingModal function in the Breeder module:
function handleBreedingModal() {
if (!isRunning()) return;
log("π Looking for breeding confirmation modal...");
let modalTries = 0;
const maxModalTries = 15;
const tryModal = () => {
if (!isRunning()) return;
let confirmBtn = null;
// Method 1: Look for the specific breeding modal button
confirmBtn = document.querySelector(
"body > div.ui-dialog.ui-corner-all.ui-widget.ui-widget-content.ui-front.ui-dialog-buttons.ui-draggable.ui-resizable > div.ui-dialog-buttonpane.ui-widget-content.ui-helper-clearfix > div > button:nth-child(1)"
);
// Method 2: Look for any visible dialog with breeding confirmation
if (!confirmBtn) {
const modals = document.querySelectorAll(
'div.ui-dialog[role="dialog"]'
);
for (let modal of modals) {
if (modal.style.display !== "none" && modal.offsetParent !== null) {
// Check if this modal contains breeding-related content
if (
modal.innerHTML.includes("breed") ||
modal.innerHTML.includes("Breed")
) {
const buttonPane = modal.querySelector(".ui-dialog-buttonpane");
if (buttonPane) {
confirmBtn = buttonPane.querySelector("button:first-child");
if (confirmBtn) {
log(
"Found breeding modal confirmation button via content search"
);
break;
}
}
}
}
}
}
// Method 3: Look for any visible dialog button as fallback
if (!confirmBtn) {
const dialogButtons = document.querySelectorAll(
".ui-dialog-buttonpane button"
);
for (let btn of dialogButtons) {
if (btn.offsetParent !== null) {
// visible
confirmBtn = btn;
log("Found dialog button via visibility fallback");
break;
}
}
}
if (confirmBtn) {
log("β Found breeding confirmation button, clicking...");
// set just bred flag
sessionStorage.setItem(JUST_BREAD, "true");
confirmBtn.click();
log(
"π Breeding confirmed! Staying on same pet to find more partners..."
);
} else if (modalTries++ < maxModalTries) {
log(
`β³ Modal button not found, retrying... (${modalTries}/${maxModalTries})`
);
setTimeout(tryModal, 300);
} else {
log("β No modal confirmation button found, moving to next pet");
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 300);
}
};
tryModal();
}
// Also update the handleBreedingSection function to handle "no more partners" case:
function handleBreedingSection() {
if (!isRunning()) return;
log("π Looking for breeding partners...");
let attempts = 0;
const maxAttempts = 1;
const findBreedingPartners = () => {
if (!isRunning()) return;
// look for a feeding link
/*
*/
// wait 100 ms
setTimeout(() => {
if (!isRunning()) return;
}, 100);
let feedingButton = document.querySelector(
'button[onclick*="pet_feed"]'
);
if (feedingButton) {
log("β Found feeding button, clicking...");
feedingButton.click();
}
// find this selector
//
// then for each item in the select, select the item, then check the breeding section
log("π looking for breeding tabs");
var breedingSelector = document.querySelector(
'select[name="enclosure"]'
);
var breedingLinks = [];
if (breedingSelector) {
log("β Found breeding selector, iterating options...");
const options = breedingSelector.querySelectorAll("option");
options.forEach((option) => {
option.selected = true;
log(`π Selected breeding option: ${option.textContent}`);
});
// Try multiple selectors for the breeding UL
let breedingUL = document.querySelector(
"#breeding > div > form > ul"
);
if (!breedingUL) {
// Fallback: look for any UL with breeding-related links
const allULs = document.querySelectorAll("ul");
for (let ul of allULs) {
if (ul.querySelector('a[onclick*="pet_breed"]')) {
breedingUL = ul;
log("Found breeding UL via fallback search");
break;
}
}
}
if (!breedingUL && attempts++ < maxAttempts) {
log(
`β³ Breeding section not loaded yet, retrying... (${attempts}/${maxAttempts})`
);
setTimeout(findBreedingPartners, 300);
return;
}
if (!breedingUL) {
log("β No breeding UL found, moving to next pet");
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 300);
return;
}
// Look for available breeding partners
breedingLinks = breedingUL.querySelectorAll(
'a[onclick*="pet_breed"]'
);
if (!breedingLinks.length) {
log(
"β No more breeding partners available for this pet, moving to next pet"
);
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 300);
return;
}
} else {
// Try multiple selectors for the breeding UL
let breedingUL = document.querySelector(
"#breeding > div > form > ul"
);
if (!breedingUL) {
// Fallback: look for any UL with breeding-related links
const allULs = document.querySelectorAll("ul");
for (let ul of allULs) {
if (ul.querySelector('a[onclick*="pet_breed"]')) {
breedingUL = ul;
log("Found breeding UL via fallback search");
break;
}
}
}
if (!breedingUL && attempts++ < maxAttempts) {
log(
`β³ Breeding section not loaded yet, retrying... (${attempts}/${maxAttempts})`
);
setTimeout(findBreedingPartners, 300);
return;
}
if (!breedingUL) {
log("β No breeding UL found, moving to next pet");
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 300);
return;
}
// Look for available breeding partners
const breedingLinks = breedingUL.querySelectorAll(
'a[onclick*="pet_breed"]'
);
if (!breedingLinks.length) {
log(
"β No more breeding partners available for this pet, moving to next pet"
);
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 300);
return;
}
}
// Process the first available breeding partner
const firstBreedingLink = breedingLinks[0];
log(
`π― Found ${breedingLinks.length} breeding partners, clicking first one...`
);
firstBreedingLink.click();
// Wait for modal to appear
setTimeout(() => {
if (isRunning()) {
handleBreedingModal();
}
}, 300);
if (breedingLinks.length > 1) {
log(
`π Found ${
breedingLinks.length - 1
} more breeding partners, will continue after this one`
);
// to repeat this pet after breeding, set the index back once
setIndex(getIndex() - 1);
}
};
findBreedingPartners();
}
function main() {
if (!isRunning()) return;
const href = location.href;
const base = getBase();
var counter = 0;
let feedingButton = document.querySelector('button[onclick*="pet_feed"]');
if (feedingButton) {
log("β Found feeding button, clicking...");
feedingButton.click();
}
log("π Breeder main executing...", href);
// if just bred, go back to breeding section
if (sessionStorage.getItem(JUST_BREAD) === "true") {
log("π Just bred, going back to breeding section...");
// set just bred flag to false
if (counter > 0) {
counter = 0;
sessionStorage.setItem(JUST_BREAD, "false");
setTimeout(() => {
if (isRunning()) {
history.back();
}
}, 300);
setTimeout(() => {
if (isRunning()) {
handlePetProfile();
}
}, 400);
} else {
counter++;
}
}
// If we're on a pet profile page
if (href.includes("sub=profile") && href.includes("pet=")) {
// Check if we're already on the breeding tab
let feedingButton = document.querySelector(
'button[onclick*="pet_feed"]'
);
if (feedingButton) {
log("β Found feeding button, clicking...");
feedingButton.click();
}
const breedingSection = document.querySelector("#breeding");
if (breedingSection) {
log("π Already on breeding section, looking for partners...");
setTimeout(() => {
if (isRunning()) {
handleBreedingSection();
}
}, 300);
} else {
let feedingButton = document.querySelector(
'button[onclick*="pet_feed"]'
);
if (feedingButton) {
log("β Found feeding button, clicking...");
feedingButton.click();
}
log("π On pet profile, need to click breeding tab");
setTimeout(() => {
if (isRunning()) {
handlePetProfile();
}
}, 300);
}
}
// If we're back at the base page and haven't collected pets yet
else if (href === base && !sessionStorage.getItem(PETS_KEY)) {
log("π At base, need to collect pets");
setTimeout(() => {
if (isRunning()) {
collectPets();
}
}, 300);
}
// If we're back at the base page and have pets collected
else if (href === base) {
log("π At base, have pets, continuing...");
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 300);
}
// If we're on a different page, go to current pet (not next!)
else {
const pets = getPets();
if (pets.length > 0) {
log("π On different page, going to current pet");
setTimeout(() => {
if (isRunning()) {
// Don't increment index - go to current pet
const currentPetUrl = pets[getIndex()];
if (currentPetUrl) {
log(`π Returning to current pet: ${currentPetUrl}`);
location.href = currentPetUrl;
} else {
goToPet();
}
}
}, 300);
} else {
log("π No pets collected, returning to base");
location.href = base;
}
}
}
return { startBot, stopBot, main };
})();
// --- Namer Module ---
const Namer = (function () {
const RUN_KEY = "namer_running";
const PETS_KEY = "namer_pets";
const IDX_KEY = "namer_index";
const BASE_KEY = "namer_base_href";
const UL_KEY = "namer_selected_ul";
const NAME = "namer_name";
function log(...args) {
console.log("%c[NAMER]", "background:#9932cc;color:#fff;", ...args);
}
function startBot() {
log(
"Starting Namer - Please click on the UL element containing the pets to name"
);
// Store the current location as base
sessionStorage.setItem(BASE_KEY, location.href);
sessionStorage.setItem(RUN_KEY, "true");
sessionStorage.setItem(IDX_KEY, "0");
sessionStorage.removeItem(PETS_KEY);
sessionStorage.removeItem(UL_KEY);
sessionStorage.removeItem(NAME);
// Enable UL selection mode
enableULSelection();
}
function stopBot() {
sessionStorage.removeItem(RUN_KEY);
sessionStorage.removeItem(UL_KEY);
disableULSelection();
log("Stopped Namer");
}
function isRunning() {
return sessionStorage.getItem(RUN_KEY) === "true";
}
function getBase() {
return sessionStorage.getItem(BASE_KEY);
}
function getPets() {
try {
return JSON.parse(sessionStorage.getItem(PETS_KEY)) || [];
} catch {
return [];
}
}
function savePets(pets) {
sessionStorage.setItem(PETS_KEY, JSON.stringify(pets));
}
function getIndex() {
return parseInt(sessionStorage.getItem(IDX_KEY) || "0", 10);
}
function setIndex(i) {
sessionStorage.setItem(IDX_KEY, String(i));
}
function getSelectedUL() {
return sessionStorage.getItem(UL_KEY);
}
function setSelectedUL(selector) {
sessionStorage.setItem(UL_KEY, selector);
}
function enableULSelection() {
// Create visual indicators
const style = document.createElement("style");
style.id = "namer-ul-selection-style";
style.textContent = `
.namer-ul-highlight {
outline: 3px solid #9932cc !important;
outline-offset: 2px !important;
cursor: pointer !important;
position: relative !important;
}
.namer-ul-highlight::before {
content: "Click to select this list for naming";
position: absolute;
top: -25px;
left: 0;
background: #9932cc;
color: white;
padding: 2px 8px;
font-size: 12px;
border-radius: 3px;
white-space: nowrap;
z-index: 10000;
}
.namer-selection-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.3);
z-index: 9999;
pointer-events: none;
}
.namer-instruction {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #9932cc;
color: white;
padding: 20px;
border-radius: 8px;
font-family: monospace;
font-size: 16px;
z-index: 10001;
text-align: center;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
}
`;
document.head.appendChild(style);
// Create overlay
const overlay = document.createElement("div");
overlay.className = "namer-selection-overlay";
overlay.id = "namer-overlay";
document.body.appendChild(overlay);
// Create instruction
const instruction = document.createElement("div");
instruction.className = "namer-instruction";
instruction.id = "namer-instruction";
instruction.innerHTML = `
π Namer Setup
Hover over UL elements and click the one containing the pets you want to name
Press ESC to cancel
`;
document.body.appendChild(instruction);
// Find all UL elements and add hover effects
const uls = document.querySelectorAll("ul");
uls.forEach((ul) => {
ul.addEventListener("mouseenter", handleULHover);
ul.addEventListener("mouseleave", handleULLeave);
ul.addEventListener("click", handleULClick);
});
// ESC to cancel
document.addEventListener("keydown", handleEscapeKey);
log(
`Found ${uls.length} UL elements - hover to highlight, click to select`
);
}
function disableULSelection() {
// Remove style
const style = document.getElementById("namer-ul-selection-style");
if (style) style.remove();
// Remove overlay and instruction
const overlay = document.getElementById("namer-overlay");
if (overlay) overlay.remove();
const instruction = document.getElementById("namer-instruction");
if (instruction) instruction.remove();
// Remove event listeners from all ULs
const uls = document.querySelectorAll("ul");
uls.forEach((ul) => {
ul.removeEventListener("mouseenter", handleULHover);
ul.removeEventListener("mouseleave", handleULLeave);
ul.removeEventListener("click", handleULClick);
ul.classList.remove("namer-ul-highlight");
});
document.removeEventListener("keydown", handleEscapeKey);
}
function handleULHover(event) {
const ul = event.target;
ul.classList.add("namer-ul-highlight");
// Add debug info overlay
const debugInfo = document.createElement("div");
debugInfo.id = "namer-debug-info";
debugInfo.style.cssText = `
position: fixed;
top: 10px;
right: 10px;
background: #9932cc;
color: white;
padding: 10px;
border-radius: 5px;
font-family: monospace;
font-size: 12px;
z-index: 10002;
max-width: 300px;
`;
const petLinks = ul.querySelectorAll('a.pet[href*="pet="]').length;
const totalLis = ul.querySelectorAll("li").length;
debugInfo.innerHTML = `
π UL Preview
Total LIs: ${totalLis}
Pet Links: ${petLinks}
${
petLinks > 0
? "β Contains pet links!"
: "β No pet links found"
}
`;
document.body.appendChild(debugInfo);
}
function handleULLeave(event) {
event.target.classList.remove("namer-ul-highlight");
// Remove debug info
const debugInfo = document.getElementById("namer-debug-info");
if (debugInfo) debugInfo.remove();
}
function handleULClick(event) {
event.preventDefault();
event.stopPropagation();
const ul = event.target;
// Remove highlight class
ul.classList.remove("namer-ul-highlight");
log(`Selected UL with ${ul.children.length} children`);
// Clean up selection mode first
disableULSelection();
// ask what the name should be with an alert prompt
const name = prompt("Enter the name to use for all pets:", "cute guy");
if (name) {
sessionStorage.setItem(NAME, name);
log(`Using name: ${name}`);
} else {
log('No name provided, using default "cute guy"');
sessionStorage.setItem(NAME, "cute guy");
}
// Collect pets immediately from the selected UL
collectPetsFromElement(ul);
}
function collectPetsFromElement(ul) {
if (!isRunning()) return;
log("Collecting pet links from selected UL");
if (!ul) {
log("No UL element provided");
stopBot();
return;
}
log(`Found UL element with ${ul.children.length} child elements`);
// Extract pet links specifically
const petLinks = [];
const lis = ul.querySelectorAll("li");
log(`Scanning ${lis.length} li elements for pet links...`);
lis.forEach((li, index) => {
// Look for pet links - using the pattern from your example
const petLink =
li.querySelector('a.pet[href*="pet="]') ||
li.querySelector('a[href*="pet="]') ||
li.querySelector('a[href*="sub=profile"]');
if (petLink && petLink.href) {
const href = petLink.href;
// Check if it's a pet profile link (not a user link)
const isPetLink =
href.includes("pet=") && href.includes("sub=profile");
if (isPetLink) {
petLinks.push(href);
log(`Found pet link ${index + 1}: ${href}`);
}
}
});
if (!petLinks.length) {
log("No pet links found in selected UL");
log("UL HTML preview:", ul.innerHTML.substring(0, 500));
// Debug what we actually found
log("Debug: Found links in UL:");
const allLinks = ul.querySelectorAll("a");
allLinks.forEach((link, i) => {
log(` Link ${i + 1}: href="${link.href}" class="${link.className}"`);
});
stopBot();
return;
}
log(`Found ${petLinks.length} pets to name`);
savePets(petLinks);
goToPet();
}
function handleEscapeKey(event) {
if (event.key === "Escape") {
log("Selection cancelled");
stopBot();
}
}
function goToPet() {
if (!isRunning()) return;
const pets = getPets();
const idx = getIndex();
if (idx >= pets.length) {
log("All pets named! Naming complete!");
stopBot();
location.href = getBase();
return;
}
log(`π Going to name pet ${idx + 1}/${pets.length}...`);
location.href = pets[idx];
}
function handlePetProfile() {
if (!isRunning()) return;
// while a close button is present, click it
//
while (document.querySelector(".ui-button-icon.ui-icon-closethick")) {
const closeBtn = document.querySelector(
".ui-button-icon.ui-icon-closethick"
);
log("π Found close button, clicking to close any open modals...");
closeBtn.click();
}
log("π Looking for naming button on pet profile...");
// Single attempt with minimal wait - no retries
setTimeout(() => {
const namingBtn = document.querySelector(
"#profile > div > form > fieldset.ui-fieldset.ui-widget-content.ui-corner-all.actions > div > div > button"
);
if (namingBtn) {
log("β Found naming button, clicking...");
namingBtn.click();
// Wait for modal to appear with fixed delay
setTimeout(() => {
if (isRunning()) {
handleNamingModal();
}
}, 250);
} else {
log("β No naming button found, moving to next pet");
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 50);
}
}, 100);
}
function handleNamingModal() {
if (!isRunning()) return;
log("π Looking for naming modal...");
// Single attempt - modal should be ready by now
const nameInput = document.querySelector(
"#dialog > fieldset > div > div > input[type=text]"
);
if (nameInput) {
log("β Found name input field, entering name...");
// Clear existing text and type new name
nameInput.value = "";
nameInput.focus();
nameInput.value = sessionStorage.getItem(NAME) || "cute guy";
// Trigger input events to ensure the change is registered
nameInput.dispatchEvent(new Event("input", { bubbles: true }));
nameInput.dispatchEvent(new Event("change", { bubbles: true }));
// click this body > div.ui-dialog.ui-corner-all.ui-widget.ui-widget-content.ui-front.ui-dialog-buttons.ui-draggable.ui-resizable > div.ui-dialog-buttonpane.ui-widget-content.ui-helper-clearfix
// just to be sure lol
document
.querySelector(
"body > div.ui-dialog.ui-corner-all.ui-widget.ui-widget-content.ui-front.ui-dialog-buttons.ui-draggable.ui-resizable > div.ui-dialog-buttonpane.ui-widget-content.ui-helper-clearfix"
)
.click();
log("π Name entered, looking for confirm button...");
// Minimal wait then look for confirm button
setTimeout(() => {
const confirmBtn = document.querySelector(
"body > div.ui-dialog.ui-corner-all.ui-widget.ui-widget-content.ui-front.ui-dialog-buttons.ui-draggable.ui-resizable > div.ui-dialog-buttonpane.ui-widget-content.ui-helper-clearfix > div > button:nth-child(1)"
);
if (confirmBtn) {
log("β Found confirm button, clicking...");
confirmBtn.click();
log("π Pet named successfully! Moving to next pet...");
// Move to next pet with minimal delay
setTimeout(() => {
if (isRunning()) {
setIndex(getIndex() + 1);
goToPet();
}
}, 25);
} else {
log("β No confirm button found, moving to next pet");
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 50);
}
}, 100);
} else {
log("β No modal input found, moving to next pet");
setIndex(getIndex() + 1);
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 50);
}
}
function main() {
if (!isRunning()) return;
const href = location.href;
const base = getBase();
log("π Namer main executing...", href);
// If we're on a pet profile page
if (href.includes("sub=profile") && href.includes("pet=")) {
log("π On pet profile, looking for naming button");
handlePetProfile();
}
// If we're back at the base page and haven't collected pets yet
else if (href === base && !sessionStorage.getItem(PETS_KEY)) {
log("π At base, need to collect pets");
setTimeout(() => {
if (isRunning()) {
// Re-enable UL selection
enableULSelection();
}
}, 50);
}
// If we're back at the base page and have pets collected
else if (href === base) {
log("π At base, have pets, continuing...");
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 50);
}
// If we're on a different page
else {
const pets = getPets();
if (pets.length > 0) {
log("π On different page, going to next pet");
setTimeout(() => {
if (isRunning()) {
goToPet();
}
}, 50);
} else {
log("π No pets collected, returning to base");
location.href = base;
}
}
}
return { startBot, stopBot, main };
})();
// --- Image Collector Module ---
const ImageCollector = (function () {
const RUN_KEY = "image_collector_running";
const SPECIES_KEY = "image_collector_species";
const COUNT_KEY = "image_collector_count";
// List of species that the puzzle solver can recognize
const SPECIES_OPTIONS = [
"Canis",
"Draconis",
"Equus",
"Feline",
"Gekko",
"Lupus",
"Mantis",
"Raptor",
"Vulpes",
];
function log(...args) {
console.log(
"%c[IMAGE-COLLECTOR]",
"background:#ff4500;color:#fff;",
...args
);
}
function startBot() {
log("Starting Image Collector");
// Show species selection modal
showSpeciesSelection();
}
function stopBot() {
sessionStorage.removeItem(RUN_KEY);
sessionStorage.removeItem(SPECIES_KEY);
sessionStorage.removeItem(COUNT_KEY);
log("Stopped Image Collector");
}
function isRunning() {
return sessionStorage.getItem(RUN_KEY) === "true";
}
function getSelectedSpecies() {
return sessionStorage.getItem(SPECIES_KEY);
}
function setSelectedSpecies(species) {
sessionStorage.setItem(SPECIES_KEY, species);
}
function getImageCount() {
return parseInt(sessionStorage.getItem(COUNT_KEY) || "0", 10);
}
function setImageCount(count) {
sessionStorage.setItem(COUNT_KEY, String(count));
}
function incrementImageCount() {
const newCount = getImageCount() + 1;
setImageCount(newCount);
return newCount;
}
function showSpeciesSelection() {
// Create modal overlay
const overlay = document.createElement("div");
overlay.id = "image-collector-species-overlay";
overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.8);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
`;
// Create modal content
const modal = document.createElement("div");
modal.style.cssText = `
background: #ff4500;
color: white;
padding: 30px;
border-radius: 10px;
font-family: monospace;
max-width: 500px;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
`;
modal.innerHTML = `
πΈ Image Collector
Select the species you want to collect images for:
${SPECIES_OPTIONS.map(
(species) => `
`
).join("")}
`;
overlay.appendChild(modal);
document.body.appendChild(overlay);
// Handle confirm button
document.getElementById("species-confirm").onclick = () => {
const selectedRadio = document.querySelector(
'input[name="species"]:checked'
);
if (selectedRadio) {
const species = selectedRadio.value;
setSelectedSpecies(species);
setImageCount(0);
sessionStorage.setItem(RUN_KEY, "true");
log(`Selected species: ${species}`);
// Remove modal
overlay.remove();
// Start the collection process
startCollectionLoop();
} else {
alert("Please select a species first!");
}
};
// Handle cancel button
document.getElementById("species-cancel").onclick = () => {
overlay.remove();
log("Species selection cancelled");
};
// Handle ESC key
document.addEventListener("keydown", function escHandler(event) {
if (event.key === "Escape") {
overlay.remove();
document.removeEventListener("keydown", escHandler);
log("Species selection cancelled");
}
});
}
function startCollectionLoop() {
if (!isRunning()) return;
const species = getSelectedSpecies();
log(`π Starting collection loop for ${species}...`);
// Start the main collection process
setTimeout(() => {
if (isRunning()) {
collectCurrentImage();
}
}, 100);
}
function collectCurrentImage() {
if (!isRunning()) return;
const species = getSelectedSpecies();
const currentCount = incrementImageCount();
const paddedCount = String(currentCount).padStart(4, "0");
const filename = `${species}_${paddedCount}`;
log(`πΈ Collecting image ${currentCount} for ${species}...`);
// Find the image element
const imageElement = document.querySelector(
"#visualizer > div > form > fieldset.ui-fieldset.ui-widget-content.ui-corner-all.display > div > img"
);
if (!imageElement) {
log(
"β Image element not found. Make sure you are on the visualizer page."
);
stopBot();
return;
}
// Get the image URL and download it
const imageUrl = imageElement.src;
if (imageUrl) {
downloadImage(imageUrl, filename)
.then(() => {
log(`β Image saved as ${filename}`);
// Wait a moment then click randomize button
setTimeout(() => {
if (isRunning()) {
clickRandomizeButton();
}
}, 100);
})
.catch((error) => {
log(`β Failed to save image: ${error}`);
// Continue anyway
setTimeout(() => {
if (isRunning()) {
clickRandomizeButton();
}
}, 100);
});
} else {
log("β No image URL found");
setTimeout(() => {
if (isRunning()) {
clickRandomizeButton();
}
}, 100);
}
}
function downloadImage(url, filename) {
return new Promise((resolve, reject) => {
// Convert relative URL to absolute if needed
const imageUrl = url.startsWith("//") ? `https:${url}` : url;
GM_xmlhttpRequest({
method: "GET",
url: imageUrl,
responseType: "blob",
onload: function (response) {
try {
// Create blob URL
const blob = response.response;
const blobUrl = URL.createObjectURL(blob);
// Create download link
const downloadLink = document.createElement("a");
downloadLink.href = blobUrl;
downloadLink.download = `${filename}.jpg`;
downloadLink.style.display = "none";
// Add to document and click
document.body.appendChild(downloadLink);
downloadLink.click();
// Clean up
document.body.removeChild(downloadLink);
URL.revokeObjectURL(blobUrl);
resolve();
} catch (error) {
reject(error);
}
},
onerror: function (error) {
reject(error);
},
});
});
}
function clickRandomizeButton() {
if (!isRunning()) return;
log("π² Clicking randomize button...");
// Find the randomize button
const randomizeButton = document.querySelector(
"#visualizer > div > form > fieldset.ui-fieldset.ui-widget-content.ui-corner-all.actions > div > div:nth-child(2) > button"
);
if (randomizeButton) {
randomizeButton.click();
log("β Randomize button clicked");
// Wait for the new image to load, then collect it
setTimeout(() => {
if (isRunning()) {
collectCurrentImage();
}
}, 100); // Wait for image to update
} else {
log(
"β Randomize button not found. Make sure you are on the visualizer page."
);
stopBot();
}
}
function main() {
if (!isRunning()) return;
// This module doesn't need URL-based navigation
// It works on the current page where the user starts it
log("π Image Collector running...");
}
return { startBot, stopBot, main };
})();
// --- Genetic Profiler Module ---
const GeneticProfiler = (function () {
const RUN_KEY = "genetic_profiler_running";
const PETS_KEY = "genetic_profiler_pets";
const IDX_KEY = "genetic_profiler_index";
const BASE_KEY = "genetic_profiler_base_href";
const UL_KEY = "genetic_profiler_selected_ul";
const COLORS_KEY = "genetic_profiler_target_colors";
function log(...args) {
console.log(
"%c[GENETIC-PROFILER]",
"background:#4b0082;color:#fff;",
...args
);
}
function startBot() {
log(
"Starting Genetic Profiler - First, please enter target color values"
);
// Show color input modal
showColorInputModal();
}
function stopBot() {
sessionStorage.removeItem(RUN_KEY);
sessionStorage.removeItem(UL_KEY);
sessionStorage.removeItem(COLORS_KEY);
disableULSelection();
log("Stopped Genetic Profiler");
}
function isRunning() {
return sessionStorage.getItem(RUN_KEY) === "true";
}
function getBase() {
return sessionStorage.getItem(BASE_KEY);
}
function getPets() {
try {
return JSON.parse(sessionStorage.getItem(PETS_KEY)) || [];
} catch {
return [];
}
}
function savePets(pets) {
sessionStorage.setItem(PETS_KEY, JSON.stringify(pets));
}
function getIndex() {
return parseInt(sessionStorage.getItem(IDX_KEY) || "0", 10);
}
function setIndex(i) {
sessionStorage.setItem(IDX_KEY, String(i));
}
function getSelectedUL() {
return sessionStorage.getItem(UL_KEY);
}
function setSelectedUL(selector) {
sessionStorage.setItem(UL_KEY, selector);
}
function getTargetColors() {
try {
return JSON.parse(sessionStorage.getItem(COLORS_KEY)) || {};
} catch {
return {};
}
}
function setTargetColors(colors) {
sessionStorage.setItem(COLORS_KEY, JSON.stringify(colors));
}
function showColorInputModal() {
// Create modal overlay
const overlay = document.createElement("div");
overlay.id = "genetic-profiler-color-overlay";
overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.8);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
`;
// Create modal content
const modal = document.createElement("div");
modal.style.cssText = `
background: #4b0082;
color: white;
padding: 30px;
border-radius: 10px;
font-family: monospace;
max-width: 500px;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
`;
modal.innerHTML = `