|
| 1 | +// Ech0 API 工具函数 |
| 2 | + |
| 3 | +interface EssayData { |
| 4 | + id: number; |
| 5 | + content: string; |
| 6 | + time: string; |
| 7 | + tags: string[]; |
| 8 | + images?: string[]; |
| 9 | +} |
| 10 | + |
| 11 | +/** |
| 12 | + * 从Ech0 RSS获取动态数据 |
| 13 | + * @param apiUrl Ech0 API地址 |
| 14 | + * @returns 转换后的动态数据数组 |
| 15 | + */ |
| 16 | +export async function fetchEch0Posts(apiUrl: string): Promise<EssayData[]> { |
| 17 | + try { |
| 18 | + const response = await fetch(`${apiUrl}/rss`); |
| 19 | + |
| 20 | + if (!response.ok) { |
| 21 | + throw new Error(`Failed to fetch Ech0 posts: ${response.status}`); |
| 22 | + } |
| 23 | + |
| 24 | + const xmlText = await response.text(); |
| 25 | + return parseRssData(xmlText); |
| 26 | + } catch (error) { |
| 27 | + console.error('Error fetching Ech0 posts:', error); |
| 28 | + // 出错时返回空数组,避免页面崩溃 |
| 29 | + return []; |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +/** |
| 34 | + * 解析RSS XML数据 |
| 35 | + * @param xmlText RSS XML文本 |
| 36 | + * @returns 转换后的动态数据数组 |
| 37 | + */ |
| 38 | +function parseRssData(xmlText: string): EssayData[] { |
| 39 | + // 使用正则表达式解析RSS数据,避免使用DOMParser(浏览器特有API) |
| 40 | + const entryRegex = /<entry>([\s\S]*?)<\/entry>/g; |
| 41 | + const entries: EssayData[] = []; |
| 42 | + let match; |
| 43 | + |
| 44 | + let index = 0; |
| 45 | + while ((match = entryRegex.exec(xmlText)) !== null) { |
| 46 | + const entryText = match[1]; |
| 47 | + index++; |
| 48 | + |
| 49 | + // 提取更新时间 |
| 50 | + const updatedRegex = /<updated>([\s\S]*?)<\/updated>/; |
| 51 | + const updatedMatch = entryText.match(updatedRegex); |
| 52 | + const updated = updatedMatch ? updatedMatch[1] : ''; |
| 53 | + |
| 54 | + // 提取摘要(使用更宽松的正则表达式,支持换行符) |
| 55 | + const summaryRegex = /<summary[^>]*>([\s\S]*?)<\/summary>/i; |
| 56 | + const summaryMatch = entryText.match(summaryRegex); |
| 57 | + const summary = summaryMatch ? summaryMatch[1] : ''; |
| 58 | + |
| 59 | + // 提取纯文本内容 |
| 60 | + const content = extractPlainText(summary); |
| 61 | + |
| 62 | + // 提取图片 |
| 63 | + const images = extractImages(summary); |
| 64 | + |
| 65 | + entries.push({ |
| 66 | + id: index, |
| 67 | + content, |
| 68 | + time: formatDate(updated), |
| 69 | + tags: ['生活'], // 默认标签 |
| 70 | + images: images.length > 0 ? images : undefined |
| 71 | + }); |
| 72 | + } |
| 73 | + |
| 74 | + // 按ID倒序排列 |
| 75 | + return entries.sort((a, b) => b.id - a.id); |
| 76 | +} |
| 77 | + |
| 78 | +/** |
| 79 | + * 从HTML中提取纯文本 |
| 80 | + * @param html HTML文本 |
| 81 | + * @returns 纯文本 |
| 82 | + */ |
| 83 | +function extractPlainText(html: string): string { |
| 84 | + // 解码HTML实体 |
| 85 | + let decodedHtml = html |
| 86 | + .replace(/</g, '<') |
| 87 | + .replace(/>/g, '>') |
| 88 | + .replace(/&/g, '&') |
| 89 | + .replace(/"/g, '"') |
| 90 | + .replace(/"/g, '"') |
| 91 | + .replace(/'/g, "'") |
| 92 | + .replace(/
/g, '\n'); |
| 93 | + |
| 94 | + // 使用正则表达式移除HTML标签 |
| 95 | + let plainText = decodedHtml.replace(/<[^>]*>/g, '').trim(); |
| 96 | + |
| 97 | + // 如果纯文本为空,说明可能是纯图片的说说,返回一个占位符 |
| 98 | + return plainText || '[图片]'; |
| 99 | +} |
| 100 | + |
| 101 | +/** |
| 102 | + * 从HTML中提取图片URL |
| 103 | + * @param html HTML文本 |
| 104 | + * @returns 图片URL数组 |
| 105 | + */ |
| 106 | +function extractImages(html: string): string[] { |
| 107 | + console.log('原始HTML:', html); |
| 108 | + |
| 109 | + // 解码HTML实体 |
| 110 | + let decodedHtml = html |
| 111 | + .replace(/</g, '<') |
| 112 | + .replace(/>/g, '>') |
| 113 | + .replace(/&/g, '&') |
| 114 | + .replace(/"/g, '"') |
| 115 | + .replace(/"/g, '"') |
| 116 | + .replace(/'/g, "'"); |
| 117 | + |
| 118 | + console.log('解码后HTML:', decodedHtml); |
| 119 | + |
| 120 | + // 使用更宽松的正则表达式提取图片URL |
| 121 | + const imgRegex = /<img[^>]*src=["']([^"']+)["']/gi; |
| 122 | + const images: string[] = []; |
| 123 | + let match; |
| 124 | + |
| 125 | + while ((match = imgRegex.exec(decodedHtml)) !== null) { |
| 126 | + let url = match[1]; |
| 127 | + console.log('找到图片URL:', url); |
| 128 | + |
| 129 | + // 将HTTP URL转换为HTTPS |
| 130 | + if (url.startsWith('http://')) { |
| 131 | + url = url.replace('http://', 'https://'); |
| 132 | + console.log('转换为HTTPS:', url); |
| 133 | + } |
| 134 | + |
| 135 | + images.push(url); |
| 136 | + } |
| 137 | + |
| 138 | + console.log('最终图片数组:', images); |
| 139 | + return images; |
| 140 | +} |
| 141 | + |
| 142 | +/** |
| 143 | + * 格式化日期 |
| 144 | + * @param dateString ISO日期字符串 |
| 145 | + * @returns YYYY-MM-DD格式的日期字符串 |
| 146 | + */ |
| 147 | +function formatDate(dateString: string): string { |
| 148 | + const date = new Date(dateString); |
| 149 | + return date.toISOString().split('T')[0]; |
| 150 | +} |
0 commit comments