diff --git a/package.json b/package.json
index 7b77ca68e5..8a7115abde 100644
--- a/package.json
+++ b/package.json
@@ -36,8 +36,10 @@
"devDependencies": {
"@crowdin/cli": "^3.7.10",
"@hrgui/libass-wasm-ts": "^1.0.3",
+ "@types/crypto-js": "^4.2.2",
"@types/mark.js": "^8.11.8",
"@types/node": "^20.0.0",
+ "@types/qrcode": "^1.5.5",
"@types/sha256": "^0.2.0",
"@types/streamsaver": "^2.0.1",
"@vitejs/plugin-legacy": "^2.0.1",
@@ -61,7 +63,6 @@
"@solid-primitives/keyboard": "^1.2.5",
"@solid-primitives/storage": "^1.3.1",
"@stitches/core": "^1.2.8",
- "@types/qrcode": "^1.5.5",
"@viselect/vanilla": "^3.5.0",
"aplayer": "^1.10.1",
"artplayer": "^5.0.9",
@@ -73,6 +74,7 @@
"copy-to-clipboard": "^3.3.2",
"crypto-js": "^4.2.0",
"flv.js": "^1.6.2",
+ "hash-wasm": "^4.12.0",
"hls.js": "^1.2.1",
"just-once": "^2.2.0",
"libass-wasm": "^4.1.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d7347e6c8e..eaef3bb0b9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -35,9 +35,6 @@ importers:
'@stitches/core':
specifier: ^1.2.8
version: 1.2.8
- '@types/qrcode':
- specifier: ^1.5.5
- version: 1.5.5
'@viselect/vanilla':
specifier: ^3.5.0
version: 3.5.0
@@ -71,6 +68,9 @@ importers:
flv.js:
specifier: ^1.6.2
version: 1.6.2
+ hash-wasm:
+ specifier: ^4.12.0
+ version: 4.12.0
hls.js:
specifier: ^1.2.1
version: 1.2.1
@@ -138,12 +138,18 @@ importers:
'@hrgui/libass-wasm-ts':
specifier: ^1.0.3
version: 1.0.3
+ '@types/crypto-js':
+ specifier: ^4.2.2
+ version: 4.2.2
'@types/mark.js':
specifier: ^8.11.8
version: 8.11.8
'@types/node':
specifier: ^20.0.0
version: 20.0.0
+ '@types/qrcode':
+ specifier: ^1.5.5
+ version: 1.5.5
'@types/sha256':
specifier: ^0.2.0
version: 0.2.0
@@ -486,6 +492,9 @@ packages:
'@stitches/core@1.2.8':
resolution: {integrity: sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg==}
+ '@types/crypto-js@4.2.2':
+ resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==}
+
'@types/debug@4.1.7':
resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==}
@@ -1091,6 +1100,9 @@ packages:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'}
+ hash-wasm@4.12.0:
+ resolution: {integrity: sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ==}
+
hast-to-hyperscript@10.0.1:
resolution: {integrity: sha512-dhIVGoKCQVewFi+vz3Vt567E4ejMppS1haBRL6TEmeLeJVB1i/FJIIg/e6s1Bwn0g5qtYojHEKvyGA+OZuyifw==}
@@ -2419,6 +2431,8 @@ snapshots:
'@stitches/core@1.2.8': {}
+ '@types/crypto-js@4.2.2': {}
+
'@types/debug@4.1.7':
dependencies:
'@types/ms': 0.7.31
@@ -2956,6 +2970,8 @@ snapshots:
dependencies:
function-bind: 1.1.1
+ hash-wasm@4.12.0: {}
+
hast-to-hyperscript@10.0.1:
dependencies:
'@types/unist': 2.0.6
diff --git a/src/lang/en/home.json b/src/lang/en/home.json
index 643cad374f..7178f2aa2f 100644
--- a/src/lang/en/home.json
+++ b/src/lang/en/home.json
@@ -93,6 +93,7 @@
},
"upload": {
"add_as_task": "Add as task",
+ "try_rapid": "Try rapid",
"upload-tips": "Drag files here to upload, or click:",
"release": "Release to upload",
"no_files_drag": "No files were dragged in.",
diff --git a/src/pages/home/uploads/Upload.tsx b/src/pages/home/uploads/Upload.tsx
index 51c4bf850a..72ef1cefaa 100644
--- a/src/pages/home/uploads/Upload.tsx
+++ b/src/pages/home/uploads/Upload.tsx
@@ -77,6 +77,7 @@ const Upload = () => {
const [uploading, setUploading] = createSignal(false)
const [asTask, setAsTask] = createSignal(false)
const [overwrite, setOverwrite] = createSignal(false)
+ const [rapid, setRapid] = createSignal(true)
const [uploadFiles, setUploadFiles] = createStore<{
uploads: UploadFileProps[]
}>({
@@ -119,6 +120,7 @@ const Upload = () => {
},
asTask(),
overwrite(),
+ rapid(),
)
if (!err) {
setUpload(path, "status", "success")
@@ -293,6 +295,14 @@ const Upload = () => {
>
{t("home.overwrite_existing")}
+ {
+ setRapid(!rapid())
+ }}
+ >
+ {t("home.upload.try_rapid")}
+
diff --git a/src/pages/home/uploads/form.ts b/src/pages/home/uploads/form.ts
index db11caaae9..85d90fe2f6 100644
--- a/src/pages/home/uploads/form.ts
+++ b/src/pages/home/uploads/form.ts
@@ -2,26 +2,35 @@ import { password } from "~/store"
import { EmptyResp } from "~/types"
import { r } from "~/utils"
import { SetUpload, Upload } from "./types"
+import { calculateHash } from "./util"
export const FormUpload: Upload = async (
uploadPath: string,
file: File,
setUpload: SetUpload,
asTask = false,
overwrite = false,
+ rapid = false,
): Promise => {
let oldTimestamp = new Date().valueOf()
let oldLoaded = 0
const form = new FormData()
form.append("file", file)
+ let headers: { [k: string]: any } = {
+ "File-Path": encodeURIComponent(uploadPath),
+ "As-Task": asTask,
+ "Content-Type": "multipart/form-data",
+ "Last-Modified": file.lastModified,
+ Password: password(),
+ Overwrite: overwrite.toString(),
+ }
+ if (rapid) {
+ const { md5, sha1, sha256 } = await calculateHash(file)
+ headers["X-File-Md5"] = md5
+ headers["X-File-Sha1"] = sha1
+ headers["X-File-Sha256"] = sha256
+ }
const resp: EmptyResp = await r.put("/fs/form", form, {
- headers: {
- "File-Path": encodeURIComponent(uploadPath),
- "As-Task": asTask,
- "Content-Type": "multipart/form-data",
- "Last-Modified": file.lastModified,
- Password: password(),
- Overwrite: overwrite.toString(),
- },
+ headers: headers,
onUploadProgress: (progressEvent) => {
if (progressEvent.total) {
const complete =
diff --git a/src/pages/home/uploads/stream.ts b/src/pages/home/uploads/stream.ts
index 1c725a716b..72980cc182 100644
--- a/src/pages/home/uploads/stream.ts
+++ b/src/pages/home/uploads/stream.ts
@@ -2,24 +2,33 @@ import { password } from "~/store"
import { EmptyResp } from "~/types"
import { r } from "~/utils"
import { SetUpload, Upload } from "./types"
+import { calculateHash } from "./util"
export const StreamUpload: Upload = async (
uploadPath: string,
file: File,
setUpload: SetUpload,
asTask = false,
overwrite = false,
+ rapid = false,
): Promise => {
let oldTimestamp = new Date().valueOf()
let oldLoaded = 0
+ let headers: { [k: string]: any } = {
+ "File-Path": encodeURIComponent(uploadPath),
+ "As-Task": asTask,
+ "Content-Type": file.type || "application/octet-stream",
+ "Last-Modified": file.lastModified,
+ Password: password(),
+ Overwrite: overwrite.toString(),
+ }
+ if (rapid) {
+ const { md5, sha1, sha256 } = await calculateHash(file)
+ headers["X-File-Md5"] = md5
+ headers["X-File-Sha1"] = sha1
+ headers["X-File-Sha256"] = sha256
+ }
const resp: EmptyResp = await r.put("/fs/put", file, {
- headers: {
- "File-Path": encodeURIComponent(uploadPath),
- "As-Task": asTask,
- "Content-Type": file.type || "application/octet-stream",
- "Last-Modified": file.lastModified,
- Password: password(),
- Overwrite: overwrite.toString(),
- },
+ headers: headers,
onUploadProgress: (progressEvent) => {
if (progressEvent.total) {
const complete =
diff --git a/src/pages/home/uploads/types.ts b/src/pages/home/uploads/types.ts
index c138d59455..ade472f71e 100644
--- a/src/pages/home/uploads/types.ts
+++ b/src/pages/home/uploads/types.ts
@@ -22,4 +22,5 @@ export type Upload = (
setUpload: SetUpload,
asTask: boolean,
overwrite: boolean,
+ rapid: boolean,
) => Promise
diff --git a/src/pages/home/uploads/util.ts b/src/pages/home/uploads/util.ts
index a3ac26a393..ee7fa88cc4 100644
--- a/src/pages/home/uploads/util.ts
+++ b/src/pages/home/uploads/util.ts
@@ -1,4 +1,5 @@
import { UploadFileProps } from "./types"
+import { createMD5, createSHA1, createSHA256 } from "hash-wasm"
export const traverseFileTree = async (entry: FileSystemEntry) => {
let res: File[] = []
@@ -59,3 +60,25 @@ export const File2Upload = (file: File): UploadFileProps => {
status: "pending",
}
}
+
+export const calculateHash = async (file: File) => {
+ const md5Digest = await createMD5()
+ const sha1Digest = await createSHA1()
+ const sha256Digest = await createSHA256()
+ const reader = file.stream().getReader()
+ const read = async () => {
+ const { done, value } = await reader.read()
+ if (done) {
+ return
+ }
+ md5Digest.update(value)
+ sha1Digest.update(value)
+ sha256Digest.update(value)
+ await read()
+ }
+ await read()
+ const md5 = md5Digest.digest("hex")
+ const sha1 = sha1Digest.digest("hex")
+ const sha256 = sha256Digest.digest("hex")
+ return { md5, sha1, sha256 }
+}