Skip to content

Commit

Permalink
Merge pull request #22 from Do1e/main
Browse files Browse the repository at this point in the history
添加Do1e并增加Seatable支持
  • Loading branch information
OrangeX4 authored Dec 15, 2024
2 parents cc53dcb + a203f98 commit c009037
Show file tree
Hide file tree
Showing 5 changed files with 294 additions and 78 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ jobs:
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('workers-site/package-lock.json') }}
- run: npm i # 执行 Blogroll 的依赖安装
- run: npm run gen # 相当于 node index.js,生成 opml.xml,opml.json 和 data.json
env:
SEATABLE_API_TOKEN: ${{ secrets.SEATABLE_API_TOKEN }}
- run: npm run build
- name: Deploy to Cloudflare Workers
uses: cloudflare/wrangler-action@v3
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Pull Request 规范:标题为自己的名字,内容可以是对自己和博
| A7R7's Notes | https://a7r7.me/index.xml | https://a7r7.me |
| StrnasnX's Blog | https://stringmax.xyz/atom.xml | https://stringmax.xyz/ |
| Yukino's Blog | https://02hyc.github.io/Blog.github.io/atom.xml | https://02hyc.github.io/Blog.github.io/ |
| Do1e | https://www.do1e.cn/feed | https://www.do1e.cn |

## OPML

Expand Down
189 changes: 111 additions & 78 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ const Parser = require('rss-parser');
const parser = new Parser();
// 引入 RSS 生成器
const RSS = require('rss');
// 引入 SeaTableAPI
const { Base } = require('seatable-api');

// 相关配置
const opmlXmlContentTitle = 'NJU-LUG Blogroll';
Expand All @@ -16,12 +18,12 @@ const opmlXmlPath = './web/public/opml.xml';
const rssXmlPath = './web/public/rss.xml';
const opmlXmlContentOp = '<opml version="2.0">\n <head>\n <title>' + opmlXmlContentTitle + '</title>\n </head>\n <body>\n\n';
const opmlXmlContentEd = '\n </body>\n</opml>';

