@mradex77/google-play-scraper 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -252,8 +252,8 @@ declare const searchOptionsSchema: z.ZodObject<{
252
252
  term: z.ZodString;
253
253
  num: z.ZodDefault<z.ZodNumber>;
254
254
  price: z.ZodDefault<z.ZodEnum<{
255
- all: "all";
256
255
  free: "free";
256
+ all: "all";
257
257
  paid: "paid";
258
258
  }>>;
259
259
  fullDetail: z.ZodDefault<z.ZodBoolean>;
package/dist/index.d.ts CHANGED
@@ -252,8 +252,8 @@ declare const searchOptionsSchema: z.ZodObject<{
252
252
  term: z.ZodString;
253
253
  num: z.ZodDefault<z.ZodNumber>;
254
254
  price: z.ZodDefault<z.ZodEnum<{
255
- all: "all";
256
255
  free: "free";
256
+ all: "all";
257
257
  paid: "paid";
258
258
  }>>;
259
259
  fullDetail: z.ZodDefault<z.ZodBoolean>;
package/dist/index.js CHANGED
@@ -495,6 +495,36 @@ const appSchema = z.object({
495
495
  url: z.string()
496
496
  });
497
497
  //#endregion
498
+ //#region src/core/text.ts
499
+ const TAB = 9;
500
+ const LINE_FEED = 10;
501
+ const CARRIAGE_RETURN = 13;
502
+ const UNIT_SEPARATOR = 31;
503
+ const DELETE = 127;
504
+ const C1_END = 159;
505
+ const SURROGATE_START = 55296;
506
+ const SURROGATE_END = 57343;
507
+ function isPreservedWhitespace(code) {
508
+ return code === TAB || code === LINE_FEED || code === CARRIAGE_RETURN;
509
+ }
510
+ function isControlCharacter(code) {
511
+ if (isPreservedWhitespace(code)) return false;
512
+ return code <= UNIT_SEPARATOR || code >= DELETE && code <= C1_END;
513
+ }
514
+ function isLoneSurrogate(code) {
515
+ return code >= SURROGATE_START && code <= SURROGATE_END;
516
+ }
517
+ function sanitizeText(value) {
518
+ if (typeof value !== "string") return;
519
+ let result = "";
520
+ for (const character of value) {
521
+ const code = character.codePointAt(0) ?? 0;
522
+ if (isControlCharacter(code) || isLoneSurrogate(code)) continue;
523
+ result += character;
524
+ }
525
+ return result;
526
+ }
527
+ //#endregion
498
528
  //#region src/features/app/transforms.ts
499
529
  const COMMENT_ROOTS = ["ds:8", "ds:9"];
500
530
  const MAX_COMMENTS = 5;
@@ -511,12 +541,11 @@ function descriptionHtmlLocalized(value) {
511
541
  0,
512
542
  1
513
543
  ]);
514
- const resolved = typeof translated === "string" && translated.length > 0 ? translated : original;
515
- return typeof resolved === "string" ? resolved : void 0;
544
+ return sanitizeText(typeof translated === "string" && translated.length > 0 ? translated : original);
516
545
  }
517
546
  function descriptionText(html) {
518
547
  if (typeof html !== "string") return;
519
- return cheerio.load(`<div>${html.replace(/<br>/g, "\r\n")}</div>`)("div").text();
548
+ return sanitizeText(cheerio.load(`<div>${html.replace(/<br>/g, "\r\n")}</div>`)("div").text());
520
549
  }
521
550
  function priceText(value) {
522
551
  return typeof value === "string" && value.length > 0 ? value : "Free";
@@ -1295,7 +1324,8 @@ const appSpecs = {
1295
1324
  1,
1296
1325
  1
1297
1326
  ]],
1298
- schema: shape$6.recentChanges
1327
+ schema: shape$6.recentChanges,
1328
+ transform: sanitizeText
1299
1329
  },
1300
1330
  comments: {
1301
1331
  paths: [[]],
@@ -1853,6 +1883,17 @@ function priceGoogleValue(value) {
1853
1883
  default: return 0;
1854
1884
  }
1855
1885
  }
1886
+ function matchesPriceFilter(free, filter) {
1887
+ switch (filter) {
1888
+ case "free": return free;
1889
+ case "paid": return !free;
1890
+ default: return true;
1891
+ }
1892
+ }
1893
+ function filterByPrice(items, filter) {
1894
+ if (filter === "all") return [...items];
1895
+ return items.filter((item) => matchesPriceFilter(item.free, filter));
1896
+ }
1856
1897
  //#endregion
1857
1898
  //#region src/features/search/search.ts
1858
1899
  const searchOptionsSchema = baseOptionsSchema.extend({
@@ -1913,7 +1954,7 @@ function createSearch(getApp) {
1913
1954
  });
1914
1955
  const client = clientFromOptions(parsed);
1915
1956
  const page = firstPage(parseScriptData(await client.request({ url: `${SEARCH_URL}?${params.toString()}` })));
1916
- const sliced = (await fetchClusterApps({
1957
+ const sliced = filterByPrice(await fetchClusterApps({
1917
1958
  client,
1918
1959
  lang: parsed.lang,
1919
1960
  country: parsed.country,
@@ -1924,7 +1965,7 @@ function createSearch(getApp) {
1924
1965
  appsPath: CLUSTER_MAPPINGS$1.apps,
1925
1966
  tokenPath: CLUSTER_MAPPINGS$1.token,
1926
1967
  context: SEARCH_CONTEXT
1927
- })).slice(0, parsed.num);
1968
+ }), parsed.price).slice(0, parsed.num);
1928
1969
  if (parsed.fullDetail) return resolveFullDetail(sliced, parsed, getApp);
1929
1970
  return z.array(searchResultSchema).parse(sliced);
1930
1971
  };
@@ -2547,17 +2588,35 @@ const developerOptionsSchema = baseOptionsSchema.extend({
2547
2588
  fullDetail: z.boolean().default(false)
2548
2589
  });
2549
2590
  const DEVELOPER_CONTEXT = "developer";
2550
- function extractInitial(blocks, numeric) {
2551
- const mappings = numeric ? NUMERIC_INITIAL_MAPPINGS : NAME_INITIAL_MAPPINGS;
2552
- const itemSpecs = numeric ? numericItemSpecs : nameItemSpecs;
2553
- const appsData = getPath(blocks, mappings.apps);
2554
- const apps = Array.isArray(appsData) ? appsData.map((item) => extract(item, itemSpecs, DEVELOPER_CONTEXT)) : [];
2555
- const token = getPath(blocks, mappings.token);
2591
+ const NUMERIC_LAYOUT = {
2592
+ mappings: NUMERIC_INITIAL_MAPPINGS,
2593
+ itemSpecs: numericItemSpecs
2594
+ };
2595
+ const NAME_LAYOUT = {
2596
+ mappings: NAME_INITIAL_MAPPINGS,
2597
+ itemSpecs: nameItemSpecs
2598
+ };
2599
+ function extractLayout(blocks, layout) {
2600
+ const appsData = getPath(blocks, layout.mappings.apps);
2601
+ if (!Array.isArray(appsData) || appsData.length === 0) return;
2602
+ const apps = appsData.map((item) => extract(item, layout.itemSpecs, DEVELOPER_CONTEXT));
2603
+ const token = getPath(blocks, layout.mappings.token);
2556
2604
  return {
2557
2605
  apps,
2558
2606
  token: typeof token === "string" ? token : void 0
2559
2607
  };
2560
2608
  }
2609
+ function extractInitial(blocks, numeric) {
2610
+ const ordered = numeric ? [NUMERIC_LAYOUT, NAME_LAYOUT] : [NAME_LAYOUT, NUMERIC_LAYOUT];
2611
+ for (const layout of ordered) {
2612
+ const extracted = extractLayout(blocks, layout);
2613
+ if (extracted !== void 0) return extracted;
2614
+ }
2615
+ return {
2616
+ apps: [],
2617
+ token: void 0
2618
+ };
2619
+ }
2561
2620
  function createDeveloper(getApp) {
2562
2621
  return async function developer(options) {
2563
2622
  const parsed = parseOptions(developerOptionsSchema, options, DEVELOPER_CONTEXT);
@@ -2841,6 +2900,9 @@ function alwaysNull() {
2841
2900
  function emptyToUndefined(value) {
2842
2901
  return typeof value === "string" && value.length > 0 ? value : void 0;
2843
2902
  }
2903
+ function cleanReplyText(value) {
2904
+ return emptyToUndefined(sanitizeText(value));
2905
+ }
2844
2906
  function buildCriteria(entry) {
2845
2907
  if (!Array.isArray(entry)) return {
2846
2908
  criteria: void 0,
@@ -2892,7 +2954,8 @@ const reviewItemSpecs = {
2892
2954
  },
2893
2955
  text: {
2894
2956
  paths: [[4]],
2895
- schema: shape.text
2957
+ schema: shape.text,
2958
+ transform: sanitizeText
2896
2959
  },
2897
2960
  replyDate: {
2898
2961
  paths: [[7, 2]],
@@ -2902,7 +2965,7 @@ const reviewItemSpecs = {
2902
2965
  replyText: {
2903
2966
  paths: [[7, 1]],
2904
2967
  schema: shape.replyText,
2905
- transform: emptyToUndefined
2968
+ transform: cleanReplyText
2906
2969
  },
2907
2970
  version: {
2908
2971
  paths: [[10]],