Skip to content

Commit

Permalink
feat: add new getGameHashes() function (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshraphael authored Jan 8, 2025
1 parent 29d9910 commit 18c12fb
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ Click the function names to open their complete docs on the docs site.

- [`getGame()`](https://api-docs.retroachievements.org/v1/get-game.html) - Get basic metadata about a game.
- [`getGameExtended()`](https://api-docs.retroachievements.org/v1/get-game-extended.html) - Get extended metadata about a game.
- [`getGameHashes()`](https://api-docs.retroachievements.org/v1/get-game-hashes.html) - Get a list of hashes linked to a game.
- [`getAchievementCount()`](https://api-docs.retroachievements.org/v1/get-achievement-count.html) - Get the list of achievement IDs for a game.
- [`getAchievementDistribution()`](https://api-docs.retroachievements.org/v1/get-achievement-distribution.html) - Get how many players have unlocked how many achievements for a game.
- [`getGameRankAndScore()`](https://api-docs.retroachievements.org/v1/get-game-rank-and-score.html) - Get a list of either the latest masters or highest hardcore points earners for a game.
Expand Down
5 changes: 4 additions & 1 deletion src/console/getConsoleIds.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ describe("Function: getConsoleIds", () => {
);

// ACT
const response = await getConsoleIds(authorization);
const response = await getConsoleIds(authorization, {
shouldOnlyRetrieveActiveSystems: true,
shouldOnlyRetrieveGameSystems: true,
});

// ASSERT
const expectedResponse: FetchedSystem[] = [
Expand Down
7 changes: 6 additions & 1 deletion src/feed/getRecentGameAwards.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ describe("Function: getRecentGameAwards", () => {
);

// ACT
const response = await getRecentGameAwards(authorization);
const response = await getRecentGameAwards(authorization, {
startDate: "2025-01-05",
offset: 10,
count: 10,
desiredAwardKinds: ["completed"],
});

const expectedResponse: RecentGameAwards = {
count: 1,
Expand Down
77 changes: 77 additions & 0 deletions src/game/getGameHashes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/* eslint-disable sonarjs/no-duplicate-string */

import { http, HttpResponse } from "msw";
import { setupServer } from "msw/node";

import { apiBaseUrl } from "../utils/internal";
import { buildAuthorization } from "../utils/public";
import { getGameHashes } from "./getGameHashes";
import type { GetGameHashesResponse } from "./models";

const server = setupServer();

describe("Function: getGameExtended", () => {
// MSW Setup
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

it("is defined #sanity", () => {
// ASSERT
expect(getGameHashes).toBeDefined();
});

it("given a game ID, retrieves extended metadata about the game", async () => {
// ARRANGE
const authorization = buildAuthorization({
username: "mockUserName",
webApiKey: "mockWebApiKey",
});

const mockResponse: GetGameHashesResponse = {
Results: [
{
Name: "Sonic The Hedgehog (USA, Europe) (Ru) (NewGame).md",
MD5: "1b1d9ac862c387367e904036114c4825",
Labels: ["nointro", "rapatches"],
PatchUrl:
"https://github.com/RetroAchievements/RAPatches/raw/main/MD/Translation/Russian/1-Sonic1-Russian.zip",
},
{
Name: "Sonic The Hedgehog (USA, Europe).md",
MD5: "1bc674be034e43c96b86487ac69d9293",
Labels: ["nointro"],
PatchUrl: null,
},
],
};

server.use(
http.get(`${apiBaseUrl}/API_GetGameHashes.php`, () =>
HttpResponse.json(mockResponse)
)
);

// ACT
const response = await getGameHashes(authorization, { gameId: 1 });

// ASSERT
expect(response).toEqual({
results: [
{
name: "Sonic The Hedgehog (USA, Europe) (Ru) (NewGame).md",
md5: "1b1d9ac862c387367e904036114c4825",
labels: ["nointro", "rapatches"],
patchUrl:
"https://github.com/RetroAchievements/RAPatches/raw/main/MD/Translation/Russian/1-Sonic1-Russian.zip",
},
{
name: "Sonic The Hedgehog (USA, Europe).md",
md5: "1bc674be034e43c96b86487ac69d9293",
labels: ["nointro"],
patchUrl: null,
},
],
});
});
});
66 changes: 66 additions & 0 deletions src/game/getGameHashes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { ID } from "../utils/internal";
import {
apiBaseUrl,
buildRequestUrl,
call,
serializeProperties,
} from "../utils/internal";
import type { AuthObject } from "../utils/public";
import type { GameHashes, GetGameHashesResponse } from "./models";

/**
* A call to this function will retrieve a list of hashes linked to a game.
*
* @param authorization An object containing your username and webApiKey.
* This can be constructed with `buildAuthorization()`.
*
* @param payload.gameId The unique game ID. If you are unsure, open the
* game's page on the RetroAchievements.org website. For example, Dragster's
* URL is https://retroachievements.org/game/14402. We can see from the
* URL that the game ID is "14402".
*
* @example
* ```
* const game = await getGameHashes(
* authorization,
* { gameId: 14402 }
* );
* ```
*
* @returns An object containing a list of game hashes.
* ```json
* {
* "Results": [
* {
* "MD5": "1b1d9ac862c387367e904036114c4825",
* "Name": "Sonic The Hedgehog (USA, Europe) (Ru) (NewGame).md",
* "Labels": ["nointro", "rapatches"],
* "PatchUrl": "https://github.com/RetroAchievements/RAPatches/raw/main/MD/Translation/Russian/1-Sonic1-Russian.zip"
* },
* {
* "MD5": "1bc674be034e43c96b86487ac69d9293",
* "Name": "Sonic The Hedgehog (USA, Europe).md",
* "Labels": ["nointro"],
* "PatchUrl": null
* }
* ]
* }
* ```
*/
export const getGameHashes = async (
authorization: AuthObject,
payload: { gameId: ID }
): Promise<GameHashes> => {
const { gameId } = payload;

const url = buildRequestUrl(
apiBaseUrl,
"/API_GetGameHashes.php",
authorization,
{ i: gameId }
);

const rawResponse = await call<GetGameHashesResponse>({ url });

return serializeProperties(rawResponse);
};
1 change: 1 addition & 0 deletions src/game/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from "./getAchievementCount";
export * from "./getAchievementDistribution";
export * from "./getGame";
export * from "./getGameExtended";
export * from "./getGameHashes";
export * from "./getGameRankAndScore";
export * from "./getGameRating";
export * from "./models";
10 changes: 10 additions & 0 deletions src/game/models/game-hashes.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
interface GameHash {
md5: string;
name: string;
labels: string[];
patchUrl: string;
}

export interface GameHashes {
results: GameHash[];
}
10 changes: 10 additions & 0 deletions src/game/models/get-game-hashes-response.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
interface GameHashResult {
MD5: string;
Name: string;
Labels: string[];
PatchUrl: string;
}

export interface GetGameHashesResponse {
Results: GameHashResult[];
}
2 changes: 2 additions & 0 deletions src/game/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ export * from "./game.model";
export * from "./game-extended.model";
export * from "./game-extended-achievement-entity.model";
export * from "./game-extended-claim-entity.model";
export * from "./game-hashes.model";
export * from "./game-rank-and-score-entity.model";
export * from "./game-rating.model";
export * from "./get-achievement-count-response.model";
export * from "./get-achievement-distribution-response.model";
export * from "./get-game-extended-response.model";
export * from "./get-game-hashes-response.model";
export * from "./get-game-rank-and-score-response.model";
export * from "./get-game-rating-response.model";
export * from "./get-game-response.model";

0 comments on commit 18c12fb

Please sign in to comment.