rssany 0.1.6 → 0.3.0
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 +23 -27
- package/app/plugins/builtin/agi-eval-evaluation.rssany.js +7 -8
- package/app/plugins/builtin/amii-research-talent.rssany.js +6 -7
- package/app/plugins/builtin/anthropic-research.rssany.js +6 -8
- package/app/plugins/builtin/appen-resources.rssany.js +6 -7
- package/app/plugins/builtin/baai-wudao-paper-article.rssany.js +9 -10
- package/app/plugins/builtin/baaidata-csdn.rssany.js +6 -7
- package/app/plugins/builtin/baidu-research.rssany.js +5 -8
- package/app/plugins/builtin/brightdata-blog.rssany.js +7 -12
- package/app/plugins/builtin/bytedance-seed-research.rssany.js +5 -7
- package/app/plugins/builtin/email.rssany.js +9 -9
- package/app/plugins/builtin/five-radar.rssany.js +10 -12
- package/app/plugins/builtin/flageval-news.rssany.js +5 -7
- package/app/plugins/builtin/google-deepmind-research.rssany.js +7 -9
- package/app/plugins/builtin/google-research-datasets.rssany.js +6 -8
- package/app/plugins/builtin/google-research.rssany.js +6 -8
- package/app/plugins/builtin/hacker-news-newest.rssany.js +7 -9
- package/app/plugins/builtin/harvard-dataverse.rssany.js +6 -8
- package/app/plugins/builtin/huaweicloud-bbs-blogs.rssany.js +7 -9
- package/app/plugins/builtin/lingowhale.rssany.js +7 -9
- package/app/plugins/builtin/meituan-tech.rssany.js +7 -10
- package/app/plugins/builtin/meta-ai-publications.rssany.js +6 -11
- package/app/plugins/builtin/mila-quebec.rssany.js +6 -8
- package/app/plugins/builtin/mit-csail-research.rssany.js +7 -9
- package/app/plugins/builtin/moonshot.rssany.js +6 -8
- package/app/plugins/builtin/opendatalab-news.rssany.js +6 -7
- package/app/plugins/builtin/opendatalab.rssany.js +5 -6
- package/app/plugins/builtin/opendrivelab-autonomous-driving.rssany.js +6 -7
- package/app/plugins/builtin/opendrivelab-embodiedai.rssany.js +7 -8
- package/app/plugins/builtin/opendrivelab-publications.rssany.js +7 -9
- package/app/plugins/builtin/opendrivelab.rssany.js +7 -8
- package/app/plugins/builtin/paperswithcode.rssany.js +6 -8
- package/app/plugins/builtin/pjlab-adg-publications.rssany.js +8 -10
- package/app/plugins/builtin/rss.rssany.js +11 -12
- package/app/plugins/builtin/selectdataset.rssany.js +6 -8
- package/app/plugins/builtin/sensetime-tech-achievements.rssany.js +7 -8
- package/app/plugins/builtin/supervisely-blog.rssany.js +6 -8
- package/app/plugins/builtin/theinformation-briefings.rssany.js +144 -136
- package/app/plugins/builtin/uci-ml-repository.rssany.js +6 -7
- package/app/plugins/builtin/venturebeat.rssany.js +7 -9
- package/app/plugins/builtin/worldlabs.rssany.js +6 -8
- package/app/plugins/builtin/x.rssany.js +7 -9
- package/app/plugins/builtin/xiaohongshu.rssany.js +119 -56
- package/app/plugins/builtin/zhipu-research.rssany.js +7 -10
- package/app/plugins/site.rssany.js +25 -25
- package/{statics → app/statics}/README.md +7 -7
- package/bin/rssany.js +226 -6
- package/dist/index.js +545 -396
- package/dist/index.js.map +1 -1
- package/package.json +20 -13
- package/scripts/dev.mjs +114 -0
- package/scripts/reset.mjs +1 -1
- package/app/plugins/builtin/google.rssany.js +0 -187
- package/init/config.json +0 -17
- package/init/sources.json +0 -353
- package/statics/401.html +0 -56
- package/statics/404.html +0 -12
- package/statics/image.png +0 -0
- package/webui/build/200.html +0 -49
- package/webui/build/_app/env.js +0 -1
- package/webui/build/_app/immutable/assets/0.BB88QFoe.css +0 -1
- package/webui/build/_app/immutable/assets/10.Dj8_pmut.css +0 -1
- package/webui/build/_app/immutable/assets/11.qYZMiTb0.css +0 -1
- package/webui/build/_app/immutable/assets/12.Ct59LCqW.css +0 -1
- package/webui/build/_app/immutable/assets/13.BhO9zvFi.css +0 -1
- package/webui/build/_app/immutable/assets/14.CujIhjQK.css +0 -1
- package/webui/build/_app/immutable/assets/15.nNGjXhCQ.css +0 -1
- package/webui/build/_app/immutable/assets/16.PP9XLDf7.css +0 -1
- package/webui/build/_app/immutable/assets/4.9wPHhVwv.css +0 -1
- package/webui/build/_app/immutable/assets/5.ClehBQ0g.css +0 -1
- package/webui/build/_app/immutable/assets/6.DSJfjJwx.css +0 -1
- package/webui/build/_app/immutable/assets/7.CrNxmd8B.css +0 -1
- package/webui/build/_app/immutable/assets/8.Ba5_jYIY.css +0 -1
- package/webui/build/_app/immutable/assets/9.m-LCx_kl.css +0 -1
- package/webui/build/_app/immutable/assets/BackToParentRoute.DGk-X5ow.css +0 -1
- package/webui/build/_app/immutable/assets/SourcesList.yTBBi3_m.css +0 -1
- package/webui/build/_app/immutable/assets/homeFeedPanelStore.CSvlNcpm.css +0 -1
- package/webui/build/_app/immutable/chunks/B-OsL1Ct.js +0 -1
- package/webui/build/_app/immutable/chunks/B2Q1a1-H.js +0 -2
- package/webui/build/_app/immutable/chunks/BK3WtZwv.js +0 -1
- package/webui/build/_app/immutable/chunks/BQqoDzLx.js +0 -1
- package/webui/build/_app/immutable/chunks/BUApaBEI.js +0 -1
- package/webui/build/_app/immutable/chunks/BbWUOQ_m.js +0 -1
- package/webui/build/_app/immutable/chunks/Bfc47y5P.js +0 -1
- package/webui/build/_app/immutable/chunks/Bp63qm3L.js +0 -1
- package/webui/build/_app/immutable/chunks/BwlaCkNX.js +0 -36
- package/webui/build/_app/immutable/chunks/C0J2-L94.js +0 -1
- package/webui/build/_app/immutable/chunks/CBY2biv-.js +0 -1
- package/webui/build/_app/immutable/chunks/CLOXMsDk.js +0 -36
- package/webui/build/_app/immutable/chunks/CVzlFH44.js +0 -1
- package/webui/build/_app/immutable/chunks/CWNeClHp.js +0 -6
- package/webui/build/_app/immutable/chunks/Cihqbfi5.js +0 -1
- package/webui/build/_app/immutable/chunks/D5GvRCv7.js +0 -1
- package/webui/build/_app/immutable/chunks/DEDI7Ecm.js +0 -1
- package/webui/build/_app/immutable/chunks/DFuhmi31.js +0 -1
- package/webui/build/_app/immutable/chunks/DMWEh-Ek.js +0 -2
- package/webui/build/_app/immutable/chunks/DgceFEv5.js +0 -1
- package/webui/build/_app/immutable/chunks/DjNLq3TF.js +0 -1
- package/webui/build/_app/immutable/chunks/Dt2CddFe.js +0 -1
- package/webui/build/_app/immutable/chunks/Dw782Tjs.js +0 -1
- package/webui/build/_app/immutable/chunks/SqCUd34O.js +0 -1
- package/webui/build/_app/immutable/chunks/Xy_fhzQq.js +0 -1
- package/webui/build/_app/immutable/chunks/hp4PFHFv.js +0 -1
- package/webui/build/_app/immutable/chunks/lk5LaiqA.js +0 -1
- package/webui/build/_app/immutable/chunks/mW5RwvnK.js +0 -13
- package/webui/build/_app/immutable/chunks/tB7QMF3U.js +0 -1
- package/webui/build/_app/immutable/chunks/xtNWTdbD.js +0 -1
- package/webui/build/_app/immutable/entry/app.B8zBPipq.js +0 -2
- package/webui/build/_app/immutable/entry/start.CxRCKeCl.js +0 -1
- package/webui/build/_app/immutable/nodes/0.ChLNE3xy.js +0 -11
- package/webui/build/_app/immutable/nodes/1.1N74-4Io.js +0 -1
- package/webui/build/_app/immutable/nodes/10.DY30t9Ib.js +0 -1
- package/webui/build/_app/immutable/nodes/11.ITuxnukH.js +0 -1
- package/webui/build/_app/immutable/nodes/12.qLzWqB1c.js +0 -1
- package/webui/build/_app/immutable/nodes/13.nT3SOzEB.js +0 -1
- package/webui/build/_app/immutable/nodes/14.BHnIxbVM.js +0 -1
- package/webui/build/_app/immutable/nodes/15.CLjT9il3.js +0 -1
- package/webui/build/_app/immutable/nodes/16.BD-mKCLN.js +0 -24
- package/webui/build/_app/immutable/nodes/17.BtYZF6FM.js +0 -1
- package/webui/build/_app/immutable/nodes/18.Ba_qJjp6.js +0 -1
- package/webui/build/_app/immutable/nodes/2.BYWOpaxy.js +0 -1
- package/webui/build/_app/immutable/nodes/3.Dt5o2Fmz.js +0 -1
- package/webui/build/_app/immutable/nodes/4.DTSxpKm7.js +0 -2
- package/webui/build/_app/immutable/nodes/5.Dy3vSsIP.js +0 -1
- package/webui/build/_app/immutable/nodes/6.DvclsL6H.js +0 -1
- package/webui/build/_app/immutable/nodes/7.D2nJy-Uz.js +0 -1
- package/webui/build/_app/immutable/nodes/8.C75mhrqs.js +0 -1
- package/webui/build/_app/immutable/nodes/9.Bp_QXw3w.js +0 -1
- package/webui/build/_app/version.json +0 -1
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export const id = "hacker-news-newest";
|
|
2
|
+
export const name = "Hacker News Newest";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/news\.ycombinator\.com\/newest\/?(\?.*)?$/i;
|
|
4
|
+
export const refreshInterval = "10min";
|
|
5
|
+
|
|
1
6
|
let _deps;
|
|
2
7
|
|
|
3
8
|
// Hacker News newest 插件:解析 newest 列表页为 FeedItem(仅列表,不做正文 enrich)
|
|
@@ -17,7 +22,7 @@ function toAbsoluteUrl(rawHref, baseUrl) {
|
|
|
17
22
|
if (!href || href.startsWith("#") || href.startsWith("javascript:")) return null;
|
|
18
23
|
try {
|
|
19
24
|
const url = new URL(href, baseUrl);
|
|
20
|
-
if (!/^https
|
|
25
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
21
26
|
return url.href;
|
|
22
27
|
} catch {
|
|
23
28
|
return null;
|
|
@@ -88,7 +93,7 @@ function parseMeta(root, row, itemId) {
|
|
|
88
93
|
}
|
|
89
94
|
|
|
90
95
|
|
|
91
|
-
async function fetchItems(sourceId, ctx) {
|
|
96
|
+
export async function fetchItems(sourceId, ctx) {
|
|
92
97
|
_deps = ctx.deps;
|
|
93
98
|
const { html, finalUrl } = await ctx.fetchHtml(sourceId, { waitMs: 3000 });
|
|
94
99
|
const root = _deps.parseHtml(html);
|
|
@@ -121,10 +126,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
121
126
|
return items;
|
|
122
127
|
}
|
|
123
128
|
|
|
124
|
-
|
|
125
|
-
export default {
|
|
126
|
-
id: "hacker-news-newest",
|
|
127
|
-
listUrlPattern: /^https?:\/\/news\.ycombinator\.com\/newest\/?(\?.*)?$/i,
|
|
128
|
-
refreshInterval: "10min",
|
|
129
|
-
fetchItems,
|
|
130
|
-
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export const id = "harvard-dataverse";
|
|
2
|
+
export const name = "Harvard Dataverse";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/dataverse\.harvard\.edu(?:\/?$|\/\?.*|\/dataverse\/[^/?#]+\/?(?:\?.*)?|\/dataverse\.xhtml(?:\?.*)?)$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
|
|
@@ -34,7 +38,7 @@ function toHttpUrl(rawUrl, baseUrl = DATAVERSE_ORIGIN) {
|
|
|
34
38
|
if (!text) return null;
|
|
35
39
|
try {
|
|
36
40
|
const url = new URL(text, baseUrl);
|
|
37
|
-
if (!/^https
|
|
41
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
38
42
|
return url.href;
|
|
39
43
|
} catch {
|
|
40
44
|
return null;
|
|
@@ -131,7 +135,7 @@ function toFeedItem(record, index) {
|
|
|
131
135
|
};
|
|
132
136
|
}
|
|
133
137
|
|
|
134
|
-
async function fetchItems(sourceId, ctx) {
|
|
138
|
+
export async function fetchItems(sourceId, ctx) {
|
|
135
139
|
_deps = ctx.deps;
|
|
136
140
|
const query = buildQuery(sourceId);
|
|
137
141
|
const apiUrl = `${DATAVERSE_SEARCH_API}?${query.toString()}`;
|
|
@@ -158,9 +162,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
158
162
|
return items;
|
|
159
163
|
}
|
|
160
164
|
|
|
161
|
-
export default {
|
|
162
|
-
id: "harvard-dataverse",
|
|
163
|
-
listUrlPattern:
|
|
164
|
-
/^https?:\/\/dataverse\.harvard\.edu(?:\/?$|\/\?.*|\/dataverse\/[^/?#]+\/?(?:\?.*)?|\/dataverse\.xhtml(?:\?.*)?)$/i,
|
|
165
|
-
fetchItems,
|
|
166
|
-
};
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export const id = "huaweicloud-bbs-blogs";
|
|
2
|
+
export const name = "Huaweicloud Bbs Blogs";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/bbs\.huaweicloud\.com\/blogs\/?(\?.*)?$/i;
|
|
4
|
+
export const refreshInterval = "1h";
|
|
5
|
+
|
|
1
6
|
let _deps;
|
|
2
7
|
|
|
3
8
|
// 华为云社区博客插件:抓取 https://bbs.huaweicloud.com/blogs 列表条目(默认仅列表,不做 enrich)
|
|
@@ -28,7 +33,7 @@ function toAbsoluteUrl(href, baseUrl) {
|
|
|
28
33
|
if (!href) return null;
|
|
29
34
|
try {
|
|
30
35
|
const url = new URL(href, baseUrl);
|
|
31
|
-
if (!/^https
|
|
36
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
32
37
|
return url.href;
|
|
33
38
|
} catch {
|
|
34
39
|
return null;
|
|
@@ -160,7 +165,7 @@ function parseFromTitleAnchors(root, pageUrl) {
|
|
|
160
165
|
}
|
|
161
166
|
|
|
162
167
|
|
|
163
|
-
async function fetchItems(sourceId, ctx) {
|
|
168
|
+
export async function fetchItems(sourceId, ctx) {
|
|
164
169
|
_deps = ctx.deps;
|
|
165
170
|
const { html, finalUrl } = await ctx.fetchHtml(sourceId, { waitMs: 4500 });
|
|
166
171
|
const root = _deps.parseHtml(html);
|
|
@@ -176,10 +181,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
176
181
|
return items;
|
|
177
182
|
}
|
|
178
183
|
|
|
179
|
-
|
|
180
|
-
export default {
|
|
181
|
-
id: "huaweicloud-bbs-blogs",
|
|
182
|
-
listUrlPattern: /^https?:\/\/bbs\.huaweicloud\.com\/blogs\/?(\?.*)?$/i,
|
|
183
|
-
refreshInterval: "1h",
|
|
184
|
-
fetchItems,
|
|
185
|
-
};
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
// lingowhale://articles?app_id=xxx&app_secret=yyy
|
|
9
9
|
// 也可通过环境变量提供(优先级低于 URL 参数):
|
|
10
10
|
// LINGOWHALE_APP_ID / LINGOWHALE_APP_SECRET
|
|
11
|
-
|
|
11
|
+
export const id = "lingowhale";
|
|
12
|
+
export const name = "Lingowhale";
|
|
13
|
+
export const listUrlPattern = /^lingowhale:\/\//;
|
|
14
|
+
export const refreshInterval = "1h";
|
|
12
15
|
|
|
13
16
|
const BASE_URL = "https://open.lingowhale.com/open-api/v1";
|
|
14
17
|
|
|
@@ -104,16 +107,11 @@ async function fetchTodayArticles(appId, appSecret) {
|
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
|
|
107
|
-
export
|
|
108
|
-
id: "lingowhale",
|
|
109
|
-
listUrlPattern: /^lingowhale:\/\//,
|
|
110
|
-
refreshInterval: "1h",
|
|
111
|
-
|
|
112
|
-
async fetchItems(sourceId, _ctx) {
|
|
110
|
+
export async function fetchItems(sourceId, _ctx) {
|
|
113
111
|
const { appId, appSecret } = resolveCredentials(sourceId);
|
|
114
112
|
const endpoint = resolveEndpoint(sourceId);
|
|
115
113
|
const maxPages = resolveMaxPages(sourceId);
|
|
116
114
|
if (endpoint === "today") return fetchTodayArticles(appId, appSecret);
|
|
117
115
|
return fetchArticles(appId, appSecret, maxPages);
|
|
118
|
-
}
|
|
119
|
-
|
|
116
|
+
}
|
|
117
|
+
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export const id = "meituan-tech";
|
|
2
|
+
export const name = "Meituan Tech";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/(www\.)?tech\.meituan\.com(\/.*)?$/i;
|
|
4
|
+
export const refreshInterval = "1day";
|
|
5
|
+
|
|
1
6
|
let _deps;
|
|
2
7
|
|
|
3
8
|
// 美团技术团队博客:https://tech.meituan.com/
|
|
@@ -12,7 +17,7 @@ function toAbsoluteUrl(href, baseUrl) {
|
|
|
12
17
|
if (!href) return null;
|
|
13
18
|
try {
|
|
14
19
|
const url = new URL(href, baseUrl);
|
|
15
|
-
if (!/^https
|
|
20
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
16
21
|
return url.href;
|
|
17
22
|
} catch {
|
|
18
23
|
return null;
|
|
@@ -34,7 +39,7 @@ function hashGuid(link) {
|
|
|
34
39
|
return _deps.createHash("sha256").update(link).digest("hex");
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
async function fetchItems(sourceId, ctx) {
|
|
42
|
+
export async function fetchItems(sourceId, ctx) {
|
|
38
43
|
_deps = ctx.deps;
|
|
39
44
|
const { html, finalUrl } = await ctx.fetchHtml(sourceId, {
|
|
40
45
|
waitMs: 5000,
|
|
@@ -120,11 +125,3 @@ async function enrichItem(item, ctx) {
|
|
|
120
125
|
return ctx.extractItem(item);
|
|
121
126
|
}
|
|
122
127
|
|
|
123
|
-
export default {
|
|
124
|
-
id: "meituan-tech",
|
|
125
|
-
listUrlPattern: /^https?:\/\/(www\.)?tech\.meituan\.com(\/.*)?$/i,
|
|
126
|
-
detailUrlPattern: /^https?:\/\/(www\.)?tech\.meituan\.com\/\d{4}\/\d{2}\/\d{2}\/[^/]+\.html(?:\?.*)?$/i,
|
|
127
|
-
refreshInterval: "1day",
|
|
128
|
-
fetchItems,
|
|
129
|
-
enrichItem,
|
|
130
|
-
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export const id = "meta-ai-publications";
|
|
2
|
+
export const name = "Meta AI Publications";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/ai\.meta\.com\/results\/?\?.*content_types(?:%5B0%5D|\[0\])=publication(?:&.*)?$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
// Meta AI Publications 插件:抓取结果页中的 publication 条目(不做正文 enrich)
|
|
@@ -5,8 +9,6 @@ let _deps;
|
|
|
5
9
|
|
|
6
10
|
|
|
7
11
|
const PUBLICATION_PATH_RE = /^\/research\/publications\/[^?#]+\/?$/i;
|
|
8
|
-
const PUBLICATION_RESULTS_URL_RE =
|
|
9
|
-
/^https?:\/\/ai\.meta\.com\/results\/?\?.*content_types(?:%5B0%5D|\[0\])=publication(?:&.*)?$/i;
|
|
10
12
|
const MONTH_TO_INDEX = {
|
|
11
13
|
january: 0,
|
|
12
14
|
february: 1,
|
|
@@ -42,7 +44,7 @@ function toAbsolutePublicationUrl(rawHref, pageUrl) {
|
|
|
42
44
|
if (!href || href.startsWith("#") || href.startsWith("javascript:")) return null;
|
|
43
45
|
try {
|
|
44
46
|
const url = new URL(href, pageUrl);
|
|
45
|
-
if (!/^https
|
|
47
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
46
48
|
if (url.hostname !== "ai.meta.com") return null;
|
|
47
49
|
if (!PUBLICATION_PATH_RE.test(url.pathname)) return null;
|
|
48
50
|
return url.href;
|
|
@@ -169,7 +171,7 @@ function extractSummary(card, title) {
|
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
|
|
172
|
-
async function fetchItems(sourceId, ctx) {
|
|
174
|
+
export async function fetchItems(sourceId, ctx) {
|
|
173
175
|
_deps = ctx.deps;
|
|
174
176
|
const { html, finalUrl, status } = await ctx.fetchHtml(sourceId, { waitMs: 3500, purify: false });
|
|
175
177
|
if (status >= 400) {
|
|
@@ -212,10 +214,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
212
214
|
}
|
|
213
215
|
return items;
|
|
214
216
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
export default {
|
|
218
|
-
id: "meta-ai-publications",
|
|
219
|
-
listUrlPattern: PUBLICATION_RESULTS_URL_RE,
|
|
220
|
-
fetchItems,
|
|
221
|
-
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export const id = "mila-quebec";
|
|
2
|
+
export const name = "Mila Quebec";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/(www\.)?mila\.quebec\/en(?:\/news)?(?:\/)?(?:\?.*)?$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
// Mila (Quebec AI Institute) 新闻列表插件:支持首页 /en 与新闻页 /en/news
|
|
@@ -39,7 +43,7 @@ function toAbsoluteHttpUrl(rawHref, baseUrl) {
|
|
|
39
43
|
if (!href || href.startsWith("#") || href.startsWith("javascript:")) return null;
|
|
40
44
|
try {
|
|
41
45
|
const url = new URL(href, baseUrl);
|
|
42
|
-
if (!/^https
|
|
46
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
43
47
|
return url.href;
|
|
44
48
|
} catch {
|
|
45
49
|
return null;
|
|
@@ -131,7 +135,7 @@ function chooseSummary(node, title) {
|
|
|
131
135
|
}
|
|
132
136
|
|
|
133
137
|
|
|
134
|
-
async function fetchItems(sourceId, ctx) {
|
|
138
|
+
export async function fetchItems(sourceId, ctx) {
|
|
135
139
|
_deps = ctx.deps;
|
|
136
140
|
const { html, finalUrl } = await ctx.fetchHtml(sourceId, { waitMs: 4000 });
|
|
137
141
|
const root = _deps.parseHtml(html);
|
|
@@ -191,9 +195,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
191
195
|
return items;
|
|
192
196
|
}
|
|
193
197
|
|
|
194
|
-
|
|
195
|
-
export default {
|
|
196
|
-
id: "mila-quebec",
|
|
197
|
-
listUrlPattern: /^https?:\/\/(www\.)?mila\.quebec\/en(?:\/news)?(?:\/)?(?:\?.*)?$/i,
|
|
198
|
-
fetchItems,
|
|
199
|
-
};
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
export const id = "mit-csail-research";
|
|
2
|
+
export const name = "MIT CSAIL Research";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/(www\.)?csail\.mit\.edu\/research(?:\?.*)?$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
// MIT CSAIL Research plugin: warm up via homepage, then parse /research list items.
|
|
4
8
|
|
|
5
9
|
|
|
6
10
|
|
|
7
|
-
const SITE_ID =
|
|
11
|
+
const SITE_ID = id;
|
|
8
12
|
const CSAIL_HOME_URL = "https://www.csail.mit.edu/";
|
|
9
13
|
const CSAIL_RESEARCH_PATH = "/research";
|
|
10
14
|
const SUMMARY_SELECTOR = "div, p, span, h2, h3, h4, a";
|
|
@@ -35,7 +39,7 @@ function toAbsoluteHttpUrl(rawHref, baseUrl) {
|
|
|
35
39
|
if (!href || href.startsWith("#") || href.startsWith("javascript:") || href.startsWith("mailto:")) return null;
|
|
36
40
|
try {
|
|
37
41
|
const url = new URL(href, baseUrl);
|
|
38
|
-
if (!/^https
|
|
42
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
39
43
|
return url.href;
|
|
40
44
|
} catch {
|
|
41
45
|
return null;
|
|
@@ -169,7 +173,7 @@ function parseItems(html, finalUrl, requestedCategory) {
|
|
|
169
173
|
}
|
|
170
174
|
|
|
171
175
|
|
|
172
|
-
async function fetchItems(sourceId, ctx) {
|
|
176
|
+
export async function fetchItems(sourceId, ctx) {
|
|
173
177
|
_deps = ctx.deps;
|
|
174
178
|
const sourceUrl = new URL(sourceId);
|
|
175
179
|
const requestedCategory = sourceUrl.searchParams.get("category") ?? "";
|
|
@@ -200,9 +204,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
200
204
|
return items;
|
|
201
205
|
}
|
|
202
206
|
|
|
203
|
-
|
|
204
|
-
export default {
|
|
205
|
-
id: SITE_ID,
|
|
206
|
-
listUrlPattern: /^https?:\/\/(www\.)?csail\.mit\.edu\/research(?:\?.*)?$/i,
|
|
207
|
-
fetchItems,
|
|
208
|
-
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export const id = "moonshot";
|
|
2
|
+
export const name = "Moonshot";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/(www\.)?moonshot\.ai(?:\/[a-z]{2}(?:-[a-z]{2})?)?\/?(\?.*)?$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
// Moonshot 官方站插件:抓取首页“最新研究”列表,输出 FeedItem(不含 enrich)
|
|
@@ -24,7 +28,7 @@ function toAbsoluteHttpUrl(rawHref, baseUrl) {
|
|
|
24
28
|
if (!href || href.startsWith("#") || href.startsWith("javascript:")) return null;
|
|
25
29
|
try {
|
|
26
30
|
const url = new URL(href, baseUrl);
|
|
27
|
-
if (!/^https
|
|
31
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
28
32
|
return url.href;
|
|
29
33
|
} catch {
|
|
30
34
|
return null;
|
|
@@ -95,7 +99,7 @@ function collectCandidateAnchors(root) {
|
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
|
|
98
|
-
async function fetchItems(sourceId, ctx) {
|
|
102
|
+
export async function fetchItems(sourceId, ctx) {
|
|
99
103
|
_deps = ctx.deps;
|
|
100
104
|
const { html, finalUrl } = await ctx.fetchHtml(sourceId, { waitMs: 4500 });
|
|
101
105
|
const root = _deps.parseHtml(html);
|
|
@@ -119,9 +123,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
119
123
|
return items;
|
|
120
124
|
}
|
|
121
125
|
|
|
122
|
-
|
|
123
|
-
export default {
|
|
124
|
-
id: "moonshot",
|
|
125
|
-
listUrlPattern: /^https?:\/\/(www\.)?moonshot\.ai(?:\/[a-z]{2}(?:-[a-z]{2})?)?\/?(\?.*)?$/i,
|
|
126
|
-
fetchItems,
|
|
127
|
-
};
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export const id = "opendatalab-news";
|
|
2
|
+
export const name = "Opendatalab News";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/(www\.)?opendatalab\.(org\.cn|com)\/news\/?(\?.*)?$/i;
|
|
4
|
+
export const refreshInterval = "1h";
|
|
5
|
+
|
|
1
6
|
let _deps;
|
|
2
7
|
|
|
3
8
|
|
|
@@ -139,7 +144,7 @@ function mapItems(records, source) {
|
|
|
139
144
|
return items;
|
|
140
145
|
}
|
|
141
146
|
|
|
142
|
-
async function fetchItems(_sourceId, _ctx) {
|
|
147
|
+
export async function fetchItems(_sourceId, _ctx) {
|
|
143
148
|
_deps = _ctx.deps;
|
|
144
149
|
const collected = [];
|
|
145
150
|
|
|
@@ -166,9 +171,3 @@ async function fetchItems(_sourceId, _ctx) {
|
|
|
166
171
|
return deduped;
|
|
167
172
|
}
|
|
168
173
|
|
|
169
|
-
export default {
|
|
170
|
-
id: "opendatalab-news",
|
|
171
|
-
listUrlPattern: /^https?:\/\/(www\.)?opendatalab\.(org\.cn|com)\/news\/?(\?.*)?$/i,
|
|
172
|
-
refreshInterval: "1h",
|
|
173
|
-
fetchItems,
|
|
174
|
-
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export const id = "opendatalab";
|
|
2
|
+
export const name = "Opendatalab";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/(www\.)?opendatalab\.(org\.cn|com)\/?(?:datasets\/?)?(?:\?.*)?$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
|
|
@@ -72,7 +76,7 @@ function parsePaginationFromSourceId(sourceId) {
|
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
async function fetchItems(sourceId, ctx) {
|
|
79
|
+
export async function fetchItems(sourceId, ctx) {
|
|
76
80
|
_deps = ctx.deps;
|
|
77
81
|
const { pageNo, pageSize } = parsePaginationFromSourceId(sourceId);
|
|
78
82
|
const response = await fetch(OPENDATALAB_LIST_API, {
|
|
@@ -102,8 +106,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
102
106
|
return items;
|
|
103
107
|
}
|
|
104
108
|
|
|
105
|
-
export default {
|
|
106
|
-
id: "opendatalab",
|
|
107
|
-
listUrlPattern: /^https?:\/\/(www\.)?opendatalab\.(org\.cn|com)\/?(?:datasets\/?)?(?:\?.*)?$/i,
|
|
108
|
-
fetchItems,
|
|
109
|
-
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export const id = "opendrivelab-autonomous-driving";
|
|
2
|
+
export const name = "Opendrivelab Autonomous Driving";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/(www\.)?opendrivelab\.com\/AutonomousDriving\/?(\?.*)?$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
// OpenDriveLab Autonomous Driving 插件:抓取时间线条目并输出 FeedItem(不含 enrich)
|
|
@@ -17,7 +21,7 @@ function toAbsoluteHttpUrl(rawHref, baseUrl) {
|
|
|
17
21
|
if (!href || href.startsWith("#") || href.startsWith("javascript:")) return null;
|
|
18
22
|
try {
|
|
19
23
|
const url = new URL(href, baseUrl);
|
|
20
|
-
if (!/^https
|
|
24
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
21
25
|
return url.href;
|
|
22
26
|
} catch {
|
|
23
27
|
return null;
|
|
@@ -72,7 +76,7 @@ function findTitleAnchor(li, finalUrl) {
|
|
|
72
76
|
return fallback;
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
async function fetchItems(sourceId, ctx) {
|
|
79
|
+
export async function fetchItems(sourceId, ctx) {
|
|
76
80
|
_deps = ctx.deps;
|
|
77
81
|
const { html, finalUrl } = await ctx.fetchHtml(sourceId, { waitMs: 3500 });
|
|
78
82
|
const root = _deps.parseHtml(html);
|
|
@@ -107,8 +111,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
107
111
|
return items;
|
|
108
112
|
}
|
|
109
113
|
|
|
110
|
-
export default {
|
|
111
|
-
id: "opendrivelab-autonomous-driving",
|
|
112
|
-
listUrlPattern: /^https?:\/\/(www\.)?opendrivelab\.com\/AutonomousDriving\/?(\?.*)?$/i,
|
|
113
|
-
fetchItems,
|
|
114
|
-
};
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
export const id = "opendrivelab-embodiedai";
|
|
2
|
+
export const name = "Opendrivelab Embodiedai";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/(www\.)?opendrivelab\.com\/EmbodiedAI\/?(\?.*)?$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
|
|
4
|
-
const SITE_ID =
|
|
8
|
+
const SITE_ID = id;
|
|
5
9
|
const DATE_RE = /\b(20\d{2})[./-](\d{1,2})[./-](\d{1,2})\b/;
|
|
6
10
|
const ACTION_LINK_LABELS = new Set([
|
|
7
11
|
"paper",
|
|
@@ -29,7 +33,7 @@ function toAbsoluteHttpUrl(rawHref, baseUrl) {
|
|
|
29
33
|
if (!href || href.startsWith("#") || href.startsWith("javascript:")) return null;
|
|
30
34
|
try {
|
|
31
35
|
const url = new URL(href, baseUrl);
|
|
32
|
-
if (!/^https
|
|
36
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
33
37
|
return url.href;
|
|
34
38
|
} catch {
|
|
35
39
|
return null;
|
|
@@ -94,7 +98,7 @@ function buildItemsFromHtml(html, finalUrl) {
|
|
|
94
98
|
return items;
|
|
95
99
|
}
|
|
96
100
|
|
|
97
|
-
async function fetchItems(sourceId, ctx) {
|
|
101
|
+
export async function fetchItems(sourceId, ctx) {
|
|
98
102
|
_deps = ctx.deps;
|
|
99
103
|
const { html, finalUrl } = await ctx.fetchHtml(sourceId, { waitMs: 3500 });
|
|
100
104
|
const items = buildItemsFromHtml(html, finalUrl);
|
|
@@ -107,8 +111,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
107
111
|
throw new Error(`[${SITE_ID}] 未解析到 Embodied AI 条目,页面结构可能已变化`);
|
|
108
112
|
}
|
|
109
113
|
|
|
110
|
-
export default {
|
|
111
|
-
id: SITE_ID,
|
|
112
|
-
listUrlPattern: /^https?:\/\/(www\.)?opendrivelab\.com\/EmbodiedAI\/?(\?.*)?$/i,
|
|
113
|
-
fetchItems,
|
|
114
|
-
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export const id = "opendrivelab-publications";
|
|
2
|
+
export const name = "Opendrivelab Publications";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/(www\.)?opendrivelab\.com\/publications\/?(\?.*)?$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
|
|
@@ -16,7 +20,7 @@ function toHttpUrl(rawHref, baseUrl) {
|
|
|
16
20
|
if (!rawHref) return null;
|
|
17
21
|
try {
|
|
18
22
|
const url = new URL(rawHref, baseUrl);
|
|
19
|
-
if (!/^https
|
|
23
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
20
24
|
return url;
|
|
21
25
|
} catch {
|
|
22
26
|
return null;
|
|
@@ -83,7 +87,7 @@ function extractContext(anchor) {
|
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
|
|
86
|
-
async function fetchItems(sourceId, ctx) {
|
|
90
|
+
export async function fetchItems(sourceId, ctx) {
|
|
87
91
|
_deps = ctx.deps;
|
|
88
92
|
const { html, finalUrl } = await ctx.fetchHtml(sourceId, { waitMs: 3500 });
|
|
89
93
|
const root = _deps.parseHtml(html);
|
|
@@ -104,7 +108,7 @@ async function fetchItems(sourceId, ctx) {
|
|
|
104
108
|
if (seen.has(link)) continue;
|
|
105
109
|
seen.add(link);
|
|
106
110
|
|
|
107
|
-
const { summary, category, year } = extractContext(anchor);
|
|
111
|
+
const { summary, category: _category, year } = extractContext(anchor);
|
|
108
112
|
const pubDate = year != null ? new Date(Date.UTC(year, 0, 1)) : new Date();
|
|
109
113
|
|
|
110
114
|
items.push({
|
|
@@ -122,9 +126,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
122
126
|
return items;
|
|
123
127
|
}
|
|
124
128
|
|
|
125
|
-
|
|
126
|
-
export default {
|
|
127
|
-
id: "opendrivelab-publications",
|
|
128
|
-
listUrlPattern: /^https?:\/\/(www\.)?opendrivelab\.com\/publications\/?(\?.*)?$/i,
|
|
129
|
-
fetchItems,
|
|
130
|
-
};
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
export const id = "opendrivelab";
|
|
2
|
+
export const name = "Opendrivelab";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/(www\.)?opendrivelab\.com\/?(\?.*)?$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
// OpenDriveLab 首页插件:解析首页展示内容并输出 FeedItem(不含 enrich)
|
|
4
8
|
|
|
5
9
|
|
|
6
|
-
const SITE_ID =
|
|
10
|
+
const SITE_ID = id;
|
|
7
11
|
const NAVIGATION_TITLES = new Set([
|
|
8
12
|
"news",
|
|
9
13
|
"recruit",
|
|
@@ -58,7 +62,7 @@ function toAbsoluteHttpUrl(rawHref, baseUrl) {
|
|
|
58
62
|
if (!href || href.startsWith("#") || href.startsWith("javascript:") || href.startsWith("mailto:")) return null;
|
|
59
63
|
try {
|
|
60
64
|
const url = new URL(href, baseUrl);
|
|
61
|
-
if (!/^https
|
|
65
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
62
66
|
return url.href;
|
|
63
67
|
} catch {
|
|
64
68
|
return null;
|
|
@@ -307,7 +311,7 @@ function parseFromTitleAnchors(root, finalUrl, seen) {
|
|
|
307
311
|
return items;
|
|
308
312
|
}
|
|
309
313
|
|
|
310
|
-
async function fetchItems(sourceId, ctx) {
|
|
314
|
+
export async function fetchItems(sourceId, ctx) {
|
|
311
315
|
_deps = ctx.deps;
|
|
312
316
|
const { html, finalUrl } = await ctx.fetchHtml(sourceId, { waitMs: 4500 });
|
|
313
317
|
const root = _deps.parseHtml(html);
|
|
@@ -326,8 +330,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
326
330
|
throw new Error(`[${SITE_ID}] 未解析到首页条目,页面结构可能已变化`);
|
|
327
331
|
}
|
|
328
332
|
|
|
329
|
-
export default {
|
|
330
|
-
id: SITE_ID,
|
|
331
|
-
listUrlPattern: /^https?:\/\/(www\.)?opendrivelab\.com\/?(\?.*)?$/i,
|
|
332
|
-
fetchItems,
|
|
333
|
-
};
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
export const id = "paperswithcode";
|
|
2
|
+
export const name = "Paperswithcode";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/(www\.)?paperswithcode\.(co|com)(?:\/(?:papers)?\/?)?(?:\?.*)?$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
|
|
4
8
|
|
|
5
|
-
const SITE_ID =
|
|
9
|
+
const SITE_ID = id;
|
|
6
10
|
const API_ORIGIN = "https://paperswithcode.co";
|
|
7
11
|
const DEFAULT_TRENDING_LIMIT = 30;
|
|
8
12
|
const DEFAULT_MAX_AGE_DAYS = 180;
|
|
@@ -187,7 +191,7 @@ async function fetchLatestItems(sourceUrl) {
|
|
|
187
191
|
}
|
|
188
192
|
|
|
189
193
|
|
|
190
|
-
async function fetchItems(sourceId, _ctx) {
|
|
194
|
+
export async function fetchItems(sourceId, _ctx) {
|
|
191
195
|
_deps = _ctx.deps;
|
|
192
196
|
let sourceUrl;
|
|
193
197
|
try {
|
|
@@ -219,9 +223,3 @@ async function fetchItems(sourceId, _ctx) {
|
|
|
219
223
|
throw new Error(`[${SITE_ID}] 未解析到条目(${errors.join(" | ")})`);
|
|
220
224
|
}
|
|
221
225
|
|
|
222
|
-
|
|
223
|
-
export default {
|
|
224
|
-
id: SITE_ID,
|
|
225
|
-
listUrlPattern: /^https?:\/\/(www\.)?paperswithcode\.(co|com)(?:\/(?:papers)?\/?)?(?:\?.*)?$/i,
|
|
226
|
-
fetchItems,
|
|
227
|
-
};
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
export const id = "pjlab-adg-publications";
|
|
2
|
+
export const name = "PJLAB Adg Publications";
|
|
3
|
+
export const listUrlPattern = /^https:\/\/pjlab-adg\.github\.io\/publications\/?(\?.*)?$/i;
|
|
4
|
+
|
|
1
5
|
let _deps;
|
|
2
6
|
|
|
3
7
|
|
|
4
8
|
|
|
5
|
-
const SITE_ID =
|
|
9
|
+
const SITE_ID = id;
|
|
6
10
|
|
|
7
11
|
|
|
8
12
|
function normalizeText(text) {
|
|
@@ -33,7 +37,7 @@ function toAbsoluteLink(rawHref, baseUrl) {
|
|
|
33
37
|
if (!href || href.startsWith("#") || href.startsWith("javascript:")) return null;
|
|
34
38
|
try {
|
|
35
39
|
const url = new URL(href, baseUrl);
|
|
36
|
-
if (!/^https
|
|
40
|
+
if (!/^https:$/i.test(url.protocol)) return null;
|
|
37
41
|
return url.href;
|
|
38
42
|
} catch {
|
|
39
43
|
return null;
|
|
@@ -140,7 +144,7 @@ function parseOneEntry(liNode, currentYear, pageUrl) {
|
|
|
140
144
|
const fallbackYear = parseYear(`${periodical} ${detailNode.textContent}`);
|
|
141
145
|
const finalYear = currentYear ?? fallbackYear;
|
|
142
146
|
const pubDate = finalYear != null ? new Date(Date.UTC(finalYear, 0, 1, 0, 0, 0)) : new Date();
|
|
143
|
-
const
|
|
147
|
+
const _badge = normalizeText((liNode.querySelector(".abbr .badge") ?? liNode.querySelector("abbr"))?.textContent) || undefined;
|
|
144
148
|
const link = pickBestLink(detailNode, pageUrl, entryId);
|
|
145
149
|
const guidSeed = entryId || link || `${title}|${author ?? ""}|${finalYear ?? ""}`;
|
|
146
150
|
|
|
@@ -183,7 +187,7 @@ function parseItems(html, finalUrl) {
|
|
|
183
187
|
}
|
|
184
188
|
|
|
185
189
|
|
|
186
|
-
async function fetchItems(sourceId, ctx) {
|
|
190
|
+
export async function fetchItems(sourceId, ctx) {
|
|
187
191
|
_deps = ctx.deps;
|
|
188
192
|
const { html, finalUrl } = await ctx.fetchHtml(sourceId, { waitMs: 3500 });
|
|
189
193
|
const pageUrl = finalUrl || sourceId;
|
|
@@ -194,9 +198,3 @@ async function fetchItems(sourceId, ctx) {
|
|
|
194
198
|
return items;
|
|
195
199
|
}
|
|
196
200
|
|
|
197
|
-
|
|
198
|
-
export default {
|
|
199
|
-
id: SITE_ID,
|
|
200
|
-
listUrlPattern: /^https?:\/\/pjlab-adg\.github\.io\/publications\/?(\?.*)?$/i,
|
|
201
|
-
fetchItems,
|
|
202
|
-
};
|