howlongtobeat-core 1.0.0 → 1.1.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/README.md CHANGED
@@ -3,18 +3,19 @@
3
3
  A TypeScript/Deno library to retrieve game completion times from
4
4
  [HowLongToBeat.com](https://howlongtobeat.com).
5
5
 
6
- [![JSR](https://jsr.io/badges/howlongtobeat-core)](https://jsr.io/howlongtobeat-core)
6
+ [![JSR](https://jsr.io/badges/@tapan/howlongtobeat)](https://jsr.io/howlongtobeat-core)
7
7
  [![npm](https://img.shields.io/npm/v/howlongtobeat-core)](https://www.npmjs.com/package/howlongtobeat-core)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
9
 
10
10
  ## Features
11
11
 
12
- - 🎮 Search games by name or HLTB ID
13
- - ⏱️ Get completion times (Main Story, Main + Extra, Completionist)
14
- - 🔍 Dual similarity algorithms (Gestalt & Levenshtein)
15
- - 🎯 Filter by DLC, mods, or hacks
16
- - 📦 Works with Deno, Node.js, and browsers
17
- - 🔒 TypeScript-first with full type definitions
12
+ - Search games by name or HLTB ID
13
+ - Get completion times (Main Story, Main + Extra, Completionist)
14
+ - Get game statistics (releases, ratings, popular games by year/platform)
15
+ - Dual similarity algorithms (Gestalt & Levenshtein)
16
+ - Filter by DLC, mods, or hacks
17
+ - Works with Deno, Node.js, and browsers
18
+ - TypeScript-first with full type definitions
18
19
 
19
20
  ## Installation
20
21
 
@@ -60,6 +61,30 @@ const game = await hltb.searchById(68151); // Elden Ring
60
61
  console.log(game?.gameName); // "Elden Ring"
61
62
  ```
62
63
 
64
+ ### Get Game Statistics
65
+
66
+ ```typescript
67
+ // Get stats for a specific year (returns monthly breakdown)
68
+ const stats2026 = await hltb.getGameStats({ year: "2026" });
69
+ if (stats2026) {
70
+ console.log(`Total releases: ${stats2026.breakdown.totalReleases}`);
71
+ console.log(`Average time: ${stats2026.breakdown.avgTime}`);
72
+ console.log(`Average rating: ${stats2026.breakdown.avgRating}`);
73
+ console.log(`Monthly breakdown:`, stats2026.months);
74
+ }
75
+
76
+ // Get all-time stats (returns yearly breakdown)
77
+ const allTimeStats = await hltb.getGameStats();
78
+ console.log(`Yearly breakdown:`, allTimeStats?.years);
79
+
80
+ // Filter by platform, genre, perspective, etc.
81
+ const pcStats = await hltb.getGameStats({
82
+ platform: "PC",
83
+ year: "2026",
84
+ genre: "RPG",
85
+ });
86
+ ```
87
+
63
88
  ### With Options
64
89
 
65
90
  ```typescript
@@ -97,6 +122,7 @@ const dlcOnly = await hltb.search("Dark Souls", SearchModifiers.ISOLATE_DLC);
97
122
  | ------------------------- | --------------------------------------- | -------------------- |
98
123
  | `search(name, modifier?)` | `Promise<HowLongToBeatEntry[] \| null>` | Search games by name |
99
124
  | `searchById(id)` | `Promise<HowLongToBeatEntry \| null>` | Get game by HLTB ID |
125
+ | `getGameStats(options?)` | `Promise<GameStatsResponse \| null>` | Get game statistics |
100
126
 
101
127
  ### `HowLongToBeatEntry`
102
128
 
@@ -125,6 +151,31 @@ const dlcOnly = await hltb.search("Dark Souls", SearchModifiers.ISOLATE_DLC);
125
151
  | `ISOLATE_HACKS` | Only show hacks |
126
152
  | `HIDE_DLC` | Hide DLC from results |
127
153
 
154
+ ### `GameStatsOptions`
155
+
156
+ | Option | Type | Description |
157
+ | ------------- | -------- | ------------------------------------------------ |
158
+ | `platform` | `string` | Filter by platform (e.g., "PC", "PlayStation 5") |
159
+ | `year` | `string` | Filter by year (e.g., "2026") |
160
+ | `perspective` | `string` | Filter by perspective (e.g., "First-Person") |
161
+ | `flow` | `string` | Filter by pacing/flow |
162
+ | `genre` | `string` | Filter by genre (e.g., "RPG", "Action") |
163
+
164
+ ### `GameStatsResponse`
165
+
166
+ | Property | Type | Description |
167
+ | ------------------------ | ------------------------ | --------------------------------------- |
168
+ | `tags` | `StatsTags` | Applied filter tags |
169
+ | `breakdown` | `StatsBreakdown` | Summary stats (releases, avgTime, etc.) |
170
+ | `months` | `Record<string, number>` | Monthly distribution (when year set) |
171
+ | `years` | `Record<string, number>` | Yearly distribution (when year not set) |
172
+ | `platformList` | `PlatformCount[]` | Games per platform |
173
+ | `categoryMostBacklogged` | `CategoryEntry[]` | Most backlogged games |
174
+ | `categoryMostCompleted` | `CategoryEntry[]` | Most completed games |
175
+ | `categoryBestRated` | `CategoryEntry[]` | Highest rated games |
176
+ | `categoryTopPlaying` | `CategoryEntry[]` | Currently most played games |
177
+ | `popularGames` | `PopularGameEntry[]` | Popular games list |
178
+
128
179
  ## Development
129
180
 
130
181
  ```bash
package/esm/mod.d.ts CHANGED
@@ -19,12 +19,21 @@
19
19
  *
20
20
  * // Filter DLC
21
21
  * const dlcOnly = await hltb.search("Dark Souls", SearchModifiers.ISOLATE_DLC);
22
+ *
23
+ * // Get game statistics for a year
24
+ * const stats = await hltb.getGameStats({ year: "2026" });
25
+ * console.log(stats?.breakdown.totalReleases); // e.g., 771
26
+ * console.log(stats?.popularGames[0]?.title); // Most popular game
27
+ *
28
+ * // Get all-time stats (yearly breakdown)
29
+ * const allTime = await hltb.getGameStats();
30
+ * console.log(allTime?.years); // { "2020": 1000, "2021": 1200, ... }
22
31
  * ```
23
32
  *
24
33
  * @module
25
34
  */
26
35
  export { HowLongToBeat } from "./src/HowLongToBeat.js";
27
36
  export { SearchModifiers } from "./src/types.js";
28
- export type { HowLongToBeatEntry, HowLongToBeatOptions, SimilarityAlgorithm, } from "./src/types.js";
37
+ export type { CategoryEntry, GameStatsOptions, GameStatsResponse, HowLongToBeatEntry, HowLongToBeatOptions, PlatformCount, PopularGameEntry, SimilarityAlgorithm, StatsBreakdown, StatsTags, } from "./src/types.js";
29
38
  export { calculateSimilarity, gestaltSimilarity, levenshteinSimilarity, } from "./src/utils/similarity.js";
30
39
  //# sourceMappingURL=mod.d.ts.map
package/esm/mod.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EACV,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,SAAS,GACV,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC"}
package/esm/mod.js CHANGED
@@ -19,6 +19,15 @@
19
19
  *
20
20
  * // Filter DLC
21
21
  * const dlcOnly = await hltb.search("Dark Souls", SearchModifiers.ISOLATE_DLC);
22
+ *
23
+ * // Get game statistics for a year
24
+ * const stats = await hltb.getGameStats({ year: "2026" });
25
+ * console.log(stats?.breakdown.totalReleases); // e.g., 771
26
+ * console.log(stats?.popularGames[0]?.title); // Most popular game
27
+ *
28
+ * // Get all-time stats (yearly breakdown)
29
+ * const allTime = await hltb.getGameStats();
30
+ * console.log(allTime?.years); // { "2020": 1000, "2021": 1200, ... }
22
31
  * ```
23
32
  *
24
33
  * @module
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Provides methods to search for games on HowLongToBeat.com
5
5
  */
6
- import type { HowLongToBeatEntry, HowLongToBeatOptions } from "./types.js";
6
+ import type { GameStatsOptions, GameStatsResponse, HowLongToBeatEntry, HowLongToBeatOptions } from "./types.js";
7
7
  import { SearchModifiers } from "./types.js";
8
8
  /**
9
9
  * HowLongToBeat API wrapper
@@ -59,5 +59,29 @@ export declare class HowLongToBeat {
59
59
  * ```
60
60
  */
61
61
  searchById(gameId: number): Promise<HowLongToBeatEntry | null>;
62
+ /**
63
+ * Get game statistics from HowLongToBeat
64
+ *
65
+ * @param options - Optional filters for platform, year, perspective, flow, genre
66
+ * @returns Game statistics including breakdowns, platform counts, and category rankings
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const hltb = new HowLongToBeat();
71
+ *
72
+ * // Get stats for 2026
73
+ * const stats = await hltb.getGameStats({ year: "2026" });
74
+ * console.log(stats?.breakdown.totalReleases); // e.g., 771
75
+ * console.log(stats?.months); // Monthly distribution
76
+ *
77
+ * // Get all-time stats (yearly distribution)
78
+ * const allTime = await hltb.getGameStats();
79
+ * console.log(allTime?.years); // Yearly distribution
80
+ *
81
+ * // Filter by platform
82
+ * const pcStats = await hltb.getGameStats({ platform: "PC", year: "2026" });
83
+ * ```
84
+ */
85
+ getGameStats(options?: GameStatsOptions): Promise<GameStatsResponse | null>;
62
86
  }
63
87
  //# sourceMappingURL=HowLongToBeat.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HowLongToBeat.d.ts","sourceRoot":"","sources":["../../src/src/HowLongToBeat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EAErB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAkB7C;;;;;;;;;GASG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAmC;IAExE;;;;OAIG;gBACS,OAAO,GAAE,oBAAyB;IAY9C;;;;;;;;;;;;;;;OAeG;IACG,MAAM,CACV,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,eAAsC,GAC/C,OAAO,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC;IAuBvC;;;;;;;;;;;;;;OAcG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;CA8CrE"}
1
+ {"version":3,"file":"HowLongToBeat.d.ts","sourceRoot":"","sources":["../../src/src/HowLongToBeat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EAErB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAuB7C;;;;;;;;;GASG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAmC;IAExE;;;;OAIG;gBACS,OAAO,GAAE,oBAAyB;IAY9C;;;;;;;;;;;;;;;OAeG;IACG,MAAM,CACV,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,eAAsC,GAC/C,OAAO,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC;IAuBvC;;;;;;;;;;;;;;OAcG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IA+CpE;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,YAAY,CAChB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;CAUrC"}
@@ -4,8 +4,8 @@
4
4
  * Provides methods to search for games on HowLongToBeat.com
5
5
  */
6
6
  import { SearchModifiers } from "./types.js";
7
- import { executeSearch, extractGameTitle, fetchGamePage, } from "./http/client.js";
8
- import { filterBySimilarity, parseGameEntries } from "./parser/json.js";
7
+ import { executeSearch, extractGameTitle, fetchGamePage, fetchGameStats, } from "./http/client.js";
8
+ import { filterBySimilarity, parseGameEntries, parseGameStats, } from "./parser/json.js";
9
9
  import { createSimilarityCalculator } from "./utils/similarity.js";
10
10
  /**
11
11
  * Default options for HowLongToBeat
@@ -139,4 +139,35 @@ export class HowLongToBeat {
139
139
  const entries = parseGameEntries([matchingGame], gameTitle, this.autoFilterTimes, this.similarityCalculator);
140
140
  return entries.length > 0 ? entries[0] : null;
141
141
  }
142
+ /**
143
+ * Get game statistics from HowLongToBeat
144
+ *
145
+ * @param options - Optional filters for platform, year, perspective, flow, genre
146
+ * @returns Game statistics including breakdowns, platform counts, and category rankings
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * const hltb = new HowLongToBeat();
151
+ *
152
+ * // Get stats for 2026
153
+ * const stats = await hltb.getGameStats({ year: "2026" });
154
+ * console.log(stats?.breakdown.totalReleases); // e.g., 771
155
+ * console.log(stats?.months); // Monthly distribution
156
+ *
157
+ * // Get all-time stats (yearly distribution)
158
+ * const allTime = await hltb.getGameStats();
159
+ * console.log(allTime?.years); // Yearly distribution
160
+ *
161
+ * // Filter by platform
162
+ * const pcStats = await hltb.getGameStats({ platform: "PC", year: "2026" });
163
+ * ```
164
+ */
165
+ async getGameStats(options = {}) {
166
+ const response = await fetchGameStats(options);
167
+ if (!response) {
168
+ // TODO: implement proper error handling
169
+ return null;
170
+ }
171
+ return parseGameStats(response);
172
+ }
142
173
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * HTTP client for HowLongToBeat API
3
3
  */
4
- import type { HLTBSearchRequest, HLTBSearchResponse } from "../types.js";
4
+ import type { GameStatsOptions, GameStatsResponse, HLTBSearchRequest, HLTBSearchResponse } from "../types.js";
5
5
  /**
6
6
  * Build search request body
7
7
  */
@@ -22,6 +22,13 @@ export declare function extractGameTitle(html: string): string | null;
22
22
  * Get base URL for constructing image and web links
23
23
  */
24
24
  export declare function getBaseUrl(): string;
25
+ /**
26
+ * Fetch game statistics from HLTB API
27
+ *
28
+ * @param options - Optional filters for the stats query
29
+ * @returns Game statistics response, or null on error
30
+ */
31
+ export declare function fetchGameStats(options?: GameStatsOptions): Promise<GameStatsResponse | null>;
25
32
  /**
26
33
  * Clear cached token and search URL (useful for testing)
27
34
  */
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/src/http/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAqJzE;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EAAE,EACrB,QAAQ,GAAE,MAAW,EACrB,IAAI,GAAE,MAAU,EAChB,IAAI,GAAE,MAAW,GAChB,iBAAiB,CA8BnB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,MAAW,GACpB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAmCpC;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoB1E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY5D;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAIjC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/src/http/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAsJrB;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EAAE,EACrB,QAAQ,GAAE,MAAW,EACrB,IAAI,GAAE,MAAU,EAChB,IAAI,GAAE,MAAW,GAChB,iBAAiB,CA8BnB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,MAAW,GACpB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAmCpC;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoB1E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY5D;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAgCnC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAIjC"}
@@ -2,6 +2,7 @@
2
2
  * HTTP client for HowLongToBeat API
3
3
  */
4
4
  const HLTB_BASE_URL = "https://howlongtobeat.com";
5
+ const HLTB_STATS_URL = `${HLTB_BASE_URL}/api/stats/games`;
5
6
  const HLTB_SEARCH_URL = `${HLTB_BASE_URL}/api/search`;
6
7
  const HLTB_GAME_URL = `${HLTB_BASE_URL}/game`;
7
8
  /**
@@ -240,6 +241,42 @@ export function extractGameTitle(html) {
240
241
  export function getBaseUrl() {
241
242
  return HLTB_BASE_URL;
242
243
  }
244
+ /**
245
+ * Fetch game statistics from HLTB API
246
+ *
247
+ * @param options - Optional filters for the stats query
248
+ * @returns Game statistics response, or null on error
249
+ */
250
+ export async function fetchGameStats(options = {}) {
251
+ // TODO: Add filter validation for platform, year, perspective, flow, genre
252
+ const params = new URLSearchParams({
253
+ platform: options.platform ?? "",
254
+ year: options.year ?? "",
255
+ perspective: options.perspective ?? "",
256
+ flow: options.flow ?? "",
257
+ genre: options.genre ?? "",
258
+ });
259
+ try {
260
+ const response = await fetch(`${HLTB_STATS_URL}?${params.toString()}`, {
261
+ method: "GET",
262
+ headers: {
263
+ "User-Agent": getRandomUserAgent(),
264
+ "Referer": HLTB_BASE_URL,
265
+ },
266
+ });
267
+ if (!response.ok) {
268
+ // TODO: implement proper error handling
269
+ console.error(`Stats request failed: ${response.status}`);
270
+ return null;
271
+ }
272
+ return await response.json();
273
+ }
274
+ catch (error) {
275
+ // TODO: implement proper error handling
276
+ console.error("Error fetching game stats:", error);
277
+ return null;
278
+ }
279
+ }
243
280
  /**
244
281
  * Clear cached token and search URL (useful for testing)
245
282
  */
@@ -14,4 +14,15 @@ export declare function parseGameEntries(rawGames: HLTBRawGame[], searchQuery: s
14
14
  * Filter entries by minimum similarity threshold
15
15
  */
16
16
  export declare function filterBySimilarity(entries: HowLongToBeatEntry[], minimumSimilarity: number): HowLongToBeatEntry[];
17
+ import type { GameStatsResponse } from "../types.js";
18
+ /**
19
+ * Parse game stats response from HLTB API
20
+ *
21
+ * Currently passes through the response as-is since the API response
22
+ * structure matches our type definition.
23
+ *
24
+ * @param raw - Raw API response
25
+ * @returns Parsed game stats response
26
+ */
27
+ export declare function parseGameStats(raw: GameStatsResponse): GameStatsResponse;
17
28
  //# sourceMappingURL=json.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/src/parser/json.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AA2BnE;;GAEG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,UAAU,GAAE,MAAU,EACtB,eAAe,GAAE,OAAe,GAC/B,kBAAkB,CAyEpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,WAAW,EAAE,EACvB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,OAAO,EACxB,mBAAmB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,GACpD,kBAAkB,EAAE,CAgBtB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,kBAAkB,EAAE,EAC7B,iBAAiB,EAAE,MAAM,GACxB,kBAAkB,EAAE,CAItB"}
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/src/parser/json.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AA2BnE;;GAEG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,UAAU,GAAE,MAAU,EACtB,eAAe,GAAE,OAAe,GAC/B,kBAAkB,CAyEpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,WAAW,EAAE,EACvB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,OAAO,EACxB,mBAAmB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,GACpD,kBAAkB,EAAE,CAgBtB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,kBAAkB,EAAE,EAC7B,iBAAiB,EAAE,MAAM,GACxB,kBAAkB,EAAE,CAItB;AAED,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,iBAAiB,GACrB,iBAAiB,CAKnB"}
@@ -111,3 +111,18 @@ export function filterBySimilarity(entries, minimumSimilarity) {
111
111
  .filter((entry) => entry.similarity >= minimumSimilarity)
112
112
  .sort((a, b) => b.similarity - a.similarity);
113
113
  }
114
+ /**
115
+ * Parse game stats response from HLTB API
116
+ *
117
+ * Currently passes through the response as-is since the API response
118
+ * structure matches our type definition.
119
+ *
120
+ * @param raw - Raw API response
121
+ * @returns Parsed game stats response
122
+ */
123
+ export function parseGameStats(raw) {
124
+ // The API response structure matches our type definition,
125
+ // so we pass it through. This function exists for consistency
126
+ // with other parsers and future transformation needs.
127
+ return raw;
128
+ }
@@ -176,4 +176,104 @@ export interface HLTBSearchRequest {
176
176
  };
177
177
  useCache: boolean;
178
178
  }
179
+ /**
180
+ * Options for filtering game statistics
181
+ */
182
+ export interface GameStatsOptions {
183
+ /** Filter by platform (e.g., "PC", "PlayStation 5") */
184
+ platform?: string;
185
+ /** Filter by year (e.g., "2026"). If omitted, returns yearly aggregates instead of monthly */
186
+ year?: string;
187
+ /** Filter by perspective (e.g., "First-Person", "Third-Person") */
188
+ perspective?: string;
189
+ /** Filter by flow/pacing */
190
+ flow?: string;
191
+ /** Filter by genre */
192
+ genre?: string;
193
+ }
194
+ /**
195
+ * Tags/filters applied to the stats query
196
+ */
197
+ export interface StatsTags {
198
+ genres: string;
199
+ platform: string;
200
+ year: string;
201
+ }
202
+ /**
203
+ * Breakdown statistics for the filtered games
204
+ */
205
+ export interface StatsBreakdown {
206
+ /** Total number of game releases */
207
+ totalReleases: number;
208
+ /** Average completion time (formatted string like "14h 8m") */
209
+ avgTime: string;
210
+ /** Average review rating (0-100) */
211
+ avgRating: number;
212
+ /** Number of playthroughs */
213
+ playthroughs: string;
214
+ }
215
+ /**
216
+ * Platform count entry
217
+ */
218
+ export interface PlatformCount {
219
+ platform: string;
220
+ count_total: number;
221
+ }
222
+ /**
223
+ * Category entry for various rankings (most backlogged, completed, etc.)
224
+ */
225
+ export interface CategoryEntry {
226
+ game_id: number;
227
+ game_name: string;
228
+ stat: number;
229
+ }
230
+ /**
231
+ * Popular game entry with additional metadata
232
+ */
233
+ export interface PopularGameEntry {
234
+ id: number;
235
+ title: string;
236
+ platform: string;
237
+ class: string;
238
+ /** Release date in "YYYY-MM-DD" format */
239
+ stats: string;
240
+ popular: number;
241
+ }
242
+ /**
243
+ * Game statistics response from HLTB API
244
+ */
245
+ export interface GameStatsResponse {
246
+ /** Applied filter tags */
247
+ tags: StatsTags;
248
+ /** Summary breakdown statistics */
249
+ breakdown: StatsBreakdown;
250
+ /** Monthly distribution (keys "00"-"12", present when year is specified) */
251
+ months?: Record<string, number>;
252
+ /** Yearly distribution (present when year is not specified) */
253
+ years?: Record<string, number>;
254
+ /** Games per platform */
255
+ platformList: PlatformCount[];
256
+ /** Games with most backlog entries */
257
+ categoryMostBacklogged: CategoryEntry[];
258
+ /** Games with most speedruns */
259
+ categoryMostSpeedruns: CategoryEntry[];
260
+ /** Games with most completions */
261
+ categoryMostCompleted: CategoryEntry[];
262
+ /** Games with most retired/dropped entries */
263
+ categoryMostRetired: CategoryEntry[];
264
+ /** Highest rated games */
265
+ categoryBestRated: CategoryEntry[];
266
+ /** Lowest rated games */
267
+ categoryWorstRated: CategoryEntry[];
268
+ /** Games currently being played the most */
269
+ categoryTopPlaying: CategoryEntry[];
270
+ /** Most reviewed games */
271
+ categoryMostReviews: CategoryEntry[];
272
+ /** Longest games by completion time */
273
+ categoryLongestGames: CategoryEntry[];
274
+ /** Shortest games by completion time */
275
+ categoryShortestGames: CategoryEntry[];
276
+ /** Currently popular games */
277
+ popularGames: PopularGameEntry[];
278
+ }
179
279
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "howlongtobeat-core",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "TypeScript library to retrieve game completion times from HowLongToBeat.com",
5
5
  "keywords": [
6
6
  "howlongtobeat",
package/script/mod.d.ts CHANGED
@@ -19,12 +19,21 @@
19
19
  *
20
20
  * // Filter DLC
21
21
  * const dlcOnly = await hltb.search("Dark Souls", SearchModifiers.ISOLATE_DLC);
22
+ *
23
+ * // Get game statistics for a year
24
+ * const stats = await hltb.getGameStats({ year: "2026" });
25
+ * console.log(stats?.breakdown.totalReleases); // e.g., 771
26
+ * console.log(stats?.popularGames[0]?.title); // Most popular game
27
+ *
28
+ * // Get all-time stats (yearly breakdown)
29
+ * const allTime = await hltb.getGameStats();
30
+ * console.log(allTime?.years); // { "2020": 1000, "2021": 1200, ... }
22
31
  * ```
23
32
  *
24
33
  * @module
25
34
  */
26
35
  export { HowLongToBeat } from "./src/HowLongToBeat.js";
27
36
  export { SearchModifiers } from "./src/types.js";
28
- export type { HowLongToBeatEntry, HowLongToBeatOptions, SimilarityAlgorithm, } from "./src/types.js";
37
+ export type { CategoryEntry, GameStatsOptions, GameStatsResponse, HowLongToBeatEntry, HowLongToBeatOptions, PlatformCount, PopularGameEntry, SimilarityAlgorithm, StatsBreakdown, StatsTags, } from "./src/types.js";
29
38
  export { calculateSimilarity, gestaltSimilarity, levenshteinSimilarity, } from "./src/utils/similarity.js";
30
39
  //# sourceMappingURL=mod.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EACV,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,SAAS,GACV,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC"}
package/script/mod.js CHANGED
@@ -20,6 +20,15 @@
20
20
  *
21
21
  * // Filter DLC
22
22
  * const dlcOnly = await hltb.search("Dark Souls", SearchModifiers.ISOLATE_DLC);
23
+ *
24
+ * // Get game statistics for a year
25
+ * const stats = await hltb.getGameStats({ year: "2026" });
26
+ * console.log(stats?.breakdown.totalReleases); // e.g., 771
27
+ * console.log(stats?.popularGames[0]?.title); // Most popular game
28
+ *
29
+ * // Get all-time stats (yearly breakdown)
30
+ * const allTime = await hltb.getGameStats();
31
+ * console.log(allTime?.years); // { "2020": 1000, "2021": 1200, ... }
23
32
  * ```
24
33
  *
25
34
  * @module
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Provides methods to search for games on HowLongToBeat.com
5
5
  */
6
- import type { HowLongToBeatEntry, HowLongToBeatOptions } from "./types.js";
6
+ import type { GameStatsOptions, GameStatsResponse, HowLongToBeatEntry, HowLongToBeatOptions } from "./types.js";
7
7
  import { SearchModifiers } from "./types.js";
8
8
  /**
9
9
  * HowLongToBeat API wrapper
@@ -59,5 +59,29 @@ export declare class HowLongToBeat {
59
59
  * ```
60
60
  */
61
61
  searchById(gameId: number): Promise<HowLongToBeatEntry | null>;
62
+ /**
63
+ * Get game statistics from HowLongToBeat
64
+ *
65
+ * @param options - Optional filters for platform, year, perspective, flow, genre
66
+ * @returns Game statistics including breakdowns, platform counts, and category rankings
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const hltb = new HowLongToBeat();
71
+ *
72
+ * // Get stats for 2026
73
+ * const stats = await hltb.getGameStats({ year: "2026" });
74
+ * console.log(stats?.breakdown.totalReleases); // e.g., 771
75
+ * console.log(stats?.months); // Monthly distribution
76
+ *
77
+ * // Get all-time stats (yearly distribution)
78
+ * const allTime = await hltb.getGameStats();
79
+ * console.log(allTime?.years); // Yearly distribution
80
+ *
81
+ * // Filter by platform
82
+ * const pcStats = await hltb.getGameStats({ platform: "PC", year: "2026" });
83
+ * ```
84
+ */
85
+ getGameStats(options?: GameStatsOptions): Promise<GameStatsResponse | null>;
62
86
  }
63
87
  //# sourceMappingURL=HowLongToBeat.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HowLongToBeat.d.ts","sourceRoot":"","sources":["../../src/src/HowLongToBeat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EAErB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAkB7C;;;;;;;;;GASG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAmC;IAExE;;;;OAIG;gBACS,OAAO,GAAE,oBAAyB;IAY9C;;;;;;;;;;;;;;;OAeG;IACG,MAAM,CACV,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,eAAsC,GAC/C,OAAO,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC;IAuBvC;;;;;;;;;;;;;;OAcG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;CA8CrE"}
1
+ {"version":3,"file":"HowLongToBeat.d.ts","sourceRoot":"","sources":["../../src/src/HowLongToBeat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EAErB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAuB7C;;;;;;;;;GASG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAmC;IAExE;;;;OAIG;gBACS,OAAO,GAAE,oBAAyB;IAY9C;;;;;;;;;;;;;;;OAeG;IACG,MAAM,CACV,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,eAAsC,GAC/C,OAAO,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC;IAuBvC;;;;;;;;;;;;;;OAcG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IA+CpE;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,YAAY,CAChB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;CAUrC"}
@@ -142,5 +142,36 @@ class HowLongToBeat {
142
142
  const entries = (0, json_js_1.parseGameEntries)([matchingGame], gameTitle, this.autoFilterTimes, this.similarityCalculator);
143
143
  return entries.length > 0 ? entries[0] : null;
144
144
  }
145
+ /**
146
+ * Get game statistics from HowLongToBeat
147
+ *
148
+ * @param options - Optional filters for platform, year, perspective, flow, genre
149
+ * @returns Game statistics including breakdowns, platform counts, and category rankings
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * const hltb = new HowLongToBeat();
154
+ *
155
+ * // Get stats for 2026
156
+ * const stats = await hltb.getGameStats({ year: "2026" });
157
+ * console.log(stats?.breakdown.totalReleases); // e.g., 771
158
+ * console.log(stats?.months); // Monthly distribution
159
+ *
160
+ * // Get all-time stats (yearly distribution)
161
+ * const allTime = await hltb.getGameStats();
162
+ * console.log(allTime?.years); // Yearly distribution
163
+ *
164
+ * // Filter by platform
165
+ * const pcStats = await hltb.getGameStats({ platform: "PC", year: "2026" });
166
+ * ```
167
+ */
168
+ async getGameStats(options = {}) {
169
+ const response = await (0, client_js_1.fetchGameStats)(options);
170
+ if (!response) {
171
+ // TODO: implement proper error handling
172
+ return null;
173
+ }
174
+ return (0, json_js_1.parseGameStats)(response);
175
+ }
145
176
  }
146
177
  exports.HowLongToBeat = HowLongToBeat;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * HTTP client for HowLongToBeat API
3
3
  */
4
- import type { HLTBSearchRequest, HLTBSearchResponse } from "../types.js";
4
+ import type { GameStatsOptions, GameStatsResponse, HLTBSearchRequest, HLTBSearchResponse } from "../types.js";
5
5
  /**
6
6
  * Build search request body
7
7
  */
@@ -22,6 +22,13 @@ export declare function extractGameTitle(html: string): string | null;
22
22
  * Get base URL for constructing image and web links
23
23
  */
24
24
  export declare function getBaseUrl(): string;
25
+ /**
26
+ * Fetch game statistics from HLTB API
27
+ *
28
+ * @param options - Optional filters for the stats query
29
+ * @returns Game statistics response, or null on error
30
+ */
31
+ export declare function fetchGameStats(options?: GameStatsOptions): Promise<GameStatsResponse | null>;
25
32
  /**
26
33
  * Clear cached token and search URL (useful for testing)
27
34
  */
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/src/http/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAqJzE;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EAAE,EACrB,QAAQ,GAAE,MAAW,EACrB,IAAI,GAAE,MAAU,EAChB,IAAI,GAAE,MAAW,GAChB,iBAAiB,CA8BnB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,MAAW,GACpB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAmCpC;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoB1E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY5D;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAIjC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/src/http/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAsJrB;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EAAE,EACrB,QAAQ,GAAE,MAAW,EACrB,IAAI,GAAE,MAAU,EAChB,IAAI,GAAE,MAAW,GAChB,iBAAiB,CA8BnB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,MAAW,GACpB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAmCpC;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoB1E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY5D;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAgCnC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAIjC"}
@@ -8,8 +8,10 @@ exports.executeSearch = executeSearch;
8
8
  exports.fetchGamePage = fetchGamePage;
9
9
  exports.extractGameTitle = extractGameTitle;
10
10
  exports.getBaseUrl = getBaseUrl;
11
+ exports.fetchGameStats = fetchGameStats;
11
12
  exports.clearCache = clearCache;
12
13
  const HLTB_BASE_URL = "https://howlongtobeat.com";
14
+ const HLTB_STATS_URL = `${HLTB_BASE_URL}/api/stats/games`;
13
15
  const HLTB_SEARCH_URL = `${HLTB_BASE_URL}/api/search`;
14
16
  const HLTB_GAME_URL = `${HLTB_BASE_URL}/game`;
15
17
  /**
@@ -248,6 +250,42 @@ function extractGameTitle(html) {
248
250
  function getBaseUrl() {
249
251
  return HLTB_BASE_URL;
250
252
  }
253
+ /**
254
+ * Fetch game statistics from HLTB API
255
+ *
256
+ * @param options - Optional filters for the stats query
257
+ * @returns Game statistics response, or null on error
258
+ */
259
+ async function fetchGameStats(options = {}) {
260
+ // TODO: Add filter validation for platform, year, perspective, flow, genre
261
+ const params = new URLSearchParams({
262
+ platform: options.platform ?? "",
263
+ year: options.year ?? "",
264
+ perspective: options.perspective ?? "",
265
+ flow: options.flow ?? "",
266
+ genre: options.genre ?? "",
267
+ });
268
+ try {
269
+ const response = await fetch(`${HLTB_STATS_URL}?${params.toString()}`, {
270
+ method: "GET",
271
+ headers: {
272
+ "User-Agent": getRandomUserAgent(),
273
+ "Referer": HLTB_BASE_URL,
274
+ },
275
+ });
276
+ if (!response.ok) {
277
+ // TODO: implement proper error handling
278
+ console.error(`Stats request failed: ${response.status}`);
279
+ return null;
280
+ }
281
+ return await response.json();
282
+ }
283
+ catch (error) {
284
+ // TODO: implement proper error handling
285
+ console.error("Error fetching game stats:", error);
286
+ return null;
287
+ }
288
+ }
251
289
  /**
252
290
  * Clear cached token and search URL (useful for testing)
253
291
  */
@@ -14,4 +14,15 @@ export declare function parseGameEntries(rawGames: HLTBRawGame[], searchQuery: s
14
14
  * Filter entries by minimum similarity threshold
15
15
  */
16
16
  export declare function filterBySimilarity(entries: HowLongToBeatEntry[], minimumSimilarity: number): HowLongToBeatEntry[];
17
+ import type { GameStatsResponse } from "../types.js";
18
+ /**
19
+ * Parse game stats response from HLTB API
20
+ *
21
+ * Currently passes through the response as-is since the API response
22
+ * structure matches our type definition.
23
+ *
24
+ * @param raw - Raw API response
25
+ * @returns Parsed game stats response
26
+ */
27
+ export declare function parseGameStats(raw: GameStatsResponse): GameStatsResponse;
17
28
  //# sourceMappingURL=json.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/src/parser/json.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AA2BnE;;GAEG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,UAAU,GAAE,MAAU,EACtB,eAAe,GAAE,OAAe,GAC/B,kBAAkB,CAyEpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,WAAW,EAAE,EACvB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,OAAO,EACxB,mBAAmB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,GACpD,kBAAkB,EAAE,CAgBtB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,kBAAkB,EAAE,EAC7B,iBAAiB,EAAE,MAAM,GACxB,kBAAkB,EAAE,CAItB"}
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/src/parser/json.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AA2BnE;;GAEG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,UAAU,GAAE,MAAU,EACtB,eAAe,GAAE,OAAe,GAC/B,kBAAkB,CAyEpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,WAAW,EAAE,EACvB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,OAAO,EACxB,mBAAmB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,GACpD,kBAAkB,EAAE,CAgBtB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,kBAAkB,EAAE,EAC7B,iBAAiB,EAAE,MAAM,GACxB,kBAAkB,EAAE,CAItB;AAED,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,iBAAiB,GACrB,iBAAiB,CAKnB"}
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.parseGameEntry = parseGameEntry;
7
7
  exports.parseGameEntries = parseGameEntries;
8
8
  exports.filterBySimilarity = filterBySimilarity;
9
+ exports.parseGameStats = parseGameStats;
9
10
  const client_js_1 = require("../http/client.js");
10
11
  const HLTB_IMAGE_URL = "https://howlongtobeat.com/games";
11
12
  /**
@@ -116,3 +117,18 @@ function filterBySimilarity(entries, minimumSimilarity) {
116
117
  .filter((entry) => entry.similarity >= minimumSimilarity)
117
118
  .sort((a, b) => b.similarity - a.similarity);
118
119
  }
120
+ /**
121
+ * Parse game stats response from HLTB API
122
+ *
123
+ * Currently passes through the response as-is since the API response
124
+ * structure matches our type definition.
125
+ *
126
+ * @param raw - Raw API response
127
+ * @returns Parsed game stats response
128
+ */
129
+ function parseGameStats(raw) {
130
+ // The API response structure matches our type definition,
131
+ // so we pass it through. This function exists for consistency
132
+ // with other parsers and future transformation needs.
133
+ return raw;
134
+ }
@@ -176,4 +176,104 @@ export interface HLTBSearchRequest {
176
176
  };
177
177
  useCache: boolean;
178
178
  }
179
+ /**
180
+ * Options for filtering game statistics
181
+ */
182
+ export interface GameStatsOptions {
183
+ /** Filter by platform (e.g., "PC", "PlayStation 5") */
184
+ platform?: string;
185
+ /** Filter by year (e.g., "2026"). If omitted, returns yearly aggregates instead of monthly */
186
+ year?: string;
187
+ /** Filter by perspective (e.g., "First-Person", "Third-Person") */
188
+ perspective?: string;
189
+ /** Filter by flow/pacing */
190
+ flow?: string;
191
+ /** Filter by genre */
192
+ genre?: string;
193
+ }
194
+ /**
195
+ * Tags/filters applied to the stats query
196
+ */
197
+ export interface StatsTags {
198
+ genres: string;
199
+ platform: string;
200
+ year: string;
201
+ }
202
+ /**
203
+ * Breakdown statistics for the filtered games
204
+ */
205
+ export interface StatsBreakdown {
206
+ /** Total number of game releases */
207
+ totalReleases: number;
208
+ /** Average completion time (formatted string like "14h 8m") */
209
+ avgTime: string;
210
+ /** Average review rating (0-100) */
211
+ avgRating: number;
212
+ /** Number of playthroughs */
213
+ playthroughs: string;
214
+ }
215
+ /**
216
+ * Platform count entry
217
+ */
218
+ export interface PlatformCount {
219
+ platform: string;
220
+ count_total: number;
221
+ }
222
+ /**
223
+ * Category entry for various rankings (most backlogged, completed, etc.)
224
+ */
225
+ export interface CategoryEntry {
226
+ game_id: number;
227
+ game_name: string;
228
+ stat: number;
229
+ }
230
+ /**
231
+ * Popular game entry with additional metadata
232
+ */
233
+ export interface PopularGameEntry {
234
+ id: number;
235
+ title: string;
236
+ platform: string;
237
+ class: string;
238
+ /** Release date in "YYYY-MM-DD" format */
239
+ stats: string;
240
+ popular: number;
241
+ }
242
+ /**
243
+ * Game statistics response from HLTB API
244
+ */
245
+ export interface GameStatsResponse {
246
+ /** Applied filter tags */
247
+ tags: StatsTags;
248
+ /** Summary breakdown statistics */
249
+ breakdown: StatsBreakdown;
250
+ /** Monthly distribution (keys "00"-"12", present when year is specified) */
251
+ months?: Record<string, number>;
252
+ /** Yearly distribution (present when year is not specified) */
253
+ years?: Record<string, number>;
254
+ /** Games per platform */
255
+ platformList: PlatformCount[];
256
+ /** Games with most backlog entries */
257
+ categoryMostBacklogged: CategoryEntry[];
258
+ /** Games with most speedruns */
259
+ categoryMostSpeedruns: CategoryEntry[];
260
+ /** Games with most completions */
261
+ categoryMostCompleted: CategoryEntry[];
262
+ /** Games with most retired/dropped entries */
263
+ categoryMostRetired: CategoryEntry[];
264
+ /** Highest rated games */
265
+ categoryBestRated: CategoryEntry[];
266
+ /** Lowest rated games */
267
+ categoryWorstRated: CategoryEntry[];
268
+ /** Games currently being played the most */
269
+ categoryTopPlaying: CategoryEntry[];
270
+ /** Most reviewed games */
271
+ categoryMostReviews: CategoryEntry[];
272
+ /** Longest games by completion time */
273
+ categoryLongestGames: CategoryEntry[];
274
+ /** Shortest games by completion time */
275
+ categoryShortestGames: CategoryEntry[];
276
+ /** Currently popular games */
277
+ popularGames: PopularGameEntry[];
278
+ }
179
279
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/src/types.ts"],"names":[],"mappings":"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"}