mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
Add Somewhat working logic
This commit is contained in:
parent
2a4221e787
commit
5e9aa2b0ea
13 changed files with 461 additions and 54 deletions
|
@ -1,48 +1,162 @@
|
|||
import aria2p
|
||||
from typing import Union, List
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
from aria2p import API, Client, Download
|
||||
import requests
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class HttpDownloader:
|
||||
def __init__(self):
|
||||
self.download = None
|
||||
self.aria2 = aria2p.API(
|
||||
aria2p.Client(
|
||||
host="http://localhost",
|
||||
port=6800,
|
||||
secret=""
|
||||
self.downloads = [] # vom păstra toate download-urile active
|
||||
self.aria2 = API(Client(host="http://localhost", port=6800))
|
||||
self.download = None # pentru compatibilitate cu codul vechi
|
||||
|
||||
def unlock_alldebrid_link(self, link: str) -> str:
|
||||
"""Deblochează un link AllDebrid și returnează link-ul real de descărcare."""
|
||||
api_key = os.getenv('ALLDEBRID_API_KEY')
|
||||
if not api_key:
|
||||
logger.error("AllDebrid API key nu a fost găsită în variabilele de mediu")
|
||||
return link
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
"https://api.alldebrid.com/v4/link/unlock",
|
||||
params={
|
||||
"agent": "hydra",
|
||||
"apikey": api_key,
|
||||
"link": link
|
||||
}
|
||||
)
|
||||
)
|
||||
data = response.json()
|
||||
|
||||
def start_download(self, url: str, save_path: str, header: str, out: str = None):
|
||||
if self.download:
|
||||
self.aria2.resume([self.download])
|
||||
if data.get("status") == "success":
|
||||
return data["data"]["link"]
|
||||
else:
|
||||
logger.error(f"Eroare la deblocarea link-ului AllDebrid: {data.get('error', {}).get('message', 'Unknown error')}")
|
||||
return link
|
||||
except Exception as e:
|
||||
logger.error(f"Eroare la apelul API AllDebrid: {str(e)}")
|
||||
return link
|
||||
|
||||
def start_download(self, url: Union[str, List[str]], save_path: str, header: str = None, out: str = None):
|
||||
logger.info(f"Starting download with URL: {url}, save_path: {save_path}, header: {header}, out: {out}")
|
||||
|
||||
# Pentru AllDebrid care returnează un link per fișier
|
||||
if isinstance(url, list):
|
||||
logger.info(f"Multiple URLs detected: {len(url)} files to download")
|
||||
self.downloads = []
|
||||
|
||||
# Deblocăm toate link-urile AllDebrid
|
||||
unlocked_urls = []
|
||||
for single_url in url:
|
||||
logger.info(f"Unlocking AllDebrid URL: {single_url}")
|
||||
unlocked_url = self.unlock_alldebrid_link(single_url)
|
||||
if unlocked_url:
|
||||
unlocked_urls.append(unlocked_url)
|
||||
logger.info(f"URL deblocat cu succes: {unlocked_url}")
|
||||
|
||||
# Descărcăm folosind link-urile deblocate
|
||||
for unlocked_url in unlocked_urls:
|
||||
logger.info(f"Adding download for unlocked URL: {unlocked_url}")
|
||||
options = {
|
||||
"dir": save_path
|
||||
}
|
||||
if header:
|
||||
if isinstance(header, list):
|
||||
options["header"] = header
|
||||
else:
|
||||
options["header"] = [header]
|
||||
|
||||
try:
|
||||
download = self.aria2.add_uris([unlocked_url], options=options)
|
||||
logger.info(f"Download added successfully: {download.gid}")
|
||||
self.downloads.append(download)
|
||||
except Exception as e:
|
||||
logger.error(f"Error adding download for URL {unlocked_url}: {str(e)}")
|
||||
|
||||
if self.downloads:
|
||||
self.download = self.downloads[0] # păstrăm primul pentru referință
|
||||
else:
|
||||
logger.error("No downloads were successfully added!")
|
||||
|
||||
# Pentru RealDebrid/alte servicii care returnează un singur link pentru tot
|
||||
else:
|
||||
downloads = self.aria2.add(url, options={"header": header, "dir": save_path, "out": out})
|
||||
logger.info(f"Single URL download: {url}")
|
||||
options = {
|
||||
"dir": save_path
|
||||
}
|
||||
if header:
|
||||
if isinstance(header, list):
|
||||
options["header"] = header
|
||||
else:
|
||||
options["header"] = [header]
|
||||
if out:
|
||||
options["out"] = out
|
||||
|
||||
self.download = downloads[0]
|
||||
try:
|
||||
download = self.aria2.add_uris([url], options=options)
|
||||
self.download = download
|
||||
self.downloads = [self.download]
|
||||
logger.info(f"Single download added successfully: {self.download.gid}")
|
||||
except Exception as e:
|
||||
logger.error(f"Error adding single download: {str(e)}")
|
||||
|
||||
def pause_download(self):
|
||||
if self.download:
|
||||
self.aria2.pause([self.download])
|
||||
try:
|
||||
for download in self.downloads:
|
||||
download.pause()
|
||||
except Exception as e:
|
||||
logger.error(f"Error pausing downloads: {str(e)}")
|
||||
|
||||
def cancel_download(self):
|
||||
if self.download:
|
||||
self.aria2.remove([self.download])
|
||||
self.download = None
|
||||
try:
|
||||
for download in self.downloads:
|
||||
download.remove()
|
||||
except Exception as e:
|
||||
logger.error(f"Error canceling downloads: {str(e)}")
|
||||
|
||||
def get_download_status(self):
|
||||
if self.download == None:
|
||||
try:
|
||||
if not self.downloads:
|
||||
return None
|
||||
|
||||
total_size = 0
|
||||
downloaded = 0
|
||||
download_speed = 0
|
||||
active_downloads = []
|
||||
|
||||
for download in self.downloads:
|
||||
try:
|
||||
download.update()
|
||||
if download.is_active:
|
||||
active_downloads.append(download)
|
||||
total_size += download.total_length
|
||||
downloaded += download.completed_length
|
||||
download_speed += download.download_speed
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating download status for {download.gid}: {str(e)}")
|
||||
|
||||
if not active_downloads:
|
||||
return None
|
||||
|
||||
# Folosim primul download pentru numele folderului
|
||||
folder_path = os.path.dirname(active_downloads[0].files[0].path)
|
||||
folder_name = os.path.basename(folder_path)
|
||||
|
||||
return {
|
||||
"progress": downloaded / total_size if total_size > 0 else 0,
|
||||
"numPeers": 0, # nu este relevant pentru HTTP
|
||||
"numSeeds": 0, # nu este relevant pentru HTTP
|
||||
"downloadSpeed": download_speed,
|
||||
"bytesDownloaded": downloaded,
|
||||
"fileSize": total_size,
|
||||
"folderName": folder_name,
|
||||
"status": "downloading"
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting download status: {str(e)}")
|
||||
return None
|
||||
|
||||
download = self.aria2.get_download(self.download.gid)
|
||||
|
||||
response = {
|
||||
'folderName': download.name,
|
||||
'fileSize': download.total_length,
|
||||
'progress': download.completed_length / download.total_length if download.total_length else 0,
|
||||
'downloadSpeed': download.download_speed,
|
||||
'numPeers': 0,
|
||||
'numSeeds': 0,
|
||||
'status': download.status,
|
||||
'bytesDownloaded': download.completed_length,
|
||||
}
|
||||
|
||||
return response
|
||||
|
|
|
@ -23,19 +23,27 @@ torrent_session = lt.session({'listen_interfaces': '0.0.0.0:{port}'.format(port=
|
|||
if start_download_payload:
|
||||
initial_download = json.loads(urllib.parse.unquote(start_download_payload))
|
||||
downloading_game_id = initial_download['game_id']
|
||||
url = initial_download['url']
|
||||
|
||||
if initial_download['url'].startswith('magnet'):
|
||||
# Verificăm dacă avem un URL de tip magnet (fie direct, fie primul dintr-o listă)
|
||||
is_magnet = False
|
||||
if isinstance(url, str):
|
||||
is_magnet = url.startswith('magnet')
|
||||
elif isinstance(url, list) and url:
|
||||
is_magnet = False # Pentru AllDebrid, chiar dacă vine dintr-un magnet, primim HTTP links
|
||||
|
||||
if is_magnet:
|
||||
torrent_downloader = TorrentDownloader(torrent_session)
|
||||
downloads[initial_download['game_id']] = torrent_downloader
|
||||
try:
|
||||
torrent_downloader.start_download(initial_download['url'], initial_download['save_path'])
|
||||
torrent_downloader.start_download(url, initial_download['save_path'])
|
||||
except Exception as e:
|
||||
print("Error starting torrent download", e)
|
||||
else:
|
||||
http_downloader = HttpDownloader()
|
||||
downloads[initial_download['game_id']] = http_downloader
|
||||
try:
|
||||
http_downloader.start_download(initial_download['url'], initial_download['save_path'], initial_download.get('header'), initial_download.get("out"))
|
||||
http_downloader.start_download(url, initial_download['save_path'], initial_download.get('header'), initial_download.get("out"))
|
||||
except Exception as e:
|
||||
print("Error starting http download", e)
|
||||
|
||||
|
@ -135,10 +143,18 @@ def action():
|
|||
|
||||
if action == 'start':
|
||||
url = data.get('url')
|
||||
print(f"Starting download with URL: {url}")
|
||||
|
||||
existing_downloader = downloads.get(game_id)
|
||||
|
||||
if url.startswith('magnet'):
|
||||
# Verificăm dacă avem un URL de tip magnet (fie direct, fie primul dintr-o listă)
|
||||
is_magnet = False
|
||||
if isinstance(url, str):
|
||||
is_magnet = url.startswith('magnet')
|
||||
elif isinstance(url, list) and url:
|
||||
is_magnet = False # Pentru AllDebrid, chiar dacă vine dintr-un magnet, primim HTTP links
|
||||
|
||||
if is_magnet:
|
||||
if existing_downloader and isinstance(existing_downloader, TorrentDownloader):
|
||||
existing_downloader.start_download(url, data['save_path'])
|
||||
else:
|
||||
|
@ -172,7 +188,6 @@ def action():
|
|||
downloader = downloads.get(game_id)
|
||||
if downloader:
|
||||
downloader.cancel_download()
|
||||
|
||||
else:
|
||||
return jsonify({"error": "Invalid action"}), 400
|
||||
|
||||
|
|
|
@ -2,6 +2,31 @@ import axios, { AxiosInstance } from "axios";
|
|||
import type { AllDebridUser } from "@types";
|
||||
import { logger } from "@main/services";
|
||||
|
||||
interface AllDebridMagnetStatus {
|
||||
id: number;
|
||||
filename: string;
|
||||
size: number;
|
||||
status: string;
|
||||
statusCode: number;
|
||||
downloaded: number;
|
||||
uploaded: number;
|
||||
seeders: number;
|
||||
downloadSpeed: number;
|
||||
uploadSpeed: number;
|
||||
uploadDate: number;
|
||||
completionDate: number;
|
||||
links: Array<{
|
||||
link: string;
|
||||
filename: string;
|
||||
size: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface AllDebridError {
|
||||
code: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export class AllDebridClient {
|
||||
private static instance: AxiosInstance;
|
||||
private static readonly baseURL = "https://api.alldebrid.com/v4";
|
||||
|
@ -9,11 +34,11 @@ export class AllDebridClient {
|
|||
static authorize(apiKey: string) {
|
||||
logger.info("[AllDebrid] Authorizing with key:", apiKey ? "***" : "empty");
|
||||
this.instance = axios.create({
|
||||
baseURL: this.baseURL,
|
||||
params: {
|
||||
agent: "hydra",
|
||||
apikey: apiKey
|
||||
}
|
||||
baseURL: this.baseURL,
|
||||
params: {
|
||||
agent: "hydra",
|
||||
apikey: apiKey
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -22,10 +47,7 @@ export class AllDebridClient {
|
|||
const response = await this.instance.get<{
|
||||
status: string;
|
||||
data?: { user: AllDebridUser };
|
||||
error?: {
|
||||
code: string;
|
||||
message: string;
|
||||
};
|
||||
error?: AllDebridError;
|
||||
}>("/user");
|
||||
|
||||
logger.info("[AllDebrid] API Response:", response.data);
|
||||
|
@ -63,4 +85,175 @@ export class AllDebridClient {
|
|||
return { error_code: "alldebrid_network_error" };
|
||||
}
|
||||
}
|
||||
|
||||
private static async uploadMagnet(magnet: string) {
|
||||
try {
|
||||
logger.info("[AllDebrid] Uploading magnet with params:", { magnet });
|
||||
|
||||
const response = await this.instance.get("/magnet/upload", {
|
||||
params: {
|
||||
magnets: [magnet]
|
||||
}
|
||||
});
|
||||
|
||||
logger.info("[AllDebrid] Upload Magnet Raw Response:", JSON.stringify(response.data, null, 2));
|
||||
|
||||
if (response.data.status === "error") {
|
||||
throw new Error(response.data.error?.message || "Unknown error");
|
||||
}
|
||||
|
||||
const magnetInfo = response.data.data.magnets[0];
|
||||
logger.info("[AllDebrid] Magnet Info:", JSON.stringify(magnetInfo, null, 2));
|
||||
|
||||
if (magnetInfo.error) {
|
||||
throw new Error(magnetInfo.error.message);
|
||||
}
|
||||
|
||||
return magnetInfo.id;
|
||||
} catch (error: any) {
|
||||
logger.error("[AllDebrid] Upload Magnet Error:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private static async checkMagnetStatus(magnetId: number): Promise<AllDebridMagnetStatus> {
|
||||
try {
|
||||
logger.info("[AllDebrid] Checking magnet status for ID:", magnetId);
|
||||
|
||||
const response = await this.instance.get(`/magnet/status`, {
|
||||
params: {
|
||||
id: magnetId
|
||||
}
|
||||
});
|
||||
|
||||
logger.info("[AllDebrid] Check Magnet Status Raw Response:", JSON.stringify(response.data, null, 2));
|
||||
|
||||
if (!response.data) {
|
||||
throw new Error("No response data received");
|
||||
}
|
||||
|
||||
if (response.data.status === "error") {
|
||||
throw new Error(response.data.error?.message || "Unknown error");
|
||||
}
|
||||
|
||||
// Verificăm noua structură a răspunsului
|
||||
const magnetData = response.data.data?.magnets;
|
||||
if (!magnetData || typeof magnetData !== 'object') {
|
||||
logger.error("[AllDebrid] Invalid response structure:", JSON.stringify(response.data, null, 2));
|
||||
throw new Error("Invalid magnet status response format");
|
||||
}
|
||||
|
||||
// Convertim răspunsul în formatul așteptat
|
||||
const magnetStatus: AllDebridMagnetStatus = {
|
||||
id: magnetData.id,
|
||||
filename: magnetData.filename,
|
||||
size: magnetData.size,
|
||||
status: magnetData.status,
|
||||
statusCode: magnetData.statusCode,
|
||||
downloaded: magnetData.downloaded,
|
||||
uploaded: magnetData.uploaded,
|
||||
seeders: magnetData.seeders,
|
||||
downloadSpeed: magnetData.downloadSpeed,
|
||||
uploadSpeed: magnetData.uploadSpeed,
|
||||
uploadDate: magnetData.uploadDate,
|
||||
completionDate: magnetData.completionDate,
|
||||
links: magnetData.links.map(link => ({
|
||||
link: link.link,
|
||||
filename: link.filename,
|
||||
size: link.size
|
||||
}))
|
||||
};
|
||||
|
||||
logger.info("[AllDebrid] Magnet Status:", JSON.stringify(magnetStatus, null, 2));
|
||||
|
||||
return magnetStatus;
|
||||
} catch (error: any) {
|
||||
logger.error("[AllDebrid] Check Magnet Status Error:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private static async unlockLink(link: string) {
|
||||
try {
|
||||
const response = await this.instance.get<{
|
||||
status: string;
|
||||
data?: { link: string };
|
||||
error?: AllDebridError;
|
||||
}>("/link/unlock", {
|
||||
params: {
|
||||
link
|
||||
}
|
||||
});
|
||||
|
||||
if (response.data.status === "error") {
|
||||
throw new Error(response.data.error?.message || "Unknown error");
|
||||
}
|
||||
|
||||
const unlockedLink = response.data.data?.link;
|
||||
if (!unlockedLink) {
|
||||
throw new Error("No download link received from AllDebrid");
|
||||
}
|
||||
|
||||
return unlockedLink;
|
||||
} catch (error: any) {
|
||||
logger.error("[AllDebrid] Unlock Link Error:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public static async getDownloadUrls(uri: string): Promise<string[]> {
|
||||
try {
|
||||
logger.info("[AllDebrid] Getting download URLs for URI:", uri);
|
||||
|
||||
if (uri.startsWith("magnet:")) {
|
||||
logger.info("[AllDebrid] Detected magnet link, uploading...");
|
||||
// 1. Upload magnet
|
||||
const magnetId = await this.uploadMagnet(uri);
|
||||
logger.info("[AllDebrid] Magnet uploaded, ID:", magnetId);
|
||||
|
||||
// 2. Verificăm statusul până când avem link-uri
|
||||
let retries = 0;
|
||||
let magnetStatus: AllDebridMagnetStatus;
|
||||
|
||||
do {
|
||||
magnetStatus = await this.checkMagnetStatus(magnetId);
|
||||
logger.info("[AllDebrid] Magnet status:", magnetStatus.status, "statusCode:", magnetStatus.statusCode);
|
||||
|
||||
if (magnetStatus.statusCode === 4) { // Ready
|
||||
// Deblocăm fiecare link în parte și aruncăm eroare dacă oricare eșuează
|
||||
const unlockedLinks = await Promise.all(
|
||||
magnetStatus.links.map(async link => {
|
||||
try {
|
||||
const unlockedLink = await this.unlockLink(link.link);
|
||||
logger.info("[AllDebrid] Successfully unlocked link:", unlockedLink);
|
||||
return unlockedLink;
|
||||
} catch (error) {
|
||||
logger.error("[AllDebrid] Failed to unlock link:", link.link, error);
|
||||
throw new Error("Failed to unlock all links");
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
logger.info("[AllDebrid] Got unlocked download links:", unlockedLinks);
|
||||
return unlockedLinks;
|
||||
}
|
||||
|
||||
if (retries++ > 30) { // Maximum 30 de încercări
|
||||
throw new Error("Timeout waiting for magnet to be ready");
|
||||
}
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000)); // Așteptăm 2 secunde între verificări
|
||||
} while (true);
|
||||
} else {
|
||||
logger.info("[AllDebrid] Regular link, unlocking...");
|
||||
// Pentru link-uri normale, doar debridam link-ul
|
||||
const downloadUrl = await this.unlockLink(uri);
|
||||
logger.info("[AllDebrid] Got unlocked download URL:", downloadUrl);
|
||||
return [downloadUrl];
|
||||
}
|
||||
} catch (error: any) {
|
||||
logger.error("[AllDebrid] Get Download URLs Error:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ import { logger } from "../logger";
|
|||
import { db, downloadsSublevel, gamesSublevel, levelKeys } from "@main/level";
|
||||
import { sortBy } from "lodash-es";
|
||||
import { TorBoxClient } from "./torbox";
|
||||
import { AllDebridClient } from "./all-debrid";
|
||||
import { spawn } from "child_process";
|
||||
|
||||
export class DownloadManager {
|
||||
private static downloadingGameId: string | null = null;
|
||||
|
@ -333,6 +335,18 @@ export class DownloadManager {
|
|||
save_path: download.downloadPath,
|
||||
};
|
||||
}
|
||||
case Downloader.AllDebrid: {
|
||||
const downloadUrls = await AllDebridClient.getDownloadUrls(download.uri);
|
||||
|
||||
if (!downloadUrls.length) throw new Error(DownloadError.NotCachedInAllDebrid);
|
||||
|
||||
return {
|
||||
action: "start",
|
||||
game_id: downloadId,
|
||||
url: downloadUrls,
|
||||
save_path: download.downloadPath,
|
||||
};
|
||||
}
|
||||
case Downloader.TorBox: {
|
||||
const { name, url } = await TorBoxClient.getDownloadInfo(download.uri);
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ import crypto from "node:crypto";
|
|||
import { pythonRpcLogger } from "./logger";
|
||||
import { Readable } from "node:stream";
|
||||
import { app, dialog } from "electron";
|
||||
import { db, levelKeys } from "@main/level";
|
||||
import type { UserPreferences } from "@types";
|
||||
|
||||
interface GamePayload {
|
||||
game_id: string;
|
||||
|
@ -42,7 +44,7 @@ export class PythonRPC {
|
|||
readable.on("data", pythonRpcLogger.log);
|
||||
}
|
||||
|
||||
public static spawn(
|
||||
public static async spawn(
|
||||
initialDownload?: GamePayload,
|
||||
initialSeeding?: GamePayload[]
|
||||
) {
|
||||
|
@ -54,6 +56,15 @@ export class PythonRPC {
|
|||
initialSeeding ? JSON.stringify(initialSeeding) : "",
|
||||
];
|
||||
|
||||
const userPreferences = await db.get<string, UserPreferences | null>(levelKeys.userPreferences, {
|
||||
valueEncoding: "json",
|
||||
});
|
||||
|
||||
const env = {
|
||||
...process.env,
|
||||
ALLDEBRID_API_KEY: userPreferences?.allDebridApiKey || ""
|
||||
};
|
||||
|
||||
if (app.isPackaged) {
|
||||
const binaryName = binaryNameByPlatform[process.platform]!;
|
||||
const binaryPath = path.join(
|
||||
|
@ -74,6 +85,7 @@ export class PythonRPC {
|
|||
const childProcess = cp.spawn(binaryPath, commonArgs, {
|
||||
windowsHide: true,
|
||||
stdio: ["inherit", "inherit"],
|
||||
env
|
||||
});
|
||||
|
||||
this.logStderr(childProcess.stderr);
|
||||
|
@ -90,6 +102,7 @@ export class PythonRPC {
|
|||
|
||||
const childProcess = cp.spawn("python3", [scriptPath, ...commonArgs], {
|
||||
stdio: ["inherit", "inherit"],
|
||||
env
|
||||
});
|
||||
|
||||
this.logStderr(childProcess.stderr);
|
||||
|
|
|
@ -11,6 +11,7 @@ export const DOWNLOADER_NAME = {
|
|||
[Downloader.Datanodes]: "Datanodes",
|
||||
[Downloader.Mediafire]: "Mediafire",
|
||||
[Downloader.TorBox]: "TorBox",
|
||||
[Downloader.AllDebrid]: "All-Debrid",
|
||||
};
|
||||
|
||||
export const MAX_MINUTES_TO_SHOW_IN_PLAYTIME = 120;
|
||||
|
|
13
src/renderer/src/constants/downloader.ts
Normal file
13
src/renderer/src/constants/downloader.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { Downloader } from "@shared";
|
||||
|
||||
export const DOWNLOADER_NAME: Record<Downloader, string> = {
|
||||
[Downloader.Gofile]: "Gofile",
|
||||
[Downloader.PixelDrain]: "PixelDrain",
|
||||
[Downloader.Qiwi]: "Qiwi",
|
||||
[Downloader.Datanodes]: "Datanodes",
|
||||
[Downloader.Mediafire]: "Mediafire",
|
||||
[Downloader.Torrent]: "Torrent",
|
||||
[Downloader.RealDebrid]: "Real-Debrid",
|
||||
[Downloader.AllDebrid]: "All-Debrid",
|
||||
[Downloader.TorBox]: "TorBox",
|
||||
};
|
|
@ -240,7 +240,9 @@ export function DownloadGroup({
|
|||
(download?.downloader === Downloader.RealDebrid &&
|
||||
!userPreferences?.realDebridApiToken) ||
|
||||
(download?.downloader === Downloader.TorBox &&
|
||||
!userPreferences?.torBoxApiToken);
|
||||
!userPreferences?.torBoxApiToken) ||
|
||||
(download?.downloader === Downloader.AllDebrid &&
|
||||
!userPreferences?.allDebridApiKey);
|
||||
|
||||
return [
|
||||
{
|
||||
|
|
|
@ -27,6 +27,11 @@
|
|||
|
||||
&__downloader-option {
|
||||
position: relative;
|
||||
padding: calc(globals.$spacing-unit * 1.5) calc(globals.$spacing-unit * 6);
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 150px;
|
||||
|
||||
&:only-child {
|
||||
grid-column: 1 / -1;
|
||||
|
@ -36,6 +41,8 @@
|
|||
&__downloader-icon {
|
||||
position: absolute;
|
||||
left: calc(globals.$spacing-unit * 2);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
&__path-error {
|
||||
|
|
|
@ -87,6 +87,8 @@ export function DownloadSettingsModal({
|
|||
return userPreferences?.realDebridApiToken;
|
||||
if (downloader === Downloader.TorBox)
|
||||
return userPreferences?.torBoxApiToken;
|
||||
if (downloader === Downloader.AllDebrid)
|
||||
return userPreferences?.allDebridApiKey;
|
||||
return true;
|
||||
});
|
||||
|
||||
|
@ -100,6 +102,8 @@ export function DownloadSettingsModal({
|
|||
userPreferences?.downloadsPath,
|
||||
downloaders,
|
||||
userPreferences?.realDebridApiToken,
|
||||
userPreferences?.torBoxApiToken,
|
||||
userPreferences?.allDebridApiKey,
|
||||
]);
|
||||
|
||||
const handleChooseDownloadsPath = async () => {
|
||||
|
@ -163,8 +167,10 @@ export function DownloadSettingsModal({
|
|||
selectedDownloader === downloader ? "primary" : "outline"
|
||||
}
|
||||
disabled={
|
||||
downloader === Downloader.RealDebrid &&
|
||||
!userPreferences?.realDebridApiToken
|
||||
(downloader === Downloader.RealDebrid &&
|
||||
!userPreferences?.realDebridApiToken) ||
|
||||
(downloader === Downloader.AllDebrid &&
|
||||
!userPreferences?.allDebridApiKey)
|
||||
}
|
||||
onClick={() => setSelectedDownloader(downloader)}
|
||||
>
|
||||
|
|
|
@ -7,6 +7,7 @@ export enum Downloader {
|
|||
Datanodes,
|
||||
Mediafire,
|
||||
TorBox,
|
||||
AllDebrid,
|
||||
}
|
||||
|
||||
export enum DownloadSourceStatus {
|
||||
|
@ -54,6 +55,7 @@ export enum AuthPage {
|
|||
export enum DownloadError {
|
||||
NotCachedInRealDebrid = "download_error_not_cached_in_real_debrid",
|
||||
NotCachedInTorbox = "download_error_not_cached_in_torbox",
|
||||
NotCachedInAllDebrid = "download_error_not_cached_in_alldebrid",
|
||||
GofileQuotaExceeded = "download_error_gofile_quota_exceeded",
|
||||
RealDebridAccountNotAuthorized = "download_error_real_debrid_account_not_authorized",
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ export const getDownloadersForUri = (uri: string) => {
|
|||
return [Downloader.RealDebrid];
|
||||
|
||||
if (uri.startsWith("magnet:")) {
|
||||
return [Downloader.Torrent, Downloader.TorBox, Downloader.RealDebrid];
|
||||
return [Downloader.Torrent, Downloader.TorBox, Downloader.RealDebrid, Downloader.AllDebrid];
|
||||
}
|
||||
|
||||
return [];
|
||||
|
|
|
@ -182,3 +182,30 @@ export interface AllDebridUser {
|
|||
isPremium: boolean;
|
||||
premiumUntil: string;
|
||||
}
|
||||
|
||||
export enum Downloader {
|
||||
Gofile = "gofile",
|
||||
PixelDrain = "pixeldrain",
|
||||
Qiwi = "qiwi",
|
||||
Datanodes = "datanodes",
|
||||
Mediafire = "mediafire",
|
||||
Torrent = "torrent",
|
||||
RealDebrid = "realdebrid",
|
||||
AllDebrid = "alldebrid",
|
||||
TorBox = "torbox",
|
||||
}
|
||||
|
||||
export enum DownloadError {
|
||||
NotCachedInRealDebrid = "not_cached_in_realdebrid",
|
||||
NotCachedInAllDebrid = "not_cached_in_alldebrid",
|
||||
// ... alte erori existente
|
||||
}
|
||||
|
||||
export interface GamePayload {
|
||||
action: string;
|
||||
game_id: string;
|
||||
url: string | string[]; // Modificăm pentru a accepta și array de URL-uri
|
||||
save_path: string;
|
||||
header?: string;
|
||||
out?: string;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue