mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-30 06:11:03 +00:00
Merge branch 'main' into linux-install
This commit is contained in:
@@ -1,47 +1,32 @@
|
||||
import { AppUpdaterEvents } from "@types";
|
||||
import { registerEvent } from "../register-event";
|
||||
import updater, { ProgressInfo, UpdateInfo } from "electron-updater";
|
||||
import updater, { UpdateInfo } from "electron-updater";
|
||||
import { WindowManager } from "@main/services";
|
||||
import { app } from "electron";
|
||||
|
||||
const { autoUpdater } = updater;
|
||||
|
||||
const sendEvent = (event: AppUpdaterEvents) => {
|
||||
WindowManager.splashWindow?.webContents.send("autoUpdaterEvent", event);
|
||||
WindowManager.mainWindow?.webContents.send("autoUpdaterEvent", event);
|
||||
};
|
||||
|
||||
const mockValuesForDebug = async () => {
|
||||
sendEvent({ type: "update-downloaded" });
|
||||
const mockValuesForDebug = () => {
|
||||
sendEvent({ type: "update-available", info: { version: "1.3.0" } });
|
||||
};
|
||||
|
||||
const checkForUpdates = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
autoUpdater
|
||||
.addListener("error", () => {
|
||||
sendEvent({ type: "error" });
|
||||
})
|
||||
.addListener("checking-for-update", () => {
|
||||
sendEvent({ type: "checking-for-updates" });
|
||||
})
|
||||
.addListener("update-not-available", () => {
|
||||
sendEvent({ type: "update-not-available" });
|
||||
})
|
||||
.addListener("update-available", (info: UpdateInfo) => {
|
||||
.once("update-available", (info: UpdateInfo) => {
|
||||
sendEvent({ type: "update-available", info });
|
||||
})
|
||||
.addListener("update-downloaded", () => {
|
||||
.once("update-downloaded", () => {
|
||||
sendEvent({ type: "update-downloaded" });
|
||||
})
|
||||
.addListener("download-progress", (info: ProgressInfo) => {
|
||||
sendEvent({ type: "download-progress", info });
|
||||
})
|
||||
.addListener("update-cancelled", () => {
|
||||
sendEvent({ type: "update-cancelled" });
|
||||
});
|
||||
|
||||
if (app.isPackaged) {
|
||||
autoUpdater.checkForUpdates();
|
||||
} else {
|
||||
await mockValuesForDebug();
|
||||
mockValuesForDebug();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { WindowManager } from "@main/services";
|
||||
import { registerEvent } from "../register-event";
|
||||
import updater from "electron-updater";
|
||||
|
||||
const { autoUpdater } = updater;
|
||||
|
||||
const continueToMainWindow = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
autoUpdater.removeAllListeners();
|
||||
WindowManager.prepareMainWindowAndCloseSplash();
|
||||
};
|
||||
|
||||
registerEvent("continueToMainWindow", continueToMainWindow);
|
||||
@@ -1,16 +1,13 @@
|
||||
import { app } from "electron";
|
||||
import { registerEvent } from "../register-event";
|
||||
import updater from "electron-updater";
|
||||
import { WindowManager } from "@main/services";
|
||||
|
||||
const { autoUpdater } = updater;
|
||||
|
||||
const restartAndInstallUpdate = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
autoUpdater.removeAllListeners();
|
||||
if (app.isPackaged) {
|
||||
autoUpdater.quitAndInstall(true, true);
|
||||
} else {
|
||||
autoUpdater.removeAllListeners();
|
||||
WindowManager.prepareMainWindowAndCloseSplash();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import "./user-preferences/update-user-preferences";
|
||||
import "./user-preferences/auto-launch";
|
||||
import "./autoupdater/check-for-updates";
|
||||
import "./autoupdater/restart-and-install-update";
|
||||
import "./autoupdater/continue-to-main-window";
|
||||
import "./user-preferences/authenticate-real-debrid";
|
||||
|
||||
ipcMain.handle("ping", () => "pong");
|
||||
ipcMain.handle("getVersion", () => app.getVersion());
|
||||
|
||||
@@ -10,7 +10,7 @@ const addGameToLibrary = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
objectID: string,
|
||||
title: string,
|
||||
gameShop: GameShop,
|
||||
shop: GameShop,
|
||||
executablePath: string | null
|
||||
) => {
|
||||
return gameRepository
|
||||
@@ -19,7 +19,7 @@ const addGameToLibrary = async (
|
||||
objectID,
|
||||
},
|
||||
{
|
||||
shop: gameShop,
|
||||
shop,
|
||||
status: null,
|
||||
executablePath,
|
||||
isDeleted: false,
|
||||
@@ -40,7 +40,7 @@ const addGameToLibrary = async (
|
||||
title,
|
||||
iconUrl,
|
||||
objectID,
|
||||
shop: gameShop,
|
||||
shop,
|
||||
executablePath,
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
|
||||
import { GameStatus } from "@shared";
|
||||
import { In } from "typeorm";
|
||||
|
||||
import { gameRepository } from "@main/repository";
|
||||
|
||||
import { getDownloadsPath } from "../helpers/get-downloads-path";
|
||||
@@ -15,7 +16,7 @@ const deleteGameFolder = async (
|
||||
const game = await gameRepository.findOne({
|
||||
where: {
|
||||
id: gameId,
|
||||
status: GameStatus.Cancelled,
|
||||
status: In(["removed", "complete"]),
|
||||
isDeleted: false,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ import { gameRepository } from "@main/repository";
|
||||
|
||||
import { searchRepacks } from "../helpers/search-games";
|
||||
import { registerEvent } from "../register-event";
|
||||
import { GameStatus } from "@shared";
|
||||
import { sortBy } from "lodash-es";
|
||||
|
||||
const getLibrary = async () =>
|
||||
@@ -24,7 +23,7 @@ const getLibrary = async () =>
|
||||
...game,
|
||||
repacks: searchRepacks(game.title),
|
||||
})),
|
||||
(game) => (game.status !== GameStatus.Cancelled ? 0 : 1)
|
||||
(game) => (game.status !== "removed" ? 0 : 1)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { gameRepository } from "../../repository";
|
||||
import { GameStatus } from "@shared";
|
||||
|
||||
const removeGame = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
@@ -9,10 +8,9 @@ const removeGame = async (
|
||||
await gameRepository.update(
|
||||
{
|
||||
id: gameId,
|
||||
status: GameStatus.Cancelled,
|
||||
},
|
||||
{
|
||||
status: null,
|
||||
status: "removed",
|
||||
downloadPath: null,
|
||||
bytesDownloaded: 0,
|
||||
progress: 0,
|
||||
|
||||
@@ -1,53 +1,25 @@
|
||||
import { gameRepository } from "@main/repository";
|
||||
|
||||
import { registerEvent } from "../register-event";
|
||||
import { WindowManager } from "@main/services";
|
||||
|
||||
import { In } from "typeorm";
|
||||
import { DownloadManager } from "@main/services";
|
||||
import { GameStatus } from "@shared";
|
||||
|
||||
const cancelGameDownload = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
gameId: number
|
||||
) => {
|
||||
const game = await gameRepository.findOne({
|
||||
where: {
|
||||
await DownloadManager.cancelDownload(gameId);
|
||||
|
||||
await gameRepository.update(
|
||||
{
|
||||
id: gameId,
|
||||
isDeleted: false,
|
||||
status: In([
|
||||
GameStatus.Downloading,
|
||||
GameStatus.DownloadingMetadata,
|
||||
GameStatus.CheckingFiles,
|
||||
GameStatus.Paused,
|
||||
GameStatus.Seeding,
|
||||
GameStatus.Finished,
|
||||
]),
|
||||
},
|
||||
});
|
||||
|
||||
if (!game) return;
|
||||
DownloadManager.cancelDownload();
|
||||
|
||||
await gameRepository
|
||||
.update(
|
||||
{
|
||||
id: game.id,
|
||||
},
|
||||
{
|
||||
status: GameStatus.Cancelled,
|
||||
bytesDownloaded: 0,
|
||||
progress: 0,
|
||||
}
|
||||
)
|
||||
.then((result) => {
|
||||
if (
|
||||
game.status !== GameStatus.Paused &&
|
||||
game.status !== GameStatus.Seeding
|
||||
) {
|
||||
if (result.affected) WindowManager.mainWindow?.setProgressBar(-1);
|
||||
}
|
||||
});
|
||||
{
|
||||
status: "removed",
|
||||
bytesDownloaded: 0,
|
||||
progress: 0,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
registerEvent("cancelGameDownload", cancelGameDownload);
|
||||
|
||||
@@ -1,30 +1,13 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { gameRepository } from "../../repository";
|
||||
import { In } from "typeorm";
|
||||
import { DownloadManager, WindowManager } from "@main/services";
|
||||
import { GameStatus } from "@shared";
|
||||
import { DownloadManager } from "@main/services";
|
||||
|
||||
const pauseGameDownload = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
gameId: number
|
||||
) => {
|
||||
DownloadManager.pauseDownload();
|
||||
|
||||
await gameRepository
|
||||
.update(
|
||||
{
|
||||
id: gameId,
|
||||
status: In([
|
||||
GameStatus.Downloading,
|
||||
GameStatus.DownloadingMetadata,
|
||||
GameStatus.CheckingFiles,
|
||||
]),
|
||||
},
|
||||
{ status: GameStatus.Paused }
|
||||
)
|
||||
.then((result) => {
|
||||
if (result.affected) WindowManager.mainWindow?.setProgressBar(-1);
|
||||
});
|
||||
await DownloadManager.pauseDownload();
|
||||
await gameRepository.update({ id: gameId }, { status: "paused" });
|
||||
};
|
||||
|
||||
registerEvent("pauseGameDownload", pauseGameDownload);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Not } from "typeorm";
|
||||
|
||||
import { registerEvent } from "../register-event";
|
||||
import { gameRepository } from "../../repository";
|
||||
import { getDownloadsPath } from "../helpers/get-downloads-path";
|
||||
import { In } from "typeorm";
|
||||
|
||||
import { DownloadManager } from "@main/services";
|
||||
import { GameStatus } from "@shared";
|
||||
import { dataSource } from "@main/data-source";
|
||||
import { Game } from "@main/entity";
|
||||
|
||||
const resumeGameDownload = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
@@ -18,31 +20,21 @@ const resumeGameDownload = async (
|
||||
});
|
||||
|
||||
if (!game) return;
|
||||
DownloadManager.pauseDownload();
|
||||
|
||||
if (game.status === GameStatus.Paused) {
|
||||
const downloadsPath = game.downloadPath ?? (await getDownloadsPath());
|
||||
if (game.status === "paused") {
|
||||
await dataSource.transaction(async (transactionalEntityManager) => {
|
||||
await DownloadManager.pauseDownload();
|
||||
|
||||
DownloadManager.resumeDownload(gameId);
|
||||
await transactionalEntityManager
|
||||
.getRepository(Game)
|
||||
.update({ status: "active", progress: Not(1) }, { status: "paused" });
|
||||
|
||||
await gameRepository.update(
|
||||
{
|
||||
status: In([
|
||||
GameStatus.Downloading,
|
||||
GameStatus.DownloadingMetadata,
|
||||
GameStatus.CheckingFiles,
|
||||
]),
|
||||
},
|
||||
{ status: GameStatus.Paused }
|
||||
);
|
||||
await DownloadManager.resumeDownload(game);
|
||||
|
||||
await gameRepository.update(
|
||||
{ id: game.id },
|
||||
{
|
||||
status: GameStatus.Downloading,
|
||||
downloadPath: downloadsPath,
|
||||
}
|
||||
);
|
||||
await transactionalEntityManager
|
||||
.getRepository(Game)
|
||||
.update({ id: gameId }, { status: "active" });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,39 +1,26 @@
|
||||
import {
|
||||
gameRepository,
|
||||
repackRepository,
|
||||
userPreferencesRepository,
|
||||
} from "@main/repository";
|
||||
import { gameRepository, repackRepository } from "@main/repository";
|
||||
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
import type { GameShop } from "@types";
|
||||
import type { StartGameDownloadPayload } from "@types";
|
||||
import { getFileBase64, getSteamAppAsset } from "@main/helpers";
|
||||
import { In } from "typeorm";
|
||||
import { DownloadManager } from "@main/services";
|
||||
import { Downloader, GameStatus } from "@shared";
|
||||
import { stateManager } from "@main/state-manager";
|
||||
import { Not } from "typeorm";
|
||||
|
||||
const startGameDownload = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
repackId: number,
|
||||
objectID: string,
|
||||
title: string,
|
||||
gameShop: GameShop,
|
||||
downloadPath: string
|
||||
payload: StartGameDownloadPayload
|
||||
) => {
|
||||
const userPreferences = await userPreferencesRepository.findOne({
|
||||
where: { id: 1 },
|
||||
});
|
||||
|
||||
const downloader = userPreferences?.realDebridApiToken
|
||||
? Downloader.RealDebrid
|
||||
: Downloader.Torrent;
|
||||
const { repackId, objectID, title, shop, downloadPath, downloader } = payload;
|
||||
|
||||
const [game, repack] = await Promise.all([
|
||||
gameRepository.findOne({
|
||||
where: {
|
||||
objectID,
|
||||
shop,
|
||||
},
|
||||
relations: { repack: true },
|
||||
}),
|
||||
repackRepository.findOne({
|
||||
where: {
|
||||
@@ -42,18 +29,13 @@ const startGameDownload = async (
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!repack || game?.status === GameStatus.Downloading) return;
|
||||
DownloadManager.pauseDownload();
|
||||
if (!repack) return;
|
||||
|
||||
await DownloadManager.pauseDownload();
|
||||
|
||||
await gameRepository.update(
|
||||
{
|
||||
status: In([
|
||||
GameStatus.Downloading,
|
||||
GameStatus.DownloadingMetadata,
|
||||
GameStatus.CheckingFiles,
|
||||
]),
|
||||
},
|
||||
{ status: GameStatus.Paused }
|
||||
{ status: "active", progress: Not(1) },
|
||||
{ status: "paused" }
|
||||
);
|
||||
|
||||
if (game) {
|
||||
@@ -62,19 +44,15 @@ const startGameDownload = async (
|
||||
id: game.id,
|
||||
},
|
||||
{
|
||||
status: GameStatus.DownloadingMetadata,
|
||||
downloadPath: downloadPath,
|
||||
status: "active",
|
||||
progress: 0,
|
||||
bytesDownloaded: 0,
|
||||
downloadPath,
|
||||
downloader,
|
||||
repack: { id: repackId },
|
||||
isDeleted: false,
|
||||
}
|
||||
);
|
||||
|
||||
DownloadManager.downloadGame(game.id);
|
||||
|
||||
game.status = GameStatus.DownloadingMetadata;
|
||||
|
||||
return game;
|
||||
} else {
|
||||
const steamGame = stateManager
|
||||
.getValue("steamGames")
|
||||
@@ -84,14 +62,14 @@ const startGameDownload = async (
|
||||
? getSteamAppAsset("icon", objectID, steamGame.clientIcon)
|
||||
: null;
|
||||
|
||||
const createdGame = await gameRepository
|
||||
.save({
|
||||
await gameRepository
|
||||
.insert({
|
||||
title,
|
||||
iconUrl,
|
||||
objectID,
|
||||
downloader,
|
||||
shop: gameShop,
|
||||
status: GameStatus.Downloading,
|
||||
shop,
|
||||
status: "active",
|
||||
downloadPath,
|
||||
repack: { id: repackId },
|
||||
})
|
||||
@@ -104,13 +82,16 @@ const startGameDownload = async (
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
DownloadManager.downloadGame(createdGame.id);
|
||||
|
||||
const { repack: _, ...rest } = createdGame;
|
||||
|
||||
return rest;
|
||||
}
|
||||
|
||||
const updatedGame = await gameRepository.findOne({
|
||||
where: {
|
||||
objectID,
|
||||
},
|
||||
relations: { repack: true },
|
||||
});
|
||||
|
||||
await DownloadManager.startDownload(updatedGame!);
|
||||
};
|
||||
|
||||
registerEvent("startGameDownload", startGameDownload);
|
||||
|
||||
14
src/main/events/user-preferences/authenticate-real-debrid.ts
Normal file
14
src/main/events/user-preferences/authenticate-real-debrid.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { RealDebridClient } from "@main/services/real-debrid";
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
const authenticateRealDebrid = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
apiToken: string
|
||||
) => {
|
||||
RealDebridClient.authorize(apiToken);
|
||||
|
||||
const user = await RealDebridClient.getUser();
|
||||
return user;
|
||||
};
|
||||
|
||||
registerEvent("authenticateRealDebrid", authenticateRealDebrid);
|
||||
@@ -2,23 +2,17 @@ import { userPreferencesRepository } from "@main/repository";
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
import type { UserPreferences } from "@types";
|
||||
import { RealDebridClient } from "@main/services/real-debrid";
|
||||
|
||||
const updateUserPreferences = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
preferences: Partial<UserPreferences>
|
||||
) => {
|
||||
if (preferences.realDebridApiToken) {
|
||||
RealDebridClient.authorize(preferences.realDebridApiToken);
|
||||
}
|
||||
|
||||
await userPreferencesRepository.upsert(
|
||||
) =>
|
||||
userPreferencesRepository.upsert(
|
||||
{
|
||||
id: 1,
|
||||
...preferences,
|
||||
},
|
||||
["id"]
|
||||
);
|
||||
};
|
||||
|
||||
registerEvent("updateUserPreferences", updateUserPreferences);
|
||||
|
||||
Reference in New Issue
Block a user