New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

google-play-scraper

Package Overview
Dependencies
Maintainers
1
Versions
87
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

google-play-scraper - npm Package Compare versions

Comparing version

to
9.2.0

14

index.d.ts

@@ -132,4 +132,6 @@ // constants

genreId: string
familyGenre: string
familyGenreId: string
categories: Array<{
name: string
id: string|null
}>
icon: string

@@ -204,3 +206,3 @@ headerImage: string

export interface IFnList {
(options?: IFnListOptions): Promise<IAppItem[]>
<T extends IFnListOptions>(options: T): T extends { fullDetail: true } ? Promise<IAppItemFullDetail[]> : Promise<IAppItem[]>
}

@@ -219,3 +221,3 @@

export interface IFnSearch {
(options: IFnSearchOptions): Promise<IAppItem[]>
<T extends IFnSearchOptions>(options: T): T extends { fullDetail: true } ? Promise<IAppItemFullDetail[]> : Promise<IAppItem[]>
}

@@ -233,3 +235,3 @@

export interface IFnDeveloper {
(options: IFnDeveloperOptions): Promise<IAppItem[]>
<T extends IFnDeveloperOptions>(options: T): T extends { fullDetail: true } ? Promise<IAppItemFullDetail[]> : Promise<IAppItem[]>
}

@@ -272,3 +274,3 @@

export interface IFnSimilar {
(options: IFnReviewsOptions): Promise<IAppItem[]>
<T extends IFnSimilarOptions>(options: T): T extends { fullDetail: true } ? Promise<IAppItemFullDetail[]> : Promise<IAppItem[]>
}

@@ -275,0 +277,0 @@

@@ -47,6 +47,9 @@ 'use strict';

description: {
path: ['ds:5', 1, 2, 72, 0, 1],
fun: helper.descriptionText
path: ['ds:5', 1, 2],
fun: (val) => helper.descriptionText(helper.descriptionHtmlLocalized(val))
},
descriptionHTML: ['ds:5', 1, 2, 72, 0, 1],
descriptionHTML: {
path: ['ds:5', 1, 2],
fun: helper.descriptionHtmlLocalized
},
summary: ['ds:5', 1, 2, 73, 0, 1],

@@ -68,2 +71,8 @@ installs: ['ds:5', 1, 2, 13, 0],

},
// If there is a discount, originalPrice if filled.
originalPrice: {
path: ['ds:5', 1, 2, 57, 0, 0, 0, 0, 1, 1, 0],
fun: (price) => price ? price / 1000000 : undefined
},
discountEndDate: ['ds:5', 1, 2, 57, 0, 0, 0, 0, 14, 1],
free: {

@@ -96,2 +105,6 @@ path: ['ds:5', 1, 2, 57, 0, 0, 0, 0, 1, 0, 0],

},
androidMaxVersion: {
path: ['ds:5', 1, 2, 140, 1, 1, 0, 1, 1],
fun: helper.normalizeAndroidVersion
},
developer: ['ds:5', 1, 2, 68, 0],

@@ -112,4 +125,16 @@ developerId: {

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],

@@ -126,2 +151,3 @@ headerImage: ['ds:5', 1, 2, 96, 0, 3, 2],

videoImage: ['ds:5', 1, 2, 100, 1, 0, 3, 2],
previewVideo: ['ds:5', 1, 2, 100, 1, 2, 0, 2],
contentRating: ['ds:5', 1, 2, 9, 0],

@@ -144,8 +170,21 @@ contentRatingDescription: ['ds:5', 1, 2, 9, 2, 1],

comments: {
path: ['ds:9', 0],
path: ['ds:8', 0],
isArray: true,
fun: helper.extractComments
},
preregister: {
path: ['ds:5', 1, 2, 18, 0],
fun: (val) => val === 1
},
earlyAccessEnabled: {
path: ['ds:5', 1, 2, 18, 2],
fun: (val) => typeof val === 'string'
},
isAvailableInPlayPass: {
path: ['ds:5', 1, 2, 62],
fun: (field) => !!field
}
};
module.exports = app;

@@ -116,3 +116,3 @@ 'use strict';

const sectionTitle = R.path(SECTIONS_MAPPING.title, section);
return R.is(String, sectionTitle) && R.isEmpty(sectionTitle);
return R.is(String, sectionTitle);
}

@@ -183,3 +183,3 @@

if (opts.num && opts.num > 250) {
throw Error("The number of results can't exceed 250");
throw Error('The number of results can\'t exceed 250');
}

@@ -186,0 +186,0 @@

const cheerio = require('cheerio');
const R = require('ramda');
function descriptionHtmlLocalized (searchArray) {
const descriptionTranslation = R.path([12, 0, 0, 1], searchArray);
const descriptionOriginal = R.path([72, 0, 1], searchArray);
return descriptionTranslation || descriptionOriginal;
}
function descriptionText (description) {

@@ -61,3 +68,25 @@ // preserve the line breaks when converting to text

/**
* 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,

@@ -68,3 +97,4 @@ priceText,

extractComments,
extractFeatures
extractFeatures,
extractCategories
};

@@ -29,3 +29,3 @@ function sleep (ms) {

* @return result of the executed function from parent settingOption @function
*/
*/
return async function returnedFunction (...args) {

@@ -32,0 +32,0 @@ // Set Date Variable if it's Empty

{
"name": "google-play-scraper",
"version": "9.1.1",
"version": "9.2.0",
"description": "scrapes app data from google play store",

@@ -27,4 +27,4 @@ "main": "index.js",

"cheerio": "^1.0.0-rc.10",
"debug": "^2.2.0",
"got": "^11.8.3",
"debug": "^3.1.0",
"got": "^11.8.6",
"memoizee": "^0.4.11",

@@ -44,4 +44,5 @@ "ramda": "^0.21.0"

"promise-log": "^0.1.0",
"sinon": "^15.2.0",
"validator": "^13.7.0"
}
}

@@ -69,2 +69,3 @@ # google-play-scraper [![workflow](https://github.com/facundoolano/google-play-scraper/actions/workflows/tests.yml/badge.svg)](https://github.com/facundoolano/google-play-scraper/actions/workflows/tests.yml)

androidVersionText: 'Varies with device',
androidMaxVersion: 'VARY',
developer: 'Google LLC',

@@ -79,4 +80,6 @@ developerId: '5700313618786177705',

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',

@@ -90,2 +93,3 @@ headerImage: 'https://lh3.googleusercontent.com/e4Sfy0cOmqpike76V6N6n-tDVbtbmt6MxbnbkKBZ_7hPHZRfsCeZhMBZK8eFDoDa1Vf-',

videoImage: undefined,
previewVideo: undefined,
contentRating: 'Everyone',

@@ -99,2 +103,5 @@ contentRatingDescription: undefined,

comments: [],
preregister: false,
earlyAccessEnabled: false,
isAvailableInPlayPass: false,
editorsChoice: true,

@@ -112,3 +119,4 @@ features: [

appId: 'com.google.android.apps.translate',
url: 'https://play.google.com/store/apps/details?id=com.google.android.apps.translate&hl=en&gl=us'
url: 'https://play.google.com/store/apps/details?id=com.google.android.apps.translate&hl=en&gl=us',
isAvailableInPlayPass: false
}

@@ -120,4 +128,4 @@ ```

* `collection` (optional, defaults to `collection.TOP_FREE`): the Google Play collection that will be retrieved. Available options can bee found [here](https://github.com/facundoolano/google-play-scraper/blob/dev/lib/constants.js#L58).
* `category` (optional, defaults to no category): the app category to filter by. Available options can bee found [here](https://github.com/facundoolano/google-play-scraper/blob/dev/lib/constants.js#L3).
* `collection` (optional, defaults to `collection.TOP_FREE`): the Google Play collection that will be retrieved. Available options can bee found [here](https://github.com/facundoolano/google-play-scraper/blob/b7669f78766b8306896447ddbe8797fe36eae49f/lib/constants.js#L67).
* `category` (optional, defaults to no category): the app category to filter by. Available options can bee found [here](https://github.com/facundoolano/google-play-scraper/blob/b7669f78766b8306896447ddbe8797fe36eae49f/lib/constants.js#L10).
* `age` (optional, defaults to no age filter): the age range to filter the apps (only for FAMILY and its subcategories). Available options are `age.FIVE_UNDER`, `age.SIX_EIGHT`, `age.NINE_UP`.

@@ -313,3 +321,3 @@ * `num` (optional, defaults to 500): the amount of apps to retrieve.

gplay.reviews({
appId: 'com.mojang.minecraftpe',
appId: 'com.dxco.pandavszombies',
sort: gplay.sort.RATING,

@@ -323,3 +331,3 @@ num: 3000

gplay.reviews({
appId: 'com.mojang.minecraftpe',
appId: 'com.dxco.pandavszombies',
sort: gplay.sort.RATING,

@@ -334,3 +342,3 @@ paginate: true,

gplay.reviews({
appId: 'com.mojang.minecraftpe',
appId: 'com.dxco.pandavszombies',
sort: gplay.sort.RATING,

@@ -337,0 +345,0 @@ paginate: true,

@@ -12,2 +12,4 @@ 'use strict';

assert.isBoolean(app.isAvailableInPlayPass);
assert.isNumber(app.score);

@@ -25,5 +27,9 @@ assert(app.score > 0);

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);

@@ -36,2 +42,3 @@ if (app.size) {

assert.equal(app.androidVersion, '7.0');
assert.equal(app.androidMaxVersion, 'VARY');

@@ -44,3 +51,6 @@ assert.isBoolean(app.available);

assert.isString(app.IAPRange);
// assert(app.preregister === false);
assert.isFalse(app.preregister);
assert.isFalse(app.earlyAccessEnabled);
assert.isUndefined(app.originalPrice);
assert.isUndefined(app.discountEndDate);

@@ -54,2 +64,3 @@ assert.equal(app.developer, 'Jam City, Inc.');

assertValidUrl(app.video);
assertValidUrl(app.previewVideo);
['1', '2', '3', '4', '5'].map((v) => assert.property(app.histogram, v));

@@ -119,3 +130,5 @@

.then((app) => {
assert.equal(app.developerAddress, '63 Market St.\nVenice CA, 90291');
assert.equal(app.developerAddress, '2772 Donald Douglas Loop, North\n' +
'Santa Monica, CA 90405\n' +
'USA');
});

@@ -185,3 +198,3 @@ });

.then((app) => {
assert.equal(app.developerInternalID, '6289421402968163029');
assert.equal(app.developerInternalID, '9028773071151690823');
});

@@ -196,2 +209,10 @@ });

});
it('should fetch android version limit set for some old apps', () => {
return gplay.app({ appId: 'air.com.zinkia.playset' })
.then((app) => {
assert.equal(app.androidVersion, '4.2');
assert.equal(app.androidMaxVersion, '7.1.1');
});
});
});

@@ -67,7 +67,7 @@ 'use strict';

describe('more results mapping', () => {
it('schould return few netflix apps', () => {
it('should return few netflix apps', () => {
return gplay.search({ term: 'netflix' })
.then((apps) => {
assert.equal(apps[0].appId, 'com.netflix.mediaclient');
assertIdsInArray(apps, 'com.netflix.ninja', 'com.netflix.NGP.StrangerThings');
assert.isAbove(apps.length, 0);
});

@@ -80,11 +80,12 @@ });

assert.equal(apps[0].appId, 'com.netflix.mediaclient');
assertIdsInArray(apps, 'com.netflix.ninja', 'com.netflix.NGP.StrangerThings');
// Don't check specific ids, as results may vary
assert.isAbove(apps.length, 1);
});
});
it('should reutrn few google mail apps', () => {
it('should return few google mail apps', () => {
return gplay.search({ term: 'gmail' })
.then((apps) => {
assert.equal(apps[0].appId, 'com.google.android.gm');
assertIdsInArray(apps, 'com.google.android.gm.lite', 'com.google.android.apps.docs');
assert.isTrue(apps.some((app) => app.appId === 'com.google.android.gm.lite'));
});

@@ -127,3 +128,3 @@ });

apps.map(assertValidApp);
assertIdsInArray(apps, 'com.runtastic.android', 'running.tracker.gps.map', 'com.google.android.apps.fitness');
assertIdsInArray(apps, 'com.runtastic.android', 'running.tracker.gps.map');
});

@@ -130,0 +131,0 @@ });

@@ -14,5 +14,5 @@ 'use strict';

it('should fetch games from different developers', () => {
return gplay.similar({ appId: 'com.mojang.minecraftpe' })
return gplay.similar({ appId: 'com.instagram.android' })
.then((apps) => assert.isTrue(apps.some(app => app.developer !== apps[0].developer)));
});
});
const requestLib = require('got');
const throttled = require('../lib/utils/throttle');
const sinon = require('sinon');
const assert = require('chai').assert;
it('Should make three requests with 5000ms interval. (Throttle function)', function (done) {
this.timeout(15000);
const req = throttled(requestLib, {
limit: 1,
interval: 5000
describe('Throttle tests', function () {
this.timeout(6000);
let server;
// Create a fake http server to emulate http call and responses.
before(function () {
server = sinon.fakeServer.create();
});
Promise.all([req({ url: 'https://httpbin.org/uuid' }), req({ url: 'https://httpbin.org/uuid' }), req({ url: 'https://httpbin.org/uuid' })])
.then((response) => response.map(req => new Date(req.headers.date).getTime()))
.then((dates) => {
const firstAndSecondReq = dates[1] - dates[0];
const secondAndThirdReq = dates[2] - dates[1];
if (
(firstAndSecondReq >= 5000 && firstAndSecondReq <= 6500) &&
(secondAndThirdReq >= 5000 && secondAndThirdReq <= 6500)
) {
done();
} else {
throw new Error('Wrong interval beetween requests.');
}
// Remove any server responses added in current test suite.
after(function () {
server.restore();
});
const url = 'https://yesno.wtf/api'; // Fake url used in this test, it could be anything.
it('Should make three requests with 2000ms interval. (Throttle function)', function () {
// If we don't want to rely on the availability of a particular api we can use mocks.
// The fake server intercept http calls and return specified objects if it mach the same method/url.
server.respondWith('GET', url, JSON.stringify({ test: 'this works' }));
const req = throttled(requestLib, {
limit: 1,
interval: 2000
});
return Promise.all([req({ url }), req({ url }), req({ url })])
.then((response) => response.map(req => new Date(req.headers.date).getTime()))
.then((dates) => {
const firstAndSecondReq = dates[1] - dates[0];
const secondAndThirdReq = dates[2] - dates[1];
assert.isAtLeast(firstAndSecondReq, 1000);
assert.isAtMost(firstAndSecondReq, 3000);
assert.isAtLeast(secondAndThirdReq, 1000);
assert.isAtMost(secondAndThirdReq, 3000);
});
});
});

Sorry, the diff of this file is not supported yet