mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-21 10:03:56 +00:00
180 lines
4.6 KiB
TypeScript
180 lines
4.6 KiB
TypeScript
import { registerEvent } from "../register-event";
|
|
import type { GameShop, ShopAssets } from "@types";
|
|
import { gamesSublevel, levelKeys } from "@main/level";
|
|
import {
|
|
composeSteamShortcut,
|
|
getSteamLocation,
|
|
getSteamShortcuts,
|
|
getSteamUsersIds,
|
|
logger,
|
|
SystemPath,
|
|
writeSteamShortcuts,
|
|
} from "@main/services";
|
|
import fs from "node:fs";
|
|
import axios from "axios";
|
|
import path from "node:path";
|
|
import { ASSETS_PATH } from "@main/constants";
|
|
import { getGameAssets } from "../catalogue/get-game-assets";
|
|
|
|
const downloadAsset = async (downloadPath: string, url?: string | null) => {
|
|
try {
|
|
if (fs.existsSync(downloadPath)) {
|
|
return downloadPath;
|
|
}
|
|
|
|
if (!url) {
|
|
return null;
|
|
}
|
|
|
|
fs.mkdirSync(path.dirname(downloadPath), { recursive: true });
|
|
|
|
const response = await axios.get(url, { responseType: "arraybuffer" });
|
|
fs.writeFileSync(downloadPath, response.data);
|
|
|
|
return downloadPath;
|
|
} catch (error) {
|
|
logger.error("Failed to download asset", error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const downloadAssetsFromSteam = async (
|
|
shop: GameShop,
|
|
objectId: string,
|
|
assets: ShopAssets | null
|
|
) => {
|
|
const gameAssetsPath = path.join(ASSETS_PATH, `${shop}-${objectId}`);
|
|
|
|
return await Promise.all([
|
|
downloadAsset(path.join(gameAssetsPath, "icon.ico"), assets?.iconUrl),
|
|
downloadAsset(
|
|
path.join(gameAssetsPath, "hero.jpg"),
|
|
assets?.libraryHeroImageUrl
|
|
),
|
|
downloadAsset(path.join(gameAssetsPath, "logo.png"), assets?.logoImageUrl),
|
|
downloadAsset(
|
|
path.join(gameAssetsPath, "cover.jpg"),
|
|
assets?.coverImageUrl
|
|
),
|
|
downloadAsset(
|
|
path.join(gameAssetsPath, "library.jpg"),
|
|
assets?.libraryImageUrl
|
|
),
|
|
]);
|
|
};
|
|
|
|
const copyAssetIfExists = async (
|
|
sourcePath: string | null,
|
|
destinationPath: string
|
|
) => {
|
|
if (sourcePath && fs.existsSync(sourcePath)) {
|
|
logger.info("Copying Steam asset", sourcePath, destinationPath);
|
|
await fs.promises.cp(sourcePath, destinationPath);
|
|
}
|
|
};
|
|
|
|
const createSteamShortcut = async (
|
|
_event: Electron.IpcMainInvokeEvent,
|
|
shop: GameShop,
|
|
objectId: string
|
|
) => {
|
|
const gameKey = levelKeys.game(shop, objectId);
|
|
const game = await gamesSublevel.get(gameKey);
|
|
|
|
if (game) {
|
|
if (!game.executablePath) {
|
|
throw new Error("No executable path found for game");
|
|
}
|
|
|
|
const assets = await getGameAssets(objectId, shop);
|
|
|
|
const steamUserIds = await getSteamUsersIds();
|
|
|
|
if (!steamUserIds.length) {
|
|
logger.error("No Steam user ID found");
|
|
throw new Error("No Steam user ID found");
|
|
}
|
|
|
|
const [iconImage, heroImage, logoImage, coverImage, libraryImage] =
|
|
await downloadAssetsFromSteam(game.shop, game.objectId, assets);
|
|
|
|
const newShortcut = composeSteamShortcut(
|
|
game.title,
|
|
game.executablePath,
|
|
iconImage
|
|
);
|
|
|
|
for (const steamUserId of steamUserIds) {
|
|
logger.info("Adding shortcut for Steam user", steamUserId);
|
|
|
|
const steamShortcuts = await getSteamShortcuts(steamUserId);
|
|
|
|
if (steamShortcuts.some((shortcut) => shortcut.appname === game.title)) {
|
|
continue;
|
|
}
|
|
|
|
const gridPath = path.join(
|
|
await getSteamLocation(),
|
|
"userdata",
|
|
steamUserId.toString(),
|
|
"config",
|
|
"grid"
|
|
);
|
|
|
|
await fs.promises.mkdir(gridPath, { recursive: true });
|
|
|
|
await Promise.all([
|
|
copyAssetIfExists(
|
|
heroImage,
|
|
path.join(gridPath, `${newShortcut.appid}_hero.jpg`)
|
|
),
|
|
copyAssetIfExists(
|
|
logoImage,
|
|
path.join(gridPath, `${newShortcut.appid}_logo.png`)
|
|
),
|
|
copyAssetIfExists(
|
|
coverImage,
|
|
path.join(gridPath, `${newShortcut.appid}p.jpg`)
|
|
),
|
|
copyAssetIfExists(
|
|
libraryImage,
|
|
path.join(gridPath, `${newShortcut.appid}.jpg`)
|
|
),
|
|
]);
|
|
|
|
steamShortcuts.push(newShortcut);
|
|
|
|
logger.info(newShortcut);
|
|
logger.info("Writing Steam shortcuts", steamShortcuts);
|
|
|
|
await writeSteamShortcuts(steamUserId, steamShortcuts);
|
|
}
|
|
|
|
if (process.platform === "linux" && !game.winePrefixPath) {
|
|
const steamWinePrefixes = path.join(
|
|
SystemPath.getPath("home"),
|
|
".local",
|
|
"share",
|
|
"Steam",
|
|
"steamapps",
|
|
"compatdata"
|
|
);
|
|
|
|
const winePrefixPath = path.join(
|
|
steamWinePrefixes,
|
|
newShortcut.appid.toString(),
|
|
"pfx"
|
|
);
|
|
|
|
await fs.promises.mkdir(winePrefixPath, { recursive: true });
|
|
|
|
await gamesSublevel.put(gameKey, {
|
|
...game,
|
|
winePrefixPath,
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
registerEvent("createSteamShortcut", createSteamShortcut);
|