v0.14.20 - Fix Purchase page scraper: const dynjs_eqstore + screen=purchase
- Bug 1: Purchase tab URL is 'screen=purchase', not 'screen=buy'
- Bug 2: dynjs_eqstore is declared with 'const', not 'var', so it doesn't
create a window property. getHVEquipStore() now also checks bare names
which works with @grant none and the IIFE scope chain
- Fixed price parsing: purchase table has 2 td cells (label + price),
previously required >3 cells so prices were always empty
- Names with 🔺 prefix are cleaned before storage
This commit is contained in:
parent
f2e8ce536a
commit
5286f66b3e
5 changed files with 51 additions and 21 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.14.19
|
// @version 0.14.20
|
||||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.14.19';
|
const VERSION = '0.14.20';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle automation
|
// — Battle automation
|
||||||
|
|
@ -3281,8 +3281,18 @@ const GEAR_DB_KEY = SP + 'geardb';
|
||||||
// ── Access HV's in-memory equipment store ──
|
// ── Access HV's in-memory equipment store ──
|
||||||
function getHVEquipStore() {
|
function getHVEquipStore() {
|
||||||
const w = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
|
const w = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
|
||||||
|
// Check window properties (works for var-declared globals like dynjs_equip)
|
||||||
if (w.dynjs_eqstore && Object.keys(w.dynjs_eqstore).length) return w.dynjs_eqstore;
|
if (w.dynjs_eqstore && Object.keys(w.dynjs_eqstore).length) return w.dynjs_eqstore;
|
||||||
if (w.dynjs_equip && Object.keys(w.dynjs_equip).length) return w.dynjs_equip;
|
if (w.dynjs_equip && Object.keys(w.dynjs_equip).length) return w.dynjs_equip;
|
||||||
|
// Check bare names (works for const/let globals that don't create window props)
|
||||||
|
try {
|
||||||
|
if (typeof dynjs_eqstore !== 'undefined' && dynjs_eqstore && Object.keys(dynjs_eqstore).length)
|
||||||
|
return dynjs_eqstore;
|
||||||
|
} catch(e) {}
|
||||||
|
try {
|
||||||
|
if (typeof dynjs_equip !== 'undefined' && dynjs_equip && Object.keys(dynjs_equip).length)
|
||||||
|
return dynjs_equip;
|
||||||
|
} catch(e) {}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3523,13 +3533,13 @@ function scrapeBuyPage() {
|
||||||
let name = label ? (label.textContent || '').trim() : '';
|
let name = label ? (label.textContent || '').trim() : '';
|
||||||
if (cb && label) name = (label.textContent || '').replace(cb.outerHTML, '').trim();
|
if (cb && label) name = (label.textContent || '').replace(cb.outerHTML, '').trim();
|
||||||
|
|
||||||
// Try to read price from buy pages (often in additional columns or cell text)
|
// Try to read price from buy pages (second td with credit cost)
|
||||||
let price = '';
|
let price = '';
|
||||||
if (!idM && !name && !itemId) return;
|
if (!idM && !name && !itemId) return;
|
||||||
const cells = row.querySelectorAll('td');
|
const cells = row.querySelectorAll('td');
|
||||||
if (cells.length > 3) {
|
if (cells.length >= 2) {
|
||||||
const lastCell = cells[cells.length - 1];
|
const priceCell = cells[cells.length - 1]; // last td = price column
|
||||||
if (lastCell) price = (lastCell.textContent || '').trim();
|
if (priceCell) price = (priceCell.textContent || '').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
const obj = { id: itemId, name: name || 'Unknown', category: cat, price, source: 'buy', scrapedAt: Date.now() };
|
const obj = { id: itemId, name: name || 'Unknown', category: cat, price, source: 'buy', scrapedAt: Date.now() };
|
||||||
|
|
@ -3559,7 +3569,7 @@ function autoScrapeGear() {
|
||||||
const url = window.location.href || '';
|
const url = window.location.href || '';
|
||||||
if (url.includes('ss=eq') || url.includes('ss=ch')) return scrapeCharacterEquip();
|
if (url.includes('ss=eq') || url.includes('ss=ch')) return scrapeCharacterEquip();
|
||||||
if (url.includes('ss=am') && (url.includes('screen=organize') || !url.includes('screen='))) return scrapeArmory();
|
if (url.includes('ss=am') && (url.includes('screen=organize') || !url.includes('screen='))) return scrapeArmory();
|
||||||
if (url.includes('ss=am') && url.includes('screen=buy')) return scrapeBuyPage();
|
if (url.includes('ss=am') && url.includes('screen=purchase')) return scrapeBuyPage();
|
||||||
if (url.includes('ss=am') && url.includes('screen=modify')) return scrapeModifyDetail();
|
if (url.includes('ss=am') && url.includes('screen=modify')) return scrapeModifyDetail();
|
||||||
if (url.includes('ss=bi')) return scrapeBuyPage();
|
if (url.includes('ss=bi')) return scrapeBuyPage();
|
||||||
return [];
|
return [];
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.14.19
|
// @version 0.14.20
|
||||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.14.19';
|
const VERSION = '0.14.20';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle automation
|
// — Battle automation
|
||||||
|
|
@ -3281,8 +3281,18 @@ const GEAR_DB_KEY = SP + 'geardb';
|
||||||
// ── Access HV's in-memory equipment store ──
|
// ── Access HV's in-memory equipment store ──
|
||||||
function getHVEquipStore() {
|
function getHVEquipStore() {
|
||||||
const w = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
|
const w = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
|
||||||
|
// Check window properties (works for var-declared globals like dynjs_equip)
|
||||||
if (w.dynjs_eqstore && Object.keys(w.dynjs_eqstore).length) return w.dynjs_eqstore;
|
if (w.dynjs_eqstore && Object.keys(w.dynjs_eqstore).length) return w.dynjs_eqstore;
|
||||||
if (w.dynjs_equip && Object.keys(w.dynjs_equip).length) return w.dynjs_equip;
|
if (w.dynjs_equip && Object.keys(w.dynjs_equip).length) return w.dynjs_equip;
|
||||||
|
// Check bare names (works for const/let globals that don't create window props)
|
||||||
|
try {
|
||||||
|
if (typeof dynjs_eqstore !== 'undefined' && dynjs_eqstore && Object.keys(dynjs_eqstore).length)
|
||||||
|
return dynjs_eqstore;
|
||||||
|
} catch(e) {}
|
||||||
|
try {
|
||||||
|
if (typeof dynjs_equip !== 'undefined' && dynjs_equip && Object.keys(dynjs_equip).length)
|
||||||
|
return dynjs_equip;
|
||||||
|
} catch(e) {}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3523,13 +3533,13 @@ function scrapeBuyPage() {
|
||||||
let name = label ? (label.textContent || '').trim() : '';
|
let name = label ? (label.textContent || '').trim() : '';
|
||||||
if (cb && label) name = (label.textContent || '').replace(cb.outerHTML, '').trim();
|
if (cb && label) name = (label.textContent || '').replace(cb.outerHTML, '').trim();
|
||||||
|
|
||||||
// Try to read price from buy pages (often in additional columns or cell text)
|
// Try to read price from buy pages (second td with credit cost)
|
||||||
let price = '';
|
let price = '';
|
||||||
if (!idM && !name && !itemId) return;
|
if (!idM && !name && !itemId) return;
|
||||||
const cells = row.querySelectorAll('td');
|
const cells = row.querySelectorAll('td');
|
||||||
if (cells.length > 3) {
|
if (cells.length >= 2) {
|
||||||
const lastCell = cells[cells.length - 1];
|
const priceCell = cells[cells.length - 1]; // last td = price column
|
||||||
if (lastCell) price = (lastCell.textContent || '').trim();
|
if (priceCell) price = (priceCell.textContent || '').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
const obj = { id: itemId, name: name || 'Unknown', category: cat, price, source: 'buy', scrapedAt: Date.now() };
|
const obj = { id: itemId, name: name || 'Unknown', category: cat, price, source: 'buy', scrapedAt: Date.now() };
|
||||||
|
|
@ -3559,7 +3569,7 @@ function autoScrapeGear() {
|
||||||
const url = window.location.href || '';
|
const url = window.location.href || '';
|
||||||
if (url.includes('ss=eq') || url.includes('ss=ch')) return scrapeCharacterEquip();
|
if (url.includes('ss=eq') || url.includes('ss=ch')) return scrapeCharacterEquip();
|
||||||
if (url.includes('ss=am') && (url.includes('screen=organize') || !url.includes('screen='))) return scrapeArmory();
|
if (url.includes('ss=am') && (url.includes('screen=organize') || !url.includes('screen='))) return scrapeArmory();
|
||||||
if (url.includes('ss=am') && url.includes('screen=buy')) return scrapeBuyPage();
|
if (url.includes('ss=am') && url.includes('screen=purchase')) return scrapeBuyPage();
|
||||||
if (url.includes('ss=am') && url.includes('screen=modify')) return scrapeModifyDetail();
|
if (url.includes('ss=am') && url.includes('screen=modify')) return scrapeModifyDetail();
|
||||||
if (url.includes('ss=bi')) return scrapeBuyPage();
|
if (url.includes('ss=bi')) return scrapeBuyPage();
|
||||||
return [];
|
return [];
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// CONFIG — default settings
|
// CONFIG — default settings
|
||||||
// ═══════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
const VERSION = '0.14.19';
|
const VERSION = '0.14.20';
|
||||||
|
|
||||||
const CFG = {
|
const CFG = {
|
||||||
// — Battle automation
|
// — Battle automation
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,18 @@ const GEAR_DB_KEY = SP + 'geardb';
|
||||||
// ── Access HV's in-memory equipment store ──
|
// ── Access HV's in-memory equipment store ──
|
||||||
function getHVEquipStore() {
|
function getHVEquipStore() {
|
||||||
const w = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
|
const w = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
|
||||||
|
// Check window properties (works for var-declared globals like dynjs_equip)
|
||||||
if (w.dynjs_eqstore && Object.keys(w.dynjs_eqstore).length) return w.dynjs_eqstore;
|
if (w.dynjs_eqstore && Object.keys(w.dynjs_eqstore).length) return w.dynjs_eqstore;
|
||||||
if (w.dynjs_equip && Object.keys(w.dynjs_equip).length) return w.dynjs_equip;
|
if (w.dynjs_equip && Object.keys(w.dynjs_equip).length) return w.dynjs_equip;
|
||||||
|
// Check bare names (works for const/let globals that don't create window props)
|
||||||
|
try {
|
||||||
|
if (typeof dynjs_eqstore !== 'undefined' && dynjs_eqstore && Object.keys(dynjs_eqstore).length)
|
||||||
|
return dynjs_eqstore;
|
||||||
|
} catch(e) {}
|
||||||
|
try {
|
||||||
|
if (typeof dynjs_equip !== 'undefined' && dynjs_equip && Object.keys(dynjs_equip).length)
|
||||||
|
return dynjs_equip;
|
||||||
|
} catch(e) {}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,13 +262,13 @@ function scrapeBuyPage() {
|
||||||
let name = label ? (label.textContent || '').trim() : '';
|
let name = label ? (label.textContent || '').trim() : '';
|
||||||
if (cb && label) name = (label.textContent || '').replace(cb.outerHTML, '').trim();
|
if (cb && label) name = (label.textContent || '').replace(cb.outerHTML, '').trim();
|
||||||
|
|
||||||
// Try to read price from buy pages (often in additional columns or cell text)
|
// Try to read price from buy pages (second td with credit cost)
|
||||||
let price = '';
|
let price = '';
|
||||||
if (!idM && !name && !itemId) return;
|
if (!idM && !name && !itemId) return;
|
||||||
const cells = row.querySelectorAll('td');
|
const cells = row.querySelectorAll('td');
|
||||||
if (cells.length > 3) {
|
if (cells.length >= 2) {
|
||||||
const lastCell = cells[cells.length - 1];
|
const priceCell = cells[cells.length - 1]; // last td = price column
|
||||||
if (lastCell) price = (lastCell.textContent || '').trim();
|
if (priceCell) price = (priceCell.textContent || '').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
const obj = { id: itemId, name: name || 'Unknown', category: cat, price, source: 'buy', scrapedAt: Date.now() };
|
const obj = { id: itemId, name: name || 'Unknown', category: cat, price, source: 'buy', scrapedAt: Date.now() };
|
||||||
|
|
@ -288,7 +298,7 @@ function autoScrapeGear() {
|
||||||
const url = window.location.href || '';
|
const url = window.location.href || '';
|
||||||
if (url.includes('ss=eq') || url.includes('ss=ch')) return scrapeCharacterEquip();
|
if (url.includes('ss=eq') || url.includes('ss=ch')) return scrapeCharacterEquip();
|
||||||
if (url.includes('ss=am') && (url.includes('screen=organize') || !url.includes('screen='))) return scrapeArmory();
|
if (url.includes('ss=am') && (url.includes('screen=organize') || !url.includes('screen='))) return scrapeArmory();
|
||||||
if (url.includes('ss=am') && url.includes('screen=buy')) return scrapeBuyPage();
|
if (url.includes('ss=am') && url.includes('screen=purchase')) return scrapeBuyPage();
|
||||||
if (url.includes('ss=am') && url.includes('screen=modify')) return scrapeModifyDetail();
|
if (url.includes('ss=am') && url.includes('screen=modify')) return scrapeModifyDetail();
|
||||||
if (url.includes('ss=bi')) return scrapeBuyPage();
|
if (url.includes('ss=bi')) return scrapeBuyPage();
|
||||||
return [];
|
return [];
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name HV Unified
|
// @name HV Unified
|
||||||
// @namespace hvunified
|
// @namespace hvunified
|
||||||
// @version 0.14.19
|
// @version 0.14.20
|
||||||
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
// @description HV Unified — battle automation, guidance, and UI enhancements for HentaiVerse
|
||||||
// @author GaboGG + Hermes
|
// @author GaboGG + Hermes
|
||||||
// @match *://*.hentaiverse.org/*
|
// @match *://*.hentaiverse.org/*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue