-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhn-data.js
More file actions
59 lines (53 loc) · 2.11 KB
/
hn-data.js
File metadata and controls
59 lines (53 loc) · 2.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// NODUS HN Radar — HN list endpoints + batched item fetch
import { fetchItem } from "./hn-api.js";
const HN_BASE = "https://hacker-news.firebaseio.com/v0";
// listKey: "top" | "new" | "best" | "show" | "ask"
export async function fetchListIds(listKey) {
const map = {
top: "topstories",
new: "newstories",
best: "beststories",
show: "showstories",
ask: "askstories"
};
const path = map[listKey] || "topstories";
const res = await fetch(`${HN_BASE}/${path}.json`);
if (!res.ok) throw new Error(`HN ${listKey} fetch failed: ${res.status}`);
const ids = await res.json();
return Array.isArray(ids) ? ids : [];
}
// Parallel fetch up to `max` items
export async function fetchItemsBatch(ids, max = 30) {
const slice = ids.slice(0, max);
const results = await Promise.all(slice.map((id) => fetchItem(id).catch(() => null)));
return results.filter((it) => it && !it.deleted && !it.dead);
}
// Extract origin domain from item url (or null if Ask/Show without external url)
export function extractDomain(url) {
if (!url) return "";
try {
const u = new URL(url);
return u.hostname.replace(/^www\./, "");
} catch {
return "";
}
}
// Checks if the post's author replied in any top-level comment.
// item must already have its `kids` array populated.
export async function checkOPActive(item, sampleSize = 8) {
if (!item || !item.by || !Array.isArray(item.kids) || item.kids.length === 0) return false;
const slice = item.kids.slice(0, sampleSize);
const results = await Promise.all(slice.map((id) => fetchItem(id).catch(() => null)));
return results.some((c) => c && !c.deleted && !c.dead && c.by === item.by);
}
// Returns "show" | "ask" | "launch" | "tell" | "poll" | null based on title prefix
export function detectItemType(title) {
if (!title) return null;
const lower = title.toLowerCase();
if (lower.startsWith("show hn:")) return "show";
if (lower.startsWith("ask hn:")) return "ask";
if (lower.startsWith("launch hn:")) return "launch";
if (lower.startsWith("tell hn:")) return "tell";
if (lower.startsWith("poll:")) return "poll";
return null;
}