code wiki / _hdl_build / nx_ia_resolve.nx

nx_ia_resolve.nx source

↩ module page · 97 lines · 5533 B

1// nx_ia_resolve.nx -- resolve an archive.org /details/ page to the actual media file URL via the sanctioned 2// public /metadata/ API. A details page is an HTML viewer that loads the media by JS, so a static fetch archives 3// the PAGE, not the movie. This fetches https://archive.org/metadata/<id> (small JSON), reads the top-level 4// "server"+"dir" and the .mp4 (h.264 derivative) filename from "files", and builds the direct download URL. The 5// search engine / archive daemon calls this before preserving an archive.org item. license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_x509_trust_store.nx" 8import "nx_browser_fetch.nx" 9const K_MAGIC_1024: i64 = 1024 10const K_MAGIC_4194304: i64 = 4194304 11const K_MAGIC_2048: i64 = 2048 12 13func ia_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 14func ia_puts(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){dst[off]=s[i];off=off+1;i=i+1} return off } 15func ia_find(hay: *u8, hl: i64, needle: *u8, nl: i64, from: i64) -> i64 { 16 if nl==0 { return from } var i: i64=from; let last: i64=hl-nl 17 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 } return 0-1 18} 19// identifier from a /details/<id> URL (to next '/' or end) 20func ia_identifier(url: *u8, ulen: i64, out: *u8, cap: i64) -> i64 { 21 let p: i64 = ia_find(url, ulen, "/details/" as *u8, 9, 0) 22 if p < 0 { out[0]=0 as u8; return 0 } 23 var i: i64 = p + 9; var o: i64 = 0 24 var go: i64 = 1 25 while go == 1 { if i>=ulen { go=0 } else { let c: i64=url[i]&0xff; if c==47 { go=0 } else { if c==63 { go=0 } else { if o<(cap-1){out[o]=c as u8;o=o+1} i=i+1 } } } } 26 out[o]=0 as u8; return o 27} 28// read a JSON string value that follows `keyq` (e.g. "\"server\":\"") into out, until the closing quote 29func ia_json_str(json: *u8, jlen: i64, keyq: *u8, out: *u8, cap: i64) -> i64 { 30 let kl: i64 = ia_slen(keyq) 31 let p: i64 = ia_find(json, jlen, keyq, kl, 0) 32 if p < 0 { out[0]=0 as u8; return 0 } 33 var i: i64 = p + kl; var o: i64 = 0 34 var go: i64 = 1 35 while go == 1 { if i>=jlen { go=0 } else { let c: i64=json[i]&0xff; if c==34 { go=0 } else { if c==92 { if o<(cap-1){out[o]=json[i+1];o=o+1} i=i+2 } else { if o<(cap-1){out[o]=c as u8;o=o+1} i=i+1 } } } } 36 out[o]=0 as u8; return o 37} 38// find the first "name":"...mp4" value (the h.264 derivative), into out 39func ia_find_mp4(json: *u8, jlen: i64, out: *u8, cap: i64) -> i64 { 40 var from: i64 = 0 41 var go: i64 = 1 42 while go == 1 { 43 let p: i64 = ia_find(json, jlen, "\"name\":\"" as *u8, 8, from) 44 if p < 0 { go = 0 } 45 else { 46 var i: i64 = p + 8; var o: i64 = 0 47 let nm: *u8 = out 48 var g2: i64 = 1 49 while g2 == 1 { if i>=jlen { g2=0 } else { let c: i64=json[i]&0xff; if c==34 { g2=0 } else { if o<(cap-1){nm[o]=c as u8;o=o+1} i=i+1 } } } 50 nm[o]=0 as u8 51 if o >= 4 { if (nm[o-4]&0xff)==46 { if (nm[o-3]&0xff)==109 { if (nm[o-2]&0xff)==112 { if (nm[o-1]&0xff)==52 { return o } } } } } // ends ".mp4" 52 from = i + 1 53 } 54 } 55 out[0]=0 as u8; return 0 56} 57// percent-encode a path segment (keep A-Za-z0-9 . _ - / ~ ; encode the rest incl space, comma, etc.) 58func ia_urlencode(s: *u8, slen: i64, out: *u8, cap: i64) -> i64 { 59 let hexd: *u8 = "0123456789ABCDEF" as *u8 60 var o: i64 = 0; var i: i64 = 0 61 while i < slen { 62 let c: i64 = s[i]&0xff 63 var safe: i64 = 0 64 if c>=48 { if c<=57 { safe=1 } } if c>=65 { if c<=90 { safe=1 } } if c>=97 { if c<=122 { safe=1 } } 65 if c==46 { safe=1 } if c==95 { safe=1 } if c==45 { safe=1 } if c==47 { safe=1 } if c==126 { safe=1 } 66 if safe==1 { if o<(cap-1){out[o]=c as u8;o=o+1} } else { if o<(cap-4){ out[o]=37 as u8; out[o+1]=hexd[(c>>4)&0xf]; out[o+2]=hexd[c&0xf]; o=o+3 } } 67 i=i+1 68 } 69 out[o]=0 as u8; return o 70} 71// RESOLVE a details URL -> the direct media download URL (fetches /metadata/ over TLS). Returns len (0 = fail). 72func ia_resolve(details_url: *u8, ulen: i64, store: *TrustStore, cr: *u8, pk: *u8, now: i64, out_url: *u8, cap: i64) -> i64 { 73 let id: *u8 = sys_mmap(K_MAGIC_1024) 74 let idl: i64 = ia_identifier(details_url, ulen, id, K_MAGIC_1024) 75 if idl == 0 { return 0 } 76 let meta: *u8 = sys_mmap(K_MAGIC_1024) 77 var mo: i64 = ia_puts(meta, 0, "https://archive.org/metadata/" as *u8); mo = ia_puts(meta, mo, id); meta[mo]=0 as u8 78 let resp: *u8 = sys_mmap(K_MAGIC_4194304) // metadata JSON is small (KBs) 79 let n: i64 = bf_fetch_follow(meta, store, cr, pk, now, resp, K_MAGIC_4194304, 5) 80 if n <= 0 { return 0 } 81 let boff: i64 = bf_body_off(resp, n) 82 let body: *u8 = ((resp as i64)+boff) as *u8 83 let blen: i64 = n - boff 84 let server: *u8 = sys_mmap(512); ia_json_str(body, blen, "\"server\":\"" as *u8, server, 512) 85 let dir: *u8 = sys_mmap(K_MAGIC_1024); ia_json_str(body, blen, "\"dir\":\"" as *u8, dir, K_MAGIC_1024) 86 let name: *u8 = sys_mmap(K_MAGIC_1024); let nl: i64 = ia_find_mp4(body, blen, name, K_MAGIC_1024) 87 if nl == 0 { return 0 } 88 if server[0] == (0 as u8) { return 0 } 89 var o: i64 = ia_puts(out_url, 0, "https://" as *u8) 90 o = ia_puts(out_url, o, server) 91 o = ia_puts(out_url, o, dir) 92 out_url[o]=47 as u8; o=o+1 // '/' 93 let enc: *u8 = sys_mmap(K_MAGIC_2048); ia_urlencode(name, nl, enc, K_MAGIC_2048) 94 o = ia_puts(out_url, o, enc) 95 out_url[o]=0 as u8 96 return o 97}