code wiki / (root) / nx_torrent_extract.nx

nx_torrent_extract.nx source

↩ module page · 201 lines · 11732 B

1// nx_torrent_extract.nx -- split a completed/partial download.part into the REAL files the torrent 2// contains, per the metadata "files" list (multi-file) or "name" (single-file). This is what turns the 3// opaque "download.part" the operator sees into a playable REBDB-1026...mkv. Reuses nx_bencode. STREAMING 4// copy (1 MiB chunks -- never mmaps the multi-GB payload). For a PARTIAL download the missing pieces are 5// zero-gaps in download.part, so the extracted media still plays ("most of a film" = the exceed axis). 6// argv[1] = the torrent folder (must contain download.meta + download.part). license_tier: ORIGINAL 7// 8// module: nishi-core.torrent.extract 9// depends: nishi-core.torrent.bencode 10// capability: TORRENT_FILE_EXTRACT 11import "nx_bencode.nx" 12const EX_MAGIC_1048576: i64 = 1048576 13const EX_MAGIC_65536: i64 = 65536 14const EX_MAGIC_2048: i64 = 2048 15 16func ex_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 17func ex_wn(v: i64) -> i64 { let t: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m; sys_write(1,"-" as *u8,1)} 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} let b: *u8=sys_mmap(28); var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 18func ex_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 19func ex_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){dst[off+i]=s[i];i=i+1} return off+ex_slen(s) } 20 21// create every directory prefix of a file path (so nested multi-file torrents work). Temporarily 22// NUL-terminates at each '/', mkdir's the prefix (EEXIST is harmless), restores. 23func ex_mkdirs(path: *u8) -> i64 { 24 var i: i64 = 0 25 while path[i] != (0 as u8) { 26 if path[i] == (47 as u8) { if i > 0 { path[i]=0 as u8; sys_mkdir(path, 0x1ff); path[i]=47 as u8 } } 27 i = i + 1 28 } 29 return 0 30} 31 32// streaming copy: srcfd bytes [start, start+len) -> a fresh file at dstpath, in 1 MiB chunks. 33func ex_copy_range(srcfd: i64, start: i64, len: i64, dstpath: *u8) -> i64 { 34 let dfd: i64 = sys_openat_wr(dstpath, 0x1a4); if dfd<0 { return 0-1 } 35 sys_lseek(srcfd, start, 0) 36 let buf: *u8 = sys_mmap(EX_MAGIC_1048576) 37 var rem: i64 = len 38 while rem > 0 { 39 var want: i64 = EX_MAGIC_1048576; if rem < want { want = rem } 40 let got: i64 = sys_read(srcfd, buf, want) 41 if got <= 0 { rem = 0 } else { sys_write(dfd, buf, got); rem = rem - got } 42 } 43 sys_close(dfd) 44 return 0 45} 46 47const EX_NAME_BONUS: i64 = 1099511627776 48func ex_lcname_has(name: *u8, sub: *u8) -> i64 { 49 let n: i64 = ex_slen(name); let m: i64 = ex_slen(sub) 50 var i: i64 = 0 51 while i + m <= n { 52 var j: i64 = 0; var ok: i64 = 1 53 while j < m { var c: i64 = name[i+j] as i64; if c>=65 { if c<=90 { c=c+32 } } if c != (sub[j] as i64) { ok=0; j=m } else { j=j+1 } } 54 if ok == 1 { return 1 } 55 i = i + 1 56 } 57 return 0 58} 59func ex_ends(name: *u8, suf: *u8) -> i64 { 60 let n: i64 = ex_slen(name); let m: i64 = ex_slen(suf) 61 if n < m { return 0 } 62 var i: i64 = 0 63 while i < m { var c: i64 = name[n-m+i] as i64; if c>=65 { if c<=90 { c=c+32 } } if c != (suf[i] as i64) { return 0 } i=i+1 } 64 return 1 65} 66func ex_is_vid(name: *u8) -> i64 { if ex_ends(name,".mp4" as *u8)==1 {return 1} if ex_ends(name,".mkv" as *u8)==1 {return 1} if ex_ends(name,".ts" as *u8)==1 {return 1} if ex_ends(name,".flv" as *u8)==1 {return 1} return 0 } 67func ex_is_img(name: *u8) -> i64 { if ex_ends(name,".jpg" as *u8)==1 {return 1} if ex_ends(name,".jpeg" as *u8)==1 {return 1} if ex_ends(name,".png" as *u8)==1 {return 1} return 0 } 68func ex_fsize(path: *u8) -> i64 { let fd: i64=sys_openat_rd(path); if fd<0 {return 0-1} let s: i64=sys_lseek(fd,0,2); sys_close(fd); return s } 69func ex_copy_file(src: *u8, dst: *u8) -> i64 { 70 let sfd: i64 = sys_openat_rd(src); if sfd<0 { return 0-1 } 71 let dfd: i64 = sys_openat_wr(dst, 0x1a4); if dfd<0 { sys_close(sfd); return 0-1 } 72 let buf: *u8 = sys_mmap(EX_MAGIC_1048576) 73 var go: i64 = 1 74 while go==1 { let r: i64=sys_read(sfd,buf,EX_MAGIC_1048576); if r<=0 {go=0} else { sys_write(dfd,buf,r) } } 75 sys_close(sfd); sys_close(dfd); return 0 76} 77func ex_poster_walk(dir: *u8, depth: i64, mode: i64, best: *u8, bestscore: *i64, madep: *i64) -> i64 { 78 if depth > 4 { return 0 } 79 let fd: i64 = sys_openat_rd(dir); if fd < 0 { return 0 } 80 let gbuf: *u8 = sys_mmap(EX_MAGIC_65536) 81 let child: *u8 = sys_mmap(EX_MAGIC_2048) 82 let dlen: i64 = ex_slen(dir) 83 var go: i64 = 1 84 while go == 1 { 85 let n: i64 = sys_getdents64(fd, gbuf, EX_MAGIC_65536) 86 if n <= 0 { go = 0 } else { 87 var off: i64 = 0 88 while off < n { 89 let rec: *u8 = ((gbuf as i64) + off) as *u8 90 let reclen: i64 = dirent_reclen(rec) 91 let typ: i64 = dirent_type(rec) 92 let name: *u8 = dirent_name(rec) 93 var skip: i64 = 0 94 if name[0]==(46 as u8) { if name[1]==(0 as u8) {skip=1} else { if name[1]==(46 as u8) { if name[2]==(0 as u8) {skip=1} } } } 95 if skip == 0 { 96 var co: i64 = 0 97 while co < dlen { child[co]=dir[co]; co=co+1 } 98 child[co]=47 as u8; co=co+1 99 var ni: i64 = 0 100 while name[ni]!=(0 as u8) { child[co]=name[ni]; co=co+1; ni=ni+1 } 101 child[co]=0 as u8 102 if typ != DT_REG { 103 ex_poster_walk(child, depth+1, mode, best, bestscore, madep) 104 } else { 105 if mode == 1 { if ex_is_img(name)==1 { if ex_ends(name,"-poster.jpg" as *u8)==0 { 106 var sc: i64 = ex_fsize(child) 107 if ex_lcname_has(name,"poster" as *u8)==1 { sc = sc + EX_NAME_BONUS } 108 if ex_lcname_has(name,"cover" as *u8)==1 { sc = sc + EX_NAME_BONUS } 109 if sc > bestscore[0] { bestscore[0]=sc; var bi: i64=0; while child[bi]!=(0 as u8){best[bi]=child[bi];bi=bi+1} best[bi]=0 as u8 } 110 } } } 111 if mode == 2 { if ex_is_vid(name)==1 { 112 let pp3: *u8 = sys_mmap(EX_MAGIC_2048) 113 let cl: i64 = ex_slen(child) 114 var dot: i64 = 0-1; var sl2: i64 = 0-1; var q: i64 = 0 115 while q < cl { if child[q]==(47 as u8){sl2=q}; if child[q]==(46 as u8){dot=q}; q=q+1 } 116 if dot > sl2 { 117 var w: i64 = 0 118 while w < dot { pp3[w]=child[w]; w=w+1 } 119 let z: i64 = ex_cat(pp3, w, "-poster.jpg" as *u8); pp3[z]=0 as u8 120 let pfd: i64 = sys_openat_rd(pp3) 121 if pfd >= 0 { sys_close(pfd) } else { 122 if ex_copy_file(best, pp3) == 0 { madep[0]=madep[0]+1 } 123 } 124 } 125 } } 126 } 127 } 128 if reclen <= 0 { off = n } else { off = off + reclen } 129 } 130 } 131 } 132 sys_close(fd) 133 return 0 134} 135 136func main(argc: i64, argv: *i64) -> i64 { 137 var outdir: *u8 = "/mnt/c/Users/elder/Downloads/nishi-torrents/REBDB-1026" as *u8 138 if argc >= 2 { outdir = argv[1] as *u8 } 139 let metapath: *u8 = sys_mmap(640); var mp: i64=ex_cat(metapath,0,outdir); mp=ex_cat(metapath,mp,"/download.meta" as *u8); metapath[mp]=0 as u8 140 let partpath: *u8 = sys_mmap(640); var pp: i64=ex_cat(partpath,0,outdir); pp=ex_cat(partpath,pp,"/download.part" as *u8); partpath[pp]=0 as u8 141 142 let mfd: i64 = sys_openat_rd(metapath); if mfd<0 { ex_w("EXTRACT verdict=RED reason=no-meta\n" as *u8); sys_exit(1); return 1 } 143 let meta: *u8 = sys_mmap(EX_MAGIC_1048576); var msize: i64=0; var r: i64=1 144 while r>0 { r=sys_read(mfd, ((meta as i64) + msize) as *u8, EX_MAGIC_1048576-msize); if r>0 {msize=msize+r} } 145 sys_close(mfd) 146 let srcfd: i64 = sys_openat_rd(partpath); if srcfd<0 { ex_w("EXTRACT verdict=RED reason=no-part\n" as *u8); sys_exit(1); return 1 } 147 148 var nfiles: i64 = 0 149 let filo: i64 = nx_bc_dict_get(meta, 0, msize, "files" as *u8, 5) 150 if filo >= 0 { 151 if (meta[filo] as i64) == 0x6C { // 'l' -- MULTI-FILE 152 var p: i64 = filo + 1 153 var off: i64 = 0 154 var run: i64 = 1 155 while run == 1 { 156 if p >= msize { run = 0 } else { if (meta[p] as i64) == 0x65 { run = 0 } else { 157 let lo: i64 = nx_bc_dict_get(meta, p, msize, "length" as *u8, 6); let lv: *i64 = sys_mmap(8) as *i64; lv[0]=0; if lo>=0 { nx_bc_int(meta, lo, msize, lv) } 158 let flen: i64 = lv[0] 159 let outp: *u8 = sys_mmap(EX_MAGIC_2048); var oo: i64 = ex_cat(outp, 0, outdir); outp[oo]=47 as u8; oo=oo+1 160 let pao: i64 = nx_bc_dict_get(meta, p, msize, "path" as *u8, 4) 161 if pao>=0 { if (meta[pao] as i64)==0x6C { 162 var pp2: i64 = pao+1; var prun: i64=1; var first: i64=1 163 while prun==1 { if pp2>=msize {prun=0} else { if (meta[pp2] as i64)==0x65 {prun=0} else { 164 let so: *i64=sys_mmap(8) as *i64; let sl: *i64=sys_mmap(8) as *i64; let np: i64=nx_bc_str(meta,pp2,msize,so,sl) 165 if np<0 {prun=0} else { 166 if first==0 { outp[oo]=47 as u8; oo=oo+1 } 167 var k: i64=0; while k<sl[0] { outp[oo]=meta[so[0]+k]; oo=oo+1; k=k+1 } 168 first=0; pp2=np 169 } 170 } } } 171 } } 172 outp[oo]=0 as u8 173 ex_mkdirs(outp) 174 ex_w(" extract " as *u8); ex_w(outp); ex_w(" (" as *u8); ex_wn(flen); ex_w(" bytes @ " as *u8); ex_wn(off); ex_w(")\n" as *u8) 175 ex_copy_range(srcfd, off, flen, outp) 176 off = off + flen 177 nfiles = nfiles + 1 178 p = nx_bc_skip(meta, p, msize) 179 } } 180 } 181 } 182 } else { // SINGLE-FILE 183 let nmo: i64 = nx_bc_dict_get(meta, 0, msize, "name" as *u8, 4); let so: *i64=sys_mmap(8) as *i64; let sl: *i64=sys_mmap(8) as *i64 184 let lno: i64 = nx_bc_dict_get(meta, 0, msize, "length" as *u8, 6); let lv: *i64=sys_mmap(8) as *i64; lv[0]=0; if lno>=0 { nx_bc_int(meta,lno,msize,lv) } 185 if nmo>=0 { nx_bc_str(meta,nmo,msize,so,sl) 186 let outp: *u8 = sys_mmap(EX_MAGIC_2048); var oo: i64=ex_cat(outp,0,outdir); outp[oo]=47 as u8; oo=oo+1; var k: i64=0; while k<sl[0]{outp[oo]=meta[so[0]+k];oo=oo+1;k=k+1} outp[oo]=0 as u8 187 ex_w(" extract " as *u8); ex_w(outp); ex_w(" (" as *u8); ex_wn(lv[0]); ex_w(" bytes)\n" as *u8) 188 ex_copy_range(srcfd, 0, lv[0], outp) 189 nfiles=1 190 } 191 } 192 sys_close(srcfd) 193 let best: *u8 = sys_mmap(EX_MAGIC_2048); best[0]=0 as u8 194 let bestscore: *i64 = sys_mmap(16) as *i64; bestscore[0]=0 195 let made: *i64 = sys_mmap(16) as *i64; made[0]=0 196 ex_poster_walk(outdir, 0, 1, best, bestscore, made) 197 if best[0] != (0 as u8) { ex_poster_walk(outdir, 0, 2, best, bestscore, made) } 198 ex_w("POSTER-BRIDGE posters=" as *u8); ex_wn(made[0]); ex_w(" cover=" as *u8); if best[0]==(0 as u8) { ex_w("none-shipped" as *u8) } else { ex_w(best) } ex_w("\n" as *u8) 199 ex_w("EXTRACT files=" as *u8); ex_wn(nfiles); ex_w(" verdict=GREEN\n" as *u8) 200 sys_exit(0); return 0 201}