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 @@ | ![小酒馆](docs/images/sm2.png "img") | ![情报站](docs/images/sm1.png "img") | -**项目截图:** +**后台项目截图:** | 网站首页 | 日报内容 | 播客脚本 | | -------------------------------------- | -------------------------------------- | -------------------------------------- | 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://raw.githubusercontent.com/justlovemaki/CloudFlare-AI-Insight-Daily/refs/heads/main/docs/images/sm2.png "img") | ![情报站](https://raw.githubusercontent.com/justlovemaki/CloudFlare-AI-Insight-Daily/refs/heads/main/docs/images/sm1.png "img") | - **收听语音版** - - | 🎙️ **小宇宙** | 📹 **抖音** | - | --- | --- | - | [来生小酒馆](https://www.xiaoyuzhoufm.com/podcast/683c62b7c1ca9cf575a5030e) | [来生情报站](https://www.douyin.com/user/MS4wLjABAAAAwpwqPQlu38sO38VyWgw9ZjDEnN4bMR5j8x111UxpseHR9DpB6-CveI5KRXOWuFwG)| - | ![小酒馆](https://raw.githubusercontent.com/justlovemaki/CloudFlare-AI-Insight-Daily/refs/heads/main/docs/images/sm2.png "img") | ![情报站](https://raw.githubusercontent.com/justlovemaki/CloudFlare-AI-Insight-Daily/refs/heads/main/docs/images/sm1.png "img") | - - `; } 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.