Initial commit

master
Edward Peterson 3 years ago
parent 2397b4bbe7
commit 3a03df9c01

@ -0,0 +1,70 @@
module.exports = class {
constructor(listing) {
this.listingId = listing.idInv;
this.description = listing.strDesc;
this.condition = listing.codeNew === 'U' ? 'USED' : 'NEW';
this.complete = listing.codeComplete;
this.quantity = listing.n4Qty;
this.colorDesc = listing.strColor;
this.colorId = listing.idColor;
this.minBuy = parseMinBuy(listing.mMinBuy);
this.sellerUsername = listing.strSellerUsername;
this.sellerStoreName = listing.strStorename;
this.instantCheckout = listing.instantCheckout;
this.prices = [
{
quantity: 1,
value: parseDollars(listing.mDisplaySalePrice)
}
]
if(listing.nTier1Qty) {
//add bulk pricing tier
this.prices.push({
quantity: listing.nTier1Qty,
value: parseDollars(listing.nTier1DisplayPrice)
})
}
if(listing.nTier2Qty) {
//add bulk pricing tier
this.prices.push({
quantity: listing.nTier2Qty,
value: parseDollars(listing.nTier2DisplayPrice)
})
}
if(listing.nTier3Qty) {
//add bulk pricing tier
this.prices.push({
quantity: listing.nTier3Qty,
value: parseDollars(listing.nTier3DisplayPrice)
})
}
}
getPrice(quantity) {
for(var i = this.prices.length - 1;i >= 0;i--){
const price = this.prices[i];
console.log(price, quantity, i)
if(quantity >= price.quantity){
return price.value * quantity
}
}
return null;
}
}
const priceRegex = /US \$(?<price>\d+\.\d+)/;
function parseMinBuy(value){
if(value === 'None') return 0;
return parseDollars(value);
}
function parseDollars(val) {
const regexed = priceRegex.exec(val);
const stringPrice = regexed?.groups?.price;
if(!stringPrice){
return 999999999;
} else {
return parseFloat(stringPrice);
}
}

@ -0,0 +1,54 @@
const superagent = require('superagent');
const LotListing = require('./LotListing')
const brickLinkAgent = superagent.agent();
module.exports = {
getInternalPartId(legoPartNumber) {
return new Promise((resolve, reject) => {
brickLinkAgent.get(`https://www.bricklink.com/v2/catalog/catalogitem.page?P=${legoPartNumber}`)
// .set('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:107.0) Gecko/20100101 Firefox/107.0')
.then((response => {
const partIdRegex = /idItem:\s+(?<idItem>\d+)/gm;
const matches = partIdRegex.exec(response.text);
resolve(matches.groups?.idItem)
})).catch(error => {
console.error('HTTP error from internalPartId', error);
reject(error);
})
})
},
getListings(internalPartId) {
return new Promise((resolve, reject) => {
brickLinkAgent.get(`https://www.bricklink.com/ajax/clone/catalogifs.ajax`)
.query({
itemid: internalPartId,
loc: 'US'
})
// .set('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:107.0) Gecko/20100101 Firefox/107.0')
.set('Accept', 'application/json').then(response => {
if(!response.body.list) {
return reject('no list found');
}
resolve(response.body.list.map(l => new LotListing(l)));
}).catch(error => {
console.error('HTTP error from getListings', error)
reject(error);
})
})
},
getStoreId(sellerUsername) {
return new Promise((resolve, reject) => {
brickLinkAgent.get(`https://store.bricklink.com/${sellerUsername}`)
.then((response => {
const storeIdRegex = /username:\s+'.+',\s+id:\s+(?<storeId>\d+)/gm;
const matches = storeIdRegex.exec(response.text);
resolve(matches.groups?.storeId)
})).catch(error => {
console.error('HTTP error from getStoreId', error)
reject(error);
})
})
}
}

