newsnow 1.1.0 → 1.1.1
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 +31 -0
- package/dist/src/sources/36kr.js +57 -0
- package/dist/src/sources/bilibili.js +16 -2
- package/dist/src/sources/fastbull.js +4 -4
- package/dist/src/sources/index.js +1 -1
- package/dist/src/sources/linuxdo.js +27 -21
- package/dist/src/sources/pcbeta.js +1 -1
- package/dist/src/sources/qqvideo.js +20 -0
- package/dist/src/sources/smzdm.js +4 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,8 +36,39 @@ newsnow hackernews
|
|
|
36
36
|
# Output as JSON (pipeable to jq, etc.)
|
|
37
37
|
newsnow hackernews --json
|
|
38
38
|
|
|
39
|
+
# Pretty-print JSON
|
|
40
|
+
newsnow hackernews --json --pretty
|
|
41
|
+
|
|
42
|
+
# Limit number of items
|
|
43
|
+
newsnow hackernews --limit 5
|
|
44
|
+
|
|
45
|
+
# Select specific fields (JSON mode)
|
|
46
|
+
newsnow hackernews --json --fields title,url
|
|
47
|
+
|
|
39
48
|
# List sources as JSON
|
|
40
49
|
newsnow list --json
|
|
50
|
+
|
|
51
|
+
# Print machine-readable JSON Schema
|
|
52
|
+
newsnow schema
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### JSON Envelopes
|
|
56
|
+
|
|
57
|
+
All `--json` output uses structured envelopes:
|
|
58
|
+
|
|
59
|
+
**Fetch** (`newsnow <source> --json`):
|
|
60
|
+
```json
|
|
61
|
+
{ "source": "hackernews", "count": 30, "items": [...] }
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**List** (`newsnow list --json`):
|
|
65
|
+
```json
|
|
66
|
+
{ "count": 66, "sources": [{ "name": "hackernews", "category": "hackernews", "envVars": [] }, ...] }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Errors** (written to stderr):
|
|
70
|
+
```json
|
|
71
|
+
{ "error": "Unknown source \"foo\"", "code": "UNKNOWN_SOURCE", "suggestions": ["foobar"] }
|
|
41
72
|
```
|
|
42
73
|
|
|
43
74
|
## Sources
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { load } from "cheerio";
|
|
2
|
+
import { myFetch } from "../fetch.js";
|
|
3
|
+
import { parseRelativeDate } from "../utils.js";
|
|
4
|
+
const quick = async () => {
|
|
5
|
+
const baseURL = "https://www.36kr.com";
|
|
6
|
+
const url = `${baseURL}/newsflashes`;
|
|
7
|
+
const response = await myFetch(url);
|
|
8
|
+
const $ = load(response);
|
|
9
|
+
const news = [];
|
|
10
|
+
const $items = $(".newsflash-item");
|
|
11
|
+
$items.each((_, el) => {
|
|
12
|
+
const $el = $(el);
|
|
13
|
+
const $a = $el.find("a.item-title");
|
|
14
|
+
const url = $a.attr("href");
|
|
15
|
+
const title = $a.text();
|
|
16
|
+
const relativeDate = $el.find(".time").text();
|
|
17
|
+
if (url && title && relativeDate) {
|
|
18
|
+
news.push({
|
|
19
|
+
url: `${baseURL}${url}`,
|
|
20
|
+
title,
|
|
21
|
+
id: url,
|
|
22
|
+
extra: { date: parseRelativeDate(relativeDate, "Asia/Shanghai").valueOf() },
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return news;
|
|
27
|
+
};
|
|
28
|
+
const renqi = async () => {
|
|
29
|
+
const url = "https://gateway.36kr.com/api/mis/nav/home/nav/rank/hot";
|
|
30
|
+
const response = await myFetch(url, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: {
|
|
33
|
+
"Content-Type": "application/json",
|
|
34
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
|
|
35
|
+
},
|
|
36
|
+
body: {
|
|
37
|
+
partner_id: "wap",
|
|
38
|
+
param: { siteId: 1, platformId: 2 },
|
|
39
|
+
timestamp: Date.now(),
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
const items = response?.data?.hotRankList ?? [];
|
|
43
|
+
return items.map((item) => {
|
|
44
|
+
const m = item.templateMaterial ?? {};
|
|
45
|
+
return {
|
|
46
|
+
url: `https://36kr.com/p/${item.itemId}`,
|
|
47
|
+
title: m.widgetTitle ?? "",
|
|
48
|
+
id: String(item.itemId),
|
|
49
|
+
extra: { info: m.authorName },
|
|
50
|
+
};
|
|
51
|
+
}).filter((item) => item.title);
|
|
52
|
+
};
|
|
53
|
+
export default {
|
|
54
|
+
"36kr": quick,
|
|
55
|
+
"36kr-quick": quick,
|
|
56
|
+
"36kr-renqi": renqi,
|
|
57
|
+
};
|
|
@@ -16,7 +16,14 @@ const hotSearch = async () => {
|
|
|
16
16
|
};
|
|
17
17
|
const hotVideo = async () => {
|
|
18
18
|
const url = "https://api.bilibili.com/x/web-interface/popular";
|
|
19
|
-
const res = await myFetch(url
|
|
19
|
+
const res = await myFetch(url, {
|
|
20
|
+
headers: {
|
|
21
|
+
"Referer": "https://www.bilibili.com",
|
|
22
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
if (!res?.data?.list)
|
|
26
|
+
throw new Error(`Bilibili popular API returned unexpected response: ${JSON.stringify(res).slice(0, 200)}`);
|
|
20
27
|
return res.data.list.map(video => ({
|
|
21
28
|
id: video.bvid,
|
|
22
29
|
title: video.title,
|
|
@@ -31,7 +38,14 @@ const hotVideo = async () => {
|
|
|
31
38
|
};
|
|
32
39
|
const ranking = async () => {
|
|
33
40
|
const url = "https://api.bilibili.com/x/web-interface/ranking/v2";
|
|
34
|
-
const res = await myFetch(url
|
|
41
|
+
const res = await myFetch(url, {
|
|
42
|
+
headers: {
|
|
43
|
+
"Referer": "https://www.bilibili.com/ranking/all",
|
|
44
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
if (!res?.data?.list)
|
|
48
|
+
throw new Error(`Bilibili ranking API returned unexpected response: ${JSON.stringify(res).slice(0, 200)}`);
|
|
35
49
|
return res.data.list.map(video => ({
|
|
36
50
|
id: video.bvid,
|
|
37
51
|
title: video.title,
|
|
@@ -7,11 +7,11 @@ const express = async () => {
|
|
|
7
7
|
const $main = $(".news-list");
|
|
8
8
|
const news = [];
|
|
9
9
|
$main.each((_, el) => {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const titleText = a.text();
|
|
10
|
+
const $el = $(el);
|
|
11
|
+
const titleText = $el.find(".title_name").text();
|
|
13
12
|
const title = titleText.match(/【(.+)】/)?.[1] ?? titleText;
|
|
14
|
-
const
|
|
13
|
+
const url = $el.find(".shear_box").attr("data-href");
|
|
14
|
+
const date = $el.attr("data-date");
|
|
15
15
|
if (url && title && date) {
|
|
16
16
|
news.push({
|
|
17
17
|
url: baseURL + url,
|
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
import { myFetch } from "../fetch.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import * as cheerio from "cheerio";
|
|
3
|
+
function parseDiscourseRSS(xml) {
|
|
4
|
+
const $ = cheerio.load(xml, { xmlMode: true });
|
|
5
|
+
const items = [];
|
|
6
|
+
$("item").each((_, el) => {
|
|
7
|
+
const pinned = $(el).find("discourse\\:topicPinned").text();
|
|
8
|
+
const archived = $(el).find("discourse\\:topicArchived").text();
|
|
9
|
+
if (pinned === "Yes" || archived === "Yes")
|
|
10
|
+
return;
|
|
11
|
+
const title = $(el).find("title").text();
|
|
12
|
+
const link = $(el).find("link").text();
|
|
13
|
+
const pubDate = $(el).find("pubDate").text();
|
|
14
|
+
if (title && link) {
|
|
15
|
+
items.push({
|
|
16
|
+
id: link,
|
|
17
|
+
title,
|
|
18
|
+
url: link,
|
|
19
|
+
pubDate: pubDate ? new Date(pubDate).getTime() : undefined,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
5
22
|
});
|
|
6
|
-
return
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
url: `https://linux.do/t/topic/${k.id}`,
|
|
12
|
-
}));
|
|
23
|
+
return items;
|
|
24
|
+
}
|
|
25
|
+
const hot = async () => {
|
|
26
|
+
const xml = await myFetch("https://linux.do/top/daily.rss");
|
|
27
|
+
return parseDiscourseRSS(xml);
|
|
13
28
|
};
|
|
14
29
|
const latest = async () => {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
});
|
|
18
|
-
return res.topic_list.topics
|
|
19
|
-
.filter(k => k.visible && !k.archived && !k.pinned)
|
|
20
|
-
.map(k => ({
|
|
21
|
-
id: k.id,
|
|
22
|
-
title: k.title,
|
|
23
|
-
pubDate: new Date(k.created_at).valueOf(),
|
|
24
|
-
url: `https://linux.do/t/topic/${k.id}`,
|
|
25
|
-
}));
|
|
30
|
+
const xml = await myFetch("https://linux.do/latest.rss");
|
|
31
|
+
return parseDiscourseRSS(xml);
|
|
26
32
|
};
|
|
27
33
|
export default {
|
|
28
34
|
"linuxdo": latest,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fetchRSS } from "../rss.js";
|
|
2
2
|
export default {
|
|
3
3
|
"pcbeta-windows11": () => fetchRSS("https://bbs.pcbeta.com/forum.php?mod=rss&fid=563&auth=0"),
|
|
4
|
-
"pcbeta-windows": () => fetchRSS("https://bbs.pcbeta.com/forum.php?mod=rss&fid=
|
|
4
|
+
"pcbeta-windows": () => fetchRSS("https://bbs.pcbeta.com/forum.php?mod=rss&fid=548&auth=0"),
|
|
5
5
|
};
|
|
@@ -31,10 +31,30 @@ const hotSearch = async () => {
|
|
|
31
31
|
module_strategy_id: {},
|
|
32
32
|
sub_module_id: "20251106065177",
|
|
33
33
|
flip_params: {
|
|
34
|
+
folding_screen_show_num: "",
|
|
35
|
+
is_mvl: "1",
|
|
36
|
+
mvl_strategy_info: JSON.stringify({
|
|
37
|
+
default_strategy_id: "06755800b45b49238582a6fa1ad0f5c5",
|
|
38
|
+
default_version: "3836",
|
|
39
|
+
hit_page_uuid: "b5080d97dc694a5fb50eb9e7c99326ac",
|
|
40
|
+
hit_tab_info: null,
|
|
41
|
+
gray_status_info: null,
|
|
42
|
+
bypass_to_un_exp_id: "",
|
|
43
|
+
}),
|
|
44
|
+
mvl_sub_mod_id: "20251106065177",
|
|
45
|
+
pad_post_show_num: "",
|
|
46
|
+
pad_pro_post_show_num: "",
|
|
47
|
+
pad_pro_small_hor_pic_display_num: "",
|
|
48
|
+
pad_small_hor_pic_display_num: "",
|
|
34
49
|
page_id: "scms_shake",
|
|
35
50
|
page_num: "0",
|
|
36
51
|
page_type: "scms_shake",
|
|
52
|
+
post_show_num: "",
|
|
53
|
+
shake_size: "",
|
|
54
|
+
small_hor_pic_display_num: "",
|
|
37
55
|
source_key: "100113",
|
|
56
|
+
un_policy_id: "06755800b45b49238582a6fa1ad0f5c5",
|
|
57
|
+
un_strategy_id: "06755800b45b49238582a6fa1ad0f5c5",
|
|
38
58
|
},
|
|
39
59
|
relace_children_key: [],
|
|
40
60
|
},
|
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const html = await myFetch(baseURL);
|
|
6
|
-
const $ = cheerio.load(html);
|
|
7
|
-
const $main = $("#feed-main-list .z-feed-title");
|
|
8
|
-
const news = [];
|
|
9
|
-
$main.each((_, el) => {
|
|
10
|
-
const a = $(el).find("a");
|
|
11
|
-
const url = a.attr("href");
|
|
12
|
-
const title = a.text();
|
|
13
|
-
news.push({ url, title, id: url });
|
|
14
|
-
});
|
|
15
|
-
return news;
|
|
16
|
-
}
|
|
17
|
-
export default { smzdm: handler };
|
|
1
|
+
import { fetchRSS } from "../rss.js";
|
|
2
|
+
export default {
|
|
3
|
+
smzdm: () => fetchRSS("https://post.smzdm.com/feed/"),
|
|
4
|
+
};
|