mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-11-04 08:10:28 +09:00
리다이렉트 경로 처리, 파일 정보 변환, 상태 표시 UI 등 중복된 코드를 통합하고 모듈 간 순환 의존성 및 계층 위반 해소
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9119c21881
commit
5b8621e524
96 files changed
+452
-548
No files matched your search
@@ -0,0 +1,5 @@
|
||||
// Chromium can't decode HEIC images, so they are converted to be displayed
|
||||
export const convertHeic = async (blob: Blob, toType: "image/png" | "image/jpeg") => {
|
||||
const { default: heic2any } = await import("heic2any");
|
||||
return (await heic2any({ blob, toType })) as Blob;
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
import { convertHeic } from "./heic.ts";
|
||||
|
||||
const scaleSize = (width: number, height: number, targetSize: number) => {
|
||||
if (width <= targetSize || height <= targetSize) {
|
||||
return { width, height };
|
||||
@@ -111,11 +113,6 @@ const generateVideoThumbnail = (videoUrl: string, time = 0) => {
|
||||
});
|
||||
};
|
||||
|
||||
const convertHeicToPng = async (blob: Blob) => {
|
||||
const { default: heic2any } = await import("heic2any");
|
||||
return (await heic2any({ blob, toType: "image/png" })) as Blob;
|
||||
};
|
||||
|
||||
// Generates a thumbnail of the image or video at the URL. Returns `null` if not supported.
|
||||
export const generateThumbnailFromUrl = async (url: string, contentType: string) => {
|
||||
try {
|
||||
@@ -125,8 +122,8 @@ export const generateThumbnailFromUrl = async (url: string, contentType: string)
|
||||
} catch {
|
||||
if (contentType !== "image/heic") return null;
|
||||
|
||||
// Chromium can't decode HEIC images
|
||||
const png = URL.createObjectURL(await convertHeicToPng(await (await fetch(url)).blob()));
|
||||
const blob = await (await fetch(url)).blob();
|
||||
const png = URL.createObjectURL(await convertHeic(blob, "image/png"));
|
||||
try {
|
||||
return await generateImageThumbnail(png);
|
||||
} finally {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { LRUCache } from "lru-cache";
|
||||
import { handleDownloadProgress } from "#lib/client/transfer/download.svelte.ts";
|
||||
import {
|
||||
DECRYPTED_FILE_URL_PREFIX,
|
||||
MAX_PREPARED_FILES,
|
||||
type FileMetadata,
|
||||
type ServiceWorkerMessage,
|
||||
type ServiceWorkerResponse,
|
||||
@@ -10,7 +12,7 @@ const PREPARE_TIMEOUT_MS = 5000;
|
||||
|
||||
// The service worker may be terminated at any time, losing its in-memory metadata.
|
||||
// Keep a copy here so that it can be re-requested on demand.
|
||||
const preparedFiles = new Map<number, FileMetadata>();
|
||||
const preparedFiles = new LRUCache<number, FileMetadata>({ max: MAX_PREPARED_FILES });
|
||||
let isListening = false;
|
||||
|
||||
export const listenForServiceWorkerMessages = () => {
|
||||
|
||||
@@ -20,43 +20,43 @@ import { getChunkCount } from "#lib/shared/format/index.ts";
|
||||
import { Scheduler } from "#lib/utils/index.ts";
|
||||
import { trpc } from "#trpc/client.ts";
|
||||
|
||||
const LIVE_STATUSES = [
|
||||
"queued",
|
||||
"encryption-pending",
|
||||
"encrypting",
|
||||
"upload-pending",
|
||||
"uploading",
|
||||
] as const;
|
||||
|
||||
type LiveStatus = (typeof LIVE_STATUSES)[number];
|
||||
|
||||
export interface FileUploadState {
|
||||
id: string;
|
||||
name: string;
|
||||
parentId: DirectoryId;
|
||||
status:
|
||||
| "queued"
|
||||
| "encryption-pending"
|
||||
| "encrypting"
|
||||
| "upload-pending"
|
||||
| "uploading"
|
||||
| "uploaded"
|
||||
| "canceled"
|
||||
| "error";
|
||||
status: LiveStatus | "uploaded" | "canceled" | "error";
|
||||
progress?: number;
|
||||
rate?: number;
|
||||
estimated?: number;
|
||||
}
|
||||
|
||||
export type LiveFileUploadState = FileUploadState & {
|
||||
status: "queued" | "encryption-pending" | "encrypting" | "upload-pending" | "uploading";
|
||||
};
|
||||
export type LiveFileUploadState = FileUploadState & { status: LiveStatus };
|
||||
|
||||
const scheduler = new Scheduler<{ fileId: number; thumbnailBuffer?: ArrayBuffer } | undefined>();
|
||||
let uploadingFiles: FileUploadState[] = $state([]);
|
||||
|
||||
const isFileUploading = (status: FileUploadState["status"]) =>
|
||||
["queued", "encryption-pending", "encrypting", "upload-pending", "uploading"].includes(status);
|
||||
const isFileUploading = (file: FileUploadState): file is LiveFileUploadState => {
|
||||
return (LIVE_STATUSES as readonly string[]).includes(file.status);
|
||||
};
|
||||
|
||||
export const getUploadingFiles = (parentId?: DirectoryId) => {
|
||||
return uploadingFiles.filter(
|
||||
(file) =>
|
||||
(parentId === undefined || file.parentId === parentId) && isFileUploading(file.status),
|
||||
);
|
||||
return uploadingFiles
|
||||
.filter(isFileUploading)
|
||||
.filter((file) => parentId === undefined || file.parentId === parentId);
|
||||
};
|
||||
|
||||
export const clearUploadedFiles = () => {
|
||||
uploadingFiles = uploadingFiles.filter((file) => isFileUploading(file.status));
|
||||
uploadingFiles = uploadingFiles.filter(isFileUploading);
|
||||
};
|
||||
|
||||
const requestDuplicateFileScan = limitFunction(
|
||||
|
||||
Reference in new issue
Block a user