mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-28 21:31:03 +00:00
Compare commits
3 Commits
feat/LBX-4
...
feat/LBX-4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14c81642a5 | ||
|
|
289b59074c | ||
|
|
db8da467e8 |
@@ -56,12 +56,17 @@ const addGameToQueue = async (
|
||||
|
||||
const updatedGame = await gamesSublevel.get(gameKey);
|
||||
|
||||
await Promise.all([
|
||||
createGame(updatedGame!).catch(() => {}),
|
||||
const promises: Promise<unknown>[] = [
|
||||
HydraApi.post(`/games/${shop}/${objectId}/download`, null, {
|
||||
needsAuth: false,
|
||||
}).catch(() => {}),
|
||||
]);
|
||||
];
|
||||
|
||||
if (updatedGame) {
|
||||
promises.push(createGame(updatedGame).catch(() => {}));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
return { ok: true };
|
||||
} catch (err: unknown) {
|
||||
|
||||
@@ -13,7 +13,7 @@ const updateDownloadQueuePosition = async (
|
||||
|
||||
const download = await downloadsSublevel.get(gameKey);
|
||||
|
||||
if (!download || !download.queued || download.status !== "paused") {
|
||||
if (!download?.queued || download.status !== "paused") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,48 +1,63 @@
|
||||
import { AxiosError } from "axios";
|
||||
import { Downloader, DownloadError } from "@shared";
|
||||
|
||||
type DownloadErrorResult = { ok: false; error?: string };
|
||||
|
||||
const handleAxiosError = (
|
||||
err: AxiosError,
|
||||
downloader: Downloader
|
||||
): DownloadErrorResult | null => {
|
||||
if (err.response?.status === 429 && downloader === Downloader.Gofile) {
|
||||
return { ok: false, error: DownloadError.GofileQuotaExceeded };
|
||||
}
|
||||
|
||||
if (err.response?.status === 403 && downloader === Downloader.RealDebrid) {
|
||||
return { ok: false, error: DownloadError.RealDebridAccountNotAuthorized };
|
||||
}
|
||||
|
||||
if (downloader === Downloader.TorBox) {
|
||||
const data = err.response?.data as { detail?: string } | undefined;
|
||||
return { ok: false, error: data?.detail };
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const HOST_NAMES: Partial<Record<Downloader, string>> = {
|
||||
[Downloader.Buzzheavier]: "Buzzheavier",
|
||||
[Downloader.FuckingFast]: "FuckingFast",
|
||||
};
|
||||
|
||||
const handleHostSpecificError = (
|
||||
message: string,
|
||||
downloader: Downloader
|
||||
): DownloadErrorResult | null => {
|
||||
const hostName = HOST_NAMES[downloader];
|
||||
if (!hostName) return null;
|
||||
|
||||
if (message.includes("Rate limit")) {
|
||||
return { ok: false, error: `${hostName}: Rate limit exceeded` };
|
||||
}
|
||||
|
||||
if (message.includes("not found") || message.includes("deleted")) {
|
||||
return { ok: false, error: `${hostName}: File not found` };
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export const handleDownloadError = (
|
||||
err: unknown,
|
||||
downloader: Downloader
|
||||
): { ok: false; error?: string } => {
|
||||
): DownloadErrorResult => {
|
||||
if (err instanceof AxiosError) {
|
||||
if (err.response?.status === 429 && downloader === Downloader.Gofile) {
|
||||
return { ok: false, error: DownloadError.GofileQuotaExceeded };
|
||||
}
|
||||
|
||||
if (err.response?.status === 403 && downloader === Downloader.RealDebrid) {
|
||||
return { ok: false, error: DownloadError.RealDebridAccountNotAuthorized };
|
||||
}
|
||||
|
||||
if (downloader === Downloader.TorBox) {
|
||||
return { ok: false, error: err.response?.data?.detail };
|
||||
}
|
||||
const result = handleAxiosError(err, downloader);
|
||||
if (result) return result;
|
||||
}
|
||||
|
||||
if (err instanceof Error) {
|
||||
if (downloader === Downloader.Buzzheavier) {
|
||||
if (err.message.includes("Rate limit")) {
|
||||
return { ok: false, error: "Buzzheavier: Rate limit exceeded" };
|
||||
}
|
||||
if (
|
||||
err.message.includes("not found") ||
|
||||
err.message.includes("deleted")
|
||||
) {
|
||||
return { ok: false, error: "Buzzheavier: File not found" };
|
||||
}
|
||||
}
|
||||
|
||||
if (downloader === Downloader.FuckingFast) {
|
||||
if (err.message.includes("Rate limit")) {
|
||||
return { ok: false, error: "FuckingFast: Rate limit exceeded" };
|
||||
}
|
||||
if (
|
||||
err.message.includes("not found") ||
|
||||
err.message.includes("deleted")
|
||||
) {
|
||||
return { ok: false, error: "FuckingFast: File not found" };
|
||||
}
|
||||
}
|
||||
const hostResult = handleHostSpecificError(err.message, downloader);
|
||||
if (hostResult) return hostResult;
|
||||
|
||||
return { ok: false, error: err.message };
|
||||
}
|
||||
|
||||
@@ -2,15 +2,12 @@ import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
import type { GameShop } from "@types";
|
||||
import { downloadsSublevel, gamesSublevel, levelKeys } from "@main/level";
|
||||
import { FILE_EXTENSIONS_TO_EXTRACT, removeSymbolsFromName } from "@shared";
|
||||
import { FILE_EXTENSIONS_TO_EXTRACT } from "@shared";
|
||||
import { SevenZip, ExtractionProgress } from "./7zip";
|
||||
import { WindowManager } from "./window-manager";
|
||||
import { publishExtractionCompleteNotification } from "./notifications";
|
||||
import { logger } from "./logger";
|
||||
import { GameExecutables } from "./game-executables";
|
||||
import createDesktopShortcut from "create-desktop-shortcuts";
|
||||
import { app } from "electron";
|
||||
import { SystemPath } from "./system-path";
|
||||
|
||||
const PROGRESS_THROTTLE_MS = 1000;
|
||||
|
||||
@@ -207,8 +204,6 @@ export class GameFilesManager {
|
||||
});
|
||||
|
||||
WindowManager.mainWindow?.webContents.send("on-library-batch-complete");
|
||||
|
||||
await this.createDesktopShortcutForGame(game.title, foundExePath);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
@@ -218,40 +213,6 @@ export class GameFilesManager {
|
||||
}
|
||||
}
|
||||
|
||||
private async createDesktopShortcutForGame(
|
||||
gameTitle: string,
|
||||
executablePath: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
const windowVbsPath = app.isPackaged
|
||||
? path.join(process.resourcesPath, "windows.vbs")
|
||||
: undefined;
|
||||
|
||||
const options = {
|
||||
filePath: executablePath,
|
||||
name: removeSymbolsFromName(gameTitle),
|
||||
outputPath: SystemPath.getPath("desktop"),
|
||||
};
|
||||
|
||||
const success = createDesktopShortcut({
|
||||
windows: { ...options, VBScriptPath: windowVbsPath },
|
||||
linux: options,
|
||||
osx: options,
|
||||
});
|
||||
|
||||
if (success) {
|
||||
logger.info(
|
||||
`[GameFilesManager] Created desktop shortcut for ${this.objectId}`
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`[GameFilesManager] Error creating desktop shortcut: ${this.objectId}`,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async findExecutableInFolder(
|
||||
folderPath: string,
|
||||
executableNames: string[]
|
||||
|
||||
@@ -221,6 +221,33 @@ export function DownloadSettingsModal({
|
||||
}
|
||||
};
|
||||
|
||||
const getButtonContent = () => {
|
||||
if (downloadStarting) {
|
||||
return (
|
||||
<>
|
||||
<SyncIcon className="download-settings-modal__loading-spinner" />
|
||||
{t("loading")}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (hasActiveDownload) {
|
||||
return (
|
||||
<>
|
||||
<PlusIcon />
|
||||
{t("add_to_queue")}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<DownloadIcon />
|
||||
{t("download_now")}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const handleStartClick = async () => {
|
||||
if (repack) {
|
||||
setDownloadStarting(true);
|
||||
@@ -462,22 +489,7 @@ export function DownloadSettingsModal({
|
||||
)
|
||||
}
|
||||
>
|
||||
{downloadStarting ? (
|
||||
<>
|
||||
<SyncIcon className="download-settings-modal__loading-spinner" />
|
||||
{t("loading")}
|
||||
</>
|
||||
) : hasActiveDownload ? (
|
||||
<>
|
||||
<PlusIcon />
|
||||
{t("add_to_queue")}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<DownloadIcon />
|
||||
{t("download_now")}
|
||||
</>
|
||||
)}
|
||||
{getButtonContent()}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user