Skip to content

Instantly share code, notes, and snippets.

@rpCal
Created January 23, 2020 13:17
Show Gist options
  • Save rpCal/d8c4247ab780b372c6b5c279355b9605 to your computer and use it in GitHub Desktop.
Save rpCal/d8c4247ab780b372c6b5c279355b9605 to your computer and use it in GitHub Desktop.
Download from private/blocked vimeo file
// 1. Open the browser developper console on the network tab
// 2. Start the video
// 3. In the dev tab, locate the load of the "master.json" file, copy its full URL
// 4. Run: node vimeo-downloader.js "<URL>"
// 5. Combine the m4v and m4a files with mkvmerge
const fs = require("fs");
const url = require("url");
const https = require("https");
var exec = require("child_process").exec;
let masterUrl = process.argv[2];
if (!masterUrl.endsWith("?base64_init=1")) {
masterUrl += "?base64_init=1";
}
getJson(masterUrl, (err, json) => {
if (err) {
throw err;
}
const videoData = json.video.pop();
const audioData = json.audio.pop();
const videoBaseUrl = url.resolve(
url.resolve(masterUrl, json.base_url),
videoData.base_url
);
const audioBaseUrl = url.resolve(
url.resolve(masterUrl, json.base_url),
audioData.base_url
);
const filename = json.clip_id;
const newFilename = process.argv[3];
processFile(
"video",
videoBaseUrl,
videoData.init_segment,
videoData.segments,
filename + ".m4v",
err => {
if (err) {
throw err;
}
console.log("processFile is done - m4v");
processFile(
"audio",
audioBaseUrl,
audioData.init_segment,
audioData.segments,
filename + ".m4a",
err => {
if (err) {
throw err;
}
console.log("processFile is done - m4a");
combineMovies(filename, () => {
console.log("combineMovies is done - mp4");
removParts(filename, () => {
console.log("removParts is done - mp4");
renameFinalFile(filename, newFilename, () => {
console.log("renameFinalFile is done - mp4");
console.log("All is done");
});
});
});
}
);
}
);
});
const combineMovies = (filename, callback) => {
var cmd = `ffmpeg -i ${filename}.m4v -i ${filename}.m4a -acodec copy -vcodec copy ${filename}.mp4`;
exec(cmd, function(error, stdout, stderr) {
if (error) {
throw error;
}
callback();
console.log(`combineMovies stdout: ${stdout.toString()} stdout: ${stderr}`);
});
};
const removParts = (filename, callback) => {
var cmd = `rm ${filename}.m4v ${filename}.m4a`;
exec(cmd, function(error, stdout, stderr) {
if (error) {
throw error;
}
callback();
console.log(`removParts stdout: ${stdout.toString()} stdout: ${stderr}`);
});
};
const renameFinalFile = (filename, newFilename, callback) => {
var cmd = `mv ${filename}.mp4 ${newFilename}.mp4`;
exec(cmd, function(error, stdout, stderr) {
if (error) {
throw error;
}
callback();
console.log(
`renameFinalFile stdout: ${stdout.toString()} stdout: ${stderr}`
);
});
};
function processFile(type, baseUrl, initData, segments, filename, cb) {
if (fs.existsSync(filename)) {
console.log(`${type} already exists`);
return cb();
}
const segmentsUrl = segments.map(seg => baseUrl + seg.url);
const initBuffer = Buffer.from(initData, "base64");
fs.writeFileSync(filename, initBuffer);
const output = fs.createWriteStream(filename, { flags: "a" });
combineSegments(type, 0, segmentsUrl, output, err => {
if (err) {
return cb(err);
}
output.end();
cb();
});
}
function combineSegments(type, i, segmentsUrl, output, cb) {
if (i >= segmentsUrl.length) {
console.log(`${type} done`);
return cb();
}
console.log(`Download ${type} segment ${i}`);
https
.get(segmentsUrl[i], res => {
res.on("data", d => output.write(d));
res.on("end", () =>
combineSegments(type, i + 1, segmentsUrl, output, cb)
);
})
.on("error", e => {
cb(e);
});
}
function getJson(url, cb) {
let data = "";
https
.get(url, res => {
res.on("data", d => (data += d));
res.on("end", () => cb(null, JSON.parse(data)));
})
.on("error", e => {
cb(e);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment