code wiki / _hdl_build / nx_vk_js.nx
nx_vk_js.nx source
↩ module page · 125 lines · 8394 B
1// nx_vk_js.nx -- structural probe of a VK video page to decide the extraction path. VK's stream is NOT in the
2// static HTML (native classifier conf=0) but al_video.php (its AJAX video API) appears -> the page either (a)
3// embeds initial player state in an INLINE script we can run/parse (like YouTube's ytInitialPlayerResponse), or
4// (b) is a pure JS shell whose EXTERNAL bundle fetches al_video.php at runtime. This dumps inline-script size +
5// the al_video.php call context + stream markers so we know which. Honest probe, no download.
6import "nx_syscalls.nx"
7import "nx_x509_trust_store.nx"
8import "nx_trust_store_load_from_certdata.nx"
9import "nx_video_sniff.nx"
10import "nx_video_sniff_fetch.nx"
11import "nx_surrogate.nx"
12const K_MAGIC_4194304: i64 = 4194304
13const K_MAGIC_8388608: i64 = 8388608
14const K_MAGIC_65536: i64 = 65536
15const K_MAGIC_16384: i64 = 16384
16const K_MAGIC_4096: i64 = 4096
17
18func pw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
19func pn(v: i64) -> i64 { let b: *u8=sys_mmap(24); var m: i64=v; if m<0{pw("-" as *u8);m=0-m} let t: *u8=sys_mmap(24); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
20func plen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
21func ci_eq(src: *u8, at: i64, n: i64, pat: *u8, pl: i64) -> i64 {
22 if at + pl > n { return 0 }
23 var k: i64 = 0
24 while k < pl { var c: i64 = src[at + k] & 0xff; if c >= 65 { if c <= 90 { c = c + 32 } } if c != (pat[k] & 0xff) { return 0 } k = k + 1 }
25 return 1
26}
27func find_ci(src: *u8, n: i64, pat: *u8, from: i64) -> i64 {
28 let pl: i64 = plen(pat)
29 var i: i64 = from
30 while i + pl <= n { if ci_eq(src, i, n, pat, pl) == 1 { return i } i = i + 1 }
31 return 0 - 1
32}
33func count_ci(src: *u8, n: i64, pat: *u8) -> i64 {
34 let pl: i64 = plen(pat)
35 var i: i64 = 0
36 var c: i64 = 0
37 while i + pl <= n { if ci_eq(src, i, n, pat, pl) == 1 { c = c + 1; i = i + pl } else { i = i + 1 } }
38 return c
39}
40// dump n bytes of src from off (printable only, others -> '.')
41func dump(src: *u8, off: i64, n: i64, total: i64) -> i64 {
42 var i: i64 = 0
43 while i < n { if off + i < total { let c: i64 = src[off + i] & 0xff; if c >= 32 { if c < 127 { sys_write(1, ((src as i64) + off + i) as *u8, 1) } else { pw("." as *u8) } } else { pw("." as *u8) } } i = i + 1 }
44 return 0
45}
46
47func main(argc: i64, argv: *i64) -> i64 {
48 var url: *u8 = "https://vk.com/video-228819579_456243195" as *u8
49 if argc >= 2 { url = argv[1] as *u8 }
50 let r: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, 512, K_MAGIC_4194304)
51 if r <= 0 { pw("certdata load failed\n" as *u8); return 1 }
52 let store: *TrustStore = r as *TrustStore
53 let status: *i64 = sys_mmap(8) as *i64
54 let cap: i64 = K_MAGIC_8388608
55 let html: *u8 = sys_mmap(cap)
56 let hn: i64 = nx_https_fetch_follow(url, store, html, cap, 6, status)
57 pw("== nx_vk_js == status=" as *u8); pn(status[0]); pw(" bytes=" as *u8); pn(hn); pw("\n" as *u8)
58 if hn <= 0 { pw("(fetch failed)\n" as *u8); return 0 }
59 // structural signals
60 pw("inline-ish markers: <script=" as *u8); pn(count_ci(html, hn, "<script" as *u8))
61 pw(" script-src=" as *u8); pn(count_ci(html, hn, "<script src" as *u8))
62 pw(" src=\"/=" as *u8); pn(count_ci(html, hn, "src=\"/" as *u8)); pw("\n" as *u8)
63 pw("state markers: mvData=" as *u8); pn(count_ci(html, hn, "mvData" as *u8))
64 pw(" playerParams=" as *u8); pn(count_ci(html, hn, "playerParams" as *u8))
65 pw(" cache={=" as *u8); pn(count_ci(html, hn, "\"cache\"" as *u8))
66 pw(" \"hash\"=" as *u8); pn(count_ci(html, hn, "\"hash\"" as *u8))
67 pw(" \"url\"=" as *u8); pn(count_ci(html, hn, "\"url" as *u8))
68 pw(" hls=" as *u8); pn(count_ci(html, hn, "hls" as *u8))
69 pw(" .mp4=" as *u8); pn(count_ci(html, hn, ".mp4" as *u8)); pw("\n" as *u8)
70 // dump all "url contexts (candidate stream URLs) + search for video-data + the video id
71 pw("-- \"url occurrences --\n" as *u8)
72 var uf: i64 = 0
73 var un: i64 = 0
74 while uf >= 0 { uf = find_ci(html, hn, "\"url" as *u8, uf); if uf >= 0 { pw(" ["); pn(un); pw("] "); dump(html, uf, 150, hn); pw("\n" as *u8); uf = uf + 4; un = un + 1 } }
75 pw("-- markers: videoid228=" as *u8); pn(count_ci(html, hn, "228819579" as *u8))
76 pw(" video_ext=" as *u8); pn(count_ci(html, hn, "video_ext" as *u8))
77 pw(" userapi=" as *u8); pn(count_ci(html, hn, "userapi" as *u8))
78 pw(" video.php=" as *u8); pn(count_ci(html, hn, "video.php" as *u8))
79 pw(" __start=" as *u8); pn(count_ci(html, hn, "window.__start" as *u8))
80 pw(" cache_=" as *u8); pn(count_ci(html, hn, "cache" as *u8))
81 pw(" src=\\\"=" as *u8); pn(count_ci(html, hn, "src=\\" as *u8))
82 pw(" master=" as *u8); pn(count_ci(html, hn, "master" as *u8))
83 pw("\n" as *u8)
84 pw("-- videoid228 occurrences --\n" as *u8)
85 var vf: i64 = 0
86 var vnn: i64 = 0
87 while vf >= 0 { vf = find_ci(html, hn, "228819579" as *u8, vf); if vf >= 0 { pw(" ["); pn(vnn); pw("] "); var sv: i64 = vf - 70; if sv < 0 { sv = 0 } dump(html, sv, 180, hn); pw("\n" as *u8); vf = vf + 9; vnn = vnn + 1 } }
88 let mm: i64 = find_ci(html, hn, "master" as *u8, 0)
89 pw("-- master ctx --\n" as *u8)
90 if mm >= 0 { var sm: i64 = mm - 40; if sm < 0 { sm = 0 } dump(html, sm, 160, hn); pw("\n" as *u8) }
91 let av: i64 = 0 - 1
92 // context around the FIRST 'hls' or '.mp4' (stream URL, if embedded)
93 var st: i64 = find_ci(html, hn, ".mp4" as *u8, 0)
94 if st < 0 { st = find_ci(html, hn, "hls" as *u8, 0) }
95 pw("-- stream ctx (200B from -80) --\n" as *u8)
96 if st >= 0 { var s2: i64 = st - 80; if s2 < 0 { s2 = 0 } dump(html, s2, 200, hn); pw("\n" as *u8) } else { pw("(no .mp4/hls in HTML)\n" as *u8) }
97 // RUN vk's INLINE JS through our engine (continue-on-error) + capture the AJAX calls its framework makes.
98 // Preamble sets up document/window; js_render_page_pending_begin runs all 70 inline scripts in one genv.
99 let sgt: *i64 = sg_new(); sg_seed(sgt)
100 let extra: *u8 = sys_mmap(K_MAGIC_65536)
101 let pl2: i64 = sg_build_preamble(sgt, extra, K_MAGIC_16384)
102 extra[pl2] = 0 as u8
103 js_set_rt_dbg(1)
104 let obx: *i64 = sys_mmap(16) as *i64
105 let tr0: i64 = sys_now_us()
106 let rc: i64 = js_render_page_pending_begin(html, hn, extra, pl2, obx)
107 let tr1: i64 = sys_now_us()
108 pw("-- JS-EXEC vk inline scripts: rc=" as *u8); pn(rc); pw(" render_ms=" as *u8); pn((tr1 - tr0) / 1000); pw(" --\n" as *u8)
109 let genv: *i64 = (obx[1]) as *i64
110 if (genv as i64) == 0 { pw("(NULL genv)\n" as *u8); return 0 }
111 let t2: i64 = js_pending_total(genv)
112 pw("captured runtime fetch/XHR calls: " as *u8); pn(t2); pw("\n" as *u8)
113 let ub: *u8 = sys_mmap(K_MAGIC_4096)
114 var pi: i64 = 0
115 while pi < t2 { let ul: i64 = js_pending_url(genv, pi, ub, K_MAGIC_4096); if ul > 0 { pw(" CAPTURED " as *u8); var q: i64 = 0; while q < ul { if q < 200 { sys_write(1, ((ub as i64) + q) as *u8, 1) } q = q + 1 } pw("\n" as *u8) } pi = pi + 1 }
116 if t2 == 0 { pw(" (no runtime fetches captured -- vk framework either needs external bundles or didn't reach the al_video call)\n" as *u8) }
117 // POST-RENDER DOM inspection: what player/video/trigger surface does vk expose after its JS ran? (decides
118 // whether play-click simulation is viable -- find a player element with a handler and fire it.)
119 let probe: *u8 = ";function Q(n,v){fetch('https://p/VKD-'+n+'-'+v+'.x')}function C(s){try{return document.querySelectorAll(s).length}catch(e){return -1}}Q('video',C('video'));Q('iframe',C('iframe'));Q('source',C('source'));Q('playerdiv',C('[class*=player]'));Q('videodiv',C('[class*=video]'));Q('button',C('button'));Q('bodykids',(document.body&&document.body.childNodes)?document.body.childNodes.length:-1);try{var vs=document.getElementsByTagName('video');if(vs[0]){Q('videosrc-len',(vs[0].getAttribute('src')||'').length)}}catch(e){Q('videosrc','THREW')}" as *u8
120 js_run_more_in_genv(genv, probe, plen(probe))
121 let t3: i64 = js_pending_total(genv)
122 var pj: i64 = t2
123 while pj < t3 { let ul: i64 = js_pending_url(genv, pj, ub, K_MAGIC_4096); if ul > 0 { pw(" DOM " as *u8); var q: i64 = 0; while q < ul { if q < 160 { sys_write(1, ((ub as i64) + q) as *u8, 1) } q = q + 1 } pw("\n" as *u8) } pj = pj + 1 }
124 return 0
125}