rssany 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -50
- package/dist/index.js +17 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/webui/build/200.html +6 -6
- package/webui/build/_app/immutable/assets/0.DjU2hdCQ.css +1 -0
- package/webui/build/_app/immutable/chunks/{DcAshVxe.js → C85CNwD2.js} +1 -1
- package/webui/build/_app/immutable/chunks/{BXCWEhUd.js → CdMsRjxJ.js} +1 -1
- package/webui/build/_app/immutable/chunks/{EIZIMsXK.js → CllQAdvt.js} +1 -1
- package/webui/build/_app/immutable/chunks/{CkUAV0m0.js → Dv1VCsiB.js} +1 -1
- package/webui/build/_app/immutable/entry/{app.DdgnooOk.js → app.BcD2eSsQ.js} +2 -2
- package/webui/build/_app/immutable/entry/start.CbkdJdz1.js +1 -0
- package/webui/build/_app/immutable/nodes/{0.BE05Cuc4.js → 0.DSUDmOx2.js} +1 -1
- package/webui/build/_app/immutable/nodes/{1.5DFDaT4c.js → 1.DU9aYGAb.js} +1 -1
- package/webui/build/_app/immutable/nodes/{10.OVK4i9XE.js → 10.Db6vw7Ih.js} +1 -1
- package/webui/build/_app/immutable/nodes/{11.Dhn_rO4A.js → 11.BaAcorz3.js} +1 -1
- package/webui/build/_app/immutable/nodes/{14.B_KpJLxn.js → 14.DqT4pcrQ.js} +1 -1
- package/webui/build/_app/immutable/nodes/{15.RaWaA-0I.js → 15.CCLbjxnH.js} +1 -1
- package/webui/build/_app/immutable/nodes/{16.DSUgqolV.js → 16.DiigpVdP.js} +1 -1
- package/webui/build/_app/immutable/nodes/{3.wQvGs9w-.js → 3.DEcYOQc-.js} +1 -1
- package/webui/build/_app/immutable/nodes/{5.CCtn90c0.js → 5.CvM1TkLG.js} +1 -1
- package/webui/build/_app/immutable/nodes/{6.C2_mjW1u.js → 6.Dscr6LkS.js} +1 -1
- package/webui/build/_app/immutable/nodes/{7.Dwz6W7A1.js → 7.Bp60MobD.js} +1 -1
- package/webui/build/_app/immutable/nodes/{8.DzkEw6rx.js → 8.DwSg0MHh.js} +1 -1
- package/webui/build/_app/immutable/nodes/{9.DtlXEwe1.js → 9.BeYOUjxR.js} +1 -1
- package/webui/build/_app/version.json +1 -1
- package/webui/build/_app/immutable/assets/0.C6Q_nuW9.css +0 -1
- package/webui/build/_app/immutable/entry/start.DhJaJZhR.js +0 -1
package/README.md
CHANGED
|
@@ -14,13 +14,12 @@
|
|
|
14
14
|
## 功能概览
|
|
15
15
|
|
|
16
16
|
- **统一订阅**:在 `.rssany/sources.json` 中配置网站列表、标准 RSS、IMAP 邮件等,由调度器按 `refresh` 策略拉取。
|
|
17
|
-
-
|
|
17
|
+
- **可插拔信源**:**Site / Source** 插件(`.rssany.js` / `.rssany.ts`),见 **[插件配置说明](./docs/plugins.md)**。
|
|
18
18
|
- **正文与解析**:在信源 `fetchItems`(及需要的 `ctx.extractItem` 等)内完成;入库后跑 pipeline。
|
|
19
19
|
- **固定 pipeline**:`app/pipeline/` 中打标签、翻译等,由 `.rssany/config.json` 的 `pipeline.steps` 开关(**不是**用户目录下的 pipeline 插件)。
|
|
20
20
|
- **LLM 辅助**:解析、提取、标签、翻译等可按配置走 OpenAI 兼容接口。
|
|
21
21
|
- **站点登录**:需登录的站点通过 Puppeteer 管理 Cookie(与产品用户账号无关)。
|
|
22
22
|
- **可选远端投递**:若 `config.json` 中 `**deliver.url`** 非空,在写库与 pipeline 完成后将条目以 `**{ sourceRef, items }**` JSON **POST** 到该 URL(由 `app/deliver/post.ts` 发送);留空则仅本地消费。
|
|
23
|
-
- **MCP**:条目检索等能力以 MCP 暴露,供 Cursor、Claude 等使用。
|
|
24
23
|
- **Web 界面**:SvelteKit 构建产物由后端托管;**Feeds** 等需 **邮箱校验**;`**/admin`** 需 `**users.role === 'admin'**`(可从 `**/me**` 进入)。
|
|
25
24
|
|
|
26
25
|
---
|
|
@@ -42,82 +41,62 @@
|
|
|
42
41
|
|
|
43
42
|
## 快速开始
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
日常使用只需 **Node.js 20.x–23.x**(与 `package.json` 的 `engines` 一致):
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
- **pnpm**
|
|
49
|
-
|
|
50
|
-
### 安装依赖
|
|
46
|
+
### 全局安装(推荐)
|
|
51
47
|
|
|
52
48
|
```bash
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
npm install -g rssany # 与 npm i -g rssany 相同
|
|
50
|
+
rssany
|
|
55
51
|
```
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
1. 复制环境变量示例并按需填写(JWT、OAuth、SMTP、LLM 等):
|
|
60
|
-
```bash
|
|
61
|
-
cp .env.example .env
|
|
62
|
-
```
|
|
63
|
-
2. 信源与全局配置:首次启动会在 **`~/.rssany/`**(Windows:`%USERPROFILE%\.rssany\`)下自动从包内 **`init/`** 目录中的默认数据复制生成 `sources.json`、`config.json`(若已存在则不会覆盖)。也可手动复制仓库里的 `init/sources.json`、`init/config.json`。
|
|
64
|
-
3. (可选)LLM:在 `.env` 中设置 `OPENAI_API_KEY`、`OPENAI_BASE_URL`、`OPENAI_MODEL` 等。
|
|
53
|
+
安装包内已包含构建好的后端与 Web 界面;启动后用浏览器打开终端里提示的地址(默认 **`http://127.0.0.1:18473/`**,端口可在**运行命令时当前目录**下的 `.env` 里设置 `PORT`)。
|
|
65
54
|
|
|
66
|
-
|
|
55
|
+
- **数据目录**:首次运行会在 **`~/.rssany/`**(Windows:`%USERPROFILE%\.rssany\`)自动从包内 **`init/`** 生成 `sources.json`、`config.json` 等(已存在则不会覆盖)。
|
|
56
|
+
- **可选配置**:在启动 `rssany` 时的**当前目录**放置 `.env`(可参考仓库里的 `.env.example`),用于 JWT、OAuth、SMTP、LLM(如 `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL`)等。
|
|
57
|
+
- **重置全部本地数据**(结束占用 `PORT` 的进程并删除用户目录,慎用):执行 **`rssany reset`**;在含 `.env` 的目录下运行可读取 `PORT` / `RSSANY_USER_DIR`,或事先在环境里导出这些变量。
|
|
67
58
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
# 推荐:API + 前端 watch(修改 Svelte 后自动写入构建目录,刷新浏览器即可)
|
|
72
|
-
pnpm run dev:all
|
|
73
|
-
|
|
74
|
-
# 或分步:先打一次前端再起后端
|
|
75
|
-
pnpm run webui:build
|
|
76
|
-
pnpm dev
|
|
77
|
-
```
|
|
59
|
+
等价于在项目里执行 `node node_modules/rssany/dist/index.js`;CLI 名为 **`rssany`**。
|
|
78
60
|
|
|
79
|
-
|
|
61
|
+
### 从源码运行(开发 / 贡献)
|
|
80
62
|
|
|
81
|
-
|
|
63
|
+
需要 **pnpm**:
|
|
82
64
|
|
|
83
65
|
```bash
|
|
84
|
-
pnpm
|
|
66
|
+
pnpm install
|
|
67
|
+
pnpm run webui:install
|
|
68
|
+
cp .env.example .env # 按需修改
|
|
85
69
|
```
|
|
86
70
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
**生产**:
|
|
71
|
+
**开发**(后端托管 `webui` 构建目录;改前端可 watch):
|
|
90
72
|
|
|
91
73
|
```bash
|
|
92
|
-
pnpm run
|
|
74
|
+
pnpm run dev:all
|
|
93
75
|
```
|
|
94
76
|
|
|
95
|
-
|
|
77
|
+
或分步:`pnpm run webui:build` 后 `pnpm dev`。
|
|
96
78
|
|
|
97
|
-
|
|
79
|
+
**仅调试 WebUI 热更新**(可选):`cd webui && pnpm dev`(Vite 代理到本机后端,见 `webui/vite.config.ts`)。
|
|
98
80
|
|
|
99
|
-
|
|
100
|
-
npm install -g rssany
|
|
101
|
-
rssany
|
|
102
|
-
```
|
|
81
|
+
**生产**(本仓库):`pnpm run webui:build && pnpm start`。
|
|
103
82
|
|
|
104
|
-
|
|
83
|
+
**重置本地数据**(与全局安装的 `rssany reset` 逻辑相同):`pnpm reset`。
|
|
105
84
|
|
|
106
|
-
|
|
85
|
+
发布到 npm 时 `prepublishOnly` 会执行 `build:all`(后端 `vite build` + `webui:build`)。
|
|
107
86
|
|
|
108
87
|
---
|
|
109
88
|
|
|
110
89
|
## 数据流(简图)
|
|
111
90
|
|
|
112
91
|
```
|
|
113
|
-
sources.json /
|
|
92
|
+
sources.json / 信源插件
|
|
114
93
|
→ 调度器触发 fetchItems
|
|
115
94
|
→ upsertItems
|
|
116
95
|
→ pipeline(每条一次)
|
|
117
96
|
→ [可选] deliver.url POST(出站,非入站 API)
|
|
118
97
|
```
|
|
119
98
|
|
|
120
|
-
消费侧:**RSS/XML**、`**/api
|
|
99
|
+
消费侧:**RSS/XML**、`**/api/*`**、Web UI。
|
|
121
100
|
|
|
122
101
|
---
|
|
123
102
|
|
|
@@ -130,11 +109,9 @@ sources.json / Site 插件
|
|
|
130
109
|
|
|
131
110
|
---
|
|
132
111
|
|
|
133
|
-
##
|
|
134
|
-
|
|
135
|
-
### 信源插件(Site)
|
|
112
|
+
## 配置
|
|
136
113
|
|
|
137
|
-
|
|
114
|
+
**信源插件(Site / Source)**:目录约定、`listUrlPattern` / `pattern`、`fetchItems`、与 `sources.json` 的关系等,见 **[docs/plugins.md](./docs/plugins.md)**。
|
|
138
115
|
|
|
139
116
|
### Pipeline(固定代码)
|
|
140
117
|
|
|
@@ -173,8 +150,9 @@ sources.json / Site 插件
|
|
|
173
150
|
## 仓库目录(摘要)
|
|
174
151
|
|
|
175
152
|
```
|
|
176
|
-
├── app/ # 后端:路由、feeder、scraper、pipeline、
|
|
153
|
+
├── app/ # 后端:路由、feeder、scraper、pipeline、db、auth…
|
|
177
154
|
│ └── plugins/builtin/ # 内置信源 *.rssany.js
|
|
155
|
+
├── docs/ # 用户文档(如 plugins.md)
|
|
178
156
|
└── webui/ # SvelteKit 前端
|
|
179
157
|
|
|
180
158
|
~/.rssany/ # 运行时用户数据(首次启动创建;或 RSSANY_USER_DIR)
|
package/dist/index.js
CHANGED
|
@@ -134,6 +134,18 @@ function getEffectiveItemFields(item, lng) {
|
|
|
134
134
|
content: (t?.content != null && t.content !== "" ? t.content : item.content) ?? ""
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
|
+
function pubDateToIsoOrNull(pubDate) {
|
|
138
|
+
if (pubDate == null) return null;
|
|
139
|
+
if (pubDate instanceof Date) {
|
|
140
|
+
const ms = pubDate.getTime();
|
|
141
|
+
return Number.isNaN(ms) ? null : pubDate.toISOString();
|
|
142
|
+
}
|
|
143
|
+
if (typeof pubDate === "string") {
|
|
144
|
+
const s = pubDate.trim();
|
|
145
|
+
return s || null;
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
137
149
|
function normalizeAuthor(author) {
|
|
138
150
|
if (author == null) return void 0;
|
|
139
151
|
if (Array.isArray(author)) return author.filter((s2) => typeof s2 === "string" && s2.trim()).map((s2) => s2.trim());
|
|
@@ -619,7 +631,7 @@ async function upsertItems(items, sourceUrlOverride) {
|
|
|
619
631
|
const nextSummary = normalizeText(item.summary) || null;
|
|
620
632
|
const nextAuthorArr = normalizeAuthor(item.author);
|
|
621
633
|
const nextAuthor = nextAuthorArr?.length ? JSON.stringify(nextAuthorArr) : null;
|
|
622
|
-
const nextPubDate = item.pubDate
|
|
634
|
+
const nextPubDate = pubDateToIsoOrNull(item.pubDate);
|
|
623
635
|
const nextTags = item.tags?.length ? JSON.stringify(item.tags) : null;
|
|
624
636
|
const nextImageUrl = typeof item.imageUrl === "string" && item.imageUrl.trim() ? item.imageUrl.trim() : null;
|
|
625
637
|
const info = stmt.run({
|
|
@@ -687,7 +699,7 @@ async function updateItemContent(item) {
|
|
|
687
699
|
const arr = normalizeAuthor(item.author);
|
|
688
700
|
return arr?.length ? JSON.stringify(arr) : null;
|
|
689
701
|
})(),
|
|
690
|
-
pubDate: item.pubDate
|
|
702
|
+
pubDate: pubDateToIsoOrNull(item.pubDate),
|
|
691
703
|
tags: item.tags?.length ? JSON.stringify(item.tags) : null,
|
|
692
704
|
translations: item.translations && Object.keys(item.translations).length > 0 ? JSON.stringify(item.translations) : null
|
|
693
705
|
});
|
|
@@ -2514,7 +2526,7 @@ function feedItemsToPayload(items) {
|
|
|
2514
2526
|
guid: i.guid,
|
|
2515
2527
|
title: i.title,
|
|
2516
2528
|
link: i.link,
|
|
2517
|
-
pubDate: i.pubDate
|
|
2529
|
+
pubDate: pubDateToIsoOrNull(i.pubDate) ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
2518
2530
|
author: i.author,
|
|
2519
2531
|
summary: i.summary,
|
|
2520
2532
|
content: i.content,
|
|
@@ -2575,7 +2587,7 @@ function toRssEntry(item, lng) {
|
|
|
2575
2587
|
link: item.link,
|
|
2576
2588
|
description: desc,
|
|
2577
2589
|
guid: item.guid,
|
|
2578
|
-
published: item.pubDate
|
|
2590
|
+
published: pubDateToIsoOrNull(item.pubDate) ?? void 0,
|
|
2579
2591
|
imageUrl: item.imageUrl
|
|
2580
2592
|
};
|
|
2581
2593
|
}
|
|
@@ -2957,7 +2969,7 @@ function registerRssApiRoutes(app) {
|
|
|
2957
2969
|
link: item.link,
|
|
2958
2970
|
summary,
|
|
2959
2971
|
author: item.author,
|
|
2960
|
-
pubDate: item.pubDate
|
|
2972
|
+
pubDate: pubDateToIsoOrNull(item.pubDate)
|
|
2961
2973
|
};
|
|
2962
2974
|
})
|
|
2963
2975
|
});
|