code wiki / _hdl_build / nx_extract_heal.nx
nx_extract_heal.nx source
↩ module page · 222 lines · 10320 B
1// nx_extract_heal.nx -- SELF-HEALING, ADAPTIVE media-URL recognition. The insight: make pattern recognition
2// DATA-DRIVEN (a pattern TABLE, not hardcoded logic), so the system can LEARN a new pattern from a failure
3// and ADAPT -- instead of a human editing code every time a site changes. Flow: classify via the table; on a
4// MISS for a URL a critic/adversary confirms IS media, LOG it + LEARN (add a pattern derived from the URL, e.g.
5// its CDN host) so the next URL from that source is caught. This is how "auto-heal + adapt" beats yt-dlp's
6// break-then-hand-patch cycle. Seeds with the same knowledge as nx_media_signal's xt_classify (now as DATA).
7import "nx_syscalls.nx"
8import "nx_media_signal.nx" // xt_find + XT_* kind consts
9const XSIG_MAGIC_4096: i64 = 4096
10const XSIG_MAGIC_4095: i64 = 4095
11const XSIG_MAGIC_1048576: i64 = 1048576
12
13const XSIG_EXT: i64 = 1
14const XSIG_PATH: i64 = 2
15const XSIG_HOST: i64 = 3
16const XH_STRIDE: i64 = 5 // per-pattern: [sigtype, pat_ptr, patlen, kind, conf]
17const XH_MAXPAT: i64 = 1024
18
19func xh_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
20func xh_new() -> *i64 { let t: *i64 = sys_mmap(8 * (1 + XH_MAXPAT * XH_STRIDE)) as *i64; t[0] = 0; return t }
21func xh_add(t: *i64, sigtype: i64, pat: *u8, patlen: i64, kind: i64, conf: i64) -> i64 {
22 if t[0] >= XH_MAXPAT { return 1 }
23 let b: i64 = 1 + t[0] * XH_STRIDE
24 t[b] = sigtype; t[b+1] = pat as i64; t[b+2] = patlen; t[b+3] = kind; t[b+4] = conf
25 t[0] = t[0] + 1
26 return 0
27}
28func xh_addc(t: *i64, sigtype: i64, pat: *u8, kind: i64, conf: i64) -> i64 { return xh_add(t, sigtype, pat, xh_slen(pat), kind, conf) }
29// seed the table with the base knowledge (was hardcoded in xt_classify; now DATA so it can be extended live).
30func xh_seed(t: *i64) -> i64 {
31 xh_addc(t, XSIG_EXT, ".m3u8" as *u8, XT_HLS, 95)
32 xh_addc(t, XSIG_EXT, ".mpd" as *u8, XT_DASH, 95)
33 xh_addc(t, XSIG_EXT, ".mp4" as *u8, XT_DIRECT, 90)
34 xh_addc(t, XSIG_EXT, ".webm" as *u8, XT_DIRECT, 90)
35 xh_addc(t, XSIG_EXT, ".m4s" as *u8, XT_SEGMENT, 85)
36 xh_addc(t, XSIG_EXT, ".ts" as *u8, XT_SEGMENT, 82)
37 xh_addc(t, XSIG_PATH, "/videoplayback" as *u8, XT_DIRECT, 70)
38 xh_addc(t, XSIG_PATH, "/master" as *u8, XT_HLS, 65)
39 xh_addc(t, XSIG_PATH, "/playlist" as *u8, XT_HLS, 62)
40 xh_addc(t, XSIG_PATH, "/hls/" as *u8, XT_HLS, 60)
41 xh_addc(t, XSIG_HOST, "googlevideo.com" as *u8, XT_DIRECT, 45)
42 return 0
43}
44// DATA-DRIVEN ranker: pick the BEST candidate from a newline-separated URL list, classifying each via the
45// TABLE (so learned patterns rank too -- the static xt_best would drop a healed URL). Mirrors xt_best.
46func xh_best(t: *i64, list: *u8, listlen: i64, out: *u8, cap: i64, kind: *i64) -> i64 {
47 let line: *u8 = sys_mmap(XSIG_MAGIC_4096)
48 let kb: *i64 = sys_mmap(8) as *i64
49 var best_score: i64 = 0
50 var best_conf: i64 = 0
51 var best_kind: i64 = XT_NONE
52 out[0] = 0 as u8
53 var p: i64 = 0
54 var go: i64 = 1
55 while go == 1 {
56 if p >= listlen { go = 0 }
57 else {
58 if (list[p] & 0xff) == 0 { go = 0 }
59 else {
60 var q: i64 = 0
61 var inl: i64 = 1
62 while inl == 1 {
63 let c: i64 = list[p] & 0xff
64 if c == 0 { inl = 0 } else { if c == 10 { inl = 0; p = p + 1 } else { if q < XSIG_MAGIC_4095 { line[q] = c as u8; q = q + 1 } p = p + 1 } }
65 }
66 line[q] = 0 as u8
67 if q > 0 {
68 let conf: i64 = xh_classify(t, line, q, kb)
69 let sc: i64 = xt_score(kb[0], conf)
70 if sc > best_score { best_score = sc; best_conf = conf; best_kind = kb[0]; var a: i64=0; while a<q { out[a]=line[a]; a=a+1 } out[q]=0 as u8 }
71 }
72 }
73 }
74 }
75 kind[0] = best_kind
76 return best_conf
77}
78// DATA-DRIVEN classify: scan the table, return the best (kind, conf).
79func xh_classify(t: *i64, url: *u8, ul: i64, out_kind: *i64) -> i64 {
80 var best_score: i64 = 0
81 var best_conf: i64 = 0
82 var best_kind: i64 = XT_NONE
83 var i: i64 = 0
84 while i < t[0] {
85 let b: i64 = 1 + i * XH_STRIDE
86 let pat: *u8 = (t[b+1]) as *u8
87 if xt_find(url, ul, pat, t[b+2], 0) >= 0 {
88 let k: i64 = t[b+3]; let c: i64 = t[b+4]
89 let sc: i64 = k * 100 + c
90 if sc > best_score { best_score = sc; best_conf = c; best_kind = k }
91 }
92 i = i + 1
93 }
94 out_kind[0] = best_kind
95 return best_conf
96}
97// extract the host from a URL (between "://" and the next '/' or ':').
98func xh_host(url: *u8, ul: i64, out: *u8, cap: i64) -> i64 {
99 let p: i64 = xt_find(url, ul, "://" as *u8, 3, 0)
100 if p < 0 { out[0] = 0 as u8; return 0 }
101 var s: i64 = p + 3
102 var w: i64 = 0
103 var go: i64 = 1
104 while go == 1 {
105 if s >= ul { go = 0 }
106 else { let c: i64 = url[s] & 0xff; if c == 47 { go = 0 } else { if c == 58 { go = 0 } else { if w < (cap-1) { out[w] = c as u8; w = w + 1 } s = s + 1 } } }
107 }
108 out[w] = 0 as u8
109 return w
110}
111// is a host already a pattern in the table? (dedup so repeated failures don't bloat it)
112func xh_has_host(t: *i64, host: *u8, hl: i64) -> i64 {
113 var i: i64 = 0
114 while i < t[0] {
115 let b: i64 = 1 + i * XH_STRIDE
116 if t[b] == XSIG_HOST { let pat: *u8 = (t[b+1]) as *u8; if t[b+2] == hl { if xt_find(pat, hl, host, hl, 0) == 0 { return 1 } } }
117 i = i + 1
118 }
119 return 0
120}
121// AUTO-HEAL: a URL that IS media (known_kind, per critic/adversary) but the table MISSED -> learn a HOST
122// pattern from it so future URLs from that source are caught. Returns 1 if a new pattern was added, 0 if
123// already known / no host. (Host learned at conf 55 = a candidate; real media still out-ranks via extension.)
124func xh_learn(t: *i64, url: *u8, ul: i64, known_kind: i64) -> i64 {
125 let host: *u8 = sys_mmap(512) // persistent (the pattern points here)
126 let hl: i64 = xh_host(url, ul, host, 512)
127 if hl <= 0 { return 0 }
128 if xh_has_host(t, host, hl) == 1 { return 0 }
129 xh_add(t, XSIG_HOST, host, hl, known_kind, 55)
130 return 1
131}
132// FAILURE LOG: append "url<TAB>reason\n" to logbuf at offset; returns new offset. (Persist via a flush.)
133func xh_log(logbuf: *u8, off: i64, cap: i64, url: *u8, ul: i64, reason: *u8) -> i64 {
134 var o: i64 = off
135 var i: i64 = 0
136 while i < ul { if o < (cap-2) { logbuf[o] = url[i]; o = o + 1 } i = i + 1 }
137 if o < (cap-2) { logbuf[o] = 9 as u8; o = o + 1 } // TAB
138 i = 0
139 while reason[i] != (0 as u8) { if o < (cap-2) { logbuf[o] = reason[i]; o = o + 1 } i = i + 1 }
140 if o < (cap-2) { logbuf[o] = 10 as u8; o = o + 1 } // NL
141 logbuf[o] = 0 as u8
142 return o
143}
144// flush the accumulated log to a file (append via read-existing + rewrite, since sys_openat_wr truncates).
145func xh_flush(path: *u8, logbuf: *u8, loglen: i64) -> i64 {
146 let fd: i64 = sys_openat_wr(path, 0x1a4)
147 if fd < 0 { return 0 - 1 }
148 sys_write(fd, logbuf, loglen)
149 sys_close(fd)
150 return 0
151}
152func xh_putn(dst: *u8, off: i64, v: i64) -> i64 { var m: i64=v; if m==0 { dst[off]=48 as u8; return off+1 } let t: *u8=sys_mmap(24); var k: i64=0; while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } var j: i64=0; while j<k { dst[off]=t[k-1-j]; off=off+1; j=j+1 } return off }
153// parse a base-10 int at *ip, skipping leading spaces; leaves ip[0] pointing at the first non-digit.
154func xh_pint(buf: *u8, ip: *i64) -> i64 {
155 var i: i64 = ip[0]
156 while (buf[i] & 0xff) == 32 { i = i + 1 } // skip leading spaces
157 var v: i64 = 0
158 var go: i64 = 1
159 while go == 1 {
160 let c: i64 = buf[i] & 0xff
161 var dig: i64 = 0
162 if c >= 48 { if c <= 57 { dig = 1 } }
163 if dig == 1 { v = v * 10 + (c - 48); i = i + 1 }
164 if dig == 0 { go = 0 }
165 }
166 ip[0] = i
167 return v
168}
169// PERSIST the pattern table -> `path` as lines "<sigtype> <kind> <conf> <pattern>" (durable healing: learned
170// patterns survive a restart). Persistence via seg_store is the ecosystem-preferred store; a flat file is the
171// portable form used here + by the gate.
172func xh_save(t: *i64, path: *u8) -> i64 {
173 let buf: *u8 = sys_mmap(XSIG_MAGIC_1048576)
174 var o: i64 = 0
175 var i: i64 = 0
176 while i < t[0] {
177 let b: i64 = 1 + i * XH_STRIDE
178 o = xh_putn(buf, o, t[b]); buf[o] = 32 as u8; o = o + 1
179 o = xh_putn(buf, o, t[b+3]); buf[o] = 32 as u8; o = o + 1
180 o = xh_putn(buf, o, t[b+4]); buf[o] = 32 as u8; o = o + 1
181 let pat: *u8 = (t[b+1]) as *u8; let pl: i64 = t[b+2]
182 var k: i64 = 0; while k < pl { buf[o] = pat[k]; o = o + 1; k = k + 1 }
183 buf[o] = 10 as u8; o = o + 1
184 i = i + 1
185 }
186 let fd: i64 = sys_openat_wr(path, 0x1a4)
187 if fd < 0 { return 0 - 1 }
188 sys_write(fd, buf, o); sys_close(fd)
189 return 0
190}
191// LOAD patterns from `path` into `t` (fresh/empty). Copies each pattern to a persistent buffer. Returns count
192// (0 if the file is absent = first run -> caller seeds). This is what makes a learned pattern outlive the run.
193func xh_load(t: *i64, path: *u8) -> i64 {
194 let buf: *u8 = sys_mmap(XSIG_MAGIC_1048576)
195 let fd: i64 = sys_openat_rd(path)
196 if fd < 0 { return 0 }
197 let n: i64 = sys_read(fd, buf, XSIG_MAGIC_1048576); sys_close(fd)
198 let ip: *i64 = sys_mmap(8) as *i64
199 var loaded: i64 = 0
200 ip[0] = 0
201 var go: i64 = 1
202 while go == 1 {
203 if ip[0] >= n { go = 0 }
204 else {
205 if (buf[ip[0]] & 0xff) == 10 { ip[0] = ip[0] + 1 }
206 else {
207 let sigtype: i64 = xh_pint(buf, ip)
208 let kind: i64 = xh_pint(buf, ip)
209 let conf: i64 = xh_pint(buf, ip)
210 var s: i64 = ip[0]
211 while (buf[s] & 0xff) == 32 { s = s + 1 } // skip the space before the pattern
212 var e: i64 = s
213 var fe: i64 = 0
214 while fe == 0 { if e >= n { fe = 1 } else { if (buf[e]&0xff) == 10 { fe = 1 } else { e = e + 1 } } }
215 let pl: i64 = e - s
216 if pl > 0 { let pat: *u8 = sys_mmap(pl + 1); var k: i64=0; while k<pl { pat[k]=buf[s+k]; k=k+1 } pat[pl]=0 as u8; xh_add(t, sigtype, pat, pl, kind, conf); loaded = loaded + 1 }
217 ip[0] = e + 1
218 }
219 }
220 }
221 return loaded
222}