mirror of
				https://github.com/hydralauncher/hydra.git
				synced 2025-03-09 15:40:26 +00:00 
			
		
		
		
	Merge pull request #1444 from hydralauncher/fix/fixing-seeding-on-level
fix: fixing seeding on level
This commit is contained in:
		
						commit
						42ae8e76a6
					
				
					 18 changed files with 108 additions and 70 deletions
				
			
		| 
						 | 
					@ -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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,14 @@ const cancelGameDownload = async (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await DownloadManager.cancelDownload(downloadKey);
 | 
					  await DownloadManager.cancelDownload(downloadKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await downloadsSublevel.del(downloadKey);
 | 
					  const download = await downloadsSublevel.get(downloadKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!download) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  await downloadsSublevel.put(downloadKey, {
 | 
				
			||||||
 | 
					    ...download,
 | 
				
			||||||
 | 
					    status: "removed",
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
registerEvent("cancelGameDownload", cancelGameDownload);
 | 
					registerEvent("cancelGameDownload", cancelGameDownload);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@ const pauseGameSeed = async (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await downloadsSublevel.put(downloadKey, {
 | 
					  await downloadsSublevel.put(downloadKey, {
 | 
				
			||||||
    ...download,
 | 
					    ...download,
 | 
				
			||||||
 | 
					    status: "complete",
 | 
				
			||||||
    shouldSeed: false,
 | 
					    shouldSeed: false,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,23 +57,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();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,9 +23,8 @@ 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, {
 | 
				
			||||||
          ...gameAchievement,
 | 
					        achievements: gameAchievement?.achievements ?? [],
 | 
				
			||||||
        unlockedAchievements: unlockedAchievements,
 | 
					        unlockedAchievements: unlockedAchievements,
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +38,6 @@ const saveAchievementsOnLocal = async (
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -219,9 +219,11 @@ export class DownloadManager {
 | 
				
			||||||
      } as PauseDownloadPayload)
 | 
					      } as PauseDownloadPayload)
 | 
				
			||||||
      .catch(() => {});
 | 
					      .catch(() => {});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (downloadKey === this.downloadingGameId) {
 | 
				
			||||||
      WindowManager.mainWindow?.setProgressBar(-1);
 | 
					      WindowManager.mainWindow?.setProgressBar(-1);
 | 
				
			||||||
      this.downloadingGameId = null;
 | 
					      this.downloadingGameId = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static async resumeDownload(download: Download) {
 | 
					  static async resumeDownload(download: Download) {
 | 
				
			||||||
    return this.startDownload(download);
 | 
					    return this.startDownload(download);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@ import {
 | 
				
			||||||
  DownloadIcon,
 | 
					  DownloadIcon,
 | 
				
			||||||
  LinkIcon,
 | 
					  LinkIcon,
 | 
				
			||||||
  PlayIcon,
 | 
					  PlayIcon,
 | 
				
			||||||
 | 
					  QuestionIcon,
 | 
				
			||||||
  ThreeBarsIcon,
 | 
					  ThreeBarsIcon,
 | 
				
			||||||
  TrashIcon,
 | 
					  TrashIcon,
 | 
				
			||||||
  UnlinkIcon,
 | 
					  UnlinkIcon,
 | 
				
			||||||
| 
						 | 
					@ -122,8 +123,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>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
| 
						 | 
					@ -136,7 +141,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>}
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
      ) : (
 | 
					      ) : (
 | 
				
			||||||
| 
						 | 
					@ -174,7 +186,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"),
 | 
				
			||||||
| 
						 | 
					@ -189,8 +201,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);
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
| 
						 | 
					@ -200,8 +212,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);
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
| 
						 | 
					@ -217,7 +229,7 @@ export function DownloadGroup({
 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (isGameDownloading || download?.status === "active") {
 | 
					    if (isGameDownloading) {
 | 
				
			||||||
      return [
 | 
					      return [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          label: t("pause"),
 | 
					          label: t("pause"),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,11 +58,13 @@ 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)
 | 
				
			||||||
| 
						 | 
					@ -73,9 +75,7 @@ export default function Downloads() {
 | 
				
			||||||
        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",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,8 +163,10 @@ export function DownloadSettingsModal({
 | 
				
			||||||
                  selectedDownloader === downloader ? "primary" : "outline"
 | 
					                  selectedDownloader === downloader ? "primary" : "outline"
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                disabled={
 | 
					                disabled={
 | 
				
			||||||
                  downloader === Downloader.RealDebrid &&
 | 
					                  (downloader === Downloader.RealDebrid &&
 | 
				
			||||||
                  !userPreferences?.realDebridApiToken
 | 
					                    !userPreferences?.realDebridApiToken) ||
 | 
				
			||||||
 | 
					                  (downloader === Downloader.TorBox &&
 | 
				
			||||||
 | 
					                    !userPreferences?.torBoxApiToken)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                onClick={() => setSelectedDownloader(downloader)}
 | 
					                onClick={() => setSelectedDownloader(downloader)}
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue