fix: fixing download cancel

This commit is contained in:
Chubby Granny Chaser 2025-02-16 03:27:11 +00:00
commit 6158108452
No known key found for this signature in database
22 changed files with 122 additions and 81 deletions

View file

@ -159,6 +159,8 @@ def action():
downloader = downloads.get(game_id) downloader = downloads.get(game_id)
if downloader: if downloader:
downloader.pause_download() downloader.pause_download()
if downloading_game_id == game_id:
downloading_game_id = -1 downloading_game_id = -1
elif action == 'cancel': elif action == 'cancel':
downloader = downloads.get(game_id) downloader = downloads.get(game_id)

View file

@ -107,7 +107,10 @@ const copyAria2Macos = async () => {
}; };
const copyAria2 = () => { const copyAria2 = () => {
if (fs.existsSync("aria2")) { const aria2Path =
process.platform === "win32" ? "aria2/aria2c.exe" : "aria2/aria2c";
if (fs.existsSync(aria2Path)) {
console.log("Aria2 already exists, skipping download..."); console.log("Aria2 already exists, skipping download...");
return; return;
} }

View file

@ -310,9 +310,9 @@
"editor_tab_save": "Save", "editor_tab_save": "Save",
"web_store": "Web store", "web_store": "Web store",
"clear_themes": "Clear", "clear_themes": "Clear",
"add_theme": "Add", "create_theme": "Create",
"add_theme_modal_title": "Create custom theme", "create_theme_modal_title": "Create custom theme",
"add_theme_modal_description": "Create a new theme to customize Hydra's appearance", "create_theme_modal_description": "Create a new theme to customize Hydra's appearance",
"theme_name": "Name", "theme_name": "Name",
"insert_theme_name": "Insert theme name", "insert_theme_name": "Insert theme name",
"set_theme": "Set theme", "set_theme": "Set theme",

View file

@ -300,9 +300,9 @@
"editor_tab_save": "Salvar", "editor_tab_save": "Salvar",
"web_store": "Loja de temas", "web_store": "Loja de temas",
"clear_themes": "Limpar", "clear_themes": "Limpar",
"add_theme": "Adicionar", "create_theme": "Criar",
"add_theme_modal_title": "Criar tema customizado", "create_theme_modal_title": "Criar tema customizado",
"add_theme_modal_description": "Criar novo tema para customizar a aparência do Hydra", "create_theme_modal_description": "Criar novo tema para customizar a aparência do Hydra",
"theme_name": "Nome", "theme_name": "Nome",
"insert_theme_name": "Insira o nome do tema", "insert_theme_name": "Insira o nome do tema",
"set_theme": "Habilitar tema", "set_theme": "Habilitar tema",

View file

@ -5,7 +5,7 @@ import type { Game, GameShop } from "@types";
import { steamGamesWorker } from "@main/workers"; import { steamGamesWorker } from "@main/workers";
import { createGame } from "@main/services/library-sync"; import { createGame } from "@main/services/library-sync";
import { steamUrlBuilder } from "@shared"; import { steamUrlBuilder } from "@shared";
import { updateLocalUnlockedAchivements } from "@main/services/achievements/update-local-unlocked-achivements"; import { updateLocalUnlockedAchievements } from "@main/services/achievements/update-local-unlocked-achivements";
import { downloadsSublevel, gamesSublevel, levelKeys } from "@main/level"; import { downloadsSublevel, gamesSublevel, levelKeys } from "@main/level";
const addGameToLibrary = async ( const addGameToLibrary = async (
@ -46,9 +46,9 @@ const addGameToLibrary = async (
await gamesSublevel.put(levelKeys.game(shop, objectId), game); await gamesSublevel.put(levelKeys.game(shop, objectId), game);
updateLocalUnlockedAchivements(game); await createGame(game).catch(() => {});
createGame(game).catch(() => {}); updateLocalUnlockedAchievements(game);
} }
}; };

View file

@ -2,7 +2,7 @@ import { registerEvent } from "../register-event";
import { DownloadManager } from "@main/services"; import { DownloadManager } from "@main/services";
import { GameShop } from "@types"; import { GameShop } from "@types";
import { levelKeys } from "@main/level"; import { downloadsSublevel, levelKeys } from "@main/level";
const cancelGameDownload = async ( const cancelGameDownload = async (
_event: Electron.IpcMainInvokeEvent, _event: Electron.IpcMainInvokeEvent,
@ -12,6 +12,15 @@ const cancelGameDownload = async (
const downloadKey = levelKeys.game(shop, objectId); const downloadKey = levelKeys.game(shop, objectId);
await DownloadManager.cancelDownload(downloadKey); await DownloadManager.cancelDownload(downloadKey);
const download = await downloadsSublevel.get(downloadKey);
if (!download) return;
await downloadsSublevel.put(downloadKey, {
...download,
status: "removed",
});
}; };
registerEvent("cancelGameDownload", cancelGameDownload); registerEvent("cancelGameDownload", cancelGameDownload);

View file

@ -15,6 +15,7 @@ const pauseGameSeed = async (
await downloadsSublevel.put(downloadKey, { await downloadsSublevel.put(downloadKey, {
...download, ...download,
status: "complete",
shouldSeed: false, shouldSeed: false,
}); });

View file

@ -8,12 +8,14 @@ const resumeGameSeed = async (
shop: GameShop, shop: GameShop,
objectId: string objectId: string
) => { ) => {
const download = await downloadsSublevel.get(levelKeys.game(shop, objectId)); const downloadKey = levelKeys.game(shop, objectId);
const download = await downloadsSublevel.get(downloadKey);
if (!download) return; if (!download) return;
await downloadsSublevel.put(levelKeys.game(shop, objectId), { await downloadsSublevel.put(downloadKey, {
...download, ...download,
status: "seeding",
shouldSeed: true, shouldSeed: true,
}); });

View file

@ -32,7 +32,7 @@ export const getUnlockedAchievements = async (
return achievementsData return achievementsData
.map((achievementData) => { .map((achievementData) => {
const unlockedAchiementData = unlockedAchievements.find( const unlockedAchievementData = unlockedAchievements.find(
(localAchievement) => { (localAchievement) => {
return ( return (
localAchievement.name.toUpperCase() == localAchievement.name.toUpperCase() ==
@ -45,11 +45,11 @@ export const getUnlockedAchievements = async (
? achievementData.icon ? achievementData.icon
: achievementData.icongray; : achievementData.icongray;
if (unlockedAchiementData) { if (unlockedAchievementData) {
return { return {
...achievementData, ...achievementData,
unlocked: true, unlocked: true,
unlockTime: unlockedAchiementData.unlockTime, unlockTime: unlockedAchievementData.unlockTime,
}; };
} }

View file

@ -49,23 +49,21 @@ export const loadState = async () => {
.values() .values()
.all() .all()
.then((games) => { .then((games) => {
return sortBy( return sortBy(games, "timestamp", "DESC");
games.filter((game) => game.queued),
"timestamp",
"DESC"
);
}); });
const [nextItemOnQueue] = downloads; const [nextItemOnQueue] = downloads.filter((game) => game.queued);
const downloadsToSeed = downloads.filter( const downloadsToSeed = downloads.filter(
(download) => (game) =>
download.shouldSeed && game.shouldSeed &&
download.downloader === Downloader.Torrent && game.downloader === Downloader.Torrent &&
download.progress === 1 && game.progress === 1 &&
download.uri !== null game.uri !== null
); );
console.log("downloadsToSeed", downloadsToSeed);
await DownloadManager.startRPC(nextItemOnQueue, downloadsToSeed); await DownloadManager.startRPC(nextItemOnQueue, downloadsToSeed);
startMainLoop(); startMainLoop();

View file

@ -23,23 +23,21 @@ const saveAchievementsOnLocal = async (
return gameAchievementsSublevel return gameAchievementsSublevel
.get(levelKey) .get(levelKey)
.then(async (gameAchievement) => { .then(async (gameAchievement) => {
if (gameAchievement) { await gameAchievementsSublevel.put(levelKey, {
await gameAchievementsSublevel.put(levelKey, { achievements: gameAchievement?.achievements ?? [],
...gameAchievement, unlockedAchievements: unlockedAchievements,
unlockedAchievements: unlockedAchievements, });
});
if (!sendUpdateEvent) return; if (!sendUpdateEvent) return;
return getUnlockedAchievements(objectId, shop, true) return getUnlockedAchievements(objectId, shop, true)
.then((achievements) => { .then((achievements) => {
WindowManager.mainWindow?.webContents.send( WindowManager.mainWindow?.webContents.send(
`on-update-achievements-${objectId}-${shop}`, `on-update-achievements-${objectId}-${shop}`,
achievements achievements
); );
}) })
.catch(() => {}); .catch(() => {});
}
}); });
}; };
@ -133,7 +131,7 @@ export const mergeAchievements = async (
); );
}) })
.catch((err) => { .catch((err) => {
if (err! instanceof SubscriptionRequiredError) { if (err instanceof SubscriptionRequiredError) {
achievementsLogger.log( achievementsLogger.log(
"Achievements not synchronized on API due to lack of subscription", "Achievements not synchronized on API due to lack of subscription",
game.objectId, game.objectId,

View file

@ -6,7 +6,7 @@ import { parseAchievementFile } from "./parse-achievement-file";
import { mergeAchievements } from "./merge-achievements"; import { mergeAchievements } from "./merge-achievements";
import type { Game, UnlockedAchievement } from "@types"; import type { Game, UnlockedAchievement } from "@types";
export const updateLocalUnlockedAchivements = async (game: Game) => { export const updateLocalUnlockedAchievements = async (game: Game) => {
const gameAchievementFiles = findAchievementFiles(game); const gameAchievementFiles = findAchievementFiles(game);
const achievementFileInsideDirectory = const achievementFileInsideDirectory =

View file

@ -219,8 +219,10 @@ export class DownloadManager {
} as PauseDownloadPayload) } as PauseDownloadPayload)
.catch(() => {}); .catch(() => {});
WindowManager.mainWindow?.setProgressBar(-1); if (downloadKey === this.downloadingGameId) {
this.downloadingGameId = null; WindowManager.mainWindow?.setProgressBar(-1);
this.downloadingGameId = null;
}
} }
static async resumeDownload(download: Download) { static async resumeDownload(download: Download) {

View file

@ -24,7 +24,7 @@ export const mergeWithRemoteGames = async () => {
? game.playTimeInMilliseconds ? game.playTimeInMilliseconds
: localGame.playTimeInMilliseconds; : localGame.playTimeInMilliseconds;
gamesSublevel.put(levelKeys.game(game.shop, game.objectId), { await gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
...localGame, ...localGame,
remoteId: game.id, remoteId: game.id,
lastTimePlayed: updatedLastTimePlayed, lastTimePlayed: updatedLastTimePlayed,
@ -39,7 +39,7 @@ export const mergeWithRemoteGames = async () => {
? steamUrlBuilder.icon(game.objectId, steamGame.clientIcon) ? steamUrlBuilder.icon(game.objectId, steamGame.clientIcon)
: null; : null;
gamesSublevel.put(levelKeys.game(game.shop, game.objectId), { await gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
objectId: game.objectId, objectId: game.objectId,
title: steamGame?.name, title: steamGame?.name,
remoteId: game.id, remoteId: game.id,

View file

@ -245,13 +245,16 @@ export class WindowManager {
); );
} else { } else {
editorWindow.loadFile(path.join(__dirname, "../renderer/index.html"), { editorWindow.loadFile(path.join(__dirname, "../renderer/index.html"), {
hash: `editor?themeId=${themeId}`, hash: `theme-editor?themeId=${themeId}`,
}); });
} }
editorWindow.once("ready-to-show", () => { editorWindow.once("ready-to-show", () => {
editorWindow.show(); editorWindow.show();
WindowManager.mainWindow?.webContents.openDevTools(); this.mainWindow?.webContents.openDevTools();
if (isStaging) {
editorWindow.webContents.openDevTools();
}
}); });
editorWindow.webContents.on("before-input-event", (event, input) => { editorWindow.webContents.on("before-input-event", (event, input) => {
@ -262,7 +265,7 @@ export class WindowManager {
}); });
editorWindow.on("close", () => { editorWindow.on("close", () => {
WindowManager.mainWindow?.webContents.closeDevTools(); this.mainWindow?.webContents.closeDevTools();
this.editorWindows.delete(themeId); this.editorWindows.delete(themeId);
}); });
} }

View file

@ -23,6 +23,7 @@
&__content { &__content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1;
padding: calc(globals.$spacing-unit * 2); padding: calc(globals.$spacing-unit * 2);
gap: calc(globals.$spacing-unit * 2); gap: calc(globals.$spacing-unit * 2);
width: 100%; width: 100%;
@ -54,6 +55,7 @@
display: flex; display: flex;
color: globals.$muted-color; color: globals.$muted-color;
border-radius: 4px; border-radius: 4px;
&:hover { &:hover {
background-color: rgba(255, 255, 255, 0.15); background-color: rgba(255, 255, 255, 0.15);
} }
@ -104,13 +106,14 @@
&__container { &__container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1;
overflow: hidden; overflow: hidden;
} }
&__section { &__section {
gap: calc(globals.$spacing-unit * 2);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: calc(globals.$spacing-unit * 2);
padding-bottom: globals.$spacing-unit; padding-bottom: globals.$spacing-unit;
} }

View file

@ -39,7 +39,7 @@ export function useDownload() {
const pauseDownload = async (shop: GameShop, objectId: string) => { const pauseDownload = async (shop: GameShop, objectId: string) => {
await window.electron.pauseGameDownload(shop, objectId); await window.electron.pauseGameDownload(shop, objectId);
await updateLibrary(); await updateLibrary();
dispatch(clearDownload()); if (lastPacket?.gameId === `${shop}:${objectId}`) dispatch(clearDownload());
}; };
const resumeDownload = async (shop: GameShop, objectId: string) => { const resumeDownload = async (shop: GameShop, objectId: string) => {

View file

@ -5,6 +5,14 @@
flex-direction: column; flex-direction: column;
gap: calc(globals.$spacing-unit * 2); gap: calc(globals.$spacing-unit * 2);
&__details-with-article {
display: flex;
align-items: center;
gap: calc(globals.$spacing-unit / 2);
align-self: flex-start;
cursor: pointer;
}
&__header { &__header {
display: flex; display: flex;
align-items: center; align-items: center;

View file

@ -24,6 +24,7 @@ import {
DownloadIcon, DownloadIcon,
LinkIcon, LinkIcon,
PlayIcon, PlayIcon,
QuestionIcon,
ThreeBarsIcon, ThreeBarsIcon,
TrashIcon, TrashIcon,
UnlinkIcon, UnlinkIcon,
@ -123,8 +124,12 @@ export function DownloadGroup({
</p> </p>
{download.downloader === Downloader.Torrent && ( {download.downloader === Downloader.Torrent && (
<small> <small
className="download-group__details-with-article"
data-open-article="peers-and-seeds"
>
{lastPacket?.numPeers} peers / {lastPacket?.numSeeds} seeds {lastPacket?.numPeers} peers / {lastPacket?.numSeeds} seeds
<QuestionIcon size={12} />
</small> </small>
)} )}
</> </>
@ -137,7 +142,14 @@ export function DownloadGroup({
return download.status === "seeding" && return download.status === "seeding" &&
download.downloader === Downloader.Torrent ? ( download.downloader === Downloader.Torrent ? (
<> <>
<p>{t("seeding")}</p> <p
data-open-article="seeding"
className="download-group__details-with-article"
>
{t("seeding")}
<QuestionIcon />
</p>
{uploadSpeed && <p>{uploadSpeed}/s</p>} {uploadSpeed && <p>{uploadSpeed}/s</p>}
</> </>
) : ( ) : (
@ -175,7 +187,7 @@ export function DownloadGroup({
const deleting = isGameDeleting(game.id); const deleting = isGameDeleting(game.id);
if (download?.progress === 1) { if (game.download?.progress === 1) {
return [ return [
{ {
label: t("install"), label: t("install"),
@ -190,8 +202,8 @@ export function DownloadGroup({
disabled: deleting, disabled: deleting,
icon: <UnlinkIcon />, icon: <UnlinkIcon />,
show: show:
download.status === "seeding" && game.download?.status === "seeding" &&
download.downloader === Downloader.Torrent, game.download?.downloader === Downloader.Torrent,
onClick: () => { onClick: () => {
pauseSeeding(game.shop, game.objectId); pauseSeeding(game.shop, game.objectId);
}, },
@ -201,8 +213,8 @@ export function DownloadGroup({
disabled: deleting, disabled: deleting,
icon: <LinkIcon />, icon: <LinkIcon />,
show: show:
download.status !== "seeding" && game.download?.status !== "seeding" &&
download.downloader === Downloader.Torrent, game.download?.downloader === Downloader.Torrent,
onClick: () => { onClick: () => {
resumeSeeding(game.shop, game.objectId); resumeSeeding(game.shop, game.objectId);
}, },
@ -218,7 +230,7 @@ export function DownloadGroup({
]; ];
} }
if (isGameDownloading || download?.status === "active") { if (isGameDownloading) {
return [ return [
{ {
label: t("pause"), label: t("pause"),

View file

@ -8,7 +8,7 @@ import "./downloads.scss";
import { DeleteGameModal } from "./delete-game-modal"; import { DeleteGameModal } from "./delete-game-modal";
import { DownloadGroup } from "./download-group"; import { DownloadGroup } from "./download-group";
import type { GameShop, LibraryGame, SeedingStatus } from "@types"; import type { GameShop, LibraryGame, SeedingStatus } from "@types";
import { orderBy, sortBy } from "lodash-es"; import { orderBy } from "lodash-es";
import { ArrowDownIcon } from "@primer/octicons-react"; import { ArrowDownIcon } from "@primer/octicons-react";
export default function Downloads() { export default function Downloads() {
@ -58,24 +58,24 @@ export default function Downloads() {
complete: [], complete: [],
}; };
const result = sortBy(library, (game) => game.download?.timestamp).reduce( const result = orderBy(
(prev, next) => { library,
/* Game has been manually added to the library or has been canceled */ (game) => game.download?.timestamp,
if (!next.download?.status || next.download?.status === "removed") "desc"
return prev; ).reduce((prev, next) => {
/* Game has been manually added to the library */
if (!next.download) return prev;
/* Is downloading */ /* Is downloading */
if (lastPacket?.gameId === next.id) if (lastPacket?.gameId === next.id)
return { ...prev, downloading: [...prev.downloading, next] }; return { ...prev, downloading: [...prev.downloading, next] };
/* Is either queued or paused */ /* Is either queued or paused */
if (next.download.queued || next.download?.status === "paused") if (next.download.queued || next.download?.status === "paused")
return { ...prev, queued: [...prev.queued, next] }; return { ...prev, queued: [...prev.queued, next] };
return { ...prev, complete: [...prev.complete, next] }; return { ...prev, complete: [...prev.complete, next] };
}, }, initialValue);
initialValue
);
const queued = orderBy(result.queued, (game) => game.download?.timestamp, [ const queued = orderBy(result.queued, (game) => game.download?.timestamp, [
"desc", "desc",

View file

@ -67,7 +67,7 @@ export const ThemeActions = ({
onClick={() => setAddThemeModalVisible(true)} onClick={() => setAddThemeModalVisible(true)}
> >
<PlusIcon /> <PlusIcon />
{t("add_theme")} {t("create_theme")}
</Button> </Button>
</div> </div>
</div> </div>

View file

@ -56,8 +56,8 @@ export const AddThemeModal = ({
return ( return (
<Modal <Modal
visible={visible} visible={visible}
title={t("add_theme_modal_title")} title={t("create_theme_modal_title")}
description={t("add_theme_modal_description")} description={t("create_theme_modal_description")}
onClose={onClose} onClose={onClose}
> >
<div className="add-theme-modal__container"> <div className="add-theme-modal__container">
@ -72,7 +72,7 @@ export const AddThemeModal = ({
/> />
<Button theme="primary" onClick={handleSubmit}> <Button theme="primary" onClick={handleSubmit}>
{t("add_theme")} {t("create_theme")}
</Button> </Button>
</div> </div>
</Modal> </Modal>