This commit is contained in:
+8
-4
@@ -42,10 +42,14 @@ The SQLite database is stored on a mounted volume at `/app/data/tracker.db` so i
|
|||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
### Stock Detection
|
### Stock Detection
|
||||||
Puppeteer navigates to each product URL and waits for React hydration (2.5s delay), then:
|
Puppeteer navigates to each product URL, waits for React hydration (2.5s + active wait for `<button>` up to 8s), then evaluates with case- and whitespace-insensitive substring matching:
|
||||||
- `<button label="Add to Cart">` present → `in_stock`
|
- Any `<button>` with `label="Add to Cart"` attribute, OR whose text contains `"add to cart"` → `in_stock`
|
||||||
- Any `<button>` whose text is `"Notify me when available"`, `"Sold Out"`, or `"Out of Stock"` → `sold_out`
|
- Any `<button>` whose text contains one of: `"login for notifications"`, `"login for updates"`, `"notify me when available"`, `"notify me"`, `"sold out"`, `"out of stock"`, `"currently unavailable"`, `"coming soon"` → `sold_out`
|
||||||
- Neither found → `unknown`
|
- Neither found → `unknown` (logs a `[Scraper] UNKNOWN debug` payload with page title, button labels, and button texts for diagnosis)
|
||||||
|
|
||||||
|
**Two gotchas the matcher handles:**
|
||||||
|
- **Auth-state difference.** The scraper runs logged out, so Ubiquiti shows `"Login for Notifications"` on sold-out items instead of the logged-in `"Notify me when available"`. Both must be in the sold-out list.
|
||||||
|
- **The `label` attribute exists only on the in-stock button.** Production DOM does carry `label="Add to Cart"` on the primary Add-to-Cart button (confirmed in DevTools), but the sold-out "Login for Notifications" button has no `label` attribute. So in-stock has two redundant signals (attribute + text), sold-out only has text — by design.
|
||||||
|
|
||||||
Product name is pulled from the `og:title` meta tag (with Ubiquiti store suffix stripped). Thumbnail is pulled from `og:image`.
|
Product name is pulled from the `og:title` meta tag (with Ubiquiti store suffix stripped). Thumbnail is pulled from `og:image`.
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,13 @@ export async function checkStockStatus(url: string): Promise<ScrapeResult> {
|
|||||||
status = 'in_stock';
|
status = 'in_stock';
|
||||||
} else {
|
} else {
|
||||||
// Sold-out / unavailable phrases — substring match on normalized button text.
|
// Sold-out / unavailable phrases — substring match on normalized button text.
|
||||||
|
// Ubiquiti shows different sold-out text depending on auth state:
|
||||||
|
// logged out → "Login for Notifications" (our scraper always sees this)
|
||||||
|
// logged in → "Notify me when available"
|
||||||
|
// Both mean the item is unavailable. Keep both, plus common siblings.
|
||||||
const soldOutPhrases = [
|
const soldOutPhrases = [
|
||||||
|
'login for notifications',
|
||||||
|
'login for updates',
|
||||||
'notify me when available',
|
'notify me when available',
|
||||||
'notify me',
|
'notify me',
|
||||||
'sold out',
|
'sold out',
|
||||||
|
|||||||
Reference in New Issue
Block a user