const seatableToken = process.env.SEATABLE_API_TOKEN;
// 解析 README 中的表格,转为 JSON
const pattern = /\| *([^\|]*) *\| *(http[^\|]*) *\| *(http[^\|]*) *\|/g;
const readmeMdContent = fs.readFileSync(readmeMdPath, { encoding: 'utf-8' });
// 生成 opml.json
const opmlJson = [];
let opmlJson = [];
let resultArray;
while ((resultArray = pattern.exec(readmeMdContent)) !== null) {
opmlJson.push({
Expand All @@ -30,87 +32,118 @@ while ((resultArray = pattern.exec(readmeMdContent)) !== null) {
htmlUrl: resultArray[3].trim()
});
}
// 保存 opml.json 和 opml.xml
fs.writeFileSync(opmlJsonPath, JSON.stringify(opmlJson, null, 2), { encoding: 'utf-8' });
const opmlXmlContent = opmlXmlContentOp
+ opmlJson.map((lineJson) => ` <outline title="${lineJson.title}" xmlUrl="${lineJson.xmlUrl}" htmlUrl="${lineJson.htmlUrl}" />\n`).join('')
+ opmlXmlContentEd;
fs.writeFileSync(opmlXmlPath, opmlXmlContent, { encoding: 'utf-8' });

// 异步处理

// 解析 SeaTable 中的表格,转为 JSON
async function parseSeaTableToJson(opmlJson) {
const seatableBase = new Base({
server: "https://table.nju.edu.cn",
APIToken: seatableToken
});
await seatableBase.auth();
const tables = await seatableBase.getTables();
const rows = await seatableBase.listRows(tables[0]['name']);
rows.forEach(row => {
if (row['Name'] && (!opmlJson.some(item => item.title === row['Name'])) && row['RSS'].startsWith('http') && row['HTML'].startsWith('http')) {
opmlJson.push({
title: row['Name'],
xmlUrl: row['RSS'],
htmlUrl: row['HTML']
});
}
});
return opmlJson;
}
(async () => {

// 用于存储各项数据
const dataJson = [];

for (const lineJson of opmlJson) {

// 如果定义 SeaTable Token,则将 SeaTable 中的数据合并到 opmlJson 中
if (seatableToken !== undefined && seatableToken !== '' && seatableToken !== null) {
try {

// 读取 RSS 的具体内容
const feed = await parser.parseURL(lineJson.xmlUrl);

// 数组合并
dataJson.push.apply(dataJson, feed.items.filter((item) => item.title && item.content && item.pubDate).map((item) => {
const pubDate = new Date(item.pubDate);
return {
name: lineJson.title,
xmlUrl: lineJson.xmlUrl,
htmlUrl: lineJson.htmlUrl,
title: item.title,
link: item.link,
summary: item.summary ? item.summary : item.content,
pubDate: pubDate,
pubDateYYMMDD: pubDate.toISOString().split('T')[0]
}
}));

opmlJson = await parseSeaTableToJson(opmlJson);
} catch (err) {

// 网络超时,进行 Log 报告
console.log(err);
console.log("-------------------------");
console.log("xmlUrl: " + lineJson.xmlUrl);
console.log("-------------------------");

}
}

// 按时间顺序排序
dataJson.sort((itemA, itemB) => itemA.pubDate < itemB.pubDate ? 1 : -1);
// 默认为保存前 n 项的数据, 并保证不超过当前时间
const curDate = new Date();
const dataJsonSliced = dataJson.filter((item) => item.pubDate <= curDate).slice(0, Math.min(maxDataJsonItemsNumber, dataJson.length));
fs.writeFileSync(dataJsonPath, JSON.stringify(dataJsonSliced, null, 2), { encoding: 'utf-8' });

// 生成 RSS 文件
var feed = new RSS({
title: 'NJU-LUG Blogroll',
description: '南京大学 Linux User Group 收集同学和校友们的 Blog',
feed_url: 'https://blogroll.njulug.org/rss.xml',
site_url: 'https://blogroll.njulug.org/',
image_url: 'https://blogroll.njulug.org/assets/logo.56c0d74c.png',
docs: 'https://blogroll.njulug.org/',
managingEditor: 'NJU-LUG',
webMaster: 'NJU-LUG',
copyright: '2022 NJU-LUG',
language: 'cn',
pubDate: dataJson[0].pubDate,
ttl: '60',
});

for (let item of dataJsonSliced) {
feed.item({
title: item.title,
description: item.summary,
url: item.link, // link to the item
author: item.name, // optional - defaults to feed author property
date: item.pubDate.toISOString(), // any format that js Date can parse.
// 保存 opml.json 和 opml.xml
fs.writeFileSync(opmlJsonPath, JSON.stringify(opmlJson, null, 2), { encoding: 'utf-8' });
const opmlXmlContent = opmlXmlContentOp
+ opmlJson.map((lineJson) => ` <outline title="${lineJson.title}" xmlUrl="${lineJson.xmlUrl}" htmlUrl="${lineJson.htmlUrl}" />\n`).join('')
+ opmlXmlContentEd;
fs.writeFileSync(opmlXmlPath, opmlXmlContent, { encoding: 'utf-8' });

// 异步处理
(async () => {

// 用于存储各项数据
const dataJson = [];

for (const lineJson of opmlJson) {

try {

// 读取 RSS 的具体内容
const feed = await parser.parseURL(lineJson.xmlUrl);

// 数组合并
dataJson.push.apply(dataJson, feed.items.filter((item) => item.title && item.content && item.pubDate).map((item) => {
const pubDate = new Date(item.pubDate);
return {
name: lineJson.title,
xmlUrl: lineJson.xmlUrl,
htmlUrl: lineJson.htmlUrl,
title: item.title,
link: item.link,
summary: item.summary ? item.summary : item.content,
pubDate: pubDate,
pubDateYYMMDD: pubDate.toISOString().split('T')[0]
}
}));

} catch (err) {

// 网络超时,进行 Log 报告
console.log(err);
console.log("-------------------------");
console.log("xmlUrl: " + lineJson.xmlUrl);
console.log("-------------------------");

}
}

// 按时间顺序排序
dataJson.sort((itemA, itemB) => itemA.pubDate < itemB.pubDate ? 1 : -1);
// 默认为保存前 n 项的数据, 并保证不超过当前时间
const curDate = new Date();
const dataJsonSliced = dataJson.filter((item) => item.pubDate <= curDate).slice(0, Math.min(maxDataJsonItemsNumber, dataJson.length));
fs.writeFileSync(dataJsonPath, JSON.stringify(dataJsonSliced, null, 2), { encoding: 'utf-8' });

// 生成 RSS 文件
var feed = new RSS({
title: 'NJU-LUG Blogroll',
description: '南京大学 Linux User Group 收集同学和校友们的 Blog',
feed_url: 'https://blogroll.njulug.org/rss.xml',
site_url: 'https://blogroll.njulug.org/',
image_url: 'https://blogroll.njulug.org/assets/logo.56c0d74c.png',
docs: 'https://blogroll.njulug.org/',
managingEditor: 'NJU-LUG',
webMaster: 'NJU-LUG',
copyright: '2022 NJU-LUG',
language: 'cn',
pubDate: dataJson[0].pubDate,
ttl: '60',
});
}

// 保存 rss.xml 文件
const rssXmlContent = feed.xml();
fs.writeFileSync(rssXmlPath, rssXmlContent, { encoding: 'utf-8' });

})();

for (let item of dataJsonSliced) {
feed.item({
title: item.title,
description: item.summary,
url: item.link, // link to the item
author: item.name, // optional - defaults to feed author property
date: item.pubDate.toISOString(), // any format that js Date can parse.
});
}

// 保存 rss.xml 文件
const rssXmlContent = feed.xml();
fs.writeFileSync(rssXmlPath, rssXmlContent, { encoding: 'utf-8' });
})();
})();
Loading

0 comments on commit c009037

Please sign in to comment.