rssany 0.1.4 → 0.1.6

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.
Files changed (78) hide show
  1. package/app/plugins/builtin/agi-eval-evaluation.rssany.js +188 -0
  2. package/app/plugins/builtin/amii-research-talent.rssany.js +73 -0
  3. package/app/plugins/builtin/anthropic-research.rssany.js +155 -0
  4. package/app/plugins/builtin/appen-resources.rssany.js +155 -0
  5. package/app/plugins/builtin/baai-wudao-paper-article.rssany.js +185 -0
  6. package/app/plugins/builtin/baaidata-csdn.rssany.js +242 -0
  7. package/app/plugins/builtin/baidu-research.rssany.js +222 -0
  8. package/app/plugins/builtin/brightdata-blog.rssany.js +301 -0
  9. package/app/plugins/builtin/bytedance-seed-research.rssany.js +231 -0
  10. package/app/plugins/builtin/five-radar.rssany.js +490 -0
  11. package/app/plugins/builtin/flageval-news.rssany.js +118 -0
  12. package/app/plugins/builtin/google-deepmind-research.rssany.js +223 -0
  13. package/app/plugins/builtin/google-research-datasets.rssany.js +171 -0
  14. package/app/plugins/builtin/google-research.rssany.js +220 -0
  15. package/app/plugins/builtin/google.rssany.js +187 -0
  16. package/app/plugins/builtin/hacker-news-newest.rssany.js +130 -0
  17. package/app/plugins/builtin/harvard-dataverse.rssany.js +166 -0
  18. package/app/plugins/builtin/huaweicloud-bbs-blogs.rssany.js +185 -0
  19. package/app/plugins/builtin/lingowhale.rssany.js +119 -0
  20. package/app/plugins/builtin/meituan-tech.rssany.js +130 -0
  21. package/app/plugins/builtin/meta-ai-publications.rssany.js +221 -0
  22. package/app/plugins/builtin/mila-quebec.rssany.js +199 -0
  23. package/app/plugins/builtin/mit-csail-research.rssany.js +208 -0
  24. package/app/plugins/builtin/moonshot.rssany.js +127 -0
  25. package/app/plugins/builtin/opendatalab-news.rssany.js +174 -0
  26. package/app/plugins/builtin/opendatalab.rssany.js +109 -0
  27. package/app/plugins/builtin/opendrivelab-autonomous-driving.rssany.js +114 -0
  28. package/app/plugins/builtin/opendrivelab-embodiedai.rssany.js +114 -0
  29. package/app/plugins/builtin/opendrivelab-publications.rssany.js +130 -0
  30. package/app/plugins/builtin/opendrivelab.rssany.js +333 -0
  31. package/app/plugins/builtin/paperswithcode.rssany.js +227 -0
  32. package/app/plugins/builtin/pjlab-adg-publications.rssany.js +202 -0
  33. package/app/plugins/builtin/rss.rssany.js +11 -1
  34. package/app/plugins/builtin/selectdataset.rssany.js +206 -0
  35. package/app/plugins/builtin/sensetime-tech-achievements.rssany.js +154 -0
  36. package/app/plugins/builtin/supervisely-blog.rssany.js +159 -0
  37. package/app/plugins/builtin/theinformation-briefings.rssany.js +136 -0
  38. package/app/plugins/builtin/uci-ml-repository.rssany.js +111 -0
  39. package/app/plugins/builtin/venturebeat.rssany.js +97 -0
  40. package/app/plugins/builtin/worldlabs.rssany.js +129 -0
  41. package/app/plugins/builtin/x.rssany.js +328 -0
  42. package/app/plugins/builtin/xiaohongshu.rssany.js +283 -0
  43. package/app/plugins/builtin/zhipu-research.rssany.js +334 -0
  44. package/dist/index.js +62 -4
  45. package/dist/index.js.map +1 -1
  46. package/package.json +1 -1
  47. package/webui/build/200.html +6 -6
  48. package/webui/build/_app/immutable/assets/{0.DjU2hdCQ.css → 0.BB88QFoe.css} +1 -1
  49. package/webui/build/_app/immutable/assets/homeFeedPanelStore.CSvlNcpm.css +1 -0
  50. package/webui/build/_app/immutable/chunks/BwlaCkNX.js +36 -0
  51. package/webui/build/_app/immutable/chunks/C0J2-L94.js +1 -0
  52. package/webui/build/_app/immutable/chunks/CLOXMsDk.js +36 -0
  53. package/webui/build/_app/immutable/chunks/{C85CNwD2.js → DgceFEv5.js} +1 -1
  54. package/webui/build/_app/immutable/chunks/{CllQAdvt.js → SqCUd34O.js} +1 -1
  55. package/webui/build/_app/immutable/entry/{app.BcD2eSsQ.js → app.B8zBPipq.js} +2 -2
  56. package/webui/build/_app/immutable/entry/start.CxRCKeCl.js +1 -0
  57. package/webui/build/_app/immutable/nodes/0.ChLNE3xy.js +11 -0
  58. package/webui/build/_app/immutable/nodes/{1.DU9aYGAb.js → 1.1N74-4Io.js} +1 -1
  59. package/webui/build/_app/immutable/nodes/{10.Db6vw7Ih.js → 10.DY30t9Ib.js} +1 -1
  60. package/webui/build/_app/immutable/nodes/{11.BaAcorz3.js → 11.ITuxnukH.js} +1 -1
  61. package/webui/build/_app/immutable/nodes/12.qLzWqB1c.js +1 -0
  62. package/webui/build/_app/immutable/nodes/{14.DqT4pcrQ.js → 14.BHnIxbVM.js} +1 -1
  63. package/webui/build/_app/immutable/nodes/{15.CCLbjxnH.js → 15.CLjT9il3.js} +1 -1
  64. package/webui/build/_app/immutable/nodes/{16.DiigpVdP.js → 16.BD-mKCLN.js} +1 -1
  65. package/webui/build/_app/immutable/nodes/{3.DEcYOQc-.js → 3.Dt5o2Fmz.js} +1 -1
  66. package/webui/build/_app/immutable/nodes/{5.CvM1TkLG.js → 5.Dy3vSsIP.js} +1 -1
  67. package/webui/build/_app/immutable/nodes/{6.Dscr6LkS.js → 6.DvclsL6H.js} +1 -1
  68. package/webui/build/_app/immutable/nodes/{7.Bp60MobD.js → 7.D2nJy-Uz.js} +1 -1
  69. package/webui/build/_app/immutable/nodes/{8.DwSg0MHh.js → 8.C75mhrqs.js} +1 -1
  70. package/webui/build/_app/immutable/nodes/{9.BeYOUjxR.js → 9.Bp_QXw3w.js} +1 -1
  71. package/webui/build/_app/version.json +1 -1
  72. package/webui/build/_app/immutable/assets/homeFeedPanelStore.BopJZtHu.css +0 -1
  73. package/webui/build/_app/immutable/chunks/CdMsRjxJ.js +0 -1
  74. package/webui/build/_app/immutable/chunks/CtijX1u3.js +0 -31
  75. package/webui/build/_app/immutable/chunks/Dv1VCsiB.js +0 -41
  76. package/webui/build/_app/immutable/entry/start.CbkdJdz1.js +0 -1
  77. package/webui/build/_app/immutable/nodes/0.DSUDmOx2.js +0 -11
  78. package/webui/build/_app/immutable/nodes/12.Cg8AeCSH.js +0 -1
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import { promisify } from "node:util";
10
10
  import puppeteerCore from "puppeteer-core";
11
11
  import { parse, NodeType } from "node-html-parser";
12
12
  import Database from "better-sqlite3";
13
- import { mkdir, copyFile, access, rename, readFile, writeFile, readdir, stat, unlink } from "node:fs/promises";
13
+ import { mkdir, writeFile, copyFile, access, rename, readFile, readdir, stat, unlink } from "node:fs/promises";
14
14
  import { fileURLToPath, pathToFileURL } from "node:url";
15
15
  import { createHash } from "node:crypto";
16
16
  import { JSDOM } from "jsdom";
@@ -188,16 +188,18 @@ function mergeSourceStatsRows(rows) {
188
188
  for (const row of rows) {
189
189
  const k = canonicalHttpSourceRef(row.source_url);
190
190
  const prev = map.get(k);
191
+ const count7 = row.count_7d ?? 0;
191
192
  if (!prev) {
192
- map.set(k, { count: row.count, latest_at: row.latest_at });
193
+ map.set(k, { count: row.count, count_7d: count7, latest_at: row.latest_at });
193
194
  } else {
194
195
  map.set(k, {
195
196
  count: prev.count + row.count,
197
+ count_7d: prev.count_7d + count7,
196
198
  latest_at: maxIso(prev.latest_at, row.latest_at)
197
199
  });
198
200
  }
199
201
  }
200
- return [...map.entries()].map(([source_url, v]) => ({ source_url, count: v.count, latest_at: v.latest_at })).sort((a, b) => b.count - a.count);
202
+ return [...map.entries()].map(([source_url, v]) => ({ source_url, count: v.count, count_7d: v.count_7d, latest_at: v.latest_at })).sort((a, b) => b.count - a.count);
201
203
  }
202
204
  const httpSourceRef = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
203
205
  __proto__: null,
@@ -218,6 +220,9 @@ const CONFIG_PATH = join(USER_DIR, "config.json");
218
220
  const LEGACY_SUBSCRIPTIONS_PATH = join(USER_DIR, "subscriptions.json");
219
221
  const BUILTIN_PLUGINS_DIR = join(PACKAGE_ROOT, "app/plugins/builtin");
220
222
  const USER_PLUGINS_DIR = join(USER_DIR, "plugins");
223
+ const USER_DIR_PACKAGE_JSON = join(USER_DIR, "package.json");
224
+ const USER_DIR_PACKAGE_JSON_MINIMAL = `${JSON.stringify({ type: "module", private: true, description: "RssAny user data root; marks plugins as ESM for Node" })}
225
+ `;
221
226
  const PLUGIN_SITE_TEMPLATE_PATH = join(PACKAGE_ROOT, "app/plugins/site.rssany.js");
222
227
  async function pathExists(p) {
223
228
  try {
@@ -262,11 +267,24 @@ async function seedExampleConfigsIfMissing() {
262
267
  }
263
268
  }
264
269
  }
270
+ async function ensureUserDirPackageJsonForPlugins() {
271
+ if (await pathExists(USER_DIR_PACKAGE_JSON)) return;
272
+ try {
273
+ await writeFile(USER_DIR_PACKAGE_JSON, USER_DIR_PACKAGE_JSON_MINIMAL, "utf-8");
274
+ logger.info("config", "已写入 .rssany/package.json(type: module,消除插件 ESM 歧义)", { path: USER_DIR_PACKAGE_JSON });
275
+ } catch (err) {
276
+ logger.warn("config", "写入 .rssany/package.json 失败", {
277
+ path: USER_DIR_PACKAGE_JSON,
278
+ err: err instanceof Error ? err.message : String(err)
279
+ });
280
+ }
281
+ }
265
282
  async function initUserDir() {
266
283
  await mkdir(USER_DIR, { recursive: true });
267
284
  await mkdir(DATA_DIR, { recursive: true });
268
285
  await mkdir(CACHE_DIR, { recursive: true });
269
286
  await mkdir(USER_PLUGINS_DIR, { recursive: true });
287
+ await ensureUserDirPackageJsonForPlugins();
270
288
  await seedExampleConfigsIfMissing();
271
289
  if (!await pathExists(SOURCES_CONFIG_PATH) && await pathExists(LEGACY_SUBSCRIPTIONS_PATH)) {
272
290
  await migrateFile(LEGACY_SUBSCRIPTIONS_PATH, SOURCES_CONFIG_PATH);
@@ -876,7 +894,11 @@ async function getSourceStats() {
876
894
  const { mergeSourceStatsRows: mergeSourceStatsRows2 } = await Promise.resolve().then(() => httpSourceRef);
877
895
  const db = await getDb();
878
896
  const rows = db.prepare(
879
- "SELECT source_url, COUNT(*) as count, MAX(COALESCE(pub_date, fetched_at)) as latest_at FROM items GROUP BY source_url ORDER BY count DESC"
897
+ `SELECT source_url,
898
+ COUNT(*) as count,
899
+ SUM(CASE WHEN julianday(fetched_at) >= julianday('now', '-7 days') THEN 1 ELSE 0 END) as count_7d,
900
+ MAX(COALESCE(pub_date, fetched_at)) as latest_at
901
+ FROM items GROUP BY source_url ORDER BY count DESC`
880
902
  ).all();
881
903
  return mergeSourceStatsRows2(rows);
882
904
  }
@@ -3381,6 +3403,42 @@ function registerSourcesRoutes(app) {
3381
3403
  return c.json({});
3382
3404
  }
3383
3405
  });
3406
+ app.post("/api/sources/open-browser", requireAdmin(), async (c) => {
3407
+ try {
3408
+ const body = await c.req.json();
3409
+ const raw = typeof body?.url === "string" ? body.url.trim() : "";
3410
+ if (!raw) return c.json({ ok: false, message: "缺少 url" }, 400);
3411
+ const lower = raw.toLowerCase();
3412
+ if (!lower.startsWith("http://") && !lower.startsWith("https://")) {
3413
+ return c.json({ ok: false, message: "仅支持 http(s) URL" }, 400);
3414
+ }
3415
+ const url = raw;
3416
+ const source = getSource(url);
3417
+ const merged = await getEffectiveProxyForListUrl(url, source);
3418
+ const proxy = resolveProxy({ proxy: merged });
3419
+ void launchBrowser({ headless: false, cacheDir: CACHE_DIR, proxy }).then(async (browser) => {
3420
+ try {
3421
+ const page = await browser.newPage();
3422
+ await applyProxyAuthToPage(page, { proxy: merged });
3423
+ const realUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
3424
+ await page.setUserAgent(realUserAgent);
3425
+ await page.setViewport({ width: 1366, height: 960 });
3426
+ await page.goto(url, { waitUntil: "domcontentloaded", timeout: 6e4 });
3427
+ page.once("close", () => {
3428
+ void browser.close().catch(() => {
3429
+ });
3430
+ });
3431
+ } catch {
3432
+ await browser.close().catch(() => {
3433
+ });
3434
+ }
3435
+ }).catch(() => {
3436
+ });
3437
+ return c.json({ ok: true, message: "已在爬虫浏览器中打开" });
3438
+ } catch {
3439
+ return c.json({ ok: false, message: "请求体无效" }, 400);
3440
+ }
3441
+ });
3384
3442
  app.get("/api/sources/raw", requireAdmin(), async (c) => {
3385
3443
  try {
3386
3444
  const raw = await getSourcesRaw();