code wiki / _hdl_build / nx_media_state.nx

nx_media_state.nx source

↩ module page · 124 lines · 6091 B

1// nx_media_state.nx -- EMBEDDED-STATE stream extraction (the yt-dlp / hanime-plugin technique): a modern SSR 2// site bakes its initial state as a JSON blob in the HTML (window.__NUXT__, ytInitialPlayerResponse, 3// __INITIAL_STATE__, __NEXT_DATA__, __APOLLO_STATE__), and that blob ALREADY contains the stream URLs -- so 4// you extract it directly, NO bundle execution needed. This is the cheapest, most robust discovery layer 5// (below JS-exec). Balanced-brace + string-aware (a `{` inside a JSON string doesn't break the scan). Learned 6// from cynthia2006/hanime-plugin (deepwiki 2026-07-10): "__NUXT__ state / JSON APIs". license_tier: ORIGINAL 7import "nx_syscalls.nx" 8 9func ms_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 10func ms_find(hay: *u8, hl: i64, needle: *u8, nl: i64, from: i64) -> i64 { 11 if nl == 0 { return from } 12 var i: i64 = from; let last: i64 = hl - nl 13 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 } 14 return 0 - 1 15} 16func ms_contains(hay: *u8, hl: i64, needle: *u8, nl: i64) -> i64 { if ms_find(hay, hl, needle, nl, 0) >= 0 { return 1 } return 0 } 17// is this URL a media/stream resource? (substring on extensions/manifest markers) 18func ms_is_media(u: *u8, ul: i64) -> i64 { 19 if ms_contains(u, ul, ".m3u8" as *u8, 5) == 1 { return 1 } 20 if ms_contains(u, ul, ".mpd" as *u8, 4) == 1 { return 1 } 21 if ms_contains(u, ul, ".mp4" as *u8, 4) == 1 { return 1 } 22 if ms_contains(u, ul, ".m4s" as *u8, 4) == 1 { return 1 } 23 if ms_contains(u, ul, ".webm" as *u8, 5) == 1 { return 1 } 24 if ms_contains(u, ul, ".mkv" as *u8, 4) == 1 { return 1 } 25 if ms_contains(u, ul, ".mov" as *u8, 4) == 1 { return 1 } 26 if ms_contains(u, ul, ".ts" as *u8, 3) == 1 { return 1 } 27 return 0 28} 29 30// extract the balanced {..} or [..] JSON value that STARTS at html[start]. String-aware (braces inside "..." 31// are ignored; \-escapes handled). Copies verbatim into out; returns length. 32func ms_extract_json_value(html: *u8, start: i64, hlen: i64, out: *u8, cap: i64) -> i64 { 33 let open: i64 = html[start] & 0xff 34 var close: i64 = 125 // '}' 35 if open == 91 { close = 93 } // '[' -> ']' 36 var depth: i64 = 0 37 var instr: i64 = 0 38 var esc: i64 = 0 39 var w: i64 = 0 40 var i: i64 = start 41 var go: i64 = 1 42 while go == 1 { 43 if i >= hlen { go = 0 } 44 else { 45 let c: i64 = html[i] & 0xff 46 if w < (cap - 1) { out[w] = c as u8; w = w + 1 } 47 if instr == 1 { 48 if esc == 1 { esc = 0 } 49 else { if c == 92 { esc = 1 } else { if c == 34 { instr = 0 } } } 50 } else { 51 if c == 34 { instr = 1 } 52 else { if c == open { depth = depth + 1 } else { if c == close { depth = depth - 1; if depth == 0 { go = 0 } } } } 53 } 54 i = i + 1 55 } 56 } 57 out[w] = 0 as u8 58 return w 59} 60// find `<marker>` in html, then the following `= {..}` / `= [..]` and extract the balanced JSON value. The 61// marker is e.g. "__NUXT__" / "ytInitialPlayerResponse" / "__INITIAL_STATE__". Returns value length or 0. 62func ms_extract_state(html: *u8, hlen: i64, marker: *u8, out: *u8, cap: i64) -> i64 { 63 let ml: i64 = ms_slen(marker) 64 let mpos: i64 = ms_find(html, hlen, marker, ml, 0) 65 if mpos < 0 { return 0 } 66 var i: i64 = mpos + ml 67 // skip to '=' (bounded; the marker must be an assignment target) 68 var guard: i64 = 0 69 var feq: i64 = 0 70 while feq == 0 { 71 if i >= hlen { return 0 } 72 if guard > 60 { return 0 } 73 if (html[i] & 0xff) == 61 { feq = 1; i = i + 1 } else { i = i + 1; guard = guard + 1 } 74 } 75 // skip to the opening '{' or '[' 76 guard = 0 77 var fop: i64 = 0 78 while fop == 0 { 79 if i >= hlen { return 0 } 80 if guard > 60 { return 0 } 81 let c: i64 = html[i] & 0xff 82 if c == 123 { fop = 1 } else { if c == 91 { fop = 1 } else { i = i + 1; guard = guard + 1 } } 83 } 84 return ms_extract_json_value(html, i, hlen, out, cap) 85} 86 87// scan a state blob for MEDIA URLs (http/https ... media-ext), unescaping JSON `\/` -> `/`, dedup, newline-sep 88// into `out`. Returns count. This turns an extracted __NUXT__/player-response blob into a download plan. 89func ms_find_streams(blob: *u8, blen: i64, out: *u8, cap: i64) -> i64 { 90 let url: *u8 = sys_mmap(4096) 91 var count: i64 = 0 92 var wp: i64 = 0 93 var i: i64 = 0 94 while i < blen { 95 var hit: i64 = 0 96 if ms_find(blob, i + 6, "https:" as *u8, 6, i) == i { hit = 1 } // match `https:` (not `//`) so 97 if hit == 0 { if ms_find(blob, i + 5, "http:" as *u8, 5, i) == i { hit = 1 } } // JSON-escaped `\/\/` still matches 98 if hit == 1 { 99 var k: i64 = 0 100 var j: i64 = i 101 var scan: i64 = 1 102 while scan == 1 { 103 if j >= blen { scan = 0 } 104 else { 105 let c: i64 = blob[j] & 0xff 106 if c == 92 { if (j + 1) < blen { if (blob[j+1]&0xff) == 47 { if k<4095 { url[k]=47 as u8; k=k+1 } j=j+2 } else { scan=0 } } else { scan=0 } } // \/ -> / 107 else { 108 if c == 34 { scan=0 } else { if c == 39 { scan=0 } else { if c == 32 { scan=0 } else { if c == 60 { scan=0 } else { if c == 44 { scan=0 } else { if c == 125 { scan=0 } else { if c == 93 { scan=0 } else { if c == 9 { scan=0 } else { if c == 10 { scan=0 } else { 109 if k < 4095 { url[k] = c as u8; k = k + 1 } j = j + 1 110 } } } } } } } } } } 111 } 112 } 113 url[k] = 0 as u8 114 if ms_is_media(url, k) == 1 { 115 if ms_contains(out, wp, url, k) == 0 { 116 if (wp + k + 1) < cap { var a: i64=0; while a<k { out[wp]=url[a]; wp=wp+1; a=a+1 } out[wp]=10 as u8; wp=wp+1; count=count+1 } 117 } 118 } 119 i = j 120 } else { i = i + 1 } 121 } 122 out[wp] = 0 as u8 123 return count 124}