#include <u.h>#include <libc.h>#include <thread.h>#include <json.h>#include "nvi.h" int cmd = Cdownload;int debug = 0; static intcmpfmt(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 voidusage(void){ fprint(2, "usage: %s [-i | [-a file_audio] [-v file_video] [-A id|quality] [-V id|quality]] url|id\n", argv0); threadexitsall("usage");} voidthreadmain(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(); if(cmd != Cinfo && ov == nil && oa == nil){ fprint(2, "at least one option (-i, -a, -v) has be specified\n"); threadexitsall("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);}
#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();
if(cmd != Cinfo && ov == nil && oa == nil){
fprint(2, "at least one option (-i, -a, -v) has be specified\n");
threadexitsall("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);
}