From b95bd3544acffd4f6fefcf50b080d3b25af08da1 Mon Sep 17 00:00:00 2001 From: "Brennan Wilkes (Text Groove)" Date: Sat, 31 Jan 2026 16:11:33 -0800 Subject: [PATCH] feat: Improvements to strath --- src/stores/strath.js | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/stores/strath.js b/src/stores/strath.js index 1fe6c32..549160a 100644 --- a/src/stores/strath.js +++ b/src/stores/strath.js @@ -1,7 +1,7 @@ "use strict"; const { decodeHtml, stripTags, cleanText, extractFirstImgUrl } = require("../utils/html"); -const { normalizeCspc } = require("../utils/sku"); +const { normalizeCspc, pickBetterSku } = require("../utils/sku"); const { humanBytes } = require("../utils/bytes"); const { padLeft, padRight } = require("../utils/string"); @@ -97,6 +97,13 @@ function extractSkuFromArticle(articleHtml) { return ""; } +function idFromImageUrl(imgUrl) { + const s = String(imgUrl || ""); + // /1487-1_... or /1487_... or /1487-... => 1487 + const m = s.match(/\/(\d{1,11})(?=[-_])/); + return m && m[1] ? `id:${m[1]}` : ""; +} + function looksInStock(articleHtml) { const a = String(articleHtml || ""); @@ -136,22 +143,23 @@ function parseProductFromArticle(articleHtml) { const price = pickPriceFromArticle(a); const productId = extractProductIdFromArticle(a); - const skuFromHtml = extractSkuFromArticle(a); - const fallbackSku = normalizeCspc(url) || ""; - const img = extractFirstImgUrl(a, "https://www.strathliquor.com/"); + const skuFromHtml = extractSkuFromArticle(a); + const skuFromImg = idFromImageUrl(img); + const fallbackSku = normalizeCspc(url) || ""; + return { name, price, url, - sku: skuFromHtml || fallbackSku, + sku: skuFromHtml || skuFromImg || fallbackSku, productId, img, }; + } - /* ---------------- Store API paging ---------------- */ function buildStoreApiBaseUrlFromCategoryUrl(startUrl) { @@ -219,8 +227,6 @@ function normalizeProductImage(p) { return direct.startsWith("//") ? `https:${direct}` : direct; } - - function toMoneyStringFromMinorUnits(valueStr, minorUnit) { const mu = Number(minorUnit); if (!Number.isFinite(mu) || mu < 0 || mu > 6) return ""; @@ -393,16 +399,24 @@ async function scanCategoryStrath(ctx, prevDb, report) { const sku = normalizeProductSku(p); const productId = normalizeProductId(p); - const fallbackSku = sku || normalizeCspc(url) || ""; const prev = discovered.get(url) || null; - const img = normalizeProductImage(p) || (prev && prev.img) || ""; + + const apiImg = normalizeProductImage(p) || ""; + const img = apiImg || (prev && prev.img) || ""; + + const skuFromApiImg = idFromImageUrl(apiImg); + const fallbackSku = sku || skuFromApiImg || normalizeCspc(url) || ""; + + const newSku = sku || fallbackSku; + const mergedSku = pickBetterSku(newSku, prev && prev.sku); + discovered.set(url, { name, price, url, - sku: sku || fallbackSku, + sku: mergedSku, productId, img, }); @@ -433,7 +447,9 @@ async function scanCategoryStrath(ctx, prevDb, report) { ctx.logger.ok(`${ctx.catPrefixOut} | Unique products (this run): ${discovered.size}`); - const { merged, newItems, updatedItems, removedItems, restoredItems } = mergeDiscoveredIntoDb(prevDb, discovered, { storeLabel: ctx.store.name }); + const { merged, newItems, updatedItems, removedItems, restoredItems } = mergeDiscoveredIntoDb(prevDb, discovered, { + storeLabel: ctx.store.name, + }); const dbObj = buildDbObject(ctx, merged); writeJsonAtomic(ctx.dbFile, dbObj);