mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
feat: adding generic http downloads
This commit is contained in:
parent
6fce60f9f7
commit
6c6fff71fe
12 changed files with 294 additions and 41 deletions
|
@ -44,6 +44,8 @@ const startGameDownload = async (
|
||||||
);
|
);
|
||||||
|
|
||||||
if (game) {
|
if (game) {
|
||||||
|
console.log("game", game);
|
||||||
|
|
||||||
await gameRepository.update(
|
await gameRepository.update(
|
||||||
{
|
{
|
||||||
id: game.id,
|
id: game.id,
|
||||||
|
@ -95,6 +97,8 @@ const startGameDownload = async (
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(updatedGame);
|
||||||
|
|
||||||
createGame(updatedGame!);
|
createGame(updatedGame!);
|
||||||
|
|
||||||
await downloadQueueRepository.delete({ game: { id: updatedGame!.id } });
|
await downloadQueueRepository.delete({ game: { id: updatedGame!.id } });
|
||||||
|
|
|
@ -22,8 +22,9 @@ const loadState = async (userPreferences: UserPreferences | null) => {
|
||||||
|
|
||||||
import("./events");
|
import("./events");
|
||||||
|
|
||||||
if (userPreferences?.realDebridApiToken)
|
if (userPreferences?.realDebridApiToken) {
|
||||||
RealDebridClient.authorize(userPreferences?.realDebridApiToken);
|
RealDebridClient.authorize(userPreferences?.realDebridApiToken);
|
||||||
|
}
|
||||||
|
|
||||||
HydraApi.setupApi().then(() => {
|
HydraApi.setupApi().then(() => {
|
||||||
uploadGamesBatch();
|
uploadGamesBatch();
|
||||||
|
|
|
@ -6,6 +6,8 @@ import { downloadQueueRepository, gameRepository } from "@main/repository";
|
||||||
import { publishDownloadCompleteNotification } from "../notifications";
|
import { publishDownloadCompleteNotification } from "../notifications";
|
||||||
import { RealDebridDownloader } from "./real-debrid-downloader";
|
import { RealDebridDownloader } from "./real-debrid-downloader";
|
||||||
import type { DownloadProgress } from "@types";
|
import type { DownloadProgress } from "@types";
|
||||||
|
import { GofileApi } from "../hosters";
|
||||||
|
import { GenericHTTPDownloader } from "./generic-http-downloader";
|
||||||
|
|
||||||
export class DownloadManager {
|
export class DownloadManager {
|
||||||
private static currentDownloader: Downloader | null = null;
|
private static currentDownloader: Downloader | null = null;
|
||||||
|
@ -13,10 +15,12 @@ export class DownloadManager {
|
||||||
public static async watchDownloads() {
|
public static async watchDownloads() {
|
||||||
let status: DownloadProgress | null = null;
|
let status: DownloadProgress | null = null;
|
||||||
|
|
||||||
if (this.currentDownloader === Downloader.RealDebrid) {
|
if (this.currentDownloader === Downloader.Torrent) {
|
||||||
|
status = await PythonInstance.getStatus();
|
||||||
|
} else if (this.currentDownloader === Downloader.RealDebrid) {
|
||||||
status = await RealDebridDownloader.getStatus();
|
status = await RealDebridDownloader.getStatus();
|
||||||
} else {
|
} else {
|
||||||
status = await PythonInstance.getStatus();
|
status = await GenericHTTPDownloader.getStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
|
@ -62,10 +66,12 @@ export class DownloadManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async pauseDownload() {
|
static async pauseDownload() {
|
||||||
if (this.currentDownloader === Downloader.RealDebrid) {
|
if (this.currentDownloader === Downloader.Torrent) {
|
||||||
|
await PythonInstance.pauseDownload();
|
||||||
|
} else if (this.currentDownloader === Downloader.RealDebrid) {
|
||||||
await RealDebridDownloader.pauseDownload();
|
await RealDebridDownloader.pauseDownload();
|
||||||
} else {
|
} else {
|
||||||
await PythonInstance.pauseDownload();
|
await GenericHTTPDownloader.pauseDownload();
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowManager.mainWindow?.setProgressBar(-1);
|
WindowManager.mainWindow?.setProgressBar(-1);
|
||||||
|
@ -73,20 +79,16 @@ export class DownloadManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async resumeDownload(game: Game) {
|
static async resumeDownload(game: Game) {
|
||||||
if (game.downloader === Downloader.RealDebrid) {
|
return this.startDownload(game);
|
||||||
RealDebridDownloader.startDownload(game);
|
|
||||||
this.currentDownloader = Downloader.RealDebrid;
|
|
||||||
} else {
|
|
||||||
PythonInstance.startDownload(game);
|
|
||||||
this.currentDownloader = Downloader.Torrent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async cancelDownload(gameId: number) {
|
static async cancelDownload(gameId: number) {
|
||||||
if (this.currentDownloader === Downloader.RealDebrid) {
|
if (this.currentDownloader === Downloader.Torrent) {
|
||||||
|
PythonInstance.cancelDownload(gameId);
|
||||||
|
} else if (this.currentDownloader === Downloader.RealDebrid) {
|
||||||
RealDebridDownloader.cancelDownload(gameId);
|
RealDebridDownloader.cancelDownload(gameId);
|
||||||
} else {
|
} else {
|
||||||
PythonInstance.cancelDownload(gameId);
|
GenericHTTPDownloader.cancelDownload(gameId);
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowManager.mainWindow?.setProgressBar(-1);
|
WindowManager.mainWindow?.setProgressBar(-1);
|
||||||
|
@ -94,12 +96,30 @@ export class DownloadManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async startDownload(game: Game) {
|
static async startDownload(game: Game) {
|
||||||
if (game.downloader === Downloader.RealDebrid) {
|
if (game.downloader === Downloader.Gofile) {
|
||||||
RealDebridDownloader.startDownload(game);
|
const id = game!.uri!.split("/").pop();
|
||||||
this.currentDownloader = Downloader.RealDebrid;
|
|
||||||
} else {
|
const token = await GofileApi.authorize();
|
||||||
|
const downloadLink = await GofileApi.getDownloadLink(id!);
|
||||||
|
|
||||||
|
console.log(downloadLink, token, "<<<");
|
||||||
|
|
||||||
|
GenericHTTPDownloader.startDownload(game, downloadLink, [
|
||||||
|
`Cookie: accountToken=${token}`,
|
||||||
|
]);
|
||||||
|
} else if (game.downloader === Downloader.PixelDrain) {
|
||||||
|
const id = game!.uri!.split("/").pop();
|
||||||
|
|
||||||
|
await GenericHTTPDownloader.startDownload(
|
||||||
|
game,
|
||||||
|
`https://pixeldrain.com/api/file/${id}?download`
|
||||||
|
);
|
||||||
|
} else if (game.downloader === Downloader.Torrent) {
|
||||||
PythonInstance.startDownload(game);
|
PythonInstance.startDownload(game);
|
||||||
this.currentDownloader = Downloader.Torrent;
|
} else if (game.downloader === Downloader.RealDebrid) {
|
||||||
|
RealDebridDownloader.startDownload(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.currentDownloader = game.downloader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
109
src/main/services/download/generic-http-downloader.ts
Normal file
109
src/main/services/download/generic-http-downloader.ts
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
import { Game } from "@main/entity";
|
||||||
|
import { gameRepository } from "@main/repository";
|
||||||
|
import { calculateETA } from "./helpers";
|
||||||
|
import { DownloadProgress } from "@types";
|
||||||
|
import { HTTPDownload } from "./http-download";
|
||||||
|
|
||||||
|
export class GenericHTTPDownloader {
|
||||||
|
private static downloads = new Map<number, string>();
|
||||||
|
private static downloadingGame: Game | null = null;
|
||||||
|
|
||||||
|
public static async getStatus() {
|
||||||
|
if (this.downloadingGame) {
|
||||||
|
const gid = this.downloads.get(this.downloadingGame.id)!;
|
||||||
|
const status = await HTTPDownload.getStatus(gid);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
const progress =
|
||||||
|
Number(status.completedLength) / Number(status.totalLength);
|
||||||
|
|
||||||
|
await gameRepository.update(
|
||||||
|
{ id: this.downloadingGame!.id },
|
||||||
|
{
|
||||||
|
bytesDownloaded: Number(status.completedLength),
|
||||||
|
fileSize: Number(status.totalLength),
|
||||||
|
progress,
|
||||||
|
status: "active",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
numPeers: 0,
|
||||||
|
numSeeds: 0,
|
||||||
|
downloadSpeed: Number(status.downloadSpeed),
|
||||||
|
timeRemaining: calculateETA(
|
||||||
|
Number(status.totalLength),
|
||||||
|
Number(status.completedLength),
|
||||||
|
Number(status.downloadSpeed)
|
||||||
|
),
|
||||||
|
isDownloadingMetadata: false,
|
||||||
|
isCheckingFiles: false,
|
||||||
|
progress,
|
||||||
|
gameId: this.downloadingGame!.id,
|
||||||
|
} as DownloadProgress;
|
||||||
|
|
||||||
|
if (progress === 1) {
|
||||||
|
this.downloads.delete(this.downloadingGame.id);
|
||||||
|
this.downloadingGame = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async pauseDownload() {
|
||||||
|
if (this.downloadingGame) {
|
||||||
|
const gid = this.downloads.get(this.downloadingGame!.id!);
|
||||||
|
|
||||||
|
if (gid) {
|
||||||
|
await HTTPDownload.pauseDownload(gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.downloadingGame = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async startDownload(
|
||||||
|
game: Game,
|
||||||
|
downloadUrl: string,
|
||||||
|
headers: string[] = []
|
||||||
|
) {
|
||||||
|
this.downloadingGame = game;
|
||||||
|
|
||||||
|
if (this.downloads.has(game.id)) {
|
||||||
|
await this.resumeDownload(game.id!);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (downloadUrl) {
|
||||||
|
const gid = await HTTPDownload.startDownload(
|
||||||
|
game.downloadPath!,
|
||||||
|
downloadUrl,
|
||||||
|
headers
|
||||||
|
);
|
||||||
|
|
||||||
|
this.downloads.set(game.id!, gid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async cancelDownload(gameId: number) {
|
||||||
|
const gid = this.downloads.get(gameId);
|
||||||
|
|
||||||
|
if (gid) {
|
||||||
|
await HTTPDownload.cancelDownload(gid);
|
||||||
|
this.downloads.delete(gameId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async resumeDownload(gameId: number) {
|
||||||
|
const gid = this.downloads.get(gameId);
|
||||||
|
|
||||||
|
if (gid) {
|
||||||
|
await HTTPDownload.resumeDownload(gid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import { sleep } from "@main/helpers";
|
||||||
import { startAria2 } from "../aria2c";
|
import { startAria2 } from "../aria2c";
|
||||||
import Aria2 from "aria2";
|
import Aria2 from "aria2";
|
||||||
|
|
||||||
export class HttpDownload {
|
export class HTTPDownload {
|
||||||
private static connected = false;
|
private static connected = false;
|
||||||
private static aria2c: ChildProcess | null = null;
|
private static aria2c: ChildProcess | null = null;
|
||||||
|
|
||||||
|
@ -56,11 +56,17 @@ export class HttpDownload {
|
||||||
await this.aria2.call("unpause", gid);
|
await this.aria2.call("unpause", gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async startDownload(downloadPath: string, downloadUrl: string) {
|
static async startDownload(
|
||||||
|
downloadPath: string,
|
||||||
|
downloadUrl: string,
|
||||||
|
header: string[] = []
|
||||||
|
) {
|
||||||
|
console.log(header);
|
||||||
if (!this.connected) await this.connect();
|
if (!this.connected) await this.connect();
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
dir: downloadPath,
|
dir: downloadPath,
|
||||||
|
header,
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.aria2.call("addUri", [downloadUrl], options);
|
return this.aria2.call("addUri", [downloadUrl], options);
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { RealDebridClient } from "../real-debrid";
|
||||||
import { gameRepository } from "@main/repository";
|
import { gameRepository } from "@main/repository";
|
||||||
import { calculateETA } from "./helpers";
|
import { calculateETA } from "./helpers";
|
||||||
import { DownloadProgress } from "@types";
|
import { DownloadProgress } from "@types";
|
||||||
import { HttpDownload } from "./http-download";
|
import { HTTPDownload } from "./http-download";
|
||||||
|
|
||||||
export class RealDebridDownloader {
|
export class RealDebridDownloader {
|
||||||
private static downloads = new Map<number, string>();
|
private static downloads = new Map<number, string>();
|
||||||
|
@ -29,6 +29,18 @@ export class RealDebridDownloader {
|
||||||
const { download } = await RealDebridClient.unrestrictLink(link);
|
const { download } = await RealDebridClient.unrestrictLink(link);
|
||||||
return decodeURIComponent(download);
|
return decodeURIComponent(download);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.downloadingGame?.uri) {
|
||||||
|
const { download } = await RealDebridClient.unrestrictLink(
|
||||||
|
this.downloadingGame?.uri
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("download>>", download);
|
||||||
|
|
||||||
|
return decodeURIComponent(download);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -37,7 +49,7 @@ export class RealDebridDownloader {
|
||||||
public static async getStatus() {
|
public static async getStatus() {
|
||||||
if (this.downloadingGame) {
|
if (this.downloadingGame) {
|
||||||
const gid = this.downloads.get(this.downloadingGame.id)!;
|
const gid = this.downloads.get(this.downloadingGame.id)!;
|
||||||
const status = await HttpDownload.getStatus(gid);
|
const status = await HTTPDownload.getStatus(gid);
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
const progress =
|
const progress =
|
||||||
|
@ -111,7 +123,7 @@ export class RealDebridDownloader {
|
||||||
static async pauseDownload() {
|
static async pauseDownload() {
|
||||||
const gid = this.downloads.get(this.downloadingGame!.id!);
|
const gid = this.downloads.get(this.downloadingGame!.id!);
|
||||||
if (gid) {
|
if (gid) {
|
||||||
await HttpDownload.pauseDownload(gid);
|
await HTTPDownload.pauseDownload(gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.realDebridTorrentId = null;
|
this.realDebridTorrentId = null;
|
||||||
|
@ -127,14 +139,18 @@ export class RealDebridDownloader {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.realDebridTorrentId = await RealDebridClient.getTorrentId(game!.uri!);
|
if (game.uri?.startsWith("magnet:")) {
|
||||||
|
this.realDebridTorrentId = await RealDebridClient.getTorrentId(
|
||||||
|
game!.uri!
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const downloadUrl = await this.getRealDebridDownloadUrl();
|
const downloadUrl = await this.getRealDebridDownloadUrl();
|
||||||
|
|
||||||
if (downloadUrl) {
|
if (downloadUrl) {
|
||||||
this.realDebridTorrentId = null;
|
this.realDebridTorrentId = null;
|
||||||
|
|
||||||
const gid = await HttpDownload.startDownload(
|
const gid = await HTTPDownload.startDownload(
|
||||||
game.downloadPath!,
|
game.downloadPath!,
|
||||||
downloadUrl
|
downloadUrl
|
||||||
);
|
);
|
||||||
|
@ -147,7 +163,7 @@ export class RealDebridDownloader {
|
||||||
const gid = this.downloads.get(gameId);
|
const gid = this.downloads.get(gameId);
|
||||||
|
|
||||||
if (gid) {
|
if (gid) {
|
||||||
await HttpDownload.cancelDownload(gid);
|
await HTTPDownload.cancelDownload(gid);
|
||||||
this.downloads.delete(gameId);
|
this.downloads.delete(gameId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,7 +172,7 @@ export class RealDebridDownloader {
|
||||||
const gid = this.downloads.get(gameId);
|
const gid = this.downloads.get(gameId);
|
||||||
|
|
||||||
if (gid) {
|
if (gid) {
|
||||||
await HttpDownload.resumeDownload(gid);
|
await HTTPDownload.resumeDownload(gid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
61
src/main/services/hosters/gofile.ts
Normal file
61
src/main/services/hosters/gofile.ts
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export interface GofileAccountsReponse {
|
||||||
|
id: string;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GofileContentChild {
|
||||||
|
id: string;
|
||||||
|
link: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GofileContentsResponse {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
children: Record<string, GofileContentChild>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GofileApi {
|
||||||
|
private static token: string;
|
||||||
|
|
||||||
|
public static async authorize() {
|
||||||
|
const response = await axios.post<{
|
||||||
|
status: string;
|
||||||
|
data: GofileAccountsReponse;
|
||||||
|
}>("https://api.gofile.io/accounts");
|
||||||
|
|
||||||
|
if (response.data.status === "ok") {
|
||||||
|
this.token = response.data.data.token;
|
||||||
|
return this.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Failed to authorize");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async getDownloadLink(id: string) {
|
||||||
|
const searchParams = new URLSearchParams({
|
||||||
|
wt: "4fd6sg89d7s6",
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await axios.get<{
|
||||||
|
status: string;
|
||||||
|
data: GofileContentsResponse;
|
||||||
|
}>(`https://api.gofile.io/contents/${id}?${searchParams.toString()}`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${this.token}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.data.status === "ok") {
|
||||||
|
if (response.data.data.type !== "folder") {
|
||||||
|
throw new Error("Only folders are supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
const [firstChild] = Object.values(response.data.data.children);
|
||||||
|
return firstChild.link;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Failed to get download link");
|
||||||
|
}
|
||||||
|
}
|
1
src/main/services/hosters/index.ts
Normal file
1
src/main/services/hosters/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from "./gofile";
|
|
@ -5,4 +5,6 @@ export const VERSION_CODENAME = "Leviticus";
|
||||||
export const DOWNLOADER_NAME = {
|
export const DOWNLOADER_NAME = {
|
||||||
[Downloader.RealDebrid]: "Real-Debrid",
|
[Downloader.RealDebrid]: "Real-Debrid",
|
||||||
[Downloader.Torrent]: "Torrent",
|
[Downloader.Torrent]: "Torrent",
|
||||||
|
[Downloader.Gofile]: "Gofile",
|
||||||
|
[Downloader.PixelDrain]: "PixelDrain",
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { DiskSpace } from "check-disk-space";
|
import { DiskSpace } from "check-disk-space";
|
||||||
import * as styles from "./download-settings-modal.css";
|
import * as styles from "./download-settings-modal.css";
|
||||||
import { Button, Link, Modal, TextField } from "@renderer/components";
|
import { Button, Link, Modal, TextField } from "@renderer/components";
|
||||||
import { CheckCircleFillIcon, DownloadIcon } from "@primer/octicons-react";
|
import { CheckCircleFillIcon, DownloadIcon } from "@primer/octicons-react";
|
||||||
import { Downloader, formatBytes } from "@shared";
|
import { Downloader, formatBytes, getDownloadersForUri } from "@shared";
|
||||||
|
|
||||||
import type { GameRepack } from "@types";
|
import type { GameRepack } from "@types";
|
||||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||||
|
@ -23,8 +23,6 @@ export interface DownloadSettingsModalProps {
|
||||||
repack: GameRepack | null;
|
repack: GameRepack | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloaders = [Downloader.Torrent, Downloader.RealDebrid];
|
|
||||||
|
|
||||||
export function DownloadSettingsModal({
|
export function DownloadSettingsModal({
|
||||||
visible,
|
visible,
|
||||||
onClose,
|
onClose,
|
||||||
|
@ -36,9 +34,8 @@ export function DownloadSettingsModal({
|
||||||
const [diskFreeSpace, setDiskFreeSpace] = useState<DiskSpace | null>(null);
|
const [diskFreeSpace, setDiskFreeSpace] = useState<DiskSpace | null>(null);
|
||||||
const [selectedPath, setSelectedPath] = useState("");
|
const [selectedPath, setSelectedPath] = useState("");
|
||||||
const [downloadStarting, setDownloadStarting] = useState(false);
|
const [downloadStarting, setDownloadStarting] = useState(false);
|
||||||
const [selectedDownloader, setSelectedDownloader] = useState(
|
const [selectedDownloader, setSelectedDownloader] =
|
||||||
Downloader.Torrent
|
useState<Downloader | null>(null);
|
||||||
);
|
|
||||||
|
|
||||||
const userPreferences = useAppSelector(
|
const userPreferences = useAppSelector(
|
||||||
(state) => state.userPreferences.value
|
(state) => state.userPreferences.value
|
||||||
|
@ -50,6 +47,10 @@ export function DownloadSettingsModal({
|
||||||
}
|
}
|
||||||
}, [visible, selectedPath]);
|
}, [visible, selectedPath]);
|
||||||
|
|
||||||
|
const downloaders = useMemo(() => {
|
||||||
|
return getDownloadersForUri(repack?.magnet ?? "");
|
||||||
|
}, [repack?.magnet]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (userPreferences?.downloadsPath) {
|
if (userPreferences?.downloadsPath) {
|
||||||
setSelectedPath(userPreferences.downloadsPath);
|
setSelectedPath(userPreferences.downloadsPath);
|
||||||
|
@ -59,9 +60,19 @@ export function DownloadSettingsModal({
|
||||||
.then((defaultDownloadsPath) => setSelectedPath(defaultDownloadsPath));
|
.then((defaultDownloadsPath) => setSelectedPath(defaultDownloadsPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userPreferences?.realDebridApiToken)
|
if (
|
||||||
|
userPreferences?.realDebridApiToken &&
|
||||||
|
downloaders.includes(Downloader.RealDebrid)
|
||||||
|
) {
|
||||||
setSelectedDownloader(Downloader.RealDebrid);
|
setSelectedDownloader(Downloader.RealDebrid);
|
||||||
}, [userPreferences?.downloadsPath, userPreferences?.realDebridApiToken]);
|
} else {
|
||||||
|
setSelectedDownloader(downloaders[0]);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
userPreferences?.downloadsPath,
|
||||||
|
downloaders,
|
||||||
|
userPreferences?.realDebridApiToken,
|
||||||
|
]);
|
||||||
|
|
||||||
const getDiskFreeSpace = (path: string) => {
|
const getDiskFreeSpace = (path: string) => {
|
||||||
window.electron.getDiskFreeSpace(path).then((result) => {
|
window.electron.getDiskFreeSpace(path).then((result) => {
|
||||||
|
@ -85,7 +96,7 @@ export function DownloadSettingsModal({
|
||||||
if (repack) {
|
if (repack) {
|
||||||
setDownloadStarting(true);
|
setDownloadStarting(true);
|
||||||
|
|
||||||
startDownload(repack, selectedDownloader, selectedPath).finally(() => {
|
startDownload(repack, selectedDownloader!, selectedPath).finally(() => {
|
||||||
setDownloadStarting(false);
|
setDownloadStarting(false);
|
||||||
onClose();
|
onClose();
|
||||||
});
|
});
|
||||||
|
@ -167,7 +178,10 @@ export function DownloadSettingsModal({
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button onClick={handleStartClick} disabled={downloadStarting}>
|
<Button
|
||||||
|
onClick={handleStartClick}
|
||||||
|
disabled={downloadStarting || selectedDownloader === null}
|
||||||
|
>
|
||||||
<DownloadIcon />
|
<DownloadIcon />
|
||||||
{t("download_now")}
|
{t("download_now")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -44,8 +44,10 @@ export function RepacksModal({
|
||||||
}, [repacks]);
|
}, [repacks]);
|
||||||
|
|
||||||
const getInfoHash = useCallback(async () => {
|
const getInfoHash = useCallback(async () => {
|
||||||
|
if (game?.uri?.startsWith("magnet:")) {
|
||||||
const torrent = await parseTorrent(game?.uri ?? "");
|
const torrent = await parseTorrent(game?.uri ?? "");
|
||||||
if (torrent.infoHash) setInfoHash(torrent.infoHash);
|
if (torrent.infoHash) setInfoHash(torrent.infoHash);
|
||||||
|
}
|
||||||
}, [game]);
|
}, [game]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
export enum Downloader {
|
export enum Downloader {
|
||||||
RealDebrid,
|
RealDebrid,
|
||||||
Torrent,
|
Torrent,
|
||||||
|
Gofile,
|
||||||
|
PixelDrain,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DownloadSourceStatus {
|
export enum DownloadSourceStatus {
|
||||||
|
@ -63,3 +65,18 @@ export const formatName = pipe<string>(
|
||||||
removeDuplicateSpaces,
|
removeDuplicateSpaces,
|
||||||
(str) => str.trim()
|
(str) => str.trim()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const realDebridHosts = ["https://1fichier.com", "https://mediafire.com"];
|
||||||
|
|
||||||
|
export const getDownloadersForUri = (uri: string) => {
|
||||||
|
if (uri.startsWith("https://gofile.io")) return [Downloader.Gofile];
|
||||||
|
if (uri.startsWith("https://pixeldrain.com")) return [Downloader.PixelDrain];
|
||||||
|
|
||||||
|
if (realDebridHosts.some((host) => uri.startsWith(host)))
|
||||||
|
return [Downloader.RealDebrid];
|
||||||
|
|
||||||
|
if (uri.startsWith("magnet:"))
|
||||||
|
return [Downloader.Torrent, Downloader.RealDebrid];
|
||||||
|
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue