diff --git a/src/tribler/ui/package-lock.json b/src/tribler/ui/package-lock.json
index 86c493fd31..1db75c3130 100644
--- a/src/tribler/ui/package-lock.json
+++ b/src/tribler/ui/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "tribler-webui",
- "version": "0.1",
+ "version": "0.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "tribler-webui",
- "version": "0.1",
+ "version": "0.1.0",
"dependencies": {
"@hookform/resolvers": "^3.3.2",
"@radix-ui/react-accordion": "^1.1.2",
@@ -31,6 +31,7 @@
"i18next": "^23.11.4",
"javascript-time-ago": "^2.5.10",
"js-cookie": "^3.0.5",
+ "jszip": "^3.10.1",
"lucide-react": "^0.292.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -56,7 +57,7 @@
"postcss": "^8.4.31",
"react-hot-toast": "^2.4.1",
"tailwindcss": "^3.3.3",
- "typescript": "^4.6.4",
+ "typescript": "^5.5.0",
"vite": "^3.1.0"
}
},
@@ -2099,6 +2100,11 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true
},
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+ },
"node_modules/cross-fetch": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
@@ -2781,6 +2787,11 @@
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
"dev": true
},
+ "node_modules/immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
+ },
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -2852,6 +2863,11 @@
"node": ">=0.12.0"
}
},
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
+ },
"node_modules/javascript-time-ago": {
"version": "2.5.10",
"resolved": "https://registry.npmjs.org/javascript-time-ago/-/javascript-time-ago-2.5.10.tgz",
@@ -2905,6 +2921,52 @@
"node": ">=6"
}
},
+ "node_modules/jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "dependencies": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
+ }
+ },
+ "node_modules/jszip/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/jszip/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/jszip/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "dependencies": {
+ "immediate": "~3.0.5"
+ }
+ },
"node_modules/lilconfig": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
@@ -3182,6 +3244,11 @@
"wrappy": "1"
}
},
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
+ },
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -3351,6 +3418,11 @@
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -3713,6 +3785,11 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
+ },
"node_modules/simple-update-notifier": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
@@ -3932,16 +4009,16 @@
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/typescript": {
- "version": "4.9.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
- "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
+ "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
- "node": ">=4.2.0"
+ "node": ">=14.17"
}
},
"node_modules/undefsafe": {
@@ -5384,6 +5461,11 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true
},
+ "core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+ },
"cross-fetch": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
@@ -5778,6 +5860,11 @@
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
"dev": true
},
+ "immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
+ },
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -5834,6 +5921,11 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
+ },
"javascript-time-ago": {
"version": "2.5.10",
"resolved": "https://registry.npmjs.org/javascript-time-ago/-/javascript-time-ago-2.5.10.tgz",
@@ -5869,6 +5961,54 @@
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
+ "jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "requires": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "requires": {
+ "immediate": "~3.0.5"
+ }
+ },
"lilconfig": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
@@ -6065,6 +6205,11 @@
"wrappy": "1"
}
},
+ "pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
+ },
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -6154,6 +6299,11 @@
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ },
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -6360,6 +6510,11 @@
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
},
+ "setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
+ },
"simple-update-notifier": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
@@ -6530,9 +6685,9 @@
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"typescript": {
- "version": "4.9.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
- "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
+ "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true
},
"undefsafe": {
diff --git a/src/tribler/ui/package.json b/src/tribler/ui/package.json
index 52eb8f9909..45ef3f2e6c 100644
--- a/src/tribler/ui/package.json
+++ b/src/tribler/ui/package.json
@@ -32,6 +32,7 @@
"i18next": "^23.11.4",
"javascript-time-ago": "^2.5.10",
"js-cookie": "^3.0.5",
+ "jszip": "^3.10.1",
"lucide-react": "^0.292.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/src/tribler/ui/src/lib/utils.ts b/src/tribler/ui/src/lib/utils.ts
index 60b8430e2c..26c1be461b 100644
--- a/src/tribler/ui/src/lib/utils.ts
+++ b/src/tribler/ui/src/lib/utils.ts
@@ -10,8 +10,9 @@ import zh from 'javascript-time-ago/locale/zh'
import Cookies from "js-cookie";
import { useTranslation } from "react-i18next";
import { triblerService } from "@/services/tribler.service";
-import { FileTreeItem } from "@/models/file.model";
+import { FileLink, FileTreeItem } from "@/models/file.model";
import { CheckedState } from "@radix-ui/react-checkbox";
+import JSZip from "jszip";
TimeAgo.setDefaultLocale(en.locale)
TimeAgo.addLocale(en)
@@ -225,3 +226,29 @@ export const getSelectedFilesFromTree = (tree: FileTreeItem, included: boolean =
selectedFiles.push(tree.index);
return selectedFiles;
}
+
+export function downloadFile(file: FileLink) {
+ var link = document.createElement("a");
+ link.download = file.name;
+ link.href = file.uri;
+ link.click();
+}
+
+export async function downloadFilesAsZip(files: FileLink[], zipName: string) {
+ const zip = new JSZip();
+ for (let i = 0; i < files.length; i++) {
+ const response = await fetch(files[i].uri);
+ if (response.status != 200) continue;
+ const blob = await response.blob();
+
+ zip.file(files[i].name, blob);
+
+ if (i == files.length - 1) {
+ const zipData = await zip.generateAsync({ type: "blob" });
+ const link = document.createElement("a");
+ link.href = window.URL.createObjectURL(zipData);
+ link.download = zipName;
+ link.click();
+ }
+ }
+}
diff --git a/src/tribler/ui/src/models/file.model.tsx b/src/tribler/ui/src/models/file.model.tsx
index dd9aee08b7..4acc56dcc3 100644
--- a/src/tribler/ui/src/models/file.model.tsx
+++ b/src/tribler/ui/src/models/file.model.tsx
@@ -19,3 +19,8 @@ export interface FileTreeItem {
included?: CheckedState;
subRows?: FileTreeItem[];
}
+
+export interface FileLink {
+ uri: string;
+ name: string;
+}
diff --git a/src/tribler/ui/src/pages/Downloads/Actions.tsx b/src/tribler/ui/src/pages/Downloads/Actions.tsx
index e9c8c1861b..81c40ba45d 100644
--- a/src/tribler/ui/src/pages/Downloads/Actions.tsx
+++ b/src/tribler/ui/src/pages/Downloads/Actions.tsx
@@ -22,6 +22,7 @@ import { useState } from "react";
import { Label } from "@/components/ui/label";
import { useTranslation } from "react-i18next";
import { PathInput } from "@/components/path-input";
+import { downloadFile, downloadFilesAsZip } from "@/lib/utils";
export default function Actions({ selectedDownloads }: { selectedDownloads: Download[] }) {
@@ -36,10 +37,10 @@ export default function Actions({ selectedDownloads }: { selectedDownloads: Down
const response = await triblerService.resumeDownload(download.infohash);
if (response === undefined) {
toast.error(`${t("ToastErrorDownloadPlay")} ${t("ToastErrorGenNetworkErr")}`);
- } else if (isErrorDict(response)){
+ } else if (isErrorDict(response)) {
toast.error(`${t("ToastErrorDownloadPlay")} ${response.error}`);
}
- })();
+ })();
});
}
const onPause = () => {
@@ -48,10 +49,10 @@ export default function Actions({ selectedDownloads }: { selectedDownloads: Down
const response = await triblerService.stopDownload(download.infohash);
if (response === undefined) {
toast.error(`${t("ToastErrorDownloadStop")} ${t("ToastErrorGenNetworkErr")}`);
- } else if (isErrorDict(response)){
+ } else if (isErrorDict(response)) {
toast.error(`${t("ToastErrorDownloadStop")} ${response.error}`);
}
- })();
+ })();
});
}
const onRemove = (removeData: boolean) => {
@@ -60,10 +61,10 @@ export default function Actions({ selectedDownloads }: { selectedDownloads: Down
const response = await triblerService.removeDownload(download.infohash, removeData);
if (response === undefined) {
toast.error(`${t("ToastErrorDownloadRemove")} ${t("ToastErrorGenNetworkErr")}`);
- } else if (isErrorDict(response)){
+ } else if (isErrorDict(response)) {
toast.error(`${t("ToastErrorDownloadRemove")} ${response.error}`);
}
- })();
+ })();
});
setRemoveDialogOpen(false);
}
@@ -73,18 +74,20 @@ export default function Actions({ selectedDownloads }: { selectedDownloads: Down
const response = await triblerService.recheckDownload(download.infohash);
if (response === undefined) {
toast.error(`${t("ToastErrorDownloadCheck")} ${t("ToastErrorGenNetworkErr")}`);
- } else if (isErrorDict(response)){
+ } else if (isErrorDict(response)) {
toast.error(`${t("ToastErrorDownloadCheck")} ${response.error}`);
}
- })();
+ })();
});
}
const onExportTorrent = () => {
- const link = document.createElement('a');
- link.href = `/api/downloads/${selectedDownloads[0].infohash}/torrent`;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
+ const files = selectedDownloads.map((download) => ({
+ uri: `/api/downloads/${download.infohash}/torrent`,
+ name: `${download.infohash}.torrent`
+ }));
+
+ if (files.length == 1) downloadFile(files[0]);
+ else if (files.length > 1) downloadFilesAsZip(files, 'torrents.zip');
}
const onMoveDownload = () => {
if (selectedDownloads.length == 1) {
@@ -96,7 +99,7 @@ export default function Actions({ selectedDownloads }: { selectedDownloads: Down
triblerService.moveDownload(selectedDownloads[0].infohash, storageLocation).then(async (response) => {
if (response === undefined) {
toast.error(`${t("ToastErrorDownloadMove")} ${t("ToastErrorGenNetworkErr")}`);
- } else if (isErrorDict(response)){
+ } else if (isErrorDict(response)) {
toast.error(`${t("ToastErrorDownloadMove")} ${response.error}`);
}
});
@@ -108,10 +111,10 @@ export default function Actions({ selectedDownloads }: { selectedDownloads: Down
const response = await triblerService.setDownloadHops(download.infohash, hops);
if (response === undefined) {
toast.error(`${t("ToastErrorDownloadSetHops")} ${t("ToastErrorGenNetworkErr")}`);
- } else if (isErrorDict(response)){
+ } else if (isErrorDict(response)) {
toast.error(`${t("ToastErrorDownloadSetHops")} ${response.error}`);
}
- })();
+ })();
});
}
@@ -212,7 +215,7 @@ export default function Actions({ selectedDownloads }: { selectedDownloads: Down
{t('ForceRecheck')}
- onExportTorrent()} disabled={selectedDownloads.length !== 1}>
+ onExportTorrent()} disabled={selectedDownloads.length < 1}>
{t('ExportTorrent')}