Skip to content

Instantly share code, notes, and snippets.

@Maxim-Mazurok
Last active April 1, 2024 13:13
Show Gist options
  • Save Maxim-Mazurok/b33271b3b72b60ff0f900c67033ff74e to your computer and use it in GitHub Desktop.
Save Maxim-Mazurok/b33271b3b72b60ff0f900c67033ff74e to your computer and use it in GitHub Desktop.
Private Vimeo / Akamai CDN long video downloader
// NOTE: you might have to run it a few times if it doesn't download the full video from the first try, I guess it needs to be cached or something..
const { appendFileSync, writeFileSync } = require("fs");
const https = require("https");
// find that URL in devtools, search for akamai, there's also manifest with different names based on quality (remove &range from it)
const URL = `https://xxxxx-adaptive.akamaized.net/exp=0000000000~xxx=xxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxx~xxxx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/parcel/video/xxxxxxxx.mp4?r=xxxxxxxxxxxxxxxxxx`;
const rangeWidth = 1000000000; // using smaller range will be slower, but might result in more stable/reliable download success
let foundEnd = false;
let currentStart = 0;
let gotData = 0;
const fileName = "video.mp4";
currentStart === 0 && writeFileSync(fileName, "");
let data = [];
const getNextChunk = () => {
const currentUrl = `${URL}&range=${currentStart}-${currentStart + rangeWidth}`;
console.log(currentUrl);
const request = https.get(currentUrl, (response) => {
data = [];
if (response.statusCode !== 200) {
console.log({ statusCode: response.statusCode });
foundEnd = true;
process.exit();
}
response.on("data", (chunk) => {
gotData++;
gotData % 1000 === 1 && console.log("got data", chunk);
data.push(chunk);
});
response.on("end", () => {
console.log("end of chunk");
for (const datum of data) {
appendFileSync(fileName, datum);
}
if (!foundEnd) {
currentStart += rangeWidth + 1;
getNextChunk();
}
});
response.on("close", (x) => console.log("close", x));
response.on("error", (x) => console.log("error", x));
response.on("pause", (x) => console.log("pause", x));
});
request.on("error", (error) => {
console.error("found error/end", error);
foundEnd = true;
});
};
getNextChunk();
@Maxim-Mazurok
Copy link
Author

Maxim-Mazurok commented Jun 8, 2023

This is URL to copy, shows up when you press play:
image

This is manifest with different qualities:
image

This time 1000000000 didn't work, got "connection reset". Lowering to 1000000 seems to have helped.

@Maxim-Mazurok
Copy link
Author

Maxim-Mazurok commented Jun 8, 2023

Also if it fails with connection reset - see last URL in log and change currentStart to the starting range from the last URL that was unsuccessful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment