code wiki / _hdl_build / nx_kvs.nx
nx_kvs.nx source
↩ module page · 226 lines · 12680 B
1// nx_kvs.nx -- KVS / kt_player URL de-obfuscator. A huge share of "legal personal download" tube sites run the
2// Kernel Video Sharing CMS, which hides the real .mp4 behind an obfuscated flashvars field:
3// video_url: 'function/0/https://host/get_file/3/<SCRAMBLED-32-hex>/aaa/bbb/name_1080p.mp4/'
4// license_code: '$<digits>'
5// The player's kt_player JS un-scrambles the 32-char hash at runtime using license_code -- which is why the real
6// URL only appears in the browser Network tab and our static harvester correctly skips the invalid string. This
7// module reproduces that de-obfuscation EXACTLY (ported verbatim from yt-dlp GenericIE._kvs_get_real_url /
8// _kvs_get_license_token) so we recover the direct URL ourselves. Faithful port -- verified by nx_kvs_gate against
9// a hand-computed token vector + the real bitchesgirls page. license_tier: ORIGINAL
10import "nx_syscalls.nx"
11const K_MAGIC_10000: i64 = 10000
12const K_MAGIC_4096: i64 = 4096
13
14func kvs_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
15func kvs_find(hay: *u8, hl: i64, needle: *u8, nl: i64, from: i64) -> i64 {
16 if nl==0 { return from }
17 var i: i64=from; let last: i64=hl-nl
18 while i<=last { var j: i64=0; var m: i64=1; while j<nl { if (hay[i+j]&0xff)!=(needle[j]&0xff){m=0;j=nl} else {j=j+1} } if m==1 {return i} i=i+1 }
19 return 0-1
20}
21func kvs_starts(s: *u8, slen: i64, pre: *u8, prelen: i64) -> i64 {
22 if slen<prelen { return 0 }
23 var i: i64=0; while i<prelen { if (s[i]&0xff)!=(pre[i]&0xff) { return 0 } i=i+1 } return 1
24}
25func kvs_next_slash(s: *u8, slen: i64, from: i64) -> i64 {
26 var i: i64=from; while i<slen { if (s[i]&0xff)==47 { return i } i=i+1 } return 0-1
27}
28
29// _kvs_get_license_token: license_code -> 32-entry token array (into tok). Returns the token count (32 when valid).
30// Verbatim: strip '$'; values=digits; modlicense=digits with '0'->'1'; center=len//2; front=int(ml[:center+1]);
31// back=int(ml[center:]); ml=str(4*abs(front-back))[:center+1]; token = [(values[i+off]+ml_digit_i)%10] for i,off.
32func kvs_license_token(lic: *u8, llen: i64, tok: *i64) -> i64 {
33 let lv: *i64 = sys_mmap(8*64) as *i64 // license_values (digit values)
34 let ml: *u8 = sys_mmap(64) // modlicense (digit chars, '0'->'1')
35 var n: i64 = 0
36 var i: i64 = 0
37 while i < llen {
38 let c: i64 = lic[i]&0xff
39 if c >= 48 { if c <= 57 {
40 lv[n] = c - 48
41 if c == 48 { ml[n] = 49 as u8 } else { ml[n] = c as u8 }
42 n = n + 1
43 } }
44 i = i + 1
45 }
46 var z: i64 = 0; while z < 32 { tok[z] = 0; z = z + 1 } // zero-fill (fallback if short)
47 if n == 0 { return 0 }
48 let center: i64 = n / 2
49 var fronthalf: i64 = 0
50 var j: i64 = 0
51 while j <= center { fronthalf = fronthalf*10 + ((ml[j]&0xff) - 48); j = j + 1 } // ml[:center+1]
52 var backhalf: i64 = 0
53 j = center
54 while j < n { backhalf = backhalf*10 + ((ml[j]&0xff) - 48); j = j + 1 } // ml[center:]
55 var diff: i64 = fronthalf - backhalf
56 if diff < 0 { diff = 0 - diff }
57 let val: i64 = 4 * diff
58 // stringify val
59 let vs: *u8 = sys_mmap(64)
60 var vk: i64 = 0
61 if val == 0 { vs[0] = 48 as u8; vk = 1 } else {
62 let t: *u8 = sys_mmap(64); var m: i64 = val; var tk: i64 = 0
63 while m > 0 { t[tk] = (48 + (m%10)) as u8; m = m/10; tk = tk + 1 }
64 var w: i64 = 0; while w < tk { vs[w] = t[tk-1-w]; w = w + 1 } vk = tk
65 }
66 var mlen: i64 = center + 1
67 if mlen > vk { mlen = vk } // str(...)[:center+1] (short-string safe)
68 var ti: i64 = 0
69 var idx: i64 = 0
70 while idx < mlen {
71 let current: i64 = (vs[idx]&0xff) - 48
72 var off: i64 = 0
73 while off < 4 {
74 let li: i64 = idx + off
75 var lvv: i64 = 0
76 if li < n { lvv = lv[li] }
77 tok[ti] = (lvv + current) % 10
78 ti = ti + 1
79 off = off + 1
80 }
81 idx = idx + 1
82 }
83 return ti
84}
85
86// _kvs_get_real_url: de-obfuscate a 'function/0/...' video_url using license_code. Non-obfuscated urls copy through.
87// The 32-char hash at path segment [3] (i.e. after /get_file/3/) is permuted by the license token's swap schedule.
88func kvs_real_url(vurl: *u8, vlen: i64, lic: *u8, llen: i64, out: *u8, cap: i64) -> i64 {
89 if kvs_starts(vurl, vlen, "function/0/" as *u8, 11) == 0 {
90 var a: i64=0; while a<vlen { if a<(cap-1) { out[a]=vurl[a] } a=a+1 } out[vlen]=0 as u8; return vlen
91 }
92 let inner: *u8 = ((vurl as i64) + 11) as *u8
93 let ilen: i64 = vlen - 11
94 let sp: i64 = kvs_find(inner, ilen, "://" as *u8, 3, 0)
95 if sp < 0 { return 0-1 }
96 let s1: i64 = kvs_next_slash(inner, ilen, sp + 3) // path slash #1 (start of path)
97 if s1 < 0 { return 0-2 }
98 let s2: i64 = kvs_next_slash(inner, ilen, s1 + 1) // #2 (after get_file)
99 if s2 < 0 { return 0-3 }
100 let s3: i64 = kvs_next_slash(inner, ilen, s2 + 1) // #3 (after the '3')
101 if s3 < 0 { return 0-4 }
102 let s4: i64 = kvs_next_slash(inner, ilen, s3 + 1) // #4 (end of hash segment)
103 if s4 < 0 { return 0-5 }
104 let hstart: i64 = s3 + 1
105 if (s4 - hstart) < 32 { return 0-6 }
106 let tok: *i64 = sys_mmap(8*32) as *i64
107 kvs_license_token(lic, llen, tok)
108 let idxs: *i64 = sys_mmap(8*32) as *i64
109 var k: i64 = 0; while k < 32 { idxs[k] = k; k = k + 1 }
110 var accum: i64 = 0
111 var src: i64 = 31
112 while src >= 0 {
113 accum = accum + tok[src]
114 let dest: i64 = (src + accum) % 32
115 let tmp: i64 = idxs[src]; idxs[src] = idxs[dest]; idxs[dest] = tmp
116 src = src - 1
117 }
118 let nh: *u8 = sys_mmap(40)
119 var h: i64 = 0; while h < 32 { nh[h] = inner[hstart + idxs[h]]; h = h + 1 }
120 // rebuild: inner[0..hstart) + permuted-hash(32) + inner[hstart+32..ilen)
121 var o: i64 = 0
122 var a: i64 = 0
123 while a < hstart { if o<(cap-1) { out[o]=inner[a]; o=o+1 } a=a+1 }
124 var b: i64 = 0
125 while b < 32 { if o<(cap-1) { out[o]=nh[b]; o=o+1 } b=b+1 }
126 var c: i64 = hstart + 32
127 while c < ilen { if o<(cap-1) { out[o]=inner[c]; o=o+1 } c=c+1 }
128 out[o]=0 as u8
129 return o
130}
131
132// value of a single-quoted flashvars field: find `key`, then copy from the next ' to the closing '. 0 if absent.
133func kvs_qval(html: *u8, hlen: i64, key: *u8, out: *u8, cap: i64) -> i64 {
134 let kl: i64 = kvs_slen(key)
135 let p: i64 = kvs_find(html, hlen, key, kl, 0)
136 if p < 0 { out[0]=0 as u8; return 0 }
137 var i: i64 = p + kl
138 var q: i64 = 0 - 1
139 while i < hlen { if (html[i]&0xff)==39 { q = i; i = hlen } else { i = i + 1 } }
140 if q < 0 { out[0]=0 as u8; return 0 }
141 var o: i64 = 0
142 var j: i64 = q + 1
143 while j < hlen { let c: i64 = html[j]&0xff; if c==39 { j = hlen } else { if o < (cap-1) { out[o]=c as u8; o=o+1 } j = j + 1 } }
144 out[o]=0 as u8
145 return o
146}
147
148// resolution score = the PARSED pixel HEIGHT from a string (URL or label). No hardcoded ladder, so 4320p (8K),
149// 2160p (4K), 1440p, or any future value all rank correctly. Recognizes "<H>p" (guarded to a sane video height
150// 100..10000 so it ignores IDs/params), "<W>x<H>" (takes the height), and small "<N>k/K" UHD aliases (height =
151// N*540: 4K->2160, 8K->4320). Returns 1 for "present but no resolution found" (still a valid fallback candidate).
152func kvs_res_score(s: *u8, slen: i64) -> i64 {
153 var best: i64 = 0
154 var i: i64 = 0
155 while i < slen {
156 let c: i64 = s[i]&0xff
157 var startrun: i64 = 0
158 if c >= 48 { if c <= 57 {
159 if i == 0 { startrun = 1 } else { let pc: i64 = s[i-1]&0xff; var pd: i64=0; if pc>=48 { if pc<=57 { pd=1 } } if pd==0 { startrun = 1 } }
160 } }
161 if startrun == 1 {
162 var v: i64 = 0
163 var j: i64 = i
164 var run: i64 = 1
165 while run == 1 { if j>=slen { run=0 } else { let d: i64=s[j]&0xff; if d>=48 { if d<=57 { v=v*10+(d-48); j=j+1 } else { run=0 } } else { run=0 } } }
166 var term: i64 = 0
167 if j < slen { term = s[j]&0xff }
168 if term == 112 { if v >= 100 { if v <= K_MAGIC_10000 { if v > best { best = v } } } } // 'p'
169 if term == 80 { if v >= 100 { if v <= K_MAGIC_10000 { if v > best { best = v } } } } // 'P'
170 if term == 120 { var v2: i64=0; var k: i64=j+1; var r2: i64=1; while r2==1 { if k>=slen { r2=0 } else { let d: i64=s[k]&0xff; if d>=48 { if d<=57 { v2=v2*10+(d-48); k=k+1 } else { r2=0 } } else { r2=0 } } } if v2>=100 { if v2<=K_MAGIC_10000 { if v2>best { best=v2 } } } } // 'x': WxH -> take the H
171 if term == 88 { var v2: i64=0; var k: i64=j+1; var r2: i64=1; while r2==1 { if k>=slen { r2=0 } else { let d: i64=s[k]&0xff; if d>=48 { if d<=57 { v2=v2*10+(d-48); k=k+1 } else { r2=0 } } else { r2=0 } } } if v2>=100 { if v2<=K_MAGIC_10000 { if v2>best { best=v2 } } } } // 'X'
172 if term == 107 { if v >= 1 { if v <= 16 { let hh: i64=v*540; if hh > best { best = hh } } } } // 'k' (4K/8K...)
173 if term == 75 { if v >= 1 { if v <= 16 { let hh: i64=v*540; if hh > best { best = hh } } } } // 'K'
174 i = j
175 } else { i = i + 1 }
176 }
177 if best == 0 { return 1 }
178 return best
179}
180// pull one flashvars field, de-obfuscate it -> out. Returns len (0 if the field is absent).
181func kvs_try_field(html: *u8, hlen: i64, field: *u8, lic: *u8, llen: i64, out: *u8, cap: i64) -> i64 {
182 let raw: *u8 = sys_mmap(K_MAGIC_4096)
183 let rl: i64 = kvs_qval(html, hlen, field, raw, K_MAGIC_4096)
184 if rl <= 0 { out[0]=0 as u8; return 0 }
185 return kvs_real_url(raw, rl, lic, llen, out, cap)
186}
187// resolution the site LABELS a field with (e.g. video_url_text: '2160p' or '4K') -- used when the filename itself
188// carries no _Np. Builds "<field>_text" and scores its value. 0 if no label.
189func kvs_label_score(html: *u8, hlen: i64, field: *u8) -> i64 {
190 let nm: *u8 = sys_mmap(64)
191 var o: i64 = 0
192 var i: i64 = 0; while field[i]!=(0 as u8) { nm[o]=field[i]; o=o+1; i=i+1 }
193 nm[o]=95 as u8; o=o+1 // '_'
194 let sfx: *u8 = "text" as *u8; var k: i64=0; while sfx[k]!=(0 as u8) { nm[o]=sfx[k]; o=o+1; k=k+1 }
195 nm[o]=0 as u8
196 let lab: *u8 = sys_mmap(64)
197 let ll: i64 = kvs_qval(html, hlen, nm, lab, 64)
198 if ll <= 0 { return 0 }
199 return kvs_res_score(lab, ll)
200}
201// progressive (directly playable in native <video>)? -- reject a manifest that snuck into video_url, since we
202// can't play/assemble HLS/DASH yet (the assembler will handle those on its own path).
203func kvs_is_prog(u: *u8, ul: i64) -> i64 {
204 if kvs_find(u, ul, ".m3u8" as *u8, 5, 0) >= 0 { return 0 }
205 if kvs_find(u, ul, ".mpd" as *u8, 4, 0) >= 0 { return 0 }
206 return 1
207}
208// PAGE-LEVEL: de-obfuscate EVERY quality (video_url / video_alt_url / video_alt_url2) and return the HIGHEST-res
209// PROGRESSIVE one -- resolution from the parsed height in the URL OR the site's _text label, whichever is larger
210// (4K/8K ranked by real pixels, no ladder). Manifest (.m3u8/.mpd) candidates are rejected here (assembler's job).
211// Audio is muxed into these progressive .mp4s (one file = video+audio). 0 if no progressive KVS media.
212func kvs_extract(html: *u8, hlen: i64, out: *u8, cap: i64) -> i64 {
213 let lic: *u8 = sys_mmap(256)
214 let llen: i64 = kvs_qval(html, hlen, "license_code" as *u8, lic, 256)
215 let cand: *u8 = sys_mmap(K_MAGIC_4096)
216 var bestlen: i64 = 0
217 var bestscore: i64 = 0 - 1
218 var cl: i64 = kvs_try_field(html, hlen, "video_url" as *u8, lic, llen, cand, K_MAGIC_4096)
219 if cl > 0 { var s: i64 = kvs_res_score(cand, cl); let ls: i64 = kvs_label_score(html, hlen, "video_url" as *u8); if ls > s { s = ls } if kvs_is_prog(cand, cl) == 0 { s = 0 - 1 } if s > bestscore { bestscore = s; bestlen = cl; var a: i64=0; while a<cl { out[a]=cand[a]; a=a+1 } out[cl]=0 as u8 } }
220 cl = kvs_try_field(html, hlen, "video_alt_url" as *u8, lic, llen, cand, K_MAGIC_4096)
221 if cl > 0 { var s: i64 = kvs_res_score(cand, cl); let ls: i64 = kvs_label_score(html, hlen, "video_alt_url" as *u8); if ls > s { s = ls } if kvs_is_prog(cand, cl) == 0 { s = 0 - 1 } if s > bestscore { bestscore = s; bestlen = cl; var a: i64=0; while a<cl { out[a]=cand[a]; a=a+1 } out[cl]=0 as u8 } }
222 cl = kvs_try_field(html, hlen, "video_alt_url2" as *u8, lic, llen, cand, K_MAGIC_4096)
223 if cl > 0 { var s: i64 = kvs_res_score(cand, cl); let ls: i64 = kvs_label_score(html, hlen, "video_alt_url2" as *u8); if ls > s { s = ls } if kvs_is_prog(cand, cl) == 0 { s = 0 - 1 } if s > bestscore { bestscore = s; bestlen = cl; var a: i64=0; while a<cl { out[a]=cand[a]; a=a+1 } out[cl]=0 as u8 } }
224 if bestlen == 0 { out[0]=0 as u8; return 0 }
225 return bestlen
226}