diff --git a/README.md b/README.md index 52e3c609..af8eb028 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,10 @@ Results: developerInternalID: '5700313618786177705', genre: 'Tools', genreId: 'TOOLS', - familyGenre: undefined, - familyGenreId: undefined, + categories: [ + { name: 'Tools', id: 'TOOLS' }, + { name: 'Another category without id', id: null } + ], icon: 'https://lh3.googleusercontent.com/ZrNeuKthBirZN7rrXPN1JmUbaG8ICy3kZSHt-WgSnREsJzo2txzCzjIoChlevMIQEA', headerImage: 'https://lh3.googleusercontent.com/e4Sfy0cOmqpike76V6N6n-tDVbtbmt6MxbnbkKBZ_7hPHZRfsCeZhMBZK8eFDoDa1Vf-', screenshots: [ diff --git a/index.d.ts b/index.d.ts index 8fd447ec..ad6e752a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -129,8 +129,10 @@ export interface IAppItemFullDetail extends IAppItem { developerAddress: string genre: string genreId: string - familyGenre: string - familyGenreId: string + categories: Array<{ + name: string + id: string|null + }> icon: string headerImage: string screenshots: string[] diff --git a/lib/app.js b/lib/app.js index 7fc41dbc..2dcb6467 100644 --- a/lib/app.js +++ b/lib/app.js @@ -109,8 +109,20 @@ const MAPPINGS = { }, genre: ['ds:5', 1, 2, 79, 0, 0, 0], genreId: ['ds:5', 1, 2, 79, 0, 0, 2], - familyGenre: ['ds:5', 0, 12, 13, 1, 0], - familyGenreId: ['ds:5', 0, 12, 13, 1, 2], + categories: { + path: ['ds:5', 1, 2], + fun: (searchArray) => { + const categories = helper.extractCategories(R.path([118], searchArray)); + if (categories.length === 0) { + // add genre and genreId like GP does when there're no categories available + categories.push({ + name: R.path([79, 0, 0, 0], searchArray), + id: R.path([79, 0, 0, 2], searchArray) + }); + } + return categories; + } + }, icon: ['ds:5', 1, 2, 95, 0, 3, 2], headerImage: ['ds:5', 1, 2, 96, 0, 3, 2], screenshots: { diff --git a/lib/utils/mappingHelpers.js b/lib/utils/mappingHelpers.js index dc5a5512..09dbd134 100644 --- a/lib/utils/mappingHelpers.js +++ b/lib/utils/mappingHelpers.js @@ -65,6 +65,27 @@ function extractFeatures (featuresArray) { })); } +/** + * Recursively extracts the categories of the App + * @param {array} categories The categories array + */ +function extractCategories (searchArray, categories = []) { + if (searchArray === null || searchArray.length === 0) return categories; + + if (searchArray.length >= 4 && typeof searchArray[0] === 'string') { + categories.push({ + name: searchArray[0], + id: searchArray[2] + }); + } else { + searchArray.forEach((sub) => { + extractCategories(sub, categories); + }); + } + + return categories; +} + module.exports = { descriptionHtmlLocalized, descriptionText, @@ -72,5 +93,6 @@ module.exports = { normalizeAndroidVersion, buildHistogram, extractComments, - extractFeatures + extractFeatures, + extractCategories }; diff --git a/test/lib.app.js b/test/lib.app.js index 51474e71..27595ae4 100644 --- a/test/lib.app.js +++ b/test/lib.app.js @@ -21,8 +21,12 @@ const validateAppDetails = (app) => { assert.isString(app.descriptionHTML); assert.isString(app.released); assert.equal(app.genreId, 'GAME_PUZZLE'); - assert.equal(app.familyGenre, undefined); - assert.equal(app.familyGenreId, undefined); + + assert.isArray(app.categories); + assert.isAbove(app.categories.length, 1); + assert.equal(app.categories[0].id, 'GAME_PUZZLE'); + assert.notEqual(app.categories[1].id, 'GAME_PUZZLE'); + assert.hasAllKeys(app.categories[0], ['name', 'id']); assert.isString(app.version); if (app.size) {