nx_galx_vidindex_nas.nx source
↩ module page · 93 lines · 4906 B
1// nx_galx_vidindex_nas.nx -- NAS-NATIVE recordings reindex (operator 2026-06-23: "investigate and resolve").
2// ROOT CAUSE FOUND: the gallery's video catalog pointed at /volume1/logging/#recycle/<model>/*.ts (the
3// Synology TRASH) while the LIVE recordings are at /volume1/logging/<model>/*.ts -> serve 404s on every
4// video. This runs ON THE NAS (via nx_nas_run): scans /volume1/logging natively (sys_getdents64), SKIPS
5// #recycle + @eaDir + .trickplay, writes the fresh catalog to a .new STAGING file (reversible; promote
6// after verify). NAS-native /volume1/... paths = exactly what the serve opens. No sh. license_tier: ORIGINAL
7import "nx_syscalls.nx"
8import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
9const VI_MAGIC_2048: i64 = 2048
10
11const GBUF: i64 = 65536
12const VI_SCAN: *u8 = "/volume1/logging"
13const VI_SCAN2: *u8 = "/volume1/logs" // 2026-07-11: the SECOND recordings tree (29.3 TB / ~14k .ts) was never indexed
14const VI_OUT: *u8 = "/volume1/ai/galx/knowledge/status/galx_vid_paths.tsv.new" // STAGING; promote after verify
15
16func vi_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
17// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
18// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
19// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
20// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
21func vi_n(v: i64) -> i64 { nxi_out(v); return 0 }
22func vi_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
23func vi_is_vid(name: *u8) -> i64 {
24 let n: i64 = vi_len(name)
25 if n >= 3 { if name[n-3]==(46 as u8) { if name[n-2]==(116 as u8) { if name[n-1]==(115 as u8) { return 1 } } } } // .ts
26 if n >= 4 { if name[n-4]==(46 as u8) {
27 if name[n-3]==(109 as u8) { if name[n-2]==(112 as u8) { if name[n-1]==(52 as u8) { return 1 } } } // .mp4
28 if name[n-3]==(109 as u8) { if name[n-2]==(107 as u8) { if name[n-1]==(118 as u8) { return 1 } } } // .mkv
29 if name[n-3]==(102 as u8) { if name[n-2]==(108 as u8) { if name[n-1]==(118 as u8) { return 1 } } } // .flv
30 } }
31 return 0
32}
33func vi_is_trick(name: *u8) -> i64 {
34 let n: i64 = vi_len(name)
35 let suf: *u8 = ".trickplay" as *u8
36 if n < 10 { return 0 }
37 var i: i64 = 0
38 while i < 10 { if name[n-10+i] != suf[i] { return 0 } i = i + 1 }
39 return 1
40}
41func vi_walk(dir: *u8, depth: i64, outfd: i64, cntp: *i64) -> i64 {
42 if depth > 6 { return 0 }
43 let fd: i64 = sys_openat_rd(dir)
44 if fd < 0 { return 0 }
45 let gbuf: *u8 = sys_mmap(GBUF)
46 let child: *u8 = sys_mmap(VI_MAGIC_2048)
47 let dlen: i64 = vi_len(dir)
48 var go: i64 = 1
49 while go == 1 {
50 let n: i64 = sys_getdents64(fd, gbuf, GBUF)
51 if n <= 0 { go = 0 } else {
52 var off: i64 = 0
53 while off < n {
54 let rec: *u8 = ((gbuf as i64) + off) as *u8
55 let reclen: i64 = dirent_reclen(rec)
56 let typ: i64 = dirent_type(rec)
57 let name: *u8 = dirent_name(rec)
58 var skip: i64 = 0
59 if name[0]==(46 as u8) { if name[1]==(0 as u8) { skip=1 } else { if name[1]==(46 as u8) { if name[2]==(0 as u8) { skip=1 } } } }
60 if name[0]==(35 as u8) { skip=1 } // '#recycle'
61 if name[0]==(64 as u8) { skip=1 } // '@eaDir' (Synology metadata)
62 if skip == 0 {
63 var co: i64 = 0
64 while co < dlen { child[co]=dir[co]; co=co+1 }
65 child[co]=47 as u8; co=co+1
66 var ni: i64 = 0
67 while name[ni]!=(0 as u8) { child[co]=name[ni]; co=co+1; ni=ni+1 }
68 child[co]=0 as u8
69 if vi_is_vid(name)==1 {
70 sys_write(outfd, child, co); sys_write(outfd, "\n" as *u8, 1); cntp[0]=cntp[0]+1
71 } else {
72 if vi_is_trick(name)==0 { if typ != DT_REG { vi_walk(child, depth+1, outfd, cntp) } }
73 }
74 }
75 if reclen <= 0 { off = n } else { off = off + reclen }
76 }
77 }
78 }
79 sys_close(fd)
80 return 0
81}
82func main(argc: i64, argv: *i64) -> i64 {
83 let outfd: i64 = sys_openat_wr(VI_OUT, 0x1a4)
84 if outfd < 0 { vi_p("VIDINDEX-NAS FAIL: cannot write " as *u8); vi_p(VI_OUT); vi_p(" (run ON the NAS)\n" as *u8); sys_exit(1); return 1 }
85 let cntp: *i64 = sys_mmap(16) as *i64
86 cntp[0] = 0
87 vi_walk(VI_SCAN, 0, outfd, cntp)
88 vi_walk(VI_SCAN2, 0, outfd, cntp) // index the second recordings tree too (/volume1/logs)
89 sys_close(outfd)
90 vi_p("VIDINDEX-NAS OK live_recordings=" as *u8); vi_n(cntp[0]); vi_p(" -> " as *u8); vi_p(VI_OUT); vi_p("\n" as *u8)
91 sys_exit(0)
92 return 0
93}