const superagent = require('superagent'); const LotListing = require('./LotListing') const brickLinkAgent = superagent.agent().set('Accept', 'application/json'); const htmlParser = require('node-html-parser'); const _ = require('lodash'); const brickOwlKey = process.env.brickowlKey module.exports = { getInternalPartId(legoPartNumber, type = 'Part') { return new Promise((resolve, reject) => { brickLinkAgent.get(`https://api.brickowl.com/v1/catalog/id_lookup`) .query({ key: brickOwlKey, id: legoPartNumber, type: type, }) // .set('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:107.0) Gecko/20100101 Firefox/107.0') .then((response => { if(response.statusCode !== 200) throw response.statusCode; const possibleIds = _.get(response, 'body.boids'); if(possibleIds.length != 1) { throw new Error(`Unable to uniquely get internal id for part ${legoPartNumber}, found ${possibleIds}`) } return resolve(possibleIds[0]); })).catch(error => { reject(error); }) }) }, getListings(internalPartId, colorId) { return new Promise(async (resolve, reject) => { await new Promise((resolve) => setTimeout(resolve, Math.random() * 500 + 100)); var query = { key: brickOwlKey, boid: internalPartId, country: 'US' // loc: 'US', // rpp: 100 // cond: 'U' } if(colorId){ query.color = colorId } brickLinkAgent.get(`https://api.brickowl.com/v1/catalog/availability`) .query(query) // .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) { console.log(response.body, query) return reject('no list found'); } //convert to array const list = _.values(response.body).filter(lot => { return lot.country === 'US' && lot.base_currency === 'USD' }); resolve(list.map(l => new LotListing({ idInv: l.lot_id, strDesc: l.url, codeNew: l.con === 'new' ? 'N' : 'U', codeComplete: null, n4Qty: parseInt(l.qty), strColor: 'UHHHH', idColor: l.boid.includes('-') ? l.boid.substring(l.boid.indexOf('-') + 1) : 0, mMinBuy: l.minimum_order, strSellerUsername: l.store_id, strStorename: l.store_name, instantCheckout: false, legoPartNumber: 'UHHHH', boid: l.boid, mDisplaySalePrice: l.price }))); }).catch(error => { console.error('HTTP error from getListings', error) reject(error); }) }) }, getListingsByLegoPartNumber(legoPartNumber, colorId){ return module.exports.getInternalPartId(legoPartNumber).then((blPartNumber) => module.exports.getListings(blPartNumber, colorId)).then(listings => { return listings.map(listing => { listing.legoPartNumber = legoPartNumber return listing; }) }) }, getStoreId(sellerUsername) { return new Error('Not implemented'); return new Promise((resolve, reject) => { brickLinkAgent.get(`https://store.bricklink.com/${sellerUsername}`) .then((response => { const storeIdRegex = /username:\s+'.+',\s+id:\s+(?\d+)/gm; const matches = storeIdRegex.exec(response.text); resolve(matches.groups?.storeId) })).catch(error => { console.error('HTTP error from getStoreId', error) reject(error); }) }) }, getSetInventory(setId) { return new Promise(async (resolve, reject) => { const setBoid = await module.exports.getInternalPartId(setId, 'Set') brickLinkAgent.get(`https://api.brickowl.com/v1/catalog/inventory`) .query({ key: brickOwlKey, boid: setBoid }) .then((response => { return resolve(_.get(response, 'body.inventory', []).map(type => { return { partNumber: null, internalPartId: type.boid, colorId: null, quantity: type.quantity } })) // var root = htmlParser.parse(response.text); // const rows = root.querySelectorAll('.IV_ITEM') // const parsed = rows.map(row => { // const partRegex = /\/v2\/catalog\/catalogitem.page\?P=(?.+)&idColor=(?\d+)/gm; // const quantityRegex = /\ (?\d+)/gm // const matches = partRegex.exec(row.innerHTML); // const quantityMatches = quantityRegex.exec(row.innerHTML); // if(!matches) return null; // return { // partNumber: matches.groups?.legoPartNumber, // colorId: parseInt(matches.groups?.colorId), // quantity: parseInt(quantityMatches.groups?.quantity) // } // }).filter(r => r !== null); resolve(parsed) })).catch(error => { console.error('HTTP error from getStoreId', error) reject(error); }) }) }, getDetails(boid) { return new Promise((resolve, reject) => { brickLinkAgent.get(`https://api.brickowl.com/v1/catalog/lookup`) .query({ key: brickOwlKey, boid: boid }) .then((response => { resolve(response.body) })).catch(error => { console.error('HTTP error from getStoreId', error) reject(error); }) }) } }