### Initialize File Upload Variables and Configuration Source: https://github.com/yohann0617/tg-disk/blob/master/static/upload.html Sets up initial variables for file handling and fetches configuration for chunk size and concurrency from the server. Uses default values if server configuration fails. ```javascript const dropZone = document.getElementById("drop-zone"); const fileInput = document.getElementById("file-input"); const fileList = document.getElementById("file-list"); let selectedFiles = []; let fileIdCounter = 0; // Default values, will be overridden by server config let CHUNK_SIZE = 20 * 1024 * 1024; // 20MB per chunk let CONCURRENT_UPLOADS = 4; // Number of concurrent chunk uploads let CONCURRENT_FILES = 3; // Number of concurrent file uploads // Fetch config from server (async function loadConfig() { try { const response = await fetch("/config"); if (response.ok) { const config = await response.json(); CHUNK_SIZE = config.chunk_size_mb * 1024 * 1024; CONCURRENT_UPLOADS = config.chunk_concurrent; CONCURRENT_FILES = config.files_concurrent; console.log("Server config loaded:", config); } } catch (e) { console.warn("Failed to load server config, using defaults:", e); } })(); ``` -------------------------------- ### Initiate File Upload Process Source: https://github.com/yohann0617/tg-disk/blob/master/static/upload.html Manages the overall upload process, including disabling the upload button, setting up upload responses, and handling concurrent file uploads using an UploadQueue. ```javascript let uploadResponses = []; let filesUploaded = 0; async function uploadFiles() { const pwd = sessionStorage.getItem("pwd"); const uploadBtn = document.getElementById("upload-btn"); uploadBtn.disabled = true; uploadBtn.innerHTML = "⏳ 上传中..."; uploadResponses = []; filesUploaded = 0; // Concurrent file upload const fileQueue = new UploadQueue(CONCURRENT_FILES); const uploadTasks = []; for (let index = 0; index < selectedFiles.length; index++) { const fileItem = selectedFiles[index]; // Skip files that are already uploaded or uploading if (fileItem.uploaded || fileItem.uploading) { continue; } fileItem.uploading = true; const task = fileQueue.add(async () => { try { const result = await uploadSingleFile(fileItem.file, fileItem.id, pwd); uploadResponses.push(result); fileItem.uploaded = true; } catch (e) { alert(`文件 ${fileItem.file.name} 上传失败: ${e.message}`); fileItem.uploading = false; } filesUploaded++; }); uploadTasks.push(task); } await Promise.all(uploadTasks); uploadBtn.disabled = false; uploadBtn.innerHTML = "🚀 开始上传"; showResultModal(uploadResponses); } ``` -------------------------------- ### Upload File in Chunks Source: https://github.com/yohann0617/tg-disk/blob/master/static/upload.html Handles the upload of a file by dividing it into chunks and uploading them concurrently. It updates a progress bar and status text during the upload process. Requires `UploadQueue`, `CHUNK_SIZE`, `CONCURRENT_UPLOADS`, `progressBar`, and `statusEl` to be defined. ```javascript async function uploadFile(file, pwd) { const CHUNK_SIZE = 1024 * 1024 * 5; // 5MB chunks const CONCURRENT_UPLOADS = 3; const totalChunks = Math.ceil(file.size / CHUNK_SIZE); console.log(` Uploading ${file.name} (${totalChunks} chunks, concurrency: ${CONCURRENT_UPLOADS})... `); const chunkIds = new Array(totalChunks); let uploadedChunks = 0; const queue = new UploadQueue(CONCURRENT_UPLOADS); const uploadTasks = []; for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) { const task = queue.add(async () => { const start = chunkIndex * CHUNK_SIZE; const end = Math.min(start + CHUNK_SIZE, file.size); const chunk = file.slice(start, end); const formData = new FormData(); formData.append("pwd", pwd); formData.append("chunk", chunk); formData.append("chunk_index", chunkIndex); formData.append("total_chunks", totalChunks); formData.append("filename", file.name); const response = await fetch("/upload_chunk", { method: "POST", body: formData }); if (!response.ok) { throw new Error(`分片 ${chunkIndex + 1} 上传失败: ${await response.text()}`); } const data = await response.json(); chunkIds[chunkIndex] = data.file_id; uploadedChunks++; const percent = (uploadedChunks / totalChunks) * 100; progressBar.style.width = percent + "%" statusEl.textContent = `上传分片 ${uploadedChunks}/${totalChunks}...`; }); uploadTasks.push(task); } await Promise.all(uploadTasks); statusEl.textContent = "合并分片..."; const mergeFormData = new FormData(); mergeFormData.append("pwd", pwd); mergeFormData.append("filename", file.name); mergeFormData.append("chunk_ids", JSON.stringify(chunkIds)); const mergeResponse = await fetch("/merge_chunks", { method: "POST", body: mergeFormData }); if (!mergeResponse.ok) { throw new Error("合并失败: " + await mergeResponse.text()); } statusEl.textContent = "✅ 完成"; return await mergeResponse.json(); } ``` -------------------------------- ### Upload Single File (Small vs. Large) Source: https://github.com/yohann0617/tg-disk/blob/master/static/upload.html Handles the upload of a single file. For small files (<= CHUNK_SIZE), it uploads directly. For large files, it initiates a concurrent chunk upload process. ```javascript async function uploadSingleFile(file, fileId, pwd) { const totalChunks = Math.ceil(file.size / CHUNK_SIZE); const statusEl = document.getElementById(`status-${fileId}`); const progressBar = document.getElementById(`bar-${fileId}`); // Small file: upload directly if (file.size <= CHUNK_SIZE) { statusEl.textContent = "上传中..."; const formData = new FormData(); formData.append("pwd", pwd); formData.append("file", file); const response = await fetch("/upload", { method: "POST", body: formData }); if (!response.ok) { throw new Error(await response.text()); } progressBar.style.width = "100%"; statusEl.textContent = "✅ 完成"; return await response.json(); } // Large file: concurrent chunk upload statusEl.textContent = `分片上传 (共 ${tot ``` -------------------------------- ### Process and Display Selected Files Source: https://github.com/yohann0617/tg-disk/blob/master/static/upload.html Adds new files to the selectedFiles array and updates the UI to display file names, sizes, and progress bars. Does not clear existing file entries. ```javascript function handleFiles(files) { // Add new files to the existing list, not replace const newFiles = Array.from(files).map(file => { const fileId = fileIdCounter++; return { id: fileId, file: file, uploading: false, uploaded: false }; }); selectedFiles = selectedFiles.concat(newFiles); // Update stats document.getElementById('stats').style.display = 'flex'; document.getElementById('file-count').textContent = selectedFiles.length; const totalBytes = selectedFiles.reduce((sum, item) => sum + item.file.size, 0); document.getElementById('total-size').textContent = formatSize(totalBytes); // Only add display items for new files, don't clear existing ones newFiles.forEach((fileItem) => { const div = document.createElement("div"); div.className = "file-item"; div.id = `file-item-${fileItem.id}`; div.innerHTML = `