ref: 8d8227ad5b80f5116e917a9adbd1a873f037041e
dir: /nvi.c/
#include <u.h> #include <libc.h> #include <thread.h> #include "nvi.h" int cmd = Cdownload; int debug = 0; static int cmpfmt(void *a_, void *b_) { Format *a, *b; a = a_; b = b_; if(a->included != b->included) return a->included - b->included; return b->sz - a->sz; } static void usage(void) { fprint(2, "usage: %s [-i | [-a file_audio] [-v file_video] [-A id|quality] [-V id|quality]] url|id\n", argv0); threadexitsall("usage"); } void threadmain(int argc, char **argv) { char *vid, *oa, *ov, *ida[8], *idv[8]; Format *f, *fa, *fv, *ba, *bv; Info *(*fun)(char *), *info; int i, j, nida, nidv; int afd, vfd; Tm tm; fmtinstall('P', Pfmt); fmtinstall('Z', Zfmt); tmfmtinstall(); fun = youtube; nida = 0; nidv = 0; oa = nil; ov = nil; ba = nil; bv = nil; ARGBEGIN{ case 'd': debug++; break; case 'i': cmd = Cinfo; break; case 'a': oa = EARGF(usage()); break; case 'v': ov = EARGF(usage()); break; case 'A': if(nida >= nelem(ida)) sysfatal("too many ids for audio"); ida[nida++] = EARGF(usage()); break; case 'V': if(nidv >= nelem(idv)) sysfatal("too many ids for video"); idv[nidv++] = EARGF(usage()); break; default: usage(); }ARGEND if(argc != 1) usage(); if((vid = strrchr(argv[0], '/')) != nil) vid++; else vid = argv[0]; if((info = fun(vid)) == nil){ fprint(2, "%r\n"); threadexitsall("failed"); } qsort(info->fmt, info->nfmt, sizeof(Format), cmpfmt); if(cmd == Cinfo){ print("ID\tQUALITY\tSIZE\tFORMAT\n"); for(i = 0, f = info->fmt; i < info->nfmt; i++, f++) print("%d\t%s\t%Z\t%s\n", f->id, f->quality, f->sz, f->type); print("\n"); print("author: %s\n", info->author); print("title: %s\n", info->title); print("description: %s\n", info->title); print("duration: %P\n", info->duration); print("published: %τ\n", tmfmt(tmtime(&tm, info->published, nil), "YYYY/MM/DD")); }else if(cmd == Cdownload){ for(j = 0, fa = nil, f = info->fmt; j < info->nfmt && fa == nil; j++, f++){ if((f->included == Iaudio) == 0) continue; if(ba == nil) ba = f; for(i = 0; i < nida && fa == nil; i++){ if((alldigit(ida[i]) && atoi(ida[i]) == f->id) || strcmp(f->quality, ida[i]) == 0){ fa = f; break; } } } for(j = 0, fv = nil, f = info->fmt; j < info->nfmt && fv == nil; j++, f++){ if((f->included & Ivideo) == 0) continue; if(bv == nil) bv = f; for(i = 0; i < nidv && fv == nil; i++){ if((alldigit(idv[i]) && atoi(idv[i]) == f->id) || strcmp(f->quality, idv[i]) == 0){ fv = f; break; } } } if(fv == nil) fv = bv; if(fa == nil && (fv->included & Iaudio) == 0) /* no audio and video stream doesn't have it either */ fa = ba; i = 0; if(oa != nil){ if((afd = open(oa, OWRITE|OTRUNC)) < 0 && (afd = create(oa, OWRITE|OTRUNC, 0644)) < 0) sysfatal("%r"); if(hget(fa->url, afd) < 0) sysfatal("%r"); i++; } if(ov != nil){ if((vfd = open(ov, OWRITE|OTRUNC)) < 0 && (vfd = create(ov, OWRITE|OTRUNC, 0644)) < 0) sysfatal("%r"); if(hget(fv->url, vfd) < 0) sysfatal("%r"); i++; } while(i-- > 0) procwait(); } threadexitsall(nil); }