From 72a92303965031b6d677da2764b4051a33d1223c Mon Sep 17 00:00:00 2001 From: Hmjz100 <98228280+hmjz100@users.noreply.github.com> Date: Mon, 27 Apr 2026 19:28:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9A=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- (改)网盘直链下载助手.user.js | 503 ++++++++++++--------------------- 1 file changed, 177 insertions(+), 326 deletions(-) diff --git a/(改)网盘直链下载助手.user.js b/(改)网盘直链下载助手.user.js index c615f1f..8eb75ee 100644 --- a/(改)网盘直链下载助手.user.js +++ b/(改)网盘直链下载助手.user.js @@ -1284,7 +1284,7 @@ // 初始化全局共享状态 this.download.active = this.download.active || 0; // 全局活跃线程数 this.download.taskCount = this.download.taskCount || 0; // 当前正在运行的 download 任务数 - const global_maxThreads = 8; // 整个允许的最大并发数 + const global_maxThreads = 10; // 整个允许的最大并发数 if (extra) base.console.info(`【LinkSwift】Download\n收到数据:`, extra); if (!extra || !extra.index || !extra.name || !extra.size) throw new Error("extra 缺少内容。"); @@ -1294,7 +1294,11 @@ requests: new Set(), results: [], active: 0, - maxSpeed: 0 + maxSpeed: 0, + lastSampleTime: Date.now(), + lastSampleLoaded: 0, + currentSpeed: 0, + totalLoaded: 0 }; const promise = new Promise((resolve, reject) => { @@ -1312,7 +1316,15 @@ size = parseInt((responseHeaders["Content-Range"]?.match(/\/(\d+)$/)?.[1] || size), 10); } - if (!status.aborted && typeof extra?.onProgress === "function") extra.onProgress(0, 0, size); + if (!status.aborted && typeof extra?.onProgress === "function") extra.onProgress({ + progress: 0, + loaded: 0, + total: size, + speed: 0, + speedText: `${base.sizeFormat(0)}/s`, + etaText: base.rtimeFormat(NaN) + }); + if (!(finalHead.status >= 200 && finalHead.status < 400)) return reject(finalHead); if (finalHead.status == 204 && finalHead.statusText === "IDM") return reject(finalHead); @@ -1324,18 +1336,19 @@ const maxRetry = extra.retry || 10; let index = 0; let offset = 0; - let totalLoaded = 0; const worker = async () => { - const minChunk = extra.minChunk || 50 * 1024; // 最小 50KB - const maxChunk = extra.maxChunk || 1 * 1024 * 1024; // 最大 1MB - let chunk = Math.floor(minChunk + (maxChunk - minChunk) * 0.37); + const minChunk = extra.minChunk || 128 * 1024; // 最小 128KB,避免过度碎片化 + const absoluteMaxChunk = extra.maxChunk || 30 * 1024 * 1024; // 放宽最大限制到 30MB + + // 初始探测块大小:从较小的基准开始(例如 256KB) + let chunk = Math.min(256 * 1024, absoluteMaxChunk); while (offset < size && !status.aborted) { // 如果全局线程满了,且当前任务已经抢到了 1 条以上的线程,则 “让路” 给后来的任务 const fairShare = Math.max(1, Math.floor(global_maxThreads / this.download.taskCount)); while (!status.aborted && this.download.active >= global_maxThreads && status.active >= fairShare) { - await new Promise(r => setTimeout(r, 200)); // 等待,直到其他任务释放或有空位 + await new Promise(r => setTimeout(r, 200)); } if (status.aborted || offset >= size) break; @@ -1347,8 +1360,11 @@ offset += _size; let attempt = 0; - while (attempt <= maxRetry && !status.aborted) { - // 占用线程计数 + let success = false; + let duration = 0.1; // 默认防除 0 + let resData; + + while (attempt <= maxRetry && !status.aborted && !success) { status.active++; this.download.active++; @@ -1356,18 +1372,48 @@ let startTime = Date.now(); let lastLoaded = 0; - let res = await new Promise((s, j) => { + resData = await new Promise((s, j) => { const xhr = base.xmlHttpRequest({ url, method: "GET", responseType: "arraybuffer", headers: { ...headers, "Range": `bytes=${start}-${end}` }, onloadstart() { - startTime = Date.now(); + startTime = Date.now(); // 拿到首字节开始为当前块计时 }, onprogress: (progress) => { - totalLoaded += (progress.loaded - lastLoaded); + const delta = progress.loaded - lastLoaded; + status.totalLoaded += delta; // 累加到全局已存载 lastLoaded = progress.loaded; - const prog = (totalLoaded * 100 / size); - if (!status.aborted && typeof extra?.onProgress === "function") extra.onProgress(prog, totalLoaded, size); + + const now = Date.now(); + const sampleDuration = (now - status.lastSampleTime) / 1000; + + // 采样频率控制 + if (sampleDuration >= 0.5) { + const instantSpeed = (status.totalLoaded - status.lastSampleLoaded) / sampleDuration; + + // 平滑处理速度 (EMA) + status.currentSpeed = status.currentSpeed === 0 + ? instantSpeed + : status.currentSpeed * 0.4 + instantSpeed * 0.6; + + // 计算剩余时间 (ETA) + const remainSize = size - status.totalLoaded; + const etaSeconds = status.currentSpeed > 0 ? remainSize / status.currentSpeed : 0; + + // 更新采样锚点 + status.lastSampleTime = now; + status.lastSampleLoaded = status.totalLoaded; + + // 回传给业务层 + if (!status.aborted && typeof extra?.onProgress === "function") extra.onProgress({ + progress: (status.totalLoaded * 100 / size), + loaded: status.totalLoaded, + total: size, + speed: status.currentSpeed, + speedText: `${base.sizeFormat(status.currentSpeed)}/s`, + etaText: base.rtimeFormat(etaSeconds) + }); + } }, onload: (load) => { status.requests.delete(xhr); @@ -1383,53 +1429,61 @@ status.requests.add(xhr); }); - // 智能分块调整 - const _duration = extra.duration || 1.5; // 目标 - const duration = (Date.now() - startTime) / 1000 || 0.1; - const speed = _size / duration; + duration = (Date.now() - startTime) / 1000 || 0.05; + status.results.push({ index: _index, data: resData }); + success = true; - let nextChunk; - if (speed > status.maxSpeed * 0.9) { - // 如果速度在提升或维持高位,说明大块是有效的,即便超时也要大胆增加 - // 目标是找到能让 speed 最大化的 chunk 大小 - nextChunk = chunk * 1.5; - status.maxSpeed = Math.max(status.maxSpeed, speed); - } else if (duration < _duration * 0.5) { - // 跑得太快了,可以尝试再加一点 - nextChunk = chunk * 1.2; - } else if (duration > _duration * 2) { - // 只有当耗时严重超过目标(比如超过 2 倍)且速度下降时,才收缩 - nextChunk = chunk * 0.8; - } else { - // 稳定期 - nextChunk = chunk; - } - - chunk = Math.max(minChunk, Math.min(maxChunk, chunk * 0.7 + nextChunk * 0.3)); - chunk = Math.floor(chunk); - - status.results.push({ index: _index, data: res }); - res = null; - break; } catch (e) { + // 发生错误通常是断流,强制将下一次计算的 chunk 缩小一半,避免死磕 + chunk = Math.max(minChunk, Math.floor(chunk * 0.5)); + await new Promise(r => setTimeout(r, 1000 * attempt)); attempt++; if (attempt > maxRetry) throw e; } finally { - // 释放线程计数 status.active--; this.download.active--; } } + + if (success) { + // 动态比例探测 + const speed = _size / duration; // 当前块测算速度 (Bytes/s) + const targetDuration = extra.duration || 2.0; // 目标:希望每个块耗时 2 秒钟下载完 + + // 根据当前真实速度,推算如果要恰好耗时 2 秒,下一个块应该多大 + let nextOptimalChunk = speed * targetDuration; + + // 涨跌幅限制,防止网络突发波动导致 chunk 暴增或暴跌 + // 一次最多涨 2 倍,最多跌至 1/3 + nextOptimalChunk = Math.min(nextOptimalChunk, chunk * 2.0); + nextOptimalChunk = Math.max(nextOptimalChunk, chunk * 0.33); + + // 平滑滤波:历史值占 40%,新预测占 60% (倾向于较快响应网络变化) + chunk = Math.floor(chunk * 0.4 + nextOptimalChunk * 0.6); + + // 最终安全边界钳制 + chunk = Math.max(minChunk, Math.min(absoluteMaxChunk, chunk)); + + // 记录最高速度 + status.maxSpeed = Math.max(status.maxSpeed, speed); + } } }; // 启动当前任务的并发线程,单任务最高 3 个 - const maxThreads = Math.min(extra.thread || 3, 3); + const maxThreads = Math.min(extra.thread || 3, global_maxThreads); await Promise.all(Array(maxThreads).fill(0).map(worker)); if (status.aborted) return; - if (!status.aborted && typeof extra?.onProgress === "function") extra.onProgress(100, size, size); + if (!status.aborted && typeof extra?.onProgress === "function") extra.onProgress({ + progress: 100, + loaded: size, + total: size, + speed: 0, + speedText: `${base.sizeFormat(0)}/s`, + etaText: base.rtimeFormat(0) + }); await new Promise(resolve => setTimeout(resolve, 0)); status.results.sort((a, b) => a.index - b.index); @@ -1462,9 +1516,58 @@ const xhr = base.xmlHttpRequest({ url: url, headers, method: "GET", responseType: "blob", onprogress: (progress) => { - if (!status.aborted && typeof extra?.onProgress === "function") extra.onProgress((progress.loaded * 100 / progress.total), progress.loaded, progress.total); + if (status.aborted) return; + + // 同步全局已存载量,单线程模式下 progress.loaded 就是已存载的总量 + status.totalLoaded = progress.loaded; + + // 频率控制 + const now = Date.now(); + const sampleDuration = (now - (status.lastSampleTime || now)) / 1000; + + if (sampleDuration >= 0.5 || !status.lastSampleTime) { + // 计算瞬时速度 + const instantSpeed = (status.totalLoaded - (status.lastSampleLoaded || 0)) / (sampleDuration || 1); + + // 平滑处理速度 (EMA) + status.currentSpeed = !status.currentSpeed + ? instantSpeed + : status.currentSpeed * 0.4 + instantSpeed * 0.6; + + // 计算剩余时间 (ETA) + const total = progress.total || size; // 优先用服务器返回的 total + const remainSize = total - status.totalLoaded; + const etaSeconds = status.currentSpeed > 0 ? remainSize / status.currentSpeed : 0; + + // 更新采样锚点 + status.lastSampleTime = now; + status.lastSampleLoaded = status.totalLoaded; + + // 回传给业务层 + if (typeof extra?.onProgress === "function") { + extra.onProgress({ + progress: (status.totalLoaded * 100 / total), + loaded: status.totalLoaded, + total: total, + speed: status.currentSpeed, + speedText: `${base.sizeFormat(status.currentSpeed)}/s`, + etaText: base.rtimeFormat(etaSeconds) + }); + } + } + }, + onload: (load) => { + if (status.aborted) return; + if (typeof extra?.onProgress === "function") extra.onProgress({ + progress: 100, + loaded: size, + total: size, + speed: 0, + speedText: `${base.sizeFormat(0)}/s`, + etaText: base.rtimeFormat(0) + }); + resolve(load); }, - onload: (load) => resolve(load), onerror: (error) => reject(error) }); status.requests.add(xhr); @@ -5080,40 +5183,12 @@ button.downloadSubtitle:disabled { status.down_enhance_downing.find(".stop").show(); status.down_enhance_downing.show(); - const startTime = Date.now(); - let lastTime = startTime; - let lastLoaded = 0; - - let emaSpeed = 0; - const tau = 2; // 时间常数(秒),数值越大速度显示越平稳,越小越灵敏。建议 1.5 - 3 之间。 - base.download(file.link, { "User-Agent": config.$baidu.api.ua.downloadLink, "Origin": "", "Referer": "" }, { ...file, - onProgress: (prog, loaded, total) => { - const time = Date.now(); - const insDiff = (time - lastTime) / 1000 || 0.001; // 瞬时耗时(秒) - const insSpeed = (loaded - lastLoaded) / insDiff; // 瞬时速度(B/s) - const avgDiff = (time - startTime) / 1000 || 0.1; // 总耗时(秒) - const avgSpeed = loaded / avgDiff; // 全局平均速度(B/s) - - const alpha = 1 - Math.exp(-insDiff / tau); - if (emaSpeed === 0) { - emaSpeed = insSpeed; // 第一次采样,直接赋值 - } else { - // EMA 公式:当前平滑值 = (1 - alpha) * 旧值 + alpha * 当前瞬时值 - emaSpeed = (1 - alpha) * emaSpeed + alpha * insSpeed; - } - - const rSize = total - loaded; - - const predictionSpeed = (emaSpeed > 1024) ? emaSpeed : avgSpeed; // 兜底 - 如果 EMA 速度异常,则参考全局平均速度 - const rTime = predictionSpeed > 0 ? rSize / predictionSpeed : 0; - - lastLoaded = loaded; - lastTime = time; - const dprog = Math.min(prog, 100); + onProgress: (data) => { + const dprog = Math.min(data.progress, 100); status.down_enhance_downing.find(".pl-progress").css("--width", `${dprog}%`); - status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% - ${base.sizeFormat(loaded)} | ${base.sizeFormat(emaSpeed)}/块 | ${base.rtimeFormat(rTime)}`); + status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% | 已存:${base.sizeFormat(data.loaded)} | 速度:${data.speedText} | 剩余:${data.etaText}`); } }) .then(async (res) => { @@ -6173,40 +6248,12 @@ button.downloadSubtitle:disabled { status.down_enhance_downing.find(".stop").show(); status.down_enhance_downing.show(); - const startTime = Date.now(); - let lastTime = startTime; - let lastLoaded = 0; - - let emaSpeed = 0; - const tau = 2; // 时间常数(秒),数值越大速度显示越平稳,越小越灵敏。建议 1.5 - 3 之间。 - base.download(file.link, undefined, { ...file, - onProgress: (prog, loaded, total) => { - const time = Date.now(); - const insDiff = (time - lastTime) / 1000 || 0.001; // 瞬时耗时(秒) - const insSpeed = (loaded - lastLoaded) / insDiff; // 瞬时速度(B/s) - const avgDiff = (time - startTime) / 1000 || 0.1; // 总耗时(秒) - const avgSpeed = loaded / avgDiff; // 全局平均速度(B/s) - - const alpha = 1 - Math.exp(-insDiff / tau); - if (emaSpeed === 0) { - emaSpeed = insSpeed; // 第一次采样,直接赋值 - } else { - // EMA 公式:当前平滑值 = (1 - alpha) * 旧值 + alpha * 当前瞬时值 - emaSpeed = (1 - alpha) * emaSpeed + alpha * insSpeed; - } - - const rSize = total - loaded; - - const predictionSpeed = (emaSpeed > 1024) ? emaSpeed : avgSpeed; // 兜底 - 如果 EMA 速度异常,则参考全局平均速度 - const rTime = predictionSpeed > 0 ? rSize / predictionSpeed : 0; - - lastLoaded = loaded; - lastTime = time; - const dprog = Math.min(prog, 100); + onProgress: (data) => { + const dprog = Math.min(data.progress, 100); status.down_enhance_downing.find(".pl-progress").css("--width", `${dprog}%`); - status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% - ${base.sizeFormat(loaded)} | ${base.sizeFormat(emaSpeed)}/块 | ${base.rtimeFormat(rTime)}`); + status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% | 已存:${base.sizeFormat(data.loaded)} | 速度:${data.speedText} | 剩余:${data.etaText}`); } }) .then(async (res) => { @@ -6565,40 +6612,12 @@ button.downloadSubtitle:disabled { status.down_enhance_downing.find(".stop").show(); status.down_enhance_downing.show(); - const startTime = Date.now(); - let lastTime = startTime; - let lastLoaded = 0; - - let emaSpeed = 0; - const tau = 2; // 时间常数(秒),数值越大速度显示越平稳,越小越灵敏。建议 1.5 - 3 之间。 - base.download(file.link, undefined, { ...file, - onProgress: (prog, loaded, total) => { - const time = Date.now(); - const insDiff = (time - lastTime) / 1000 || 0.001; // 瞬时耗时(秒) - const insSpeed = (loaded - lastLoaded) / insDiff; // 瞬时速度(B/s) - const avgDiff = (time - startTime) / 1000 || 0.1; // 总耗时(秒) - const avgSpeed = loaded / avgDiff; // 全局平均速度(B/s) - - const alpha = 1 - Math.exp(-insDiff / tau); - if (emaSpeed === 0) { - emaSpeed = insSpeed; // 第一次采样,直接赋值 - } else { - // EMA 公式:当前平滑值 = (1 - alpha) * 旧值 + alpha * 当前瞬时值 - emaSpeed = (1 - alpha) * emaSpeed + alpha * insSpeed; - } - - const rSize = total - loaded; - - const predictionSpeed = (emaSpeed > 1024) ? emaSpeed : avgSpeed; // 兜底 - 如果 EMA 速度异常,则参考全局平均速度 - const rTime = predictionSpeed > 0 ? rSize / predictionSpeed : 0; - - lastLoaded = loaded; - lastTime = time; - const dprog = Math.min(prog, 100); + onProgress: (data) => { + const dprog = Math.min(data.progress, 100); status.down_enhance_downing.find(".pl-progress").css("--width", `${dprog}%`); - status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% - ${base.sizeFormat(loaded)} | ${base.sizeFormat(emaSpeed)}/块 | ${base.rtimeFormat(rTime)}`); + status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% | 已存:${base.sizeFormat(data.loaded)} | 速度:${data.speedText} | 剩余:${data.etaText}`); } }) .then(async (res) => { @@ -7000,40 +7019,12 @@ button.downloadSubtitle:disabled { status.down_enhance_downing.find(".stop").show(); status.down_enhance_downing.show(); - const startTime = Date.now(); - let lastTime = startTime; - let lastLoaded = 0; - - let emaSpeed = 0; - const tau = 2; // 时间常数(秒),数值越大速度显示越平稳,越小越灵敏。建议 1.5 - 3 之间。 - base.download(file.link, undefined, { ...file, - onProgress: (prog, loaded, total) => { - const time = Date.now(); - const insDiff = (time - lastTime) / 1000 || 0.001; // 瞬时耗时(秒) - const insSpeed = (loaded - lastLoaded) / insDiff; // 瞬时速度(B/s) - const avgDiff = (time - startTime) / 1000 || 0.1; // 总耗时(秒) - const avgSpeed = loaded / avgDiff; // 全局平均速度(B/s) - - const alpha = 1 - Math.exp(-insDiff / tau); - if (emaSpeed === 0) { - emaSpeed = insSpeed; // 第一次采样,直接赋值 - } else { - // EMA 公式:当前平滑值 = (1 - alpha) * 旧值 + alpha * 当前瞬时值 - emaSpeed = (1 - alpha) * emaSpeed + alpha * insSpeed; - } - - const rSize = total - loaded; - - const predictionSpeed = (emaSpeed > 1024) ? emaSpeed : avgSpeed; // 兜底 - 如果 EMA 速度异常,则参考全局平均速度 - const rTime = predictionSpeed > 0 ? rSize / predictionSpeed : 0; - - lastLoaded = loaded; - lastTime = time; - const dprog = Math.min(prog, 100); + onProgress: (data) => { + const dprog = Math.min(data.progress, 100); status.down_enhance_downing.find(".pl-progress").css("--width", `${dprog}%`); - status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% - ${base.sizeFormat(loaded)} | ${base.sizeFormat(emaSpeed)}/块 | ${base.rtimeFormat(rTime)}`); + status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% | 已存:${base.sizeFormat(data.loaded)} | 速度:${data.speedText} | 剩余:${data.etaText}`); } }) .then(async (res) => { @@ -7351,40 +7342,12 @@ button.downloadSubtitle:disabled { status.down_enhance_downing.find(".stop").show(); status.down_enhance_downing.show(); - const startTime = Date.now(); - let lastTime = startTime; - let lastLoaded = 0; - - let emaSpeed = 0; - const tau = 2; // 时间常数(秒),数值越大速度显示越平稳,越小越灵敏。建议 1.5 - 3 之间。 - base.download(file.link, undefined, { ...file, - onProgress: (prog, loaded, total) => { - const time = Date.now(); - const insDiff = (time - lastTime) / 1000 || 0.001; // 瞬时耗时(秒) - const insSpeed = (loaded - lastLoaded) / insDiff; // 瞬时速度(B/s) - const avgDiff = (time - startTime) / 1000 || 0.1; // 总耗时(秒) - const avgSpeed = loaded / avgDiff; // 全局平均速度(B/s) - - const alpha = 1 - Math.exp(-insDiff / tau); - if (emaSpeed === 0) { - emaSpeed = insSpeed; // 第一次采样,直接赋值 - } else { - // EMA 公式:当前平滑值 = (1 - alpha) * 旧值 + alpha * 当前瞬时值 - emaSpeed = (1 - alpha) * emaSpeed + alpha * insSpeed; - } - - const rSize = total - loaded; - - const predictionSpeed = (emaSpeed > 1024) ? emaSpeed : avgSpeed; // 兜底 - 如果 EMA 速度异常,则参考全局平均速度 - const rTime = predictionSpeed > 0 ? rSize / predictionSpeed : 0; - - lastLoaded = loaded; - lastTime = time; - const dprog = Math.min(prog, 100); + onProgress: (data) => { + const dprog = Math.min(data.progress, 100); status.down_enhance_downing.find(".pl-progress").css("--width", `${dprog}%`); - status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% - ${base.sizeFormat(loaded)} | ${base.sizeFormat(emaSpeed)}/块 | ${base.rtimeFormat(rTime)}`); + status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% | 已存:${base.sizeFormat(data.loaded)} | 速度:${data.speedText} | 剩余:${data.etaText}`); } }) .then(async (res) => { @@ -7681,40 +7644,12 @@ button.downloadSubtitle:disabled { status.down_enhance_downing.find(".stop").show(); status.down_enhance_downing.show(); - const startTime = Date.now(); - let lastTime = startTime; - let lastLoaded = 0; - - let emaSpeed = 0; - const tau = 2; // 时间常数(秒),数值越大速度显示越平稳,越小越灵敏。建议 1.5 - 3 之间。 - base.download(file.link, undefined, { ...file, - onProgress: (prog, loaded, total) => { - const time = Date.now(); - const insDiff = (time - lastTime) / 1000 || 0.001; // 瞬时耗时(秒) - const insSpeed = (loaded - lastLoaded) / insDiff; // 瞬时速度(B/s) - const avgDiff = (time - startTime) / 1000 || 0.1; // 总耗时(秒) - const avgSpeed = loaded / avgDiff; // 全局平均速度(B/s) - - const alpha = 1 - Math.exp(-insDiff / tau); - if (emaSpeed === 0) { - emaSpeed = insSpeed; // 第一次采样,直接赋值 - } else { - // EMA 公式:当前平滑值 = (1 - alpha) * 旧值 + alpha * 当前瞬时值 - emaSpeed = (1 - alpha) * emaSpeed + alpha * insSpeed; - } - - const rSize = total - loaded; - - const predictionSpeed = (emaSpeed > 1024) ? emaSpeed : avgSpeed; // 兜底 - 如果 EMA 速度异常,则参考全局平均速度 - const rTime = predictionSpeed > 0 ? rSize / predictionSpeed : 0; - - lastLoaded = loaded; - lastTime = time; - const dprog = Math.min(prog, 100); + onProgress: (data) => { + const dprog = Math.min(data.progress, 100); status.down_enhance_downing.find(".pl-progress").css("--width", `${dprog}%`); - status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% - ${base.sizeFormat(loaded)} | ${base.sizeFormat(emaSpeed)}/块 | ${base.rtimeFormat(rTime)}`); + status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% | 已存:${base.sizeFormat(data.loaded)} | 速度:${data.speedText} | 剩余:${data.etaText}`); } }) .then(async (res) => { @@ -8084,40 +8019,12 @@ button.downloadSubtitle:disabled { status.down_enhance_downing.find(".stop").show(); status.down_enhance_downing.show(); - const startTime = Date.now(); - let lastTime = startTime; - let lastLoaded = 0; - - let emaSpeed = 0; - const tau = 2; // 时间常数(秒),数值越大速度显示越平稳,越小越灵敏。建议 1.5 - 3 之间。 - base.download(file.link, { "User-Agent": config.$quark.api.ua.downloadLink }, { ...file, - onProgress: (prog, loaded, total) => { - const time = Date.now(); - const insDiff = (time - lastTime) / 1000 || 0.001; // 瞬时耗时(秒) - const insSpeed = (loaded - lastLoaded) / insDiff; // 瞬时速度(B/s) - const avgDiff = (time - startTime) / 1000 || 0.1; // 总耗时(秒) - const avgSpeed = loaded / avgDiff; // 全局平均速度(B/s) - - const alpha = 1 - Math.exp(-insDiff / tau); - if (emaSpeed === 0) { - emaSpeed = insSpeed; // 第一次采样,直接赋值 - } else { - // EMA 公式:当前平滑值 = (1 - alpha) * 旧值 + alpha * 当前瞬时值 - emaSpeed = (1 - alpha) * emaSpeed + alpha * insSpeed; - } - - const rSize = total - loaded; - - const predictionSpeed = (emaSpeed > 1024) ? emaSpeed : avgSpeed; // 兜底 - 如果 EMA 速度异常,则参考全局平均速度 - const rTime = predictionSpeed > 0 ? rSize / predictionSpeed : 0; - - lastLoaded = loaded; - lastTime = time; - const dprog = Math.min(prog, 100); + onProgress: (data) => { + const dprog = Math.min(data.progress, 100); status.down_enhance_downing.find(".pl-progress").css("--width", `${dprog}%`); - status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% - ${base.sizeFormat(loaded)} | ${base.sizeFormat(emaSpeed)}/块 | ${base.rtimeFormat(rTime)}`); + status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% | 已存:${base.sizeFormat(data.loaded)} | 速度:${data.speedText} | 剩余:${data.etaText}`); } }) .then(async (res) => { @@ -8529,40 +8436,12 @@ button.downloadSubtitle:disabled { status.down_enhance_downing.find(".stop").show(); status.down_enhance_downing.show(); - const startTime = Date.now(); - let lastTime = startTime; - let lastLoaded = 0; - - let emaSpeed = 0; - const tau = 2; // 时间常数(秒),数值越大速度显示越平稳,越小越灵敏。建议 1.5 - 3 之间。 - base.download(file.link, { "User-Agent": config.$uc.api.ua.downloadLink }, { ...file, - onProgress: (prog, loaded, total) => { - const time = Date.now(); - const insDiff = (time - lastTime) / 1000 || 0.001; // 瞬时耗时(秒) - const insSpeed = (loaded - lastLoaded) / insDiff; // 瞬时速度(B/s) - const avgDiff = (time - startTime) / 1000 || 0.1; // 总耗时(秒) - const avgSpeed = loaded / avgDiff; // 全局平均速度(B/s) - - const alpha = 1 - Math.exp(-insDiff / tau); - if (emaSpeed === 0) { - emaSpeed = insSpeed; // 第一次采样,直接赋值 - } else { - // EMA 公式:当前平滑值 = (1 - alpha) * 旧值 + alpha * 当前瞬时值 - emaSpeed = (1 - alpha) * emaSpeed + alpha * insSpeed; - } - - const rSize = total - loaded; - - const predictionSpeed = (emaSpeed > 1024) ? emaSpeed : avgSpeed; // 兜底 - 如果 EMA 速度异常,则参考全局平均速度 - const rTime = predictionSpeed > 0 ? rSize / predictionSpeed : 0; - - lastLoaded = loaded; - lastTime = time; - const dprog = Math.min(prog, 100); + onProgress: (data) => { + const dprog = Math.min(data.progress, 100); status.down_enhance_downing.find(".pl-progress").css("--width", `${dprog}%`); - status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% - ${base.sizeFormat(loaded)} | ${base.sizeFormat(emaSpeed)}/块 | ${base.rtimeFormat(rTime)}`); + status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% | 已存:${base.sizeFormat(data.loaded)} | 速度:${data.speedText} | 剩余:${data.etaText}`); } }) .then(async (res) => { @@ -8931,40 +8810,12 @@ button.downloadSubtitle:disabled { status.down_enhance_downing.find(".stop").show(); status.down_enhance_downing.show(); - const startTime = Date.now(); - let lastTime = startTime; - let lastLoaded = 0; - - let emaSpeed = 0; - const tau = 2; // 时间常数(秒),数值越大速度显示越平稳,越小越灵敏。建议 1.5 - 3 之间。 - base.download(file.link, undefined, { ...file, - onProgress: (prog, loaded, total) => { - const time = Date.now(); - const insDiff = (time - lastTime) / 1000 || 0.001; // 瞬时耗时(秒) - const insSpeed = (loaded - lastLoaded) / insDiff; // 瞬时速度(B/s) - const avgDiff = (time - startTime) / 1000 || 0.1; // 总耗时(秒) - const avgSpeed = loaded / avgDiff; // 全局平均速度(B/s) - - const alpha = 1 - Math.exp(-insDiff / tau); - if (emaSpeed === 0) { - emaSpeed = insSpeed; // 第一次采样,直接赋值 - } else { - // EMA 公式:当前平滑值 = (1 - alpha) * 旧值 + alpha * 当前瞬时值 - emaSpeed = (1 - alpha) * emaSpeed + alpha * insSpeed; - } - - const rSize = total - loaded; - - const predictionSpeed = (emaSpeed > 1024) ? emaSpeed : avgSpeed; // 兜底 - 如果 EMA 速度异常,则参考全局平均速度 - const rTime = predictionSpeed > 0 ? rSize / predictionSpeed : 0; - - lastLoaded = loaded; - lastTime = time; - const dprog = Math.min(prog, 100); + onProgress: (data) => { + const dprog = Math.min(data.progress, 100); status.down_enhance_downing.find(".pl-progress").css("--width", `${dprog}%`); - status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% - ${base.sizeFormat(loaded)} | ${base.sizeFormat(emaSpeed)}/块 | ${base.rtimeFormat(rTime)}`); + status.down_enhance_downing.find(".pl-progress .text").text(`${dprog.toFixed(2)}% | 已存:${base.sizeFormat(data.loaded)} | 速度:${data.speedText} | 剩余:${data.etaText}`); } }) .then(async (res) => {