Add -m switch

Disaply size of downloaded file in an human way
This commit is contained in:
Grégory Soutadé 2016-08-12 18:10:03 +02:00
parent a5d01d4ddf
commit c3c7945ddf
1 changed files with 116 additions and 25 deletions

141
gget.c
View File

@ -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;
} }