Skip to content

Instantly share code, notes, and snippets.

@guilhermepontes
Last active May 4, 2025 19:37
Show Gist options
  • Save guilhermepontes/2a5c5969de80b3ad6ebe0886135f5722 to your computer and use it in GitHub Desktop.
Save guilhermepontes/2a5c5969de80b3ad6ebe0886135f5722 to your computer and use it in GitHub Desktop.
download manually from iDrive
const fs = require("fs");
const path = require("path");
const https = require("https");
// File and paths
// get this data from "https://evssyncweb25.idrive.com/evs/browseFolder" call
const filePath = "files.json";
const logFilePath = "failed_downloads.log";
const baseUrl = "https://evssyncweb25.idrive.com/evs/v1/downloadFile?version=0&p=";
const directoryPath = "IDRIVE_PATH";
const externalDrivePath = "/Volumes/T7 Shield/";
// Concurrency settings
const CONCURRENCY_LIMIT = 5;
// Headers
const headers = {
accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "en-GB,en;q=0.9,en-US;q=0.8,pt;q=0.7,bn;q=0.6,nl;q=0.5",
"sec-ch-ua":
'"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"macOS"',
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
cookie: "",
};
// Download a single file
const downloadFile = (fileUrl, outputPath, fileName) => {
return new Promise((resolve, reject) => {
https
.get(fileUrl, { headers }, (response) => {
if (response.statusCode !== 200) {
return reject(new Error(`HTTP ${response.statusCode}`));
}
const fileStream = fs.createWriteStream(outputPath);
response.pipe(fileStream);
fileStream.on("finish", resolve);
fileStream.on("error", reject);
})
.on("error", reject);
});
};
// Log failed downloads
const logFailedDownload = (fileName) => {
const logMessage = `${new Date().toISOString()} - Failed: ${fileName}\n`;
fs.appendFileSync(logFilePath, logMessage);
};
// Process downloads in batches
const processInBatches = async (tasks, batchSize) => {
let index = 0;
while (index < tasks.length) {
const batch = tasks.slice(index, index + batchSize);
await Promise.all(
batch.map((task) =>
task().catch((err) => {
// Error already logged inside task
})
)
);
index += batchSize;
}
};
// Main function
const processFiles = async (items) => {
const filesToDownload = items.filter(
(item) => !item.is_dir && !item.name.includes(" 2.")
);
const tasks = filesToDownload.map((item) => {
return async () => {
const fileName = item.name;
const fullPath = encodeURIComponent(directoryPath + fileName);
const fileUrl = `${baseUrl}${fullPath}`;
const outputPath = path.join(externalDrivePath, fileName);
try {
await downloadFile(fileUrl, outputPath, fileName);
console.log(`βœ… Downloaded: ${fileName}`);
} catch (err) {
console.error(`❌ Failed: ${fileName} (${err.message})`);
logFailedDownload(fileName);
}
};
});
console.log(`πŸš€ Starting download of ${tasks.length} files...`);
await processInBatches(tasks, CONCURRENCY_LIMIT);
console.log("βœ… All downloads attempted.");
};
// Read and parse JSON
fs.readFile(filePath, "utf-8", (err, data) => {
if (err) return console.error("❌ Error reading file:", err);
try {
const items = JSON.parse(data);
processFiles(items);
} catch (e) {
console.error("❌ Error parsing JSON:", e);
}
});
[
{
"is_dir": false,
"name": "IMG_1264.jpg",
"size": "8290842",
"ver": "1",
"lmd": "2022/07/11 02:15:53",
"thumb_exists": false,
"attrib_star": "0",
"attrib_desc": "0",
"share": "-",
"capture_date": "0",
"save_time": "2022/07/13 13:13:29",
"chk": "NA"
},
{
"is_dir": false,
"name": "IMG_1265.jpg",
"size": "8516889",
"ver": "1",
"lmd": "2022/07/11 02:15:56",
"thumb_exists": false,
"attrib_star": "0",
"attrib_desc": "0",
"share": "-",
"capture_date": "0",
"save_time": "2022/07/13 13:13:29",
"chk": "NA"
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment