2024-04-22 15:38:35 +09:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <libgen.h>
|
2024-04-26 17:14:42 +09:00
|
|
|
|
#include <string.h>
|
2024-04-26 18:14:15 +09:00
|
|
|
|
#include <unistd.h>
|
2024-04-22 15:38:35 +09:00
|
|
|
|
|
|
|
|
|
#include <curl/curl.h>
|
|
|
|
|
|
|
|
|
|
const char* sofname = "odl";
|
2024-05-02 18:46:09 +09:00
|
|
|
|
const char* version = "0.3.0";
|
2024-05-12 17:23:49 +09:00
|
|
|
|
const char* avalopt = "nopv";
|
2024-04-22 15:38:35 +09:00
|
|
|
|
char* filename;
|
|
|
|
|
|
2024-04-26 18:14:15 +09:00
|
|
|
|
int opt;
|
2024-05-12 17:23:49 +09:00
|
|
|
|
int yokou_flag = 0;
|
2024-04-26 18:14:15 +09:00
|
|
|
|
int output_flag = 0;
|
|
|
|
|
int version_flag = 0;
|
2024-04-26 21:52:19 +09:00
|
|
|
|
int already_flag = 0;
|
2024-04-26 18:14:15 +09:00
|
|
|
|
int err_flag = 0;
|
2024-05-12 13:35:48 +09:00
|
|
|
|
int dlstat = 0;
|
|
|
|
|
int onedlsuc = 0;
|
2024-04-26 18:14:15 +09:00
|
|
|
|
|
2024-04-26 17:14:42 +09:00
|
|
|
|
char* get_filename(const char* url) {
|
|
|
|
|
char* fn_start = strrchr(url, '/');
|
|
|
|
|
if (fn_start == NULL) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
fn_start++;
|
|
|
|
|
|
|
|
|
|
char* query = strchr(fn_start, '?');
|
|
|
|
|
char* anchor = strchr(fn_start, '#');
|
|
|
|
|
char* fn_end = NULL;
|
|
|
|
|
|
|
|
|
|
if (query != NULL && anchor != NULL) {
|
|
|
|
|
fn_end = (query < anchor) ? query : anchor;
|
|
|
|
|
} else if (query != NULL) {
|
|
|
|
|
fn_end = query;
|
|
|
|
|
} else if (anchor != NULL) {
|
|
|
|
|
fn_end = anchor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// URLでパラメートルがなければ、そのままファイル名をコピーして
|
|
|
|
|
if (fn_end == NULL) {
|
|
|
|
|
fn_end = strchr(fn_start, '\0');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t length = fn_end - fn_start;
|
|
|
|
|
|
|
|
|
|
char* extfn = malloc(length + 1);
|
|
|
|
|
if (extfn == NULL) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strncpy(extfn, fn_start, length);
|
|
|
|
|
extfn[length] = '\0';
|
|
|
|
|
|
|
|
|
|
return extfn;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-22 15:38:35 +09:00
|
|
|
|
int progress_callback(void *cp, double dt, double dn, double ut, double un) {
|
|
|
|
|
(void)cp;
|
|
|
|
|
(void)ut;
|
|
|
|
|
(void)un;
|
|
|
|
|
|
|
|
|
|
double progress = (dn / dt) * 100.0;
|
|
|
|
|
|
|
|
|
|
printf("\r[");
|
|
|
|
|
int barw = 50;
|
|
|
|
|
int pos = (int)(progress * barw / 100.0);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < barw; ++i) {
|
|
|
|
|
if (i < pos) printf("=");
|
|
|
|
|
else if (i == pos) printf(">");
|
|
|
|
|
else printf(" ");
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-25 17:57:40 +09:00
|
|
|
|
printf("] %.2f%% %s", progress, filename);
|
2024-04-22 15:38:35 +09:00
|
|
|
|
fflush(stdout);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-26 18:14:15 +09:00
|
|
|
|
void handle_o(int argc, char* argv[]) {
|
|
|
|
|
output_flag = 1;
|
|
|
|
|
if (optind < argc) {
|
|
|
|
|
if (filename != NULL) {
|
|
|
|
|
fprintf(
|
|
|
|
|
stderr,
|
|
|
|
|
"-oをご利用する場合、1つのファイルだけをダウンロード出来ます。\n"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
filename = argv[optind];
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "-oの後でファイル名がありません。");
|
|
|
|
|
err_flag = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-12 17:23:49 +09:00
|
|
|
|
void dlsucmsg() {
|
|
|
|
|
if (yokou_flag == 0) printf("\nダウンロードに完了しました。\n");
|
|
|
|
|
else {
|
|
|
|
|
printf("\nダウンロードに完了しました。\n");
|
|
|
|
|
printf("予行演習モードですので、ファイルを保存していません。\n");
|
|
|
|
|
printf("保存するには、「-n」フラグを消して下さい。\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-22 18:37:00 +09:00
|
|
|
|
void usage() {
|
|
|
|
|
printf("%s-%s\nusage: %s [-%s] [url ...]\n", sofname, version, sofname, avalopt);
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-26 18:14:15 +09:00
|
|
|
|
void flags(int opt, int argc, char* argv[]) {
|
|
|
|
|
switch (opt) {
|
2024-05-12 17:23:49 +09:00
|
|
|
|
case 'n':
|
|
|
|
|
yokou_flag = 1;
|
|
|
|
|
break;
|
2024-04-26 18:14:15 +09:00
|
|
|
|
case 'o':
|
|
|
|
|
handle_o(argc, argv);
|
|
|
|
|
break;
|
2024-04-26 21:52:19 +09:00
|
|
|
|
case 'p':
|
|
|
|
|
already_flag = 1;
|
|
|
|
|
break;
|
2024-04-26 18:14:15 +09:00
|
|
|
|
case 'v':
|
|
|
|
|
version_flag = 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
err_flag = 1;
|
2024-05-22 18:37:00 +09:00
|
|
|
|
usage();
|
2024-04-26 18:14:15 +09:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int downloader(CURL* curl, char* filename, const char* url) {
|
2024-04-26 21:52:19 +09:00
|
|
|
|
if (already_flag == 1 && access(filename, F_OK) != -1) {
|
|
|
|
|
printf("ファイルが既に存在しますので、ダウンロードしません。\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2024-04-26 18:14:15 +09:00
|
|
|
|
|
|
|
|
|
curl_easy_setopt(curl, CURLOPT_URL, url);
|
2024-05-12 11:19:01 +09:00
|
|
|
|
|
2024-05-02 18:46:09 +09:00
|
|
|
|
// Clownflareは面倒くさいわね・・・
|
|
|
|
|
curl_easy_setopt(
|
|
|
|
|
curl,
|
|
|
|
|
CURLOPT_USERAGENT,
|
|
|
|
|
"Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0"
|
|
|
|
|
);
|
2024-05-02 20:10:58 +09:00
|
|
|
|
// Pixivも結構面倒くさい
|
|
|
|
|
if (
|
|
|
|
|
strstr("s.pixiv.net", url) == 0 ||
|
|
|
|
|
strstr("i.pixiv.net", url) == 0 ||
|
|
|
|
|
strstr("s.pximg.net", url) == 0 ||
|
|
|
|
|
strstr("i.pximg.net", url) == 0
|
|
|
|
|
) {
|
|
|
|
|
curl_easy_setopt(curl, CURLOPT_REFERER, "https://www.pixiv.net/");
|
|
|
|
|
}
|
2024-05-12 11:19:01 +09:00
|
|
|
|
|
|
|
|
|
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);
|
|
|
|
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
|
|
|
|
|
|
2024-05-12 17:23:49 +09:00
|
|
|
|
FILE* file = NULL;
|
|
|
|
|
|
|
|
|
|
if (yokou_flag == 0) {
|
|
|
|
|
file = fopen(filename, "wb");
|
|
|
|
|
} else {
|
|
|
|
|
file = fopen("/tmp/odl_test", "wb");
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-12 11:19:01 +09:00
|
|
|
|
if (!file) {
|
|
|
|
|
perror("ファイルを開けません。");
|
|
|
|
|
curl_easy_cleanup(curl);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-26 18:14:15 +09:00
|
|
|
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
|
2024-05-12 17:23:49 +09:00
|
|
|
|
|
2024-05-12 11:19:01 +09:00
|
|
|
|
long httpcode = 0;
|
2024-04-26 18:14:15 +09:00
|
|
|
|
CURLcode res = curl_easy_perform(curl);
|
2024-05-12 11:19:01 +09:00
|
|
|
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpcode);
|
|
|
|
|
|
2024-04-26 18:14:15 +09:00
|
|
|
|
fclose(file);
|
2024-05-12 17:23:49 +09:00
|
|
|
|
if (yokou_flag == 1) unlink("/tmp/odl_test");
|
2024-04-26 18:14:15 +09:00
|
|
|
|
|
|
|
|
|
if (res != CURLE_OK) {
|
2024-05-12 17:23:49 +09:00
|
|
|
|
if (yokou_flag == 0) unlink(filename);
|
2024-04-26 18:14:15 +09:00
|
|
|
|
fprintf(stderr, "\nダウンロードに失敗: %s\n", curl_easy_strerror(res));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-12 11:19:01 +09:00
|
|
|
|
if (res == CURLE_ABORTED_BY_CALLBACK || httpcode != 200) {
|
2024-05-12 17:23:49 +09:00
|
|
|
|
if (yokou_flag == 0) unlink(filename);
|
2024-05-12 13:35:48 +09:00
|
|
|
|
fprintf(stderr, "\n%sをダウンロードに失敗: HTTP CODE: %ld\n", filename, httpcode);
|
2024-05-12 11:19:01 +09:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-26 18:14:15 +09:00
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-22 15:38:35 +09:00
|
|
|
|
int main(int argc, char* argv[]) {
|
|
|
|
|
if (argc < 2) {
|
2024-05-22 18:37:00 +09:00
|
|
|
|
usage();
|
2024-04-22 15:38:35 +09:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-26 21:52:19 +09:00
|
|
|
|
while ((opt = getopt(argc, argv, avalopt)) != -1) {
|
2024-04-26 18:14:15 +09:00
|
|
|
|
flags(opt, argc, argv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (err_flag == 1) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (version_flag == 1) {
|
|
|
|
|
printf("%s-%s\n", sofname, version);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-22 15:38:35 +09:00
|
|
|
|
CURL* curl = curl_easy_init();
|
|
|
|
|
if (!curl) {
|
|
|
|
|
perror("curlを初期設置に失敗。");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-26 18:14:15 +09:00
|
|
|
|
// 一つのファイルだけが可能
|
|
|
|
|
if (output_flag == 1) {
|
|
|
|
|
if (optind >= argc) {
|
|
|
|
|
fprintf(stderr, "-oの後でURLがありません。");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-26 17:14:42 +09:00
|
|
|
|
if (filename == NULL) {
|
2024-04-26 18:14:15 +09:00
|
|
|
|
fprintf(stderr, "-oの後でファイル名がありません。");
|
|
|
|
|
return 1;
|
2024-04-26 17:14:42 +09:00
|
|
|
|
}
|
2024-04-22 15:38:35 +09:00
|
|
|
|
|
2024-04-26 18:14:15 +09:00
|
|
|
|
filename = argv[optind];
|
|
|
|
|
const char* url = argv[optind+1];
|
2024-05-12 13:35:48 +09:00
|
|
|
|
dlstat = downloader(curl, filename, url);
|
|
|
|
|
if (dlstat == 0) onedlsuc = 1;
|
2024-04-22 15:38:35 +09:00
|
|
|
|
|
2024-04-26 18:14:15 +09:00
|
|
|
|
curl_easy_cleanup(curl);
|
2024-05-12 17:23:49 +09:00
|
|
|
|
|
2024-05-12 13:35:48 +09:00
|
|
|
|
if (onedlsuc == 1) {
|
2024-05-12 17:23:49 +09:00
|
|
|
|
dlsucmsg();
|
2024-05-12 13:35:48 +09:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2024-04-22 15:38:35 +09:00
|
|
|
|
|
2024-05-12 13:35:48 +09:00
|
|
|
|
return 1;
|
2024-04-26 18:14:15 +09:00
|
|
|
|
}
|
2024-04-22 15:38:35 +09:00
|
|
|
|
|
2024-04-26 18:14:15 +09:00
|
|
|
|
// 複数ファイル名可能
|
|
|
|
|
for (int i = optind; i < argc; i++) {
|
|
|
|
|
const char* url = argv[i];
|
|
|
|
|
filename = get_filename(url);
|
|
|
|
|
if (filename == NULL) {
|
|
|
|
|
fprintf(stderr, "URLからファイル名を抽出出来ませんでした。\n");
|
|
|
|
|
continue;
|
2024-04-22 15:38:35 +09:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-12 13:35:48 +09:00
|
|
|
|
dlstat = downloader(curl, filename, url);
|
|
|
|
|
if (dlstat == 0) onedlsuc = 1;
|
2024-04-22 15:38:35 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
curl_easy_cleanup(curl);
|
2024-05-12 13:35:48 +09:00
|
|
|
|
if (onedlsuc == 1) {
|
2024-05-12 17:23:49 +09:00
|
|
|
|
dlsucmsg();
|
2024-05-12 13:35:48 +09:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2024-04-22 15:38:35 +09:00
|
|
|
|
|
2024-05-12 13:35:48 +09:00
|
|
|
|
return 1;
|
2024-04-22 15:38:35 +09:00
|
|
|
|
}
|