nx_media_player.nx source
↩ module page · 125 lines · 6535 B
1// nx_media_player.nx -- EXPOSURE rung X3: a privacy-respecting player/viewer.
2// "What am I watching" shown IN THE PLAYER (info panel), never in the URL.
3// Emits knowledge/staging/media/player.html: a stage (img/video by type) + an
4// info panel (title/type/resolution/person-present/skin, extensible to
5// face/preference/mood tags) + prev/next. The URL only ever holds an OPAQUE
6// index (#3) -- the filename/path lives in the in-page data + panel, so the
7// address bar leaks nothing. Metadata via the nx_media_index tagger.
8//
9// Sovereign: syscalls + nx_media_index. license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "nx_media_index.nx"
12const K_MAGIC_4096: i64 = 4096
13const K_MAGIC_4095: i64 = 4095
14
15func gp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
16func gnum(v: i64) -> i64 {
17 let bb: *u8 = sys_mmap(28)
18 var m: i64 = v
19 if m < 0 { sys_write(1, "-\x00" as *u8, 1); m = 0 - m }
20 let t: *u8 = sys_mmap(28)
21 var k: i64 = 0
22 if m == 0 { t[0] = 48 as u8; k = 1 }
23 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
24 var i: i64 = 0
25 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
26 sys_write(1, bb, k)
27 return 0
28}
29func fps(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
30func fnum(fd: i64, v: i64) -> i64 {
31 let bb: *u8 = sys_mmap(28)
32 var m: i64 = v
33 if m < 0 { sys_write(fd, "-\x00" as *u8, 1); m = 0 - m }
34 let t: *u8 = sys_mmap(28)
35 var k: i64 = 0
36 if m == 0 { t[0] = 48 as u8; k = 1 }
37 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
38 var i: i64 = 0
39 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
40 sys_write(fd, bb, k)
41 return 0
42}
43func strip_prefix(s: *u8, pre: *u8) -> i64 {
44 var i: i64 = 0
45 while pre[i] != (0 as u8) { if s[i] != pre[i] { return 0 } i = i + 1 }
46 return i
47}
48// write the basename (after the last '/') of a path to fd -- friendly title,
49// no directory leaked
50func fps_base(fd: i64, s: *u8) -> i64 {
51 var n: i64 = 0
52 var last: i64 = 0 - 1
53 while s[n] != (0 as u8) { if (s[n] as i64) == 47 { last = n } n = n + 1 }
54 var i: i64 = last + 1
55 while i < n { sys_write(fd, (s as i64 + i) as *u8, 1); i = i + 1 }
56 return 0
57}
58
59func main() -> i64 {
60 let szp: *i64 = sys_mmap(16) as *i64
61 let buf: *u8 = sys_read_file("knowledge/staging/media/idx_in.txt\x00" as *u8, szp)
62 if (buf as i64) == 0 { gp("nx_media_player: no idx_in.txt\n\x00" as *u8); return 1 }
63 let len: i64 = szp[0]
64 let fd: i64 = sys_openat_wr("knowledge/staging/media/player.html\x00" as *u8, 420)
65 if fd < 0 { gp("nx_media_player: cannot write html\n\x00" as *u8); return 2 }
66
67 fps(fd, "<!doctype html><html><head><meta charset=utf-8><title>Nishi Player</title><style>\x00" as *u8)
68 fps(fd, "body{background:#0c0c0c;color:#eee;font-family:sans-serif;margin:0;display:flex;height:100vh}\x00" as *u8)
69 fps(fd, "#stage{flex:1;display:flex;align-items:center;justify-content:center;background:#000}\x00" as *u8)
70 fps(fd, "#stage img,#stage video{max-width:100%;max-height:100vh}\x00" as *u8)
71 fps(fd, "#side{width:300px;padding:16px;background:#161616;overflow:auto}\x00" as *u8)
72 fps(fd, "#title{font-size:15px;font-weight:bold;word-break:break-all}.row{margin-top:8px;font-size:13px;color:#bbb}\x00" as *u8)
73 fps(fd, ".present{color:#39ff14;font-weight:bold}.absent{color:#888}.nav{margin-top:14px}button{background:#333;color:#eee;border:0;padding:6px 12px;margin-right:6px;cursor:pointer}\x00" as *u8)
74 fps(fd, "</style></head><body><div id=stage></div><div id=side><div id=title></div>\x00" as *u8)
75 fps(fd, "<div class=row id=meta></div><div class=row id=detect></div>\x00" as *u8)
76 fps(fd, "<div class=nav><button onclick=go(-1)>← prev</button><button onclick=go(1)>next →</button></div>\x00" as *u8)
77 fps(fd, "<div class=row style=color:#555;margin-top:18px>URL stays opaque (index only); info lives here, not in the address bar.</div></div>\x00" as *u8)
78 fps(fd, "<script>var M=[\x00" as *u8)
79
80 let pbuf: *u8 = sys_mmap(K_MAGIC_4096)
81 let out: *i64 = sys_mmap(128) as *i64
82 var count: i64 = 0
83 var present: i64 = 0
84 var i: i64 = 0
85 while i < len {
86 var j: i64 = i
87 while j < len && (buf[j] as i64) != 10 { j = j + 1 }
88 var end: i64 = j
89 if end > i && (buf[end - 1] as i64) == 13 { end = end - 1 }
90 let ll: i64 = end - i
91 if ll > 0 {
92 var k: i64 = 0
93 while k < ll && k < K_MAGIC_4095 { pbuf[k] = buf[i + k]; k = k + 1 }
94 pbuf[k] = 0 as u8
95 nx_mindex_tag_path(pbuf, out)
96 if out[0] == NX_MIDX_OK {
97 if out[5] == 1 { present = present + 1 }
98 let off: i64 = strip_prefix(pbuf, "knowledge/staging/media/\x00" as *u8)
99 let src: *u8 = (pbuf as i64 + off) as *u8
100 fps(fd, "{n:\"\x00" as *u8); fps_base(fd, pbuf); fps(fd, "\",s:\"\x00" as *u8); fps(fd, src)
101 fps(fd, "\",t:\"image\",w:\x00" as *u8); fnum(fd, out[1]); fps(fd, ",h:\x00" as *u8); fnum(fd, out[2])
102 fps(fd, ",p:\x00" as *u8); fnum(fd, out[5]); fps(fd, ",k:\x00" as *u8); fnum(fd, out[3]); fps(fd, "},\x00" as *u8)
103 count = count + 1
104 }
105 }
106 i = j + 1
107 }
108
109 fps(fd, "];var cur=0;function go(d){show(cur+d);}\x00" as *u8)
110 fps(fd, "function show(i){if(i<0)i=0;if(i>=M.length)i=M.length-1;cur=i;var m=M[i];\x00" as *u8)
111 fps(fd, "var st=document.getElementById('stage');\x00" as *u8)
112 fps(fd, "st.innerHTML=(m.t=='video')?('<video controls autoplay src=\"'+m.s+'\"></video>'):('<img src=\"'+m.s+'\">');\x00" as *u8)
113 fps(fd, "document.getElementById('title').textContent=m.n;\x00" as *u8)
114 fps(fd, "document.getElementById('meta').textContent=m.t+' '+m.w+'x'+m.h+' ('+(i+1)+'/'+M.length+')';\x00" as *u8)
115 fps(fd, "document.getElementById('detect').innerHTML=(m.p?'<span class=present>person present</span>':'<span class=absent>no person</span>')+' skin '+m.k+'permille';\x00" as *u8)
116 fps(fd, "location.hash=i;}\x00" as *u8)
117 fps(fd, "var h=parseInt(location.hash.slice(1));show(isNaN(h)?0:h);\x00" as *u8)
118 fps(fd, "</script></body></html>\n\x00" as *u8)
119 sys_close(fd)
120
121 gp("nx_media_player items=\x00" as *u8); gnum(count)
122 gp(" present=\x00" as *u8); gnum(present)
123 gp(" -> knowledge/staging/media/player.html (URL=opaque index; info in panel)\n\x00" as *u8)
124 return 0
125}