mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-16 06:58:46 +00:00
썸네일을 메모리와 OPFS에 캐시하도록 개선
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
export * from "./cache";
|
||||
export * from "./download";
|
||||
export * from "./thumbnail";
|
||||
export * from "./upload";
|
||||
|
||||
29
src/lib/modules/file/thumbnail.ts
Normal file
29
src/lib/modules/file/thumbnail.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { LRUCache } from "lru-cache";
|
||||
import { readFile, writeFile, deleteFile } from "$lib/modules/opfs";
|
||||
import { getThumbnailUrl } from "$lib/modules/thumbnail";
|
||||
|
||||
const loadedThumbnails = new LRUCache<number, string>({ max: 100 });
|
||||
|
||||
export const getFileThumbnail = async (fileId: number) => {
|
||||
const thumbnail = loadedThumbnails.get(fileId);
|
||||
if (thumbnail) {
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
const thumbnailBuffer = await readFile(`/thumbnails/${fileId}`);
|
||||
if (!thumbnailBuffer) return null;
|
||||
|
||||
const thumbnailUrl = getThumbnailUrl(thumbnailBuffer);
|
||||
loadedThumbnails.set(fileId, thumbnailUrl);
|
||||
return thumbnailUrl;
|
||||
};
|
||||
|
||||
export const storeFileThumbnail = async (fileId: number, thumbnailBuffer: ArrayBuffer) => {
|
||||
await writeFile(`/thumbnails/${fileId}`, thumbnailBuffer);
|
||||
loadedThumbnails.set(fileId, getThumbnailUrl(thumbnailBuffer));
|
||||
};
|
||||
|
||||
export const deleteFileThumbnail = async (fileId: number) => {
|
||||
loadedThumbnails.delete(fileId);
|
||||
await deleteFile(`/thumbnails/${fileId}`);
|
||||
};
|
||||
@@ -130,9 +130,8 @@ const encryptFile = limitFunction(
|
||||
const lastModifiedAtEncrypted = await encryptString(file.lastModified.toString(), dataKey);
|
||||
|
||||
const thumbnail = await generateThumbnail(file, fileType);
|
||||
const thumbnailEncrypted = thumbnail
|
||||
? await encryptData(await thumbnail.arrayBuffer(), dataKey)
|
||||
: null;
|
||||
const thumbnailBuffer = await thumbnail?.arrayBuffer();
|
||||
const thumbnailEncrypted = thumbnailBuffer ? await encryptData(thumbnailBuffer, dataKey) : null;
|
||||
|
||||
status.update((value) => {
|
||||
value.status = "upload-pending";
|
||||
@@ -148,7 +147,8 @@ const encryptFile = limitFunction(
|
||||
nameEncrypted,
|
||||
createdAtEncrypted,
|
||||
lastModifiedAtEncrypted,
|
||||
thumbnailEncrypted,
|
||||
thumbnail: thumbnail &&
|
||||
thumbnailEncrypted && { plaintext: thumbnailBuffer, ...thumbnailEncrypted },
|
||||
};
|
||||
},
|
||||
{ concurrency: 4 },
|
||||
@@ -198,7 +198,9 @@ export const uploadFile = async (
|
||||
hmacSecret: HmacSecret,
|
||||
masterKey: MasterKey,
|
||||
onDuplicate: () => Promise<boolean>,
|
||||
): Promise<{ fileId: number; fileBuffer: ArrayBuffer } | undefined> => {
|
||||
): Promise<
|
||||
{ fileId: number; fileBuffer: ArrayBuffer; thumbnailBuffer?: ArrayBuffer } | undefined
|
||||
> => {
|
||||
const status = writable<FileUploadStatus>({
|
||||
name: file.name,
|
||||
parentId,
|
||||
@@ -236,7 +238,7 @@ export const uploadFile = async (
|
||||
nameEncrypted,
|
||||
createdAtEncrypted,
|
||||
lastModifiedAtEncrypted,
|
||||
thumbnailEncrypted,
|
||||
thumbnail,
|
||||
} = await encryptFile(status, file, fileBuffer, masterKey);
|
||||
|
||||
const form = new FormData();
|
||||
@@ -263,20 +265,20 @@ export const uploadFile = async (
|
||||
form.set("checksum", fileEncryptedHash);
|
||||
|
||||
let thumbnailForm = null;
|
||||
if (thumbnailEncrypted) {
|
||||
if (thumbnail) {
|
||||
thumbnailForm = new FormData();
|
||||
thumbnailForm.set(
|
||||
"metadata",
|
||||
JSON.stringify({
|
||||
dekVersion: dataKeyVersion.toISOString(),
|
||||
contentIv: thumbnailEncrypted.iv,
|
||||
contentIv: thumbnail.iv,
|
||||
} satisfies FileThumbnailUploadRequest),
|
||||
);
|
||||
thumbnailForm.set("content", new Blob([thumbnailEncrypted.ciphertext]));
|
||||
thumbnailForm.set("content", new Blob([thumbnail.ciphertext]));
|
||||
}
|
||||
|
||||
const { fileId } = await requestFileUpload(status, form, thumbnailForm);
|
||||
return { fileId, fileBuffer };
|
||||
return { fileId, fileBuffer, thumbnailBuffer: thumbnail?.plaintext };
|
||||
} catch (e) {
|
||||
status.update((value) => {
|
||||
value.status = "error";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { encodeToBase64 } from "$lib/modules/crypto";
|
||||
|
||||
const scaleSize = (width: number, height: number, targetSize: number) => {
|
||||
if (width <= targetSize || height <= targetSize) {
|
||||
return { width, height };
|
||||
@@ -74,3 +76,7 @@ export const generateVideoThumbnail = (videoUrl: string, time = 0) => {
|
||||
video.src = videoUrl;
|
||||
});
|
||||
};
|
||||
|
||||
export const getThumbnailUrl = (thumbnailBuffer: ArrayBuffer) => {
|
||||
return `data:image/webp;base64,${encodeToBase64(thumbnailBuffer)}`;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user