Skip to content

Commit

Permalink
feat: adding change hero
Browse files Browse the repository at this point in the history
  • Loading branch information
thegrannychaseroperation committed Oct 5, 2024
1 parent 586df61 commit 035e424
Show file tree
Hide file tree
Showing 48 changed files with 521 additions and 501 deletions.
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@
"@vanilla-extract/css": "^1.14.2",
"@vanilla-extract/dynamic": "^2.1.1",
"@vanilla-extract/recipes": "^0.5.2",
"adm-zip": "^0.5.16",
"archiver": "^7.0.1",
"auto-launch": "^5.0.6",
"axios": "^1.7.7",
"better-sqlite3": "^11.2.1",
Expand Down Expand Up @@ -74,6 +72,7 @@
"react-redux": "^9.1.1",
"react-router-dom": "^6.22.3",
"sudo-prompt": "^9.2.1",
"tar": "^7.4.3",
"typeorm": "^0.3.20",
"user-agents": "^1.1.193",
"yaml": "^2.4.1",
Expand All @@ -88,8 +87,6 @@
"@electron-toolkit/tsconfig": "^1.0.1",
"@sentry/vite-plugin": "^2.20.1",
"@swc/core": "^1.4.16",
"@types/adm-zip": "^0.5.5",
"@types/archiver": "^6.0.2",
"@types/auto-launch": "^5.0.5",
"@types/color": "^3.0.6",
"@types/folder-hash": "^4.0.4",
Expand Down
2 changes: 1 addition & 1 deletion src/main/events/catalogue/get-catalogue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const getCatalogue = async (
title: steamGame.name,
shop: game.shop,
cover: steamUrlBuilder.library(game.objectId),
objectID: game.objectId,
objectId: game.objectId,
};
})
);
Expand Down
18 changes: 9 additions & 9 deletions src/main/events/catalogue/get-game-shop-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import { registerEvent } from "../register-event";
import { steamGamesWorker } from "@main/workers";

