Skip to content

Instantly share code, notes, and snippets.

@alexdrean
Forked from aik099/vimeo-downloader.js
Last active July 20, 2023 22:23
Show Gist options
  • Save alexdrean/a027dd89a90a6d0aa54983f87f34a5c4 to your computer and use it in GitHub Desktop.
Save alexdrean/a027dd89a90a6d0aa54983f87f34a5c4 to your computer and use it in GitHub Desktop.
Download video from Vimeo (chopped m4s files)
// 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);
});
}
@SalimF
Copy link

SalimF commented Nov 27, 2020

Works great , but I'm downloading on low quality video , as @jangxx suggested .

const videoData = json.video.find(v => v.height == 360); // or 1080, or something else

@jtgasper3
Copy link

Worked perfectly. Thanks!

@wvolkov
Copy link

wvolkov commented Mar 16, 2021

It doesn't work with private videos though :(

@cesarcf
Copy link

cesarcf commented Aug 25, 2021

Hello, I download the audio and the video well but I am having problems with ffmpeg, I installed on the macBook through homebrew and when launching the script it failed me. I am trying to mix .m4v and .m4a extension files. Do I need to install something else?

this is the version -> ffmpeg version 4.4 Copyright (c) 2000-2021 the FFmpeg developers
and this is the log:

combining video and audio...
/Users/cesarcf/vimeo/vimeo-downloader.js:44
throw err;
^

Error: Command failed: ffmpeg -i 95a3e237-4ea3-4acf-8fc2-ba0c1e12f711.m4v -i 95a3e237-4ea3-4acf-8fc2-ba0c1e12f711.m4a -c copy 95a3e237-4ea3-4acf-8fc2-ba0c1e12f711.mp4
ffmpeg version 4.4 Copyright (c) 2000-2021 the FFmpeg developers
built with Apple clang version 12.0.0 (clang-1200.0.32.29)
configuration: --prefix=/usr/local/Cellar/ffmpeg/4.4_2 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-avresample --enable-videotoolbox
libavutil 56. 70.100 / 56. 70.100
libavcodec 58.134.100 / 58.134.100
libavformat 58. 76.100 / 58. 76.100
libavdevice 58. 13.100 / 58. 13.100
libavfilter 7.110.100 / 7.110.100
libavresample 4. 0. 0 / 4. 0. 0
libswscale 5. 9.100 / 5. 9.100
libswresample 3. 9.100 / 3. 9.100
libpostproc 55. 9.100 / 55. 9.100
[m4v @ 0x7fa04d810400] Format m4v detected only with low score of 1, misdetection possible!
[mpeg4 @ 0x7fa04d000a00] only rectangular vol supported
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 8049 of 37593632 before time_increment_resolution
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 8066 of 37593632 before fixed_vop_rate
[mpeg4 @ 0x7fa04d000a00] Ignoring multiple VOL headers
Last message repeated 1 times
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 37593380 of 37593632 before time_increment
[mpeg4 @ 0x7fa04d000a00] only rectangular vol supported
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 8049 of 37593344 before time_increment_resolution
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 8066 of 37593344 before fixed_vop_rate
[mpeg4 @ 0x7fa04d000a00] Ignoring multiple VOL headers
Last message repeated 1 times
[mpeg4 @ 0x7fa04d000a00] only rectangular vol supported
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 8049 of 37593632 before time_increment_resolution
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 8066 of 37593632 before fixed_vop_rate
[mpeg4 @ 0x7fa04d000a00] Ignoring multiple VOL headers
Last message repeated 1 times
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 37593380 of 37593632 before time_increment
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 43 of 311566976 in gop_header
[mpeg4 @ 0x7fa04d000a00] only rectangular vol supported
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 50792585 of 311566976 before time_increment_resolution
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 50792602 of 311566976 before fixed_vop_rate
[mpeg4 @ 0x7fa04d000a00] Ignoring multiple VOL headers
Last message repeated 42 times
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 311566915 of 311566976 before time_increment
[mpeg4 @ 0x7fa04d000a00] time_increment_bits 10 is invalid in relation to the current bitstream, this is likely caused by a missing VOL header
[mpeg4 @ 0x7fa04d000a00] time_increment_bits set to 16 bits, based on bitstream analysis
[mpeg4 @ 0x7fa04d000a00] only rectangular vol supported
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 8049 of 37593344 before time_increment_resolution
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 8066 of 37593344 before fixed_vop_rate
[mpeg4 @ 0x7fa04d000a00] Ignoring multiple VOL headers
Last message repeated 1 times
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 43 of 311566976 in gop_header
[mpeg4 @ 0x7fa04d000a00] only rectangular vol supported
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 50792585 of 311566976 before time_increment_resolution
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 50792602 of 311566976 before fixed_vop_rate
[mpeg4 @ 0x7fa04d000a00] Ignoring multiple VOL headers
Last message repeated 42 times
[mpeg4 @ 0x7fa04d000a00] Marker bit missing at 311566915 of 311566976 before time_increment
[mpeg4 @ 0x7fa04d000a00] time_increment_bits 10 is invalid in relation to the current bitstream, this is likely caused by a missing VOL header
[mpeg4 @ 0x7fa04d000a00] time_increment_bits set to 16 bits, based on bitstream analysis
[m4v @ 0x7fa04d810400] Stream #0: not enough frames to estimate rate; consider increasing probesize
[m4v @ 0x7fa04d810400] decoding for stream 0 failed
[m4v @ 0x7fa04d810400] Could not find codec parameters for stream 0 (Video: mpeg4 (Main Profile), none): unspecified size
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
Input #0, m4v, from '95a3e237-4ea3-4acf-8fc2-ba0c1e12f711.m4v':
Duration: N/A, start: 1.875000, bitrate: N/A
Stream #0:0: Video: mpeg4 (Main Profile), none, 65536 tbr, 1200k tbn, 65536 tbc
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7fa04d819800] Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7fa04d819800] moov atom not found
95a3e237-4ea3-4acf-8fc2-ba0c1e12f711.m4a: Invalid data found when processing input

at ChildProcess.exithandler (child_process.js:303:12)
at ChildProcess.emit (events.js:315:20)
at maybeClose (internal/child_process.js:1021:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:286:5) {

killed: false,
code: 1,
signal: null,
cmd: 'ffmpeg -i 95a3e237-4ea3-4acf-8fc2-ba0c1e12f711.m4v -i 95a3e237-4ea3-4acf-8fc2-ba0c1e12f711.m4a -c copy 95a3e237-4ea3-4acf-8fc2-ba0c1e12f711.mp4'
}

@cesarcf
Copy link

cesarcf commented Aug 31, 2021

@alexdrean can you help me with this?

@jrichardsz
Copy link

same error!

@alexdrean
Copy link
Author

alexdrean commented Oct 3, 2021

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.

@kevinaso
Copy link

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