238 lines
6.7 KiB
JavaScript
Executable file
238 lines
6.7 KiB
JavaScript
Executable file
#!/usr/bin/node
|
|
|
|
const axios = require("axios");
|
|
const fs = require("fs");
|
|
const progress = require("cli-progress");
|
|
const lib = require("./lib");
|
|
|
|
let args;
|
|
if (process.argv[0].includes("node")) {
|
|
args = require("minimist")(process.argv.slice(2));
|
|
} else {
|
|
args = require("minimist")(process.argv.slice(1));
|
|
}
|
|
|
|
if (args._.length == 0) {
|
|
console.log(`gdd - google drive downloader`);
|
|
console.log(`source code: https://git.gay/a/gdd`);
|
|
console.log(`licensed under the unlicense.`);
|
|
return;
|
|
}
|
|
|
|
switch(args._[0]) {
|
|
case "captcha":
|
|
if (args._[1] && args._[2]) {
|
|
let solver = args._[1];
|
|
let key = args._[2];
|
|
|
|
console.log("Setting captcha solver to", solver);
|
|
console.log("Setting captcha solver key to", key);
|
|
|
|
lib.setConfig("captcha", {
|
|
solver: solver,
|
|
key: key
|
|
});
|
|
|
|
console.log("- Completed!");
|
|
} else {
|
|
console.log("ERR! Usage: gdd captcha <solver name> <solver key>");
|
|
}
|
|
return;
|
|
|
|
case "config":
|
|
switch(args._[1]) {
|
|
case "location":
|
|
console.log(`${__dirname}/config.json`);
|
|
return;
|
|
|
|
case "print":
|
|
console.log(JSON.stringify(lib.getConfig(), null, 2));
|
|
return;
|
|
|
|
default:
|
|
console.log("ERR! Usage: gdd <print|location>");
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
args._.forEach(function(e) {
|
|
if (!lib.isDriveLink(e)) {
|
|
console.log(`ERR! "${e}" is not a valid Google Drive link.`)
|
|
return;
|
|
}
|
|
});
|
|
|
|
let downloads = args._;
|
|
delete args._;
|
|
|
|
begin(downloads, args);
|
|
|
|
async function begin(array, args) {
|
|
if (!args) args = {};
|
|
|
|
try {
|
|
for (let a in array) {
|
|
console.log(`Fetching metadata for "${array[a]}"...`);
|
|
let meta = await lib.fetchMetadata(array[a], "", args);
|
|
if (meta.type == "file") {
|
|
let dl;
|
|
try {
|
|
dl = await lib.fetchDownloadLink(meta.id, args);
|
|
} catch(err) {
|
|
if (err.code == "LT100") {
|
|
if (args["dry-run"] == true) {
|
|
console.log(`Got download URL for "${meta.name}": `, err.url);
|
|
continue;
|
|
} else {
|
|
await download(err.url, meta.name, (args.dest || args.destination));
|
|
console.log(`- Download is complete!`);
|
|
continue;
|
|
}
|
|
} else throw err;
|
|
}
|
|
if (args["dry-run"] == true) {
|
|
console.log(`Got download URL for "${dl.name}": `, dl.url);
|
|
continue;
|
|
} else {
|
|
await download(dl, meta.name, (args.dest || args.destination));
|
|
console.log(`- Download is complete!`);
|
|
continue;
|
|
}
|
|
} else {
|
|
if (lib.isDebug(args)) console.log(`[DEBUG] Got data`, meta);
|
|
meta = await lib.flattenFolder(meta, "", args);
|
|
|
|
console.log("Finished retrieving metadata, initiating download...");
|
|
|
|
await downloadFolder(meta.files, 0, args);
|
|
console.log(`- Downloads from "${array[a]}" are complete!`);
|
|
continue;
|
|
}
|
|
}
|
|
process.exit();
|
|
} catch(err) {
|
|
console.log(`ERR!`, (err.stack || err.message || err));
|
|
process.exit(1);
|
|
}
|
|
|
|
}
|
|
|
|
async function downloadFolder(array, index, args) {
|
|
if (!index) index = 0;
|
|
|
|
if (array[index]) {
|
|
console.log(`\nStarting download ${(index + 1)} of ${array.length} ("${array[index].name}")`);
|
|
if (lib.isDebug(args) == true) console.log(`[DEBUG] Fetching download link...`);
|
|
let dl;
|
|
try {
|
|
dl = await lib.fetchDownloadLink(array[index].id, args);
|
|
} catch(err) {
|
|
if (err.code == "LT100") {
|
|
console.log(`Got download URL for "${array[index].name}": `, err.url);
|
|
await download(err.url, array[index].name, args.destination);
|
|
return (await downloadFolder(array, (index + 1), args));
|
|
} else {
|
|
console.log(`ERR! Skipped download due to error:`, (err.message || err.code || err));
|
|
console.log(`Waiting 10 seconds to retry...`);
|
|
await new Promise(function(resolve, reject) {setTimeout(function() {resolve()}, 10000)});
|
|
return (await downloadFolder(array, index, args));
|
|
}
|
|
}
|
|
if (lib.isDebug(args) == true) console.log(`[DEBUG] Got download link, sending to download function....`);
|
|
|
|
let downloadPath = ``;
|
|
if (args.dest || args.destination) {
|
|
let dest = (args.dest || args.destination);
|
|
if (!dest.endsWith("/")) dest = `${dest}/`;
|
|
if (array[index].path) downloadPath = `${dest}${array[index].path}`;
|
|
}
|
|
|
|
try {
|
|
await download(dl, array[index].name, downloadPath);
|
|
return (await downloadFolder(array, (index + 1), args));
|
|
} catch(err) {
|
|
console.log(`ERR! Skipped download due to error:`, (err.message || err.code || err));
|
|
console.log(`Waiting 10 seconds to retry...`);
|
|
await new Promise(function(resolve, reject) {setTimeout(function() {resolve()}, 10000)});
|
|
return (await downloadFolder(array, (index + 1), args));
|
|
}
|
|
} else return true;
|
|
}
|
|
|
|
async function download(url, name, destination) {
|
|
if (!destination || destination == "" || destination == "./") destination = `./${name}`;
|
|
else if (destination) {
|
|
let e = destination.split("/");
|
|
for (let a in e) {
|
|
if (a == 0) continue;
|
|
let f = e.slice(0, a).join("/");
|
|
if (!fs.existsSync(f)) fs.mkdirSync(f);
|
|
}
|
|
|
|
if (!e[e.length - 1].includes(".")) {
|
|
if (destination.endsWith("/")) destination = `${destination}${name}`;
|
|
else destination = `${destination}/${name}`;
|
|
} else {
|
|
name = e[e.length - 1];
|
|
}
|
|
}
|
|
|
|
let speed;
|
|
let header = lib.defaultHeaders;
|
|
|
|
|
|
let string = ``;
|
|
if (args["cookies"]) {
|
|
let cookie = await getCookies(args["cookies"], "drive.google.com");
|
|
|
|
for (let a in cookie) {
|
|
string = `${string} ${cookie[a].name}=${cookie[a].value};`;
|
|
}
|
|
header.cookie = string.substring(1, (string.length - 1));
|
|
}
|
|
|
|
let {data, headers} = await axios({
|
|
url: url,
|
|
responseType: "stream",
|
|
headers: header
|
|
});
|
|
|
|
let size = parseInt(headers["content-length"]);
|
|
|
|
if (name.length >= 30) name = `${name.substring(0, 27)}...`;
|
|
|
|
let pb = new progress.SingleBar({
|
|
format: `${name} {bar} {speed}`,
|
|
barCompleteChar: `\u2588`,
|
|
barIncompleteChar: `\u2591`
|
|
});
|
|
|
|
pb.start(size, 0);
|
|
|
|
data.on("data", function(chunk) {
|
|
if (!speed) speed = chunk.length;
|
|
else speed = speed + chunk.length;
|
|
|
|
let s;
|
|
if (speed !== 0) s = bytesToSize(speed);
|
|
|
|
if (!s) pb.increment(chunk.length)
|
|
else pb.increment(chunk.length, {speed: s});
|
|
});
|
|
|
|
setInterval(function() {
|
|
speed = 0;
|
|
}, 1000);
|
|
|
|
data.pipe(fs.createWriteStream(destination));
|
|
|
|
return (await lib.returnWhenDone(data, pb));
|
|
}
|
|
|
|
function bytesToSize(bytes) {
|
|
var sizes = ['B/s', 'KB/s', 'MB/s', 'GB/s', 'TB/s'];
|
|
if (bytes == 0) return '0 Byte';
|
|
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
|
|
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
|
|
} |