howlongtobeat-core 0.1.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 +58 -7
- package/esm/mod.d.ts +11 -2
- package/esm/mod.d.ts.map +1 -1
- package/esm/mod.js +10 -1
- package/esm/src/HowLongToBeat.d.ts +25 -1
- package/esm/src/HowLongToBeat.d.ts.map +1 -1
- package/esm/src/HowLongToBeat.js +33 -2
- package/esm/src/http/client.d.ts +8 -1
- package/esm/src/http/client.d.ts.map +1 -1
- package/esm/src/http/client.js +37 -0
- package/esm/src/parser/json.d.ts +11 -0
- package/esm/src/parser/json.d.ts.map +1 -1
- package/esm/src/parser/json.js +15 -0
- package/esm/src/types.d.ts +100 -0
- package/esm/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/script/mod.d.ts +11 -2
- package/script/mod.d.ts.map +1 -1
- package/script/mod.js +9 -0
- package/script/src/HowLongToBeat.d.ts +25 -1
- package/script/src/HowLongToBeat.d.ts.map +1 -1
- package/script/src/HowLongToBeat.js +31 -0
- package/script/src/http/client.d.ts +8 -1
- package/script/src/http/client.d.ts.map +1 -1
- package/script/src/http/client.js +38 -0
- package/script/src/parser/json.d.ts +11 -0
- package/script/src/parser/json.d.ts.map +1 -1
- package/script/src/parser/json.js +16 -0
- package/script/src/types.d.ts +100 -0
- package/script/src/types.d.ts.map +1 -1
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
|
-
[](https://jsr.io/howlongtobeat-core)
|
|
7
7
|
[](https://www.npmjs.com/package/howlongtobeat-core)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
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";
|
|
29
|
-
export { calculateSimilarity, gestaltSimilarity, levenshteinSimilarity } from "./src/utils/similarity.js";
|
|
37
|
+
export type { CategoryEntry, GameStatsOptions, GameStatsResponse, HowLongToBeatEntry, HowLongToBeatOptions, PlatformCount, PopularGameEntry, SimilarityAlgorithm, StatsBreakdown, StatsTags, } from "./src/types.js";
|
|
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
|
|
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
|
|
@@ -28,4 +37,4 @@ export { HowLongToBeat } from "./src/HowLongToBeat.js";
|
|
|
28
37
|
// Types and enums
|
|
29
38
|
export { SearchModifiers } from "./src/types.js";
|
|
30
39
|
// Utility exports for advanced usage
|
|
31
|
-
export { calculateSimilarity, gestaltSimilarity, levenshteinSimilarity } from "./src/utils/similarity.js";
|
|
40
|
+
export { calculateSimilarity, gestaltSimilarity, levenshteinSimilarity, } from "./src/utils/similarity.js";
|
|
@@ -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;
|
|
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"}
|
package/esm/src/HowLongToBeat.js
CHANGED
|
@@ -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
|
}
|
package/esm/src/http/client.d.ts
CHANGED
|
@@ -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,
|
|
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"}
|
package/esm/src/http/client.js
CHANGED
|
@@ -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
|
*/
|
package/esm/src/parser/json.d.ts
CHANGED
|
@@ -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"}
|
package/esm/src/parser/json.js
CHANGED
|
@@ -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
|
+
}
|
package/esm/src/types.d.ts
CHANGED
|
@@ -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
|
package/esm/src/types.d.ts.map
CHANGED
|
@@ -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
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";
|
|
29
|
-
export { calculateSimilarity, gestaltSimilarity, levenshteinSimilarity } from "./src/utils/similarity.js";
|
|
37
|
+
export type { CategoryEntry, GameStatsOptions, GameStatsResponse, HowLongToBeatEntry, HowLongToBeatOptions, PlatformCount, PopularGameEntry, SimilarityAlgorithm, StatsBreakdown, StatsTags, } from "./src/types.js";
|
|
38
|
+
export { calculateSimilarity, gestaltSimilarity, levenshteinSimilarity, } from "./src/utils/similarity.js";
|
|
30
39
|
//# sourceMappingURL=mod.d.ts.map
|
package/script/mod.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA
|
|
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;
|
|
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,
|
|
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
|
+
}
|
package/script/src/types.d.ts
CHANGED
|
@@ -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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"}
|