From 58194ba29fdb67368cef9f953cc35bb7925d774c Mon Sep 17 00:00:00 2001 From: yuming Date: Thu, 23 Apr 2026 10:18:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=98=9F=E5=88=97=E6=97=A5=E6=9C=9F?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=20+=20=E4=BB=BB=E5=8A=A1=E5=88=86?= =?UTF-8?q?=E6=AF=8D=E6=94=B9=E4=B8=BA=E7=9C=9F=E6=AD=A3=E8=A6=81=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E7=9A=84=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 队列卡片:显示 📅 2025-11-20 至 2026-04-23,替代原 SQL filter 字符串 - 任务状态:分母改为 qualified - existing_skipped(本次真正待下载数), 跳过文案在有本次跳过时追加"其中本次跳过 X" - 新增 existing_skipped 计数器,在 "文件已存在" 和 "db 标记跳过" 两处独立递增 Co-Authored-By: Claude Opus 4.7 (1M context) --- media_downloader.py | 4 ++++ module/download_stat.py | 3 +++ module/templates/index.html | 45 ++++++++++++++++++++++++------------- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/media_downloader.py b/media_downloader.py index 03261af..785e162 100644 --- a/media_downloader.py +++ b/media_downloader.py @@ -441,6 +441,8 @@ async def download_media( ) # Update skip counter increment_task_stat("skipped_files") + # 这一类跳过属于"本次任务中发现已下载",单独计数给前端算分母 + increment_task_stat("existing_skipped") increment_task_stat("checked_messages") return DownloadStatus.SkipDownload, None else: @@ -450,6 +452,8 @@ async def download_media( f"id={message.id} {ui_file_name} {_reason},跳过。\n" ) increment_task_stat("skipped_files") + # db 标记为跳过也算"本次任务跳过" + increment_task_stat("existing_skipped") increment_task_stat("checked_messages") return DownloadStatus.SkipDownload, None else: diff --git a/module/download_stat.py b/module/download_stat.py index 74acb5f..19b9961 100644 --- a/module/download_stat.py +++ b/module/download_stat.py @@ -37,6 +37,8 @@ _task_progress: dict = { "qualified_files": 0, # 缓存命中后的预计下载总数;未命中时遍历结束后再赋值 "estimated_total": 0, + # 本次任务中"通过了 filter 但因已下载/被标记而跳过"的数量,用于前端算"真正要下载"的分母 + "existing_skipped": 0, "is_checking": False, "last_update": 0, } @@ -129,6 +131,7 @@ def reset_task_progress(): "failed_files": 0, "qualified_files": 0, "estimated_total": 0, + "existing_skipped": 0, "is_checking": False, "last_update": time.time(), } diff --git a/module/templates/index.html b/module/templates/index.html index 29d4949..7b40b79 100644 --- a/module/templates/index.html +++ b/module/templates/index.html @@ -1281,6 +1281,14 @@ (endDate ? ' and message_date <= ' + endDate + ' 23:59:59' : ''); } + // 把队列里的起止日期格式化成 "📅 2025-11-20 至 2026-04-23";无日期则 fallback 到原 filter + function formatQueueDateRange(startDate, endDate, fallbackFilter) { + if (startDate) { + return '📅 ' + startDate + ' 至 ' + (endDate || startDate); + } + return fallbackFilter || '无过滤条件'; + } + function renderQueue() { const card = document.getElementById('queue-card'); const list = document.getElementById('queue-list'); @@ -1288,16 +1296,19 @@ if (!downloadQueue.length) { card.style.display = 'none'; return; } card.style.display = ''; count.textContent = downloadQueue.length + ' 个'; - list.innerHTML = downloadQueue.map((q, i) => ` + list.innerHTML = downloadQueue.map((q, i) => { + const dateStr = formatQueueDateRange(q.start_date, q.end_date, q.download_filter); + return `
${i + 1}
${escapeHtml(q.chat_title || q.chat_id)}
-
${escapeHtml(q.download_filter || '无过滤条件')}
+
${escapeHtml(dateStr)}
- `).join(''); + `; + }).join(''); } function addToQueue() { @@ -1454,27 +1465,31 @@ document.getElementById('banner-chat').textContent = title; const dl = p.downloading_files||0, done = p.completed_files||0, skip = p.skipped_files||0; const qual = p.qualified_files||0, est = p.estimated_total||0; - // 分母优先用缓存值;没有就用当次遍历实时累加的 qualified - const total = est || qual; - const doneStr = total ? `${done} / ${total}` : `${done}`; + const existingSkip = p.existing_skipped || 0; + // 分母优先用缓存值;没有就用当次遍历实时累加的 qualified。再扣除"本次任务已跳过",得到真正要下载的数量 + const rawTotal = est || qual; + const realTotal = Math.max(0, rawTotal - existingSkip); + const doneStr = rawTotal ? `${done} / ${realTotal}` : `${done}`; + // 跳过文案:有本次跳过时追加说明 + const skipStr = existingSkip > 0 ? `跳过${skip},其中本次跳过${existingSkip}` : `跳过${skip}`; let st = ''; - if (p.is_checking && paused) st = `⏸ 已暂停 · 扫描中… (跳过${skip})`; - else if (p.is_checking && dl>0) st = `🔍 扫描+下载中 (${dl}个,${doneStr},跳过${skip})`; - else if (p.is_checking) st = `🔍 扫描中… (${doneStr},跳过${skip})`; - else if (paused) st = `⏸ 已暂停 (${doneStr},跳过${skip})`; - else if (dl>0) st = `🚀 下载中 (${dl}个,${doneStr},跳过${skip})`; - else if (done>0||skip>0) st = `✅ 完成 (${doneStr},跳过${skip})`; + if (p.is_checking && paused) st = `⏸ 已暂停 · 扫描中… (${skipStr})`; + else if (p.is_checking && dl>0) st = `🔍 扫描+下载中 (${dl}个,${doneStr},${skipStr})`; + else if (p.is_checking) st = `🔍 扫描中… (${doneStr},${skipStr})`; + else if (paused) st = `⏸ 已暂停 (${doneStr},${skipStr})`; + else if (dl>0) st = `🚀 下载中 (${dl}个,${doneStr},${skipStr})`; + else if (done>0||skip>0) st = `✅ 完成 (${doneStr},${skipStr})`; else st = '⏳ 等待开始'; document.getElementById('banner-state').textContent = st; // 进度条:有总数才显示;扫描中且无缓存时给"扫描中…"后缀 const prog = document.getElementById('banner-progress'); - if (total > 0) { + if (realTotal > 0) { prog.style.display = 'flex'; - const pct = Math.min(100, Math.round(done * 100 / total)); + const pct = Math.min(100, Math.round(done * 100 / realTotal)); document.getElementById('tbp-fill').style.width = pct + '%'; const suffix = (!est && p.is_checking) ? '(扫描中…)' : ''; - document.getElementById('tbp-text').textContent = `${done} / ${total}${suffix}`; + document.getElementById('tbp-text').textContent = `${done} / ${realTotal}${suffix}`; } else { prog.style.display = 'none'; }