喜欢看b站的小伙伴们,看到喜欢的视频时,可能想要下载下来,保存到自己的电脑。因为有的视频可能过了几天就被up主删除了,或者被b站删除了。然而b站没有提供下载的功能
于是作为网站开发者的我,连夜分析了一波b站的视频机制(发现机制和YouTube是相同的,所以这个方法也可以下载YouTube的视频),发现b站为了防止视频被别人获取,可以说是费尽了心思。然而前端是没有安全性可言的,任何网站都能够被pojie。现在假设一个10分钟的视频,b站首先把图像和声音分开发送,然后每次只发送部分内容,比如1分钟的内容。那么算下来,这个视频需要发10个图像包,10个声音包,加起来发送20次
我们来到b站,选择一个喜欢的视频,点击播放,在视频的页面按F12键打开控制台
打开Network选项,发现有很多网络请求,我们找到这种fetch类型的,而且文件比较大的这种,就是视频,它紧挨着的下面的请求就是这段视频对应的音频
temp1.then(_=>_.blob()).then(_=>{
var url = window.URL.createObjectURL(_)
var a = document.createElement('a')
a.href = url
a.download = 'video'
a.click()
})
temp2.then(_=>_.blob()).then(_=>{
var url = window.URL.createObjectURL(_)
var a = document.createElement('a')
a.href = url
a.download = 'audio'
a.click()
})
视频已经完整的下载下来了,接下来可以用一些视频播放软件,把2个文件合并到一起,比如vlc
b站的播放原理:使用浏览器的MediaSource方法,加入视频流和音频流,就可以同步播放,核心代码如下:
var video = document.querySelector('video');
var videoCodec = 'video/mp4; codecs="avc1.42E01E"';
var audioCodec = 'audio/mp4; codecs="mp4a.40.2"';
var mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
function sourceOpen(){
var mediaSource = this;
var videoBuffer = mediaSource.addSourceBuffer(videoCodec);
var audioBuffer = mediaSource.addSourceBuffer(audioCodec);
/*
* buffer数据处理(append、remove等)完成时会触发 updateend 事件
* 这里省略对audioBuffer的 updateended 事件等待
*/
videoBuffer.addEventListener('updateend', function(){
mediaSource.endOfStream();
video.play();
});
/*
* 这里省略网络数据请求的过程,且假设音视频都只有一个片段文件。
*/
videoBuffer.appendBuffer(vbuf);
audioBuffer.appendBuffer(abuf);
}var video = document.querySelector('video');
var videoCodec = 'video/mp4; codecs="avc1.42E01E"';
var audioCodec = 'audio/mp4; codecs="mp4a.40.2"';
var mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
function sourceOpen(){
var mediaSource = this;
var videoBuffer = mediaSource.addSourceBuffer(videoCodec);
var audioBuffer = mediaSource.addSourceBuffer(audioCodec);
/*
* buffer数据处理(append、remove等)完成时会触发 updateend 事件
* 这里省略对audioBuffer的 updateended 事件等待
*/
videoBuffer.addEventListener('updateend', function(){
mediaSource.endOfStream();
video.play();
});
/*
* 这里省略网络数据请求的过程,且假设音视频都只有一个片段文件。
*/
videoBuffer.appendBuffer(vbuf);
audioBuffer.appendBuffer(abuf);
}