From 519ced5e88c3e51d7c5cc5d2338aabb1b1a7bee2 Mon Sep 17 00:00:00 2001 From: awalol Date: Sun, 15 Jun 2025 04:01:52 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=E5=85=A8=E9=83=A8=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DownloadAll.tsx | 53 ++++++++++++++++++++++++++++++++++ src/tabs/MainTab.tsx | 4 +++ 2 files changed, 57 insertions(+) create mode 100644 src/components/DownloadAll.tsx diff --git a/src/components/DownloadAll.tsx b/src/components/DownloadAll.tsx new file mode 100644 index 0000000..814df4f --- /dev/null +++ b/src/components/DownloadAll.tsx @@ -0,0 +1,53 @@ +import { DecryptedAudioFile, selectFiles } from '~/features/file-listing/fileListingSlice'; +import { useAppSelector } from '~/hooks'; + +export function DownloadAll() { + const files = useAppSelector(selectFiles); + const filesLength = Object.keys(files).length; + const onClickDownloadAll = async () => { + let dir: FileSystemDirectoryHandle | undefined; + let success = 0; + try { + dir = await window.showDirectoryPicker(); + } catch (e) { + console.error(e); + } + for (const [_, file] of Object.entries(files)) { + try { + if (dir) { + await DownloadNew(dir, file); + } else { + await DownloadOld(file); + } + success++; + } catch (e) { + console.error('下载失败: ' + file.fileName, e); + } + } + alert('下载成功: ' + success + ',下载失败: ' + (filesLength - success)); + }; + + return ( + + ); +} + +async function DownloadNew(dir: FileSystemDirectoryHandle, file: DecryptedAudioFile) { + const response = await fetch(file.decrypted); + const blob = await response.blob(); + const fileHandle = await dir.getFileHandle(file.cleanName + '.' + file.ext, { create: true }); + const writable = await fileHandle.createWritable(); + await writable.write(blob); + await writable.close(); +} + +async function DownloadOld(file: DecryptedAudioFile) { + const a = document.createElement('a'); + a.href = file.decrypted; + a.download = file.cleanName + '.' + file.ext; + document.body.append(a); + a.click(); + a.remove(); +} diff --git a/src/tabs/MainTab.tsx b/src/tabs/MainTab.tsx index 3491ce1..0f85087 100644 --- a/src/tabs/MainTab.tsx +++ b/src/tabs/MainTab.tsx @@ -1,5 +1,6 @@ import { RiErrorWarningLine } from 'react-icons/ri'; import { SelectFile } from '../components/SelectFile'; +import { DownloadAll } from '~/components/DownloadAll'; import { FileListing } from '~/features/file-listing/FileListing'; import { useAppDispatch, useAppSelector } from '~/hooks.ts'; @@ -39,6 +40,9 @@ export function MainTab() {
+
+ +
); From fa7292f65bd057a52bee1bac73a08d58fe700a1c Mon Sep 17 00:00:00 2001 From: awalol Date: Sun, 15 Jun 2025 14:05:11 +0800 Subject: [PATCH 2/3] =?UTF-8?q?ui:=20=E5=AE=8C=E5=96=84=E5=85=A8=E9=83=A8?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E6=8C=89=E9=92=AE=E7=9A=84=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E5=92=8C=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AppRoot.tsx | 2 ++ src/components/DownloadAll.tsx | 12 ++++++++++-- src/tabs/MainTab.tsx | 4 ---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/components/AppRoot.tsx b/src/components/AppRoot.tsx index dbee96a..696c46d 100644 --- a/src/components/AppRoot.tsx +++ b/src/components/AppRoot.tsx @@ -15,6 +15,7 @@ import { Bounce, ToastContainer } from 'react-toastify'; import { SettingsHome } from '~/features/settings/SettingsHome'; import { FAQ_PAGES } from '~/faq/FAQPages'; import { FaqHome } from '~/faq/FaqHome'; +import { DownloadAll } from '~/components/DownloadAll.tsx'; // Private to this file only. const store = setupStore(); @@ -71,6 +72,7 @@ export function AppRoot() { transition={Bounce} /> +