mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-01-23 13:34:54 +03:00
feat: pass seeding list from downloader.py to download page
This commit is contained in:
parent
452532e18b
commit
a9085ec2ed
@ -198,7 +198,10 @@
|
||||
"queued": "Queued",
|
||||
"no_downloads_title": "Such empty",
|
||||
"no_downloads_description": "You haven't downloaded anything with Hydra yet, but it's never too late to start.",
|
||||
"checking_files": "Checking files…"
|
||||
"checking_files": "Checking files…",
|
||||
"seeding": "Seeding",
|
||||
"stop_seed": "Stop seed",
|
||||
"resume_seed": "Resume seed"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Downloads path",
|
||||
|
@ -194,7 +194,10 @@
|
||||
"queued": "Na fila",
|
||||
"no_downloads_title": "Nada por aqui…",
|
||||
"no_downloads_description": "Você ainda não baixou nada pelo Hydra, mas nunca é tarde para começar.",
|
||||
"checking_files": "Verificando arquivos…"
|
||||
"checking_files": "Verificando arquivos…",
|
||||
"seeding": "Semeando",
|
||||
"stop_seed": "Parar seed",
|
||||
"resume_seed": "Retomar seed"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Diretório dos downloads",
|
||||
|
@ -54,6 +54,9 @@ export class Game {
|
||||
@Column("int", { default: Downloader.Torrent })
|
||||
downloader: Downloader;
|
||||
|
||||
@Column("boolean", { default: false })
|
||||
shouldSeed: boolean;
|
||||
|
||||
/**
|
||||
* Progress is a float between 0 and 1
|
||||
*/
|
||||
|
@ -14,6 +14,7 @@ import { AddWinePrefixToGame } from "./migrations/20241019081648_add_wine_prefix
|
||||
import { AddStartMinimizedColumn } from "./migrations/20241030171454_add_start_minimized_column";
|
||||
import { AddSeedAfterDownloadCompletesColumn } from "./migrations/20241101012727_add_seed_after_download_completes_column";
|
||||
import { AddSeedListTable } from "./migrations/20241103231555_add_seed_list_table";
|
||||
import { AddShouldSeedColumn } from "./migrations/20241107211345_add_should_seed_colum";
|
||||
export type HydraMigration = Knex.Migration & { name: string };
|
||||
|
||||
class MigrationSource implements Knex.MigrationSource<HydraMigration> {
|
||||
@ -32,6 +33,7 @@ class MigrationSource implements Knex.MigrationSource<HydraMigration> {
|
||||
AddStartMinimizedColumn,
|
||||
AddSeedAfterDownloadCompletesColumn,
|
||||
AddSeedListTable,
|
||||
AddShouldSeedColumn,
|
||||
]);
|
||||
}
|
||||
getMigrationName(migration: HydraMigration): string {
|
||||
|
17
src/main/migrations/20241107211345_add_should_seed_colum.ts
Normal file
17
src/main/migrations/20241107211345_add_should_seed_colum.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import type { HydraMigration } from "@main/knex-client";
|
||||
import type { Knex } from "knex";
|
||||
|
||||
export const AddShouldSeedColumn: HydraMigration = {
|
||||
name: "AddShouldSeedColumn",
|
||||
up: (knex: Knex) => {
|
||||
return knex.schema.alterTable("game", (table) => {
|
||||
return table.boolean("shouldSeed").notNullable().defaultTo(false);
|
||||
});
|
||||
},
|
||||
|
||||
down: async (knex: Knex) => {
|
||||
return knex.schema.alterTable("game", (table) => {
|
||||
return table.dropColumn("shouldSeed");
|
||||
});
|
||||
},
|
||||
};
|
@ -5,7 +5,6 @@ import { WindowManager } from "../window-manager";
|
||||
import {
|
||||
downloadQueueRepository,
|
||||
gameRepository,
|
||||
seedListRepository,
|
||||
userPreferencesRepository,
|
||||
} from "@main/repository";
|
||||
import { publishDownloadCompleteNotification } from "../notifications";
|
||||
@ -63,20 +62,8 @@ export class DownloadManager {
|
||||
userPreferences?.seedAfterDownloadCompletes &&
|
||||
this.currentDownloader === Downloader.Torrent
|
||||
) {
|
||||
const existingSeed = await seedListRepository.findOne({
|
||||
where: { downloadUri: game.uri! },
|
||||
});
|
||||
|
||||
if (existingSeed) {
|
||||
await seedListRepository.update(
|
||||
{ downloadUri: game.uri! },
|
||||
{ shouldSeed: true }
|
||||
);
|
||||
} else {
|
||||
await seedListRepository.save({
|
||||
downloadUri: game.uri!,
|
||||
shouldSeed: true,
|
||||
});
|
||||
if (!game.shouldSeed) {
|
||||
await gameRepository.update(game.id, { shouldSeed: true });
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,9 +84,13 @@ export class DownloadManager {
|
||||
}
|
||||
|
||||
public static async watchSeedingList() {
|
||||
const seedingList = await PythonInstance.getSeedingList();
|
||||
const shouldSeedGames = await gameRepository.findOne({
|
||||
where: { shouldSeed: true },
|
||||
});
|
||||
|
||||
if (shouldSeedGames) {
|
||||
const seedingList = await PythonInstance.getSeedingList();
|
||||
|
||||
if (seedingList) {
|
||||
WindowManager.mainWindow?.webContents.send(
|
||||
"on-seeding-list",
|
||||
JSON.parse(JSON.stringify(seedingList))
|
||||
|
@ -66,6 +66,16 @@ export class PythonInstance {
|
||||
"/seed-list"
|
||||
);
|
||||
|
||||
if (response.data && response.data.length > 0) {
|
||||
|
||||
for (const seed of response.data) {
|
||||
await gameRepository.update(
|
||||
{ id: seed.gameId },
|
||||
{ status: "seeding" }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,6 @@ export interface LibtorrentSeedingPayload {
|
||||
numPeers: number;
|
||||
numSeeds: number;
|
||||
uploadSpeed: number;
|
||||
// isCheckingFiles: boolean;
|
||||
fileSize: number;
|
||||
folderName: string;
|
||||
status: LibtorrentStatus;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useMemo } from "react";
|
||||
|
||||
import type { LibraryGame } from "@types";
|
||||
import type { LibraryGame, SeedingList } from "@types";
|
||||
|
||||
import { Badge, Button } from "@renderer/components";
|
||||
import {
|
||||
@ -21,6 +22,7 @@ export interface DownloadGroupProps {
|
||||
title: string;
|
||||
openDeleteGameModal: (gameId: number) => void;
|
||||
openGameInstaller: (gameId: number) => void;
|
||||
seedingList: SeedingList[];
|
||||
}
|
||||
|
||||
export function DownloadGroup({
|
||||
@ -28,6 +30,7 @@ export function DownloadGroup({
|
||||
title,
|
||||
openDeleteGameModal,
|
||||
openGameInstaller,
|
||||
seedingList = [],
|
||||
}: DownloadGroupProps) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
@ -46,6 +49,17 @@ export function DownloadGroup({
|
||||
isGameDeleting,
|
||||
} = useDownload();
|
||||
|
||||
const seedingMap = useMemo(() => {
|
||||
if (!Array.isArray(seedingList) || seedingList.length === 0) {
|
||||
return new Map<number, SeedingList>();
|
||||
}
|
||||
const map = new Map<number, SeedingList>();
|
||||
seedingList.forEach((seed) => {
|
||||
map.set(seed.gameId, seed);
|
||||
});
|
||||
return map;
|
||||
}, [seedingList]);
|
||||
|
||||
const getFinalDownloadSize = (game: LibraryGame) => {
|
||||
const isGameDownloading = lastPacket?.game.id === game.id;
|
||||
|
||||
@ -60,6 +74,7 @@ export function DownloadGroup({
|
||||
const getGameInfo = (game: LibraryGame) => {
|
||||
const isGameDownloading = lastPacket?.game.id === game.id;
|
||||
const finalDownloadSize = getFinalDownloadSize(game);
|
||||
const seed = seedingMap.get(game.id);
|
||||
|
||||
if (isGameDeleting(game.id)) {
|
||||
return <p>{t("deleting")}</p>;
|
||||
@ -98,7 +113,18 @@ export function DownloadGroup({
|
||||
}
|
||||
|
||||
if (game.progress === 1) {
|
||||
return <p>{t("completed")}</p>;
|
||||
return (
|
||||
<>
|
||||
{seed ? (
|
||||
<>
|
||||
<p>{t("seeding")}</p>
|
||||
<p>{formatBytes(seed.uploadSpeed ?? 0)}/s</p>
|
||||
</>
|
||||
) : (
|
||||
<p>{t("completed")}</p>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (game.status === "paused") {
|
||||
@ -127,8 +153,8 @@ export function DownloadGroup({
|
||||
|
||||
const getGameActions = (game: LibraryGame) => {
|
||||
const isGameDownloading = lastPacket?.game.id === game.id;
|
||||
|
||||
const deleting = isGameDeleting(game.id);
|
||||
const seed = seedingMap.get(game.id);
|
||||
|
||||
if (game.progress === 1) {
|
||||
return (
|
||||
@ -144,6 +170,18 @@ export function DownloadGroup({
|
||||
<Button onClick={() => openDeleteGameModal(game.id)} theme="outline">
|
||||
{t("delete")}
|
||||
</Button>
|
||||
|
||||
{seed && game.shouldSeed && (
|
||||
<Button theme="outline">
|
||||
{t("stop_seed")}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{seed && !game.shouldSeed && (
|
||||
<Button theme="outline">
|
||||
{t("resume_seed")}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -36,8 +36,6 @@ export default function Downloads() {
|
||||
window.electron.onSeedingList((value) => setSeedingList(value));
|
||||
}, []);
|
||||
|
||||
console.log("sexo", seedingList);
|
||||
|
||||
const handleOpenGameInstaller = (gameId: number) =>
|
||||
window.electron.openGameInstaller(gameId).then((isBinaryInPath) => {
|
||||
if (!isBinaryInPath) setShowBinaryNotFoundModal(true);
|
||||
@ -130,6 +128,7 @@ export default function Downloads() {
|
||||
library={group.library}
|
||||
openDeleteGameModal={handleOpenDeleteGameModal}
|
||||
openGameInstaller={handleOpenGameInstaller}
|
||||
seedingList={seedingList}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
@ -7,7 +7,8 @@ export type GameStatus =
|
||||
| "paused"
|
||||
| "error"
|
||||
| "complete"
|
||||
| "removed";
|
||||
| "removed"
|
||||
| "seeding";
|
||||
|
||||
export type GameShop = "steam" | "epic";
|
||||
|
||||
@ -124,6 +125,7 @@ export interface Game {
|
||||
objectID: string;
|
||||
shop: GameShop;
|
||||
downloadQueue: DownloadQueue | null;
|
||||
shouldSeed: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@ -156,6 +158,9 @@ export interface SeedingList {
|
||||
numPeers: number;
|
||||
numSeeds: number;
|
||||
uploadSpeed: number;
|
||||
gameId: number;
|
||||
folderName: string;
|
||||
fileSize: number;
|
||||
}
|
||||
|
||||
export interface UserPreferences {
|
||||
|
@ -176,7 +176,7 @@ class TorrentDownloader:
|
||||
torrent_info = {
|
||||
'folderName': info.name() if info else "",
|
||||
'fileSize': info.total_size() if info else 0,
|
||||
'gameId': self.downloading_game_id,
|
||||
'gameId': game_id,
|
||||
'progress': status.progress,
|
||||
'downloadSpeed': status.download_rate,
|
||||
'uploadSpeed': status.upload_rate,
|
||||
@ -189,6 +189,4 @@ class TorrentDownloader:
|
||||
if status.state == 5:
|
||||
response.append(torrent_info)
|
||||
|
||||
# print(response)
|
||||
return response
|
||||
# return None
|
||||
return response
|
Loading…
Reference in New Issue
Block a user