175 lines
4.0 KiB
JavaScript
175 lines
4.0 KiB
JavaScript
#!/usr/bin/env node
|
||
|
||
/**
|
||
* 飞书卡片消息格式化
|
||
* 生成可点击链接的富文本卡片
|
||
*/
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
const DAILY_DIR = path.join(__dirname, '../../daily');
|
||
|
||
function getYesterdayDate() {
|
||
const d = new Date();
|
||
d.setDate(d.getDate() - 1);
|
||
return d.toLocaleDateString('zh-CN', {
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit',
|
||
timeZone: 'Asia/Shanghai'
|
||
}).replace(/\//g, '-');
|
||
}
|
||
|
||
function parseMarkdown(markdown) {
|
||
const lines = markdown.split('\n');
|
||
const items = [];
|
||
let currentTime = '';
|
||
let totalItems = 0;
|
||
|
||
// 解析元数据
|
||
for (let i = 0; i < lines.length; i++) {
|
||
const line = lines[i];
|
||
if (line.startsWith('> 采集时间:')) {
|
||
currentTime = line.replace('> 采集时间:', '').trim();
|
||
}
|
||
if (line.startsWith('> 总条目:')) {
|
||
totalItems = parseInt(line.replace('> 总条目:', '').trim());
|
||
}
|
||
}
|
||
|
||
// 解析新闻条目
|
||
const itemRegex = /^(\d+)\.\s+\[([^\]]+)\]\(([^)]+)\)\s+-\s+\*\*([^*]+)\*\*/;
|
||
let currentItem = null;
|
||
|
||
for (let i = 0; i < lines.length; i++) {
|
||
const line = lines[i];
|
||
const match = line.match(itemRegex);
|
||
|
||
if (match) {
|
||
if (currentItem) {
|
||
items.push(currentItem);
|
||
}
|
||
|
||
// 清理URL
|
||
let url = match[3];
|
||
let title = match[2];
|
||
|
||
if (url.includes('login?return_to=')) {
|
||
const realPath = decodeURIComponent(url.split('return_to=')[1]);
|
||
url = `https://github.com${realPath}`;
|
||
title = realPath.replace('/', '');
|
||
}
|
||
|
||
currentItem = {
|
||
number: match[1],
|
||
title: title,
|
||
url: url,
|
||
source: match[4],
|
||
description: ''
|
||
};
|
||
} else if (currentItem && line.trim().startsWith('>') && !line.includes('采集时间') && !line.includes('总条目')) {
|
||
currentItem.description = line.replace(/^\s*>\s*/, '').trim();
|
||
}
|
||
}
|
||
|
||
if (currentItem) {
|
||
items.push(currentItem);
|
||
}
|
||
|
||
return { currentTime, totalItems, items };
|
||
}
|
||
|
||
function createFeishuCard(data) {
|
||
const { currentTime, totalItems, items } = data;
|
||
|
||
const elements = [
|
||
{
|
||
tag: "div",
|
||
text: {
|
||
tag: "lark_md",
|
||
content: `**⏰ 采集时间**: ${currentTime}\n**📊 总条目**: ${totalItems}条`
|
||
}
|
||
},
|
||
{
|
||
tag: "hr"
|
||
}
|
||
];
|
||
|
||
// 添加新闻条目
|
||
items.forEach((item, index) => {
|
||
const num = ['1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣', '🔟'][index] || `${index + 1}.`;
|
||
|
||
elements.push({
|
||
tag: "div",
|
||
text: {
|
||
tag: "lark_md",
|
||
content: `${num} **${item.title}**\n\`${item.source}\`\n> ${item.description}\n[🔗 点击查看详情](${item.url})`
|
||
}
|
||
});
|
||
|
||
// 每条之间加分隔线(除了最后一条)
|
||
if (index < items.length - 1) {
|
||
elements.push({
|
||
tag: "hr"
|
||
});
|
||
}
|
||
});
|
||
|
||
// 添加底部提示
|
||
elements.push({
|
||
tag: "hr"
|
||
});
|
||
elements.push({
|
||
tag: "note",
|
||
elements: [
|
||
{
|
||
tag: "plain_text",
|
||
content: "💡 点击链接跳转到GitHub查看详情\n*Generated by AINewsCollector*"
|
||
}
|
||
]
|
||
});
|
||
|
||
return {
|
||
msg_type: "interactive",
|
||
card: {
|
||
header: {
|
||
title: {
|
||
tag: "plain_text",
|
||
content: `📰 AI Daily Brief - ${getYesterdayDate()}`
|
||
},
|
||
template: "blue"
|
||
},
|
||
elements: elements
|
||
}
|
||
};
|
||
}
|
||
|
||
async function main() {
|
||
const yesterday = getYesterdayDate();
|
||
const reportPath = path.join(DAILY_DIR, `${yesterday}.md`);
|
||
|
||
if (!fs.existsSync(reportPath)) {
|
||
console.log(`❌ 未找到昨日简报: ${reportPath}`);
|
||
return { success: false, error: 'Report not found' };
|
||
}
|
||
|
||
const markdown = fs.readFileSync(reportPath, 'utf8');
|
||
const data = parseMarkdown(markdown);
|
||
const card = createFeishuCard(data);
|
||
|
||
console.log(JSON.stringify(card, null, 2));
|
||
|
||
return {
|
||
success: true,
|
||
date: yesterday,
|
||
card: card
|
||
};
|
||
}
|
||
|
||
if (require.main === module) {
|
||
main().catch(console.error);
|
||
}
|
||
|
||
module.exports = { main, createFeishuCard, parseMarkdown };
|