Include three compact history items in WeChat morning draft inline body.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-09-24 11:27:40 +08:00
parent 2afe7df4a5
commit dbb16f0678
2 changed files with 92 additions and 3 deletions
+49 -3
View File
@@ -181,6 +181,18 @@ function extractClassDivBlocks(parentHtml, classPrefix) {
return blocks;
}
function extractHistoryItemBlocks(parentHtml) {
const source = String(parentHtml ?? '');
const blocks = [];
const re = /<(?:div|li)\s+class="history-item[^"]*"[^>]*>[\s\S]*?<\/(?:div|li)>/gi;
let match = re.exec(source);
while (match) {
blocks.push(match[0]);
match = re.exec(source);
}
return blocks;
}
function isNews002Html(html) {
const source = String(html ?? '');
if (/\bclass="[^"]*\bmasthead\b/u.test(source)) return true;
@@ -608,6 +620,28 @@ function renderWeatherSection(sectionHtml, { sectionId = 'weather', maxDetailCha
return parts.filter(Boolean).join('');
}
function renderHistorySection(sectionHtml, { maxItems = 3, maxBodyChars = 72 } = {}) {
const title = extractInnerHtml(sectionHtml, /<div class="section-title"[^>]*>([\s\S]*?)<\/div>/i);
const items = extractHistoryItemBlocks(sectionHtml)
.slice(0, maxItems)
.map((item) => {
const year = stripInlineText(extractInnerHtml(item, /<span class="hy"[^>]*>([\s\S]*?)<\/span>/i));
const event = truncatePlainText(
stripInlineText(extractInnerHtml(item, /<span class="he"[^>]*>([\s\S]*?)<\/span>/i)),
maxBodyChars,
);
if (!year || !event) return '';
return [
`<section style="margin:0 0 8px;background:${BRAND.tintRed};border-radius:10px;padding:11px 12px">`,
`<p style="margin:0;font-size:14px;color:${BRAND.ink};line-height:1.65"><strong style="color:${BRAND.red}">${year}</strong> · ${event}</p>`,
'</section>',
].join('');
})
.filter(Boolean);
if (items.length === 0) return '';
return [renderSectionTitle(title, 'history'), ...items].join('');
}
function renderKnowledgeSection(sectionHtml, { maxItems = 4, maxBodyChars = 130 } = {}) {
const title = extractInnerHtml(sectionHtml, /<div class="section-title"[^>]*>([\s\S]*?)<\/div>/i);
const items = extractClassDivBlocks(sectionHtml, 'knowledge-item')
@@ -767,7 +801,7 @@ const DEFAULT_CARD_BODY_CHARS = 132;
const MIN_CARDS_TO_KEEP = 16;
const BASE_TRIM_FLAGS = Object.freeze({
skipHistory: true,
skipHistory: false,
skipKnowledge: false,
skipWeather: false,
skipQuickLinks: true,
@@ -870,10 +904,12 @@ function resolveSectionCardLimit(section, sectionCardLimits) {
function shouldSkipSection(section, trimProfile) {
if (!section) return true;
if (section.id === 'hot') return true;
if (section.id === 'history') return true;
if (section.id === 'history') return trimProfile?.skipHistory === true;
if (section.id === 'knowledge' && trimProfile?.skipKnowledge === true) return true;
if (trimProfile?.skipSectionIds?.includes(section.id)) return true;
return /历史上的今天|近7天新闻早报/u.test(section.title);
if (/近7天新闻早报/u.test(section.title)) return true;
if (/历史上的今天/u.test(section.title) && trimProfile?.skipHistory !== false) return true;
return false;
}
function renderPageFooter(html) {
@@ -1006,6 +1042,15 @@ function buildWechatInlineContent(html, {
continue;
}
if (section.id === 'history') {
const rendered = renderHistorySection(section.html);
if (rendered) {
contentParts.push(rendered);
renderedSectionCount += 1;
}
continue;
}
if (section.id === 'knowledge') {
const rendered = renderKnowledgeSection(section.html, {
maxItems: resolveSectionCardLimit(section, trimProfile.sectionCardLimits) ?? 4,
@@ -1228,6 +1273,7 @@ export const wechatDailyNewsInlineInternals = {
renderTodayDigest,
renderBriefStats,
renderWeatherSection,
renderHistorySection,
selectTouristWeatherCards,
isPopularTouristCityName,
renderKnowledgeSection,
+43
View File
@@ -91,6 +91,49 @@ test('buildWechatInlineContent renders weather and optional quick links', () =>
assert.match(built.content, /30°/u);
});
const HISTORY_HTML = `<!DOCTYPE html><html><body><div class="container">
<div class="hero"><h1>📰 每日新闻早报</h1></div>
<div class="section" id="headlines"><div class="section-title">要闻</div><div class="card"><h3>头条</h3><p>正文</p></div></div>
<div class="section" id="history">
<div class="section-title">📜 历史上的今天 · 9月24日</div>
<ol class="history-list">
<li class="history-item"><span class="hy">1949年</span><span class="he">中国人民政治协商会议第一届全体会议开幕。</span></li>
<li class="history-item"><span class="hy">1957年</span><span class="he">美国小石城中央高中发生种族融合冲突。</span></li>
<li class="history-item"><span class="hy">1996年</span><span class="he">《全面禁止核试验条约》在联合国开放签署。</span></li>
<li class="history-item"><span class="hy">2008年</span><span class="he">神舟七号载人飞船成功发射。</span></li>
</ol>
</div>
</div></body></html>`;
test('renderHistorySection renders up to three compact history items', () => {
const sections = wechatDailyNewsInlineInternals.splitSections(HISTORY_HTML);
const history = sections.find((item) => item.id === 'history');
const rendered = wechatDailyNewsInlineInternals.renderHistorySection(history.html);
assert.match(rendered, /历史上的今天 · 9月24日/u);
assert.match(rendered, /1949年/u);
assert.match(rendered, /1957年/u);
assert.match(rendered, /1996年/u);
assert.doesNotMatch(rendered, /2008年/u);
assert.match(rendered, /中国人民政治协商会议/u);
});
test('buildWechatInlineContent includes history snippet by default', () => {
const built = wechatDailyNewsInlineInternals.buildWechatInlineContent(HISTORY_HTML, {
includeFixedLayout: false,
});
assert.match(built.content, /历史上的今天 · 9月24日/u);
assert.match(built.content, /1949年/u);
assert.doesNotMatch(built.content, /2008年/u);
});
test('buildWechatInlineContent can skip history when trimProfile requests it', () => {
const built = wechatDailyNewsInlineInternals.buildWechatInlineContent(HISTORY_HTML, {
includeFixedLayout: false,
trimProfile: { skipHistory: true },
});
assert.doesNotMatch(built.content, /历史上的今天/u);
});
test('convertDailyNewsHtmlToWechatInlineArticle keeps weather when trimming', () => {
const article = convertDailyNewsHtmlToWechatInlineArticle(WEATHER_HTML, {
includeFixedLayout: false,