Skip to content

Instantly share code, notes, and snippets.

@aik099
Forked from mistic100/vimeo-downloader.js
Last active September 4, 2023 13:37
Show Gist options
  • Save aik099/69f221d100b87cb29f4fb6c29d72838e to your computer and use it in GitHub Desktop.
Save aik099/69f221d100b87cb29f4fb6c29d72838e 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) {
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);
});
}
@keponk
Copy link

keponk commented Mar 6, 2021

@aik099 trying to get this to work... the script seems to start ok but fails when running combineCmd with :

...
combining video and audio...
/home/joel/workspace/hackvimeo/script.js:75
              throw err;
              ^

Error: Command failed: ffmpeg -i e53f1dff-bb7f-449c-8f67-4a96e2acc2a7.m4v -i e53f1dff-bb7f-449c-8f67-4a96e2acc2a7.m4a -c copy e53f1dff-bb7f-449c-8f67-4a96e2acc2a7.mp4
ffmpeg version 4.3.2 Copyright (c) 2000-2021 the FFmpeg developers
  built with gcc 10 (GCC)
  configuration: --prefix=/usr --bindir=/usr/bin --datadir=/usr/share/ffmpeg --docdir=/usr/share/doc/ffmpeg --incdir=/usr/include/ffmpeg --libdir=/usr/lib64 --mandir=/usr/share/man --arch=x86_64 --optflags='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection' --extra-ldflags='-Wl,-z,relro -Wl,--as-needed -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld ' --extra-cflags=' -I/usr/include/rav1e' --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libvo-amrwbenc --enable-version3 --enable-bzlib --disable-crystalhd --enable-fontconfig --enable-frei0r --enable-gcrypt --enable-gnutls --enable-ladspa --enable-libaom --enable-libdav1d --enable-libass --enable-libbluray --enable-libcdio --enable-libdrm --enable-libjack --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-liblensfun --enable-libmp3lame --enable-libmysofa --enable-nvenc --enable-openal --enable-opencl --enable-opengl --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librav1e --enable-libsmbclient --enable-version3 --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libvorbis --enable-libv4l2 --enable-libvidstab --enable-libvmaf --enable-version3 --enable-vapoursynth --enable-libvpx --enable-vulkan --enable-libglslang --enable-libx264 --enable-libx265 --enable-libxvid --enable-libxml2 --enable-libzimg --enable-libzvbi --enable-lv2 --enable-avfilter --enable-avresample --enable-libmodplug --enable-postproc --enable-pthreads --disable-static --enable-shared --enable-gpl --disable-debug --disable-stripping --shlibdir=/usr/lib64 --enable-lto --enable-libmfx --enable-runtime-cpudetect
[m4v @ 0x561fe70f4dc0] Format m4v detected only with low score of 1, misdetection possible!
[mpeg4 @ 0x561fe70f69c0] illegal chroma format
[mpeg4 @ 0x561fe70f69c0] Marker bit missing at 8341 of 1226943056 before time_increment_resolution
[mpeg4 @ 0x561fe70f69c0] framerate==0
[mpeg4 @ 0x561fe70f69c0] illegal chroma format
[mpeg4 @ 0x561fe70f69c0] Marker bit missing at 8341 of 1226935664 before time_increment_resolution
[mpeg4 @ 0x561fe70f69c0] framerate==0
[mpeg4 @ 0x561fe70f69c0] illegal chroma format
[mpeg4 @ 0x561fe70f69c0] Marker bit missing at 8341 of 1226943056 before time_increment_resolution
[mpeg4 @ 0x561fe70f69c0] framerate==0
[mpeg4 @ 0x561fe70f69c0] header damaged
[m4v @ 0x561fe70f4dc0] Stream #0: not enough frames to estimate rate; consider increasing probesize
[m4v @ 0x561fe70f4dc0] decoding for stream 0 failed
[m4v @ 0x561fe70f4dc0] Could not find codec parameters for stream 0 (Video: mpeg4, none): unspecified size
Consider increasing the value for the 'analyzeduration' and 'probesize' options
Input #0, m4v, from 'e53f1dff-bb7f-449c-8f67-4a96e2acc2a7.m4v':
  Duration: N/A, bitrate: N/A
    Stream #0:0: Video: mpeg4, none, 25 tbr, 1200k tbn, 25 tbc
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x561fe710b740] Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x561fe710b740] moov atom not found
e53f1dff-bb7f-449c-8f67-4a96e2acc2a7.m4a: Invalid data found when processing input

seems like ffmpeg needs more info? is there some extra flags to give ffmpeg that could help?

EDIT: adding more info. Looking further into the ffmpeg error I saw someone suggested the data may be encrypted. I coincidentally noticed this on my console while streaming the video in question

Adaptive Video Streaming Service by www.bitmovin.com instrument.js:110:45
Player Version 8.55.0 instrument.js:110:45
EmeEncryptionSchemePolyfill: No native encryptionScheme support found. Patching encryptionScheme support. instrument.js:110:45

Some forums related to encrypted video in general suggested a key might be available to decrypt but this is where i hit a wall with my knowledge. Could there be a decription key somewhere we could use? or is this a blocker related to DRM stuff?

@aik099
Copy link
Author

aik099 commented Mar 6, 2021

@keponk
Copy link

keponk commented Mar 9, 2021

@aik099 yes that worked! thanks for the tip :)

@zachduda
Copy link

zachduda commented Feb 3, 2023

I know this is an older gist but I'd like to say

a) you are a legend
b) this is so ****ing helpful
c) long live aik009

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