import { extractPageTitle } from './wechat/verify/share-preview-repair.mjs'; const MAX_WECHAT_CONTENT_CHARS = 20000; const MAX_WECHAT_CONTENT_TARGET_CHARS = 19600; const DEFAULT_PORTAL_URL = 'https://m.tkmind.cn'; const CARD_VARIANTS = { 'highlight-box': { wrap: 'background:linear-gradient(135deg,#b71c1c,#d32f2f);border-radius:12px;padding:14px;margin:0 0 10px;color:#fff;', title: 'margin:0 0 6px;font-size:16px;font-weight:700;color:#fff;line-height:1.5;', body: 'margin:0 0 6px;font-size:14px;line-height:1.7;color:#ffcdd2;', source: 'margin:0;font-size:12px;color:#90caf4;', tag: 'display:inline-block;font-size:11px;padding:2px 8px;border-radius:4px;margin:0 0 6px;background:rgba(255,255,255,.18);color:#fff;', }, 'highlight-box-orange': { wrap: 'background:linear-gradient(135deg,#e65100,#bf360c);border-radius:12px;padding:14px;margin:0 0 10px;color:#fff;', title: 'margin:0 0 6px;font-size:16px;font-weight:700;color:#fff;line-height:1.5;', body: 'margin:0 0 6px;font-size:14px;line-height:1.7;color:#ffe0b2;', source: 'margin:0;font-size:12px;color:#ffcdd2;', tag: 'display:inline-block;font-size:11px;padding:2px 8px;border-radius:4px;margin:0 0 6px;background:rgba(255,255,255,.18);color:#fff;', }, 'highlight-box-gold': { wrap: 'background:linear-gradient(135deg,#0d47a1,#1565c0);border-radius:12px;padding:14px;margin:0 0 10px;color:#fff;', title: 'margin:0 0 6px;font-size:16px;font-weight:700;color:#fff;line-height:1.5;', body: 'margin:0 0 6px;font-size:14px;line-height:1.7;color:#bbdefb;', source: 'margin:0;font-size:12px;color:#bbdefb;', tag: 'display:inline-block;font-size:11px;padding:2px 8px;border-radius:4px;margin:0 0 6px;background:rgba(255,255,255,.18);color:#fff;', }, 'highlight-box-teal': { wrap: 'background:linear-gradient(135deg,#004d40,#00695c);border-radius:12px;padding:14px;margin:0 0 10px;color:#fff;', title: 'margin:0 0 6px;font-size:16px;font-weight:700;color:#fff;line-height:1.5;', body: 'margin:0 0 6px;font-size:14px;line-height:1.7;color:#b2dfdb;', source: 'margin:0;font-size:12px;color:#b2dfdb;', tag: 'display:inline-block;font-size:11px;padding:2px 8px;border-radius:4px;margin:0 0 6px;background:rgba(255,255,255,.18);color:#fff;', }, default: { wrap: 'background:#fff;border-radius:12px;padding:14px;margin:0 0 10px;', title: 'margin:0 0 4px;font-size:16px;font-weight:600;color:#1a202c;line-height:1.5;', body: 'margin:0 0 6px;font-size:14px;color:#4a5568;line-height:1.7;', source: 'margin:0;font-size:12px;color:#a0aec0;', tag: 'display:inline-block;font-size:11px;padding:2px 8px;border-radius:4px;margin:0 0 6px;background:#ffebee;color:#b71c1c;', }, }; const TAG_CLASS_COLORS = { 'tag-red': 'background:#ffcdd2;color:#b71c1c;', 'tag-blue': 'background:#bbdefb;color:#0d47a1;', 'tag-green': 'background:#c8e6c9;color:#1b5e20;', 'tag-purple': 'background:#e1bee7;color:#6a1b9a;', 'tag-orange': 'background:#ffe0b2;color:#e65100;', 'tag-teal': 'background:#b2dfdb;color:#004d40;', 'tag-pink': 'background:#f8bbd0;color:#880e4f;', 'tag-gray': 'background:#e0e0e0;color:#424242;', 'tag-amber': 'background:#ffecb3;color:#ff6f00;', }; function extractMetaDescription(html) { const match = String(html ?? '').match( /]+name=["']description["'][^>]+content=["']([^"']*)["']/i, ); return match?.[1]?.trim() ?? ''; } function stripScripts(html) { return String(html ?? '').replace(//gi, ''); } function sanitizeInlineHtml(html) { return stripScripts(String(html ?? '')) .replace(/<(?!\/?(a\b|br\b|strong\b|span\b|b\b|em\b|i\b)\b)[^>]+>/gi, '') .replace(/\son\w+="[^"]*"/gi, '') .trim(); } function extractInnerHtml(block, pattern) { const match = String(block ?? '').match(pattern); return match?.[1] ? sanitizeInlineHtml(match[1]) : ''; } function detectCardVariant(cardHtml) { if (/highlight-box-orange/u.test(cardHtml)) return 'highlight-box-orange'; if (/highlight-box-gold/u.test(cardHtml)) return 'highlight-box-gold'; if (/highlight-box-teal/u.test(cardHtml)) return 'highlight-box-teal'; if (/highlight-box/u.test(cardHtml)) return 'highlight-box'; return 'default'; } function renderTagHtml(cardHtml, styles) { const tagMatch = String(cardHtml).match(/]*(?:style="([^"]*)")?[^>]*>([\s\S]*?)<\/span>/i); if (!tagMatch) return ''; const className = tagMatch[1]?.trim() ?? ''; const inlineStyle = tagMatch[2]?.trim() ?? ''; const label = sanitizeInlineHtml(tagMatch[3]); if (!label) return ''; const colorStyle = TAG_CLASS_COLORS[className.replace(/^\s+/, '')] ?? ''; const style = inlineStyle || colorStyle || styles.tag; return `${label}`; } function renderCard(cardHtml) { const variant = detectCardVariant(cardHtml); const styles = CARD_VARIANTS[variant] ?? CARD_VARIANTS.default; const tag = renderTagHtml(cardHtml, styles); const title = extractInnerHtml(cardHtml, /]*>([\s\S]*?)<\/h3>/i); const body = extractInnerHtml(cardHtml, /]*>([\s\S]*?)<\/p>/i); const sourceRaw = extractInnerHtml(cardHtml, /
]*>([\s\S]*?)<\/div>/i); const source = sourceRaw.replace(/^来源:?/u, '').trim(); if (!title) return ''; const parts = [ `
`, tag ? `

${tag}

` : '', `

${title}

`, body ? `

${body}

` : '', source ? `

来源:${source}

` : '', '
', ]; return parts.filter(Boolean).join(''); } function renderSectionTitle(titleHtml) { const text = sanitizeInlineHtml(titleHtml).replace(/]*>([\s\S]*?)<\/span>/gi, '$1'); if (!text) return ''; return `

${text}

`; } function renderHero(html) { const title = sanitizeInlineHtml(String(html).match(/]*>([\s\S]*?)<\/h1>/i)?.[1] ?? '') || '📰 每日新闻早报'; const dateBadge = sanitizeInlineHtml(String(html).match(/
]*>([\s\S]*?)<\/div>/i)?.[1] ?? ''); const subtitle = sanitizeInlineHtml(String(html).match(/
]*>([\s\S]*?)<\/div>/i)?.[1] ?? ''); return [ '
', `

${title}

`, dateBadge ? `

${dateBadge}

` : '', subtitle ? `

${subtitle}

` : '', '
', ].filter(Boolean).join(''); } function renderReadOriginalTop(publicUrl) { if (!publicUrl) return ''; return [ '
', `📖 点击阅读原文`, '

查看完整排版、图片与更多栏目

', '
', ].join(''); } function renderCreatePortalCTA(portalUrl = DEFAULT_PORTAL_URL) { return `

✨ 一起创作 → 点我

`; } function renderFollowMpSection(qrcodeImageUrl = '') { if (qrcodeImageUrl) { return [ '
', '

📣 关注 TKMind 服务号

', '

长按扫描关注,每日早报不错过

', `TKMind 服务号二维码`, '

长按扫描关注

', '
', ].join(''); } return [ '
', '

📣 关注 TKMind 服务号

', '

推送草稿时将嵌入公众号二维码

', '
', ].join(''); } function renderWeatherSection(sectionHtml) { const title = extractInnerHtml(sectionHtml, /
]*>([\s\S]*?)<\/div>/i); const summary = extractInnerHtml(sectionHtml, /
]*>([\s\S]*?)<\/div>/i); const cityCards = [...String(sectionHtml).matchAll(/
]*>[\s\S]*?([\s\S]*?)<\/span>[\s\S]*?([\s\S]*?)<\/span>[\s\S]*?([\s\S]*?)<\/span>/gi)] .map((item) => `${sanitizeInlineHtml(item[1])}${sanitizeInlineHtml(item[2])} ${sanitizeInlineHtml(item[3])}`) .slice(0, 12); const footer = extractInnerHtml(sectionHtml, /

([\s\S]*?)<\/p>/i); const parts = [renderSectionTitle(title)]; parts.push('

'); if (summary) { parts.push(`

${summary.replace(/]*>/gi, ' ').replace(/<\/div>/gi, ' ')}

`); } if (cityCards.length > 0) { parts.push(`

${cityCards.join(' · ')}

`); } parts.push('
'); if (footer) { parts.push(`

${footer}

`); } return parts.join(''); } function splitSections(html) { const body = String(html ?? '').match(/([\s\S]*?)<\/body>/i)?.[1] ?? String(html ?? ''); return body .split(/
]*>/i) .slice(1) .map((chunk) => { const id = chunk.match(/^[^>]*id="([^"]+)"/i)?.[1] ?? ''; const htmlChunk = `
]*>([\s\S]*?)<\/div>/i)); return { id, title, html: htmlChunk }; }); } function stripInlineText(value) { return sanitizeInlineHtml(String(value ?? '')) .replace(/]*>([\s\S]*?)<\/span>/gi, '$1') .replace(/<[^>]+>/g, '') .replace(/\s+/g, ' ') .trim(); } const DEFAULT_SECTION_CARD_LIMITS = { headlines: 6, world: 3, domestic: 3, google: 2, finance: 3, tech: 3, sports: 2, technews: 2, hot: 1, }; const TRIM_PROFILES = [ { skipHistory: true, sectionCardLimits: null, maxBodyChars: null }, { skipHistory: true, sectionCardLimits: DEFAULT_SECTION_CARD_LIMITS, maxBodyChars: 120, }, { skipHistory: true, sectionCardLimits: { ...DEFAULT_SECTION_CARD_LIMITS, headlines: 5, world: 2, domestic: 2 }, maxBodyChars: 90, }, { skipHistory: true, sectionCardLimits: { headlines: 4, world: 2, domestic: 2, google: 2, finance: 2, tech: 2, sports: 1, technews: 1, hot: 1 }, maxBodyChars: 72, }, { skipHistory: true, sectionCardLimits: { headlines: 3, world: 2, domestic: 2, google: 2, finance: 2, tech: 2, sports: 1, technews: 0, hot: 1 }, maxBodyChars: 64, }, { skipHistory: true, sectionCardLimits: { headlines: 3, world: 2, domestic: 2, google: 1, finance: 2, tech: 2, sports: 1, technews: 0, hot: 0 }, maxBodyChars: 56, }, ]; function buildFallbackTrimProfiles() { const profiles = []; for (let headlines = 3; headlines >= 2; headlines -= 1) { for (let maxBodyChars = 56; maxBodyChars >= 24; maxBodyChars -= 8) { for (const skipWeather of [false, true]) { profiles.push({ skipHistory: true, skipWeather, sectionCardLimits: { headlines, world: 2, domestic: 2, google: 1, finance: 2, tech: 2, sports: 1, technews: 0, hot: 0, }, maxBodyChars, }); } } } return profiles; } function resolveSectionCardLimit(section, sectionCardLimits) { if (!sectionCardLimits) return null; return sectionCardLimits[section.id] ?? 3; } function estimateQrcodeUrlForLayout(qrcodeImageUrl = '') { const url = String(qrcodeImageUrl ?? ''); if (!url) return ''; if (url.length >= 180) return url; return `${url}${'x'.repeat(180 - url.length)}`; } function estimateFixedLayoutLength({ publicUrl = '', qrcodeImageUrl = '', portalUrl = DEFAULT_PORTAL_URL } = {}) { const qrcodeForEstimate = estimateQrcodeUrlForLayout(qrcodeImageUrl); return ( (publicUrl ? renderReadOriginalTop(publicUrl).length : 0) + renderFollowMpSection(qrcodeForEstimate).length + renderCreatePortalCTA(portalUrl).length ); } function buildWechatInlineContent(html, { publicUrl = '', qrcodeImageUrl = '', portalUrl = DEFAULT_PORTAL_URL, trimProfile = TRIM_PROFILES[0], includeFixedLayout = true, } = {}) { const sections = splitSections(html); const bodyParts = [renderHero(html)]; for (const section of sections) { if (trimProfile.skipHistory && shouldSkipSection(section, trimProfile)) { continue; } if (resolveSectionCardLimit(section, trimProfile.sectionCardLimits) === 0) { continue; } if (section.id === 'weather') { if (!trimProfile.skipWeather) { bodyParts.push(renderWeatherSection(section.html)); } continue; } bodyParts.push(renderGenericSection(section.html, { maxCards: resolveSectionCardLimit(section, trimProfile.sectionCardLimits), maxBodyChars: trimProfile.maxBodyChars, })); } bodyParts.push(renderFooter(html)); const ordered = [...bodyParts]; if (includeFixedLayout) { if (publicUrl) ordered.splice(1, 0, renderReadOriginalTop(publicUrl)); ordered.push(renderFollowMpSection(qrcodeImageUrl)); ordered.push(renderCreatePortalCTA(portalUrl)); } return { content: ordered.join(''), sectionCount: sections.length, renderedSectionCount: sections.filter((section) => { if (trimProfile.skipHistory && shouldSkipSection(section, trimProfile)) return false; if (resolveSectionCardLimit(section, trimProfile.sectionCardLimits) === 0) return false; return true; }).length, }; } function truncatePlainText(value, maxChars) { const text = String(value ?? '').replace(/\s+/g, ' ').trim(); if (!maxChars || text.length <= maxChars) return text; return `${text.slice(0, Math.max(0, maxChars - 1))}…`; } function shouldSkipSection(section, trimProfile) { if (!section) return true; if (['history', 'knowledge'].includes(section.id)) return true; if (trimProfile?.skipSectionIds?.includes(section.id)) return true; return /历史上的今天|近7天新闻早报/u.test(section.title); } function renderGenericSection(sectionHtml, { maxCards = null, maxBodyChars = null } = {}) { const title = extractInnerHtml(sectionHtml, /
]*>([\s\S]*?)<\/div>/i); if (/近7天新闻早报/u.test(stripInlineText(title))) return ''; const cards = sectionHtml.split(/
]*>([\s\S]*?)<\/p>/i, (match, body) => { const plain = body.replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim(); return match.replace(body, truncatePlainText(plain, maxBodyChars)); }); } const rendered = renderCard(`