v0.14.12 - Add captureAllTooltips() with async hover-to-popup delay
- captureAllTooltips() iterates each equipment slot, calls equips.set() to trigger the tooltip popup, waits 300ms for the DOM to update, then reads and saves the full stat block from #popup_box - Catches 'Popup Box' default text vs real tooltip - Saves stats directly to localStorage gear DB - Exposed as HV.captureTooltips() for console use - For best results: visit Character Equipment page, run HV.captureTooltips()
This commit is contained in:
parent
c632c13818
commit
ce09755fa8
6 changed files with 201 additions and 63 deletions
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name HV Unified
|
||||
// @namespace hvunified
|
||||
// @version 0.14.11
|
||||
// @version 0.14.12
|
||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||
// @author GaboGG + Hermes
|
||||
// @match *://*.hentaiverse.org/*
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
// CONFIG — default settings
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
const VERSION = '0.14.11';
|
||||
const VERSION = '0.14.12';
|
||||
|
||||
const CFG = {
|
||||
// — Battle automation
|
||||
|
|
@ -3442,18 +3442,17 @@ function scrapeCharacterEquip() {
|
|||
});
|
||||
|
||||
// Read the popup box for the currently-displayed tooltip
|
||||
const tooltip = parseTooltipPopup();
|
||||
|
||||
// Merge tooltip stats with the matching item
|
||||
if (tooltip && tooltip.name) {
|
||||
const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name));
|
||||
if (matchIdx >= 0) {
|
||||
scraped[matchIdx].stats = tooltip.stats;
|
||||
} else if (scraped.length > 0) {
|
||||
// If no match, attach to first item as extra info
|
||||
scraped[0].tooltipStats = tooltip.stats;
|
||||
// Note: popup_box only updates on actual hover; triggerAllTooltips
|
||||
// may not work if equips.set is async. We still get names/IDs from slots.
|
||||
try {
|
||||
const tooltip = parseTooltipPopup();
|
||||
if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') {
|
||||
const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name));
|
||||
if (matchIdx >= 0) {
|
||||
scraped[matchIdx].stats = tooltip.stats;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (scraped.length > 0) {
|
||||
const db = getGearDB();
|
||||
|
|
@ -3563,20 +3562,66 @@ function triggerAllTooltips() {
|
|||
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || '';
|
||||
const idMatch = omo.match(/equips\.set\((\d+)/);
|
||||
if (idMatch && typeof equips !== 'undefined' && equips.set) {
|
||||
// Trigger the tooltip
|
||||
equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130);
|
||||
|
||||
// Read the popup
|
||||
const tooltip = parseTooltipPopup();
|
||||
if (tooltip && tooltip.name) {
|
||||
results.push(tooltip);
|
||||
}
|
||||
try {
|
||||
equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130);
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Manual: hover each item and capture tooltip stats with delays
|
||||
// Run this from console on the character equipment page for full stats
|
||||
function captureAllTooltips(delay = 400) {
|
||||
const slots = document.querySelectorAll('#eqsb > .eqb');
|
||||
const results = [];
|
||||
let idx = 0;
|
||||
|
||||
function next() {
|
||||
if (idx >= slots.length) {
|
||||
console.log(`%c[HV] Captured ${results.length} tooltips`, 'color:#0f0');
|
||||
// Re-scrape with the captured data
|
||||
autoScrapeGear();
|
||||
return;
|
||||
}
|
||||
|
||||
const slot = slots[idx];
|
||||
const nameDiv = slot.querySelector(':scope > div[onmouseover]');
|
||||
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : '';
|
||||
const idMatch = omo.match(/equips\.set\((\d+)/);
|
||||
|
||||
if (idMatch && typeof equips !== 'undefined' && equips.set) {
|
||||
try {
|
||||
equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130);
|
||||
// Wait for popup to populate
|
||||
setTimeout(() => {
|
||||
const tooltip = parseTooltipPopup();
|
||||
if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') {
|
||||
// Store in localStorage directly
|
||||
const db = getGearDB();
|
||||
const match = db.find(e => e.id === idMatch[1]);
|
||||
if (match) {
|
||||
match.stats = tooltip.stats;
|
||||
saveGearDB(db);
|
||||
}
|
||||
results.push(tooltip);
|
||||
console.log(`%c[HV] [${idx}] ${tooltip.name}`, 'color:#888');
|
||||
}
|
||||
idx++;
|
||||
next();
|
||||
}, 300);
|
||||
return;
|
||||
} catch (e) {}
|
||||
}
|
||||
idx++;
|
||||
next();
|
||||
}
|
||||
|
||||
next();
|
||||
return 'Capturing tooltips... check console';
|
||||
}
|
||||
|
||||
// ── Auto-detect and scrape current page ──
|
||||
function autoScrapeGear() {
|
||||
const url = window.location.href || '';
|
||||
|
|
@ -3954,6 +3999,7 @@ window.HV = {
|
|||
gearSummary: () => logGearSummary(),
|
||||
scrapeGear: () => autoScrapeGear(),
|
||||
gearDebug: () => debugScrapeGear(),
|
||||
captureTooltips: () => captureAllTooltips(),
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name HV Unified
|
||||
// @namespace hvunified
|
||||
// @version 0.14.11
|
||||
// @version 0.14.12
|
||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||
// @author GaboGG + Hermes
|
||||
// @match *://*.hentaiverse.org/*
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
// CONFIG — default settings
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
const VERSION = '0.14.11';
|
||||
const VERSION = '0.14.12';
|
||||
|
||||
const CFG = {
|
||||
// — Battle automation
|
||||
|
|
@ -3442,18 +3442,17 @@ function scrapeCharacterEquip() {
|
|||
});
|
||||
|
||||
// Read the popup box for the currently-displayed tooltip
|
||||
const tooltip = parseTooltipPopup();
|
||||
|
||||
// Merge tooltip stats with the matching item
|
||||
if (tooltip && tooltip.name) {
|
||||
const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name));
|
||||
if (matchIdx >= 0) {
|
||||
scraped[matchIdx].stats = tooltip.stats;
|
||||
} else if (scraped.length > 0) {
|
||||
// If no match, attach to first item as extra info
|
||||
scraped[0].tooltipStats = tooltip.stats;
|
||||
// Note: popup_box only updates on actual hover; triggerAllTooltips
|
||||
// may not work if equips.set is async. We still get names/IDs from slots.
|
||||
try {
|
||||
const tooltip = parseTooltipPopup();
|
||||
if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') {
|
||||
const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name));
|
||||
if (matchIdx >= 0) {
|
||||
scraped[matchIdx].stats = tooltip.stats;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (scraped.length > 0) {
|
||||
const db = getGearDB();
|
||||
|
|
@ -3563,20 +3562,66 @@ function triggerAllTooltips() {
|
|||
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || '';
|
||||
const idMatch = omo.match(/equips\.set\((\d+)/);
|
||||
if (idMatch && typeof equips !== 'undefined' && equips.set) {
|
||||
// Trigger the tooltip
|
||||
equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130);
|
||||
|
||||
// Read the popup
|
||||
const tooltip = parseTooltipPopup();
|
||||
if (tooltip && tooltip.name) {
|
||||
results.push(tooltip);
|
||||
}
|
||||
try {
|
||||
equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130);
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Manual: hover each item and capture tooltip stats with delays
|
||||
// Run this from console on the character equipment page for full stats
|
||||
function captureAllTooltips(delay = 400) {
|
||||
const slots = document.querySelectorAll('#eqsb > .eqb');
|
||||
const results = [];
|
||||
let idx = 0;
|
||||
|
||||
function next() {
|
||||
if (idx >= slots.length) {
|
||||
console.log(`%c[HV] Captured ${results.length} tooltips`, 'color:#0f0');
|
||||
// Re-scrape with the captured data
|
||||
autoScrapeGear();
|
||||
return;
|
||||
}
|
||||
|
||||
const slot = slots[idx];
|
||||
const nameDiv = slot.querySelector(':scope > div[onmouseover]');
|
||||
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : '';
|
||||
const idMatch = omo.match(/equips\.set\((\d+)/);
|
||||
|
||||
if (idMatch && typeof equips !== 'undefined' && equips.set) {
|
||||
try {
|
||||
equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130);
|
||||
// Wait for popup to populate
|
||||
setTimeout(() => {
|
||||
const tooltip = parseTooltipPopup();
|
||||
if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') {
|
||||
// Store in localStorage directly
|
||||
const db = getGearDB();
|
||||
const match = db.find(e => e.id === idMatch[1]);
|
||||
if (match) {
|
||||
match.stats = tooltip.stats;
|
||||
saveGearDB(db);
|
||||
}
|
||||
results.push(tooltip);
|
||||
console.log(`%c[HV] [${idx}] ${tooltip.name}`, 'color:#888');
|
||||
}
|
||||
idx++;
|
||||
next();
|
||||
}, 300);
|
||||
return;
|
||||
} catch (e) {}
|
||||
}
|
||||
idx++;
|
||||
next();
|
||||
}
|
||||
|
||||
next();
|
||||
return 'Capturing tooltips... check console';
|
||||
}
|
||||
|
||||
// ── Auto-detect and scrape current page ──
|
||||
function autoScrapeGear() {
|
||||
const url = window.location.href || '';
|
||||
|
|
@ -3954,6 +3999,7 @@ window.HV = {
|
|||
gearSummary: () => logGearSummary(),
|
||||
scrapeGear: () => autoScrapeGear(),
|
||||
gearDebug: () => debugScrapeGear(),
|
||||
captureTooltips: () => captureAllTooltips(),
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// CONFIG — default settings
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
const VERSION = '0.14.11';
|
||||
const VERSION = '0.14.12';
|
||||
|
||||
const CFG = {
|
||||
// — Battle automation
|
||||
|
|
|
|||
|
|
@ -199,18 +199,17 @@ function scrapeCharacterEquip() {
|
|||
});
|
||||
|
||||
// Read the popup box for the currently-displayed tooltip
|
||||
const tooltip = parseTooltipPopup();
|
||||
|
||||
// Merge tooltip stats with the matching item
|
||||
if (tooltip && tooltip.name) {
|
||||
const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name));
|
||||
if (matchIdx >= 0) {
|
||||
scraped[matchIdx].stats = tooltip.stats;
|
||||
} else if (scraped.length > 0) {
|
||||
// If no match, attach to first item as extra info
|
||||
scraped[0].tooltipStats = tooltip.stats;
|
||||
// Note: popup_box only updates on actual hover; triggerAllTooltips
|
||||
// may not work if equips.set is async. We still get names/IDs from slots.
|
||||
try {
|
||||
const tooltip = parseTooltipPopup();
|
||||
if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') {
|
||||
const matchIdx = scraped.findIndex(s => tooltip.name.includes(s.name) || s.name.includes(tooltip.name));
|
||||
if (matchIdx >= 0) {
|
||||
scraped[matchIdx].stats = tooltip.stats;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (scraped.length > 0) {
|
||||
const db = getGearDB();
|
||||
|
|
@ -320,20 +319,66 @@ function triggerAllTooltips() {
|
|||
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : slot.getAttribute('onmouseover') || '';
|
||||
const idMatch = omo.match(/equips\.set\((\d+)/);
|
||||
if (idMatch && typeof equips !== 'undefined' && equips.set) {
|
||||
// Trigger the tooltip
|
||||
equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130);
|
||||
|
||||
// Read the popup
|
||||
const tooltip = parseTooltipPopup();
|
||||
if (tooltip && tooltip.name) {
|
||||
results.push(tooltip);
|
||||
}
|
||||
try {
|
||||
equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130);
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Manual: hover each item and capture tooltip stats with delays
|
||||
// Run this from console on the character equipment page for full stats
|
||||
function captureAllTooltips(delay = 400) {
|
||||
const slots = document.querySelectorAll('#eqsb > .eqb');
|
||||
const results = [];
|
||||
let idx = 0;
|
||||
|
||||
function next() {
|
||||
if (idx >= slots.length) {
|
||||
console.log(`%c[HV] Captured ${results.length} tooltips`, 'color:#0f0');
|
||||
// Re-scrape with the captured data
|
||||
autoScrapeGear();
|
||||
return;
|
||||
}
|
||||
|
||||
const slot = slots[idx];
|
||||
const nameDiv = slot.querySelector(':scope > div[onmouseover]');
|
||||
const omo = nameDiv ? (nameDiv.getAttribute('onmouseover') || '') : '';
|
||||
const idMatch = omo.match(/equips\.set\((\d+)/);
|
||||
|
||||
if (idMatch && typeof equips !== 'undefined' && equips.set) {
|
||||
try {
|
||||
equips.set(parseInt(idMatch[1]), 'slot_pane', 250, 130);
|
||||
// Wait for popup to populate
|
||||
setTimeout(() => {
|
||||
const tooltip = parseTooltipPopup();
|
||||
if (tooltip && tooltip.name && tooltip.name !== 'Popup Box') {
|
||||
// Store in localStorage directly
|
||||
const db = getGearDB();
|
||||
const match = db.find(e => e.id === idMatch[1]);
|
||||
if (match) {
|
||||
match.stats = tooltip.stats;
|
||||
saveGearDB(db);
|
||||
}
|
||||
results.push(tooltip);
|
||||
console.log(`%c[HV] [${idx}] ${tooltip.name}`, 'color:#888');
|
||||
}
|
||||
idx++;
|
||||
next();
|
||||
}, 300);
|
||||
return;
|
||||
} catch (e) {}
|
||||
}
|
||||
idx++;
|
||||
next();
|
||||
}
|
||||
|
||||
next();
|
||||
return 'Capturing tooltips... check console';
|
||||
}
|
||||
|
||||
// ── Auto-detect and scrape current page ──
|
||||
function autoScrapeGear() {
|
||||
const url = window.location.href || '';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name HV Unified
|
||||
// @namespace hvunified
|
||||
// @version 0.14.11
|
||||
// @version 0.14.12
|
||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||
// @author GaboGG + Hermes
|
||||
// @match *://*.hentaiverse.org/*
|
||||
|
|
|
|||
|
|
@ -25,4 +25,5 @@ window.HV = {
|
|||
gearSummary: () => logGearSummary(),
|
||||
scrapeGear: () => autoScrapeGear(),
|
||||
gearDebug: () => debugScrapeGear(),
|
||||
captureTooltips: () => captureAllTooltips(),
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue