diff --git a/news-morning-page-blocks.mjs b/news-morning-page-blocks.mjs new file mode 100644 index 0000000..6a886af --- /dev/null +++ b/news-morning-page-blocks.mjs @@ -0,0 +1,86 @@ +/** + * news002 早报页固定区块:订阅引导、历史上的今天、封面图候选。 + * 纯函数,供模板 spec 与 draft 推送共用。 + */ + +export function resolveNewsMorningSubscribeBindUrl(env = process.env) { + const explicit = String(env.H5_WECHAT_NEWS_MORNING_SUBSCRIBE_BIND_URL ?? '').trim(); + if (explicit) return explicit; + const bindPath = String(env.H5_WECHAT_MP_BIND_PATH ?? '/bind').trim() || '/bind'; + if (/^https?:\/\//i.test(bindPath)) return bindPath; + const base = String( + env.H5_WECHAT_MP_PUBLIC_BASE_URL + ?? env.H5_PUBLIC_BASE_URL + ?? 'https://m.tkmind.cn', + ).trim().replace(/\/+$/, ''); + return `${base}${bindPath.startsWith('/') ? bindPath : `/${bindPath}`}`; +} + +export function resolveNewsMorningPushSubscriptionId(env = process.env) { + const raw = String(env.H5_WECHAT_NEWS_MORNING_PUSH_SUBSCRIPTION_ID ?? '2').trim(); + return /^\d+$/.test(raw) ? raw : '2'; +} + +export function buildNewsMorningSubscribeBlockSpec(env = process.env) { + const bindUrl = resolveNewsMorningSubscribeBindUrl(env); + const subId = resolveNewsMorningPushSubscriptionId(env); + return [ + '`.subscribe` 订阅引导(必须放在 history 之前):', + `- 按钮:\`立即订阅\`(禁止 href="#masthead" 或 # 空链)`, + `- 副文案两行:① 点此完成微信账号绑定;② 绑定后回到本服务号,回复 **${subId}** 开通「每日新闻早报」推送(默认 07:30,可说「${subId}改到7点」调整)`, + '- 可加小字:未绑定时回复数字不会生效,须先完成绑定。', + ].join('\n'); +} + +export function buildNewsMorningHistorySectionSpec() { + return [ + 'id=history 栏目「历史上的今天」(禁止做成外链小卡片或往期早报链接):', + '- 结构:`
    ` + 6~7 条 `
  1. `', + '- 每条:`{四位年份}{与当天月日相关的可核实中外历史事件,20~45 字}`', + '- 须覆盖不同年代、中外各至少 2 条;禁止 `.h-grid` / `.h-item` / Wikipedia / checkiday 等外链占位', + '- 禁止只写「历史/节日/足球」等标签词而不写具体事件', + ].join('\n'); +} + +export function collectNewsMorningCoverImageCandidates(html) { + const source = String(html ?? ''); + const candidates = []; + const seen = new Set(); + const push = (url) => { + const normalized = String(url ?? '') + .trim() + .replace(/&/gi, '&') + .replace(/"/gi, '"'); + if (!normalized || /^data:/i.test(normalized) || seen.has(normalized)) return; + seen.add(normalized); + candidates.push(normalized); + }; + + for (const match of source.matchAll( + /]*\blead-card\b[^>]*>[\s\S]*?]*\bsrc=["']([^"']+)["']/gi, + )) { + push(match[1]); + } + + const headlinesBlock = source.match( + /
    \s*<\/div>\s*