Files
CloudFlare-AI-Insight-Daily/src/github.js
luofeng cd81280bcb refactor(handlers): 拆分RSS工作流为独立的生成与存储阶段
引入两阶段RSS处理架构以支持订阅源摘要预览功能:

第一阶段 - 内容生成(/generateRssContent):
  * 读取daily目录原始markdown
  * 调用AI生成精简摘要
  * 持久化至GitHub rss目录

第二阶段 - 数据同步(/writeRssData):
  * 消费rss目录预生成内容
  * 转换为HTML并同步至KV存储

其他调整:
  * 创建官网引流模板(appUrl.js)
  * 实现智能断行的文本裁剪工具
  * 优化日报页面广告展示顺序
  * 修正getDailyReportContent异常日志输出
2026-01-12 18:03:53 +08:00

142 lines
5.0 KiB
JavaScript
Executable File

// src/github.js
/**
* Generic wrapper for calling the GitHub API.
*/
export async function callGitHubApi(env, path, method = 'GET', body = null) {
const GITHUB_TOKEN = env.GITHUB_TOKEN;
const GITHUB_REPO_OWNER = env.GITHUB_REPO_OWNER;
const GITHUB_REPO_NAME = env.GITHUB_REPO_NAME;
if (!GITHUB_TOKEN || !GITHUB_REPO_OWNER || !GITHUB_REPO_NAME) {
console.error("GitHub environment variables (GITHUB_TOKEN, GITHUB_REPO_OWNER, GITHUB_REPO_NAME) are not configured.");
throw new Error("GitHub API configuration is missing in environment variables.");
}
const url = `https://api.github.com/repos/${GITHUB_REPO_OWNER}/${GITHUB_REPO_NAME}${path}`;
const headers = {
'Authorization': `Bearer ${GITHUB_TOKEN}`,
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'Cloudflare-Worker-ContentBot/1.0'
};
if (method !== 'GET' && method !== 'DELETE' && body) {
headers['Content-Type'] = 'application/json';
}
const response = await fetch(url, {
method: method,
headers: headers,
body: body ? JSON.stringify(body) : null
});
if (!response.ok) {
const errorText = await response.text();
let errorJsonMessage = errorText;
try {
const errorJson = JSON.parse(errorText);
if (errorJson && errorJson.message) {
errorJsonMessage = errorJson.message;
if (errorJson.errors) {
errorJsonMessage += ` Details: ${JSON.stringify(errorJson.errors)}`;
}
}
} catch (e) { /* Ignore */ }
console.error(`GitHub API Error: ${response.status} ${response.statusText} for ${method} ${url}. Message: ${errorJsonMessage}`);
throw new Error(`GitHub API request to ${path} failed: ${response.status} - ${errorJsonMessage}`);
}
if (response.status === 204 || response.headers.get("content-length") === "0") {
return null;
}
return response.json();
}
/**
* Gets the SHA of a file from GitHub.
*/
export async function getGitHubFileSha(env, filePath) {
const GITHUB_BRANCH = env.GITHUB_BRANCH || 'main';
try {
const data = await callGitHubApi(env, `/contents/${filePath}?ref=${GITHUB_BRANCH}`);
return data && data.sha ? data.sha : null;
} catch (error) {
if (error.message.includes("404") || error.message.toLowerCase().includes("not found")) {
console.log(`File not found on GitHub: ${filePath} (branch: ${GITHUB_BRANCH})`);
return null;
}
console.error(`Error getting SHA for ${filePath}:`, error);
throw error;
}
}
/**
* Creates a new file or updates an existing one on GitHub.
*/
export async function createOrUpdateGitHubFile(env, filePath, content, commitMessage, existingSha = null) {
const GITHUB_BRANCH = env.GITHUB_BRANCH || 'main';
const base64Content = b64EncodeUnicode(content);
const payload = {
message: commitMessage,
content: base64Content,
branch: GITHUB_BRANCH
};
if (existingSha) {
payload.sha = existingSha;
}
return callGitHubApi(env, `/contents/${filePath}`, 'PUT', payload);
}
/**
* Gets the content of a file from GitHub.
*/
export async function getDailyReportContent(env, filePath) {
const GITHUB_BRANCH = env.GITHUB_BRANCH || 'main';
const GITHUB_REPO_OWNER = env.GITHUB_REPO_OWNER;
const GITHUB_REPO_NAME = env.GITHUB_REPO_NAME;
if (!GITHUB_REPO_OWNER || !GITHUB_REPO_NAME) {
console.error("GitHub environment variables (GITHUB_REPO_OWNER, GITHUB_REPO_NAME) are not configured.");
throw new Error("GitHub API configuration is missing in environment variables.");
}
try {
const data = await callGitHubApi(env, `/contents/${filePath}?ref=${GITHUB_BRANCH}`);
return b64DecodeUnicode(data.content);
} catch (error) {
console.error(`Error fetching daily report content from ${filePath}:`, 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
}
}