code wiki / _hdl_build / nx_gallery_serve.nx
nx_gallery_serve.nx source
↩ module page · 2044 lines · 153759 B
1// nx_gallery_serve.nx -- SOVEREIGN Nishi image-library gallery daemon (port 18090). Pinterest-style masonry
2// of the FULL-RESOLUTION images (no thumbnails) with infinite scroll, sort, search, and STATE FILTERS:
3// viewed (clicked), rated, and favorite. Favorite = the LoRA-training flag (knowledge/status/galx_fav.log
4// is the training candidate set a downstream LoRA/i2i pipeline consumes). Clicking opens the lossless image
5// with the generation-factor panel and a rating control; opening marks it viewed.
6//
7// GET / -> gallery shell (masonry + infinite scroll + filters + lightbox)
8// GET /api/list?o=&n=&s=&q=&filter= -> {"total":N,"items":[cid...]} (filter=all|fav|rated|viewed)
9// GET /img/<cid> -> full-resolution lossless source PNG
10// GET /meta/<cid> -> {factor:value,...} from the PNG tEXt/iTXt
11// GET /state/<cid> -> {"fav":0|1,"rating":N,"viewed":0|1}
12// POST /view img= -> mark viewed (append galx_views.log)
13// POST /fav img=&v= -> set favorite 0/1 (append galx_fav.log) [LoRA-training flag]
14// POST /rate img=&score= -> append one EVAL O-line
15// All logic is NishiLang; bash is only ever a launcher. license_tier: ORIGINAL
16import "nx_syscalls.nx"
17import "nx_ts_marks.nx" // T1 clip-analysis: ts_classify (markers+dur -> content label) for /vid/<id>/analysis
18import "nx_search_inverted_persist.nx" // durable inverted index (nx_inv_load/query + tokenizer + FNV hash)
19import "nx_bm25.nx" // Okapi BM25 primitives (bm_idf_micro / bm_sat_milli, integer x1e6)
20import "nx_galx_cid_index.nx" // sovereign O(1) cid->path store (replaces the per-request galx_cid_paths.tsv scan)
21import "nx_galx_shell_jslint.nx" // sovereign JS-syntax guard for the inline shell <script> (no JS engine here)
22import "nx_prefix.nx" // R-UX-3 as-you-type autocomplete (sorted-vocab binary-search lower bound)
23import "nx_galx_sortindex.nx" // R2 sort engine: gated stable merge-sort (si_msort) for sort-by-key
24import "nx_galx_durbin_lib.nx" // R2 perf: O(1) galx_dur.bin dur lookup (db_lookup) -> no 16MB /dur PCR re-scan
25import "nx_galx_tags.nx" // R4 media-manager: append-only tag store (tg_*, gated nx_galx_tags_gate)
26const VIEW_MAGIC_2048: i64 = 2048
27const VIEW_MAGIC_2000: i64 = 2000
28const VIEW_MAGIC_1024: i64 = 1024
29const VIEW_MAGIC_1048576: i64 = 1048576
30const VIEW_MAGIC_8388608: i64 = 8388608
31const VIEW_MAGIC_7776000000: i64 = 7776000000
32const VIEW_MAGIC_1000000: i64 = 1000000
33const VIEW_MAGIC_8191: i64 = 8191
34const VIEW_MAGIC_50000000: i64 = 50000000
35const VIEW_MAGIC_262144: i64 = 262144
36const VIEW_MAGIC_262208: i64 = 262208
37const VIEW_MAGIC_4096: i64 = 4096
38const VIEW_MAGIC_1500000: i64 = 1500000
39const VIEW_MAGIC_65536: i64 = 65536
40const VIEW_MAGIC_258000: i64 = 258000
41const VIEW_MAGIC_200000: i64 = 200000
42const VIEW_MAGIC_250000: i64 = 250000
43const VIEW_MAGIC_1100: i64 = 1100
44const VIEW_MAGIC_8192: i64 = 8192
45const VIEW_MAGIC_16384: i64 = 16384
46const VIEW_MAGIC_60000: i64 = 60000
47const VIEW_MAGIC_131072: i64 = 131072
48const VIEW_MAGIC_100000: i64 = 100000
49const VIEW_MAGIC_200008: i64 = 200008
50const VIEW_MAGIC_18090: i64 = 18090
51const VIEW_MAGIC_4194304: i64 = 4194304
52
53const VIEW_IDX: *u8 = "knowledge/status/galx_view_index.txt" as *u8
54const SEARCH_IDX: *u8 = "knowledge/status/galx_search.tsv" as *u8
55const FAV_LOG: *u8 = "knowledge/status/galx_fav.log" as *u8
56const VIEW_LOG: *u8 = "knowledge/status/galx_views.log" as *u8
57const EVAL_LOG: *u8 = "knowledge/status/eval_lanes.log" as *u8
58const HIDDEN_LOG: *u8 = "knowledge/status/galx_hidden.log" as *u8 // R3 soft-hide: append "<id> <0|1>" (reversible)
59const TAGS_LOG: *u8 = "knowledge/status/galx_tags.log" as *u8 // R4 tags: append "<id>\t<tag>\t<0|1>" (last-wins, additive)
60
61func eh_find(buf: *u8, n: i64, pat: *u8, plen: i64) -> i64 {
62 var i: i64 = 0
63 while i + plen <= n {
64 var j: i64 = 0
65 var ok: i64 = 1
66 while j < plen { if buf[i+j] != pat[j] { ok = 0 } j = j + 1 }
67 if ok == 1 { return 1 }
68 i = i + 1
69 }
70 return 0
71}
72func gs_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){dst[off+i]=s[i];i=i+1} return off+i }
73func gs_u(dst: *u8, off: i64, v: i64) -> i64 {
74 var m: i64 = v
75 let t: *u8 = sys_mmap(28)
76 var k: i64 = 0
77 if m == 0 { t[0] = 48 as u8; k = 1 }
78 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
79 var o: i64 = off
80 var i: i64 = 0
81 while i < k { dst[o] = t[k-1-i]; o = o + 1; i = i + 1 }
82 return o
83}
84func gs_strlen(s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){i=i+1} return i }
85func gs_lower(c: i64) -> i64 { if c >= 65 { if c <= 90 { return c + 32 } } return c }
86func gs_qint(req: *u8, rn: i64, key: *u8, deflt: i64) -> i64 {
87 let kl: i64 = gs_strlen(key)
88 var i: i64 = 0
89 var at: i64 = 0 - 1
90 var stop: i64 = rn
91 while i < stop {
92 if req[i] == (10 as u8) { stop = i } else {
93 if at < 0 { if i + kl <= rn { var j: i64=0; var ok: i64=1; while j<kl { if req[i+j]!=key[j]{ok=0} j=j+1 } if ok==1 { at=i+kl } } }
94 i = i + 1
95 }
96 }
97 if at < 0 { return deflt }
98 var v: i64 = 0; var any: i64 = 0; var q: i64 = at
99 while q < rn { if req[q] >= (48 as u8) { if req[q] <= (57 as u8) { v=v*10+((req[q] as i64)-48); any=1; q=q+1 } else { q=rn } } else { q=rn } }
100 if any == 0 { return deflt }
101 return v
102}
103func gs_404(rbuf: *u8) -> i64 { return gs_cat(rbuf, 0, "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 9\r\nConnection: close\r\n\r\nnot found" as *u8) }
104func gs_okjson(rbuf: *u8, body: *u8, blen: i64) -> i64 {
105 var o: i64 = 0
106 o = gs_cat(rbuf, o, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nConnection: close\r\nCache-Control: no-store\r\nContent-Length: " as *u8)
107 o = gs_u(rbuf, o, blen)
108 o = gs_cat(rbuf, o, "\r\n\r\n" as *u8)
109 var i: i64 = 0
110 while i < blen { rbuf[o] = body[i]; o = o + 1; i = i + 1 }
111 return o
112}
113
114func gs_peel_cid(req: *u8, rn: i64, cidout: *u8) -> i64 {
115 let pat: *u8 = "GET /img/" as *u8
116 var i: i64 = 0; var at: i64 = 0 - 1
117 while i + 9 <= rn { var j: i64=0; var ok: i64=1; while j<9 { if req[i+j]!=pat[j]{ok=0} j=j+1 } if ok==1 { if at<0 { at=i+9 } } i=i+1 }
118 if at < 0 { return 0 }
119 var c: i64 = 0
120 while c < 69 { cidout[c] = req[at + c]; c = c + 1 }
121 cidout[69] = 0 as u8
122 return 1
123}
124func gs_peel_pat(req: *u8, rn: i64, pat: *u8, plen: i64, cidout: *u8) -> i64 {
125 var i: i64 = 0; var at: i64 = 0 - 1
126 while i + plen <= rn { var j: i64=0; var ok: i64=1; while j<plen { if req[i+j]!=pat[j]{ok=0} j=j+1 } if ok==1 { if at<0 { at=i+plen } } i=i+1 }
127 if at < 0 { return 0 }
128 var c: i64 = 0
129 while c < 69 { cidout[c] = req[at + c]; c = c + 1 }
130 cidout[69] = 0 as u8
131 return 1
132}
133// extract the img= CID value from a POST body (69 chars). returns 1 ok.
134func gs_body_cid(req: *u8, rn: i64, cidout: *u8) -> i64 {
135 var bodyat: i64 = 0 - 1
136 var i: i64 = 0
137 while i + 4 <= rn { if req[i]==(13 as u8) { if req[i+1]==(10 as u8) { if req[i+2]==(13 as u8) { if req[i+3]==(10 as u8) { if bodyat<0 { bodyat=i+4 } } } } } i=i+1 }
138 if bodyat < 0 { return 0 }
139 var iat: i64 = 0 - 1
140 var pi: i64 = bodyat
141 while pi + 4 <= rn { if req[pi]==(105 as u8) { if req[pi+1]==(109 as u8) { if req[pi+2]==(103 as u8) { if req[pi+3]==(61 as u8) { if iat<0 { iat=pi+4 } } } } } pi=pi+1 }
142 if iat < 0 { return 0 }
143 var c: i64 = 0
144 while c < 69 { if iat + c >= rn { return 0 } cidout[c] = req[iat + c]; c = c + 1 }
145 cidout[69] = 0 as u8
146 return 1
147}
148// cid->path resolution context: the sovereign O(1) hash index (idx+blob), loaded once at startup, COW-shared to children.
149struct NxCidx {
150 idx: *u8
151 blob: *u8
152 nb: i64
153 ready: i64
154}
155
156func gs_sidecar(cidx: *NxCidx, cid: *u8, pathout: *u8) -> i64 {
157 // FAST PATH: the sovereign O(1) index. Falls through to the legacy TSV scan only if it is absent or the cid is
158 // not indexed yet (a stale index after new images are added) -- zero-regression.
159 if (cidx as i64) != 0 { if cidx.ready == 1 {
160 if gs_cidindex_lookup(cidx.idx, cidx.blob, cidx.nb, cid, pathout) == 1 { return 1 }
161 } }
162 let szp: *i64 = sys_mmap(16) as *i64
163 let b: *u8 = sys_read_file("knowledge/status/galx_cid_paths.tsv" as *u8, szp)
164 let sz: i64 = szp[0]
165 if (b as i64) == 0 { return 0 }
166 var i: i64 = 0; var ls: i64 = 0
167 while i < sz {
168 if b[i] == (10 as u8) {
169 var eq: i64 = 1; var k: i64 = 0
170 while k < 69 { if b[ls + k] != cid[k] { eq = 0 } k = k + 1 }
171 if b[ls + 69] != (9 as u8) { eq = 0 }
172 if eq == 1 { var po: i64=0; var p: i64=ls+70; while p<i { pathout[po]=b[p]; po=po+1; p=p+1 } pathout[po]=0 as u8; return 1 }
173 ls = i + 1
174 }
175 i = i + 1
176 }
177 return 0
178}
179func gs_serve_png(rbuf: *u8, req: *u8, rn: i64, cidx: *NxCidx) -> i64 {
180 let cid: *u8 = sys_mmap(96)
181 if gs_peel_cid(req, rn, cid) == 0 { return gs_404(rbuf) }
182 let path: *u8 = sys_mmap(VIEW_MAGIC_2048)
183 if gs_sidecar(cidx, cid, path) == 0 { return gs_404(rbuf) }
184 let szp: *i64 = sys_mmap(16) as *i64
185 let png: *u8 = sys_read_file(path, szp)
186 let plen: i64 = szp[0]
187 if (png as i64) == 0 { return gs_404(rbuf) }
188 var o: i64 = 0
189 o = gs_cat(rbuf, o, "HTTP/1.1 200 OK\r\nContent-Type: image/png\r\nCache-Control: max-age=86400\r\nContent-Length: " as *u8)
190 o = gs_u(rbuf, o, plen)
191 o = gs_cat(rbuf, o, "\r\nConnection: close\r\n\r\n" as *u8)
192 var i: i64 = 0
193 while i < plen { rbuf[o] = png[i]; o = o + 1; i = i + 1 }
194 return o
195}
196
197// ---- image THUMBNAILS (S-class: NEVER serve full-res into a 160px grid cell) ----
198// GET /thumb/<cid> -> a small cached PNG thumbnail. Cold cache -> generate via nx_galx_thumb
199// (sovereign decode->bilinear downscale->encode), atomic .new+rename so a concurrent reader never sees a
200// partial file. If the generator is absent or fails, FALL BACK to the full-res image so the grid is never
201// broken (zero-regression: without the generator deployed, /thumb behaves exactly like /img). The lightbox
202// still requests /img/<cid> (full-res). Cache dir = thumbs/ under the gallery CWD (/volume1/ai/galx).
203const GS_THUMB_ELF: *u8 = "/volume1/ai/galx/nx_galx_thumb.elf"
204const GS_THUMB_MAX: *u8 = "384"
205
206// generic cid peel after an arbitrary request prefix (gs_peel_cid is /img/-only). 1 ok / 0 not found.
207func gs_peel_cid_pat(req: *u8, rn: i64, pat: *u8, plen: i64, cidout: *u8) -> i64 {
208 var i: i64 = 0; var at: i64 = 0 - 1
209 while i + plen <= rn { var j: i64 = 0; var ok: i64 = 1; while j < plen { if req[i+j] != pat[j] { ok = 0 } j = j + 1 } if ok == 1 { if at < 0 { at = i + plen } } i = i + 1 }
210 if at < 0 { return 0 }
211 if at + 69 > rn { return 0 }
212 var c: i64 = 0
213 while c < 69 { cidout[c] = req[at + c]; c = c + 1 }
214 cidout[69] = 0 as u8
215 return 1
216}
217func gs_file_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
218// read a file and serve it as image/png (7-day cache). returns response length, or gs_404 if missing.
219func gs_send_imgfile(rbuf: *u8, path: *u8, ctype: *u8) -> i64 {
220 let szp: *i64 = sys_mmap(16) as *i64
221 let png: *u8 = sys_read_file(path, szp)
222 let plen: i64 = szp[0]
223 if (png as i64) == 0 { return gs_404(rbuf) }
224 var o: i64 = gs_cat(rbuf, 0, "HTTP/1.1 200 OK\r\nContent-Type: " as *u8)
225 o = gs_cat(rbuf, o, ctype)
226 o = gs_cat(rbuf, o, "\r\nCache-Control: max-age=604800\r\nContent-Length: " as *u8)
227 o = gs_u(rbuf, o, plen)
228 o = gs_cat(rbuf, o, "\r\nConnection: close\r\n\r\n" as *u8)
229 var i: i64 = 0
230 while i < plen { rbuf[o] = png[i]; o = o + 1; i = i + 1 }
231 return o
232}
233// fork+exec nx_galx_thumb <src> <outnew> 384 ; returns child exit code (0=ok, 127=exec unavailable).
234func gs_thumb_run(src: *u8, outnew: *u8) -> i64 {
235 let argv: *i64 = sys_mmap(48) as *i64
236 argv[0] = GS_THUMB_ELF as i64; argv[1] = src as i64; argv[2] = outnew as i64; argv[3] = GS_THUMB_MAX as i64; argv[4] = 0
237 let envp: *i64 = sys_mmap(8) as *i64; envp[0] = 0
238 let pid: i64 = sys_fork()
239 if pid == 0 { sys_execve_clean(GS_THUMB_ELF, argv, envp); sys_exit(127) }
240 let st: *i64 = sys_mmap(16) as *i64
241 sys_wait4(pid, st, 0)
242 return (st[0] >> 8) & 0xff
243}
244func gs_thumb(rbuf: *u8, req: *u8, rn: i64, cidx: *NxCidx) -> i64 {
245 let cid: *u8 = sys_mmap(96)
246 if gs_peel_cid_pat(req, rn, "GET /thumb/" as *u8, 11, cid) == 0 { return gs_404(rbuf) }
247 // CACHE-FIRST: a cached thumb serves O(1) WITHOUT resolving cid->path at all -- the whole point on a 60-thumb grid.
248 let cache: *u8 = sys_mmap(VIEW_MAGIC_2048)
249 var co: i64 = gs_cat(cache, 0, "thumbs/" as *u8)
250 var k: i64 = 0; while k < 69 { cache[co] = cid[k]; co = co + 1; k = k + 1 }
251 co = gs_cat(cache, co, ".jpg" as *u8); cache[co] = 0 as u8
252 if gs_file_exists(cache) == 1 { return gs_send_imgfile(rbuf, cache, "image/jpeg" as *u8) }
253 // cold: NOW resolve the source (O(1) sovereign index), generate to .new, atomic rename, serve
254 let src: *u8 = sys_mmap(VIEW_MAGIC_2048)
255 if gs_sidecar(cidx, cid, src) == 0 { return gs_404(rbuf) }
256 __syscall(83, "thumbs" as *u8 as i64, 493, 0, 0, 0, 0) // mkdir thumbs (idempotent; EEXIST ignored)
257 let cnew: *u8 = sys_mmap(VIEW_MAGIC_2048)
258 var no: i64 = gs_cat(cnew, 0, cache); no = gs_cat(cnew, no, ".new" as *u8); cnew[no] = 0 as u8
259 if gs_thumb_run(src, cnew) == 0 { __syscall(82, cnew as i64, cache as i64, 0, 0, 0, 0) } // rename .new -> cache (atomic)
260 if gs_file_exists(cache) == 1 { return gs_send_imgfile(rbuf, cache, "image/jpeg" as *u8) }
261 // FALLBACK: generator absent/failed -> serve full-res so the grid is never broken
262 return gs_send_imgfile(rbuf, src, "image/png" as *u8)
263}
264
265const GS_UPSCALE_ELF: *u8 = "/volume1/ai/galx/nx_galx_upscale.elf"
266const GS_UPSCALE_MODE: *u8 = "one"
267const GS_UPSCALE_FACTOR: *u8 = "2"
268// fork nx_galx_upscale (sovereign decode->bilinear UPscale->encode); rc 0 = ok. Mirrors gs_thumb_run.
269func gs_upscale_run(src: *u8, outnew: *u8) -> i64 {
270 let argv: *i64 = sys_mmap(56) as *i64
271 argv[0] = GS_UPSCALE_ELF as i64; argv[1] = GS_UPSCALE_MODE as i64; argv[2] = src as i64; argv[3] = outnew as i64; argv[4] = GS_UPSCALE_FACTOR as i64; argv[5] = 0
272 let envp: *i64 = sys_mmap(8) as *i64; envp[0] = 0
273 let pid: i64 = sys_fork()
274 if pid == 0 { sys_execve_clean(GS_UPSCALE_ELF, argv, envp); sys_exit(127) }
275 let st: *i64 = sys_mmap(16) as *i64
276 sys_wait4(pid, st, 0)
277 return (st[0] >> 8) & 0xff
278}
279// GET /upscale/<cid> -> a cached 2x bilinear-upscaled PNG. Cold -> resolve source -> fork nx_galx_upscale
280// -> atomic .new+rename -> serve. Generator absent/failed -> FALL BACK to the full-res original
281// (zero-regression: without nx_galx_upscale.elf deployed, /upscale behaves exactly like /img).
282func gs_upscale(rbuf: *u8, req: *u8, rn: i64, cidx: *NxCidx) -> i64 {
283 let cid: *u8 = sys_mmap(96)
284 if gs_peel_cid_pat(req, rn, "GET /upscale/" as *u8, 13, cid) == 0 { return gs_404(rbuf) }
285 let cache: *u8 = sys_mmap(VIEW_MAGIC_2048)
286 var co: i64 = gs_cat(cache, 0, "upscale/" as *u8)
287 var k: i64 = 0; while k < 69 { cache[co] = cid[k]; co = co + 1; k = k + 1 }
288 co = gs_cat(cache, co, "_2x.png" as *u8); cache[co] = 0 as u8
289 if gs_file_exists(cache) == 1 { return gs_send_imgfile(rbuf, cache, "image/png" as *u8) }
290 let src: *u8 = sys_mmap(VIEW_MAGIC_2048)
291 if gs_sidecar(cidx, cid, src) == 0 { return gs_404(rbuf) }
292 __syscall(83, "upscale" as *u8 as i64, 493, 0, 0, 0, 0)
293 let cnew: *u8 = sys_mmap(VIEW_MAGIC_2048)
294 var no: i64 = gs_cat(cnew, 0, cache); no = gs_cat(cnew, no, ".new" as *u8); cnew[no] = 0 as u8
295 if gs_upscale_run(src, cnew) == 0 { __syscall(82, cnew as i64, cache as i64, 0, 0, 0, 0) }
296 if gs_file_exists(cache) == 1 { return gs_send_imgfile(rbuf, cache, "image/png" as *u8) }
297 return gs_send_imgfile(rbuf, src, "image/png" as *u8)
298}
299// ---- recordings (cam .ts archive; poster.jpg sibling = ready-made thumbnail) ----
300func gs_wb64(b: *u8, o: i64, v: i64) -> i64 { b[o]=((v>>56)&0xff) as u8; b[o+1]=((v>>48)&0xff) as u8; b[o+2]=((v>>40)&0xff) as u8; b[o+3]=((v>>32)&0xff) as u8; b[o+4]=((v>>24)&0xff) as u8; b[o+5]=((v>>16)&0xff) as u8; b[o+6]=((v>>8)&0xff) as u8; b[o+7]=(v&0xff) as u8; return o+8 }
301func gs_rb64(b: *u8, o: i64) -> i64 { return ((b[o] as i64)<<56)|((b[o+1] as i64)<<48)|((b[o+2] as i64)<<40)|((b[o+3] as i64)<<32)|((b[o+4] as i64)<<24)|((b[o+5] as i64)<<16)|((b[o+6] as i64)<<8)|(b[o+7] as i64) }
302// Build galx_vid_off.bin (id -> TSV byte offset) so gs_vid_line is O(1) instead of a 4.35MB scan/request.
303// Header (big-endian): tsv_size(8) n(8) then n*off(8). tsv_size = freshness check. Called once at startup;
304// nx_galx_vidoff is the standalone refresher (no restart needed). Idempotent.
305func gs_vidoff_build() -> i64 {
306 let szp: *i64 = sys_mmap(16) as *i64
307 let b: *u8 = sys_read_file("knowledge/status/galx_vid_paths.tsv" as *u8, szp)
308 if (b as i64)==0 { return 0 }
309 let sz: i64 = szp[0]
310 var n: i64 = 1; var i: i64 = 0
311 while i < sz { if b[i]==(10 as u8) { if i+1 < sz { n=n+1 } } i=i+1 }
312 let ob: *u8 = sys_mmap(16 + n*8 + 64)
313 gs_wb64(ob, 0, sz); gs_wb64(ob, 8, n); gs_wb64(ob, 16, 0)
314 var cnt: i64 = 1; i = 0
315 while i < sz { if b[i]==(10 as u8) { if i+1 < sz { if cnt < n { gs_wb64(ob, 16+cnt*8, i+1); cnt=cnt+1 } } } i=i+1 }
316 let wf: i64 = sys_openat_wr("knowledge/status/galx_vid_off.bin" as *u8, 0x1a4)
317 if wf < 0 { return 0 }
318 sys_write(wf, ob, 16+n*8); sys_close(wf)
319 return 1
320}
321// copy the path on line `id` of the video index into out; returns 1 if found.
322// fast path: O(1) via galx_vid_off.bin (freshness-guarded by tsv_size); falls back to a full scan.
323func gs_vid_line(id: i64, out: *u8) -> i64 {
324 let ofd: i64 = sys_openat_rd("knowledge/status/galx_vid_off.bin" as *u8)
325 if ofd >= 0 {
326 let hdr: *u8 = sys_mmap(32); let hr: i64 = sys_read(ofd, hdr, 16)
327 if hr == 16 {
328 let stored: i64 = gs_rb64(hdr, 0); let n: i64 = gs_rb64(hdr, 8)
329 let tfd: i64 = sys_openat_rd("knowledge/status/galx_vid_paths.tsv" as *u8)
330 if tfd >= 0 {
331 let cur: i64 = sys_lseek(tfd, 0, 2)
332 if cur == stored { if id >= 0 { if id < n {
333 sys_lseek(ofd, 16 + id*8, 0)
334 let obf: *u8 = sys_mmap(16); let orr: i64 = sys_read(ofd, obf, 8)
335 if orr == 8 {
336 let off: i64 = gs_rb64(obf, 0)
337 sys_lseek(tfd, off, 0)
338 let lb: *u8 = sys_mmap(VIEW_MAGIC_2048); let lr: i64 = sys_read(tfd, lb, VIEW_MAGIC_2000)
339 if lr > 0 {
340 var o: i64=0; var p: i64=0
341 while p < lr { if lb[p]==(10 as u8) { p=lr } else { out[o]=lb[p]; o=o+1; p=p+1 } }
342 out[o]=0 as u8; sys_close(ofd); sys_close(tfd)
343 if o > 0 { return 1 } else { return 0 }
344 }
345 }
346 } } }
347 sys_close(tfd)
348 }
349 }
350 sys_close(ofd)
351 }
352 // fallback: full scan (offset index missing or stale)
353 let szp: *i64 = sys_mmap(16) as *i64
354 let b: *u8 = sys_read_file("knowledge/status/galx_vid_paths.tsv" as *u8, szp)
355 let sz: i64 = szp[0]
356 if (b as i64) == 0 { return 0 }
357 var i: i64 = 0; var ls: i64 = 0; var ln: i64 = 0
358 while i <= sz {
359 var nl: i64 = 0
360 if i == sz { nl = 1 } else { if b[i]==(10 as u8) { nl = 1 } }
361 if nl == 1 {
362 if ln == id { if i > ls { var o: i64=0; var p: i64=ls; while p<i { out[o]=b[p]; o=o+1; p=p+1 } out[o]=0 as u8; return 1 } return 0 }
363 ln = ln + 1; ls = i + 1
364 }
365 i = i + 1
366 }
367 return 0
368}
369// parse a numeric id that follows `pat` in the request line.
370func gs_peel_num(req: *u8, rn: i64, pat: *u8, plen: i64) -> i64 {
371 var i: i64 = 0; var at: i64 = 0 - 1
372 while i + plen <= rn { var j: i64=0; var ok: i64=1; while j<plen { if req[i+j]!=pat[j]{ok=0} j=j+1 } if ok==1 { if at<0 { at=i+plen } } i=i+1 }
373 if at < 0 { return 0 - 1 }
374 var v: i64 = 0; var any: i64 = 0; var q: i64 = at
375 while q < rn { if req[q]>=(48 as u8) { if req[q]<=(57 as u8) { v=v*10+((req[q] as i64)-48); any=1; q=q+1 } else { q=rn } } else { q=rn } }
376 if any == 0 { return 0 - 1 }
377 return v
378}
379// derive the poster path: replace the final ".ext" with "-poster.jpg".
380func gs_poster_path(vid: *u8, out: *u8) -> i64 {
381 let nn: i64 = gs_strlen(vid)
382 var dot: i64 = nn
383 var i: i64 = nn - 1
384 while i >= 0 { if vid[i]==(46 as u8) { if dot==nn { dot = i } } i = i - 1 }
385 var o: i64 = 0; var k: i64 = 0
386 while k < dot { out[o]=vid[k]; o=o+1; k=k+1 }
387 let suf: *u8 = "-poster.jpg" as *u8
388 var s: i64 = 0
389 while suf[s]!=(0 as u8){ out[o]=suf[s]; o=o+1; s=s+1 }
390 out[o]=0 as u8
391 return 0
392}
393// GET /vidthumb/<id> -> the recording's poster jpg (the thumbnail). Small file -> via rbuf.
394func gs_vidthumb(rbuf: *u8, req: *u8, rn: i64) -> i64 {
395 let id: i64 = gs_peel_num(req, rn, "GET /vidthumb/" as *u8, 14)
396 if id < 0 { return gs_404(rbuf) }
397 let vid: *u8 = sys_mmap(VIEW_MAGIC_2048)
398 if gs_vid_line(id, vid) == 0 { return gs_404(rbuf) }
399 let poster: *u8 = sys_mmap(VIEW_MAGIC_2048)
400 gs_poster_path(vid, poster)
401 let szp: *i64 = sys_mmap(16) as *i64
402 let jpg: *u8 = sys_read_file(poster, szp)
403 let jl: i64 = szp[0]
404 if (jpg as i64) == 0 { return gs_404(rbuf) }
405 var o: i64 = 0
406 o = gs_cat(rbuf, o, "HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\nCache-Control: max-age=86400\r\nContent-Length: " as *u8)
407 o = gs_u(rbuf, o, jl)
408 o = gs_cat(rbuf, o, "\r\nConnection: close\r\n\r\n" as *u8)
409 var i: i64 = 0
410 while i < jl { rbuf[o]=jpg[i]; o=o+1; i=i+1 }
411 return o
412}
413// ---- /vid playback: native containers (mp4/mov/webm/...) stream directly with HTTP Range (seekable + audio);
414// MPEG-TS is demuxed to fMP4 on the fly. All written DIRECTLY to cfd (files can be GBs). Returns 1 (sent). ----
415func gs_streq(a: *u8, b: *u8) -> i64 { var i: i64=0; while a[i]!=(0 as u8) { if a[i]!=b[i] { return 0 } i=i+1 } if b[i]!=(0 as u8) { return 0 } return 1 }
416// lowercased file extension (after the last '.' of the basename) -> ex (NUL-terminated, <=14 chars)
417func gs_vid_ext(vid: *u8, ex: *u8) -> i64 {
418 let nn: i64 = gs_strlen(vid)
419 var dot: i64 = 0 - 1; var go: i64 = 1; var i: i64 = nn - 1
420 while i >= 0 { if go==1 { if vid[i]==(47 as u8) { go=0 } else { if vid[i]==(46 as u8) { if dot<0 { dot=i } } } } i=i-1 }
421 var k: i64 = 0
422 if dot >= 0 { var p: i64 = dot+1; while p < nn { if k<14 { var c: i64=vid[p] as i64; if c>=65 { if c<=90 { c=c+32 } } ex[k]=c as u8; k=k+1 } p=p+1 } }
423 ex[k]=0 as u8
424 return k
425}
426func gs_vid_mime(ex: *u8) -> *u8 {
427 if gs_streq(ex, "webm" as *u8)==1 { return "video/webm" as *u8 }
428 if gs_streq(ex, "mkv" as *u8)==1 { return "video/x-matroska" as *u8 }
429 if gs_streq(ex, "flv" as *u8)==1 { return "video/x-flv" as *u8 }
430 return "video/mp4" as *u8
431}
432// serve a regular file with HTTP Range support (206/Content-Range/Accept-Ranges) so the browser can seek.
433func gs_serve_file_range(cfd: i64, req: *u8, rn: i64, path: *u8, ctype: *u8) -> i64 {
434 let nf: *u8 = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8
435 let fd: i64 = sys_openat_rd(path)
436 if fd < 0 { sys_write(cfd, nf, gs_strlen(nf)); return 1 }
437 let size: i64 = sys_lseek(fd, 0, 2)
438 var hasrange: i64 = 0; var rstart: i64 = 0; var rend: i64 = size - 1
439 let pat: *u8 = "Range: bytes=" as *u8; let pl: i64 = 13
440 var i: i64 = 0; var at: i64 = 0 - 1
441 while i + pl <= rn { if at<0 { var j: i64=0; var ok: i64=1; while j<pl { if req[i+j]!=pat[j]{ok=0} j=j+1 } if ok==1 { at=i+pl } } i=i+1 }
442 if at >= 0 {
443 hasrange = 1
444 var p: i64 = at
445 var sv: i64 = 0; var sany: i64 = 0; var stop: i64 = 0
446 while stop==0 { if p>=rn { stop=1 } else { let c: i64=req[p] as i64; if c>=48 { if c<=57 { sv=sv*10+(c-48); sany=1; p=p+1 } else { stop=1 } } else { stop=1 } } }
447 if sany==1 { rstart = sv }
448 if p < rn { if req[p]==(45 as u8) { p=p+1 } }
449 var ev: i64 = 0; var eany: i64 = 0; stop=0
450 while stop==0 { if p>=rn { stop=1 } else { let c: i64=req[p] as i64; if c>=48 { if c<=57 { ev=ev*10+(c-48); eany=1; p=p+1 } else { stop=1 } } else { stop=1 } } }
451 if eany==1 { rend = ev }
452 }
453 if rstart < 0 { rstart = 0 }
454 if rstart >= size { rstart = 0; rend = size - 1; hasrange = 0 }
455 if rend >= size { rend = size - 1 }
456 if rend < rstart { rend = size - 1 }
457 let clen: i64 = rend - rstart + 1
458 let hb: *u8 = sys_mmap(VIEW_MAGIC_1024); var ho: i64 = 0
459 if hasrange == 1 {
460 ho = gs_cat(hb, ho, "HTTP/1.1 206 Partial Content\r\nContent-Type: " as *u8)
461 ho = gs_cat(hb, ho, ctype)
462 ho = gs_cat(hb, ho, "\r\nAccept-Ranges: bytes\r\nContent-Range: bytes " as *u8)
463 ho = gs_u(hb, ho, rstart); hb[ho]=45 as u8; ho=ho+1; ho = gs_u(hb, ho, rend); hb[ho]=47 as u8; ho=ho+1; ho = gs_u(hb, ho, size)
464 ho = gs_cat(hb, ho, "\r\nContent-Length: " as *u8); ho = gs_u(hb, ho, clen)
465 ho = gs_cat(hb, ho, "\r\nCache-Control: max-age=3600\r\nConnection: close\r\n\r\n" as *u8)
466 } else {
467 ho = gs_cat(hb, ho, "HTTP/1.1 200 OK\r\nContent-Type: " as *u8)
468 ho = gs_cat(hb, ho, ctype)
469 ho = gs_cat(hb, ho, "\r\nAccept-Ranges: bytes\r\nContent-Length: " as *u8); ho = gs_u(hb, ho, size)
470 ho = gs_cat(hb, ho, "\r\nCache-Control: max-age=3600\r\nConnection: close\r\n\r\n" as *u8)
471 }
472 sys_write(cfd, hb, ho)
473 sys_lseek(fd, rstart, 0)
474 let buf: *u8 = sys_mmap(VIEW_MAGIC_1048576)
475 var remain: i64 = clen
476 while remain > 0 {
477 var want: i64 = VIEW_MAGIC_1048576
478 if remain < want { want = remain }
479 let got: i64 = sys_read(fd, buf, want)
480 if got <= 0 { remain = 0 } else {
481 var w: i64 = 0
482 while w < got { let r2: i64 = sys_write(cfd, ((buf as i64)+w) as *u8, got-w); if r2<=0 { w=got; remain=0 } else { w=w+r2 } }
483 if remain > 0 { remain = remain - got }
484 }
485 }
486 sys_close(fd)
487 return 1
488}
489// i64 -> NUL-terminated decimal string in buf; returns length.
490func gs_itoa(v: i64, buf: *u8) -> i64 {
491 var m: i64=v; if m<0 { m=0-m }
492 let t: *u8=sys_mmap(32); var k: i64=0
493 if m==0 { t[0]=(48 as u8); k=1 }
494 while m>0 { let q: i64=m/10; t[k]=((48+(m-q*10)) as u8); m=q; k=k+1 }
495 var i: i64=0; while i<k { buf[i]=t[k-1-i]; i=i+1 } buf[k]=(0 as u8)
496 return k
497}
498// scan TS packets in b[0..n) for PCRs (adaptation field, PCR_flag 0x10, 33-bit base @90kHz).
499func gs_pcr_scan(b: *u8, n: i64, fp: *i64, lp: *i64) -> i64 {
500 var i: i64=0
501 while i+188<=n {
502 if b[i]!=(0x47 as u8) { i=i+1 } else {
503 let afc: i64=((b[i+3] as i64)>>4)&3
504 if afc>=2 { let afl: i64=b[i+4] as i64; if afl>0 { let fl: i64=b[i+5] as i64; if ((fl>>4)&1)==1 {
505 let base: i64=((b[i+6] as i64)<<25)|((b[i+7] as i64)<<17)|((b[i+8] as i64)<<9)|((b[i+9] as i64)<<1)|((b[i+10] as i64)>>7)
506 if fp[0]<0 { fp[0]=base } lp[0]=base
507 } } }
508 i=i+188
509 }
510 }
511 return 0
512}
513// MPEG-TS duration in ms via first+last PCR (reads only an 8MB window at each end, no full scan).
514func gs_ts_dur(path: *u8) -> i64 {
515 let fd: i64=sys_openat_rd(path); if fd<0 { return 0 }
516 let size: i64=sys_lseek(fd,0,2)
517 let W: i64=VIEW_MAGIC_8388608
518 let b: *u8=sys_mmap(W+16)
519 let fp: *i64=sys_mmap(16) as *i64; fp[0]=0-1
520 let lp: *i64=sys_mmap(16) as *i64; lp[0]=0-1
521 sys_lseek(fd,0,0)
522 var got: i64=0; var go: i64=1
523 while go==1 { if got>=W { go=0 } else { let r: i64=sys_read(fd,((b as i64)+got) as *u8,W-got); if r<=0 { go=0 } else { got=got+r } } }
524 gs_pcr_scan(b,got,fp,lp)
525 let first: i64=fp[0]
526 let fp2: *i64=sys_mmap(16) as *i64; fp2[0]=0-1
527 let lp2: *i64=sys_mmap(16) as *i64; lp2[0]=0-1
528 var es: i64=size-W; if es<0 { es=0 }
529 sys_lseek(fd,es,0)
530 got=0; go=1
531 while go==1 { if got>=W { go=0 } else { let r: i64=sys_read(fd,((b as i64)+got) as *u8,W-got); if r<=0 { go=0 } else { got=got+r } } }
532 gs_pcr_scan(b,got,fp2,lp2)
533 let last: i64=lp2[0]
534 sys_close(fd)
535 if first<0 { return 0 }
536 if last<0 { return 0 }
537 var d: i64=last-first; if d<=0 { return 0 } if d>VIEW_MAGIC_7776000000 { return 0 }
538 return d/90
539}
540// current galx_vid_paths.tsv size -> freshness key for galx_dur.bin (line N -> video N valid while unchanged).
541func gs_vidpaths_size() -> i64 {
542 let tfd: i64 = sys_openat_rd("knowledge/status/galx_vid_paths.tsv" as *u8)
543 if tfd < 0 { return 0 }
544 let s: i64 = sys_lseek(tfd, 0, 2); sys_close(tfd); return s
545}
546// GET /vid/<id>/dur -> total duration in ms (text). The .ts seekbar needs this (fly-remux has no Content-Length).
547// FAST PATH: O(1) precomputed lookup in galx_dur.bin (built by nx_galx_durbin from the durindex output);
548// a <=0 result (not-yet-indexed / unknown) falls back to the live 16MB first+last-PCR scan, so never wrong.
549func gs_vid_dur_reply(cfd: i64, vid: *u8, id: i64) -> i64 {
550 var dur: i64 = db_lookup("knowledge/status/galx_dur.bin" as *u8, id, gs_vidpaths_size())
551 if dur <= 0 { dur = gs_ts_dur(vid) }
552 let body: *u8=sys_mmap(32); let blen: i64=gs_itoa(dur, body)
553 let hb: *u8=sys_mmap(256); var ho: i64=0
554 ho=gs_cat(hb,ho,"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nCache-Control: no-store\r\nConnection: close\r\nContent-Length: " as *u8)
555 ho=gs_u(hb,ho,blen)
556 ho=gs_cat(hb,ho,"\r\n\r\n" as *u8)
557 sys_write(cfd,hb,ho); sys_write(cfd,body,blen)
558 return 1
559}
560// reload-on-seek: ?t=<ms>&d=<dur_ms> -> proportional start byte = size * t / dur (client passes dur from /dur).
561func gs_seek_byte(req: *u8, rn: i64, vid: *u8) -> i64 {
562 let f: i64=gs_peel_num(req,rn,"?b=" as *u8,3)
563 if f<=0 { return 0 }
564 let fd: i64=sys_openat_rd(vid); if fd<0 { return 0 }
565 let size: i64=sys_lseek(fd,0,2); sys_close(fd)
566 return (size*f)/VIEW_MAGIC_1000000
567}
568// GET /vid/<id>/init.mp4 -> MSE init segment (ftyp+moov, both tracks) via the muxer's init mode.
569func gs_vid_init(cfd: i64, vid: *u8) -> i64 {
570 let hdr: *u8 = "HTTP/1.1 200 OK\r\nContent-Type: video/mp4\r\nCache-Control: max-age=3600\r\nConnection: close\r\n\r\n" as *u8
571 sys_write(cfd, hdr, gs_strlen(hdr))
572 sys_dup3(cfd, 1, 0)
573 let wpath: *u8 = "/volume1/ai/galx/nx_ts2fmp4.elf" as *u8
574 let mi: *u8 = "init" as *u8
575 let argv: *i64 = sys_mmap(64) as *i64
576 argv[0]=wpath as i64; argv[1]=vid as i64; argv[2]=mi as i64; argv[3]=0
577 let envp: *i64 = sys_mmap(8) as *i64; envp[0]=0
578 sys_execve_clean(wpath, argv, envp); sys_exit(127); return 1
579}
580// ---- sovereign MSE backend: read the NXVI index, serve init/segments, lazy-build the index ----
581func gs_be32(b: *u8, o: i64) -> i64 { return ((b[o] as i64)<<24)|((b[o+1] as i64)<<16)|((b[o+2] as i64)<<8)|(b[o+3] as i64) }
582func gs_be64(b: *u8, o: i64) -> i64 { return (gs_be32(b,o)<<32)|(gs_be32(b,o+4)&0xffffffff) }
583func gs_hex2(b: *u8, o: i64, v: i64) -> i64 { let h: *u8="0123456789abcdef" as *u8; b[o]=h[(v>>4)&0xf]; b[o+1]=h[v&0xf]; return o+2 }
584func gs_idxpath(id: i64, buf: *u8) -> i64 { var o: i64=gs_cat(buf,0,"knowledge/status/galxidx_" as *u8); let d: *u8=sys_mmap(32); let dl: i64=gs_itoa(id,d); var k: i64=0; while k<dl { buf[o]=d[k]; o=o+1; k=k+1 } o=gs_cat(buf,o,".idx" as *u8); buf[o]=0 as u8; return o }
585// fork a detached background indexer (nx_ts_index <vid> <idxpath>); orphan survives the request child.
586func gs_idx_build(id: i64, vid: *u8) -> i64 {
587 let p: i64 = sys_fork()
588 if p == 0 {
589 let ipath: *u8 = sys_mmap(256); gs_idxpath(id, ipath)
590 let wpath: *u8 = "/volume1/ai/galx/nx_ts_index.elf" as *u8
591 let argv: *i64 = sys_mmap(64) as *i64
592 argv[0]=wpath as i64; argv[1]=vid as i64; argv[2]=ipath as i64; argv[3]=0
593 let envp: *i64 = sys_mmap(8) as *i64; envp[0]=0
594 sys_execve_clean(wpath, argv, envp); sys_exit(127)
595 }
596 return 0
597}
598// GET /vid/<id>/seg?t=<ms> -> the media segment (moof+mdat) for the keyframe covering <ms>, via muxer seg mode.
599func gs_vid_seg(cfd: i64, vid: *u8, sb: i64, eb: i64, base: i64, vpid: i64, apid: i64) -> i64 {
600 let hdr: *u8 = "HTTP/1.1 200 OK\r\nContent-Type: video/mp4\r\nCache-Control: max-age=3600\r\nConnection: close\r\n\r\n" as *u8
601 sys_write(cfd, hdr, gs_strlen(hdr)); sys_dup3(cfd, 1, 0)
602 let wpath: *u8 = "/volume1/ai/galx/nx_ts2fmp4.elf" as *u8
603 let ms: *u8 = "seg" as *u8
604 let a3: *u8 = sys_mmap(32); gs_itoa(sb, a3); let a4: *u8 = sys_mmap(32); gs_itoa(eb, a4); let a5: *u8 = sys_mmap(32); gs_itoa(base, a5)
605 var vp: i64 = vpid; if vp < 1 { vp = 0 } if vp > VIEW_MAGIC_8191 { vp = 0 } var ap: i64 = apid; if ap < 1 { ap = 0 } if ap > VIEW_MAGIC_8191 { ap = 0 }
606 let a6: *u8 = sys_mmap(32); gs_itoa(vp, a6); let a7: *u8 = sys_mmap(32); gs_itoa(ap, a7)
607 let argv: *i64 = sys_mmap(64) as *i64
608 argv[0]=wpath as i64; argv[1]=vid as i64; argv[2]=ms as i64; argv[3]=a3 as i64; argv[4]=a4 as i64; argv[5]=a5 as i64; argv[6]=a6 as i64; argv[7]=a7 as i64; argv[8]=0
609 let envp: *i64 = sys_mmap(8) as *i64; envp[0]=0
610 sys_execve_clean(wpath, argv, envp); sys_exit(127); return 1
611}
612func gs_503(cfd: i64) -> i64 { let m: *u8="HTTP/1.1 503 Service Unavailable\r\nContent-Type: text/plain\r\nCache-Control: no-store\r\nContent-Length: 8\r\nConnection: close\r\n\r\nbuilding" as *u8; sys_write(cfd, m, gs_strlen(m)); return 1 }
613func gs_seg_handler(cfd: i64, id: i64, vid: *u8, req: *u8, rn: i64) -> i64 {
614 let ipath: *u8 = sys_mmap(256); gs_idxpath(id, ipath)
615 let szp: *i64 = sys_mmap(16) as *i64
616 let b: *u8 = sys_read_file(ipath, szp)
617 if (b as i64)==0 { gs_idx_build(id, vid); return gs_503(cfd) }
618 if szp[0] < 48 { return gs_503(cfd) }
619 if b[0]!=(78 as u8) { return gs_503(cfd) }
620 if gs_be32(b,4)!=2 { gs_idx_build(id, vid); return gs_503(cfd) }
621 var tt: i64 = gs_peel_num(req, rn, "?t=" as *u8, 3); if tt<0 { tt=0 }
622 let vidpid: i64 = gs_be32(b, 24)
623 let audpid: i64 = gs_be32(b, 28)
624 let spslen: i64 = gs_be32(b, 32)
625 let ppslen: i64 = gs_be32(b, 36+spslen)
626 let nkf: i64 = gs_be64(b, 40+spslen+ppslen)
627 let kfo: i64 = 48 + spslen + ppslen
628 var n: i64 = 0; var i: i64 = 0
629 while i < nkf { let tm: i64 = gs_be64(b, kfo+i*16); if tm <= tt { n=i } else { i=nkf } i=i+1 }
630 let sb: i64 = gs_be64(b, kfo+n*16+8)
631 var eb: i64 = sb + VIEW_MAGIC_50000000
632 if n+1 < nkf { eb = gs_be64(b, kfo+(n+1)*16+8) }
633 let base: i64 = gs_be64(b, kfo+n*16)
634 return gs_vid_seg(cfd, vid, sb, eb, base, vidpid, audpid)
635}
636// browser-native containers (mp4/m4v/mov/webm) play + seek directly via HTTP Range -> no NXVI index/MSE needed.
637func gs_vid_native(ex: *u8) -> i64 { if gs_streq(ex,"mp4" as *u8)==1 {return 1} if gs_streq(ex,"m4v" as *u8)==1 {return 1} if gs_streq(ex,"mov" as *u8)==1 {return 1} if gs_streq(ex,"webm" as *u8)==1 {return 1} return 0 }
638func gs_segs_handler(cfd: i64, id: i64, vid: *u8) -> i64 {
639 let ex0: *u8 = sys_mmap(16); gs_vid_ext(vid, ex0)
640 if gs_vid_native(ex0)==1 { let nb: *u8 = sys_mmap(128); let nl: i64 = gs_okjson(nb, "{\"native\":1}" as *u8, 12); sys_write(cfd, nb, nl); return 1 }
641 if gs_streq(ex0,"ts" as *u8)==0 { if gs_streq(ex0,"m2ts" as *u8)==0 { let rb0: *u8 = sys_mmap(128); let rl0: i64 = gs_okjson(rb0, "{\"ready\":0}" as *u8, 11); sys_write(cfd, rb0, rl0); return 1 } }
642 let ipath: *u8 = sys_mmap(256); gs_idxpath(id, ipath)
643 let szp: *i64 = sys_mmap(16) as *i64
644 let b: *u8 = sys_read_file(ipath, szp)
645 let body: *u8 = sys_mmap(128); var bo: i64 = 0
646 if (b as i64)==0 { gs_idx_build(id, vid); bo=gs_cat(body,0,"{\"ready\":0}" as *u8) } else { if b[0]!=(78 as u8) { bo=gs_cat(body,0,"{\"ready\":0}" as *u8) } else { if gs_be32(b,4)!=2 { gs_idx_build(id, vid); bo=gs_cat(body,0,"{\"ready\":0}" as *u8) } else {
647 let dur: i64 = gs_be64(b, 8); let spslen: i64 = gs_be32(b, 32); let ppslen: i64 = gs_be32(b, 36+spslen); let nkf: i64 = gs_be64(b, 40+spslen+ppslen)
648 if nkf > 0 { bo=gs_cat(body,0,"{\"ready\":1,\"dur\":" as *u8); bo=gs_u(body,bo,dur); bo=gs_cat(body,bo,",\"n\":" as *u8); bo=gs_u(body,bo,nkf); bo=gs_cat(body,bo,",\"codec\":\"avc1." as *u8); bo=gs_hex2(body,bo,b[37] as i64); bo=gs_hex2(body,bo,b[38] as i64); bo=gs_hex2(body,bo,b[39] as i64); bo=gs_cat(body,bo,"\"}" as *u8) } else { bo=gs_cat(body,0,"{\"ready\":0}" as *u8) }
649 } } }
650 let rb: *u8 = sys_mmap(512); let ln: i64 = gs_okjson(rb, body, bo); sys_write(cfd, rb, ln); return 1
651}
652// remux an MPEG-TS recording to fragmented MP4 on the fly (stdout = the client socket).
653func gs_vid_remux_ts(cfd: i64, vid: *u8, start_byte: i64) -> i64 {
654 let hdr: *u8 = "HTTP/1.1 200 OK\r\nContent-Type: video/mp4\r\nCache-Control: no-store\r\nConnection: close\r\n\r\n" as *u8
655 sys_write(cfd, hdr, gs_strlen(hdr))
656 sys_dup3(cfd, 1, 0)
657 let wpath: *u8 = "/volume1/ai/galx/nx_ts2fmp4.elf" as *u8
658 let argv: *i64 = sys_mmap(64) as *i64
659 argv[0] = wpath as i64; argv[1] = vid as i64
660 if start_byte > 0 { let sb: *u8 = sys_mmap(32); gs_itoa(start_byte, sb); let mz: *u8 = "0" as *u8; argv[2] = mz as i64; argv[3] = sb as i64; argv[4] = 0 } else { argv[2] = 0 }
661 let envp: *i64 = sys_mmap(8) as *i64; envp[0] = 0
662 sys_execve_clean(wpath, argv, envp)
663 sys_exit(127)
664 return 1
665}
666// remux a Matroska (.mkv) recording to fragmented MP4 on the fly (stdout = client socket). H.264/HEVC video.
667func gs_vid_remux_mkv(cfd: i64, vid: *u8, start_byte: i64) -> i64 {
668 let hdr: *u8 = "HTTP/1.1 200 OK\r\nContent-Type: video/mp4\r\nCache-Control: no-store\r\nConnection: close\r\n\r\n" as *u8
669 sys_write(cfd, hdr, gs_strlen(hdr))
670 sys_dup3(cfd, 1, 0)
671 let wpath: *u8 = "/volume1/ai/galx/nx_mkv2fmp4.elf" as *u8
672 let argv: *i64 = sys_mmap(64) as *i64
673 argv[0] = wpath as i64; argv[1] = vid as i64
674 if start_byte > 0 { let sb: *u8 = sys_mmap(32); gs_itoa(start_byte, sb); argv[2] = sb as i64; argv[3] = 0 } else { argv[2] = 0 }
675 let envp: *i64 = sys_mmap(8) as *i64; envp[0] = 0
676 sys_execve_clean(wpath, argv, envp); sys_exit(127); return 1
677}
678// GET /vid/<id>/marks -> clip-analysis markers (dead-air etc.) from the NXVI's back-compat NXMK sidecar tail.
679// JSON [{type,start,end}] in ms (type 1=dead-air). Empty [] if no index or a legacy idx without the tail.
680func gs_vid_marks(cfd: i64, id: i64) -> i64 {
681 let ipath: *u8 = sys_mmap(256); gs_idxpath(id, ipath)
682 let szp: *i64 = sys_mmap(16) as *i64
683 let b: *u8 = sys_read_file(ipath, szp)
684 let body: *u8 = sys_mmap(VIEW_MAGIC_262144); var bo: i64 = gs_cat(body, 0, "[" as *u8)
685 if (b as i64) != 0 { if szp[0] > 48 { if b[0]==(78 as u8) {
686 let spslen: i64 = gs_be32(b, 32)
687 let ppslen: i64 = gs_be32(b, 36+spslen)
688 let nkf: i64 = gs_be64(b, 40+spslen+ppslen)
689 let mo: i64 = 48 + spslen + ppslen + nkf*16
690 if (mo+12) <= szp[0] { if b[mo]==(78 as u8) { if b[mo+1]==(88 as u8) { if b[mo+2]==(77 as u8) { if b[mo+3]==(75 as u8) {
691 let nm: i64 = gs_be64(b, mo+4)
692 var ko: i64 = mo + 12
693 var i: i64 = 0
694 while i < nm {
695 if (ko+24) <= szp[0] {
696 let ty: i64 = gs_be32(b, ko)
697 let st: i64 = gs_be64(b, ko+4)
698 let en: i64 = gs_be64(b, ko+12)
699 if i > 0 { bo = gs_cat(body, bo, "," as *u8) }
700 bo = gs_cat(body, bo, "{\"type\":" as *u8); bo = gs_u(body, bo, ty)
701 bo = gs_cat(body, bo, ",\"start\":" as *u8); bo = gs_u(body, bo, st)
702 bo = gs_cat(body, bo, ",\"end\":" as *u8); bo = gs_u(body, bo, en)
703 bo = gs_cat(body, bo, "}" as *u8)
704 }
705 ko = ko + 24
706 i = i + 1
707 }
708 } } } } }
709 } } }
710 bo = gs_cat(body, bo, "]" as *u8)
711 let rb: *u8 = sys_mmap(VIEW_MAGIC_262208); let ln: i64 = gs_okjson(rb, body, bo)
712 sys_write(cfd, rb, ln); return 1
713}
714// GET /vid/<id>/analysis -> the FIRST classification rung: fuse the NXMK markers + duration into a coarse content
715// label (quiet/active/rhythmic-dance/scene-heavy/mixed) + the profile. ts_classify (gated 11/11) does the join.
716func gs_vid_analysis(cfd: i64, id: i64) -> i64 {
717 let ipath: *u8 = sys_mmap(256); gs_idxpath(id, ipath)
718 let szp: *i64 = sys_mmap(16) as *i64
719 let b: *u8 = sys_read_file(ipath, szp)
720 let mt: *i64 = sys_mmap(8*VIEW_MAGIC_4096) as *i64; let ms: *i64 = sys_mmap(8*VIEW_MAGIC_4096) as *i64; let me: *i64 = sys_mmap(8*VIEW_MAGIC_4096) as *i64
721 var nm: i64 = 0
722 var dur: i64 = 0
723 if (b as i64) != 0 { if szp[0] > 48 { if b[0]==(78 as u8) {
724 dur = gs_be64(b, 8)
725 let spslen: i64 = gs_be32(b, 32)
726 let ppslen: i64 = gs_be32(b, 36+spslen)
727 let nkf: i64 = gs_be64(b, 40+spslen+ppslen)
728 let mo: i64 = 48 + spslen + ppslen + nkf*16
729 if (mo+12) <= szp[0] { if b[mo]==(78 as u8) { if b[mo+1]==(88 as u8) { if b[mo+2]==(77 as u8) { if b[mo+3]==(75 as u8) {
730 let cnt: i64 = gs_be64(b, mo+4)
731 var ko: i64 = mo + 12
732 var i: i64 = 0
733 while i < cnt {
734 if (ko+24) <= szp[0] { if nm < VIEW_MAGIC_4096 { mt[nm] = gs_be32(b, ko); ms[nm] = gs_be64(b, ko+4); me[nm] = gs_be64(b, ko+12); nm = nm + 1 } }
735 ko = ko + 24
736 i = i + 1
737 }
738 } } } } }
739 } } }
740 let out: *i64 = sys_mmap(8*8) as *i64
741 let label: i64 = ts_classify(mt, ms, me, nm, dur, out)
742 var lbl: *u8 = "mixed" as *u8
743 if label == 0 { lbl = "quiet/static" as *u8 }
744 if label == 1 { lbl = "active/dynamic" as *u8 }
745 if label == 2 { lbl = "rhythmic/dance-like" as *u8 }
746 if label == 3 { lbl = "scene-heavy" as *u8 }
747 let body: *u8 = sys_mmap(512); var bo: i64 = 0
748 bo = gs_cat(body, bo, "{\"label\":\"" as *u8); bo = gs_cat(body, bo, lbl)
749 bo = gs_cat(body, bo, "\",\"dur\":" as *u8); bo = gs_u(body, bo, dur)
750 bo = gs_cat(body, bo, ",\"quiet_ms\":" as *u8); bo = gs_u(body, bo, out[0])
751 bo = gs_cat(body, bo, ",\"active_ms\":" as *u8); bo = gs_u(body, bo, out[1])
752 bo = gs_cat(body, bo, ",\"rhythmic_ms\":" as *u8); bo = gs_u(body, bo, out[2])
753 bo = gs_cat(body, bo, ",\"scenes\":" as *u8); bo = gs_u(body, bo, out[3])
754 bo = gs_cat(body, bo, ",\"marks\":" as *u8); bo = gs_u(body, bo, nm)
755 bo = gs_cat(body, bo, "}" as *u8)
756 let rb: *u8 = sys_mmap(VIEW_MAGIC_1024); let ln: i64 = gs_okjson(rb, body, bo)
757 sys_write(cfd, rb, ln); return 1
758}
759// GET /vid/<id> -> play a recording: native container direct (Range) or MPEG-TS/Matroska remux.
760func gs_vid_stream(cfd: i64, req: *u8, rn: i64) -> i64 {
761 let nf: *u8 = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8
762 let id: i64 = gs_peel_num(req, rn, "GET /vid/" as *u8, 9)
763 if id < 0 { sys_write(cfd, nf, gs_strlen(nf)); return 1 }
764 let vid: *u8 = sys_mmap(VIEW_MAGIC_2048)
765 if gs_vid_line(id, vid) == 0 { sys_write(cfd, nf, gs_strlen(nf)); return 1 }
766 if eh_find(req, rn, "/init.mp4" as *u8, 9) == 1 { return gs_vid_init(cfd, vid) }
767 if eh_find(req, rn, "/dur" as *u8, 4) == 1 { return gs_vid_dur_reply(cfd, vid, id) }
768 if eh_find(req, rn, "/segs" as *u8, 5) == 1 { return gs_segs_handler(cfd, id, vid) }
769 if eh_find(req, rn, "/marks" as *u8, 6) == 1 { return gs_vid_marks(cfd, id) }
770 if eh_find(req, rn, "/analysis" as *u8, 9) == 1 { return gs_vid_analysis(cfd, id) }
771 if eh_find(req, rn, "/seg" as *u8, 4) == 1 { return gs_seg_handler(cfd, id, vid, req, rn) }
772 let ex: *u8 = sys_mmap(16)
773 gs_vid_ext(vid, ex)
774 if gs_streq(ex, "ts" as *u8)==1 { return gs_vid_remux_ts(cfd, vid, gs_seek_byte(req, rn, vid)) }
775 if gs_streq(ex, "m2ts" as *u8)==1 { return gs_vid_remux_ts(cfd, vid, gs_seek_byte(req, rn, vid)) }
776 if gs_streq(ex, "mkv" as *u8)==1 { return gs_vid_remux_mkv(cfd, vid, gs_seek_byte(req, rn, vid)) }
777 return gs_serve_file_range(cfd, req, rn, vid, gs_vid_mime(ex))
778}
779// resolve a video path's collection from the data-driven rules file (substring<TAB>cat, first match wins).
780// 'r'=Recordings (cam) / 'm'=Media (SFW) / 'v'=Videos (NSFW). default 'r'. Lets sources be re-sorted w/o rebuild.
781func gs_path_cat(b: *u8, ls: i64, le: i64, rb: *u8, rsz: i64) -> i64 {
782 if (rb as i64) == 0 { return 114 }
783 var i: i64 = 0; var lstart: i64 = 0
784 while i <= rsz {
785 var nl: i64 = 0; if i==rsz { nl=1 } else { if rb[i]==(10 as u8) { nl=1 } }
786 if nl==1 {
787 var tab: i64 = 0-1; var p: i64 = lstart
788 while p < i { if rb[p]==(9 as u8) { if tab<0 { tab=p } } p=p+1 }
789 if tab > lstart { if tab+1 < i {
790 let slen: i64 = tab - lstart
791 var q: i64 = ls; var found: i64 = 0
792 while q + slen <= le {
793 var j: i64=0; var ok: i64=1
794 while j<slen { if b[q+j]!=rb[lstart+j]{ok=0; j=slen} else { j=j+1 } }
795 if ok==1 { found=1; q=le } else { q=q+1 }
796 }
797 if found==1 { return rb[tab+1] as i64 }
798 } }
799 lstart = i+1
800 }
801 i = i+1
802 }
803 return 114
804}
805// ---- per-category INDEX (R4: O(page) collection listing instead of a 372k-line scan + rule-match/request) ----
806// At startup gs_catidx_build scans galx_vid_paths.tsv ONCE, applies the rules (gs_path_cat), and writes a
807// per-category file galx_cat_<c>.bin = [tsv_size i64][count i64][lineno i64 ...] (file order; reader slices
808// newest-first). gs_catidx_emit serves a page directly from that file; if it is missing or its tsv_size stamp
809// != the live galx_vid_paths.tsv size (stale), it returns 0 and gs_collection_list FALLS BACK to the full scan
810// -> zero-regression. Research-grounded (a keyset/index slice is ~hundreds x faster at depth than an offset scan).
811func gs_file_size(path: *u8) -> i64 {
812 let fd: i64 = sys_openat_rd(path)
813 if fd < 0 { return 0 - 1 }
814 let sz: i64 = sys_lseek(fd, 0, 2)
815 sys_close(fd)
816 return sz
817}
818func gs_catidx_path(wantc: i64, out: *u8) -> i64 {
819 var o: i64 = gs_cat(out, 0, "knowledge/status/galx_cat_" as *u8)
820 out[o] = wantc as u8; o = o + 1
821 o = gs_cat(out, o, ".bin" as *u8); out[o] = 0 as u8
822 return o
823}
824func gs_catidx_write(path: *u8, tsvsz: i64, arr: *i64, cnt: i64) -> i64 {
825 let ob: *u8 = sys_mmap(16 + cnt * 8 + 64)
826 gs_wb64(ob, 0, tsvsz); gs_wb64(ob, 8, cnt)
827 var k: i64 = 0; while k < cnt { gs_wb64(ob, 16 + k * 8, arr[k]); k = k + 1 }
828 let fd: i64 = sys_openat_wr(path, 0x1a4) // 0644
829 if fd < 0 { return 0 - 1 }
830 sys_write(fd, ob, 16 + cnt * 8)
831 sys_close(fd)
832 return cnt
833}
834// Scan galx_vid_paths.tsv once + bucket line numbers by category, matching gs_collection_list's lineno/keep
835// semantics EXACTLY (lineno counts every line; only lines with len>3 are bucketed; the same gs_path_cat rules).
836func gs_catidx_build() -> i64 {
837 let rszp: *i64 = sys_mmap(16) as *i64
838 let rb: *u8 = sys_read_file("knowledge/status/galx_vid_rules.tsv" as *u8, rszp)
839 let rsz: i64 = rszp[0]
840 let szp: *i64 = sys_mmap(16) as *i64
841 let b: *u8 = sys_read_file("knowledge/status/galx_vid_paths.tsv" as *u8, szp)
842 let sz: i64 = szp[0]
843 if (b as i64) == 0 { return 0 }
844 let ar: *i64 = sys_mmap(8 * VIEW_MAGIC_1500000) as *i64; var nr: i64 = 0
845 let am: *i64 = sys_mmap(8 * VIEW_MAGIC_1500000) as *i64; var nm: i64 = 0
846 let av: *i64 = sys_mmap(8 * VIEW_MAGIC_1500000) as *i64; var nv: i64 = 0
847 var i: i64 = 0; var ls: i64 = 0; var lineno: i64 = 0
848 while i <= sz {
849 var nl: i64 = 0; if i == sz { nl = 1 } else { if b[i] == (10 as u8) { nl = 1 } }
850 if nl == 1 {
851 if i - ls > 3 {
852 let cat: i64 = gs_path_cat(b, ls, i, rb, rsz)
853 if cat == 114 { if nr < VIEW_MAGIC_1500000 { ar[nr] = lineno; nr = nr + 1 } }
854 else { if cat == 109 { if nm < VIEW_MAGIC_1500000 { am[nm] = lineno; nm = nm + 1 } }
855 else { if cat == 118 { if nv < VIEW_MAGIC_1500000 { av[nv] = lineno; nv = nv + 1 } } } }
856 }
857 lineno = lineno + 1; ls = i + 1
858 }
859 i = i + 1
860 }
861 let pth: *u8 = sys_mmap(256)
862 gs_catidx_path(114, pth); gs_catidx_write(pth, sz, ar, nr)
863 gs_catidx_path(109, pth); gs_catidx_write(pth, sz, am, nm)
864 gs_catidx_path(118, pth); gs_catidx_write(pth, sz, av, nv)
865 return nr + nm + nv
866}
867// Serve one page from the pre-built category index, newest-first. Returns the response length, or 0 if the
868// index is missing/stale (the caller then does the full scan = the fallback). Matches gs_collection_list output.
869// Discovery offset (2026-06-28 deep-research validated): surface the MIDDLE of a collection, not just
870// the ends. A materialized rank array (our catidx/matched[]) makes jump-to-position O(1) -- the
871// Elasticsearch search_after "no random access" limit applies to disk cursors, not in-RAM arrays.
872// &pct=N -> jump to N% through the collection (0..100), deterministic.
873// &rand=1 -> random page (mono-clock nsec seed) so repeated loads roam the whole library, not the ends.
874// Returns o0 when neither is set. Next rung: least-recently-surfaced weighted rotation (Efraimidis-Spirakis).
875func gs_eff_offset(req: *u8, rn: i64, count: i64, o0: i64) -> i64 {
876 if count <= 0 { return 0 }
877 let pct: i64 = gs_qint(req, rn, "pct=", 0 - 1)
878 if pct >= 0 { var pc: i64 = pct; if pc > 100 { pc = 100 } var off: i64 = (count * pc) / 100; if off >= count { off = count - 1 } return off }
879 let rnd: i64 = gs_qint(req, rn, "rand=", 0)
880 if rnd == 1 { let ts: *i64 = sys_mmap(16) as *i64; sys_clock_gettime_mono(ts); var seed: i64 = ts[1]; if seed < 0 { seed = 0 - seed } return seed % count }
881 return o0
882}
883func gs_catidx_emit(rbuf: *u8, req: *u8, rn: i64, wantc: i64, o0: i64, n: i64) -> i64 {
884 let live: i64 = gs_file_size("knowledge/status/galx_vid_paths.tsv" as *u8)
885 if live < 0 { return 0 }
886 let pth: *u8 = sys_mmap(256); gs_catidx_path(wantc, pth)
887 let szp: *i64 = sys_mmap(16) as *i64
888 let cb: *u8 = sys_read_file(pth, szp)
889 if (cb as i64) == 0 { return 0 }
890 if szp[0] < 16 { return 0 }
891 if gs_rb64(cb, 0) != live { return 0 } // stale -> fall back to the scan
892 let count: i64 = gs_rb64(cb, 8)
893 let eo0: i64 = gs_eff_offset(req, rn, count, o0)
894 let body: *u8 = sys_mmap(VIEW_MAGIC_65536); var bo: i64 = 0
895 bo = gs_cat(body, bo, "{\"kind\":\"rec\",\"total\":" as *u8); bo = gs_u(body, bo, count); bo = gs_cat(body, bo, ",\"items\":[" as *u8)
896 var k: i64 = 0; var first: i64 = 1
897 while k < n { let disp: i64 = eo0 + k; if disp >= count { k = n } else { let id: i64 = gs_rb64(cb, 16 + (count - 1 - disp) * 8); if first == 0 { body[bo] = 44 as u8; bo = bo + 1 } first = 0; body[bo] = 34 as u8; bo = bo + 1; bo = gs_u(body, bo, id); body[bo] = 34 as u8; bo = bo + 1; k = k + 1 } }
898 bo = gs_cat(body, bo, "]}" as *u8)
899 return gs_okjson(rbuf, body, bo)
900}
901// R2 sort-by-key handlers (ss_emit_size / ss_emit_runtime) live in nx_galx_sortindex.nx (imported above) and
902// are sovereignly gated by nx_galx_sortserve_gate; the daemon's sort= routes call them directly. Index format:
903// galx_sort_<key>_<c>.bin = [stamp=vid_paths size][count][ids asc-by-key], read fwd(asc)/bwd(desc) + si_eff_offset.
904// GET /api/list?filter=recordings|media|videos[&model=] -> ids of that collection, newest-first.
905func gs_collection_list(rbuf: *u8, req: *u8, rn: i64, wantc: i64, o0: i64, n: i64) -> i64 {
906 let mbuf: *u8 = sys_mmap(256); var mlen: i64 = 0
907 var li: i64 = 0; var mpos: i64 = 0 - 1; var stop: i64 = rn
908 while li < stop { if req[li]==(10 as u8) { stop = li } else { if mpos < 0 { if li+6 <= rn { if req[li]==(109 as u8){ if req[li+1]==(111 as u8){ if req[li+2]==(100 as u8){ if req[li+3]==(101 as u8){ if req[li+4]==(108 as u8){ if req[li+5]==(61 as u8){ mpos = li+6 } } } } } } } } li = li + 1 } }
909 if mpos >= 0 { var p: i64 = mpos; var go: i64 = 1; while go == 1 { if p >= rn { go = 0 } else { let c: i64 = req[p] as i64; if c==38 { go=0 } else { if c==32 { go=0 } else { if c==10 { go=0 } else { if c==13 { go=0 } else { if mlen < 255 { mbuf[mlen]=c as u8; mlen=mlen+1 } p=p+1 } } } } } } }
910 // R4 fast path: no model filter -> serve the page straight from the pre-built category index (fresh check
911 // inside). Returns 0 (miss/stale) -> fall through to the full scan below. The &model= path always scans.
912 if mlen == 0 { let fr: i64 = gs_catidx_emit(rbuf, req, rn, wantc, o0, n); if fr > 0 { return fr } }
913 let rszp: *i64 = sys_mmap(16) as *i64
914 let rb: *u8 = sys_read_file("knowledge/status/galx_vid_rules.tsv" as *u8, rszp)
915 let rsz: i64 = rszp[0]
916 let szp: *i64 = sys_mmap(16) as *i64
917 let b: *u8 = sys_read_file("knowledge/status/galx_vid_paths.tsv" as *u8, szp)
918 let sz: i64 = szp[0]
919 let matched: *i64 = sys_mmap(8 * VIEW_MAGIC_1000000) as *i64; var nmatch: i64 = 0
920 if (b as i64) != 0 {
921 var i: i64 = 0; var ls: i64 = 0; var lineno: i64 = 0
922 while i <= sz {
923 var nl: i64 = 0; if i == sz { nl = 1 } else { if b[i]==(10 as u8) { nl = 1 } }
924 if nl == 1 {
925 if i - ls > 3 {
926 let cat: i64 = gs_path_cat(b, ls, i, rb, rsz)
927 if cat == wantc {
928 var keep: i64 = 1
929 if mlen > 0 {
930 var last: i64 = 0-1; var prev: i64 = 0-1; var p: i64 = ls
931 while p < i { if b[p]==(47 as u8) { prev = last; last = p } p = p + 1 }
932 keep = 0
933 if prev >= 0 { if last > prev { let ps: i64 = prev+1; let pl: i64 = last-ps
934 if pl == mlen { var eq: i64 = 1; var c: i64 = 0; while c < pl { if b[ps+c] != mbuf[c] { eq = 0 } c = c + 1 } if eq == 1 { keep = 1 } }
935 } }
936 }
937 if keep == 1 { if nmatch < VIEW_MAGIC_1000000 { matched[nmatch] = lineno; nmatch = nmatch + 1 } }
938 }
939 }
940 lineno = lineno + 1; ls = i + 1
941 }
942 i = i + 1
943 }
944 }
945 let body: *u8 = sys_mmap(VIEW_MAGIC_65536); var bo: i64 = 0
946 bo = gs_cat(body, bo, "{\"kind\":\"rec\",\"total\":" as *u8); bo = gs_u(body, bo, nmatch); bo = gs_cat(body, bo, ",\"items\":[" as *u8)
947 let eo0: i64 = gs_eff_offset(req, rn, nmatch, o0)
948 var k: i64 = 0; var first: i64 = 1
949 while k < n { let disp: i64 = eo0 + k; if disp >= nmatch { k = n } else { let id: i64 = matched[nmatch-1-disp]; if first==0 { body[bo]=44 as u8; bo=bo+1 } first=0; body[bo]=34 as u8; bo=bo+1; bo = gs_u(body, bo, id); body[bo]=34 as u8; bo=bo+1; k=k+1 } }
950 bo = gs_cat(body, bo, "]}" as *u8)
951 return gs_okjson(rbuf, body, bo)
952}
953// GET /api/list?filter=recordings -> {"total":N,"kind":"rec","items":[id...]} newest-first (reverse index).
954func gs_recordings_list(rbuf: *u8, req: *u8, rn: i64, o0: i64, n: i64) -> i64 {
955 // parse optional &model=<name> (the person/folder) from the request line
956 let mbuf: *u8 = sys_mmap(256); var mlen: i64 = 0
957 var li: i64 = 0; var mpos: i64 = 0 - 1; var stop: i64 = rn
958 while li < stop { if req[li]==(10 as u8) { stop = li } else { if mpos < 0 { if li+6 <= rn { if req[li]==(109 as u8){ if req[li+1]==(111 as u8){ if req[li+2]==(100 as u8){ if req[li+3]==(101 as u8){ if req[li+4]==(108 as u8){ if req[li+5]==(61 as u8){ mpos = li+6 } } } } } } } } li = li + 1 } }
959 if mpos >= 0 { var p: i64 = mpos; var go: i64 = 1; while go == 1 { if p >= rn { go = 0 } else { let c: i64 = req[p] as i64; if c==38 { go=0 } else { if c==32 { go=0 } else { if c==10 { go=0 } else { if c==13 { go=0 } else { if mlen < 255 { mbuf[mlen]=c as u8; mlen=mlen+1 } p=p+1 } } } } } } }
960 let szp: *i64 = sys_mmap(16) as *i64
961 let b: *u8 = sys_read_file("knowledge/status/galx_vid_paths.tsv" as *u8, szp)
962 let sz: i64 = szp[0]
963 let body: *u8 = sys_mmap(VIEW_MAGIC_65536)
964 var bo: i64 = 0
965 if mlen == 0 {
966 var total: i64 = 0
967 if (b as i64) != 0 { var i: i64 = 0; while i < sz { if b[i]==(10 as u8) { total = total + 1 } i = i + 1 } }
968 bo = gs_cat(body, bo, "{\"kind\":\"rec\",\"total\":" as *u8); bo = gs_u(body, bo, total); bo = gs_cat(body, bo, ",\"items\":[" as *u8)
969 let eo0: i64 = gs_eff_offset(req, rn, total, o0)
970 var k: i64 = 0; var first: i64 = 1
971 while k < n { let disp: i64 = eo0 + k; if disp >= total { k = n } else { let id: i64 = total-1-disp; if first==0 { body[bo]=44 as u8; bo=bo+1 } first=0; body[bo]=34 as u8; bo=bo+1; bo = gs_u(body, bo, id); body[bo]=34 as u8; bo=bo+1; k=k+1 } }
972 bo = gs_cat(body, bo, "]}" as *u8)
973 } else {
974 let matched: *i64 = sys_mmap(8 * VIEW_MAGIC_1000000) as *i64; var nmatch: i64 = 0
975 if (b as i64) != 0 {
976 var i: i64 = 0; var ls: i64 = 0; var lineno: i64 = 0
977 while i <= sz {
978 var nl: i64 = 0; if i == sz { nl = 1 } else { if b[i]==(10 as u8) { nl = 1 } }
979 if nl == 1 { if i - ls > 3 {
980 var last: i64 = 0-1; var prev: i64 = 0-1; var p: i64 = ls
981 while p < i { if b[p]==(47 as u8) { prev = last; last = p } p = p + 1 }
982 if prev >= 0 { if last > prev { let ps: i64 = prev+1; let pl: i64 = last-ps
983 if pl == mlen { var eq: i64 = 1; var c: i64 = 0; while c < pl { if b[ps+c] != mbuf[c] { eq = 0 } c = c + 1 } if eq == 1 { if nmatch < VIEW_MAGIC_1000000 { matched[nmatch] = lineno; nmatch = nmatch + 1 } } }
984 } }
985 lineno = lineno + 1
986 } ls = i + 1 }
987 i = i + 1
988 }
989 }
990 bo = gs_cat(body, bo, "{\"kind\":\"rec\",\"total\":" as *u8); bo = gs_u(body, bo, nmatch); bo = gs_cat(body, bo, ",\"items\":[" as *u8)
991 let eo0: i64 = gs_eff_offset(req, rn, nmatch, o0)
992 var k: i64 = 0; var first: i64 = 1
993 while k < n { let disp: i64 = eo0 + k; if disp >= nmatch { k = n } else { let id: i64 = matched[nmatch-1-disp]; if first==0 { body[bo]=44 as u8; bo=bo+1 } first=0; body[bo]=34 as u8; bo=bo+1; bo = gs_u(body, bo, id); body[bo]=34 as u8; bo=bo+1; k=k+1 } }
994 bo = gs_cat(body, bo, "]}" as *u8)
995 }
996 return gs_okjson(rbuf, body, bo)
997}
998// GET /api/models -> [{"m":"<person>","c":<count>},...] from galx_models.tsv (sorted by count desc)
999func gs_models(rbuf: *u8) -> i64 {
1000 let szp: *i64 = sys_mmap(16) as *i64
1001 let b: *u8 = sys_read_file("knowledge/status/galx_models.tsv" as *u8, szp)
1002 let sz: i64 = szp[0]
1003 let body: *u8 = sys_mmap(VIEW_MAGIC_262144); var bo: i64 = 0
1004 body[bo] = 91 as u8; bo = bo + 1
1005 var first: i64 = 1
1006 if (b as i64) != 0 {
1007 var i: i64 = 0; var ls: i64 = 0
1008 while i <= sz {
1009 var nl: i64 = 0; if i == sz { nl = 1 } else { if b[i]==(10 as u8) { nl = 1 } }
1010 if nl == 1 { if i - ls >= 3 {
1011 var tab: i64 = 0-1; var p: i64 = ls; while p < i { if b[p]==(9 as u8) { if tab < 0 { tab = p } } p = p + 1 }
1012 if tab >= 0 { if bo < VIEW_MAGIC_258000 {
1013 if first == 0 { body[bo]=44 as u8; bo=bo+1 } first = 0
1014 bo = gs_cat(body, bo, "{\"m\":\"" as *u8)
1015 var c: i64 = ls; while c < tab { let ch: i64 = b[c] as i64; if ch==34 { body[bo]=92 as u8; bo=bo+1; body[bo]=34 as u8; bo=bo+1 } else { if ch==92 { body[bo]=92 as u8; bo=bo+1; body[bo]=92 as u8; bo=bo+1 } else { body[bo]=ch as u8; bo=bo+1 } } c = c + 1 }
1016 bo = gs_cat(body, bo, "\",\"c\":" as *u8)
1017 var d: i64 = tab+1; while d < i { body[bo]=b[d]; bo=bo+1; d=d+1 }
1018 body[bo] = 125 as u8; bo = bo + 1
1019 } }
1020 } ls = i + 1 }
1021 i = i + 1
1022 }
1023 }
1024 body[bo] = 93 as u8; bo = bo + 1
1025 return gs_okjson(rbuf, body, bo)
1026}
1027
1028// ---- /meta ----
1029func gs_jesc(dst: *u8, o: i64, ch: i64) -> i64 {
1030 if ch == 34 { dst[o]=92 as u8; dst[o+1]=34 as u8; return o+2 }
1031 if ch == 92 { dst[o]=92 as u8; dst[o+1]=92 as u8; return o+2 }
1032 if ch < 32 { dst[o]=32 as u8; return o+1 }
1033 dst[o]=ch as u8; return o+1
1034}
1035func gs_meta(rbuf: *u8, req: *u8, rn: i64, cidx: *NxCidx) -> i64 {
1036 let cid: *u8 = sys_mmap(96)
1037 let okc: i64 = gs_peel_pat(req, rn, "GET /meta/" as *u8, 10, cid)
1038 let body: *u8 = sys_mmap(VIEW_MAGIC_262144)
1039 var bo: i64 = 0
1040 body[bo] = 123 as u8; bo = bo + 1
1041 var first: i64 = 1
1042 if okc == 1 {
1043 let path: *u8 = sys_mmap(VIEW_MAGIC_2048)
1044 if gs_sidecar(cidx, cid, path) == 1 {
1045 let szp: *i64 = sys_mmap(16) as *i64
1046 let png: *u8 = sys_read_file(path, szp)
1047 let n: i64 = szp[0]
1048 if (png as i64) != 0 { if n > 8 {
1049 var off: i64 = 8
1050 var guard: i64 = 0
1051 while off + 12 <= n {
1052 if guard > VIEW_MAGIC_200000 { off = n } else {
1053 guard = guard + 1
1054 let len: i64 = gs_be32(png, off)
1055 let t0: i64=png[off+4] as i64; let t1: i64=png[off+5] as i64; let t2: i64=png[off+6] as i64; let t3: i64=png[off+7] as i64
1056 let dataoff: i64 = off + 8
1057 if dataoff + len > n { off = n } else { if len < 0 { off = n } else {
1058 let dend: i64 = dataoff + len
1059 var istext: i64=0; if t0==116 { if t1==69 { if t2==88 { if t3==116 { istext=1 } } } }
1060 var isitxt: i64=0; if t0==105 { if t1==84 { if t2==88 { if t3==116 { isitxt=1 } } } }
1061 if istext == 1 {
1062 var kwe: i64 = dend; var p: i64 = dataoff
1063 while p < dend { if png[p]==(0 as u8) { if kwe==dend { kwe=p } } p=p+1 }
1064 if kwe < dend { if bo < VIEW_MAGIC_250000 {
1065 if first==0 { body[bo]=44 as u8; bo=bo+1 } first=0
1066 body[bo]=34 as u8; bo=bo+1
1067 var k: i64=dataoff; while k<kwe { bo=gs_jesc(body,bo,png[k] as i64); k=k+1 }
1068 body[bo]=34 as u8; bo=bo+1; body[bo]=58 as u8; bo=bo+1; body[bo]=34 as u8; bo=bo+1
1069 var v: i64=kwe+1; while v<dend { if bo<VIEW_MAGIC_258000 { bo=gs_jesc(body,bo,png[v] as i64) } v=v+1 }
1070 body[bo]=34 as u8; bo=bo+1
1071 } }
1072 }
1073 if isitxt == 1 {
1074 var kwe2: i64=dend; var p2: i64=dataoff
1075 while p2<dend { if png[p2]==(0 as u8) { if kwe2==dend { kwe2=p2 } } p2=p2+1 }
1076 if kwe2 + 2 < dend {
1077 let cflag: i64=png[kwe2+1] as i64
1078 var lange: i64=dend; var p3: i64=kwe2+3
1079 while p3<dend { if png[p3]==(0 as u8) { if lange==dend { lange=p3 } } p3=p3+1 }
1080 var transe: i64=dend; var p4: i64=lange+1
1081 while p4<dend { if png[p4]==(0 as u8) { if transe==dend { transe=p4 } } p4=p4+1 }
1082 let textoff: i64=transe+1
1083 if cflag==0 { if kwe2<dend { if textoff<=dend { if bo<VIEW_MAGIC_250000 {
1084 if first==0 { body[bo]=44 as u8; bo=bo+1 } first=0
1085 body[bo]=34 as u8; bo=bo+1
1086 var k2: i64=dataoff; while k2<kwe2 { bo=gs_jesc(body,bo,png[k2] as i64); k2=k2+1 }
1087 body[bo]=34 as u8; bo=bo+1; body[bo]=58 as u8; bo=bo+1; body[bo]=34 as u8; bo=bo+1
1088 var v2: i64=textoff; while v2<dend { if bo<VIEW_MAGIC_258000 { bo=gs_jesc(body,bo,png[v2] as i64) } v2=v2+1 }
1089 body[bo]=34 as u8; bo=bo+1
1090 } } } }
1091 }
1092 }
1093 let nextoff: i64 = dataoff + len + 4
1094 if nextoff <= off { off = n } else { off = nextoff }
1095 } }
1096 }
1097 }
1098 }}
1099 }
1100 }
1101 body[bo] = 125 as u8; bo = bo + 1
1102 return gs_okjson(rbuf, body, bo)
1103}
1104
1105// ---- state logs (append-only) ----
1106func gs_append_line(path: *u8, line: *u8, len: i64) -> i64 {
1107 let fd: i64 = sys_openat_append(path, 0x1a4)
1108 if fd < 0 { return 0 - 1 }
1109 sys_write(fd, line, len)
1110 sys_close(fd)
1111 return 0
1112}
1113const TELE_LOG: *u8 = "knowledge/status/galx_telemetry.log" as *u8
1114// POST /telemetry: the client beacons JS errors / perf / long-tasks here; we append the raw JSON line to a sovereign
1115// log the operator/Claude reads -> the closed loop (client issue -> server log -> autonomous fix). One line/event, capped.
1116func gs_telemetry(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1117 var bodyat: i64 = 0 - 1
1118 var i: i64 = 0
1119 while i + 4 <= rn { if req[i]==(13 as u8) { if req[i+1]==(10 as u8) { if req[i+2]==(13 as u8) { if req[i+3]==(10 as u8) { if bodyat<0 { bodyat=i+4 } } } } } i=i+1 }
1120 if bodyat >= 0 {
1121 var blen: i64 = rn - bodyat
1122 if blen > VIEW_MAGIC_1024 { blen = VIEW_MAGIC_1024 }
1123 if blen > 0 {
1124 let line: *u8 = sys_mmap(VIEW_MAGIC_1100)
1125 var lo: i64 = 0
1126 var b: i64 = 0
1127 while b < blen { let ch: i64 = req[bodyat+b] as i64; if ch != 10 { if ch != 13 { line[lo]=ch as u8; lo=lo+1 } } b=b+1 }
1128 line[lo] = 10 as u8; lo = lo + 1
1129 gs_append_line(TELE_LOG, line, lo)
1130 }
1131 }
1132 return gs_cat(rbuf, 0, "HTTP/1.1 204 No Content\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
1133}
1134func gs_same_origin(req: *u8, rn: i64) -> i64 {
1135 let h1: i64 = eh_find(req, rn, "Host: 127.0.0.1:18090" as *u8, 21)
1136 let h2: i64 = eh_find(req, rn, "Host: localhost:18090" as *u8, 21)
1137 if h1 == 0 { if h2 == 0 { return 0 } }
1138 let hasorigin: i64 = eh_find(req, rn, "Origin: " as *u8, 8)
1139 let o1: i64 = eh_find(req, rn, "Origin: http://127.0.0.1:18090" as *u8, 30)
1140 let o2: i64 = eh_find(req, rn, "Origin: http://localhost:18090" as *u8, 30)
1141 if hasorigin == 1 { if o1 == 0 { if o2 == 0 { return 0 } } }
1142 return 1
1143}
1144func gs_forbidden(rbuf: *u8) -> i64 { return gs_cat(rbuf, 0, "HTTP/1.1 403 Forbidden\r\nContent-Type: text/plain\r\nContent-Length: 9\r\nConnection: close\r\n\r\nforbidden" as *u8) }
1145func gs_okrate(rbuf: *u8) -> i64 { return gs_cat(rbuf, 0, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 2\r\nConnection: close\r\n\r\nok" as *u8) }
1146// POST /view img=<cid> -> append cid to views log
1147func gs_view(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1148 if gs_same_origin(req, rn) == 0 { return gs_forbidden(rbuf) }
1149 let cid: *u8 = sys_mmap(96)
1150 if gs_body_cid(req, rn, cid) == 0 { return gs_okrate(rbuf) }
1151 let line: *u8 = sys_mmap(80)
1152 var c: i64 = 0
1153 while c < 69 { line[c] = cid[c]; c = c + 1 }
1154 line[69] = 10 as u8
1155 gs_append_line(VIEW_LOG, line, 70)
1156 return gs_okrate(rbuf)
1157}
1158// POST /fav img=<cid>&v=<0|1> -> append "cid\tv" to fav log (LoRA-training flag set)
1159func gs_fav(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1160 if gs_same_origin(req, rn) == 0 { return gs_forbidden(rbuf) }
1161 let cid: *u8 = sys_mmap(96)
1162 if gs_body_cid(req, rn, cid) == 0 { return gs_okrate(rbuf) }
1163 var v: i64 = gs_qint(req, rn, "v=" as *u8, 1) // body param (gs_qint scans whole request first line; v= is in body but no newline before it in a single-segment POST) -- fallback handled below
1164 // robust: find v= in the body specifically
1165 var bodyat: i64 = 0 - 1
1166 var bi: i64 = 0
1167 while bi + 4 <= rn { if req[bi]==(13 as u8) { if req[bi+1]==(10 as u8) { if req[bi+2]==(13 as u8) { if req[bi+3]==(10 as u8) { if bodyat<0 { bodyat=bi+4 } } } } } bi=bi+1 }
1168 if bodyat >= 0 {
1169 var p: i64 = bodyat
1170 var vat: i64 = 0 - 1
1171 while p + 2 <= rn { if req[p]==(118 as u8) { if req[p+1]==(61 as u8) { if vat<0 { vat=p+2 } } } p=p+1 }
1172 if vat >= 0 { if req[vat]==(48 as u8) { v = 0 } else { v = 1 } }
1173 }
1174 let line: *u8 = sys_mmap(80)
1175 var c: i64 = 0
1176 while c < 69 { line[c] = cid[c]; c = c + 1 }
1177 line[69] = 9 as u8
1178 if v == 0 { line[70] = 48 as u8 } else { line[70] = 49 as u8 }
1179 line[71] = 10 as u8
1180 gs_append_line(FAV_LOG, line, 72)
1181 return gs_okrate(rbuf)
1182}
1183// POST /hide id=<lineno>&v=<0|1> -> append "<id> <v>" to galx_hidden.log. R3 reversible soft-hide: the
1184// sort-index build excludes current-hidden ids (rule 13: NEVER deletes the file, fully restorable via v=0).
1185func gs_hide(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1186 if gs_same_origin(req, rn) == 0 { return gs_forbidden(rbuf) }
1187 var bodyat: i64 = 0 - 1; var bi: i64 = 0
1188 while bi + 4 <= rn { if req[bi]==(13 as u8) { if req[bi+1]==(10 as u8) { if req[bi+2]==(13 as u8) { if req[bi+3]==(10 as u8) { if bodyat<0 { bodyat=bi+4 } } } } } bi=bi+1 }
1189 if bodyat < 0 { bodyat = 0 }
1190 let bp: *u8 = ((req as i64) + bodyat) as *u8; let bl: i64 = rn - bodyat
1191 let id: i64 = gs_qint(bp, bl, "id=" as *u8, 0 - 1)
1192 if id < 0 { return gs_okrate(rbuf) }
1193 var v: i64 = gs_qint(bp, bl, "v=" as *u8, 1); if v != 0 { v = 1 }
1194 let line: *u8 = sys_mmap(48); var o: i64 = 0
1195 o = gs_u(line, o, id); line[o] = 32 as u8; o = o + 1
1196 if v == 0 { line[o] = 48 as u8 } else { line[o] = 49 as u8 } o = o + 1
1197 line[o] = 10 as u8; o = o + 1
1198 gs_append_line(HIDDEN_LOG, line, o)
1199 return gs_okrate(rbuf)
1200}
1201// GET /api/hidden -> {"hidden":[id,...]} the linenos currently hidden (last v=1). Sorted views already exclude
1202// them server-side; the client uses this to skip them in the non-sorted (newest/oldest, &model=) views too.
1203func gs_hidden_list(rbuf: *u8) -> i64 {
1204 let bm: *u8 = sys_mmap(VIEW_MAGIC_262144); ss_load_hidden(bm)
1205 let body: *u8 = sys_mmap(VIEW_MAGIC_1048576); var bo: i64 = 0
1206 bo = gs_cat(body, bo, "{\"hidden\":[" as *u8)
1207 var first: i64 = 1; var byte: i64 = 0
1208 while byte < VIEW_MAGIC_262144 {
1209 if bm[byte] != (0 as u8) {
1210 var bit: i64 = 0
1211 while bit < 8 {
1212 if (bm[byte] as i64 & (1 << bit)) != 0 {
1213 if first == 0 { body[bo] = 44 as u8; bo = bo + 1 } first = 0
1214 bo = gs_u(body, bo, byte * 8 + bit)
1215 }
1216 bit = bit + 1
1217 }
1218 }
1219 byte = byte + 1
1220 }
1221 bo = gs_cat(body, bo, "]}" as *u8)
1222 return gs_okjson(rbuf, body, bo)
1223}
1224// GET /api/durs?ids=1,2,3 -> {"<id>":dur_ms,...} runtime badges for a grid page in ONE request (O(1) per id
1225// from galx_dur.bin). Omits unknown/zero/stale ids. Composes db_batch_durs (gated in nx_galx_durbin_lib).
1226func gs_durs_batch(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1227 let ids: *u8 = sys_mmap(VIEW_MAGIC_8192); var o: i64 = 0
1228 var p: i64 = 0 - 1; var i: i64 = 0
1229 while i + 4 <= rn {
1230 if req[i]==(105 as u8) { if req[i+1]==(100 as u8) { if req[i+2]==(115 as u8) { if req[i+3]==(61 as u8) { p = i + 4; i = rn } } } }
1231 i = i + 1
1232 }
1233 if p >= 0 {
1234 var j: i64 = p
1235 while j < rn { let c: i64 = req[j] as i64
1236 if c == 32 { j = rn } else { if c == 38 { j = rn } else { if c == 13 { j = rn } else { if c == 10 { j = rn } else { ids[o]=req[j]; o=o+1; j=j+1 } } } } }
1237 }
1238 ids[o] = 0 as u8
1239 let body: *u8 = sys_mmap(VIEW_MAGIC_1048576)
1240 let bo: i64 = db_batch_durs(body, ids, "knowledge/status/galx_dur.bin" as *u8, gs_vidpaths_size())
1241 return gs_okjson(rbuf, body, bo)
1242}
1243// extract + sanitise a "tag=" value from buf[0..bl): keep alnum/dash, '+' -> space, drop the rest; max 32.
1244// (keeps tabs/newlines/quotes OUT of the log + JSON so the store can't be corrupted or injected.)
1245func gs_extract_tag(bp: *u8, bl: i64, out: *u8) -> i64 {
1246 var p: i64 = 0 - 1; var i: i64 = 0
1247 while i + 4 <= bl { if bp[i]==(116 as u8) { if bp[i+1]==(97 as u8) { if bp[i+2]==(103 as u8) { if bp[i+3]==(61 as u8) { p=i+4; i=bl } } } } i=i+1 }
1248 if p < 0 { return 0 }
1249 var o: i64 = 0; var j: i64 = p
1250 while j < bl {
1251 let c: i64 = bp[j] as i64
1252 var stop: i64 = 0
1253 if c == 38 { stop = 1 } if c == 32 { stop = 1 } if c == 13 { stop = 1 } if c == 10 { stop = 1 }
1254 if stop == 1 { j = bl } else {
1255 var ch: i64 = c; var keep: i64 = 0
1256 if c == 43 { ch = 32; keep = 1 }
1257 if c >= 48 { if c <= 57 { keep = 1 } }
1258 if c >= 65 { if c <= 90 { keep = 1 } }
1259 if c >= 97 { if c <= 122 { keep = 1 } }
1260 if c == 45 { keep = 1 }
1261 if keep == 1 { if o < 32 { out[o] = ch as u8; o = o + 1 } }
1262 j = j + 1
1263 }
1264 }
1265 return o
1266}
1267// extract the "id=" value from buf[0..bl) into out (up to &/space/CR/LF; tab stripped; max 80). Works for an
1268// int video lineno OR a 69-char image cid -- the unified string id for the string-keyed tag store. returns len.
1269func gs_extract_id(bp: *u8, bl: i64, out: *u8) -> i64 {
1270 var p: i64 = 0 - 1; var i: i64 = 0
1271 while i + 3 <= bl { if bp[i]==(105 as u8) { if bp[i+1]==(100 as u8) { if bp[i+2]==(61 as u8) { p=i+3; i=bl } } } i=i+1 }
1272 if p < 0 { return 0 }
1273 var o: i64 = 0; var j: i64 = p
1274 while j < bl {
1275 let c: i64 = bp[j] as i64
1276 var stop: i64 = 0
1277 if c == 38 { stop = 1 } if c == 32 { stop = 1 } if c == 13 { stop = 1 } if c == 10 { stop = 1 }
1278 if stop == 1 { j = bl } else {
1279 if c != 9 { if o < 80 { out[o] = bp[j] as u8; o = o + 1 } }
1280 j = j + 1
1281 }
1282 }
1283 return o
1284}
1285// POST /tag id=<videoLineno|imageCid>&tag=<name>&v=<0|1> -> append "<id>\t<tag>\t<v>" (string-keyed; rule-13).
1286func gs_tag(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1287 if gs_same_origin(req, rn) == 0 { return gs_forbidden(rbuf) }
1288 var bodyat: i64 = 0 - 1; var bi: i64 = 0
1289 while bi + 4 <= rn { if req[bi]==(13 as u8) { if req[bi+1]==(10 as u8) { if req[bi+2]==(13 as u8) { if req[bi+3]==(10 as u8) { if bodyat<0 { bodyat=bi+4 } } } } } bi=bi+1 }
1290 if bodyat < 0 { bodyat = 0 }
1291 let bp: *u8 = ((req as i64) + bodyat) as *u8; let bl: i64 = rn - bodyat
1292 let idp: *u8 = sys_mmap(96); let idl: i64 = gs_extract_id(bp, bl, idp)
1293 if idl <= 0 { return gs_okrate(rbuf) }
1294 var v: i64 = gs_qint(bp, bl, "v=" as *u8, 1); if v != 0 { v = 1 }
1295 let tag: *u8 = sys_mmap(64); let tl: i64 = gs_extract_tag(bp, bl, tag)
1296 if tl <= 0 { return gs_okrate(rbuf) }
1297 let line: *u8 = sys_mmap(256); let o: i64 = tg_op_line_s(line, idp, idl, tag, tl, v)
1298 gs_append_line(TAGS_LOG, line, o)
1299 return gs_okrate(rbuf)
1300}
1301// GET /api/tags?id=<lineno> -> ["tag",...] the video's current tags.
1302func gs_tags_get(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1303 let idp: *u8 = sys_mmap(96); let idl: i64 = gs_extract_id(req, rn, idp)
1304 let body: *u8 = sys_mmap(VIEW_MAGIC_8192); var bo: i64 = 0
1305 if idl <= 0 { bo = gs_cat(body, 0, "[]" as *u8) } else {
1306 let szp: *i64 = sys_mmap(16) as *i64; let log: *u8 = sys_read_file(TAGS_LOG, szp)
1307 if (log as i64) == 0 { bo = gs_cat(body, 0, "[]" as *u8) } else { bo = tg_tags_for_id_s(log, szp[0], idp, idl, body) }
1308 }
1309 return gs_okjson(rbuf, body, bo)
1310}
1311// GET /api/tagged?tag=<name> -> [id,...] videos currently carrying the tag (the tag FILTER).
1312func gs_tagged_get(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1313 let tag: *u8 = sys_mmap(64); let tl: i64 = gs_extract_tag(req, rn, tag)
1314 let body: *u8 = sys_mmap(VIEW_MAGIC_1048576); var bo: i64 = 0
1315 if tl <= 0 { bo = gs_cat(body, 0, "[]" as *u8) } else {
1316 let szp: *i64 = sys_mmap(16) as *i64; let log: *u8 = sys_read_file(TAGS_LOG, szp)
1317 if (log as i64) == 0 { bo = gs_cat(body, 0, "[]" as *u8) } else { bo = tg_ids_for_tag_s(log, szp[0], tag, tl, body) }
1318 }
1319 return gs_okjson(rbuf, body, bo)
1320}
1321// GET /api/alltags -> ["tag",...] all distinct tag names ever used (the picker / tag-cloud).
1322func gs_alltags_get(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1323 let body: *u8 = sys_mmap(VIEW_MAGIC_65536); var bo: i64 = 0
1324 let szp: *i64 = sys_mmap(16) as *i64; let log: *u8 = sys_read_file(TAGS_LOG, szp)
1325 if (log as i64) == 0 { bo = gs_cat(body, 0, "[]" as *u8) } else { bo = tg_all_tags_s(log, szp[0], body) }
1326 return gs_okjson(rbuf, body, bo)
1327}
1328// scan a cid<TAB>v log for the LAST v of cid; returns -1 if absent.
1329func gs_last_v(path: *u8, cid: *u8) -> i64 {
1330 let szp: *i64 = sys_mmap(16) as *i64
1331 let b: *u8 = sys_read_file(path, szp)
1332 let sz: i64 = szp[0]
1333 if (b as i64) == 0 { return 0 - 1 }
1334 var i: i64 = 0; var ls: i64 = 0; var last: i64 = 0 - 1
1335 while i <= sz {
1336 var nl: i64 = 0
1337 if i == sz { nl = 1 } else { if b[i]==(10 as u8) { nl = 1 } }
1338 if nl == 1 {
1339 if i - ls >= 69 { var eq: i64=1; var k: i64=0; while k<69 { if b[ls+k]!=cid[k]{eq=0} k=k+1 }
1340 if eq == 1 { if b[ls+70]==(48 as u8) { last = 0 } else { last = 1 } } }
1341 ls = i + 1
1342 }
1343 i = i + 1
1344 }
1345 return last
1346}
1347// is cid present anywhere as a line-start in a plain-cid log?
1348func gs_present(path: *u8, cid: *u8) -> i64 {
1349 let szp: *i64 = sys_mmap(16) as *i64
1350 let b: *u8 = sys_read_file(path, szp)
1351 let sz: i64 = szp[0]
1352 if (b as i64) == 0 { return 0 }
1353 var i: i64 = 0; var ls: i64 = 0
1354 while i <= sz {
1355 var nl: i64 = 0
1356 if i == sz { nl = 1 } else { if b[i]==(10 as u8) { nl = 1 } }
1357 if nl == 1 { if i-ls >= 69 { var eq: i64=1; var k: i64=0; while k<69 { if b[ls+k]!=cid[k]{eq=0} k=k+1 } if eq==1 { return 1 } } ls=i+1 }
1358 i = i + 1
1359 }
1360 return 0
1361}
1362// last rating score for cid from eval log (EVAL img=<cid> lane=O score=<N>); -1 if none.
1363func gs_last_score(cid: *u8) -> i64 {
1364 let szp: *i64 = sys_mmap(16) as *i64
1365 let b: *u8 = sys_read_file(EVAL_LOG, szp)
1366 let sz: i64 = szp[0]
1367 if (b as i64) == 0 { return 0 - 1 }
1368 var i: i64 = 0; var last: i64 = 0 - 1
1369 while i + 4 < sz {
1370 if b[i]==(105 as u8) { if b[i+1]==(109 as u8) { if b[i+2]==(103 as u8) { if b[i+3]==(61 as u8) {
1371 let cat: i64 = i + 4
1372 var eq: i64 = 1; var k: i64 = 0
1373 while k < 69 { if cat+k >= sz { eq=0; k=69 } else { if b[cat+k]!=cid[k] { eq=0; k=69 } else { k=k+1 } } }
1374 if eq == 1 {
1375 var sp: i64 = cat + 69
1376 var sat: i64 = 0 - 1
1377 while sp + 6 <= sz { if b[sp]==(115 as u8) { if b[sp+1]==(99 as u8) { if b[sp+2]==(111 as u8) { if b[sp+3]==(114 as u8) { if b[sp+4]==(101 as u8) { if b[sp+5]==(61 as u8) { sat=sp+6; sp=sz } } } } } } if b[sp]==(10 as u8) { sp=sz } else { sp=sp+1 } }
1378 if sat >= 0 { var v: i64=0; var q: i64=sat; while q<sz { if b[q]>=(48 as u8) { if b[q]<=(57 as u8) { v=v*10+((b[q] as i64)-48); q=q+1 } else { q=sz } } else { q=sz } } last=v }
1379 }
1380 } } } }
1381 i = i + 1
1382 }
1383 return last
1384}
1385func gs_state(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1386 let cid: *u8 = sys_mmap(96)
1387 if gs_peel_pat(req, rn, "GET /state/" as *u8, 11, cid) == 0 { return gs_404(rbuf) }
1388 let fav: i64 = gs_last_v(FAV_LOG, cid)
1389 let viewed: i64 = gs_present(VIEW_LOG, cid)
1390 let score: i64 = gs_last_score(cid)
1391 let body: *u8 = sys_mmap(128)
1392 var bo: i64 = 0
1393 bo = gs_cat(body, bo, "{\"fav\":" as *u8); if fav == 1 { bo = gs_cat(body, bo, "1" as *u8) } else { bo = gs_cat(body, bo, "0" as *u8) }
1394 bo = gs_cat(body, bo, ",\"viewed\":" as *u8); bo = gs_u(body, bo, viewed)
1395 bo = gs_cat(body, bo, ",\"rating\":" as *u8); if score < 0 { bo = gs_cat(body, bo, "-1" as *u8) } else { bo = gs_u(body, bo, score) }
1396 bo = gs_cat(body, bo, "}" as *u8)
1397 return gs_okjson(rbuf, body, bo)
1398}
1399
1400// ===== BM25 RANKED q= SEARCH over the durable gallery index (replaces the 465MB/query substring scan) =====
1401// Loaded ONCE in the parent before the accept loop; every request-child inherits it via fork copy-on-write,
1402// so per-request cost is just an index shortlist + BM25 over the matched candidates -- no re-read, no 465MB scan.
1403struct NxGalIdx {
1404 idx: *NxInvIndex
1405 up: *i64 // per-doc url pointer (cid = url+5, the 69 bytes after "/img/")
1406 xp: *i64 // per-doc text pointer (the searchable prompt)
1407 xl: *i64 // per-doc text length
1408 ndocs: i64
1409 valid: i64
1410}
1411
1412// count tokens (len>=2) in text[0..n) -- the doc length BM25 normalizes by
1413func gs_bm_doclen(text: *u8, n: i64) -> i64 {
1414 var cnt: i64 = 0; var i: i64 = 0
1415 while i < n {
1416 if nx_inv_is_token_char(text[i] as i64) == 0 { i = i + 1 } else {
1417 let s: i64 = i; var go: i64 = 1
1418 while go == 1 { if i >= n { go = 0 } else { if nx_inv_is_token_char(text[i] as i64) == 1 { i = i + 1 } else { go = 0 } } }
1419 if i - s >= 2 { cnt = cnt + 1 }
1420 }
1421 }
1422 return cnt
1423}
1424// term-frequency of token-hash `th` in text (FNV-lowercased tokenization -- matches the index, case-insensitive)
1425func gs_bm_tf(text: *u8, n: i64, th: i64) -> i64 {
1426 var cnt: i64 = 0; var i: i64 = 0
1427 while i < n {
1428 if nx_inv_is_token_char(text[i] as i64) == 0 { i = i + 1 } else {
1429 let s: i64 = i; var go: i64 = 1
1430 while go == 1 { if i >= n { go = 0 } else { if nx_inv_is_token_char(text[i] as i64) == 1 { i = i + 1 } else { go = 0 } } }
1431 let len: i64 = i - s
1432 if len >= 2 { if nx_inv_hash_bytes_lower(((text as i64) + s) as *u8, len) == th { cnt = cnt + 1 } }
1433 }
1434 }
1435 return cnt
1436}
1437// load idx + parse the manifest (url<TAB>title<TAB>text) into per-doc slice arrays. 1=ok (gal.valid=1), 0=fall back to substring.
1438func gs_galidx_load(gal: *NxGalIdx, idx_path: *u8, manifest_path: *u8) -> i64 {
1439 gal.valid = 0
1440 let idx: *NxInvIndex = nx_inv_load(idx_path)
1441 if idx == 0 as *NxInvIndex { return 0 }
1442 let mbox: *i64 = sys_mmap(16) as *i64
1443 let mbuf: *u8 = sys_read_file(manifest_path, mbox)
1444 if mbuf == 0 as *u8 { return 0 }
1445 let mn: i64 = mbox[0]
1446 var nl: i64 = 0; var i: i64 = 0
1447 while i < mn { if mbuf[i] == (10 as u8) { nl = nl + 1 } i = i + 1 }
1448 if nl <= 0 { return 0 }
1449 let up: *i64 = sys_mmap(8 * (nl + 8)) as *i64
1450 let xp: *i64 = sys_mmap(8 * (nl + 8)) as *i64
1451 let xl: *i64 = sys_mmap(8 * (nl + 8)) as *i64
1452 var d: i64 = 0; var ls: i64 = 0; i = 0
1453 while i < mn {
1454 if mbuf[i] == (10 as u8) {
1455 let le: i64 = i
1456 var t1: i64 = 0 - 1; var t2: i64 = 0 - 1; var k: i64 = ls
1457 while k < le { if mbuf[k] == (9 as u8) { if t1 < 0 { t1 = k } else { if t2 < 0 { t2 = k } } } k = k + 1 }
1458 up[d] = (mbuf as i64) + ls
1459 if t2 > t1 { if t1 >= ls { xp[d] = (mbuf as i64) + t2 + 1; xl[d] = le - t2 - 1 } else { xp[d] = (mbuf as i64) + ls; xl[d] = 0 } }
1460 if t2 <= t1 { xp[d] = (mbuf as i64) + ls; xl[d] = 0 }
1461 d = d + 1; ls = i + 1
1462 }
1463 i = i + 1
1464 }
1465 if idx.n_rows != d { return 0 } // stale idx/manifest pair -> substring fallback
1466 gal.idx = idx; gal.up = up; gal.xp = xp; gal.xl = xl; gal.ndocs = d; gal.valid = 1
1467 return 1
1468}
1469// BM25-ranked q= search -> {"items":[cid...]} for page [o0, o0+ncount). Multi-word: union shortlist, corpus-IDF.
1470func gs_bm25_emit(rbuf: *u8, gal: *NxGalIdx, qbuf: *u8, qlen: i64, o0: i64, ncount: i64) -> i64 {
1471 let idx: *NxInvIndex = gal.idx
1472 let ndocs: i64 = gal.ndocs
1473 let body: *u8 = sys_mmap(VIEW_MAGIC_262144)
1474 var bo: i64 = gs_cat(body, 0, "{\"items\":[" as *u8)
1475 let seen: *u8 = sys_mmap(ndocs + 8)
1476 let res: *NxInvQueryResult = sys_mmap(64) as *NxInvQueryResult
1477 let rowids: *i64 = sys_mmap(8 * VIEW_MAGIC_262144) as *i64 // was VIEW_MAGIC_16384 -> a common term in a 200k library overflowed it and truncated matches (a "not full results" cause)
1478 let qh: *i64 = sys_mmap(8 * 16) as *i64 // term hashes
1479 let qdf: *i64 = sys_mmap(8 * 16) as *i64 // corpus document-frequency per term
1480 var nq: i64 = 0; var i: i64 = 0
1481 while i < qlen {
1482 if nx_inv_is_token_char(qbuf[i] as i64) == 0 { i = i + 1 } else {
1483 let s: i64 = i; var go: i64 = 1
1484 while go == 1 { if i >= qlen { go = 0 } else { if nx_inv_is_token_char(qbuf[i] as i64) == 1 { i = i + 1 } else { go = 0 } } }
1485 let tl: i64 = i - s
1486 if tl >= 2 { if nq < 16 {
1487 nx_inv_query_term(idx, ((qbuf as i64) + s) as *u8, tl, rowids, VIEW_MAGIC_262144, res)
1488 if res.verdict == NX_INV_OK {
1489 qh[nq] = nx_inv_hash_bytes_lower(((qbuf as i64) + s) as *u8, tl)
1490 qdf[nq] = res.postings_count
1491 nq = nq + 1
1492 var r: i64 = 0
1493 while r < res.n_rowids_filled { let rid: i64 = rowids[r]; if rid >= 0 { if rid < ndocs { seen[rid] = 1 as u8 } } r = r + 1 }
1494 }
1495 } }
1496 }
1497 }
1498 let CAP: i64 = VIEW_MAGIC_60000
1499 let cand: *i64 = sys_mmap(8 * (CAP + 8)) as *i64
1500 let cdl: *i64 = sys_mmap(8 * (CAP + 8)) as *i64
1501 var ncand: i64 = 0; var total_dl: i64 = 0; var d: i64 = 0
1502 while d < ndocs {
1503 if seen[d] == (1 as u8) { if ncand < CAP {
1504 cand[ncand] = d; let dl: i64 = gs_bm_doclen(gal.xp[d] as *u8, gal.xl[d]); cdl[ncand] = dl; total_dl = total_dl + dl; ncand = ncand + 1
1505 } }
1506 d = d + 1
1507 }
1508 if ncand == 0 { bo = gs_cat(body, bo, "]}" as *u8); return gs_okjson(rbuf, body, bo) }
1509 var avgdl: i64 = total_dl / ncand; if avgdl <= 0 { avgdl = 1 }
1510 let score: *i64 = sys_mmap(8 * (ncand + 8)) as *i64
1511 var c: i64 = 0
1512 while c < ncand {
1513 let dd: i64 = cand[c]; var sc: i64 = 0; var t: i64 = 0
1514 while t < nq {
1515 let tf: i64 = gs_bm_tf(gal.xp[dd] as *u8, gal.xl[dd], qh[t])
1516 if tf > 0 { let idf: i64 = bm_idf_micro(ndocs, qdf[t]); let sat: i64 = bm_sat_milli(tf, cdl[c], avgdl); sc = sc + (idf * sat) / 1000 }
1517 t = t + 1
1518 }
1519 score[c] = sc; c = c + 1
1520 }
1521 // partial selection sort by descending score. Sort a DEDUP MARGIN beyond the page (ncount*2+64) so
1522 // that after dropping duplicate-cid docs the page still fills with UNIQUE results -- the root of the
1523 // "search returns repeat results AND not full results" bug (the index can hold >1 doc per cid).
1524 let want: i64 = o0 + ncount * 2 + 64
1525 var a: i64 = 0
1526 while a < ncand {
1527 if a >= want { a = ncand } else {
1528 var best: i64 = a; var b: i64 = a + 1
1529 while b < ncand { if score[b] > score[best] { best = b } b = b + 1 }
1530 if best != a { let ts: i64 = score[a]; score[a] = score[best]; score[best] = ts; let tc: i64 = cand[a]; cand[a] = cand[best]; cand[best] = tc }
1531 a = a + 1
1532 }
1533 }
1534 // emit page [o0, o0+ncount) of UNIQUE cids: walk score-sorted cands, dedup by 69-byte cid, emit window.
1535 let uptr: *i64 = sys_mmap(8 * (o0 + ncount + 16)) as *i64 // cid pointers of uniques seen so far
1536 var uniq: i64 = 0; var first: i64 = 1; var e: i64 = 0
1537 while e < want {
1538 if uniq >= o0 + ncount { e = want } else { if e >= ncand { e = want } else {
1539 let cptr: *u8 = (gal.up[cand[e]] + 5) as *u8
1540 var dup: i64 = 0; var u: i64 = 0
1541 while u < uniq { if gs_cideq2(cptr, 0, (uptr[u]) as *u8, 0) == 1 { dup = 1; u = uniq } else { u = u + 1 } }
1542 if dup == 0 {
1543 if uniq >= o0 { bo = gs_emit_cid(body, bo, first, cptr, 0); first = 0 }
1544 uptr[uniq] = cptr as i64; uniq = uniq + 1
1545 }
1546 e = e + 1
1547 } }
1548 }
1549 bo = gs_cat(body, bo, "]}" as *u8)
1550 return gs_okjson(rbuf, body, bo)
1551}
1552
1553// ---- /api/list ----
1554func gs_emit_cid(body: *u8, o0: i64, first: i64, buf: *u8, pos: i64) -> i64 {
1555 var o: i64 = o0
1556 if first == 0 { body[o]=44 as u8; o=o+1 }
1557 body[o]=34 as u8; o=o+1
1558 var c: i64 = 0
1559 while c < 69 { body[o]=buf[pos+c]; o=o+1; c=c+1 }
1560 body[o]=34 as u8; o=o+1
1561 return o
1562}
1563// compare 69-byte cids at two buffer offsets
1564func gs_cideq2(a: *u8, ao: i64, b: *u8, bo: i64) -> i64 { var k: i64=0; while k<69 { if a[ao+k]!=b[bo+k] { return 0 } k=k+1 } return 1 }
1565// FILTER list from a state log. kind: 0=plain cid lines(views) ; 1=cid TAB v (fav, keep v==1) ; 2=EVAL img=cid (rated).
1566// Emits matching cids most-recent-first, de-duped, paginated [o,o+n).
1567func gs_filter_list(rbuf: *u8, logpath: *u8, kind: i64, o0: i64, n: i64) -> i64 {
1568 let szp: *i64 = sys_mmap(16) as *i64
1569 let b: *u8 = sys_read_file(logpath, szp)
1570 let sz: i64 = szp[0]
1571 let body: *u8 = sys_mmap(VIEW_MAGIC_131072)
1572 var bo: i64 = 0
1573 bo = gs_cat(body, bo, "{\"items\":[" as *u8)
1574 if (b as i64) != 0 {
1575 let CAP: i64 = VIEW_MAGIC_100000
1576 let coff: *i64 = sys_mmap(8 * CAP) as *i64 // offset of each occurrence's cid
1577 let cv: *i64 = sys_mmap(8 * CAP) as *i64 // v (kind1) else 1
1578 var m: i64 = 0
1579 var i: i64 = 0; var ls: i64 = 0
1580 while i <= sz {
1581 var nl: i64 = 0
1582 if i == sz { nl = 1 } else { if b[i]==(10 as u8) { nl = 1 } }
1583 if nl == 1 {
1584 let llen: i64 = i - ls
1585 if kind == 2 {
1586 // find img= in line
1587 var p: i64 = ls
1588 var cat: i64 = 0 - 1
1589 while p + 4 <= i { if b[p]==(105 as u8) { if b[p+1]==(109 as u8) { if b[p+2]==(103 as u8) { if b[p+3]==(61 as u8) { cat=p+4; p=i } } } } p=p+1 }
1590 if cat >= 0 { if cat + 69 <= i { if m < CAP { coff[m]=cat; cv[m]=1; m=m+1 } } }
1591 } else {
1592 if llen >= 69 { if m < CAP { coff[m]=ls; if kind==1 { if b[ls+70]==(48 as u8) { cv[m]=0 } else { cv[m]=1 } } else { cv[m]=1 } m=m+1 } }
1593 }
1594 ls = i + 1
1595 }
1596 i = i + 1
1597 }
1598 // walk backward (recent first), dedup, collect results (offsets) into res[]
1599 let res: *i64 = sys_mmap(8 * CAP) as *i64
1600 var rn2: i64 = 0
1601 var x: i64 = m - 1
1602 while x >= 0 {
1603 let off: i64 = coff[x]
1604 var seen: i64 = 0
1605 var y: i64 = 0
1606 while y < rn2 { if gs_cideq2(b, res[y], b, off) == 1 { seen = 1; y = rn2 } else { y = y + 1 } }
1607 // also must dedup against earlier-excluded (v==0) cids; track those too
1608 if seen == 0 {
1609 // first (most recent) occurrence of this cid: decide include by its v
1610 if cv[x] == 1 { res[rn2] = off; rn2 = rn2 + 1 }
1611 else { res[rn2] = off; rn2 = rn2 + 1 } // record to mark seen; but excluded from emit below via a parallel flag
1612 }
1613 x = x - 1
1614 }
1615 // res[] now holds first-seen (recent-first) cids INCLUDING v==0; re-walk to emit only those whose first-seen v==1.
1616 // Simpler correct pass: recompute include set honoring most-recent v.
1617 // (res already recent-first & deduped.) Determine each res cid's most-recent v by scanning coff/cv recent-first.
1618 var emitted: i64 = 0
1619 var first: i64 = 1
1620 var skipped: i64 = 0
1621 var r: i64 = 0
1622 while r < rn2 {
1623 let off: i64 = res[r]
1624 // most-recent v for this cid:
1625 var vv: i64 = 1
1626 var z: i64 = m - 1
1627 var found: i64 = 0
1628 while z >= 0 { if found == 0 { if gs_cideq2(b, coff[z], b, off) == 1 { vv = cv[z]; found = 1; z = 0 - 1 } else { z = z - 1 } } else { z = 0 - 1 } }
1629 if vv == 1 {
1630 if skipped >= o0 { if emitted < n { bo = gs_emit_cid(body, bo, first, b, off); first = 0; emitted = emitted + 1 } }
1631 skipped = skipped + 1
1632 }
1633 r = r + 1
1634 }
1635 }
1636 bo = gs_cat(body, bo, "]}" as *u8)
1637 return gs_okjson(rbuf, body, bo)
1638}
1639// GET /api/suggest?q=<prefix> -> {"suggestions":["term",...]} (ADDITIVE; existing search untouched). As-you-type
1640// autocomplete over the sorted gallery vocab strings (knowledge/index/gallery.vocab, built by nx_vocab_extract --
1641// the hash-index has token HASHES not strings, so this string vocab is the missing piece). Binary-search lower
1642// bound = O(log V + k). Per-request load of the 1.6MB sorted vocab (load-once-in-parent is the noted optimization).
1643func gs_api_suggest(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1644 var li: i64 = 0; var qpos: i64 = 0 - 1; var stop: i64 = rn
1645 while li < stop { if req[li]==(10 as u8) { stop=li } else { if qpos<0 { if li+2<=rn { if req[li]==(113 as u8) { if req[li+1]==(61 as u8) { qpos=li+2 } } } } li=li+1 } }
1646 let qbuf: *u8 = sys_mmap(64)
1647 var qlen: i64 = 0
1648 if qpos >= 0 { var p: i64=qpos; var go: i64=1; while go==1 { if p>=rn { go=0 } else { let ch: i64=req[p] as i64; if ch==38 { go=0 } else { if ch==32 { go=0 } else { if ch==10 { go=0 } else { if ch==13 { go=0 } else { if qlen<48 { qbuf[qlen]=gs_lower(ch) as u8; qlen=qlen+1 } p=p+1 } } } } } } }
1649 qbuf[qlen] = 0 as u8
1650 let body: *u8 = sys_mmap(VIEW_MAGIC_8192)
1651 var bo: i64 = gs_cat(body, 0, "{\"suggestions\":[" as *u8)
1652 if qlen >= 1 {
1653 let vbox: *i64 = sys_mmap(16) as *i64
1654 let vbuf: *u8 = sys_read_file("knowledge/index/gallery.vocab" as *u8, vbox)
1655 if (vbuf as i64) != 0 {
1656 let vn: i64 = vbox[0]
1657 let ptrs: *i64 = sys_mmap(8 * VIEW_MAGIC_200008) as *i64
1658 var nl: i64 = 0; var ls: i64 = 0; var i: i64 = 0
1659 while i < vn { if vbuf[i]==(10 as u8) { vbuf[i]=0 as u8; if i>ls { if nl<VIEW_MAGIC_200000 { ptrs[nl]=(vbuf as i64)+ls; nl=nl+1 } } ls=i+1 } i=i+1 }
1660 let out: *i64 = sys_mmap(8 * 64) as *i64
1661 let m: i64 = vr_prefix_collect(ptrs, nl, qbuf, qlen, out)
1662 var k: i64 = 0; var first: i64 = 1
1663 while k < m { if k < 10 {
1664 if first==0 { body[bo]=44 as u8; bo=bo+1 }
1665 body[bo]=34 as u8; bo=bo+1
1666 let t: *u8 = ptrs[out[k]] as *u8
1667 var c: i64 = 0; while t[c]!=(0 as u8) { body[bo]=t[c]; bo=bo+1; c=c+1 }
1668 body[bo]=34 as u8; bo=bo+1
1669 first=0
1670 } k=k+1 }
1671 }
1672 }
1673 bo = gs_cat(body, bo, "]}" as *u8)
1674 return gs_okjson(rbuf, body, bo)
1675}
1676
1677// GET /api/list?filter=gens -> ONLY LLM-generated images (this gallery's historical default view).
1678// Reads the gens cid index galx_view_index.txt (70-byte records: 69-byte cid + newline), newest-first.
1679func gs_gens_list(rbuf: *u8, req: *u8, rn: i64, isold: i64, o0: i64, n: i64) -> i64 {
1680 let fd: i64 = sys_openat_rd(VIEW_IDX)
1681 if fd < 0 { return gs_cat(rbuf, 0, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: 22\r\n\r\n{\"total\":0,\"items\":[]}" as *u8) }
1682 let endpos: i64 = sys_lseek(fd, 0, 2)
1683 let total: i64 = endpos / 70
1684 let eo0: i64 = gs_eff_offset(req, rn, total, o0)
1685 let body: *u8 = sys_mmap(VIEW_MAGIC_131072)
1686 var bo: i64 = 0
1687 bo = gs_cat(body, bo, "{\"total\":" as *u8); bo = gs_u(body, bo, total); bo = gs_cat(body, bo, ",\"items\":[" as *u8)
1688 let line: *u8 = sys_mmap(80)
1689 var k: i64 = 0; var first: i64 = 1
1690 while k < n {
1691 let disp: i64 = eo0 + k
1692 if disp >= total { k = n } else {
1693 var fl: i64 = disp
1694 if isold == 1 { fl = total - 1 - disp }
1695 sys_lseek(fd, fl * 70, 0)
1696 let got: i64 = sys_read(fd, line, 69)
1697 if got == 69 { bo = gs_emit_cid(body, bo, first, line, 0); first = 0 }
1698 k = k + 1
1699 }
1700 }
1701 sys_close(fd)
1702 bo = gs_cat(body, bo, "]}" as *u8)
1703 return gs_okjson(rbuf, body, bo)
1704}
1705// GET /api/list (default / filter=all) -> ALL media: every video id (galx_vid_paths.tsv) + every gen cid
1706// (galx_view_index.txt), newest-first, paginated [o,o+n). Video line-ids use gs_collection_list semantics
1707// (a real line is len>3) so /vid/ and /vidthumb/ resolve identically; the frontend addCell renders mixed ids.
1708func gs_allmedia_list(rbuf: *u8, req: *u8, rn: i64, isold: i64, o0: i64, n: i64) -> i64 {
1709 let gfd: i64 = sys_openat_rd(VIEW_IDX)
1710 var gtotal: i64 = 0
1711 if gfd >= 0 { let gep: i64 = sys_lseek(gfd, 0, 2); gtotal = gep / 70 }
1712 let szp: *i64 = sys_mmap(16) as *i64
1713 let vb: *u8 = sys_read_file("knowledge/status/galx_vid_paths.tsv" as *u8, szp)
1714 let vsz: i64 = szp[0]
1715 let vids: *i64 = sys_mmap(8 * VIEW_MAGIC_1000000) as *i64
1716 var nvid: i64 = 0
1717 if (vb as i64) != 0 {
1718 var i: i64 = 0; var ls: i64 = 0; var lineno: i64 = 0
1719 while i <= vsz {
1720 var nl: i64 = 0
1721 if i == vsz { nl = 1 } else { if vb[i] == (10 as u8) { nl = 1 } }
1722 if nl == 1 {
1723 if i - ls > 3 { if nvid < VIEW_MAGIC_1000000 { vids[nvid] = lineno; nvid = nvid + 1 } }
1724 lineno = lineno + 1; ls = i + 1
1725 }
1726 i = i + 1
1727 }
1728 }
1729 let total: i64 = gtotal + nvid
1730 let eo0: i64 = gs_eff_offset(req, rn, total, o0)
1731 let body: *u8 = sys_mmap(VIEW_MAGIC_131072)
1732 var bo: i64 = 0
1733 bo = gs_cat(body, bo, "{\"total\":" as *u8); bo = gs_u(body, bo, total); bo = gs_cat(body, bo, ",\"items\":[" as *u8)
1734 let line: *u8 = sys_mmap(80)
1735 var k: i64 = 0; var first: i64 = 1
1736 while k < n {
1737 let disp: i64 = eo0 + k
1738 if disp >= total { k = n } else {
1739 var sp: i64 = disp
1740 if isold == 1 { sp = total - 1 - disp }
1741 if sp < nvid {
1742 let vidid: i64 = vids[nvid - 1 - sp]
1743 if first == 0 { body[bo] = 44 as u8; bo = bo + 1 }
1744 first = 0
1745 body[bo] = 34 as u8; bo = bo + 1
1746 bo = gs_u(body, bo, vidid)
1747 body[bo] = 34 as u8; bo = bo + 1
1748 } else {
1749 let gi: i64 = sp - nvid
1750 if gfd >= 0 {
1751 sys_lseek(gfd, gi * 70, 0)
1752 let got: i64 = sys_read(gfd, line, 69)
1753 if got == 69 { bo = gs_emit_cid(body, bo, first, line, 0); first = 0 }
1754 }
1755 }
1756 k = k + 1
1757 }
1758 }
1759 if gfd >= 0 { sys_close(gfd) }
1760 bo = gs_cat(body, bo, "]}" as *u8)
1761 return gs_okjson(rbuf, body, bo)
1762}
1763func gs_api_list(rbuf: *u8, req: *u8, rn: i64, gal: *NxGalIdx) -> i64 {
1764 let o0: i64 = gs_qint(req, rn, "o=" as *u8, 0)
1765 var n: i64 = gs_qint(req, rn, "n=" as *u8, 100)
1766 if n > 400 { n = 400 }
1767 if n < 1 { n = 1 }
1768 let isold: i64 = eh_find(req, rn, "s=old" as *u8, 5)
1769 // R2 sort-by-size for the video collections (lazily self-builds galx_sort_s_<c>.bin; composes pct=/rand=).
1770 // dir defaults to desc (largest first); &dir=asc flips it. Image/fav/rated/viewed paths ignore sort= (no-op).
1771 // R2 sort -> the sovereignly-gated handlers in nx_galx_sortindex.nx (ss_emit_*); gate = nx_galx_sortserve_gate.
1772 if eh_find(req, rn, "sort=size" as *u8, 9) == 1 {
1773 var sdir: i64 = 1; if eh_find(req, rn, "dir=asc" as *u8, 7) == 1 { sdir = 0 }
1774 if eh_find(req, rn, "filter=recordings" as *u8, 17) == 1 { return ss_emit_size(rbuf, req, rn, 114, sdir, o0, n) }
1775 if eh_find(req, rn, "filter=media" as *u8, 12) == 1 { return ss_emit_size(rbuf, req, rn, 109, sdir, o0, n) }
1776 if eh_find(req, rn, "filter=videos" as *u8, 13) == 1 { return ss_emit_size(rbuf, req, rn, 118, sdir, o0, n) }
1777 }
1778 if eh_find(req, rn, "sort=runtime" as *u8, 12) == 1 {
1779 var rdir: i64 = 1; if eh_find(req, rn, "dir=asc" as *u8, 7) == 1 { rdir = 0 }
1780 if eh_find(req, rn, "filter=recordings" as *u8, 17) == 1 { return ss_emit_runtime(rbuf, req, rn, 114, rdir, o0, n) }
1781 if eh_find(req, rn, "filter=media" as *u8, 12) == 1 { return ss_emit_runtime(rbuf, req, rn, 109, rdir, o0, n) }
1782 if eh_find(req, rn, "filter=videos" as *u8, 13) == 1 { return ss_emit_runtime(rbuf, req, rn, 118, rdir, o0, n) }
1783 }
1784 if eh_find(req, rn, "sort=name" as *u8, 9) == 1 {
1785 var ndir: i64 = 0; if eh_find(req, rn, "dir=desc" as *u8, 8) == 1 { ndir = 1 } // name defaults A->Z (asc)
1786 if eh_find(req, rn, "filter=recordings" as *u8, 17) == 1 { return ss_emit_name(rbuf, req, rn, 114, ndir, o0, n) }
1787 if eh_find(req, rn, "filter=media" as *u8, 12) == 1 { return ss_emit_name(rbuf, req, rn, 109, ndir, o0, n) }
1788 if eh_find(req, rn, "filter=videos" as *u8, 13) == 1 { return ss_emit_name(rbuf, req, rn, 118, ndir, o0, n) }
1789 }
1790 // filter
1791 if eh_find(req, rn, "filter=recordings" as *u8, 17) == 1 { return gs_collection_list(rbuf, req, rn, 114, o0, n) }
1792 if eh_find(req, rn, "filter=media" as *u8, 12) == 1 { return gs_collection_list(rbuf, req, rn, 109, o0, n) }
1793 if eh_find(req, rn, "filter=videos" as *u8, 13) == 1 { return gs_collection_list(rbuf, req, rn, 118, o0, n) }
1794 if eh_find(req, rn, "filter=fav" as *u8, 10) == 1 { return gs_filter_list(rbuf, FAV_LOG, 1, o0, n) }
1795 if eh_find(req, rn, "filter=rated" as *u8, 12) == 1 { return gs_filter_list(rbuf, EVAL_LOG, 2, o0, n) }
1796 if eh_find(req, rn, "filter=viewed" as *u8, 13) == 1 { return gs_filter_list(rbuf, VIEW_LOG, 0, o0, n) }
1797 if eh_find(req, rn, "filter=gens" as *u8, 11) == 1 { return gs_gens_list(rbuf, req, rn, isold, o0, n) }
1798 // q=
1799 var li: i64 = 0; var qpos: i64 = 0 - 1; var stop: i64 = rn
1800 while li < stop { if req[li]==(10 as u8) { stop=li } else { if qpos<0 { if li+2<=rn { if req[li]==(113 as u8) { if req[li+1]==(61 as u8) { qpos=li+2 } } } } li=li+1 } }
1801 let qbuf: *u8 = sys_mmap(512)
1802 var qlen: i64 = 0
1803 if qpos >= 0 { var p: i64=qpos; var go: i64=1; while go==1 { if p>=rn { go=0 } else { let ch: i64=req[p] as i64; if ch==38 { go=0 } else { if ch==32 { go=0 } else { if ch==10 { go=0 } else { if ch==13 { go=0 } else { if qlen<500 { qbuf[qlen]=gs_lower(ch) as u8; qlen=qlen+1 } p=p+1 } } } } } } }
1804 let body: *u8 = sys_mmap(VIEW_MAGIC_131072)
1805 var bo: i64 = 0
1806 if qlen == 0 {
1807 return gs_allmedia_list(rbuf, req, rn, isold, o0, n)
1808 } else {
1809 // BM25 RANKED path (durable index loaded once in the parent; inherited via COW). Falls through to the
1810 // legacy substring scan only if the index is absent/stale -- so search is never worse than before.
1811 if gal.valid == 1 { return gs_bm25_emit(rbuf, gal, qbuf, qlen, o0, n) }
1812 let szp: *i64 = sys_mmap(16) as *i64
1813 let sb: *u8 = sys_read_file(SEARCH_IDX, szp)
1814 let sz: i64 = szp[0]
1815 bo = gs_cat(body, bo, "{\"items\":[" as *u8)
1816 if (sb as i64) == 0 { bo = gs_cat(body, bo, "],\"building\":1}" as *u8) } else {
1817 var i: i64 = 0; var ls: i64 = 0; var matched: i64 = 0; var emitted: i64 = 0; var first: i64 = 1
1818 while i < sz {
1819 if sb[i] == (10 as u8) {
1820 if i - ls > 70 { if sb[ls+69]==(9 as u8) {
1821 var hit: i64=0; var p: i64=ls+70
1822 while p + qlen <= i { var j: i64=0; var ok: i64=1; while j<qlen { if sb[p+j]!=qbuf[j]{ok=0; j=qlen} else { j=j+1 } } if ok==1 { hit=1; p=i } else { p=p+1 } }
1823 if hit==1 { if matched>=o0 { if emitted<n { bo=gs_emit_cid(body,bo,first,sb,ls); first=0; emitted=emitted+1 } } matched=matched+1 }
1824 } }
1825 ls = i + 1
1826 }
1827 i = i + 1
1828 }
1829 bo = gs_cat(body, bo, "]}" as *u8)
1830 }
1831 }
1832 return gs_okjson(rbuf, body, bo)
1833}
1834
1835// ---- /rate ----
1836func gs_rate(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1837 if gs_same_origin(req, rn) == 0 { return gs_forbidden(rbuf) }
1838 let cid: *u8 = sys_mmap(96)
1839 if gs_body_cid(req, rn, cid) == 0 { return gs_cat(rbuf, 0, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nContent-Length: 3\r\nConnection: close\r\n\r\nbad" as *u8) }
1840 var bodyat: i64 = 0 - 1
1841 var i: i64 = 0
1842 while i + 4 <= rn { if req[i]==(13 as u8) { if req[i+1]==(10 as u8) { if req[i+2]==(13 as u8) { if req[i+3]==(10 as u8) { if bodyat<0 { bodyat=i+4 } } } } } i=i+1 }
1843 let score: *u8 = sys_mmap(32)
1844 var sm: i64 = 0
1845 if bodyat >= 0 {
1846 var sat: i64 = 0 - 1; var ps: i64 = bodyat
1847 while ps + 6 <= rn { var oks: i64=1; let sp: *u8="score=" as *u8; var jj: i64=0; while jj<6 { if req[ps+jj]!=sp[jj]{oks=0} jj=jj+1 } if oks==1 { if sat<0 { sat=ps+6 } } ps=ps+1 }
1848 if sat >= 0 { var q: i64=sat; var god: i64=1; while q<rn { if god==1 { if req[q]>=(48 as u8) { if req[q]<=(57 as u8) { score[sm]=req[q]; sm=sm+1 } else { god=0 } } else { god=0 } } q=q+1 } }
1849 }
1850 score[sm] = 0 as u8
1851 let line: *u8 = sys_mmap(256)
1852 var lo: i64 = gs_cat(line, 0, "EVAL img=" as *u8)
1853 var c: i64 = 0
1854 while c < 69 { line[lo] = cid[c]; lo = lo + 1; c = c + 1 }
1855 lo = gs_cat(line, lo, " lane=O score=" as *u8)
1856 var s2: i64 = 0
1857 while score[s2] != (0 as u8) { line[lo] = score[s2]; lo = lo + 1; s2 = s2 + 1 }
1858 line[lo] = 10 as u8; lo = lo + 1
1859 gs_append_line(EVAL_LOG, line, lo)
1860 return gs_okrate(rbuf)
1861}
1862
1863// POST /lora/export -> run the sovereign export organ (favorites -> training manifest), return the count.
1864func gs_lora_export(rbuf: *u8, req: *u8, rn: i64) -> i64 {
1865 if gs_same_origin(req, rn) == 0 { return gs_forbidden(rbuf) }
1866 let wpath: *u8 = "/volume1/ai/galx/nx_galx_lora_export.elf" as *u8
1867 let argv: *i64 = sys_mmap(16) as *i64
1868 argv[0] = wpath as i64; argv[1] = 0
1869 let envp: *i64 = sys_mmap(8) as *i64; envp[0] = 0
1870 let pid: i64 = sys_fork()
1871 if pid == 0 { sys_execve_clean(wpath, argv, envp); sys_exit(127) }
1872 let st: *i64 = sys_mmap(16) as *i64
1873 sys_wait4(pid, st, 0)
1874 let szp: *i64 = sys_mmap(16) as *i64
1875 let b: *u8 = sys_read_file("knowledge/lora/favorites/manifest.tsv" as *u8, szp)
1876 let sz: i64 = szp[0]
1877 var cnt: i64 = 0
1878 if (b as i64) != 0 { var i: i64 = 0; while i < sz { if b[i]==(10 as u8) { cnt = cnt + 1 } i = i + 1 } }
1879 let body: *u8 = sys_mmap(128)
1880 var bo: i64 = gs_cat(body, 0, "{\"exported\":" as *u8)
1881 bo = gs_u(body, bo, cnt)
1882 bo = gs_cat(body, bo, "}" as *u8)
1883 return gs_okjson(rbuf, body, bo)
1884}
1885
1886// ---- gallery shell ----
1887func gs_shell(rbuf: *u8) -> i64 {
1888 // 256KB: the shell outgrew 128KB when the lightbox gained history-close + anchored pinch (2026-07-14)
1889 let body: *u8 = sys_mmap(VIEW_MAGIC_262144)
1890 var bo: i64 = 0
1891 bo = gs_cat(body, bo, "<!doctype html><html lang=en><meta charset=utf-8><title>Nishi Gallery</title><meta name=viewport content='width=device-width,initial-scale=1'><style>:root{--bg:#0b0d10;--fg:#e6e8eb;--mut:#8b929c;--card:#15181d;--acc:#5b9dff;--fav:#ff5a7a;--bd:#222831}*{box-sizing:border-box}html,body{margin:0;height:100%}body{background:var(--bg);color:var(--fg);font:14px/1.5 Inter,system-ui,sans-serif}header{position:sticky;top:0;z-index:5;display:flex;gap:10px;align-items:center;flex-wrap:wrap;padding:10px 14px;background:rgba(11,13,16,.95);border-bottom:1px solid var(--bd);backdrop-filter:blur(8px)}header h1{font-size:15px;font-weight:600;margin:0}header input{flex:1;min-width:160px;max-width:460px;background:#0f1318;border:1px solid var(--bd);color:var(--fg);border-radius:9px;padding:8px 12px}header select,.fbtn{background:#0f1318;border:1px solid var(--bd);color:var(--fg);border-radius:9px;padding:8px 11px;cursor:pointer;font-size:13px}.fbtn.on{background:var(--acc);color:#06101f;border-color:var(--acc)}.count{color:var(--mut);font-size:12px;margin-left:auto}#grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:8px;padding:10px}.cell{position:relative;display:block;border-radius:10px;overflow:hidden;background:var(--card);border:1px solid var(--bd);cursor:pointer;aspect-ratio:1;content-visibility:auto;contain-intrinsic-size:220px}.cell img{width:100%;height:100%;object-fit:cover;display:block}.cell.f::after{content:'\\2665';position:absolute;top:6px;right:8px;color:var(--fav);font-size:16px;text-shadow:0 1px 3px #000}#st{color:var(--mut);text-align:center;padding:18px;font-size:13px}#lb{position:fixed;inset:0;background:rgba(0,0,0,.95);display:none;z-index:50}#lb.on{display:block}#lbimg{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:18px;overflow:auto;touch-action:pan-y}#pbar{position:absolute;left:0;right:0;bottom:0;display:flex;align-items:center;gap:10px;padding:10px 14px;background:linear-gradient(transparent,rgba(0,0,0,.8))}#pbar button,#pbar a{background:none;border:0;color:#fff;font-size:20px;cursor:pointer;padding:0 4px;line-height:1;text-decoration:none}#pbar input[type=range]{flex:1;cursor:pointer}#pbar .tt{color:#fff;font-size:12px;white-space:nowrap;min-width:92px;text-align:right}#lbimg img{max-width:100%;max-height:100%;object-fit:contain;border-radius:8px;touch-action:none;transform-origin:0 0;will-change:transform}#lbv{max-width:100%;max-height:100%;border-radius:8px;display:none;touch-action:pan-y}.cell .play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:38px;color:#fff;opacity:.92;text-shadow:0 2px 10px #000;pointer-events:none}.dur{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.78);color:#fff;font-size:11px;line-height:1.3;padding:1px 5px;border-radius:4px;font-weight:600;pointer-events:none}.dur:empty{display:none}.daband{position:absolute;top:calc(50% - 3px);height:6px;background:rgba(255,90,90,.6);pointer-events:none;border-radius:2px;z-index:1}.daband.t2{background:rgba(90,200,255,.95);width:2px;z-index:3}.daband.t3{background:rgba(120,220,120,.45);z-index:1}.daband.t4{background:rgba(200,120,255,.5);z-index:1}#tagbar{position:absolute;left:50%;transform:translateX(-50%);bottom:58px;display:none;flex-wrap:wrap;gap:6px;justify-content:center;max-width:88vw;z-index:6}.tg{background:#2a2f3a;color:#cdd3df;border-radius:12px;padding:3px 10px;font-size:12px;display:inline-flex;align-items:center;gap:6px}.tg b{cursor:pointer;color:#8a93a6;font-weight:700;font-style:normal}.tg b:hover{color:#ff6b6b}#tgin{background:#1a1d24;border:1px solid var(--bd);color:#fff;border-radius:12px;padding:3px 10px;font-size:12px;width:84px;outline:none}#tagsfab{position:fixed;left:16px;bottom:16px;z-index:20;background:var(--card);border:1px solid var(--bd);color:#cdd3df;border-radius:50%;width:46px;height:46px;font-size:20px;cursor:pointer;box-shadow:0 2px 10px #0008}#tagcloud{position:fixed;left:16px;bottom:72px;z-index:20;display:none;flex-wrap:wrap;gap:8px;max-width:80vw;max-height:50vh;overflow:auto;background:var(--card);border:1px solid var(--bd);border-radius:12px;padding:12px}.seld{outline:3px solid #4a9eff;outline-offset:-3px}#selfab{position:fixed;left:74px;bottom:16px;z-index:20;background:var(--card);border:1px solid var(--bd);color:#cdd3df;border-radius:50%;width:46px;height:46px;font-size:20px;cursor:pointer;box-shadow:0 2px 10px #0008}#selfab.on{background:#4a9eff;color:#fff}#selbar{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:21;display:none;gap:10px;align-items:center;background:var(--card);border:1px solid var(--bd);border-radius:12px;padding:8px 14px;box-shadow:0 2px 14px #000a}#selbar button{background:#2a2f3a;color:#fff;border:none;border-radius:8px;padding:5px 12px;cursor:pointer;font-size:13px}#selcount{color:#cdd3df;font-size:13px}#side{position:absolute;left:0;right:0;bottom:0;background:var(--card);border-top:1px solid var(--bd);border-radius:16px 16px 0 0;padding:26px 18px 18px;overflow:auto;max-height:72vh;transform:translateY(calc(100% - 46px));transition:transform .3s cubic-bezier(.32,.72,0,1);box-shadow:0 -10px 34px rgba(0,0,0,.55);z-index:70;touch-action:none}#side.up{transform:translateY(0)}#side::before{content:'';position:absolute;top:10px;left:50%;transform:translateX(-50%);width:46px;height:5px;border-radius:3px;background:var(--mut);opacity:.85;cursor:pointer}#side h2{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--mut);margin:14px 0 8px}#side h2:first-child{margin-top:0}#favbtn{width:100%;background:#1a1f27;border:1px solid var(--bd);color:var(--fav);border-radius:8px;padding:10px;font-weight:600;cursor:pointer;font-size:14px}#favbtn.on{background:var(--fav);color:#1a0a0f;border-color:var(--fav)}.fac{font-size:12px;display:flex;justify-content:space-between;gap:12px;padding:5px 0;border-bottom:1px solid var(--bd)}.fac b{color:var(--mut);font-weight:500;white-space:nowrap}.fac span{text-align:right;word-break:break-word}#rng{width:100%}#rval{font-size:15px;font-weight:700;color:var(--acc)}#rbtn{width:100%;background:var(--acc);color:#06101f;border:0;border-radius:8px;padding:9px;font-weight:600;cursor:pointer;margin-top:6px}#rmsg{font-size:12px;color:#5ad08a;min-height:15px;margin-top:6px}#x{position:absolute;top:8px;right:14px;color:#fff;font-size:30px;cursor:pointer;opacity:.7;z-index:60}.nav{position:absolute;top:50%;transform:translateY(-50%);font-size:40px;color:#fff;opacity:.4;cursor:pointer;padding:12px;user-select:none;z-index:60}.nav:hover{opacity:1}#pv{left:6px}#nx{right:14px}#x{font-size:36px;padding:2px 14px}.spin{position:absolute;top:50%;left:50%;width:46px;height:46px;margin:-23px 0 0 -23px;border:4px solid rgba(255,255,255,.25);border-top-color:#fff;border-radius:50%;animation:sp .8s linear infinite;z-index:55}@keyframes sp{to{transform:rotate(360deg)}}@media(max-width:760px){#grid{grid-template-columns:repeat(auto-fill,minmax(108px,1fr));gap:5px;padding:6px}#lb.on{grid-template-columns:1fr;grid-template-rows:1fr}#lbimg{padding:0;width:100vw;height:100dvh}#side{position:fixed;left:0;right:0;bottom:0;top:auto;width:100%;max-height:84dvh;border-left:none;border-top:1px solid var(--bd);border-radius:16px 16px 0 0;padding:26px 16px calc(16px + env(safe-area-inset-bottom));transform:translateY(calc(100% - 48px));transition:transform .3s cubic-bezier(.32,.72,0,1);z-index:70;box-shadow:0 -10px 34px rgba(0,0,0,.55);touch-action:none}#side.up{transform:translateY(0)}#side::before{content:'';position:absolute;top:9px;left:50%;transform:translateX(-50%);width:42px;height:5px;border-radius:3px;background:var(--mut);opacity:.85}.nav{display:none}#x{font-size:38px;top:6px;right:14px;opacity:.95;z-index:80}header h1{font-size:14px}header input{min-width:110px}}</style>" as *u8)
1892 bo = gs_cat(body, bo, "<body><header><h1>Nishi Gallery</h1><input id=q placeholder='search prompts...' autocomplete=off><button class=fbtn on data-f=all>All</button><button class=fbtn data-f=gens>Gens</button><button class=fbtn data-f=fav>♥ Favorites</button><button class=fbtn data-f=rated>Rated</button><button class=fbtn data-f=viewed>Viewed</button><button class=fbtn data-f=recordings>► Recordings</button><button class=fbtn data-f=media>📺 Media</button><button class=fbtn data-f=videos>🎬 Videos</button><select id=modelsel style=display:none><option value=>All people</option></select><button id=loraexp class=fbtn title='Export favorited images as a LoRA training dataset'>♥→LoRA</button><select id=sort><option value=new>Newest</option><option value=old>Oldest</option><option value=lg>Largest file</option><option value=sm>Smallest file</option><option value=lng>Longest</option><option value=sht>Shortest</option><option value=naz>Name A→Z</option><option value=nza>Name Z→A</option></select><button id=rnd class=fbtn title='Jump to a random spot in the library'>🎲 Random</button><label style='display:flex;align-items:center;gap:5px;color:var(--mut);font-size:12px' title='Drag to jump anywhere in the library (0%=newest, 100%=oldest)'>📍<input id=pos type=range min=0 max=100 value=0 style='flex:0 0 110px;max-width:110px'></label><span class=count id=count></span></header><div id=grid></div><div id=sentinel></div><button id=tagsfab onclick=toggleTagCloud() title=Tags>🏷</button><div id=tagcloud></div><button id=selfab onclick=toggleSelMode() title=Select>☑</button><div id=selbar><span id=selcount>0 selected</span><button onclick=batchHide()>Hide</button><button onclick=batchTag()>Tag</button><button onclick=toggleSelMode()>Done</button></div><div id=st>loading...</div>" as *u8)
1893 bo = gs_cat(body, bo, "<script>(function(){var B=(location.pathname.indexOf('/gallery')===0)?'/gallery':'';var grid=document.getElementById('grid'),sent=document.getElementById('sentinel'),st=document.getElementById('st'),q=document.getElementById('q'),sortsel=document.getElementById('sort'),countEl=document.getElementById('count');var off=0,N=60,loading=false,done=false,cids=[],favs={},hidden={},filter='all',cols=[],colH=[],ncols=0,gridIsRec=false,model='',modelsLoaded=false;var lastTotal=0,rndb=document.getElementById('rnd'),posb=document.getElementById('pos');var TB=function(o){try{var d=JSON.stringify(o);if(navigator.sendBeacon){navigator.sendBeacon(B+'/telemetry',d)}else{fetch(B+'/telemetry',{method:'POST',body:d,keepalive:true})}}catch(_){}};window.addEventListener('error',function(e){TB({k:'jserr',m:((e.message||'')+'').slice(0,300),s:((e.filename||'')+'').slice(0,160),l:e.lineno||0,c:e.colno||0,p:location.pathname})});window.addEventListener('unhandledrejection',function(e){TB({k:'reject',m:(((e.reason&&e.reason.message)||e.reason||'')+'').slice(0,300)})});addEventListener('load',function(){setTimeout(function(){try{var nv=performance.getEntriesByType('navigation')[0],fp=performance.getEntriesByType('paint');TB({k:'perf',dcl:nv?Math.round(nv.domContentLoadedEventEnd):0,ld:nv?Math.round(nv.loadEventEnd):0,fcp:(fp&&fp[0])?Math.round(fp[0].startTime):0,n:cids.length,vp:innerWidth+'x'+innerHeight})}catch(_){}},0)});try{new PerformanceObserver(function(pl){pl.getEntries().forEach(function(en){if(en.duration>150){TB({k:'longtask',d:Math.round(en.duration),p:location.pathname})}})}).observe({type:'longtask',buffered:true})}catch(_){}function esc(s){return String(s).replace(/[<&>]/g,function(c){return c=='<'?'<':c=='>'?'>':'&'})}function smap(){var v=sortsel.value;if(v=='lg')return 'sort=size&dir=desc';if(v=='sm')return 'sort=size&dir=asc';if(v=='lng')return 'sort=runtime&dir=desc';if(v=='sht')return 'sort=runtime&dir=asc';if(v=='naz')return 'sort=name&dir=asc';if(v=='nza')return 'sort=name&dir=desc';return 's='+v}function qs(){return 'o='+off+'&n='+N+'&'+smap()+'&filter='+filter+'&model='+encodeURIComponent(model)+'&q='+encodeURIComponent(q.value)}function buildcols(){grid.innerHTML=''}function shortest(){var mi=0;for(var i=1;i<ncols;i++){if(colH[i]<colH[mi])mi=i}return mi}var selMode=false,sel={},selN=0;function toggleSelMode(){selMode=!selMode;if(!selMode){for(var k in sel){var e=grid.querySelector('[data-cid='+k+']');if(e)e.classList.remove('seld')}sel={};selN=0}selfab.classList.toggle('on',selMode);selbar.style.display=selMode?'flex':'none';updSel()}function toggleSel(cid,el){if(sel[cid]){delete sel[cid];el.classList.remove('seld');selN=selN-1}else{sel[cid]=1;el.classList.add('seld');selN=selN+1}updSel()}function updSel(){selcount.textContent=selN+' selected'}function selIds(){var a=[];for(var k in sel){a.push(k)}return a}function batchHide(){var ids=selIds();if(!ids.length)return;if(!confirm('Hide '+ids.length+' videos? (reversible)'))return;var n=0;ids.forEach(function(id){fetch(B+'/hide',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'id='+id+'&v=1'}).then(function(){hidden[id]=1;n=n+1;if(n==ids.length){toggleSelMode();reset()}})})}function batchTag(){var ids=selIds();if(!ids.length)return;var t=prompt('Tag '+ids.length+' videos with:');if(!t)return;t=t.replace(/[^a-zA-Z0-9 -]/g,'').replace(/ /g,'+');if(!t)return;var n=0;ids.forEach(function(id){fetch(B+'/tag',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'id='+id+'&tag='+t+'&v=1'}).then(function(){n=n+1;if(n==ids.length){toggleSelMode()}})})}function toggleTagCloud(){if(tagcloud.style.display=='flex'){tagcloud.style.display='none';return}tagcloud.style.display='flex';tagcloud.innerHTML='loading...';fetch(B+'/api/alltags').then(function(r){return r.json()}).then(function(ts){if(!ts.length){tagcloud.innerHTML='no tags yet';return}var h='';for(var i=0;i<ts.length;i++){h+='<span class=tg>'+ts[i]+'</span>'}tagcloud.innerHTML=h;var cs=tagcloud.querySelectorAll('.tg');for(var i=0;i<cs.length;i++){(function(nm){cs[i].onclick=function(){tagcloud.style.display='none';renderTagged(nm)}})(ts[i])}}).catch(function(){tagcloud.innerHTML='error'})}function renderTagged(t){lb.classList.remove('on');cur=-1;lbv.pause();done=true;loading=false;cids=[];gridIsRec=1;buildcols();countEl.textContent='#'+t;st.textContent='';fetch(B+'/api/tagged?tag='+encodeURIComponent(t).replace(/%20/g,'+')).then(function(r){return r.json()}).then(function(ids){for(var i=0;i<ids.length;i++){if(!hidden[ids[i]]){cids.push(ids[i]);addCell(ids[i])}}loadDurs(ids);if(!ids.length){st.textContent='no videos tagged '+t}}).catch(function(){st.textContent='error'})}function postTag(cid,tag,v){var b='id='+cid+'&tag='+tag.replace(/[^a-zA-Z0-9 -]/g,'').replace(/ /g,'+')+'&v='+v;fetch(B+'/tag',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:b}).then(function(){showTags(cid)})}function showTags(cid){tagbar.style.display='flex';fetch(B+'/api/tags?id='+cid).then(function(r){return r.json()}).then(function(ts){var h='';for(var i=0;i<ts.length;i++){h+='<span class=tg>'+ts[i]+'<b>×</b></span>'}tagbar.innerHTML=h+'<input id=tgin placeholder=+tag autocomplete=off>';var cs=tagbar.querySelectorAll('.tg');for(var i=0;i<cs.length;i++){(function(nm){cs[i].onclick=function(){renderTagged(nm)};cs[i].querySelector('b').onclick=function(e){e.stopPropagation();postTag(cid,nm,0)}})(ts[i])}var inp=document.getElementById('tgin');inp.onkeydown=function(e){if(e.key=='Enter'){e.preventDefault();var x=inp.value.trim();if(x){postTag(cid,x,1)}}}}).catch(function(){})}function fmtDur(ms){var s=Math.floor(ms/1000),h=Math.floor(s/3600),m=Math.floor((s%3600)/60),ss=s%60;function p(n){return(n<10?'0':'')+n}return h>0?h+':'+p(m)+':'+p(ss):m+':'+p(ss)}function loadDurs(ids){if(!ids||!ids.length)return;fetch(B+'/api/durs?ids='+ids.join(',')).then(function(r){return r.json()}).then(function(d){for(var k in d){var e=grid.querySelector('[data-durid='+k+']');if(e&&d[k]>0)e.textContent=fmtDur(d[k])}}).catch(function(){})}function addCell(cid){var isRec=(''+cid).length<=12;var el=document.createElement('a');el.className='cell'+(favs[cid]?' f':'');el.href=isRec?B+'/vid/'+cid:B+'/img/'+cid;el.dataset.cid=cid;var im=document.createElement('img');im.loading='lazy';im.decoding='async';im.src=isRec?B+'/vidthumb/'+cid:B+'/thumb/'+cid;el.appendChild(im);if(isRec){var pl=document.createElement('span');pl.className='play';pl.innerHTML='►';el.appendChild(pl);var dvb=document.createElement('span');dvb.className='dur';dvb.dataset.durid=cid;el.appendChild(dvb)}el.addEventListener('click',function(e){e.preventDefault();if(selMode){toggleSel(cid,el)}else{openLb(cids.indexOf(cid))}});grid.appendChild(el)}function reset(){off=0;done=false;cids=[];gridIsRec=(filter=='recordings'||filter=='media'||filter=='videos');buildcols();st.textContent='loading...';load()}function maybeMore(){if(loading||done)return;var vh=window.innerHeight||document.documentElement.clientHeight;if(sent.getBoundingClientRect().top < vh+1400){load()}}function load(){if(loading||done)return;loading=true;fetch(B+'/api/list?'+qs()).then(function(r){if(r.status===401){location.href=B+'/login';return new Promise(function(){})}return r.json()}).then(function(j){var a=j.items||[];if(j.total!=null){countEl.textContent=j.total.toLocaleString()+(gridIsRec?(' '+filter):' images');lastTotal=j.total}if(j.building)st.textContent='search index still building...';if(!a.length){done=true;loading=false;st.textContent=cids.length?'':'nothing here';return}a.forEach(function(cid){if(gridIsRec&&hidden[cid])return;cids.push(cid);addCell(cid)});if(gridIsRec)loadDurs(a);off+=a.length;loading=false;st.textContent='';setTimeout(maybeMore,90)}).catch(function(){loading=false;st.textContent='error'})}var io=new IntersectionObserver(function(es){if(es[0].isIntersecting)maybeMore()},{rootMargin:'1400px'});io.observe(sent);window.addEventListener('scroll',maybeMore,{passive:true});window.addEventListener('resize',maybeMore,{passive:true});var t;q.addEventListener('input',function(){clearTimeout(t);t=setTimeout(reset,350)});sortsel.addEventListener('change',reset);var msel=document.getElementById('modelsel');msel.addEventListener('change',function(){model=msel.value;reset()});[].forEach.call(document.querySelectorAll('.fbtn'),function(btn){btn.addEventListener('click',function(){[].forEach.call(document.querySelectorAll('.fbtn'),function(b){b.classList.remove('on')});btn.classList.add('on');filter=btn.dataset.f;if(filter=='recordings'){msel.style.display='';if(!modelsLoaded){modelsLoaded=true;fetch(B+'/api/models').then(function(r){return r.json()}).then(function(a){a.forEach(function(o){var op=document.createElement('option');op.value=o.m;op.textContent=o.m+' ('+o.c+')';msel.appendChild(op)})})}}else{msel.style.display='none';model=''}reset()})});function jumpOff(o2){off=o2<0?0:o2;done=false;loading=false;cids=[];gridIsRec=(filter=='recordings'||filter=='media'||filter=='videos');buildcols();st.textContent='loading...';load()}if(rndb){rndb.onclick=function(){var t=lastTotal||0;if(t<1)return;var span=t-N;if(span<1)span=1;jumpOff(Math.floor(Math.random()*span))}}if(posb){posb.onchange=function(){var t=lastTotal||0;if(t<1)return;var o2=Math.floor(t*(parseInt(posb.value)||0)/100);if(o2>t-1)o2=t-1;if(o2<0)o2=0;jumpOff(o2)}}" as *u8)
1894 bo = gs_cat(body, bo, "var lb=document.createElement('div');lb.id='lb';lb.innerHTML='<div id=lbimg><img id=lbi><video id=lbv playsinline preload=auto></video><div id=spin class=spin style=display:none></div><div id=pbar style=display:none><button id=pp>►</button><span id=skw style=position:relative;flex:1;display:flex;align-items:center><input type=range min=0 value=0 id=seek style=flex:1></span><span id=seekt class=tt></span><span id=pres class=tt></span><button id=pfs title=fullscreen>⛶</button><a id=pdl href=# download title=download>⇩</a><button id=phide title=hide>🗑</button></div><div id=ibar style=display:none;position:absolute;bottom:14px;left:50%;transform:translateX(-50%);gap:16px;background:rgba(0,0,0,.62);padding:8px;border-radius:9px;z-index:6;align-items:center><a id=iorig target=_blank style=color:#fff;text-decoration:none;font-size:14px>↗ Original size</a><a id=idl download style=color:#fff;text-decoration:none;font-size:14px>⇩ Download</a><a id=iup target=_blank style=color:#fff;text-decoration:none;font-size:14px>⤢ 2× Upscale</a></div></div><div id=tagbar></div><span id=x>×</span><span class=nav id=pv>‹</span><span class=nav id=nx>›</span><div id=side><button id=favbtn>♥ Favorite</button><h2>Generation factors</h2><div id=fac></div><div id=ratewrap><h2>Rate</h2><div id=rval>500</div><input type=range min=0 max=1000 value=500 id=rng><button id=rbtn>Submit rating</button><div id=rmsg></div></div></div>';document.body.appendChild(lb);var lbi=document.getElementById('lbi'),lbv=document.getElementById('lbv'),ratewrap=document.getElementById('ratewrap'),fac=document.getElementById('fac'),rng=document.getElementById('rng'),rval=document.getElementById('rval'),rmsg=document.getElementById('rmsg'),favbtn=document.getElementById('favbtn'),pbar=document.getElementById('pbar'),tagbar=document.getElementById('tagbar'),tagcloud=document.getElementById('tagcloud'),selfab=document.getElementById('selfab'),selbar=document.getElementById('selbar'),selcount=document.getElementById('selcount'),pp=document.getElementById('pp'),seek=document.getElementById('seek'),seekt=document.getElementById('seekt'),pfs=document.getElementById('pfs'),pdl=document.getElementById('pdl'),phide=document.getElementById('phide'),pres=document.getElementById('pres'),ibar=document.getElementById('ibar'),iorig=document.getElementById('iorig'),idl=document.getElementById('idl'),iup=document.getElementById('iup'),curDur=0,seekT0=0,dragging=0,mseOn=0,mms=null,msb=null,mcid=-1,mdur=0,mfetch=0,mseekv=-1,mremoved=0,minit=0,nativeSeek=0,mseg=0,cur=-1,curRec=0;function fmt(ms){var s=Math.floor(ms/1000),m=Math.floor(s/60),h=Math.floor(m/60);s=s%60;m=m%60;function p(x){return(x<10?'0':'')+x}return(h>0?h+':'+p(m):m)+':'+p(s)}function post(u,b){return fetch(u,{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:b})}function setfav(cid,on){favs[cid]=on?1:0;favbtn.classList.toggle('on',!!on);var c=grid.querySelector('.cell[data-cid=\"'+cid+'\"]');if(c)c.classList.toggle('f',!!on)}" as *u8)
1895 bo = gs_cat(body, bo, "function mseFail(cid){mseOn=0;lbv.src=B+'/vid/'+cid;lbv.load();lbv.play()}function mseFetch(tms){if(mfetch||!msb)return;mfetch=1;fetch(B+'/vid/'+mcid+'/seg?t='+Math.floor(tms)).then(function(r){return r.arrayBuffer()}).then(function(a){mfetch=0;if(msb&&!msb.updating){try{msb.appendBuffer(new Uint8Array(a))}catch(e){}}}).catch(function(){mfetch=0})}function msePump(){if(!msb||msb.updating)return;if(mseekv>=0){if(mremoved==0){mremoved=1;try{msb.remove(0,1000000000)}catch(e){}return}var s=mseekv;mseekv=-1;try{lbv.currentTime=s/1000}catch(e){}mseFetch(s);return}if(minit==0){minit=1;mseFetch(0);return}if(msb.buffered.length){var en=msb.buffered.end(msb.buffered.length-1);if((en-lbv.currentTime<12)&&(en*1000<mdur-400))mseFetch(en*1000)}}function mseStart(cid,dur,codec){mseOn=1;mcid=cid;mdur=dur;minit=0;mseekv=-1;mremoved=0;mfetch=0;try{mms=new MediaSource()}catch(e){mseFail(cid);return}lbv.src=URL.createObjectURL(mms);mms.addEventListener('sourceopen',function(){if(msb)return;try{msb=mms.addSourceBuffer('video/mp4; codecs=\"'+codec+',mp4a.40.2\"')}catch(e){mseFail(cid);return}try{mms.duration=dur/1000}catch(e){}msb.addEventListener('updateend',msePump);fetch(B+'/vid/'+cid+'/init.mp4').then(function(r){return r.arrayBuffer()}).then(function(a){if(msb&&!msb.updating){try{msb.appendBuffer(new Uint8Array(a))}catch(e){mseFail(cid)}}}).catch(function(){mseFail(cid)})});lbv.play()}function mseSeekTo(tms){if(!msb)return;mseekv=tms;mremoved=0;if(!msb.updating)msePump()}function mseCovered(t){if(!msb)return 0;for(var i=0;i<msb.buffered.length;i++){if(t>=msb.buffered.start(i)&&t<msb.buffered.end(i)-0.1)return 1}return 0}function mseSeekFetch(tms){if(!mseOn||!msb)return;var g=++mseg;var tt=Math.max(0,Math.floor(tms));var ap=function(a){if(g!=mseg||!msb)return;if(msb.updating){setTimeout(function(){ap(a)},30);return}try{msb.appendBuffer(new Uint8Array(a))}catch(e){if(e&&e.name=='QuotaExceededError'){try{msb.remove(0,Math.max(0,lbv.currentTime-20))}catch(_){}setTimeout(function(){ap(a)},60)}}};fetch(B+'/vid/'+mcid+'/seg?t='+tt).then(function(r){return r.arrayBuffer()}).then(function(a){if(g!=mseg)return;ap(a)}).catch(function(){})}function msePollForReady(cid,n){if(cids[cur]!=cid)return;fetch(B+'/vid/'+cid+'/segs').then(function(r){return r.json()}).then(function(j){if(cids[cur]!=cid)return;if(j.dur&&j.dur>0){curDur=j.dur;mdur=j.dur}if(j.ready&&j.codec){seekt.textContent='0:00'+(curDur>0?' / '+fmt(curDur):'');mseStart(cid,j.dur||curDur,j.codec);return}if(j.native){nativeSeek=1;seekt.textContent='0:00'+(curDur>0?' / '+fmt(curDur):'');lbv.src=B+'/vid/'+cid;lbv.load();lbv.play();return}if(n<40){seekt.textContent='preparing...';setTimeout(function(){msePollForReady(cid,n+1)},1200);return}nativeSeek=0;lbv.src=B+'/vid/'+cid;lbv.load();lbv.play();if(!curDur)segDurPoll(cid,0)}).catch(function(){if(cids[cur]!=cid)return;if(n<40){setTimeout(function(){msePollForReady(cid,n+1)},1500)}else{lbv.src=B+'/vid/'+cid;lbv.load();lbv.play();segDurPoll(cid,0)}})}" as *u8)
1896 bo = gs_cat(body, bo, "function vidAnalysis(cid){fetch(B+'/vid/'+cid+'/analysis').then(function(r){return r.json()}).then(function(a){if(!a||!a.label)return;var d=a.dur||1;function pc(x){return Math.round((x||0)/d*100)}fac.innerHTML+='<div class=fac><b>content</b><span>'+a.label+'</span></div><div class=fac><b>profile</b><span>'+a.scenes+' scenes / '+pc(a.active_ms)+'% active / '+pc(a.rhythmic_ms)+'% rhythmic / '+pc(a.quiet_ms)+'% quiet</span></div>'}).catch(function(){})}var daMarks=[];function daClear(){var w=document.getElementById('skw');daMarks=[];if(w){var b=w.querySelectorAll('.daband');for(var i=0;i<b.length;i++)b[i].parentNode.removeChild(b[i])}}function daRender(){var w=document.getElementById('skw');if(!w)return;var old=w.querySelectorAll('.daband');for(var i=0;i<old.length;i++)old[i].parentNode.removeChild(old[i]);if(!curDur||curDur<=0)return;for(var j=0;j<daMarks.length;j++){var m=daMarks[j];var el=document.createElement('div');el.className='daband t'+m.type;el.style.left=(m.start/curDur*100)+'%';var wp=(m.end-m.start)/curDur*100;if(m.type==2){wp=0.4}else if(wp<0.6){wp=0.6}el.style.width=wp+'%';var nm=m.type==1?'dead air':(m.type==2?'scene cut':(m.type==3?'high motion':(m.type==4?'rhythm/dance':'mark')));el.title=nm+' '+Math.round((m.end-m.start)/1000)+'s';w.appendChild(el)}}function segDurPoll(cid,n){if(cids[cur]!=cid)return;fetch(B+'/vid/'+cid+'/segs').then(function(r){return r.json()}).then(function(j){if(cids[cur]!=cid)return;if(j.dur&&j.dur>0){curDur=j.dur;mdur=j.dur;var now=mseOn?Math.floor(lbv.currentTime*1000):seekT0+Math.floor(lbv.currentTime*1000);seekt.textContent=fmt(now)+' / '+fmt(curDur)}else if(n<40){setTimeout(function(){segDurPoll(cid,n+1)},1500)}}).catch(function(){})}" as *u8)
1897 bo = gs_cat(body, bo, "function openLb(i){cur=i;var cid=cids[i];lb.classList.add('on');if(!window._lbPushed){history.pushState({lb:1},'');window._lbPushed=1}lbZreset();spin.style.display='block';rmsg.textContent='';tagbar.style.display='none';showTags(cid);curRec=(''+cid).length<=12;if(curRec){lbi.style.display='none';lbv.style.display='block';favbtn.style.display='none';ratewrap.style.display='none';side.style.display='none';pbar.style.display='flex';ibar.style.display='none';pdl.href=B+'/vid/'+cid;pp.innerHTML='❙❙';seekT0=0;seek.max=1000000;seek.value=0;curDur=0;mseOn=0;msb=null;nativeSeek=0;seekt.textContent='0:00';lbv.poster=B+'/vidthumb/'+cid;daClear();fetch(B+'/vid/'+cid+'/marks').then(function(r){return r.json()}).then(function(mk){daMarks=mk;daRender();setTimeout(daRender,2600)}).catch(function(){});fetch(B+'/vid/'+cid+'/segs').then(function(r){return r.json()}).then(function(j){curDur=j.dur||0;mdur=j.dur||0;nativeSeek=j.native?1:0;if(j.ready&&j.codec){mseStart(cid,j.dur,j.codec);seekt.textContent='0:00'+(curDur>0?' / '+fmt(curDur):'')}else if(j.native){lbv.src=B+'/vid/'+cid;lbv.load();lbv.play();seekt.textContent='0:00'+(curDur>0?' / '+fmt(curDur):'')}else{seekt.textContent='preparing...';msePollForReady(cid,0)}}).catch(function(){lbv.src=B+'/vid/'+cid;lbv.load();lbv.play();segDurPoll(cid,0)});fac.innerHTML='<div class=fac><b>recording</b><span>#'+cid+'</span></div><div class=fac><a href='+B+'/vid/'+cid+' download>download .ts</a></div>';vidAnalysis(cid)}else{lbv.pause();lbv.removeAttribute('src');lbv.style.display='none';pbar.style.display='none';lbi.style.display='block';favbtn.style.display='block';ratewrap.style.display='block';side.style.display='block';try{side.classList.toggle('up',localStorage.getItem('nsidey')==='1')}catch(_){}lbi.src=B+'/img/'+cid;iorig.href=B+'/img/'+cid;idl.href=B+'/img/'+cid;idl.download=cid+'.png';iup.href=B+'/upscale/'+cid;ibar.style.display='flex';rng.value=500;rval.textContent='500';fac.innerHTML='<div class=fac><b>loading</b></div>';post(B+'/view','img='+cid);fetch(B+'/state/'+cid).then(function(r){return r.json()}).then(function(s){setfav(cid,s.fav);if(s.rating>=0){rng.value=s.rating;rval.textContent=s.rating}});fetch(B+'/meta/'+cid).then(function(r){return r.json()}).then(function(m){var k=Object.keys(m);fac.innerHTML=k.length?k.map(function(x){return '<div class=fac><b>'+esc(x)+'</b><span>'+esc(m[x])+'</span></div>'}).join(''):'<div class=fac><b>no factors</b></div>'}).catch(function(){fac.innerHTML='<div class=fac><b>unavailable</b></div>'})}}function hide(){lb.classList.remove('on');cur=-1;lbv.pause();lbZreset();if(window._lbPushed){window._lbPushed=0;history.back()}}window.addEventListener('popstate',function(){if(lb.classList.contains('on')){window._lbPushed=0;hide()}});var _lbZ=1,_lbTX=0,_lbTY=0,_lbP=new Map(),_lbG=null;function lbZap(){lbi.style.transform=_lbZ>1?('translate('+_lbTX+'px,'+_lbTY+'px) scale('+_lbZ+')'):'';window._lbZ=_lbZ}function lbZreset(){_lbZ=1;_lbTX=0;_lbTY=0;_lbP.clear();_lbG=null;lbZap()}lbi.addEventListener('pointerdown',function(e){if(curRec)return;_lbP.set(e.pointerId,{x:e.clientX,y:e.clientY});var r=lbi.getBoundingClientRect(),ox=r.left-_lbTX,oy=r.top-_lbTY;if(_lbP.size==2){var a=Array.from(_lbP.values());_lbG={d:Math.hypot(a[0].x-a[1].x,a[0].y-a[1].y),cx:(a[0].x+a[1].x)/2,cy:(a[0].y+a[1].y)/2,z:_lbZ,tx:_lbTX,ty:_lbTY,ox:ox,oy:oy}}else if(_lbP.size==1){_lbG={x:e.clientX,y:e.clientY,tx:_lbTX,ty:_lbTY,one:1}}});lbi.addEventListener('pointermove',function(e){if(!_lbP.has(e.pointerId)||!_lbG)return;_lbP.set(e.pointerId,{x:e.clientX,y:e.clientY});if(_lbP.size==2&&_lbG.d){var a=Array.from(_lbP.values());var d=Math.hypot(a[0].x-a[1].x,a[0].y-a[1].y),cx=(a[0].x+a[1].x)/2,cy=(a[0].y+a[1].y)/2;var nz=Math.min(8,Math.max(1,_lbG.z*d/_lbG.d));_lbTX=cx-_lbG.ox-(nz/_lbG.z)*(_lbG.cx-_lbG.ox-_lbG.tx);_lbTY=cy-_lbG.oy-(nz/_lbG.z)*(_lbG.cy-_lbG.oy-_lbG.ty);_lbZ=nz;if(_lbZ<=1.001){_lbZ=1;_lbTX=0;_lbTY=0}lbZap();e.preventDefault()}else if(_lbP.size==1&&_lbG.one&&_lbZ>1){_lbTX=_lbG.tx+(e.clientX-_lbG.x);_lbTY=_lbG.ty+(e.clientY-_lbG.y);lbZap();e.preventDefault()}});function _lbUp(e){_lbP.delete(e.pointerId);if(_lbP.size==0)_lbG=null}lbi.addEventListener('pointerup',_lbUp);lbi.addEventListener('pointercancel',_lbUp);lbi.addEventListener('dblclick',function(e){if(_lbZ>1){lbZreset()}else{var r=lbi.getBoundingClientRect();_lbZ=2.5;_lbTX=(e.clientX-r.left)*(1-2.5);_lbTY=(e.clientY-r.top)*(1-2.5);lbZap()}});" as *u8)
1898 bo = gs_cat(body, bo, "var spin=document.getElementById('spin');document.getElementById('x').onclick=hide;lb.addEventListener('click',function(e){if(e.target.id=='lb'||e.target.id=='lbimg')hide()});lbi.addEventListener('load',function(){spin.style.display='none'});lbv.addEventListener('loadeddata',function(){spin.style.display='none'});lbv.addEventListener('loadedmetadata',function(){if(nativeSeek&&curDur<=0&&isFinite(lbv.duration))curDur=Math.floor(lbv.duration*1000);var h=lbv.videoHeight;pres.textContent=h?(lbv.videoWidth+'x'+h+(h>=4320?' 8K':h>=2160?' 4K':h>=1440?' 1440p':h>=1080?' 1080p':h>=720?' 720p':'')):''});lbv.addEventListener('error',function(){spin.style.display='none';if(gridIsRec&&cur>=0){fac.innerHTML+='<div class=fac><b>codec</b><span>browser cannot decode this video; if HEVC/H.265 install HEVC Video Extensions from the Microsoft Store then reload</span></div>'}});document.getElementById('pv').onclick=function(){if(cur>0)openLb(cur-1)};document.getElementById('nx').onclick=function(){if(cur<cids.length-1)openLb(cur+1)};favbtn.onclick=function(){var cid=cids[cur];var on=favs[cid]?0:1;setfav(cid,on);post(B+'/fav','img='+cid+'&v='+on)};document.getElementById('loraexp').onclick=function(){post(B+'/lora/export','').then(function(r){return r.json()}).then(function(j){alert('Exported '+j.exported+' favorite(s) to the LoRA training dataset:\\nknowledge/lora/favorites/manifest.tsv')}).catch(function(){alert('export failed')})};rng.oninput=function(){rval.textContent=rng.value};seek.oninput=function(){dragging=1;var f=parseInt(seek.value)||0;var ms=curDur>0?Math.floor(f/1000000*curDur):0;seekt.textContent=fmt(ms)+(curDur>0?' / '+fmt(curDur):'')};seek.onchange=function(){dragging=0;if(cur<0||!curRec)return;var f=parseInt(seek.value)||0;if(mseOn){var _w=curDur>0?Math.floor(f/1000000*curDur):0;try{lbv.currentTime=_w/1000}catch(e){}return}if(nativeSeek){var nd=lbv.duration;if(!nd||!isFinite(nd))nd=curDur/1000;if(nd>0)lbv.currentTime=f/1000000*nd;return}var cid=cids[cur];seekT0=curDur>0?Math.floor(f/1000000*curDur):0;spin.style.display='block';lbv.src=B+'/vid/'+cid+'?b='+f;lbv.load();lbv.play()};" as *u8)
1899 bo = gs_cat(body, bo, "lbv.addEventListener('seeking',function(){if(!mseOn||!msb)return;var t=lbv.currentTime;if(mseCovered(t))return;mseSeekFetch(t*1000)});lbv.addEventListener('timeupdate',function(){if(dragging||!curRec)return;if(mseOn){if(mdur>0){var mt=Math.floor(lbv.currentTime*1000);seek.value=Math.floor(mt/mdur*1000000);seekt.textContent=fmt(mt)+' / '+fmt(mdur)}if(msb&&!msb.updating&&msb.buffered.length){var en=msb.buffered.end(msb.buffered.length-1);if((en-lbv.currentTime<10)&&(en*1000<mdur-400))mseFetch(en*1000)}return}var ms=seekT0+Math.floor(lbv.currentTime*1000);if(curDur>0){seek.value=Math.floor(ms/curDur*1000000);seekt.textContent=fmt(ms)+' / '+fmt(curDur)}else{seekt.textContent=fmt(ms)}});pp.onclick=function(){if(lbv.paused)lbv.play();else lbv.pause()};lbv.addEventListener('play',function(){pp.innerHTML='❙❙'});lbv.addEventListener('pause',function(){pp.innerHTML='►'});pfs.onclick=function(){if(lbv.requestFullscreen)lbv.requestFullscreen();else if(lbv.webkitEnterFullscreen)lbv.webkitEnterFullscreen()};phide.onclick=function(){if(cur<0)return;var cid=cids[cur];post(B+'/hide','id='+cid+'&v=1');hidden[cid]=1;var c=grid.querySelector('.cell[data-cid=\"'+cid+'\"]');if(c&&c.parentNode)c.parentNode.removeChild(c);var ix=cids.indexOf(cid);if(ix>=0)cids.splice(ix,1);hide()};lbv.addEventListener('click',function(){if(lbv.paused)lbv.play();else lbv.pause()});document.getElementById('rbtn').onclick=function(){var cid=cids[cur];post(B+'/rate','img='+cid+'&score='+rng.value).then(function(r){rmsg.textContent=r.ok?'saved '+rng.value:'error'})};document.addEventListener('keydown',function(e){if(cur<0)return;if(e.key=='Escape')hide();else if(e.key=='ArrowLeft'&&cur>0)openLb(cur-1);else if(e.key=='ArrowRight'&&cur<cids.length-1)openLb(cur+1);else if(e.key=='f'){favbtn.onclick()}});var lbimg=document.getElementById('lbimg'),side=document.getElementById('side');var _sx=0,_sy=0,_st=0,_sw=0;function _nb(){[cids[cur-1],cids[cur+1]].forEach(function(c){if(c!=null){var i=new Image();i.src=((''+c).length<=12)?B+'/vidthumb/'+c:B+'/img/'+c}})}lbimg.addEventListener('touchstart',function(e){var g=e.target.tagName;if(g=='INPUT'||g=='BUTTON'){_sw=0;return}if(e.touches.length>1||_lbZ>1){_sw=0;return}_sw=1;var t=e.touches[0];_sx=t.clientX;_sy=t.clientY;_st=Date.now()},{passive:true});lbimg.addEventListener('touchend',function(e){if(!_sw)return;var t=e.changedTouches[0],dx=t.clientX-_sx,dy=t.clientY-_sy;if(Date.now()-_st<700&&Math.abs(dx)>46&&Math.abs(dx)>Math.abs(dy)*1.3){if(dx<0&&cur<cids.length-1){openLb(cur+1);_nb()}else if(dx>0&&cur>0){openLb(cur-1);_nb()}}},{passive:true});side.addEventListener('click',function(e){var r=side.getBoundingClientRect();if(e.clientY-r.top<44){side.classList.toggle('up');try{localStorage.setItem('nsidey',side.classList.contains('up')?'1':'0')}catch(_){}}});fetch(B+'/api/hidden').then(function(r){return r.json()}).then(function(j){(j.hidden||[]).forEach(function(x){hidden[x]=1});reset()}).catch(function(){reset()})})();</script></body></html>" as *u8)
1900 var o: i64 = 0
1901 o = gs_cat(rbuf, o, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nCache-Control: no-store, must-revalidate\r\nConnection: close\r\nContent-Length: " as *u8)
1902 o = gs_u(rbuf, o, bo)
1903 o = gs_cat(rbuf, o, "\r\n\r\n" as *u8)
1904 var i: i64 = 0
1905 while i < bo { rbuf[o] = body[i]; o = o + 1; i = i + 1 }
1906 return o
1907}
1908
1909// R2: spawn the duration-index batch (nx_galx_durindex -> galx_dur.raw) DETACHED at boot so runtime-sort
1910// populates without blocking the serve. Double-fork + nx_setsid: the grandchild reparents to init (no zombie
1911// here, survives gallery restarts/SSH close). The durindex flock-guards itself + is resumable, so re-spawning
1912// each boot is safe (a 2nd instance just exits; a complete one scans + exits fast). Inherits cwd /volume1/ai/galx
1913// (the elfs + knowledge/status/ data live there). Spawn failure is isolated -> serve is unaffected.
1914func gs_spawn_durindex() -> i64 {
1915 let pid: i64 = sys_fork()
1916 if pid == 0 {
1917 let gpid: i64 = sys_fork()
1918 if gpid == 0 {
1919 nx_setsid()
1920 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1921 let lg: i64 = sys_openat_append("galx_durindex.log" as *u8, 0x1a4)
1922 if dn >= 0 { sys_dup3(dn, 0, 0) }
1923 if lg >= 0 { sys_dup3(lg, 1, 0); sys_dup3(lg, 2, 0) }
1924 nx_chmod("./nx_galx_durindex.elf" as *u8, 0x1ed) // recv lands files 0644 -> make 0755 (+x) before exec
1925 nx_chmod("./nx_ts_dur.elf" as *u8, 0x1ed) // the durindex execve's this per video, so it too needs +x
1926 let av: *i64 = sys_mmap(64) as *i64
1927 av[0] = "./nx_galx_durindex.elf" as *u8 as i64
1928 av[1] = "knowledge/status/galx_vid_paths.tsv" as *u8 as i64
1929 av[2] = "./nx_ts_dur.elf" as *u8 as i64
1930 av[3] = "knowledge/status/galx_dur.raw" as *u8 as i64
1931 av[4] = 0
1932 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
1933 sys_execve_clean("./nx_galx_durindex.elf" as *u8, av, envp)
1934 sys_exit(127)
1935 }
1936 sys_exit(0)
1937 }
1938 let st: *i64 = sys_mmap(16) as *i64
1939 sys_wait4(pid, st, 0)
1940 return pid
1941}
1942func main(argc: i64, argv: *i64) -> i64 {
1943 // port override via argv[1] (additive: no args -> production's 18090; a test instance can bind e.g. 18091)
1944 var port: i64 = VIEW_MAGIC_18090
1945 if argc >= 2 { var pv: i64 = 0; var pi: i64 = 0; let pa: *u8 = argv[1] as *u8; while pa[pi] != (0 as u8) { if pa[pi] >= (48 as u8) { if pa[pi] <= (57 as u8) { pv = pv * 10 + ((pa[pi] as i64) - 48) } } pi = pi + 1 } if pv > 0 { port = pv } }
1946 let addr: *u8 = sys_mmap(16)
1947 addr[0]=2 as u8; addr[1]=0 as u8; addr[2]=((port>>8)&0xff) as u8; addr[3]=(port&0xff) as u8
1948 addr[4]=127 as u8; addr[5]=0 as u8; addr[6]=0 as u8; addr[7]=1 as u8
1949 addr[8]=0 as u8; addr[9]=0 as u8; addr[10]=0 as u8; addr[11]=0 as u8; addr[12]=0 as u8; addr[13]=0 as u8; addr[14]=0 as u8; addr[15]=0 as u8
1950 let lfd: i64 = sys_socket(2, 1 | 0x80000, 0) // SOCK_CLOEXEC: no exec'd child (per-request remuxers, any batch) inherits the :VIEW_MAGIC_18090 listener -> never a held-port crash-loop
1951 if lfd < 0 { return 10 }
1952 let optval: *u8 = sys_mmap(4); optval[0]=1 as u8; optval[1]=0 as u8; optval[2]=0 as u8; optval[3]=0 as u8
1953 sys_setsockopt(lfd, 1, 2, optval, 4)
1954 if sys_bind(lfd, addr, 16) < 0 { return 20 }
1955 if sys_listen(lfd, 64) < 0 { return 30 }
1956 gs_vidoff_build() // build the O(1) id->path offset index once at startup (gs_vid_line uses it; full-scan fallback if stale)
1957 let cbpid: i64 = sys_fork() // R4: build the per-category (r/m/v) line indexes in a CHILD so its big reads don't persist in the long-lived parent VA
1958 if cbpid == 0 { gs_catidx_build(); sys_exit(0) }
1959 let cbst: *i64 = sys_mmap(16) as *i64
1960 sys_wait4(cbpid, cbst, 0)
1961 // NOTE: the duration-index batch is NOT boot-spawned (it was destabilising the serve on the NAS); re-trigger
1962 // it as a one-shot instead. gs_spawn_durindex() remains available for a deliberate, supervised kick.
1963 // SOVEREIGN O(1) cid->path index: (re)build in a CHILD (the 34MB TSV read stays out of the long-lived parent VA), then load it.
1964 __syscall(83, "knowledge/index" as *u8 as i64, 493, 0, 0, 0, 0) // mkdir knowledge/index (idempotent)
1965 let xbpid: i64 = sys_fork()
1966 if xbpid == 0 { gs_cidindex_build("knowledge/status/galx_cid_paths.tsv" as *u8, "knowledge/index/galx_cid.idx" as *u8, "knowledge/index/galx_cid.blob" as *u8); sys_exit(0) }
1967 let xbst: *i64 = sys_mmap(16) as *i64
1968 sys_wait4(xbpid, xbst, 0)
1969 let cidx: *NxCidx = sys_mmap(64) as *NxCidx
1970 cidx.ready = 0
1971 let cixp: *i64 = sys_mmap(16) as *i64; let cixi: *u8 = sys_read_file("knowledge/index/galx_cid.idx" as *u8, cixp)
1972 if (cixi as i64) != 0 {
1973 let cbxp: *i64 = sys_mmap(16) as *i64; let cixb: *u8 = sys_read_file("knowledge/index/galx_cid.blob" as *u8, cbxp)
1974 if (cixb as i64) != 0 { cidx.idx = cixi; cidx.blob = cixb; cidx.nb = cidx_rd64(cixi, 0); cidx.ready = 1
1975 let cm: *u8 = "gallery: sovereign O(1) cid->path index LOADED (no per-request TSV scan)\n" as *u8; sys_write(2, cm, gs_strlen(cm)) }
1976 }
1977 if cidx.ready == 0 { let cm2: *u8 = "gallery: cid index absent -> legacy TSV scan fallback\n" as *u8; sys_write(2, cm2, gs_strlen(cm2)) }
1978 // SELF-CHECK the WHOLE shell at startup (fail-LOUD in the log; never crashes -> never-brick). No JS engine here,
1979 // so this is the only automatic catch for a broken shell: JS SyntaxError, truncation, or unbalanced CSS. The
1980 // pre-deploy gate nx_galx_shell_jslint_gate is the PRIMARY guard; this is the runtime net. 256KB buffer >> shell.
1981 let shbuf: *u8 = sys_mmap(VIEW_MAGIC_262144)
1982 let shlen: i64 = gs_shell(shbuf)
1983 let sjp: *i64 = sys_mmap(16) as *i64
1984 let sjl: i64 = jslint_find_script(shbuf, shlen, sjp)
1985 var shok: i64 = 1
1986 if sjl < 0 { shok = 0; let lmn: *u8 = "gallery: shell self-check: NO inline <script>\n" as *u8; sys_write(2, lmn, gs_strlen(lmn)) }
1987 if sjl >= 0 { if jslint_scan_script(((shbuf as i64) + sjp[0]) as *u8, sjl) >= 0 { shok = 0; let lmf: *u8 = "gallery: *** SHELL JS INVALID (broken token in inline script) ***\n" as *u8; sys_write(2, lmf, gs_strlen(lmf)) } }
1988 if shell_complete(shbuf, shlen) == 0 { shok = 0; let lmc: *u8 = "gallery: *** SHELL INCOMPLETE (not <!doctype..</html> -- truncated?) ***\n" as *u8; sys_write(2, lmc, gs_strlen(lmc)) }
1989 if shell_style_balanced(shbuf, shlen) == 0 { shok = 0; let lms: *u8 = "gallery: *** SHELL CSS BRACES UNBALANCED ***\n" as *u8; sys_write(2, lms, gs_strlen(lms)) }
1990 if shok == 1 { let lmo: *u8 = "gallery: shell self-check OK (JS parses + page complete + CSS balanced)\n" as *u8; sys_write(2, lmo, gs_strlen(lmo)) }
1991 // load the durable BM25 search index ONCE in the parent; request-children inherit it via fork COW.
1992 let gal: *NxGalIdx = sys_mmap(64) as *NxGalIdx
1993 if gs_galidx_load(gal, "knowledge/index/gallery.idx" as *u8, "knowledge/index/gallery.manifest" as *u8) == 1 {
1994 let m1: *u8 = "gallery: BM25 ranked q= search ENABLED (durable index loaded)\n" as *u8; sys_write(2, m1, gs_strlen(m1))
1995 } else {
1996 let m2: *u8 = "gallery: no/stale index -> legacy substring q= fallback\n" as *u8; sys_write(2, m2, gs_strlen(m2))
1997 }
1998 let req: *u8 = sys_mmap(VIEW_MAGIC_16384)
1999 let reapst: *i64 = sys_mmap(16) as *i64
2000 while 1 == 1 {
2001 let cfd: i64 = sys_accept(lfd)
2002 if cfd < 0 { continue }
2003 let pid: i64 = sys_fork()
2004 if pid == 0 {
2005 sys_close(lfd)
2006 let rn: i64 = sys_read(cfd, req, VIEW_MAGIC_16384)
2007 if eh_find(req, rn, "GET /vid/" as *u8, 9) == 1 { gs_vid_stream(cfd, req, rn); sys_close(cfd); sys_exit(0) }
2008 var rbuf: *u8 = sys_mmap(VIEW_MAGIC_4194304)
2009 var rlen: i64 = 0
2010 if eh_find(req, rn, "GET /api/models" as *u8, 15) == 1 { rlen = gs_models(rbuf) }
2011 if rlen == 0 { if eh_find(req, rn, "GET /api/suggest" as *u8, 16) == 1 { rlen = gs_api_suggest(rbuf, req, rn) } }
2012 if rlen == 0 { if eh_find(req, rn, "GET /api/hidden" as *u8, 15) == 1 { rlen = gs_hidden_list(rbuf) } }
2013 if rlen == 0 { if eh_find(req, rn, "GET /api/durs" as *u8, 13) == 1 { rlen = gs_durs_batch(rbuf, req, rn) } }
2014 if rlen == 0 { if eh_find(req, rn, "GET /api/alltags" as *u8, 16) == 1 { rlen = gs_alltags_get(rbuf, req, rn) } }
2015 if rlen == 0 { if eh_find(req, rn, "GET /api/tagged" as *u8, 15) == 1 { rlen = gs_tagged_get(rbuf, req, rn) } }
2016 if rlen == 0 { if eh_find(req, rn, "GET /api/tags" as *u8, 13) == 1 { rlen = gs_tags_get(rbuf, req, rn) } }
2017 if rlen == 0 { if eh_find(req, rn, "GET /api/list" as *u8, 13) == 1 { rlen = gs_api_list(rbuf, req, rn, gal) } }
2018 if rlen == 0 { if eh_find(req, rn, "GET /img/" as *u8, 9) == 1 { rlen = gs_serve_png(rbuf, req, rn, cidx) } }
2019 if rlen == 0 { if eh_find(req, rn, "GET /thumb/" as *u8, 11) == 1 { rlen = gs_thumb(rbuf, req, rn, cidx) } }
2020 if rlen == 0 { if eh_find(req, rn, "GET /upscale/" as *u8, 13) == 1 { rlen = gs_upscale(rbuf, req, rn, cidx) } }
2021 if rlen == 0 { if eh_find(req, rn, "GET /vidthumb/" as *u8, 14) == 1 { rlen = gs_vidthumb(rbuf, req, rn) } }
2022 if rlen == 0 { if eh_find(req, rn, "GET /meta/" as *u8, 10) == 1 { rlen = gs_meta(rbuf, req, rn, cidx) } }
2023 if rlen == 0 { if eh_find(req, rn, "GET /state/" as *u8, 11) == 1 { rlen = gs_state(rbuf, req, rn) } }
2024 if rlen == 0 { if eh_find(req, rn, "POST /view" as *u8, 10) == 1 { rlen = gs_view(rbuf, req, rn) } }
2025 if rlen == 0 { if eh_find(req, rn, "POST /telemetry" as *u8, 15) == 1 { rlen = gs_telemetry(rbuf, req, rn) } }
2026 if rlen == 0 { if eh_find(req, rn, "POST /fav" as *u8, 9) == 1 { rlen = gs_fav(rbuf, req, rn) } }
2027 if rlen == 0 { if eh_find(req, rn, "POST /hide" as *u8, 10) == 1 { rlen = gs_hide(rbuf, req, rn) } }
2028 if rlen == 0 { if eh_find(req, rn, "POST /tag" as *u8, 9) == 1 { rlen = gs_tag(rbuf, req, rn) } }
2029 if rlen == 0 { if eh_find(req, rn, "POST /rate" as *u8, 10) == 1 { rlen = gs_rate(rbuf, req, rn) } }
2030 if rlen == 0 { if eh_find(req, rn, "POST /lora/export" as *u8, 17) == 1 { rlen = gs_lora_export(rbuf, req, rn) } }
2031 if rlen == 0 { if eh_find(req, rn, "GET / " as *u8, 6) == 1 { rlen = gs_shell(rbuf) } }
2032 if rlen == 0 { if eh_find(req, rn, "GET /?" as *u8, 6) == 1 { rlen = gs_shell(rbuf) } }
2033 if rlen == 0 { rlen = gs_404(rbuf) }
2034 sys_write(cfd, rbuf, rlen)
2035 sys_close(cfd)
2036 sys_exit(0)
2037 }
2038 sys_close(cfd)
2039 var reaped: i64 = 1
2040 while reaped > 0 { reaped = sys_wait4(0 - 1, reapst, 1) }
2041 }
2042 sys_close(lfd)
2043 return 0
2044}