From 0a51188982e6714ae622c2cab65909377bd22dbb Mon Sep 17 00:00:00 2001 From: Maya Date: Fri, 21 Nov 2025 21:48:41 +0300 Subject: [PATCH] feat: AIO archive conversion --- messages/en.json | 5 ++- messages/ko.json | 2 +- messages/zh-Hans.json | 2 +- messages/zh-Hant.json | 2 +- .../functional/FormatDropdown.svelte | 42 ++++++++++++++++++- src/lib/store/index.svelte.ts | 10 ++--- src/lib/types/file.svelte.ts | 2 +- 7 files changed, 53 insertions(+), 12 deletions(-) diff --git a/messages/en.json b/messages/en.json index 7fac2f8..3f4b16e 100644 --- a/messages/en.json +++ b/messages/en.json @@ -47,8 +47,9 @@ } }, "convert": { - "zip_file": { - "extracting": "Detected ZIP archive: {filename}", + "archive_file": { + "extract": "Extract archive", + "extracting": "Detected archive: {filename}", "extracted": "Extracted {extract_count} files from {filename}. {ignore_count} items were ignored.", "detected": "Detected {type} files in {filename}.", "audio": "audio", diff --git a/messages/ko.json b/messages/ko.json index 8b42565..1638323 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -47,7 +47,7 @@ } }, "convert": { - "zip_file": { + "archive_file": { "extracting": "ZIP파일 감지됨: {filename}", "extracted": "{filename}압축 파일에서 {extract_count}개의 파일을 풀었습니다. {ignore_count}개 항목은 무시되었습니다.", "extract_error": "{filename}압축 파일 풀던 중 오류 발생: {error}" diff --git a/messages/zh-Hans.json b/messages/zh-Hans.json index 86a505b..eb864e6 100644 --- a/messages/zh-Hans.json +++ b/messages/zh-Hans.json @@ -47,7 +47,7 @@ } }, "convert": { - "zip_file": { + "archive_file": { "extracting": "检测到 ZIP 压缩包:{filename}", "extracted": "从 {filename} 中提取了 {extract_count} 个文件。{ignore_count} 个项目被忽略。", "extract_error": "提取 {filename} 时出错:{error}" diff --git a/messages/zh-Hant.json b/messages/zh-Hant.json index 7410b69..5b15556 100644 --- a/messages/zh-Hant.json +++ b/messages/zh-Hant.json @@ -47,7 +47,7 @@ } }, "convert": { - "zip_file": { + "archive_file": { "extracting": "偵測到 ZIP 壓縮檔:{filename}", "extracted": "從 {filename} 中提取了 {extract_count} 個檔案。{ignore_count} 個項目被忽略。", "extract_error": "提取 {filename} 時出錯:{error}" diff --git a/src/lib/components/functional/FormatDropdown.svelte b/src/lib/components/functional/FormatDropdown.svelte index f816985..276fbef 100644 --- a/src/lib/components/functional/FormatDropdown.svelte +++ b/src/lib/components/functional/FormatDropdown.svelte @@ -7,7 +7,8 @@ import { ChevronDown, SearchIcon } from "lucide-svelte"; import { onMount } from "svelte"; import { quintOut } from "svelte/easing"; - import type { VertFile } from "$lib/types"; + import { VertFile } from "$lib/types"; + import { log, error } from "$lib/util/logger"; type Props = { categories: Categories; @@ -276,6 +277,33 @@ }, 0); // let dropdown open first }; + const extract = async () => { + // extract all files in zip, then add all extracted files to files store + if (!file) return; + const { extractZip } = await import("$lib/util/zip"); + const extractedFiles = await extractZip(file.file); + + if (!Array.isArray(extractedFiles) || extractedFiles.length === 0) + return; + + const newFiles = extractedFiles + .map(({ filename, data }) => { + try { + const f = new File([new Uint8Array(data)], filename, { + type: "application/octet-stream", + }); + const ext = filename.split(".").pop() ?? ""; + return new VertFile(f, ext); + } catch (err) { + return null; + } + }) + .filter(Boolean); + + files.files = files.files.filter((f) => f !== file); + newFiles.forEach((f) => files.add(f)); + }; + onMount(() => { const handleClickOutside = (e: MouseEvent) => { if (dropdown && !dropdown.contains(e.target as Node)) { @@ -439,6 +467,18 @@ {/if} + + + {#if file?.name.toLowerCase().endsWith(".zip")} +
+ +
+ {/if} {/if} diff --git a/src/lib/store/index.svelte.ts b/src/lib/store/index.svelte.ts index 8445023..a5f7e64 100644 --- a/src/lib/store/index.svelte.ts +++ b/src/lib/store/index.svelte.ts @@ -146,7 +146,7 @@ class Files { log(["files"], `extracting zip file: ${file.name}`); ToastManager.add({ type: "info", - message: m["convert.zip_file.extracting"]({ + message: m["convert.archive_file.extracting"]({ filename: file.name, }), }); @@ -208,8 +208,8 @@ class Files { ToastManager.add({ type: "success", - message: m["convert.zip_file.detected"]({ - type: m[`convert.zip_file.${type}`](), + message: m["convert.archive_file.detected"]({ + type: m[`convert.archive_file.${type}`](), filename: file.name, }), }); @@ -225,7 +225,7 @@ class Files { ToastManager.add({ type: "success", - message: m["convert.zip_file.extracted"]({ + message: m["convert.archive_file.extracted"]({ filename: file.name, extract_count: entries.length, ignore_count: 0, @@ -258,7 +258,7 @@ class Files { error(["files"], `error extracting zip file: ${err}`); ToastManager.add({ type: "error", - message: m["convert.zip_file.extract_error"]({ + message: m["convert.archive_file.extract_error"]({ filename: file.name, error: String(err), }), diff --git a/src/lib/types/file.svelte.ts b/src/lib/types/file.svelte.ts index 4c9c320..e928493 100644 --- a/src/lib/types/file.svelte.ts +++ b/src/lib/types/file.svelte.ts @@ -86,7 +86,7 @@ export class VertFile { `${file.name.split(".").slice(0, -1).join(".")}.${ext?.toLowerCase()}`, ); this.file = newFile; - this.to = to; + this.to = to.startsWith(".") ? to : `.${to}`; this.converters = converters.filter((c) => c.formatStrings().includes(this.from), );