Add -m switch
Disaply size of downloaded file in an human way
This commit is contained in:
parent
a5d01d4ddf
commit
c3c7945ddf
141
gget.c
141
gget.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Grégory Soutadé
|
Copyright 2014-2016 Grégory Soutadé
|
||||||
|
|
||||||
This file is part of gget.
|
This file is part of gget.
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ static int get_console_width()
|
||||||
typedef struct {
|
typedef struct {
|
||||||
curl_off_t dltotal;
|
curl_off_t dltotal;
|
||||||
curl_off_t dlnow;
|
curl_off_t dlnow;
|
||||||
|
curl_off_t dllast;
|
||||||
unsigned speed;
|
unsigned speed;
|
||||||
} stats_t ;
|
} stats_t ;
|
||||||
|
|
||||||
|
@ -101,6 +102,7 @@ typedef struct {
|
||||||
unsigned already_downloaded;
|
unsigned already_downloaded;
|
||||||
unsigned start;
|
unsigned start;
|
||||||
unsigned end;
|
unsigned end;
|
||||||
|
unsigned max_chunk_size;
|
||||||
curl_off_t max_speed;
|
curl_off_t max_speed;
|
||||||
stats_t* stats;
|
stats_t* stats;
|
||||||
} transfert_t;
|
} transfert_t;
|
||||||
|
@ -216,8 +218,8 @@ static int progress_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl
|
||||||
|
|
||||||
curl_easy_getinfo(t->curl, CURLINFO_SPEED_DOWNLOAD, &speed_d);
|
curl_easy_getinfo(t->curl, CURLINFO_SPEED_DOWNLOAD, &speed_d);
|
||||||
|
|
||||||
t->stats[t->id].dltotal = dltotal + t->already_downloaded;
|
t->stats[t->id].dlnow += (dlnow - t->stats[t->id].dllast);
|
||||||
t->stats[t->id].dlnow = dlnow + t->already_downloaded;
|
t->stats[t->id].dllast = dlnow;
|
||||||
t->stats[t->id].speed = speed_d;
|
t->stats[t->id].speed = speed_d;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -226,14 +228,12 @@ static int progress_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl
|
||||||
void* do_transfert(transfert_t* t)
|
void* do_transfert(transfert_t* t)
|
||||||
{
|
{
|
||||||
CURLcode res;
|
CURLcode res;
|
||||||
char range[50];
|
char range[64];
|
||||||
|
unsigned start, end, chunk_size;
|
||||||
snprintf(range, sizeof(range), "%u-%u", t->start, t->end);
|
|
||||||
|
|
||||||
curl_easy_setopt(t->curl, CURLOPT_USERAGENT, t->user_agent);
|
curl_easy_setopt(t->curl, CURLOPT_USERAGENT, t->user_agent);
|
||||||
curl_easy_setopt(t->curl, CURLOPT_URL, t->url);
|
curl_easy_setopt(t->curl, CURLOPT_URL, t->url);
|
||||||
curl_easy_setopt(t->curl, CURLOPT_FOLLOWLOCATION, 1L);
|
curl_easy_setopt(t->curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
curl_easy_setopt(t->curl, CURLOPT_RANGE, range);
|
|
||||||
|
|
||||||
if (t->max_speed)
|
if (t->max_speed)
|
||||||
curl_easy_setopt(t->curl, CURLOPT_MAX_RECV_SPEED_LARGE, t->max_speed);
|
curl_easy_setopt(t->curl, CURLOPT_MAX_RECV_SPEED_LARGE, t->max_speed);
|
||||||
|
@ -248,13 +248,37 @@ void* do_transfert(transfert_t* t)
|
||||||
curl_easy_setopt(t->curl, CURLOPT_XFERINFOFUNCTION, progress_cb);
|
curl_easy_setopt(t->curl, CURLOPT_XFERINFOFUNCTION, progress_cb);
|
||||||
curl_easy_setopt(t->curl, CURLOPT_XFERINFODATA, t);
|
curl_easy_setopt(t->curl, CURLOPT_XFERINFODATA, t);
|
||||||
|
|
||||||
/* Perform the request, res will get the return code */
|
start = t->start;
|
||||||
res = curl_easy_perform(t->curl);
|
if (t->max_chunk_size && (t->end - t->start) > t->max_chunk_size)
|
||||||
/* Check for errors */
|
chunk_size = t->max_chunk_size;
|
||||||
if(res != CURLE_OK)
|
else
|
||||||
fprintf(stderr, "curl_easy_perform() failed: %s\n",
|
chunk_size = t->end - t->start;
|
||||||
curl_easy_strerror(res));
|
end = start + chunk_size;
|
||||||
|
|
||||||
|
while (start < t->end)
|
||||||
|
{
|
||||||
|
snprintf(range, sizeof(range), "%u-%u", start, end);
|
||||||
|
curl_easy_setopt(t->curl, CURLOPT_RANGE, range);
|
||||||
|
|
||||||
|
/* Perform the request, res will get the return code */
|
||||||
|
res = curl_easy_perform(t->curl);
|
||||||
|
/* Check for errors */
|
||||||
|
if(res != CURLE_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "curl_easy_perform() failed: %s\n",
|
||||||
|
curl_easy_strerror(res));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
start += chunk_size + 1;
|
||||||
|
if (t->max_chunk_size && (t->end - start) > t->max_chunk_size)
|
||||||
|
chunk_size = t->max_chunk_size;
|
||||||
|
else
|
||||||
|
chunk_size = t->end - start;
|
||||||
|
end = start + chunk_size;
|
||||||
|
t->stats[t->id].dllast = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +286,7 @@ static int configure_transfert(int id, transfert_t* t,
|
||||||
char* url, char* filename,
|
char* url, char* filename,
|
||||||
unsigned start, unsigned end,
|
unsigned start, unsigned end,
|
||||||
unsigned max_speed, char* user_agent,
|
unsigned max_speed, char* user_agent,
|
||||||
int* exists)
|
unsigned max_chunk_size, int* exists)
|
||||||
{
|
{
|
||||||
// filename + . + number + \0
|
// filename + . + number + \0
|
||||||
unsigned filename_size = strlen(filename)+1+3+1;
|
unsigned filename_size = strlen(filename)+1+3+1;
|
||||||
|
@ -284,6 +308,7 @@ static int configure_transfert(int id, transfert_t* t,
|
||||||
t->end = end;
|
t->end = end;
|
||||||
t->max_speed = max_speed;
|
t->max_speed = max_speed;
|
||||||
t->user_agent = user_agent;
|
t->user_agent = user_agent;
|
||||||
|
t->max_chunk_size = max_chunk_size;
|
||||||
|
|
||||||
if (stat(t->tmp_filename, &s))
|
if (stat(t->tmp_filename, &s))
|
||||||
{
|
{
|
||||||
|
@ -371,6 +396,7 @@ static int get_file_info(char* url, char* user_agent,
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
|
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADER, 1L);
|
curl_easy_setopt(curl, CURLOPT_HEADER, 1L);
|
||||||
|
|
||||||
|
@ -452,13 +478,14 @@ static void find_free_file(char** filename)
|
||||||
static void usage(char* program_name)
|
static void usage(char* program_name)
|
||||||
{
|
{
|
||||||
printf("%s: Parallel HTTP file download\n", program_name);
|
printf("%s: Parallel HTTP file download\n", program_name);
|
||||||
printf("usage: %s [-n nb_threads] [-l speed_limit] [-o out_filename] [-u user_agent] [-q] [-h] url\n",
|
printf("usage: %s [-n nb_threads] [-l speed_limit] [-o out_filename] [-u user_agent] [-m max_chunk_size[kKmMgG] ] [-q] [-h] url\n",
|
||||||
program_name);
|
program_name);
|
||||||
printf("\t-n : Specify number of threads (default : %d)\n", DEFAULT_NB_THREADS);
|
printf("\t-n : Specify number of threads (default : %d)\n", DEFAULT_NB_THREADS);
|
||||||
printf("\t-l : Download speed limit for all threads (not per thread)\n");
|
printf("\t-l : Download speed limit for all threads (not per thread)\n");
|
||||||
printf("\t-o : Out filename, default is retrieved by GET request or '%s' if not found\n",
|
printf("\t-o : Out filename, default is retrieved by GET request or '%s' if not found\n",
|
||||||
DEFAULT_OUT_FILENAME);
|
DEFAULT_OUT_FILENAME);
|
||||||
printf("\t-u : User agent, default is '%s'\n", DEFAULT_USER_AGENT);
|
printf("\t-u : User agent, default is '%s'\n", DEFAULT_USER_AGENT);
|
||||||
|
printf("\t-m : Max chunk size in bytes\n");
|
||||||
printf("\t-q : Quiet mode\n");
|
printf("\t-q : Quiet mode\n");
|
||||||
printf("\t-h : Display help\n");
|
printf("\t-h : Display help\n");
|
||||||
}
|
}
|
||||||
|
@ -467,14 +494,15 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
pthread_t display_thread = 0;
|
pthread_t display_thread = 0;
|
||||||
unsigned nb_threads = DEFAULT_NB_THREADS;
|
unsigned nb_threads = DEFAULT_NB_THREADS;
|
||||||
char* user_agent = strdup(DEFAULT_USER_AGENT);
|
char* user_agent = strdup(DEFAULT_USER_AGENT), *endptr;
|
||||||
stats_t* stats = NULL;
|
stats_t* stats = NULL;
|
||||||
int ret = -1, i;
|
int ret = -1, i;
|
||||||
stats_params_t stats_params;
|
stats_params_t stats_params;
|
||||||
transfert_t* transferts = NULL;
|
transfert_t* transferts = NULL;
|
||||||
unsigned total_size, thread_size;
|
unsigned total_size, thread_size, multiplier=1;
|
||||||
unsigned start, end, max_speed = 0, quiet = 0;
|
double displayed_size;
|
||||||
char* out_filename = NULL, *url = NULL;
|
unsigned start, end, max_speed = 0, quiet = 0, max_chunk_size = 0;
|
||||||
|
char* out_filename = NULL, *url = NULL, c;
|
||||||
char* suffix = "B";
|
char* suffix = "B";
|
||||||
void* res;
|
void* res;
|
||||||
int opt;
|
int opt;
|
||||||
|
@ -484,7 +512,7 @@ int main(int argc, char** argv)
|
||||||
int continuous_mode=0;
|
int continuous_mode=0;
|
||||||
int exists;
|
int exists;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "hn:l:o:u:q")) != -1) {
|
while ((opt = getopt(argc, argv, "hn:l:o:u:qm:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'n':
|
case 'n':
|
||||||
nb_threads = atoi(optarg);
|
nb_threads = atoi(optarg);
|
||||||
|
@ -499,6 +527,39 @@ int main(int argc, char** argv)
|
||||||
case 'l':
|
case 'l':
|
||||||
max_speed = atoi(optarg);
|
max_speed = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'm':
|
||||||
|
if (strlen(optarg) > 1)
|
||||||
|
{
|
||||||
|
c = optarg[strlen(optarg)-1];
|
||||||
|
if (c < '0' || c > '9')
|
||||||
|
{
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
multiplier *= 1024;
|
||||||
|
case 'm':
|
||||||
|
case 'M':
|
||||||
|
multiplier *= 1024;
|
||||||
|
case 'k':
|
||||||
|
case 'K':
|
||||||
|
multiplier *= 1024;
|
||||||
|
optarg[strlen(optarg)-1] = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max_chunk_size = strtoul(optarg, &endptr, 0);
|
||||||
|
if (*endptr)
|
||||||
|
{
|
||||||
|
usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
max_chunk_size *= multiplier;
|
||||||
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
out_filename = strdup(optarg);
|
out_filename = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
|
@ -539,7 +600,29 @@ int main(int argc, char** argv)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf("Save in '%s'\n\n", out_filename);
|
{
|
||||||
|
displayed_size = (double)total_size;
|
||||||
|
suffix = "B";
|
||||||
|
if (displayed_size > (1024))
|
||||||
|
{
|
||||||
|
displayed_size /= 1024.0;
|
||||||
|
suffix = "kB";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayed_size > (1024))
|
||||||
|
{
|
||||||
|
displayed_size /= 1024.0;
|
||||||
|
suffix = "MB";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayed_size > (1024))
|
||||||
|
{
|
||||||
|
displayed_size /= 1024.0;
|
||||||
|
suffix = "GB";
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Save in '%s' (%.2f%s)\n\n", out_filename, displayed_size, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
stats = malloc(sizeof(*stats)*nb_threads);
|
stats = malloc(sizeof(*stats)*nb_threads);
|
||||||
memset(stats, 0, sizeof(*stats)*nb_threads);
|
memset(stats, 0, sizeof(*stats)*nb_threads);
|
||||||
|
@ -561,10 +644,16 @@ int main(int argc, char** argv)
|
||||||
end = total_size;
|
end = total_size;
|
||||||
|
|
||||||
ret = configure_transfert(i, &transferts[i], url, out_filename,
|
ret = configure_transfert(i, &transferts[i], url, out_filename,
|
||||||
start, end, max_speed, user_agent, &exists);
|
start, end, max_speed, user_agent,
|
||||||
|
max_chunk_size, &exists);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
|
transferts[i].stats[i].dltotal = transferts[i].already_downloaded +
|
||||||
|
(end - start);
|
||||||
|
transferts[i].stats[i].dlnow = transferts[i].already_downloaded;
|
||||||
|
transferts[i].stats[i].dllast = 0;
|
||||||
|
|
||||||
// First set continuous mode
|
// First set continuous mode
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
|
@ -583,7 +672,8 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Check for last temporary file
|
// Check for last temporary file
|
||||||
configure_transfert(i, &transferts[i], url, out_filename,
|
configure_transfert(i, &transferts[i], url, out_filename,
|
||||||
start, end, max_speed, user_agent, &exists);
|
start, end, max_speed, user_agent, max_chunk_size,
|
||||||
|
&exists);
|
||||||
unlink(transferts[i].tmp_filename);
|
unlink(transferts[i].tmp_filename);
|
||||||
|
|
||||||
if (exists)
|
if (exists)
|
||||||
|
@ -665,7 +755,8 @@ end:
|
||||||
if (transferts)
|
if (transferts)
|
||||||
free(transferts);
|
free(transferts);
|
||||||
|
|
||||||
printf("\n");
|
if (!quiet)
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user