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}