Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add new getGameHashes() function #114

Merged
merged 3 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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";
/**
joshraphael marked this conversation as resolved.
Show resolved Hide resolved
* 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 (
joshraphael marked this conversation as resolved.
Show resolved Hide resolved
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";
Loading