mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-03 00:33:49 +03:00
feat: display upload speed during seeding
This commit is contained in:
parent
8ec52bf193
commit
56687948bf
@ -76,8 +76,6 @@ export class DownloadManager {
|
|||||||
|
|
||||||
const seedStatus = await PythonInstance.getSeedStatus();
|
const seedStatus = await PythonInstance.getSeedStatus();
|
||||||
|
|
||||||
console.log(seedStatus);
|
|
||||||
|
|
||||||
if (seedStatus.length === 0) {
|
if (seedStatus.length === 0) {
|
||||||
for (const game of gamesToSeed) {
|
for (const game of gamesToSeed) {
|
||||||
if (game.uri && game.downloadPath) {
|
if (game.uri && game.downloadPath) {
|
||||||
@ -102,6 +100,11 @@ export class DownloadManager {
|
|||||||
{ status: "seeding" }
|
{ status: "seeding" }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WindowManager.mainWindow?.webContents.send(
|
||||||
|
"on-seeding-status",
|
||||||
|
JSON.parse(JSON.stringify(seedStatus))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async pauseSeeding(gameId: number) {
|
static async pauseSeeding(gameId: number) {
|
||||||
|
@ -11,6 +11,7 @@ import type {
|
|||||||
GameRunning,
|
GameRunning,
|
||||||
FriendRequestAction,
|
FriendRequestAction,
|
||||||
UpdateProfileRequest,
|
UpdateProfileRequest,
|
||||||
|
SeedingStatus,
|
||||||
} from "@types";
|
} from "@types";
|
||||||
import type { CatalogueCategory } from "@shared";
|
import type { CatalogueCategory } from "@shared";
|
||||||
import type { AxiosProgressEvent } from "axios";
|
import type { AxiosProgressEvent } from "axios";
|
||||||
@ -38,6 +39,14 @@ contextBridge.exposeInMainWorld("electron", {
|
|||||||
ipcRenderer.on("on-download-progress", listener);
|
ipcRenderer.on("on-download-progress", listener);
|
||||||
return () => ipcRenderer.removeListener("on-download-progress", listener);
|
return () => ipcRenderer.removeListener("on-download-progress", listener);
|
||||||
},
|
},
|
||||||
|
onSeedingStatus: (cb: (value: SeedingStatus[]) => void) => {
|
||||||
|
const listener = (
|
||||||
|
_event: Electron.IpcRendererEvent,
|
||||||
|
value: SeedingStatus[]
|
||||||
|
) => cb(value);
|
||||||
|
ipcRenderer.on("on-seeding-status", listener);
|
||||||
|
return () => ipcRenderer.removeListener("on-seeding-status", listener);
|
||||||
|
},
|
||||||
|
|
||||||
/* Catalogue */
|
/* Catalogue */
|
||||||
searchGames: (query: string) => ipcRenderer.invoke("searchGames", query),
|
searchGames: (query: string) => ipcRenderer.invoke("searchGames", query),
|
||||||
|
4
src/renderer/src/declaration.d.ts
vendored
4
src/renderer/src/declaration.d.ts
vendored
@ -10,6 +10,7 @@ import type {
|
|||||||
ShopDetails,
|
ShopDetails,
|
||||||
Steam250Game,
|
Steam250Game,
|
||||||
DownloadProgress,
|
DownloadProgress,
|
||||||
|
SeedingStatus,
|
||||||
UserPreferences,
|
UserPreferences,
|
||||||
StartGameDownloadPayload,
|
StartGameDownloadPayload,
|
||||||
RealDebridUser,
|
RealDebridUser,
|
||||||
@ -51,6 +52,9 @@ declare global {
|
|||||||
onDownloadProgress: (
|
onDownloadProgress: (
|
||||||
cb: (value: DownloadProgress) => void
|
cb: (value: DownloadProgress) => void
|
||||||
) => () => Electron.IpcRenderer;
|
) => () => Electron.IpcRenderer;
|
||||||
|
onSeedingStatus: (
|
||||||
|
cb: (value: SeedingStatus[]) => void
|
||||||
|
) => () => Electron.IpcRenderer;
|
||||||
|
|
||||||
/* Catalogue */
|
/* Catalogue */
|
||||||
searchGames: (query: string) => Promise<CatalogueEntry[]>;
|
searchGames: (query: string) => Promise<CatalogueEntry[]>;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import type { LibraryGame } from "@types";
|
import type { LibraryGame, SeedingStatus } from "@types";
|
||||||
|
|
||||||
import { Badge, Button } from "@renderer/components";
|
import { Badge, Button } from "@renderer/components";
|
||||||
import {
|
import {
|
||||||
@ -16,12 +16,14 @@ import * as styles from "./download-group.css";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
||||||
import { XCircleIcon } from "@primer/octicons-react";
|
import { XCircleIcon } from "@primer/octicons-react";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
export interface DownloadGroupProps {
|
export interface DownloadGroupProps {
|
||||||
library: LibraryGame[];
|
library: LibraryGame[];
|
||||||
title: string;
|
title: string;
|
||||||
openDeleteGameModal: (gameId: number) => void;
|
openDeleteGameModal: (gameId: number) => void;
|
||||||
openGameInstaller: (gameId: number) => void;
|
openGameInstaller: (gameId: number) => void;
|
||||||
|
seedingStatus: SeedingStatus[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DownloadGroup({
|
export function DownloadGroup({
|
||||||
@ -29,6 +31,7 @@ export function DownloadGroup({
|
|||||||
title,
|
title,
|
||||||
openDeleteGameModal,
|
openDeleteGameModal,
|
||||||
openGameInstaller,
|
openGameInstaller,
|
||||||
|
seedingStatus,
|
||||||
}: DownloadGroupProps) {
|
}: DownloadGroupProps) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
@ -60,9 +63,21 @@ export function DownloadGroup({
|
|||||||
return "N/A";
|
return "N/A";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const seedingMap = useMemo(() => {
|
||||||
|
if (!Array.isArray(seedingStatus) || seedingStatus.length === 0) {
|
||||||
|
return new Map<number, SeedingStatus>();
|
||||||
|
}
|
||||||
|
const map = new Map<number, SeedingStatus>();
|
||||||
|
seedingStatus.forEach((seed) => {
|
||||||
|
map.set(seed.gameId, seed);
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
}, [seedingStatus]);
|
||||||
|
|
||||||
const getGameInfo = (game: LibraryGame) => {
|
const getGameInfo = (game: LibraryGame) => {
|
||||||
const isGameDownloading = lastPacket?.game.id === game.id;
|
const isGameDownloading = lastPacket?.game.id === game.id;
|
||||||
const finalDownloadSize = getFinalDownloadSize(game);
|
const finalDownloadSize = getFinalDownloadSize(game);
|
||||||
|
const seedingStatus = seedingMap.get(game.id);
|
||||||
|
|
||||||
if (isGameDeleting(game.id)) {
|
if (isGameDeleting(game.id)) {
|
||||||
return <p>{t("deleting")}</p>;
|
return <p>{t("deleting")}</p>;
|
||||||
@ -101,10 +116,13 @@ export function DownloadGroup({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (game.progress === 1) {
|
if (game.progress === 1) {
|
||||||
// return <p>{t("completed")}</p>;
|
const uploadSpeed = formatBytes(seedingStatus?.uploadSpeed ?? 0);
|
||||||
|
|
||||||
return game.status === "seeding" ? (
|
return game.status === "seeding" ? (
|
||||||
<p>{t("seeding")}</p>
|
<>
|
||||||
|
<p>{t("seeding")}</p>
|
||||||
|
{uploadSpeed && <p>{uploadSpeed}/s</p>}
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<p>{t("completed")}</p>
|
<p>{t("completed")}</p>
|
||||||
);
|
);
|
||||||
|
@ -2,12 +2,12 @@ import { useTranslation } from "react-i18next";
|
|||||||
|
|
||||||
import { useDownload, useLibrary } from "@renderer/hooks";
|
import { useDownload, useLibrary } from "@renderer/hooks";
|
||||||
|
|
||||||
import { useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { BinaryNotFoundModal } from "../shared-modals/binary-not-found-modal";
|
import { BinaryNotFoundModal } from "../shared-modals/binary-not-found-modal";
|
||||||
import * as styles from "./downloads.css";
|
import * as styles from "./downloads.css";
|
||||||
import { DeleteGameModal } from "./delete-game-modal";
|
import { DeleteGameModal } from "./delete-game-modal";
|
||||||
import { DownloadGroup } from "./download-group";
|
import { DownloadGroup } from "./download-group";
|
||||||
import type { LibraryGame } from "@types";
|
import type { LibraryGame, SeedingStatus } from "@types";
|
||||||
import { orderBy } from "lodash-es";
|
import { orderBy } from "lodash-es";
|
||||||
import { ArrowDownIcon } from "@primer/octicons-react";
|
import { ArrowDownIcon } from "@primer/octicons-react";
|
||||||
|
|
||||||
@ -30,6 +30,12 @@ export default function Downloads() {
|
|||||||
|
|
||||||
const { lastPacket } = useDownload();
|
const { lastPacket } = useDownload();
|
||||||
|
|
||||||
|
const [seedingStatus, setSeedingStatus] = useState<SeedingStatus[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.electron.onSeedingStatus((value) => setSeedingStatus(value));
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleOpenGameInstaller = (gameId: number) =>
|
const handleOpenGameInstaller = (gameId: number) =>
|
||||||
window.electron.openGameInstaller(gameId).then((isBinaryInPath) => {
|
window.electron.openGameInstaller(gameId).then((isBinaryInPath) => {
|
||||||
if (!isBinaryInPath) setShowBinaryNotFoundModal(true);
|
if (!isBinaryInPath) setShowBinaryNotFoundModal(true);
|
||||||
@ -122,6 +128,7 @@ export default function Downloads() {
|
|||||||
library={group.library}
|
library={group.library}
|
||||||
openDeleteGameModal={handleOpenDeleteGameModal}
|
openDeleteGameModal={handleOpenDeleteGameModal}
|
||||||
openGameInstaller={handleOpenGameInstaller}
|
openGameInstaller={handleOpenGameInstaller}
|
||||||
|
seedingStatus={seedingStatus}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -153,6 +153,12 @@ export interface DownloadProgress {
|
|||||||
game: LibraryGame;
|
game: LibraryGame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SeedingStatus {
|
||||||
|
gameId: number;
|
||||||
|
status: GameStatus;
|
||||||
|
uploadSpeed: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface UserPreferences {
|
export interface UserPreferences {
|
||||||
downloadsPath: string | null;
|
downloadsPath: string | null;
|
||||||
language: string;
|
language: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user