@ -0,0 +1,100 @@
const brickLinkAPI = require('./bricklink');
const _ = require('lodash');
const cart = [
{
partNumber: '4592c01',
quantity: 2
},
{
partNumber: '3962b',
quantity: 1
},
{
partNumber: '3022',
quantity: 1
},
{
partNumber: '4081b',
quantity: 4
},
{
partNumber: '4740',
quantity: 1
},
{
partNumber: '3031',
quantity: 1
},
{
partNumber: '30303',
quantity: 1
},
{
partNumber: '3049b',
quantity: 1
},
{
partNumber: '3069bpc1',
quantity: 1
},
{
partNumber: '3004',
quantity: 1
},
{
partNumber: '2342',
quantity: 1
},
]
Promise.each = async function(arr, fn) { // take an array and a function
const results = [];
for(const item of arr) results.push(await item);
return results;
}
Promise.each(cart.map(lot => {
return new Promise((resolve, reject) => {
brickLinkAPI.getInternalPartId(lot.partNumber).then((blId) => {
brickLinkAPI.getListings(blId).then(listings => {
console.log(listings.length + 'Listings found');
const lotsWithEnoughItems = listings.filter(l => l.quantity >= lot.quantity);
// const lotsWithEnoughItemsAndAboveMinBuy = lotsWithEnoughItems.filter(lotf => lotf.minBuy === 'None' || (lotf.getPrice(lot.quantity) > lotf.minBuy)).map(lotf => {
// lotf.calculatedPrice = lotf.getPrice(lot.quantity);
// return lotf;
// })
setTimeout(() => {
resolve(lotsWithEnoughItems);
}, 1000)
}).catch(error => {
console.error('Failed to fetch listings', error);
reject(error);
})
}).catch(error => {
console.error('Failed to fetch internal id', error);
reject(error);
})
});
})).then(parts => {
var groupedLots = [];
const possibleLots = _.flatten(parts);
possibleLots.forEach(lot => {
const group = _.findIndex(groupedLots, l => l.sellerUsername === lot.sellerUsername);
if(group === -1) {
const newGroup = {
sellerUsername: lot.sellerUsername,
minBuy: lot.minBuy,
lots: [lot]
}
groupedLots.push(newGroup);
} else {
groupedLots[group].lots.push(lot);
}
})
console.log(groupedLots.filter(gl => gl.lots.length > 1));
})

233
package-lock.json generated

@ -0,0 +1,233 @@
{
"name": "bricklinkaggregator",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
}
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
},
"cookiejar": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz",
"integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ=="
},
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"dezalgo": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
"integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
"requires": {
"asap": "^2.0.0",
"wrappy": "1"
}
},
"fast-safe-stringify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
},
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"formidable": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.1.tgz",
"integrity": "sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==",
"requires": {
"dezalgo": "^1.0.4",
"hexoid": "^1.0.0",
"once": "^1.4.0",
"qs": "^6.11.0"
}
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"get-intrinsic": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
"integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.3"
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"requires": {
"function-bind": "^1.1.1"
}
},
"has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
},
"hexoid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g=="
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
},
"mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"object-inspect": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
"integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ=="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"requires": {
"wrappy": "1"
}
},
"qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"requires": {
"side-channel": "^1.0.4"
}
},
"semver": {
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"requires": {
"lru-cache": "^6.0.0"
}
},
"side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"requires": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
}
},
"superagent": {
"version": "8.0.6",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.6.tgz",
"integrity": "sha512-HqSe6DSIh3hEn6cJvCkaM1BLi466f1LHi4yubR0tpewlMpk4RUFFy35bKz8SsPBwYfIIJy5eclp+3tCYAuX0bw==",
"requires": {
"component-emitter": "^1.3.0",
"cookiejar": "^2.1.3",
"debug": "^4.3.4",
"fast-safe-stringify": "^2.1.1",
"form-data": "^4.0.0",
"formidable": "^2.1.1",
"methods": "^1.1.2",
"mime": "2.6.0",
"qs": "^6.11.0",
"semver": "^7.3.8"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
}

@ -0,0 +1,15 @@
{
"name": "bricklinkaggregator",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"lodash": "^4.17.21",
"superagent": "^8.0.6"
}
}
Loading…
Cancel
Save