-
-
Save alexdrean/a027dd89a90a6d0aa54983f87f34a5c4 to your computer and use it in GitHub Desktop.
Download video from Vimeo (chopped m4s files)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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>" | |
// (done automatically now) 5. Combine the m4v and m4a files with mkvmerge | |
const fs = require('fs'); | |
const url = require('url'); | |
const https = require('https'); | |
const { exec } = require('child_process'); | |
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.sort((v1,v2) => v1.avg_bitrate - v2.avg_bitrate).pop(); | |
const audioData = json.audio.sort((a1,a2) => a1.avg_bitrate - a2.avg_bitrate).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); | |
processFile('video', videoBaseUrl, videoData.init_segment, videoData.segments, json.clip_id + '.m4v', (err) => { | |
if (err) { | |
throw err; | |
} | |
processFile('audio', audioBaseUrl, audioData.init_segment, audioData.segments, json.clip_id + '.m4a', (err) => { | |
if (err) { | |
throw err; | |
} | |
console.log('combining video and audio...'); | |
let combineCmd = 'ffmpeg -i ' + json.clip_id + '.m4v -i ' + json.clip_id + '.m4a -c copy ' + json.clip_id + '.mp4'; | |
exec(combineCmd, (err, stdout, stderr) => { | |
if (err) { | |
exec('file ' + json.clip_id + '.m4v ' + json.clip_id + '.m4a', () => throw err); | |
} | |
console.log(`stdout: ${stdout}`); | |
console.log(`stderr: ${stderr}`); | |
console.log('removing video and audio in favor of combined version...'); | |
fs.unlink(json.clip_id + '.m4v', (err) => { | |
if (err) { | |
throw err; | |
} | |
fs.unlink(json.clip_id + '.m4a', (err) => { | |
if (err) { | |
throw err; | |
} | |
console.log('all done'); | |
}); | |
}); | |
}); | |
}); | |
}); | |
}); | |
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); | |
}); | |
} |
Hi folks, not a very experienced one. Where am Im supposed to input the master.json url? Also it will work just running the script in visual studio code or is it necessary to set up a project in a dedicated IDE?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Unfortunately I do not have the time to look into this right now. You may try combining video and audio externally, or search ffmpeg forums about this. It seems like the downloaded content is not in .m4v format. I would suggest replacing every instance of ".mp4" with other common video file extensions and see if you can find the correct one. You could also analyze the downloaded video-only with the
file
command and deduct the correct extension that way. I've updated the script so it does that automatically in case ffmpeg crashes. This should help you figure out what is happening here.