ref: 748cb65df1bf26d73030a178d5390edd7f007934
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);
}