ref: d1d1267271f9f0bc6ad4a2a31ad7bc3b6125d820
dir: /nvi.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <json.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; 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(); vid = argv[0]; if(strncmp(argv[0], "http", 4) == 0){ if(strstr(argv[0], "youtu") != nil && (vid = strrpbrk(argv[0], "/=")) != nil) vid++; else fun = peertube; } if((info = fun(vid)) == nil) sysfatal("%r"); 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->quality : "----", f->sz, f->type); print("\n"); if(*info->author) print("author: %s\n", info->author); if(*info->title) print("title: %s\n", info->title); if(*info->description) print("description: %s\n", info->description); if(info->duration != 0) print("duration: %P\n", info->duration); if(tmnorm(&info->published) != 0) print("published: %τ\n", tmfmt(&info->published, "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) || (f->quality != nil && 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; /* no audio and video stream doesn't have it either */ if(fa == nil && (fv == nil || (fv->included & Iaudio) == 0)) fa = ba; i = 0; if(oa != nil){ if((afd = open(oa, OWRITE|OTRUNC)) < 0 && (afd = create(oa, OWRITE|OTRUNC, 0644)) < 0) sysfatal("%r"); if(fa != nil && ++i && hget(fa->url, afd) < 0) sysfatal("%r"); } if(ov != nil){ if((vfd = open(ov, OWRITE|OTRUNC)) < 0 && (vfd = create(ov, OWRITE|OTRUNC, 0644)) < 0) sysfatal("%r"); if(fv != nil && ++i && hget(fv->url, vfd) < 0) sysfatal("%r"); } if(i == 0) sysfatal("no streams found"); while(i-- > 0) procwait(); } threadexitsall(nil); }