const getLocalizedSteamAppDetails = async (
objectID: string,
objectId: string,
language: string
): Promise<ShopDetails | null> => {
if (language === "english") {
return getSteamAppDetails(objectID, language);
return getSteamAppDetails(objectId, language);
}

return getSteamAppDetails(objectID, language).then(
return getSteamAppDetails(objectId, language).then(
async (localizedAppDetails) => {
const steamGame = await steamGamesWorker.run(Number(objectID), {
const steamGame = await steamGamesWorker.run(Number(objectId), {
name: "getById",
});

Expand All @@ -34,21 +34,21 @@ const getLocalizedSteamAppDetails = async (

const getGameShopDetails = async (
_event: Electron.IpcMainInvokeEvent,
objectID: string,
objectId: string,
shop: GameShop,
language: string
): Promise<ShopDetails | null> => {
if (shop === "steam") {
const cachedData = await gameShopCacheRepository.findOne({
where: { objectID, language },
where: { objectID: objectId, language },
});

const appDetails = getLocalizedSteamAppDetails(objectID, language).then(
const appDetails = getLocalizedSteamAppDetails(objectId, language).then(
(result) => {
if (result) {
gameShopCacheRepository.upsert(
{
objectID,
objectID: objectId,
shop: "steam",
language,
serializedData: JSON.stringify(result),
Expand All @@ -68,7 +68,7 @@ const getGameShopDetails = async (
if (cachedGame) {
return {
...cachedGame,
objectID,
objectId,
} as ShopDetails;
}

Expand Down
31 changes: 16 additions & 15 deletions src/main/events/catalogue/get-games.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import type { CatalogueEntry } from "@types";

import { registerEvent } from "../register-event";
import { steamGamesWorker } from "@main/workers";
import { HydraApi } from "@main/services";
import { steamUrlBuilder } from "@shared";

const getGames = async (
_event: Electron.IpcMainInvokeEvent,
take = 12,
cursor = 0
): Promise<{ results: CatalogueEntry[]; cursor: number }> => {
const steamGames = await steamGamesWorker.run(
{ limit: take, offset: cursor },
{ name: "list" }
skip = 0
): Promise<CatalogueEntry[]> => {
const searchParams = new URLSearchParams({
take: take.toString(),
skip: skip.toString(),
});

const games = await HydraApi.get<CatalogueEntry[]>(
`/games/catalogue?${searchParams.toString()}`,
undefined,
{ needsAuth: false }
);

return {
results: steamGames.map((steamGame) => ({
title: steamGame.name,
shop: "steam",
cover: steamUrlBuilder.library(steamGame.id),
objectID: steamGame.id,
})),
cursor: cursor + steamGames.length,
};
return games.map((game) => ({
...game,
cover: steamUrlBuilder.library(game.objectId),
}));
};

registerEvent("getGames", getGames);
8 changes: 4 additions & 4 deletions src/main/events/catalogue/get-how-long-to-beat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import { gameShopCacheRepository } from "@main/repository";

const getHowLongToBeat = async (
_event: Electron.IpcMainInvokeEvent,
objectID: string,
objectId: string,
shop: GameShop,
title: string
): Promise<HowLongToBeatCategory[] | null> => {
const searchHowLongToBeatPromise = searchHowLongToBeat(title);

const gameShopCache = await gameShopCacheRepository.findOne({
where: { objectID, shop },
where: { objectID: objectId, shop },
});

const howLongToBeatCachedData = gameShopCache?.howLongToBeatSerializedData
Expand All @@ -23,15 +23,15 @@ const getHowLongToBeat = async (

return searchHowLongToBeatPromise.then(async (response) => {
const game = response.data.find(
(game) => game.profile_steam === Number(objectID)
(game) => game.profile_steam === Number(objectId)
);

if (!game) return null;
const howLongToBeat = await getHowLongToBeatGame(String(game.game_id));

gameShopCacheRepository.upsert(
{
objectID,
objectID: objectId,
shop,
howLongToBeatSerializedData: JSON.stringify(howLongToBeat),
},
Expand Down
5 changes: 4 additions & 1 deletion src/main/events/cloud-save/delete-game-artifact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { registerEvent } from "../register-event";
const deleteGameArtifact = async (
_event: Electron.IpcMainInvokeEvent,
gameArtifactId: string
) => HydraApi.delete<{ ok: boolean }>(`/games/artifacts/${gameArtifactId}`);
) =>
HydraApi.delete<{ ok: boolean }>(
`/profile/games/artifacts/${gameArtifactId}`
);

registerEvent("deleteGameArtifact", deleteGameArtifact);
79 changes: 64 additions & 15 deletions src/main/events/cloud-save/download-game-artifact.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,61 @@
import { HydraApi, logger, Ludusavi, WindowManager } from "@main/services";
import fs from "node:fs";
import AdmZip from "adm-zip";
import * as tar from "tar";
import { registerEvent } from "../register-event";
import axios from "axios";
import { app } from "electron";
import path from "node:path";
import { backupsPath } from "@main/constants";
import type { GameShop } from "@types";

import YAML from "yaml";

export interface LudusaviBackup {
files: {
[key: string]: {
hash: string;
size: number;
};
};
}

const replaceLudusaviBackupWithCurrentUser = (
mappingPath: string,
backupHomeDir: string
) => {
const data = fs.readFileSync(mappingPath, "utf8");
const manifest = YAML.parse(data);

const currentHomeDir = app.getPath("home");

const backups = manifest.backups.map((backup: LudusaviBackup) => {
const files = Object.entries(backup.files).reduce((prev, [key, value]) => {
return {
...prev,
[key.replace(backupHomeDir, currentHomeDir)]: value,
};
}, {});

return {
...backup,
files,
};
});

fs.writeFileSync(mappingPath, YAML.stringify({ ...manifest, backups }));
};

const downloadGameArtifact = async (
_event: Electron.IpcMainInvokeEvent,
objectId: string,
shop: GameShop,
gameArtifactId: string
) => {
const { downloadUrl, objectKey } = await HydraApi.post<{
const { downloadUrl, objectKey, homeDir } = await HydraApi.post<{
downloadUrl: string;
objectKey: string;
}>(`/games/artifacts/${gameArtifactId}/download`);
homeDir: string;
}>(`/profile/games/artifacts/${gameArtifactId}/download`);

const zipLocation = path.join(app.getPath("userData"), objectKey);
const backupPath = path.join(backupsPath, `${shop}-${objectId}`);
Expand All @@ -42,20 +80,31 @@ const downloadGameArtifact = async (
});

writer.on("close", () => {
const zip = new AdmZip(zipLocation);
zip.extractAllToAsync(backupPath, true, true, (err) => {
if (err) {
logger.error("Failed to extract zip", err);
throw err;
}

Ludusavi.restoreBackup(backupPath).then(() => {
WindowManager.mainWindow?.webContents.send(
`on-backup-download-complete-${objectId}-${shop}`,
true
tar
.x({
file: zipLocation,
cwd: backupPath,
})
.then(async () => {
const [game] = await Ludusavi.findGames(shop, objectId);
if (!game) throw new Error("Game not found in Ludusavi manifest");

const mappingPath = path.join(
backupsPath,
`${shop}-${objectId}`,
game,
"mapping.yaml"
);

replaceLudusaviBackupWithCurrentUser(mappingPath, homeDir);

Ludusavi.restoreBackup(backupPath).then(() => {
WindowManager.mainWindow?.webContents.send(
`on-backup-download-complete-${objectId}-${shop}`,
true
);
});
});
});
});
};

Expand Down
4 changes: 3 additions & 1 deletion src/main/events/cloud-save/get-game-artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ const getGameArtifacts = async (
shop,
});

return HydraApi.get<GameArtifact[]>(`/games/artifacts?${params.toString()}`);
return HydraApi.get<GameArtifact[]>(
`/profile/games/artifacts?${params.toString()}`
);
};

registerEvent("getGameArtifacts", getGameArtifacts);
Loading

0 comments on commit 035e424

Please sign in to comment.