diff --git a/.editorconfig b/.editorconfig index b966b3b..ab0ec79 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,16 +1,18 @@ -# See editorconfig.org - root = true [*] - -indent_style = space -indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = false [*.md] +trim_trailing_whitespace = false + +[*.{js,json,yml,yaml}] +indent_style = space +indent_size = 2 -trim_trailing_whitespace = false \ No newline at end of file +#[*.go] +#indent_style = tab +#indent_size = 8 diff --git a/.gitattributes b/.gitattributes index 6a0ab8b..20f6dde 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,7 +11,8 @@ *.css text *.js text *.json text +*.go text *.bat text *.sh text -*.exe binary \ No newline at end of file +*.exe binary diff --git a/.gitignore b/.gitignore index b283d00..b53ff59 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,14 @@ -node_modules/ -npm-debug.log - .DS_Store -.idea +Thumbs.db *.log -*.heapsnapshot -.coverrun -.coverdata -dump.rdb -xunit.xml +*.exe +*.prof +*.out -sources/ \ No newline at end of file +tmp/ +logs/ +reports/ +releases/ +vendor/ +node_modules/ diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 423d103..0000000 --- a/.jshintrc +++ /dev/null @@ -1,14 +0,0 @@ -{ - "eqeqeq": true, - "trailing": true, - "strict": true, - - "unused": true, // Warns for unused variables - "forin": true, // Requires all for in loops to filter object's items - - "sub": true, // Tolerate using `[]` notation - "laxbreak": true, // Tolerate possibly unsafe line breakings - - "-W065": false, // Missing radix parameter. - "-W110": false // Mixed double and single quotes. -} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index b5b40f7..c21da9a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,8 @@ +sudo: false + language: node_js + node_js: - "0.12" - - "0.10" - - "iojs" \ No newline at end of file + - "4" + - "6" \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f1d7f72..b48956c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,37 +1,37 @@ -## Changelog +# Changelog -### 1.0.2 (2015-03-15) +## 1.0.2 (2015-03-15) -* Misc. updates +- Misc. updates -### 1.0.1 (2014-12-19) +## 1.0.1 (2014-12-19) -* Change dom element +- Change dom element -### 1.0.0 (2014-07-04) +## 1.0.0 (2014-07-04) -* Stable release +- Stable release -### 0.1.4 (2014-05-22) +## 0.1.4 (2014-05-22) -* Update badges -* Misc. updates +- Update badges +- Misc. updates -### 0.1.3 (2014-04-26) +## 0.1.3 (2014-04-26) -* Add unit test -* Add npm badge -* Add Build Status -* Add .travis.yml +- Add unit test +- Add npm badge +- Add Build Status +- Add .travis.yml -### 0.1.2 (2014-04-09) +## 0.1.2 (2014-04-09) -* Misc. changes +- Misc. changes -### 0.1.1 (2014-01-19) +## 0.1.1 (2014-01-19) -* Reimplementation for handling return and errors +- Reimplementation for handling return and errors -### 0.1.0 (2014-01-19) +## 0.1.0 (2014-01-19) -* Initial release \ No newline at end of file +- Initial release \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt index 76fb181..ff6dc6c 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,21 +1,21 @@ The MIT License (MIT) -Copyright (c) 2014 Fatih Cetinkaya (http://github.com/cmfatih/amazon-seller) +Copyright (c) 2014 Fatih Cetinkaya (http://github.com/devfacet/amazon-seller) -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index e7fb1eb..dc6d475 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ -## Amazon Seller +# Amazon Seller [![NPM][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] Amazon Seller is a module for retrieving Amazon seller information. -### Installation +## Installation -``` +```bash npm install amazon-seller ``` -### Usage +## Usage ```javascript var amzSel = require('amazon-seller'); @@ -79,13 +79,13 @@ amzSel.sellerInfo({sellerId: 'A3TYU8WJN37NYT', marketplace: 'US'}, function(err, */ ``` -### License +## License Licensed under The MIT License (MIT) For the full copyright and license information, please view the LICENSE.txt file. [npm-url]: http://npmjs.org/package/amazon-seller -[npm-image]: https://badge.fury.io/js/amazon-seller.png +[npm-image]: https://badge.fury.io/js/amazon-seller.svg -[travis-url]: https://travis-ci.org/cmfatih/amazon-seller -[travis-image]: https://travis-ci.org/cmfatih/amazon-seller.svg?branch=master \ No newline at end of file +[travis-url]: https://travis-ci.org/devfacet/amazon-seller +[travis-image]: https://travis-ci.org/devfacet/amazon-seller.svg?branch=master diff --git a/index.js b/index.js index be535f6..fd01749 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,314 @@ /* * Amazon Seller - * Copyright (c) 2014 Fatih Cetinkaya (http://github.com/cmfatih/amazon-seller) * For the full copyright and license information, please view the LICENSE.txt file. */ /* jslint node: true */ 'use strict'; -module.exports = require('./lib/'); \ No newline at end of file +var request = require('request'), + htmlParser = require("htmlparser"); + +// Init the module +module.exports = function() { + + var sellerInfo, // seller info - function + + urlList = { // list of urls + "info": { + "mobile": "/gp/aw/sp.html/?s={{sellerId}}", + "full": "/gp/aag/details/?seller={{sellerId}}" + }, + "browse": { + "mobile": "/gp/aw/b/{{sellerId}}", + "full": "/gp/browse.html?me={{sellerId}}" + } + }, + + mpDef = "US", // default marketplace + mpList = { // marketplace list + "US": { + "id": "ATVPDKIKX0DER", + "name": "US", + "url": "www.amazon.com", + "country": {"code": "US", "name": "United States"} + }, + "CA": { + "id": "A2EUQ1WTGCTBG2", + "name": "CA", + "url": "www.amazon.ca", + "country": {"code": "CA", "name": "Canada"} + }, + "UK": { + "id": "A1F83G8C2ARO7P", + "name": "UK", + "url": "www.amazon.co.uk", + "country": {"code": "UK", "name": "United Kingdom"} + }, + "DE": { + "id": "A1PA6795UKMFR9", + "name": "DE", + "url": "www.amazon.de", + "country": {"code": "DE", "name": "Germany"} + }, + "ES": { + "id": "A1RKKUPIHCS9HS", + "name": "ES", + "url": "www.amazon.es", + "country": {"code": "ES", "name": "Spain"} + }, + "FR": { + "id": "A13V1IB3VIYZZH", + "name": "FR", + "url": "www.amazon.fr", + "country": {"code": "FR", "name": "France"} + }, + "IN": { + "id": "A21TJRUUN4KGV", + "name": "IN", + "url": "www.amazon.in", + "country": {"code": "IN", "name": "India"} + }, + "IT": { + "id": "APJ6JRA9NG5V4", + "name": "IT", + "url": "www.amazon.it", + "country": {"code": "IT", "name": "Italy"} + }, + "JP": { + "id": "A1VC38T7YXB528", + "name": "JP", + "url": "www.amazon.co.jp", + "country": {"code": "JP", "name": "Japan"} + }, + "CN": { + "id": "AAHKV2X7AFYLW", + "name": "CN", + "url": "www.amazon.cn", + "country": {"code": "CN", "name": "China"} + } + }; + + // Returns seller info + sellerInfo = function sellerInfo(options, callback) { + + var returnData = null, + returnErr = null, + sellerId = null, + marketplace = null, + reqOpt = { + url: null, + method: 'GET', + timeout: 30000 + }; + + sellerId = (options && options.sellerId) ? options.sellerId : null; + marketplace = (options && options.marketplace) ? options.marketplace : mpDef; + + // Check options + if(!sellerId) { + returnErr = { + "type": "fatal", + "code": "amzsel-001", + "source": "sellerInfo", + "message": "Missing seller Id!" + }; + } + else if(!marketplace || !mpList[marketplace]) { + returnErr = { + "type": "fatal", + "code": "amzsel-002", + "source": "sellerInfo", + "message": "Invalid marketplace!" + }; + } + + if(returnErr) { + if(callback && typeof callback === 'function') { + return callback(returnErr, returnData); + } else { + return {"error": returnErr, "data": returnData}; + } + } + + returnData = { + "id": sellerId, + "name": null, + "url": { + "mobile": ('http://' + mpList[marketplace].url + urlList.info.mobile).replace('{{sellerId}}', sellerId), + "full": ('http://' + mpList[marketplace].url + urlList.info.full).replace('{{sellerId}}', sellerId) + }, + "feedback": { + "star": null, + "rating": null, + "history": { + "d30": null, + "d90": null, + "d365": null, + "lifetime": null + } + }, + "marketplace": mpList[marketplace] + }; + + // Send request + reqOpt.url = returnData.url.mobile; + + request(reqOpt, function (err, res, body) { + + if(!err && res.statusCode === 200) { + + // Parse html + var hpHandler = new htmlParser.DefaultHandler(function (err, dom) { + if(!err) { + + //console.log('dom', JSON.stringify(dom)); // for debug + //console.log('dom', JSON.stringify(dom[1].children[1], null, 2)); // for debug + + var domBody = (dom && dom[1] && dom[1].children && dom[1].children[1] && dom[1].children[1].type === 'tag' && dom[1].children[1].name === 'body') ? dom[1].children[1] : null; + + if(domBody) { + var domElems = (domBody && domBody.children) ? domBody.children : [], + domElemsCnt = domElems.length + ; + + // Check DOM + for (var i = 0; i < domElemsCnt; i++) { + + // Seller name + if(!returnData.name && domElems[i].type === 'tag' && domElems[i].attribs && domElems[i].attribs.href) { + if(domElems[i].attribs.href.indexOf('/gp/aw/b/' + sellerId + '/') > -1) { + var selNameElem = (domElems[i].children && domElems[i].children[0]) ? domElems[i].children[0] : null; + + if(selNameElem && selNameElem.type === 'text') { + returnData.name = (selNameElem && selNameElem.data) ? selNameElem.data : null; + } + } + } + + // Feedback star + if(!returnData.feedback.star && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf('Average seller feedback rating') > -1) { + var fbStarElem = ('' + domElems[i].data).replace(/(Average seller feedback rating:| )/g, '').trim().split('/'); + var fbStarVal = (fbStarElem[0]) ? parseFloat(fbStarElem[0]) : null; + + returnData.feedback.star = !isNaN(fbStarVal) ? fbStarVal : null; + } + + // Feedback rating + if(!returnData.feedback.rating && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf(' ratings)') > -1) { + var fbRatingElem = ('' + domElems[i].data).replace(/(\(| ratings\))/g, '').trim(); + var fbRatingVal = (fbRatingElem) ? parseFloat(fbRatingElem) : null; + + returnData.feedback.rating = !isNaN(fbRatingVal) ? fbRatingVal : null; + } + + // Feedback history - Last 30 days + if(!returnData.feedback.history.d30 && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf('Last 30 days') > -1) { + + returnData.feedback.history.d30 = {"positive": null, "neutral": null, "negative": null, "rating": null}; + if(domElems[i+2].type === 'text' && ('' + domElems[i+2].data).indexOf('Positive') > -1) returnData.feedback.history.d30.positive = ('' + domElems[i+2].data).replace(/(:|-|Positive)/g, '').trim(); + if(domElems[i+4].type === 'text' && ('' + domElems[i+4].data).indexOf('Neutral') > -1) returnData.feedback.history.d30.neutral = ('' + domElems[i+4].data).replace(/(:|-|Neutral)/g, '').trim(); + if(domElems[i+6].type === 'text' && ('' + domElems[i+6].data).indexOf('Negative') > -1) returnData.feedback.history.d30.negative = ('' + domElems[i+6].data).replace(/(:|-|Negative)/g, '').trim(); + if(domElems[i+8].type === 'text' && ('' + domElems[i+8].data).indexOf('Feedback Rating') > -1) returnData.feedback.history.d30.rating = ('' + domElems[i+8].data).replace(/(:|-|Feedback Rating)/g, '').trim(); + + if(returnData.feedback.history.d30.rating) { + var fbHistory30Num = parseInt(returnData.feedback.history.d30.rating, 10); + if(!isNaN(fbHistory30Num)) returnData.feedback.history.d30.rating = fbHistory30Num; + } + } + + // Feedback history - Last 90 days + if(!returnData.feedback.history.d90 && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf('Last 90 days') > -1) { + + returnData.feedback.history.d90 = {"positive": null, "neutral": null, "negative": null, "rating": null}; + if(domElems[i+2].type === 'text' && ('' + domElems[i+2].data).indexOf('Positive') > -1) returnData.feedback.history.d90.positive = ('' + domElems[i+2].data).replace(/(:|-|Positive)/g, '').trim(); + if(domElems[i+4].type === 'text' && ('' + domElems[i+4].data).indexOf('Neutral') > -1) returnData.feedback.history.d90.neutral = ('' + domElems[i+4].data).replace(/(:|-|Neutral)/g, '').trim(); + if(domElems[i+6].type === 'text' && ('' + domElems[i+6].data).indexOf('Negative') > -1) returnData.feedback.history.d90.negative = ('' + domElems[i+6].data).replace(/(:|-|Negative)/g, '').trim(); + if(domElems[i+8].type === 'text' && ('' + domElems[i+8].data).indexOf('Feedback Rating') > -1) returnData.feedback.history.d90.rating = ('' + domElems[i+8].data).replace(/(:|-|Feedback Rating)/g, '').trim(); + + if(returnData.feedback.history.d90.rating) { + var fbHistory90Num = parseInt(returnData.feedback.history.d90.rating, 10); + if(!isNaN(fbHistory90Num)) returnData.feedback.history.d90.rating = fbHistory90Num; + } + } + + // Feedback history - Last 365 days + if(!returnData.feedback.history.d365 && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf('Last 365 days') > -1) { + + returnData.feedback.history.d365 = {"positive": null, "neutral": null, "negative": null, "rating": null}; + if(domElems[i+2].type === 'text' && ('' + domElems[i+2].data).indexOf('Positive') > -1) returnData.feedback.history.d365.positive = ('' + domElems[i+2].data).replace(/(:|-|Positive)/g, '').trim(); + if(domElems[i+4].type === 'text' && ('' + domElems[i+4].data).indexOf('Neutral') > -1) returnData.feedback.history.d365.neutral = ('' + domElems[i+4].data).replace(/(:|-|Neutral)/g, '').trim(); + if(domElems[i+6].type === 'text' && ('' + domElems[i+6].data).indexOf('Negative') > -1) returnData.feedback.history.d365.negative = ('' + domElems[i+6].data).replace(/(:|-|Negative)/g, '').trim(); + if(domElems[i+8].type === 'text' && ('' + domElems[i+8].data).indexOf('Feedback Rating') > -1) returnData.feedback.history.d365.rating = ('' + domElems[i+8].data).replace(/(:|-|Feedback Rating)/g, '').trim(); + + if(returnData.feedback.history.d365.rating) { + var fbHistory365Num = parseInt(returnData.feedback.history.d365.rating, 10); + if(!isNaN(fbHistory365Num)) returnData.feedback.history.d365.rating = fbHistory365Num; + } + } + + // Feedback history - Lifetime + if(!returnData.feedback.history.lifetime && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf('Lifetime') > -1) { + + returnData.feedback.history.lifetime = {"positive": null, "neutral": null, "negative": null, "rating": null}; + if(domElems[i+2].type === 'text' && ('' + domElems[i+2].data).indexOf('Positive') > -1) returnData.feedback.history.lifetime.positive = ('' + domElems[i+2].data).replace(/(:|-|Positive)/g, '').trim(); + if(domElems[i+4].type === 'text' && ('' + domElems[i+4].data).indexOf('Neutral') > -1) returnData.feedback.history.lifetime.neutral = ('' + domElems[i+4].data).replace(/(:|-|Neutral)/g, '').trim(); + if(domElems[i+6].type === 'text' && ('' + domElems[i+6].data).indexOf('Negative') > -1) returnData.feedback.history.lifetime.negative = ('' + domElems[i+6].data).replace(/(:|-|Negative)/g, '').trim(); + if(domElems[i+8].type === 'text' && ('' + domElems[i+8].data).indexOf('Feedback Rating') > -1) returnData.feedback.history.lifetime.rating = ('' + domElems[i+8].data).replace(/(:|-|Feedback Rating)/g, '').trim(); + + if(returnData.feedback.history.lifetime.rating) { + var fbHistoryLTNum = parseInt(returnData.feedback.history.lifetime.rating, 10); + if(!isNaN(fbHistoryLTNum)) returnData.feedback.history.lifetime.rating = fbHistoryLTNum; + } + } + } + } else { + returnErr = { + "type": "fatal", + "code": "amzsel-003", + "source": "sellerInfo", + "message": "Invalid body content!" + }; + } + } else { + returnErr = { + "type": "fatal", + "code": "amzsel-004", + "source": "sellerInfo", + "message": "HTML parsing error! (" + err + ")" + }; + } + }, {ignoreWhitespace: true, verbose: false}); + + + // Remove new lines and tags (font) + var regexClr = new RegExp('<]*>|<.font[^><]*>', 'g'); + var bodyF = ('' + body).replace(/(\r\n|\n|\r||<\/b>)/gm, ''); + bodyF = bodyF.replace(regexClr, ''); + + // Parse + var hpParser = new htmlParser.Parser(hpHandler); + hpParser.parseComplete(bodyF); + + } else { + returnErr = { + "type": "fatal", + "code": "amzsel-005", + "source": "sellerInfo", + "message": (err) ? ('' + err) : 'HTTP status code: ' + ('' + res.statusCode) + }; + } + + if(callback && typeof callback === 'function') { + return callback(returnErr, returnData); + } else { + return {"error": returnErr, "data": returnData}; + } + }); + }; + + // Return + return { + sellerInfo: sellerInfo + }; +}(); \ No newline at end of file diff --git a/lib/amazon-seller.js b/lib/amazon-seller.js deleted file mode 100644 index 8811b8d..0000000 --- a/lib/amazon-seller.js +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Amazon Seller - * Copyright (c) 2014 Fatih Cetinkaya (http://github.com/cmfatih/amazon-seller) - * For the full copyright and license information, please view the LICENSE.txt file. - */ - -/* jslint node: true */ -'use strict'; - -var request = require('request'), - htmlParser = require("htmlparser"); - -// Init the module -exports = module.exports = function() { - - var sellerInfo, // seller info - function - - urlList = { // list of urls - "info": { - "mobile": "/gp/aw/sp.html/?s={{sellerId}}", - "full": "/gp/aag/details/?seller={{sellerId}}" - }, - "browse": { - "mobile": "/gp/aw/b/{{sellerId}}", - "full": "/gp/browse.html?me={{sellerId}}" - } - }, - - mpDef = "US", // default marketplace - mpList = { // marketplace list - "US": { - "id": "ATVPDKIKX0DER", - "name": "US", - "url": "www.amazon.com", - "country": {"code": "US", "name": "United States"} - }, - "CA": { - "id": "A2EUQ1WTGCTBG2", - "name": "CA", - "url": "www.amazon.ca", - "country": {"code": "CA", "name": "Canada"} - }, - "UK": { - "id": "A1F83G8C2ARO7P", - "name": "UK", - "url": "www.amazon.co.uk", - "country": {"code": "UK", "name": "United Kingdom"} - }, - "DE": { - "id": "A1PA6795UKMFR9", - "name": "DE", - "url": "www.amazon.de", - "country": {"code": "DE", "name": "Germany"} - }, - "ES": { - "id": "A1RKKUPIHCS9HS", - "name": "ES", - "url": "www.amazon.es", - "country": {"code": "ES", "name": "Spain"} - }, - "FR": { - "id": "A13V1IB3VIYZZH", - "name": "FR", - "url": "www.amazon.fr", - "country": {"code": "FR", "name": "France"} - }, - "IN": { - "id": "A21TJRUUN4KGV", - "name": "IN", - "url": "www.amazon.in", - "country": {"code": "IN", "name": "India"} - }, - "IT": { - "id": "APJ6JRA9NG5V4", - "name": "IT", - "url": "www.amazon.it", - "country": {"code": "IT", "name": "Italy"} - }, - "JP": { - "id": "A1VC38T7YXB528", - "name": "JP", - "url": "www.amazon.co.jp", - "country": {"code": "JP", "name": "Japan"} - }, - "CN": { - "id": "AAHKV2X7AFYLW", - "name": "CN", - "url": "www.amazon.cn", - "country": {"code": "CN", "name": "China"} - } - }; - - // Returns seller info - sellerInfo = function sellerInfo(options, callback) { - - var returnData = null, - returnErr = null, - sellerId = null, - marketplace = null, - reqOpt = { - url: null, - method: 'GET', - timeout: 30000 - }; - - sellerId = (options && options.sellerId) ? options.sellerId : null; - marketplace = (options && options.marketplace) ? options.marketplace : mpDef; - - // Check options - if(!sellerId) { - returnErr = { - "type": "fatal", - "code": "amzsel-001", - "source": "sellerInfo", - "message": "Missing seller Id!" - }; - } - else if(!marketplace || !mpList[marketplace]) { - returnErr = { - "type": "fatal", - "code": "amzsel-002", - "source": "sellerInfo", - "message": "Invalid marketplace!" - }; - } - - if(returnErr) { - if(callback && typeof callback === 'function') { - return callback(returnErr, returnData); - } else { - return {"error": returnErr, "data": returnData}; - } - } - - returnData = { - "id": sellerId, - "name": null, - "url": { - "mobile": ('http://' + mpList[marketplace].url + urlList.info.mobile).replace('{{sellerId}}', sellerId), - "full": ('http://' + mpList[marketplace].url + urlList.info.full).replace('{{sellerId}}', sellerId) - }, - "feedback": { - "star": null, - "rating": null, - "history": { - "d30": null, - "d90": null, - "d365": null, - "lifetime": null - } - }, - "marketplace": mpList[marketplace] - }; - - // Send request - reqOpt.url = returnData.url.mobile; - - request(reqOpt, function (err, res, body) { - - if(!err && res.statusCode === 200) { - - // Parse html - var hpHandler = new htmlParser.DefaultHandler(function (err, dom) { - if(!err) { - - //console.log('dom', JSON.stringify(dom)); // for debug - //console.log('dom', JSON.stringify(dom[1].children[1], null, 2)); // for debug - - var domBody = (dom && dom[1] && dom[1].children && dom[1].children[1] && dom[1].children[1].type === 'tag' && dom[1].children[1].name === 'body') ? dom[1].children[1] : null; - - if(domBody) { - var domElems = (domBody && domBody.children) ? domBody.children : [], - domElemsCnt = domElems.length - ; - - // Check DOM - for (var i = 0; i < domElemsCnt; i++) { - - // Seller name - if(!returnData.name && domElems[i].type === 'tag' && domElems[i].attribs && domElems[i].attribs.href) { - if(domElems[i].attribs.href.indexOf('/gp/aw/b/' + sellerId + '/') > -1) { - var selNameElem = (domElems[i].children && domElems[i].children[0]) ? domElems[i].children[0] : null; - - if(selNameElem && selNameElem.type === 'text') { - returnData.name = (selNameElem && selNameElem.data) ? selNameElem.data : null; - } - } - } - - // Feedback star - if(!returnData.feedback.star && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf('Average seller feedback rating') > -1) { - var fbStarElem = ('' + domElems[i].data).replace(/(Average seller feedback rating:| )/g, '').trim().split('/'); - var fbStarVal = (fbStarElem[0]) ? parseFloat(fbStarElem[0]) : null; - - returnData.feedback.star = !isNaN(fbStarVal) ? fbStarVal : null; - } - - // Feedback rating - if(!returnData.feedback.rating && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf(' ratings)') > -1) { - var fbRatingElem = ('' + domElems[i].data).replace(/(\(| ratings\))/g, '').trim(); - var fbRatingVal = (fbRatingElem) ? parseFloat(fbRatingElem) : null; - - returnData.feedback.rating = !isNaN(fbRatingVal) ? fbRatingVal : null; - } - - // Feedback history - Last 30 days - if(!returnData.feedback.history.d30 && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf('Last 30 days') > -1) { - - returnData.feedback.history.d30 = {"positive": null, "neutral": null, "negative": null, "rating": null}; - if(domElems[i+2].type === 'text' && ('' + domElems[i+2].data).indexOf('Positive') > -1) returnData.feedback.history.d30.positive = ('' + domElems[i+2].data).replace(/(:|-|Positive)/g, '').trim(); - if(domElems[i+4].type === 'text' && ('' + domElems[i+4].data).indexOf('Neutral') > -1) returnData.feedback.history.d30.neutral = ('' + domElems[i+4].data).replace(/(:|-|Neutral)/g, '').trim(); - if(domElems[i+6].type === 'text' && ('' + domElems[i+6].data).indexOf('Negative') > -1) returnData.feedback.history.d30.negative = ('' + domElems[i+6].data).replace(/(:|-|Negative)/g, '').trim(); - if(domElems[i+8].type === 'text' && ('' + domElems[i+8].data).indexOf('Feedback Rating') > -1) returnData.feedback.history.d30.rating = ('' + domElems[i+8].data).replace(/(:|-|Feedback Rating)/g, '').trim(); - - if(returnData.feedback.history.d30.rating) { - var fbHistory30Num = parseInt(returnData.feedback.history.d30.rating, 10); - if(!isNaN(fbHistory30Num)) returnData.feedback.history.d30.rating = fbHistory30Num; - } - } - - // Feedback history - Last 90 days - if(!returnData.feedback.history.d90 && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf('Last 90 days') > -1) { - - returnData.feedback.history.d90 = {"positive": null, "neutral": null, "negative": null, "rating": null}; - if(domElems[i+2].type === 'text' && ('' + domElems[i+2].data).indexOf('Positive') > -1) returnData.feedback.history.d90.positive = ('' + domElems[i+2].data).replace(/(:|-|Positive)/g, '').trim(); - if(domElems[i+4].type === 'text' && ('' + domElems[i+4].data).indexOf('Neutral') > -1) returnData.feedback.history.d90.neutral = ('' + domElems[i+4].data).replace(/(:|-|Neutral)/g, '').trim(); - if(domElems[i+6].type === 'text' && ('' + domElems[i+6].data).indexOf('Negative') > -1) returnData.feedback.history.d90.negative = ('' + domElems[i+6].data).replace(/(:|-|Negative)/g, '').trim(); - if(domElems[i+8].type === 'text' && ('' + domElems[i+8].data).indexOf('Feedback Rating') > -1) returnData.feedback.history.d90.rating = ('' + domElems[i+8].data).replace(/(:|-|Feedback Rating)/g, '').trim(); - - if(returnData.feedback.history.d90.rating) { - var fbHistory90Num = parseInt(returnData.feedback.history.d90.rating, 10); - if(!isNaN(fbHistory90Num)) returnData.feedback.history.d90.rating = fbHistory90Num; - } - } - - // Feedback history - Last 365 days - if(!returnData.feedback.history.d365 && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf('Last 365 days') > -1) { - - returnData.feedback.history.d365 = {"positive": null, "neutral": null, "negative": null, "rating": null}; - if(domElems[i+2].type === 'text' && ('' + domElems[i+2].data).indexOf('Positive') > -1) returnData.feedback.history.d365.positive = ('' + domElems[i+2].data).replace(/(:|-|Positive)/g, '').trim(); - if(domElems[i+4].type === 'text' && ('' + domElems[i+4].data).indexOf('Neutral') > -1) returnData.feedback.history.d365.neutral = ('' + domElems[i+4].data).replace(/(:|-|Neutral)/g, '').trim(); - if(domElems[i+6].type === 'text' && ('' + domElems[i+6].data).indexOf('Negative') > -1) returnData.feedback.history.d365.negative = ('' + domElems[i+6].data).replace(/(:|-|Negative)/g, '').trim(); - if(domElems[i+8].type === 'text' && ('' + domElems[i+8].data).indexOf('Feedback Rating') > -1) returnData.feedback.history.d365.rating = ('' + domElems[i+8].data).replace(/(:|-|Feedback Rating)/g, '').trim(); - - if(returnData.feedback.history.d365.rating) { - var fbHistory365Num = parseInt(returnData.feedback.history.d365.rating, 10); - if(!isNaN(fbHistory365Num)) returnData.feedback.history.d365.rating = fbHistory365Num; - } - } - - // Feedback history - Lifetime - if(!returnData.feedback.history.lifetime && domElems[i].type === 'text' && domElems[i].data && ('' + domElems[i].data).indexOf('Lifetime') > -1) { - - returnData.feedback.history.lifetime = {"positive": null, "neutral": null, "negative": null, "rating": null}; - if(domElems[i+2].type === 'text' && ('' + domElems[i+2].data).indexOf('Positive') > -1) returnData.feedback.history.lifetime.positive = ('' + domElems[i+2].data).replace(/(:|-|Positive)/g, '').trim(); - if(domElems[i+4].type === 'text' && ('' + domElems[i+4].data).indexOf('Neutral') > -1) returnData.feedback.history.lifetime.neutral = ('' + domElems[i+4].data).replace(/(:|-|Neutral)/g, '').trim(); - if(domElems[i+6].type === 'text' && ('' + domElems[i+6].data).indexOf('Negative') > -1) returnData.feedback.history.lifetime.negative = ('' + domElems[i+6].data).replace(/(:|-|Negative)/g, '').trim(); - if(domElems[i+8].type === 'text' && ('' + domElems[i+8].data).indexOf('Feedback Rating') > -1) returnData.feedback.history.lifetime.rating = ('' + domElems[i+8].data).replace(/(:|-|Feedback Rating)/g, '').trim(); - - if(returnData.feedback.history.lifetime.rating) { - var fbHistoryLTNum = parseInt(returnData.feedback.history.lifetime.rating, 10); - if(!isNaN(fbHistoryLTNum)) returnData.feedback.history.lifetime.rating = fbHistoryLTNum; - } - } - } - } else { - returnErr = { - "type": "fatal", - "code": "amzsel-003", - "source": "sellerInfo", - "message": "Invalid body content!" - }; - } - } else { - returnErr = { - "type": "fatal", - "code": "amzsel-004", - "source": "sellerInfo", - "message": "HTML parsing error! (" + err + ")" - }; - } - }, {ignoreWhitespace: true, verbose: false}); - - - // Remove new lines and tags (font) - var regexClr = new RegExp('<]*>|<.font[^><]*>', 'g'); - var bodyF = ('' + body).replace(/(\r\n|\n|\r||<\/b>)/gm, ''); - bodyF = bodyF.replace(regexClr, ''); - - // Parse - var hpParser = new htmlParser.Parser(hpHandler); - hpParser.parseComplete(bodyF); - - } else { - returnErr = { - "type": "fatal", - "code": "amzsel-005", - "source": "sellerInfo", - "message": (err) ? ('' + err) : 'HTTP status code: ' + ('' + res.statusCode) - }; - } - - if(callback && typeof callback === 'function') { - return callback(returnErr, returnData); - } else { - return {"error": returnErr, "data": returnData}; - } - }); - }; - - // Return - return { - sellerInfo: sellerInfo - }; -}(); \ No newline at end of file diff --git a/package.json b/package.json index 9ac1668..79d0515 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,15 @@ { "name": "amazon-seller", "version": "1.0.2", - "description": "Amazon Seller is a module for retrieving Amazon seller information.", + "description": "A module for retrieving Amazon seller information", + "main": "index.js", + "scripts": { + "test": "node node_modules/mocha/bin/mocha --timeout 5000 --slow 2000 --reporter spec test/test-all.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/devfacet/amazon-seller.git" + }, "keywords": [ "amazon", "seller", @@ -9,35 +17,16 @@ "fba", "fbm" ], - "homepage": "http://github.com/cmfatih/amazon-seller", - "repository": { - "type": "git", - "url": "https://github.com/cmfatih/amazon-seller.git" - }, - "bugs": { - "url": "http://github.com/cmfatih/amazon-seller/issues" - }, + "author": "devfacet", "license": "MIT", - "private": false, - "author": { - "name": "cmfatih", - "url": "http://github.com/cmfatih" - }, - "contributors": [], - "main": "lib/amazon-seller.js", - "scripts": { - "test": "node node_modules/mocha/bin/mocha --timeout 5000 --slow 2000 --reporter spec test/test-all.js" - }, - "engines": [ - "node >= 0.10.0" - ], + "homepage": "http://github.com/devfacet/amazon-seller", "dependencies": { - "utilex": "~1.1.0", - "request": "~2.51.0", - "htmlparser": "~1.7.7" + "utilex": "3.x.x", + "request": "2.x.x", + "htmlparser": "1.7.x" }, "devDependencies": { - "mocha": "2.2.x", - "chai": "2.1.x" + "mocha": "3.2.x", + "chai": "3.5.x" } } \ No newline at end of file