diff --git a/wechat-news-morning-draft-worker.mjs b/wechat-news-morning-draft-worker.mjs index 31f8a8c..145131e 100644 --- a/wechat-news-morning-draft-worker.mjs +++ b/wechat-news-morning-draft-worker.mjs @@ -1,3 +1,5 @@ +import fs from 'node:fs'; +import path from 'node:path'; import { executeScheduledTask } from './scheduled-task-executor.mjs'; import { localDateKey } from './schedule-time.mjs'; import { @@ -29,6 +31,23 @@ function resolveTodayPage(config, h5Root, now = Date.now()) { return page; } +function archiveTodayPageForForce(config, h5Root, now, logger) { + const page = resolveTodayPage(config, h5Root, now); + if (!page?.localPath || !fs.existsSync(page.localPath)) return null; + const stamp = new Date(now).toISOString().replace(/[:.]/g, '-'); + const archived = path.join(path.dirname(page.localPath), `_archived-${page.slug}-${stamp}.html`); + fs.renameSync(page.localPath, archived); + if (page.thumbPath && fs.existsSync(page.thumbPath)) { + const archivedThumb = archived.replace(/\.html$/i, '.thumbnail.png'); + fs.renameSync(page.thumbPath, archivedThumb); + } + logger.log?.('[NewsMorningDraft] archived today page before force generate', { + from: page.relativePath, + to: path.basename(archived), + }); + return archived; +} + export function startWechatNewsMorningDraftWorker({ wechatNewsMorningDraftService = null, mpConfig = null, @@ -68,6 +87,9 @@ export function startWechatNewsMorningDraftWorker({ if (generationInFlightDateKey === dateKey) return null; generationInFlightDateKey = dateKey; try { + if (force) { + archiveTodayPageForForce(config, h5Root, now, logger); + } let searchBrief = ''; try { searchBrief = await prefetchNewsSearch({ diff --git a/wechat-news-morning-draft-worker.test.mjs b/wechat-news-morning-draft-worker.test.mjs index ff8fb49..309cb9b 100644 --- a/wechat-news-morning-draft-worker.test.mjs +++ b/wechat-news-morning-draft-worker.test.mjs @@ -156,6 +156,7 @@ test('runOnce honors forceGenerateOnce even when today page exists', async () => env: { H5_WECHAT_NEWS_MORNING_DRAFT_WORKER_ENABLED: '1' }, executeTask: async (task) => { executeCalls.push(task.taskSpec); + fs.writeFileSync(path.join(publicDir, 'daily-news-0911.html'), `${SAMPLE_HTML}`); }, intervalMs: 30_000, runOnStart: false, @@ -168,6 +169,10 @@ test('runOnce honors forceGenerateOnce even when today page exists', async () => assert.equal(config.forceGenerateOnce, false); assert.equal(pushCalls.length, 1); assert.equal(pushCalls[0].triggeredBy, 'manual-generate'); + assert.equal(fs.existsSync(path.join(publicDir, 'daily-news-0911.html')), true); + assert.ok( + fs.readdirSync(publicDir).some((name) => name.startsWith('_archived-daily-news-0911-')), + ); } finally { Date.now = originalNow; fs.rmSync(tmpRoot, { recursive: true, force: true }); @@ -203,6 +208,7 @@ test('generateToday skips existing page unless force is set', async () => { env: { H5_WECHAT_NEWS_MORNING_DRAFT_WORKER_ENABLED: '1' }, executeTask: async (task) => { executeCalls.push(task.taskSpec); + fs.writeFileSync(path.join(publicDir, 'daily-news-0911.html'), `${SAMPLE_HTML}`); }, prefetchNewsSearch: async () => '【专用联网搜索预取】国内国际热门事件', intervalMs: 30_000, @@ -223,6 +229,10 @@ test('generateToday skips existing page unless force is set', async () => { assert.match(executeCalls[0], /tkmind_search/u); assert.match(executeCalls[0], /专用联网搜索预取/u); assert.match(executeCalls[0], /国内国际热门事件/u); + assert.match(fs.readFileSync(path.join(publicDir, 'daily-news-0911.html'), 'utf8'), /forced/); + assert.ok( + fs.readdirSync(publicDir).some((name) => name.startsWith('_archived-daily-news-0911-')), + ); } finally { fs.rmSync(tmpRoot, { recursive: true, force: true }); }