ech0-api.ts
· 3.8 KiB · TypeScript
Sin formato
// Ech0 API 工具函数
interface EssayData {
id: number;
content: string;
time: string;
tags: string[];
images?: string[];
}
/**
* 从Ech0 RSS获取动态数据
* @param apiUrl Ech0 API地址
* @returns 转换后的动态数据数组
*/
export async function fetchEch0Posts(apiUrl: string): Promise<EssayData[]> {
try {
const response = await fetch(`${apiUrl}/rss`);
if (!response.ok) {
throw new Error(`Failed to fetch Ech0 posts: ${response.status}`);
}
const xmlText = await response.text();
return parseRssData(xmlText);
} catch (error) {
console.error('Error fetching Ech0 posts:', error);
// 出错时返回空数组,避免页面崩溃
return [];
}
}
/**
* 解析RSS XML数据
* @param xmlText RSS XML文本
* @returns 转换后的动态数据数组
*/
function parseRssData(xmlText: string): EssayData[] {
// 使用正则表达式解析RSS数据,避免使用DOMParser(浏览器特有API)
const entryRegex = /<entry>([\s\S]*?)<\/entry>/g;
const entries: EssayData[] = [];
let match;
let index = 0;
while ((match = entryRegex.exec(xmlText)) !== null) {
const entryText = match[1];
index++;
// 提取更新时间
const updatedRegex = /<updated>([\s\S]*?)<\/updated>/;
const updatedMatch = entryText.match(updatedRegex);
const updated = updatedMatch ? updatedMatch[1] : '';
// 提取摘要(使用更宽松的正则表达式,支持换行符)
const summaryRegex = /<summary[^>]*>([\s\S]*?)<\/summary>/i;
const summaryMatch = entryText.match(summaryRegex);
const summary = summaryMatch ? summaryMatch[1] : '';
// 提取纯文本内容
const content = extractPlainText(summary);
// 提取图片
const images = extractImages(summary);
entries.push({
id: index,
content,
time: formatDate(updated),
tags: ['生活'], // 默认标签
images: images.length > 0 ? images : undefined
});
}
// 按ID倒序排列
return entries.sort((a, b) => b.id - a.id);
}
/**
* 从HTML中提取纯文本
* @param html HTML文本
* @returns 纯文本
*/
function extractPlainText(html: string): string {
// 解码HTML实体
let decodedHtml = html
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/
/g, '\n');
// 使用正则表达式移除HTML标签
let plainText = decodedHtml.replace(/<[^>]*>/g, '').trim();
// 如果纯文本为空,说明可能是纯图片的说说,返回一个占位符
return plainText || '[图片]';
}
/**
* 从HTML中提取图片URL
* @param html HTML文本
* @returns 图片URL数组
*/
function extractImages(html: string): string[] {
console.log('原始HTML:', html);
// 解码HTML实体
let decodedHtml = html
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/"/g, '"')
.replace(/'/g, "'");
console.log('解码后HTML:', decodedHtml);
// 使用更宽松的正则表达式提取图片URL
const imgRegex = /<img[^>]*src=["']([^"']+)["']/gi;
const images: string[] = [];
let match;
while ((match = imgRegex.exec(decodedHtml)) !== null) {
let url = match[1];
console.log('找到图片URL:', url);
// 将HTTP URL转换为HTTPS
if (url.startsWith('http://')) {
url = url.replace('http://', 'https://');
console.log('转换为HTTPS:', url);
}
images.push(url);
}
console.log('最终图片数组:', images);
return images;
}
/**
* 格式化日期
* @param dateString ISO日期字符串
* @returns YYYY-MM-DD格式的日期字符串
*/
function formatDate(dateString: string): string {
const date = new Date(dateString);
return date.toISOString().split('T')[0];
}
| 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 | } |
| 151 |