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>&#9829; Favorites</button><button class=fbtn data-f=rated>Rated</button><button class=fbtn data-f=viewed>Viewed</button><button class=fbtn data-f=recordings>&#9658; Recordings</button><button class=fbtn data-f=media>&#128250; Media</button><button class=fbtn data-f=videos>&#127916; 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'>&#9829;&#8594;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&#8594;Z</option><option value=nza>Name Z&#8594;A</option></select><button id=rnd class=fbtn title='Jump to a random spot in the library'>&#127922; 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)'>&#128205;<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>&#127991;</button><div id=tagcloud></div><button id=selfab onclick=toggleSelMode() title=Select>&#9745;</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=='<'?'&lt;':c=='>'?'&gt;':'&amp;'})}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>&times;</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='&#9658;';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>&#9658;</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>&#9974;</button><a id=pdl href=# download title=download>&#8681;</a><button id=phide title=hide>&#128465;</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>&#8599; Original size</a><a id=idl download style=color:#fff;text-decoration:none;font-size:14px>&#8681; Download</a><a id=iup target=_blank style=color:#fff;text-decoration:none;font-size:14px>&#10530; 2&#215; Upscale</a></div></div><div id=tagbar></div><span id=x>&times;</span><span class=nav id=pv>&#8249;</span><span class=nav id=nx>&#8250;</span><div id=side><button id=favbtn>&#9829; 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='&#10073;&#10073;';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='&#10073;&#10073;'});lbv.addEventListener('pause',function(){pp.innerHTML='&#9658;'});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}