Skip to content

Instantly share code, notes, and snippets.

@shanept
Last active June 4, 2023 05:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shanept/eb081c0d65d848cc48a4a79809c9794e to your computer and use it in GitHub Desktop.
Save shanept/eb081c0d65d848cc48a4a79809c9794e to your computer and use it in GitHub Desktop.
Vimeo DASH stream downloader
/***
* This will create 2 separate files:
* - Vimeo Rip.mp4 - The video file
* - Vimeo Rip.mp4a - The associated audio
*
* This is by Vimeo's design. These files simply need to be merged.
* The following ffmpeg command may be used:
*
* ffmpeg -i ".\Vimeo Rip.mp4" -i ".\Vimeo Rip.mp4a" -c copy output.mp4
*/
(function() {
var url = playerConfig.request.files.dash.cdns[playerConfig.request.files.dash.default_cdn].url;
console.info("Ripping DASH stream from VIMEO. This may take some time...");
// First we load the stream manifest
var xhr = new XMLHttpRequest
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
handleStream(xhr.responseText);
} else {
console.error("STATUS: " + xhr.status);
}
}
};
xhr.open("GET", url);
xhr.send();
function handleStream(streamData) {
// Now we pick the highest bitrate stream
var stream = JSON.parse(streamData);
var base_url = new URL(stream.base_url, url);
stream.video.sort(function(x,y) {
if (x.width > y.width) return -1;
if (x.width < y.width) return +1;
return 0;
});
stream.audio.sort(function(a, b) {
if (a.bitrate > b.bitrate) return -1;
if (a.bitrate < b.bitrate) return +1;
return 0;
});
audioRip(videoRip);
function videoRip(cb) {
var videoStream = stream.video.filter(v => v.hasOwnProperty('index_segment'))[0];
var videoUrl = base_url + videoStream.base_url;
// Now we start gluing the stream together... We need to figure out how many bytes this file is.
// We can do this by looking at the end range of the last segment.
var lastByte = videoStream.segments.at(-1).url.split('-')[1];
// Now we can forge our URL range to begin at byte 0 and finish at lastByte
var forgedBasePath = videoStream.index_segment.split('range=')[0] + 'range=0-' + lastByte;
console.info('Picking ' + videoStream.height + 'p stream');
console.debug('Video file size ' + lastByte + 'B. Beginning download now.');
(function() {
let x = new XMLHttpRequest();
x.responseType = "blob";
x.onreadystatechange = function() {
if (x.readyState == 4 && x.status == 200) {
saveData(x.response, "Vimeo Rip.mp4");
if (cb) {
cb();
}
}
};
x.open("GET", videoUrl + forgedBasePath);
x.send();
})();
}
function audioRip(cb) {
var audioStream = stream.audio.filter(a => a.hasOwnProperty('index_segment'))[0];
var audioUrl = base_url + audioStream.base_url;
var lastByte = audioStream.segments.at(-1).url.split('-')[1];
var forgedBasePath = audioStream.index_segment.split('range=')[0] + 'range=0-' + lastByte;
console.info('Picking ' + audioStream.bitrate + ' bitrate ' + audioStream.codecs + ' stream');
console.debug('Audio file size ' + lastByte + 'B. Beginning download now.');
(function() {
let x = new XMLHttpRequest();
x.responseType = "blob";
x.onreadystatechange = function() {
if (x.readyState == 4 && x.status == 200) {
saveData(x.response, "Vimeo Rip.mp4a");
if (cb) {
cb();
}
}
};
x.open("GET", audioUrl + forgedBasePath);
x.send();
})();
}
}
function saveData(data, name) {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
url = window.URL.createObjectURL(data);
a.href = url;
a.download = name;
a.click();
window.URL.revokeObjectURL(url);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment