From 3c6740528e03a4b45488f84699ee0bd00be96a97 Mon Sep 17 00:00:00 2001
From: justlovemaki <274166795@qq.com>
Date: Sun, 15 Jun 2025 14:34:24 +0800
Subject: [PATCH] =?UTF-8?q?feat(rss):=20=E6=B7=BB=E5=8A=A0RSS=E8=AE=A2?=
=?UTF-8?q?=E9=98=85=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98=E5=8C=96=E6=97=A5?=
=?UTF-8?q?=E6=9C=9F=E5=A4=84=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在DEPLOYMENT.md中添加RSS_FEED_URL环境变量配置说明
- 修改日期处理函数,统一使用GMT时区格式
- 实现RSS订阅功能,支持通过Feedly等阅读器订阅
- 优化GitHub API调用的Base64编解码处理
- 更新README展示RSS订阅链接和访问方式
---
README.md | 11 ++++++---
docs/DEPLOYMENT.md | 1 +
src/foot.js | 17 ++++++-------
src/github.js | 45 +++++++++++++++++++++++++---------
src/handlers/commitToGitHub.js | 4 +--
src/handlers/genAIContent.js | 2 +-
src/handlers/getRss.js | 5 ++--
src/handlers/writeRssData.js | 9 ++++---
src/helpers.js | 33 ++++++++++++++++---------
9 files changed, 81 insertions(+), 46 deletions(-)
diff --git a/README.md b/README.md
index f4dc5c5..9834fcb 100644
--- a/README.md
+++ b/README.md
@@ -59,8 +59,13 @@
**在线阅读地址:**
-* 🌐 **主站点(GitHub Pages )**:[website-1](https://justlovemaki.github.io/CloudFlare-AI-Insight-Daily/today/book/)
-* 📖 **备用站点(Cloudflare)**:[website-2](https://ai-today.justlikemaki.vip/)
+你可以通过以下任一方式访问每日生成的最新资讯:
+
+| 访问方式 | 链接 | 状态 |
+| ----------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
+| 📡 **RSS 订阅** | [https://justlovemaki.github.io/CloudFlare-AI-Insight-Daily/rss.xml](https://justlovemaki.github.io/CloudFlare-AI-Insight-Daily/rss.xml) | 推荐使用 [Feedly](https://feedly.com/), [Folo](https://app.follow.is/) 等阅读器 |
+| 🌐 **主站点 (GitHub)** | [https://justlovemaki.github.io/CloudFlare-AI-Insight-Daily/today/book/](https://justlovemaki.github.io/CloudFlare-AI-Insight-Daily/today/book/) | ✅ 稳定 🚀 速度 |
+| 📖 **备用站点 (Cloudflare)** | [https://ai-today.justlikemaki.vip/](https://ai-today.justlikemaki.vip/) | |
**内容成果展示:**
@@ -70,7 +75,7 @@
|  |  |
-**项目截图:**
+**后台项目截图:**
| 网站首页 | 日报内容 | 播客脚本 |
| -------------------------------------- | -------------------------------------- | -------------------------------------- |
diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md
index 65cca21..32de825 100644
--- a/docs/DEPLOYMENT.md
+++ b/docs/DEPLOYMENT.md
@@ -172,6 +172,7 @@ TWITTER_FETCH_PAGES = "2"
* 在您的 GitHub 仓库页面,进入 `Settings` -> `Secrets and variables` -> `Actions`。
* 在 `Variables` 标签页,点击 `New repository variable`。
* 创建一个名为 `IMAGE_PROXY_URL` 的变量,值为您的代理服务地址,例如 `https://your-proxy.com/`。
+ * 创建一个名为 `RSS_FEED_URL` 的变量,值为您的后端服务地址,例如 `https://your-backend.com/rss`。
4. **🚀 触发 Action 并验证**
* 手动触发一次 `build-daily-book` 工作流,或等待其定时自动执行。
diff --git a/src/foot.js b/src/foot.js
index 9426e3c..b5036af 100644
--- a/src/foot.js
+++ b/src/foot.js
@@ -1,15 +1,14 @@
export function insertFoot() {
return `
- ---
+---
+
+**收听语音版**
+
+| 🎙️ **小宇宙** | 📹 **抖音** |
+| --- | --- |
+| [来生小酒馆](https://www.xiaoyuzhoufm.com/podcast/683c62b7c1ca9cf575a5030e) | [来生情报站](https://www.douyin.com/user/MS4wLjABAAAAwpwqPQlu38sO38VyWgw9ZjDEnN4bMR5j8x111UxpseHR9DpB6-CveI5KRXOWuFwG)|
+|  |  |
- **收听语音版**
-
- | 🎙️ **小宇宙** | 📹 **抖音** |
- | --- | --- |
- | [来生小酒馆](https://www.xiaoyuzhoufm.com/podcast/683c62b7c1ca9cf575a5030e) | [来生情报站](https://www.douyin.com/user/MS4wLjABAAAAwpwqPQlu38sO38VyWgw9ZjDEnN4bMR5j8x111UxpseHR9DpB6-CveI5KRXOWuFwG)|
- |  |  |
-
-
`;
}
diff --git a/src/github.js b/src/github.js
index c0ad1b5..cbc2365 100644
--- a/src/github.js
+++ b/src/github.js
@@ -75,7 +75,7 @@ export async function getGitHubFileSha(env, filePath) {
*/
export async function createOrUpdateGitHubFile(env, filePath, content, commitMessage, existingSha = null) {
const GITHUB_BRANCH = env.GITHUB_BRANCH || 'main';
- const base64Content = btoa(String.fromCharCode(...new TextEncoder().encode(content)));
+ const base64Content = b64EncodeUnicode(content);
const payload = {
message: commitMessage,
@@ -102,20 +102,41 @@ export async function getDailyReportContent(env, filePath) {
throw new Error("GitHub API configuration is missing in environment variables.");
}
- const rawUrl = `https://raw.githubusercontent.com/${GITHUB_REPO_OWNER}/${GITHUB_REPO_NAME}/${GITHUB_BRANCH}/${filePath}`;
- console.log(rawUrl)
try {
- const response = await fetch(rawUrl);
- if (!response.ok) {
- if (response.status === 404) {
- console.log(`File not found: ${filePath} on branch ${GITHUB_BRANCH}`);
- return null;
- }
- throw new Error(`Failed to fetch file from GitHub: ${response.status} ${response.statusText}`);
- }
- return await response.text();
+ const data = await callGitHubApi(env, `/contents/${filePath}?ref=${GITHUB_BRANCH}`);
+ return b64DecodeUnicode(data.content);
} catch (error) {
console.error(`Error fetching daily report content from ${rawUrl}:`, error);
throw error;
}
}
+
+// Base64 encode (UTF-8 safe)
+function b64EncodeUnicode(str) {
+ // Replacing '+' with '-' and '/' with '_' makes it URL-safe, but GitHub API expects standard Base64
+ // Using btoa directly after encodeURIComponent is standard
+ try {
+ return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
+ function toSolidBytes(match, p1) {
+ return String.fromCharCode('0x' + p1);
+ }));
+ } catch (e) {
+ console.error("Base64 Encoding Error:", e);
+ showStatus("Error: Could not encode content for GitHub.", true);
+ return null; // Return null on error
+ }
+}
+
+// Base64 decode (UTF-8 safe)
+function b64DecodeUnicode(str) {
+ try {
+ // Standard Base64 decoding
+ return decodeURIComponent(atob(str).split('').map(function(c) {
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
+ }).join(''));
+ } catch(e) {
+ console.error("Base64 Decoding Error:", e);
+ showStatus("Error: Could not decode file content from GitHub.", true);
+ return null; // Return null on error
+ }
+}
\ No newline at end of file
diff --git a/src/handlers/commitToGitHub.js b/src/handlers/commitToGitHub.js
index e10297b..6f113c7 100644
--- a/src/handlers/commitToGitHub.js
+++ b/src/handlers/commitToGitHub.js
@@ -1,5 +1,5 @@
// src/handlers/commitToGitHub.js
-import { getISODate, formatMarkdownText, replaceImageProxy,formatDateToChineseWithTime } from '../helpers.js';
+import { getISODate, formatMarkdownText, replaceImageProxy,formatDateToGMT0WithTime, sleep } from '../helpers.js';
import { getGitHubFileSha, createOrUpdateGitHubFile } from '../github.js';
import { storeInKV } from '../kv.js';
import { marked } from '../marked.esm.js';
@@ -19,7 +19,7 @@ export async function handleCommitToGitHub(request, env) {
link: '/daily/'+dateStr+'.html',
content_html: null,
// 可以添加其他相關欄位,例如作者、來源等
- published_date: formatDateToChineseWithTime(new Date()) // 記錄保存時間
+ published_date: formatDateToGMT0WithTime(new Date()) // 記錄保存時間
}
const filesToCommit = [];
diff --git a/src/handlers/genAIContent.js b/src/handlers/genAIContent.js
index d408550..db73f14 100644
--- a/src/handlers/genAIContent.js
+++ b/src/handlers/genAIContent.js
@@ -229,7 +229,7 @@ export async function handleGenAIContent(request, env) {
if (fullPromptForCall2_User) promptsMarkdownContent += `### User Input (Output of Call 1)\n\`\`\`\n${fullPromptForCall2_User}\n\`\`\`\n\n`;
let dailySummaryMarkdownContent = `# ${env.DAILY_TITLE} ${formatDateToChinese(dateStr)}\n\n${removeMarkdownCodeBlock(outputOfCall2)}`;
- if (env.INSERT_FOOT) dailySummaryMarkdownContent += insertFoot() +`\n\n`;
+ if (env.INSERT_FOOT=='true') dailySummaryMarkdownContent += insertFoot() +`\n\n`;
const successHtml = generateGenAiPageHtml(
env,
diff --git a/src/handlers/getRss.js b/src/handlers/getRss.js
index 6e4c94d..7e75468 100644
--- a/src/handlers/getRss.js
+++ b/src/handlers/getRss.js
@@ -23,7 +23,6 @@ export async function handleRss(request, env) {
const allData = [];
const today = getShanghaiTime(); // 加上東八時區的偏移量
- console.log(today);
for (let i = 0; i < days; i++) {
const date = new Date(today);
@@ -58,7 +57,7 @@ export async function handleRss(request, env) {
const finalData = Object.values(filteredData);
finalData.forEach(item => {
- const pubDate = item.published_date ? formatRssDate(new Date(item.published_date)) : formatRssDate(new Date());
+ const pubDate = formatRssDate(new Date(item.published_date));
const content = minifyHTML(item.content_html);
const title = item.title || '无标题';
const link = env.BOOK_LINK+item.link || '#';
@@ -84,7 +83,7 @@ export async function handleRss(request, env) {
${env.BOOK_LINK}
近 ${days} 天的AI日报
zh-cn
- ${formatRssDate(new Date())}
+ ${formatRssDate()}
${rssItems}
diff --git a/src/handlers/writeRssData.js b/src/handlers/writeRssData.js
index 311e4d0..5729ad1 100644
--- a/src/handlers/writeRssData.js
+++ b/src/handlers/writeRssData.js
@@ -1,4 +1,4 @@
-import { replaceImageProxy, formatDateToChineseWithTime } from '../helpers.js';
+import { replaceImageProxy, formatDateToGMT0WithTime } from '../helpers.js';
import { getDailyReportContent } from '../github.js';
import { storeInKV } from '../kv.js';
import { marked } from '../marked.esm.js';
@@ -24,16 +24,17 @@ export async function handleWriteRssData(request, env) {
link: '/daily/'+dateStr+'.html',
content_html: null,
// 可以添加其他相關欄位,例如作者、來源等
- published_date: formatDateToChineseWithTime(new Date()) // 記錄保存時間
+ published_date: formatDateToGMT0WithTime(new Date()) // 記錄保存時間
}
report.content_html = marked.parse(replaceImageProxy(env.IMG_PROXY, content));
storeInKV(env.DATA_KV, `${dateStr}-report`, report);
- return new Response(JSON.stringify({ message: `Successfully fetched and stored daily report for ${dateStr}`}), {
+ return new Response(JSON.stringify(report), {
headers: { 'Content-Type': 'application/json' },
status: 200
});
} catch (error) {
- console.error('Error handling daily report:', error);
+ console.error('Error handling daily report:', error.message);
+ return new Response(`Error handling daily report: ${error.message}`, { status: 500 });
}
}
\ No newline at end of file
diff --git a/src/helpers.js b/src/helpers.js
index 5829540..b946957 100644
--- a/src/helpers.js
+++ b/src/helpers.js
@@ -231,20 +231,29 @@ export function formatDateToChineseWithTime(isoDateString) {
* @returns {string} 格式化後的日期字串
*/
export function formatRssDate(date) {
- const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
- const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
-
- const dayOfWeek = days[date.getUTCDay()];
- const dayOfMonth = date.getUTCDate();
- const month = months[date.getUTCMonth()];
- const year = date.getUTCFullYear();
- const hours = String(date.getUTCHours()).padStart(2, '0');
- const minutes = String(date.getUTCMinutes()).padStart(2, '0');
- const seconds = String(date.getUTCSeconds()).padStart(2, '0');
-
- return `${dayOfWeek}, ${dayOfMonth} ${month} ${year} ${hours}:${minutes}:${seconds} GMT`;
+ if (!date) return new Date().toUTCString();
+
+ return date.toUTCString();
}
+
+ export function formatDateToGMT0WithTime(isoDateString) {
+ if (!isoDateString) return '';
+ const date = new Date(isoDateString);
+ const options = {
+ year: 'numeric',
+ month: 'numeric',
+ day: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+ hour12: false, // 使用24小时制
+ timeZone: 'GMT'
+ };
+ // 使用 'zh-CN' 语言环境以确保中文格式
+ return new Intl.DateTimeFormat('zh-CN', options).format(date);
+}
+
/**
* Converts English double quotes (") to Chinese double quotes (“”).
* @param {string} text - The input string.