mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
feat: improving cloud sync manual mapping
This commit is contained in:
parent
7de6e96f63
commit
bfcf8178d8
15 changed files with 164 additions and 132 deletions
|
|
@ -1,6 +1,8 @@
|
|||
import { app } from "electron";
|
||||
import path from "node:path";
|
||||
|
||||
export const LUDUSAVI_MANIFEST_URL = "https://cdn.losbroxas.org/manifest.yaml";
|
||||
|
||||
export const defaultDownloadsPath = app.getPath("downloads");
|
||||
|
||||
export const databaseDirectory = path.join(app.getPath("appData"), "hydra");
|
||||
|
|
|
|||
|
|
@ -122,12 +122,9 @@ const downloadGameArtifact = async (
|
|||
cwd: backupPath,
|
||||
})
|
||||
.then(async () => {
|
||||
const [game] = await Ludusavi.findGames(shop, objectId);
|
||||
if (!game) throw new Error("Game not found in Ludusavi manifest");
|
||||
|
||||
replaceLudusaviBackupWithCurrentUser(
|
||||
backupPath,
|
||||
game.replaceAll(":", "_"),
|
||||
objectId,
|
||||
normalizePath(homeDir)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,13 @@
|
|||
import { registerEvent } from "../register-event";
|
||||
import type { GameShop } from "@types";
|
||||
import { Ludusavi } from "@main/services";
|
||||
import path from "node:path";
|
||||
import { backupsPath } from "@main/constants";
|
||||
|
||||
const getGameBackupPreview = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
objectId: string,
|
||||
shop: GameShop
|
||||
) => {
|
||||
const backupPath = path.join(backupsPath, `${shop}-${objectId}`);
|
||||
|
||||
return Ludusavi.getBackupPreview(shop, objectId, backupPath);
|
||||
return Ludusavi.getBackupPreview(shop, objectId);
|
||||
};
|
||||
|
||||
registerEvent("getGameBackupPreview", getGameBackupPreview);
|
||||
|
|
|
|||
14
src/main/events/cloud-save/select-game-backup-path.ts
Normal file
14
src/main/events/cloud-save/select-game-backup-path.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { registerEvent } from "../register-event";
|
||||
import type { GameShop } from "@types";
|
||||
import { Ludusavi } from "@main/services";
|
||||
|
||||
const selectGameBackupPath = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
_shop: GameShop,
|
||||
objectId: string,
|
||||
backupPath: string | null
|
||||
) => {
|
||||
return Ludusavi.addCustomGame(objectId, backupPath);
|
||||
};
|
||||
|
||||
registerEvent("selectGameBackupPath", selectGameBackupPath);
|
||||
|
|
@ -65,6 +65,7 @@ import "./cloud-save/get-game-artifacts";
|
|||
import "./cloud-save/get-game-backup-preview";
|
||||
import "./cloud-save/upload-save-game";
|
||||
import "./cloud-save/delete-game-artifact";
|
||||
import "./cloud-save/select-game-backup-path";
|
||||
import "./notifications/publish-new-repacks-notification";
|
||||
import { isPortableVersion } from "@main/helpers";
|
||||
import "./misc/show-item-in-folder";
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import path from "node:path";
|
|||
import YAML from "yaml";
|
||||
|
||||
import ludusaviWorkerPath from "../workers/ludusavi.worker?modulePath";
|
||||
import { LUDUSAVI_MANIFEST_URL } from "@main/constants";
|
||||
|
||||
export class Ludusavi {
|
||||
private static ludusaviPath = path.join(app.getPath("appData"), "ludusavi");
|
||||
|
|
@ -25,15 +26,6 @@ export class Ludusavi {
|
|||
},
|
||||
});
|
||||
|
||||
static async findGames(shop: GameShop, objectId: string): Promise<string[]> {
|
||||
const games = await this.worker.run(
|
||||
{ objectId, shop },
|
||||
{ name: "findGames" }
|
||||
);
|
||||
|
||||
return games;
|
||||
}
|
||||
|
||||
static async getConfig() {
|
||||
if (!fs.existsSync(this.ludusaviConfigPath)) {
|
||||
await this.worker.run(undefined, { name: "generateConfig" });
|
||||
|
|
@ -47,36 +39,36 @@ export class Ludusavi {
|
|||
}
|
||||
|
||||
static async backupGame(
|
||||
shop: GameShop,
|
||||
_shop: GameShop,
|
||||
objectId: string,
|
||||
backupPath: string,
|
||||
winePrefix?: string | null
|
||||
): Promise<LudusaviBackup> {
|
||||
const games = await this.findGames(shop, objectId);
|
||||
if (!games.length) throw new Error("Game not found");
|
||||
|
||||
return this.worker.run(
|
||||
{ title: games[0], backupPath, winePrefix },
|
||||
{ title: objectId, backupPath, winePrefix },
|
||||
{ name: "backupGame" }
|
||||
);
|
||||
}
|
||||
|
||||
static async getBackupPreview(
|
||||
shop: GameShop,
|
||||
objectId: string,
|
||||
backupPath: string
|
||||
_shop: GameShop,
|
||||
objectId: string
|
||||
): Promise<LudusaviBackup | null> {
|
||||
const games = await this.findGames(shop, objectId);
|
||||
|
||||
if (!games.length) return null;
|
||||
const [game] = games;
|
||||
const config = await this.getConfig();
|
||||
|
||||
const backupData = await this.worker.run(
|
||||
{ title: game, backupPath, preview: true },
|
||||
{ title: objectId, preview: true },
|
||||
{ name: "backupGame" }
|
||||
);
|
||||
|
||||
return backupData;
|
||||
const customGame = config.customGames.find(
|
||||
(game) => game.name === objectId
|
||||
);
|
||||
|
||||
return {
|
||||
...backupData,
|
||||
customBackupPath: customGame?.files[0] || null,
|
||||
};
|
||||
}
|
||||
|
||||
static async restoreBackup(backupPath: string) {
|
||||
|
|
@ -87,24 +79,24 @@ export class Ludusavi {
|
|||
const config = await this.getConfig();
|
||||
|
||||
config.manifest.enable = false;
|
||||
config.manifest.secondary = [
|
||||
{ url: "https://cdn.losbroxas.org/manifest.yaml", enable: true },
|
||||
];
|
||||
config.manifest.secondary = [{ url: LUDUSAVI_MANIFEST_URL, enable: true }];
|
||||
|
||||
fs.writeFileSync(this.ludusaviConfigPath, YAML.stringify(config));
|
||||
}
|
||||
|
||||
static async addCustomGame(title: string, savePath: string) {
|
||||
static async addCustomGame(title: string, savePath: string | null) {
|
||||
const config = await this.getConfig();
|
||||
const filteredGames = config.customGames.filter(
|
||||
(game) => game.name !== title
|
||||
);
|
||||
|
||||
filteredGames.push({
|
||||
name: title,
|
||||
files: [savePath],
|
||||
registry: [],
|
||||
});
|
||||
if (savePath) {
|
||||
filteredGames.push({
|
||||
name: title,
|
||||
files: [savePath],
|
||||
registry: [],
|
||||
});
|
||||
}
|
||||
|
||||
config.customGames = filteredGames;
|
||||
fs.writeFileSync(this.ludusaviConfigPath, YAML.stringify(config));
|
||||
|
|
|
|||
|
|
@ -1,29 +1,10 @@
|
|||
import type { GameShop, LudusaviBackup, LudusaviFindResult } from "@types";
|
||||
import type { LudusaviBackup } from "@types";
|
||||
import cp from "node:child_process";
|
||||
|
||||
import { workerData } from "node:worker_threads";
|
||||
|
||||
const { binaryPath } = workerData;
|
||||
|
||||
export const findGames = ({
|
||||
shop,
|
||||
objectId,
|
||||
}: {
|
||||
shop: GameShop;
|
||||
objectId: string;
|
||||
}) => {
|
||||
const args = ["find", "--api"];
|
||||
|
||||
if (shop === "steam") {
|
||||
args.push("--steam-id", objectId);
|
||||
}
|
||||
|
||||
const result = cp.execFileSync(binaryPath, args);
|
||||
|
||||
const games = JSON.parse(result.toString("utf-8")) as LudusaviFindResult;
|
||||
return Object.keys(games.games);
|
||||
};
|
||||
|
||||
export const backupGame = ({
|
||||
title,
|
||||
backupPath,
|
||||
|
|
@ -35,7 +16,7 @@ export const backupGame = ({
|
|||
preview?: boolean;
|
||||
winePrefix?: string;
|
||||
}) => {
|
||||
const args = ["backup", `"${title}"`, "--api", "--force"];
|
||||
const args = ["backup", title, "--api", "--force"];
|
||||
|
||||
if (preview) args.push("--preview");
|
||||
if (backupPath) args.push("--path", backupPath);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue