mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-19 01:03:57 +00:00
chore: merge with main
This commit is contained in:
@@ -40,7 +40,7 @@ export class Game {
|
||||
shop: GameShop;
|
||||
|
||||
@Column("text", { nullable: true })
|
||||
status: string;
|
||||
status: string | null;
|
||||
|
||||
@Column("float", { default: 0 })
|
||||
progress: number;
|
||||
@@ -61,6 +61,9 @@ export class Game {
|
||||
@JoinColumn()
|
||||
repack: Repack;
|
||||
|
||||
@Column("boolean", { default: false })
|
||||
isDeleted: boolean;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@ const getGames = async (
|
||||
|
||||
let i = 0 + cursor;
|
||||
|
||||
if (!steamGames.length) return [];
|
||||
|
||||
while (results.length < take) {
|
||||
const game = steamGames[i];
|
||||
const repacks = searchRepacks(game.name);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import checkDiskSpace from "check-disk-space";
|
||||
|
||||
import { registerEvent } from "../register-event";
|
||||
import { getDownloadsPath } from "../helpers/get-downloads-path";
|
||||
|
||||
const getDiskFreeSpace = async (_event: Electron.IpcMainInvokeEvent) =>
|
||||
checkDiskSpace(await getDownloadsPath());
|
||||
const getDiskFreeSpace = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
path: string
|
||||
) => checkDiskSpace(path);
|
||||
|
||||
registerEvent(getDiskFreeSpace, {
|
||||
name: "getDiskFreeSpace",
|
||||
|
||||
@@ -7,8 +7,8 @@ import { formatName, getSteamAppAsset, repackerFormatter } from "@main/helpers";
|
||||
import { stateManager } from "@main/state-manager";
|
||||
|
||||
const { Index } = flexSearch;
|
||||
const repacksIndex = new Index({ tokenize: "strict" });
|
||||
const steamGamesIndex = new Index({ tokenize: "forward" });
|
||||
const repacksIndex = new Index();
|
||||
const steamGamesIndex = new Index({ tokenize: "reverse" });
|
||||
|
||||
const repacks = stateManager.getValue("repacks");
|
||||
const steamGames = stateManager.getValue("steamGames");
|
||||
@@ -21,8 +21,6 @@ for (let i = 0; i < repacks.length; i++) {
|
||||
repacksIndex.add(i, formatName(formatter(repack.title)));
|
||||
}
|
||||
|
||||
console.log(true);
|
||||
|
||||
for (let i = 0; i < steamGames.length; i++) {
|
||||
const steamGame = steamGames[i];
|
||||
steamGamesIndex.add(i, formatName(steamGame.name));
|
||||
|
||||
@@ -17,6 +17,7 @@ import "./library/get-repackers-friendly-names";
|
||||
import "./library/open-game";
|
||||
import "./library/open-game-installer";
|
||||
import "./library/remove-game";
|
||||
import "./library/remove-game-from-library";
|
||||
import "./misc/get-or-cache-image";
|
||||
import "./misc/open-external";
|
||||
import "./misc/show-open-dialog";
|
||||
@@ -24,6 +25,7 @@ import "./torrenting/cancel-game-download";
|
||||
import "./torrenting/pause-game-download";
|
||||
import "./torrenting/resume-game-download";
|
||||
import "./torrenting/start-game-download";
|
||||
import "./torrenting/remove-game-from-download";
|
||||
import "./user-preferences/get-user-preferences";
|
||||
import "./user-preferences/update-user-preferences";
|
||||
|
||||
|
||||
@@ -13,15 +13,34 @@ const addGameToLibrary = async (
|
||||
gameShop: GameShop,
|
||||
executablePath: string
|
||||
) => {
|
||||
const iconUrl = await getImageBase64(await getSteamGameIconUrl(objectID));
|
||||
|
||||
return gameRepository.insert({
|
||||
title,
|
||||
iconUrl,
|
||||
objectID,
|
||||
shop: gameShop,
|
||||
executablePath,
|
||||
const game = await gameRepository.findOne({
|
||||
where: {
|
||||
objectID,
|
||||
},
|
||||
});
|
||||
|
||||
if (game) {
|
||||
return gameRepository.update(
|
||||
{
|
||||
id: game.id,
|
||||
},
|
||||
{
|
||||
shop: gameShop,
|
||||
executablePath,
|
||||
isDeleted: false,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
const iconUrl = await getImageBase64(await getSteamGameIconUrl(objectID));
|
||||
|
||||
return gameRepository.insert({
|
||||
title,
|
||||
iconUrl,
|
||||
objectID,
|
||||
shop: gameShop,
|
||||
executablePath,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
registerEvent(addGameToLibrary, {
|
||||
|
||||
@@ -22,7 +22,10 @@ const deleteGameFolder = async (
|
||||
if (!game) return;
|
||||
|
||||
if (game.folderName) {
|
||||
const folderPath = path.join(await getDownloadsPath(), game.folderName);
|
||||
const folderPath = path.join(
|
||||
game.downloadPath ?? (await getDownloadsPath()),
|
||||
game.folderName
|
||||
);
|
||||
|
||||
if (fs.existsSync(folderPath)) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@@ -9,6 +9,7 @@ const getGameByObjectID = async (
|
||||
gameRepository.findOne({
|
||||
where: {
|
||||
objectID,
|
||||
isDeleted: false,
|
||||
},
|
||||
relations: {
|
||||
repack: true,
|
||||
|
||||
@@ -5,9 +5,12 @@ import { searchRepacks } from "../helpers/search-games";
|
||||
import { registerEvent } from "../register-event";
|
||||
import { sortBy } from "lodash-es";
|
||||
|
||||
const getLibrary = async (_event: Electron.IpcMainInvokeEvent) =>
|
||||
const getLibrary = async () =>
|
||||
gameRepository
|
||||
.find({
|
||||
where: {
|
||||
isDeleted: false,
|
||||
},
|
||||
order: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { stateManager } from "@main/state-manager";
|
||||
|
||||
const getRepackersFriendlyNames = async (_event: Electron.IpcMainInvokeEvent) =>
|
||||
const getRepackersFriendlyNames = async () =>
|
||||
stateManager.getValue("repackersFriendlyNames").reduce((prev, next) => {
|
||||
return { ...prev, [next.name]: next.friendlyName };
|
||||
}, {});
|
||||
|
||||
@@ -23,7 +23,7 @@ const openGameInstaller = async (
|
||||
);
|
||||
|
||||
if (!fs.existsSync(gamePath)) {
|
||||
await gameRepository.delete({ id: gameId });
|
||||
await gameRepository.update({ id: gameId }, { status: null });
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
13
src/main/events/library/remove-game-from-library.ts
Normal file
13
src/main/events/library/remove-game-from-library.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { gameRepository } from "../../repository";
|
||||
|
||||
const removeGameFromLibrary = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
gameId: number
|
||||
) => {
|
||||
gameRepository.update({ id: gameId }, { isDeleted: true });
|
||||
};
|
||||
|
||||
registerEvent(removeGameFromLibrary, {
|
||||
name: "removeGameFromLibrary",
|
||||
});
|
||||
@@ -25,14 +25,13 @@ const cancelGameDownload = async (
|
||||
|
||||
if (!game) return;
|
||||
|
||||
gameRepository
|
||||
await gameRepository
|
||||
.update(
|
||||
{
|
||||
id: game.id,
|
||||
},
|
||||
{
|
||||
status: GameStatus.Cancelled,
|
||||
downloadPath: null,
|
||||
bytesDownloaded: 0,
|
||||
progress: 0,
|
||||
}
|
||||
|
||||
34
src/main/events/torrenting/remove-game-from-download.ts
Normal file
34
src/main/events/torrenting/remove-game-from-download.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { GameStatus } from "@main/constants";
|
||||
import { gameRepository } from "@main/repository";
|
||||
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
const removeGameFromDownload = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
gameId: number
|
||||
) => {
|
||||
const game = await gameRepository.findOne({
|
||||
where: {
|
||||
id: gameId,
|
||||
status: GameStatus.Cancelled,
|
||||
},
|
||||
});
|
||||
|
||||
if (!game) return;
|
||||
|
||||
gameRepository.update(
|
||||
{
|
||||
id: game.id,
|
||||
},
|
||||
{
|
||||
status: null,
|
||||
downloadPath: null,
|
||||
bytesDownloaded: 0,
|
||||
progress: 0,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
registerEvent(removeGameFromDownload, {
|
||||
name: "removeGameFromDownload",
|
||||
});
|
||||
@@ -5,7 +5,6 @@ import { GameStatus } from "@main/constants";
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
import type { GameShop } from "@types";
|
||||
import { getDownloadsPath } from "../helpers/get-downloads-path";
|
||||
import { getImageBase64 } from "@main/helpers";
|
||||
import { In } from "typeorm";
|
||||
|
||||
@@ -14,7 +13,8 @@ const startGameDownload = async (
|
||||
repackId: number,
|
||||
objectID: string,
|
||||
title: string,
|
||||
gameShop: GameShop
|
||||
gameShop: GameShop,
|
||||
downloadPath: string
|
||||
) => {
|
||||
const [game, repack] = await Promise.all([
|
||||
gameRepository.findOne({
|
||||
@@ -37,8 +37,6 @@ const startGameDownload = async (
|
||||
|
||||
writePipe.write({ action: "pause" });
|
||||
|
||||
const downloadsPath = game?.downloadPath ?? (await getDownloadsPath());
|
||||
|
||||
await gameRepository.update(
|
||||
{
|
||||
status: In([
|
||||
@@ -57,8 +55,9 @@ const startGameDownload = async (
|
||||
},
|
||||
{
|
||||
status: GameStatus.DownloadingMetadata,
|
||||
downloadPath: downloadsPath,
|
||||
downloadPath: downloadPath,
|
||||
repack: { id: repackId },
|
||||
isDeleted: false,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -66,18 +65,11 @@ const startGameDownload = async (
|
||||
action: "start",
|
||||
game_id: game.id,
|
||||
magnet: repack.magnet,
|
||||
save_path: downloadsPath,
|
||||
save_path: downloadPath,
|
||||
});
|
||||
|
||||
game.status = GameStatus.DownloadingMetadata;
|
||||
|
||||
writePipe.write({
|
||||
action: "start",
|
||||
game_id: game.id,
|
||||
magnet: repack.magnet,
|
||||
save_path: downloadsPath,
|
||||
});
|
||||
|
||||
return game;
|
||||
} else {
|
||||
const iconUrl = await getImageBase64(await getSteamGameIconUrl(objectID));
|
||||
@@ -88,7 +80,7 @@ const startGameDownload = async (
|
||||
objectID,
|
||||
shop: gameShop,
|
||||
status: GameStatus.DownloadingMetadata,
|
||||
downloadPath: downloadsPath,
|
||||
downloadPath: downloadPath,
|
||||
repack: { id: repackId },
|
||||
});
|
||||
|
||||
@@ -96,7 +88,7 @@ const startGameDownload = async (
|
||||
action: "start",
|
||||
game_id: createdGame.id,
|
||||
magnet: repack.magnet,
|
||||
save_path: downloadsPath,
|
||||
save_path: downloadPath,
|
||||
});
|
||||
|
||||
const { repack: _, ...rest } = createdGame;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { app, BrowserWindow } from "electron";
|
||||
import { init } from "@sentry/electron/main";
|
||||
import i18n from "i18next";
|
||||
import path from "node:path";
|
||||
import { electronApp, optimizer } from "@electron-toolkit/utils";
|
||||
import { resolveDatabaseUpdates, WindowManager } from "@main/services";
|
||||
import { dataSource } from "@main/data-source";
|
||||
import * as resources from "@locales";
|
||||
@@ -49,8 +50,10 @@ if (process.defaultApp) {
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(() => {
|
||||
electronApp.setAppUserModelId("site.hydralauncher.hydra");
|
||||
|
||||
dataSource.initialize().then(async () => {
|
||||
// await resolveDatabaseUpdates();
|
||||
await resolveDatabaseUpdates();
|
||||
|
||||
await import("./main");
|
||||
|
||||
@@ -59,10 +62,14 @@ app.whenReady().then(() => {
|
||||
});
|
||||
|
||||
WindowManager.createMainWindow();
|
||||
// WindowManager.createSystemTray(userPreferences?.language || "en");
|
||||
WindowManager.createSystemTray(userPreferences?.language || "en");
|
||||
});
|
||||
});
|
||||
|
||||
app.on("browser-window-created", (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window);
|
||||
});
|
||||
|
||||
app.on("second-instance", (_event, commandLine) => {
|
||||
// Someone tried to run a second instance, we should focus our window.
|
||||
if (WindowManager.mainWindow) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
getNewGOGGames,
|
||||
getNewRepacksFromCPG,
|
||||
getNewRepacksFromUser,
|
||||
getNewRepacksFromXatab,
|
||||
// getNewRepacksFromXatab,
|
||||
// getNewRepacksFromOnlineFix,
|
||||
readPipe,
|
||||
startProcessWatcher,
|
||||
@@ -73,9 +73,9 @@ const checkForNewRepacks = async () => {
|
||||
getNewGOGGames(
|
||||
existingRepacks.filter((repack) => repack.repacker === "GOG")
|
||||
),
|
||||
getNewRepacksFromXatab(
|
||||
existingRepacks.filter((repack) => repack.repacker === "Xatab")
|
||||
),
|
||||
// getNewRepacksFromXatab(
|
||||
// existingRepacks.filter((repack) => repack.repacker === "Xatab")
|
||||
// ),
|
||||
getNewRepacksFromCPG(
|
||||
existingRepacks.filter((repack) => repack.repacker === "CPG")
|
||||
),
|
||||
|
||||
@@ -1,11 +1,27 @@
|
||||
import { BrowserWindow, Menu, Tray, app } from "electron";
|
||||
import { electronApp, optimizer, is } from "@electron-toolkit/utils";
|
||||
import { is } from "@electron-toolkit/utils";
|
||||
import { t } from "i18next";
|
||||
import path from "node:path";
|
||||
import icon from "../../../resources/icon.png?asset";
|
||||
import trayIcon from "../../../resources/icon.png?asset";
|
||||
|
||||
export class WindowManager {
|
||||
public static mainWindow: Electron.BrowserWindow | null = null;
|
||||
|
||||
private static loadURL(hash = "") {
|
||||
// HMR for renderer base on electron-vite cli.
|
||||
// Load the remote URL for development or the local html file for production.
|
||||
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
|
||||
this.mainWindow.loadURL(
|
||||
`${process.env["ELECTRON_RENDERER_URL"]}#/${hash}`
|
||||
);
|
||||
} else {
|
||||
this.mainWindow.loadFile(path.join(__dirname, "../renderer/index.html"), {
|
||||
hash,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static createMainWindow() {
|
||||
// Create the browser window.
|
||||
this.mainWindow = new BrowserWindow({
|
||||
@@ -14,7 +30,7 @@ export class WindowManager {
|
||||
minWidth: 1024,
|
||||
minHeight: 540,
|
||||
titleBarStyle: "hidden",
|
||||
// icon: path.join(__dirname, "..", "..", "images", "icon.png"),
|
||||
...(process.platform === "linux" ? { icon } : {}),
|
||||
trafficLightPosition: { x: 16, y: 16 },
|
||||
titleBarOverlay: {
|
||||
symbolColor: "#DADBE1",
|
||||
@@ -27,42 +43,24 @@ export class WindowManager {
|
||||
},
|
||||
});
|
||||
|
||||
this.loadURL();
|
||||
this.mainWindow.removeMenu();
|
||||
|
||||
// HMR for renderer base on electron-vite cli.
|
||||
// Load the remote URL for development or the local html file for production.
|
||||
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
|
||||
this.mainWindow.loadURL(process.env["ELECTRON_RENDERER_URL"]);
|
||||
} else {
|
||||
this.mainWindow.loadFile(path.join(__dirname, "../renderer/index.html"));
|
||||
}
|
||||
|
||||
this.mainWindow.webContents.on("did-finish-load", () => {
|
||||
if (!app.isPackaged) {
|
||||
// Open the DevTools.
|
||||
this.mainWindow.webContents.openDevTools();
|
||||
}
|
||||
});
|
||||
|
||||
this.mainWindow.on("close", () => {
|
||||
WindowManager.mainWindow.setProgressBar(-1);
|
||||
});
|
||||
}
|
||||
|
||||
public static redirect(path: string) {
|
||||
public static redirect(hash: string) {
|
||||
if (!this.mainWindow) this.createMainWindow();
|
||||
this.mainWindow.loadURL(`${MAIN_WINDOW_WEBPACK_ENTRY}#${path}`);
|
||||
this.loadURL(hash);
|
||||
|
||||
if (this.mainWindow.isMinimized()) this.mainWindow.restore();
|
||||
this.mainWindow.focus();
|
||||
}
|
||||
|
||||
public static createSystemTray(language: string) {
|
||||
const tray = new Tray(
|
||||
app.isPackaged
|
||||
? path.join(process.resourcesPath, "icon_tray.png")
|
||||
: path.join(__dirname, "..", "..", "resources", "icon_tray.png")
|
||||
);
|
||||
const tray = new Tray(trayIcon);
|
||||
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user