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