nx_learnmine.nx source
↩ module page · 106 lines · 5932 B
1// nx_learnmine.nx -- THE LEARNING-MINING COMMAND (operator 2026-09-06: farm creators and archives for videos, transcripts and
2// how-to text as supporting guides for the /compare rungs). Rung 1: digest an archive.org advancedsearch listing (output=json,
3// mirrored by nx_research_fetch) into item rows and a census, so a seat reads two hundred rows instead of a quarter-megabyte.
4// usage: nx_learnmine items <listing.json> [max] one ITEM row per item (idx, identifier, mediatype, date, downloads, title,
5// subjects) and a DESC row per described item (full length announced, head shown)
6// nx_learnmine subjects <listing.json> [top] the subject frequency table, count descending (a FLOOR when the table filled)
7// nx_learnmine census <listing.json> the summary line only
8// rows are pipe-separated and every field is sanitised (a pipe in the source becomes a slash, a newline a space), so a row is
9// one line and the summary is LAST. exits: 0 digested (GREEN) - 2 usage - 3 refused by name (UNREADABLE, NO-DOCS, MALFORMED,
10// CAPACITY). Nothing here fetches: the bytes come from the provenance-journalled mirror.
11// license_tier: ORIGINAL No hw writes (Rule 26).
12import "nx_syscalls.nx"
13import "nx_learnmine_lib.nx"
14
15const LN_EXIT_OK: i64 = 0
16const LN_EXIT_USAGE: i64 = 2
17const LN_EXIT_REFUSED: i64 = 3
18const LN_MAX_ITEMS: i64 = 4096
19const LN_DEFAULT_TOP: i64 = 40
20const LN_VERB_ITEMS: *u8 = "items"
21const LN_VERB_SUBJECTS: *u8 = "subjects"
22const LN_VERB_CENSUS: *u8 = "census"
23
24func ln_puts(s: *u8) -> i64 { sys_write(1, s, lm_len(s)); return 0 }
25func ln_putn(v: i64) -> i64 { let t: *u8 = sys_mmap(32); let e: i64 = lm_putd(t, 0, v); sys_write(1, t, e); return 0 }
26func ln_kv(k: *u8, v: *u8) -> i64 { ln_puts(" " as *u8); ln_puts(k); ln_puts("=" as *u8); ln_puts(v); return 0 }
27func ln_kvn(k: *u8, v: i64) -> i64 { ln_puts(" " as *u8); ln_puts(k); ln_puts("=" as *u8); ln_putn(v); return 0 }
28func ln_sep() -> i64 { ln_puts("|" as *u8); return 0 }
29func ln_usage() -> i64 {
30 ln_puts("usage: nx_learnmine items <listing.json> [max] | subjects <listing.json> [top] | census <listing.json>\n" as *u8)
31 return LN_EXIT_USAGE
32}
33func ln_summary(lst: *i64) -> i64 {
34 ln_puts("LEARNMINE" as *u8)
35 ln_kvn("items" as *u8, lst[LM_L_ITEMS]); ln_kvn("numfound" as *u8, lst[LM_L_NUMFOUND])
36 ln_kvn("movies" as *u8, lst[LM_L_MOVIES]); ln_kvn("texts" as *u8, lst[LM_L_TEXTS]); ln_kvn("audio" as *u8, lst[LM_L_AUDIO])
37 ln_kvn("image" as *u8, lst[LM_L_IMAGE]); ln_kvn("other" as *u8, lst[LM_L_OTHER])
38 ln_kv("newest" as *u8, lst[LM_L_NEWEST] as *u8); ln_kv("oldest" as *u8, lst[LM_L_OLDEST] as *u8)
39 ln_kvn("downloads" as *u8, lst[LM_L_DOWNLOADS]); ln_kvn("truncated_descs" as *u8, lst[LM_L_TRUNCATED_DESCS])
40 ln_puts(" verdict=GREEN\n" as *u8)
41 return 0
42}
43
44func main(argc: i64, argv: *i64) -> i64 {
45 if argc < 3 { return ln_usage() }
46 let verb: *u8 = argv[1] as *u8
47 let path: *u8 = argv[2] as *u8
48 var mode: i64 = 0
49 if lm_streq(verb, LN_VERB_ITEMS) == 1 { mode = 1 }
50 if lm_streq(verb, LN_VERB_SUBJECTS) == 1 { mode = 2 }
51 if lm_streq(verb, LN_VERB_CENSUS) == 1 { mode = 3 }
52 if mode == 0 { return ln_usage() }
53 let lp: *i64 = sys_mmap(16) as *i64
54 let b: *u8 = sys_read_file(path, lp)
55 if (b as i64) == 0 {
56 ln_puts("LEARNMINE-REFUSED rule=UNREADABLE" as *u8); ln_kv("path" as *u8, path); ln_puts("\n" as *u8)
57 return LN_EXIT_REFUSED
58 }
59 let items: *i64 = sys_mmap(8 * LM_I_SLOTS * LN_MAX_ITEMS) as *i64
60 let lst: *i64 = sys_mmap(8 * LM_L_SLOTS) as *i64
61 let rc: i64 = lm_parse_listing(b, lp[0], items, LN_MAX_ITEMS, lst)
62 if rc != LM_OK {
63 ln_puts("LEARNMINE-REFUSED rule=" as *u8); ln_puts(lm_err_name(rc)); ln_kv("path" as *u8, path); ln_kvn("bytes" as *u8, lp[0]); ln_puts("\n" as *u8)
64 return LN_EXIT_REFUSED
65 }
66 let n: i64 = lst[LM_L_ITEMS]
67 if mode == 1 {
68 var max: i64 = n
69 if argc >= 4 { let m: i64 = lm_atoi(argv[3] as *u8); if m > 0 { if m < max { max = m } } }
70 var i: i64 = 0
71 while i < max {
72 let base: i64 = i * LM_I_SLOTS
73 ln_puts("ITEM" as *u8); ln_sep(); ln_putn(i); ln_sep()
74 ln_puts(items[base + LM_I_ID] as *u8); ln_sep()
75 ln_puts(items[base + LM_I_TYPE] as *u8); ln_sep()
76 ln_puts(items[base + LM_I_DATE] as *u8); ln_sep()
77 ln_putn(items[base + LM_I_DOWNLOADS]); ln_sep()
78 ln_puts(items[base + LM_I_TITLE] as *u8); ln_sep()
79 ln_puts(items[base + LM_I_SUBJECTS] as *u8); ln_puts("\n" as *u8)
80 if items[base + LM_I_DESC_LEN] > 0 {
81 ln_puts("DESC" as *u8); ln_sep(); ln_puts(items[base + LM_I_ID] as *u8); ln_sep()
82 ln_putn(items[base + LM_I_DESC_LEN]); ln_sep(); ln_puts(items[base + LM_I_DESC] as *u8); ln_puts("\n" as *u8)
83 }
84 i = i + 1
85 }
86 ln_puts("ITEMS" as *u8); ln_kvn("shown" as *u8, max); ln_kvn("of" as *u8, n); ln_puts("\n" as *u8)
87 }
88 if mode == 2 {
89 var top: i64 = LN_DEFAULT_TOP
90 if argc >= 4 { let t: i64 = lm_atoi(argv[3] as *u8); if t > 0 { top = t } }
91 let subj: *i64 = sys_mmap(8 * LM_SUBJ_CAP) as *i64
92 let counts: *i64 = sys_mmap(8 * LM_SUBJ_CAP) as *i64
93 let full: *i64 = sys_mmap(16) as *i64
94 let d: i64 = lm_subjects(items, n, subj, counts, LM_SUBJ_CAP, full)
95 var shown: i64 = d
96 if top < shown { shown = top }
97 var j: i64 = 0
98 while j < shown {
99 ln_puts("SUBJECT" as *u8); ln_sep(); ln_putn(j + 1); ln_sep(); ln_putn(counts[j]); ln_sep(); ln_puts(subj[j] as *u8); ln_puts("\n" as *u8)
100 j = j + 1
101 }
102 ln_puts("SUBJECTS" as *u8); ln_kvn("distinct" as *u8, d); ln_kvn("shown" as *u8, shown); ln_kvn("floor" as *u8, full[0]); ln_puts("\n" as *u8)
103 }
104 ln_summary(lst)
105 return LN_EXIT_OK
106}