From 931edc0c9299f3b1635ee7934a6c056d26d1712d Mon Sep 17 00:00:00 2001 From: Stefan Wagner Date: Fri, 30 Jun 2023 19:20:37 +0200 Subject: [PATCH 1/2] Add gurkerl v1 (no categories) --- site/model/stores.js | 8 +++ stores/gurkerl.js | 119 +++++++++++++++++++++++++++++++++++++++++++ stores/index.js | 1 + 3 files changed, 128 insertions(+) create mode 100644 stores/gurkerl.js diff --git a/site/model/stores.js b/site/model/stores.js index f99eaf33..c024dc08 100644 --- a/site/model/stores.js +++ b/site/model/stores.js @@ -66,6 +66,14 @@ exports.stores = { getUrl: (item) => `https://www.penny.at/produkte/${item.url}`, removeOld: true, }, + gurkerl: { + name: "gurkerl", + budgetBrands: ["kitchin", "yutto", "fjoru", "miil", "moddia", "dacello", "pappudia", "ubomi", "sutcha"], // taken from https://www.gurkerl.at/c135195-unsere-marken + color: "green", + defaultChecked: true, + getUrl: (item) => `https://www.gurkerl.at/${item.id}`, + removeOld: true, + }, dmDe: { name: "DM DE", budgetBrands: ["balea"], diff --git a/stores/gurkerl.js b/stores/gurkerl.js new file mode 100644 index 00000000..b4ceea31 --- /dev/null +++ b/stores/gurkerl.js @@ -0,0 +1,119 @@ +const axios = require("axios"); +const utils = require("./utils"); + +const units = { + bund: { unit: "stk", factor: 1 }, + pack: { unit: "stk", factor: 1 }, + wl: { unit: "stk", factor: 1 }, + " 200 stk": { unit: "stk", factor: 200 }, +}; + +const GURKERL_WARHOUSE = 9000; + +async function getCategories() { + let path = `https://www.gurkerl.at/services/frontend-service/renderer/navigation/flat.json?warehouseId=${GURKERL_WARHOUSE}`; + let json = await axios.get(path); + let cids = []; + + for (const [key, value] of Object.entries(json.data.navigation)) { + if (value.parentId > 0) { + continue; + } + cids.push(value.id); + } + + return cids; +} + +async function getChunked(urlPrefix, ids, chunkSize = 200) { + let res = []; + let chunks = []; + let retries = 0; + + for (let i = 0; i < ids.length; i += chunkSize) { + chunks.push(ids.slice(i, i + chunkSize)); + } + + for (let [idx, chunk] of chunks.entries()) { + // console.log(`Chunk ${idx+1}/${chunks.length}`); + let json; + try { + json = await axios.get(urlPrefix + chunk.join("&"), { timeout: 2000 }); + } catch (ex) { + console.error(ex); + } + + if (json) { + res = res.concat(json.data); + } else { + idx--; + retries++; + } + await sleep(retries * 100); + } + + return res; +} + +async function getProducts(cid) { + let path = `https://www.gurkerl.at/api/v1/categories/normal/${cid}/products?page=0&size=10000`; + let pidsJSON = await axios.get(path); + let pids = pidsJSON.data.productIds; + + let pidsQuery = pids.map((pid) => `products=${pid}`); + let products = await getChunked(`https://www.gurkerl.at/api/v1/products?`, pidsQuery); + + let jsonPrices = await getChunked(`https://www.gurkerl.at/api/v1/products/prices?`, pidsQuery); + jsonPrices.forEach((p) => { + let pIndex = products.findIndex((prod) => prod.id == p.productId); + products[pIndex].price = p.price; + products[pIndex].sales = p.sales; + }); + + return products; +} + +exports.getCanonical = function (item, today) { + let [quantity, unit] = utils.parseUnitAndQuantityAtEnd(item.textualAmount); + + let price = item.price.amount; + if (item.sales?.[0]?.type == "sale") { + // Temp. discounted price + price = item.sales[0].price.amount; + } + + return utils.convertUnit( + { + id: item.id, + name: item.name, + price: price, + priceHistory: [{ date: today, price: price }], + quantity, + unit, + bio: item.name.toLowerCase().includes("bio"), + slug: item.id, // @TODO: add real slug, id only works though + }, + units, + "gurkerl" + ); +}; + +exports.fetchData = async function () { + let cids = await getCategories(); + let products = []; + + for (let cid of cids) { + console.log(`Fetching category ${cid}:`); + products = products.concat(await getProducts(cid)); + } + + return products; +}; + +exports.initializeCategoryMapping = async () => {}; + +exports.mapCategory = (rawItem) => {}; + +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} diff --git a/stores/index.js b/stores/index.js index b7f1f67e..04e91489 100644 --- a/stores/index.js +++ b/stores/index.js @@ -11,3 +11,4 @@ exports.reweDe = require("./rewe-de"); exports.penny = require("./penny"); exports.mueller = require("./mueller"); exports.muellerDe = require("./mueller-de"); +exports.gurkerl = require("./gurkerl"); From 3646080832c651881908f81360641e39c63cfeeb Mon Sep 17 00:00:00 2001 From: Stefan Wagner Date: Fri, 30 Jun 2023 19:31:29 +0200 Subject: [PATCH 2/2] gurkerl: dedplicate products --- stores/gurkerl.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stores/gurkerl.js b/stores/gurkerl.js index b4ceea31..9e955e39 100644 --- a/stores/gurkerl.js +++ b/stores/gurkerl.js @@ -107,6 +107,8 @@ exports.fetchData = async function () { products = products.concat(await getProducts(cid)); } + products = [...new Map(products.map((p) => [p.id, p])).values()]; + return products; };